• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Author: Jon Trulson <jtrulson@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 
WT5001(int uart)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 
~WT5001()69 WT5001::~WT5001()
70 {
71   if (m_ttyFd != -1)
72     close(m_ttyFd);
73 
74   mraa_deinit();
75 }
76 
dataAvailable(unsigned int millis)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 
readData(char * buffer,int len)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 
writeData(char * buffer,int len)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 
setupTty(speed_t baud)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 
checkResponse(WT5001_OPCODE_T opcode)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 
play(WT5001_PLAYSOURCE_T psrc,uint16_t index)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 
stop()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 
next()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 
previous()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 
pause()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 
setVolume(uint8_t vol)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 
queue(uint16_t index)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 
setPlayMode(WT5001_PLAYMODE_T pm)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 
insert(uint16_t index)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 
setDate(uint16_t year,uint8_t month,uint8_t day)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 
setTime(uint8_t hour,uint8_t minute,uint8_t second)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 
setAlarm(uint8_t hour,uint8_t minute,uint8_t second)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 
clearAlarm()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 
getVolume(uint8_t * vol)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 
getPlayState(uint8_t * ps)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 
getNumFiles(WT5001_PLAYSOURCE_T psrc,uint16_t * numf)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 
getCurrentFile(uint16_t * curf)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 
getDate(uint16_t * year,uint8_t * month,uint8_t * day)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 
getTime(uint8_t * hour,uint8_t * minute,uint8_t * second)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