Home | History | Annotate | Download | only in wt5001
      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