1 /* 2 * Author: Jon Trulson <jtrulson (at) ics.com> 3 * Copyright (c) 2014 Intel Corporation. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <iostream> 26 #include <sstream> 27 #include <string> 28 #include <stdexcept> 29 30 #include "wt5001.h" 31 32 using namespace upm; 33 using namespace std; 34 35 static const int defaultDelay = 100; // max wait time for read 36 37 WT5001::WT5001(int uart) 38 { 39 m_ttyFd = -1; 40 41 if ( !(m_uart = mraa_uart_init(uart)) ) 42 { 43 throw std::invalid_argument(std::string(__FUNCTION__) + 44 ": mraa_uart_init() failed"); 45 return; 46 } 47 48 // This requires a recent MRAA (1/2015) 49 const char *devPath = mraa_uart_get_dev_path(m_uart); 50 51 if (!devPath) 52 { 53 throw std::runtime_error(std::string(__FUNCTION__) + 54 ": mraa_uart_get_dev_path() failed"); 55 return; 56 } 57 58 // now open the tty 59 if ( (m_ttyFd = open(devPath, O_RDWR)) == -1) 60 { 61 throw std::runtime_error(std::string(__FUNCTION__) + 62 ": open of " + 63 string(devPath) + " failed: " + 64 string(strerror(errno))); 65 return; 66 } 67 } 68 69 WT5001::~WT5001() 70 { 71 if (m_ttyFd != -1) 72 close(m_ttyFd); 73 74 mraa_deinit(); 75 } 76 77 bool WT5001::dataAvailable(unsigned int millis) 78 { 79 if (m_ttyFd == -1) 80 return false; 81 82 struct timeval timeout; 83 84 // no waiting 85 timeout.tv_sec = 0; 86 timeout.tv_usec = millis * 1000; 87 88 int nfds; 89 fd_set readfds; 90 91 FD_ZERO(&readfds); 92 93 FD_SET(m_ttyFd, &readfds); 94 95 if (select(m_ttyFd + 1, &readfds, NULL, NULL, &timeout) > 0) 96 return true; // data is ready 97 else 98 return false; 99 } 100 101 int WT5001::readData(char *buffer, int len) 102 { 103 if (m_ttyFd == -1) 104 return(-1); 105 106 if (!dataAvailable(defaultDelay)) 107 return 0; // timed out 108 109 int rv = read(m_ttyFd, buffer, len); 110 111 if (rv < 0) 112 { 113 throw std::runtime_error(std::string(__FUNCTION__) + 114 ": read() failed: " + 115 string(strerror(errno))); 116 return rv; 117 } 118 119 return rv; 120 } 121 122 int WT5001::writeData(char *buffer, int len) 123 { 124 if (m_ttyFd == -1) 125 return(-1); 126 127 // first, flush any pending but unread input 128 tcflush(m_ttyFd, TCIFLUSH); 129 130 int rv = write(m_ttyFd, buffer, len); 131 132 if (rv < 0) 133 { 134 throw std::runtime_error(std::string(__FUNCTION__) + 135 ": write() failed: " + 136 string(strerror(errno))); 137 return rv; 138 } 139 140 tcdrain(m_ttyFd); 141 142 return rv; 143 } 144 145 bool WT5001::setupTty(speed_t baud) 146 { 147 if (m_ttyFd == -1) 148 return(false); 149 150 struct termios termio; 151 152 // get current modes 153 tcgetattr(m_ttyFd, &termio); 154 155 // setup for a 'raw' mode. 81N, no echo or special character 156 // handling, such as flow control. 157 cfmakeraw(&termio); 158 159 // set our baud rates 160 cfsetispeed(&termio, baud); 161 cfsetospeed(&termio, baud); 162 163 // make it so 164 if (tcsetattr(m_ttyFd, TCSAFLUSH, &termio) < 0) 165 { 166 throw std::runtime_error(std::string(__FUNCTION__) + 167 ": tcsetattr() failed: " + 168 string(strerror(errno))); 169 return false; 170 } 171 172 return true; 173 } 174 175 bool WT5001::checkResponse(WT5001_OPCODE_T opcode) 176 { 177 char resp; 178 char fopcode = (char)opcode; 179 180 int rv = readData(&resp, 1); 181 182 // check for wrong response byte, or timeout 183 if ((resp != fopcode) || rv == 0 ) 184 return false; 185 186 return true; 187 } 188 189 bool WT5001::play(WT5001_PLAYSOURCE_T psrc, uint16_t index) 190 { 191 char pkt[6]; 192 WT5001_OPCODE_T opcode = PLAY_SD; 193 194 pkt[0] = WT5001_START; 195 pkt[1] = 0x04; // length 196 197 switch (psrc) // src 198 { 199 case SD: 200 opcode = PLAY_SD; 201 break; 202 203 case SPI: 204 opcode = PLAY_SPI; 205 break; 206 207 case UDISK: 208 opcode = PLAY_UDISK; 209 break; 210 } 211 212 pkt[2] = opcode; 213 pkt[3] = (index >> 8) & 0xff; // index hi 214 pkt[4] = index & 0xff; // index lo 215 pkt[5] = WT5001_END; 216 217 writeData(pkt, 6); 218 219 return checkResponse(opcode); 220 } 221 222 bool WT5001::stop() 223 { 224 char pkt[4]; 225 WT5001_OPCODE_T opcode = STOP; 226 227 pkt[0] = WT5001_START; 228 pkt[1] = 0x02; // length 229 pkt[2] = opcode; 230 pkt[3] = WT5001_END; 231 232 writeData(pkt, 4); 233 234 return checkResponse(opcode); 235 } 236 237 bool WT5001::next() 238 { 239 char pkt[4]; 240 WT5001_OPCODE_T opcode = NEXT; 241 242 pkt[0] = WT5001_START; 243 pkt[1] = 0x02; // length 244 pkt[2] = opcode; 245 pkt[3] = WT5001_END; 246 247 writeData(pkt, 4); 248 249 return checkResponse(opcode); 250 } 251 252 bool WT5001::previous() 253 { 254 char pkt[4]; 255 WT5001_OPCODE_T opcode = PREVIOUS; 256 257 pkt[0] = WT5001_START; 258 pkt[1] = 0x02; // length 259 pkt[2] = opcode; 260 pkt[3] = WT5001_END; 261 262 writeData(pkt, 4); 263 264 return checkResponse(opcode); 265 } 266 267 bool WT5001::pause() 268 { 269 char pkt[4]; 270 WT5001_OPCODE_T opcode = PAUSE; 271 272 pkt[0] = WT5001_START; 273 pkt[1] = 0x02; // length 274 pkt[2] = opcode; 275 pkt[3] = WT5001_END; 276 277 writeData(pkt, 4); 278 279 return checkResponse(opcode); 280 } 281 282 bool WT5001::setVolume(uint8_t vol) 283 { 284 if (vol > WT5001_MAX_VOLUME) 285 { 286 // C++11 std::to_string() would be nice, but... 287 std::ostringstream str; 288 str << WT5001_MAX_VOLUME; 289 290 throw std::out_of_range(std::string(__FUNCTION__) + 291 ": angle must be between 0 and " + 292 str.str()); 293 return false; 294 } 295 296 char pkt[5]; 297 WT5001_OPCODE_T opcode = SET_VOLUME; 298 299 pkt[0] = WT5001_START; 300 pkt[1] = 0x03; // length 301 pkt[2] = opcode; 302 pkt[3] = vol; 303 pkt[4] = WT5001_END; 304 305 writeData(pkt, 5); 306 307 return checkResponse(opcode); 308 } 309 310 bool WT5001::queue(uint16_t index) 311 { 312 char pkt[6]; 313 WT5001_OPCODE_T opcode = QUEUE; 314 315 pkt[0] = WT5001_START; 316 pkt[1] = 0x04; // length 317 pkt[2] = opcode; 318 pkt[3] = (index >> 8) & 0xff; // index hi 319 pkt[4] = index & 0xff; // index lo 320 pkt[5] = WT5001_END; 321 322 writeData(pkt, 6); 323 324 return checkResponse(opcode); 325 } 326 327 bool WT5001::setPlayMode(WT5001_PLAYMODE_T pm) 328 { 329 char pkt[5]; 330 WT5001_OPCODE_T opcode = PLAY_MODE; 331 332 pkt[0] = WT5001_START; 333 pkt[1] = 0x03; // length 334 pkt[2] = opcode; 335 pkt[3] = pm; 336 pkt[4] = WT5001_END; 337 338 writeData(pkt, 5); 339 340 return checkResponse(opcode); 341 } 342 343 bool WT5001::insert(uint16_t index) 344 { 345 char pkt[6]; 346 WT5001_OPCODE_T opcode = INSERT_SONG; 347 348 pkt[0] = WT5001_START; 349 pkt[1] = 0x04; // length 350 pkt[2] = opcode; 351 pkt[3] = (index >> 8) & 0xff; // index hi 352 pkt[4] = index & 0xff; // index lo 353 pkt[5] = WT5001_END; 354 355 writeData(pkt, 6); 356 357 return checkResponse(opcode); 358 } 359 360 bool WT5001::setDate(uint16_t year, uint8_t month, uint8_t day) 361 { 362 char pkt[8]; 363 WT5001_OPCODE_T opcode = SET_DATE; 364 365 pkt[0] = WT5001_START; 366 pkt[1] = 0x06; // length 367 pkt[2] = opcode; 368 pkt[3] = (year >> 8) & 0xff; // year hi 369 pkt[4] = year & 0xff; // year lo 370 pkt[5] = month; // month 371 pkt[6] = day; // day 372 pkt[7] = WT5001_END; 373 374 writeData(pkt, 8); 375 376 return checkResponse(opcode); 377 } 378 379 bool WT5001::setTime(uint8_t hour, uint8_t minute, uint8_t second) 380 { 381 char pkt[7]; 382 WT5001_OPCODE_T opcode = SET_TIME; 383 384 pkt[0] = WT5001_START; 385 pkt[1] = 0x05; // length 386 pkt[2] = opcode; 387 pkt[3] = hour; // hour 388 pkt[4] = minute; // minute 389 pkt[5] = second; // second 390 pkt[6] = WT5001_END; 391 392 writeData(pkt, 7); 393 394 return checkResponse(opcode); 395 } 396 397 bool WT5001::setAlarm(uint8_t hour, uint8_t minute, uint8_t second) 398 { 399 char pkt[7]; 400 WT5001_OPCODE_T opcode = SET_ALARM; 401 402 pkt[0] = WT5001_START; 403 pkt[1] = 0x05; // length 404 pkt[2] = opcode; 405 pkt[3] = hour; // hour 406 pkt[4] = minute; // minute 407 pkt[5] = second; // second 408 pkt[6] = WT5001_END; 409 410 writeData(pkt, 7); 411 412 return checkResponse(opcode); 413 } 414 415 bool WT5001::clearAlarm() 416 { 417 char pkt[4]; 418 WT5001_OPCODE_T opcode = CLEAR_ALARM; 419 420 pkt[0] = WT5001_START; 421 pkt[1] = 0x02; // length 422 pkt[2] = opcode; 423 pkt[3] = WT5001_END; 424 425 writeData(pkt, 4); 426 427 return checkResponse(opcode); 428 } 429 430 bool WT5001::getVolume(uint8_t *vol) 431 { 432 char pkt[4]; 433 WT5001_OPCODE_T opcode = READ_VOLUME; 434 435 pkt[0] = WT5001_START; 436 pkt[1] = 0x02; // length 437 pkt[2] = opcode; 438 pkt[3] = WT5001_END; 439 440 writeData(pkt, 4); 441 442 if (!checkResponse(opcode)) 443 return false; 444 445 // there should be a byte waiting for us, the volume 446 int rv = readData((char *)vol, 1); 447 if (rv != 1) 448 return false; 449 450 return true; 451 } 452 453 bool WT5001::getPlayState(uint8_t *ps) 454 { 455 char pkt[4]; 456 WT5001_OPCODE_T opcode = READ_PLAY_STATE; 457 458 pkt[0] = WT5001_START; 459 pkt[1] = 0x02; // length 460 pkt[2] = opcode; 461 pkt[3] = WT5001_END; 462 463 writeData(pkt, 4); 464 465 if (!checkResponse(opcode)) 466 return false; 467 468 // there should be a byte waiting for us, the play state 469 int rv = readData((char *)ps, 1); 470 if (rv != 1) 471 return false; 472 473 return true; 474 } 475 476 bool WT5001::getNumFiles(WT5001_PLAYSOURCE_T psrc, uint16_t *numf) 477 { 478 char pkt[4]; 479 WT5001_OPCODE_T opcode; 480 481 pkt[0] = WT5001_START; 482 pkt[1] = 0x02; // length 483 484 switch (psrc) // src 485 { 486 case SD: 487 opcode = READ_SD_NUMF; 488 break; 489 490 case SPI: 491 opcode = READ_SPI_NUMF; 492 break; 493 494 case UDISK: 495 opcode = READ_UDISK_NUMF; 496 break; 497 } 498 499 pkt[2] = opcode; 500 pkt[3] = WT5001_END; 501 502 writeData(pkt, 4); 503 504 if (!checkResponse(opcode)) 505 return false; 506 507 // read the two byte response, and encode them 508 char buf[2]; 509 int rv = readData(buf, 2); 510 if (rv != 2) 511 return false; 512 513 *numf = (buf[0] << 8) | buf[1]; 514 515 return true; 516 } 517 518 bool WT5001::getCurrentFile(uint16_t *curf) 519 { 520 char pkt[4]; 521 WT5001_OPCODE_T opcode = READ_CUR_FNAME; 522 523 pkt[0] = WT5001_START; 524 pkt[1] = 0x02; // length 525 pkt[2] = opcode; 526 pkt[3] = WT5001_END; 527 528 writeData(pkt, 4); 529 530 if (!checkResponse(opcode)) 531 return false; 532 533 // read the two byte response, and encode them 534 char buf[2]; 535 int rv = readData(buf, 2); 536 if (rv != 2) 537 return false; 538 539 *curf = (buf[0] << 8) | (buf[1] & 0xff); 540 541 return true; 542 } 543 544 bool WT5001::getDate(uint16_t *year, uint8_t *month, uint8_t *day) 545 { 546 char pkt[4]; 547 WT5001_OPCODE_T opcode = READ_DATE; 548 549 pkt[0] = WT5001_START; 550 pkt[1] = 0x02; // length 551 pkt[2] = opcode; 552 pkt[3] = WT5001_END; 553 554 writeData(pkt, 4); 555 556 if (!checkResponse(opcode)) 557 return false; 558 559 // read the 4 byte response 560 char buf[4]; 561 int rv = readData(buf, 4); 562 if (rv != 4) 563 return false; 564 565 *year = (buf[0] << 8) | (buf[1] & 0xff); 566 *month = buf[2]; 567 *day = buf[3]; 568 return true; 569 } 570 571 bool WT5001::getTime(uint8_t *hour, uint8_t *minute, uint8_t *second) 572 { 573 char pkt[4]; 574 WT5001_OPCODE_T opcode = READ_TIME; 575 576 pkt[0] = WT5001_START; 577 pkt[1] = 0x02; // length 578 pkt[2] = opcode; 579 pkt[3] = WT5001_END; 580 581 writeData(pkt, 4); 582 583 if (!checkResponse(opcode)) 584 return false; 585 586 // read the 3 byte response 587 char buf[3]; 588 int rv = readData(buf, 3); 589 if (rv != 3) 590 return false; 591 592 *hour = buf[0]; 593 *minute = buf[1]; 594 *second = buf[2]; 595 return true; 596 } 597 598