1 /*
2  * Author: Jon Trulson <jtrulson@ics.com>
3  * Copyright (c) 2015 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 <string>
27 #include <stdexcept>
28 
29 #include "hmtrp.h"
30 
31 using namespace upm;
32 using namespace std;
33 
34 static const int defaultDelay = 100;     // max wait time for read
35 
36 // protocol start code
37 const uint8_t HMTRP_START1 = 0xaa;
38 const uint8_t HMTRP_START2 = 0xfa;
39 
HMTRP(int uart)40 HMTRP::HMTRP(int uart)
41 {
42   m_ttyFd = -1;
43 
44   if ( !(m_uart = mraa_uart_init(uart)) )
45     {
46       throw std::invalid_argument(std::string(__FUNCTION__) +
47                                   ": mraa_uart_init() failed");
48       return;
49     }
50 
51   // This requires a recent MRAA (1/2015)
52   const char *devPath = mraa_uart_get_dev_path(m_uart);
53 
54   if (!devPath)
55     {
56       throw std::runtime_error(std::string(__FUNCTION__) +
57                                ": mraa_uart_get_dev_path() failed");
58       return;
59     }
60 
61   // now open the tty
62   if ( (m_ttyFd = open(devPath, O_RDWR)) == -1)
63     {
64       throw std::runtime_error(std::string(__FUNCTION__) +
65                                ": open of " +
66                                string(devPath) + " failed: " +
67                                string(strerror(errno)));
68       return;
69     }
70 }
71 
~HMTRP()72 HMTRP::~HMTRP()
73 {
74   if (m_ttyFd != -1)
75     close(m_ttyFd);
76 }
77 
dataAvailable(unsigned int millis)78 bool HMTRP::dataAvailable(unsigned int millis)
79 {
80   if (m_ttyFd == -1)
81     return false;
82 
83   struct timeval timeout;
84 
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,int millis)101 int HMTRP::readData(char *buffer, int len, int millis)
102 {
103   if (m_ttyFd == -1)
104     return(-1);
105 
106   // if specified, wait to see if input shows up, otherwise block
107   if (millis >= 0)
108     {
109       if (!dataAvailable(millis))
110         return 0;               // timed out
111     }
112 
113   int rv = read(m_ttyFd, buffer, len);
114 
115   if (rv < 0)
116     {
117       throw std::runtime_error(std::string(__FUNCTION__) +
118                                ": read() failed: " +
119                                string(strerror(errno)));
120       return rv;
121     }
122 
123   return rv;
124 }
125 
writeData(char * buffer,int len)126 int HMTRP::writeData(char *buffer, int len)
127 {
128   if (m_ttyFd == -1)
129     return(-1);
130 
131   int rv = write(m_ttyFd, buffer, len);
132 
133   if (rv < 0)
134     {
135       throw std::runtime_error(std::string(__FUNCTION__) +
136                                ": write() failed: " +
137                                string(strerror(errno)));
138       return rv;
139     }
140 
141   tcdrain(m_ttyFd);
142 
143   return rv;
144 }
145 
setupTty(speed_t baud)146 bool HMTRP::setupTty(speed_t baud)
147 {
148   if (m_ttyFd == -1)
149     return(false);
150 
151   struct termios termio;
152 
153   // get current modes
154   tcgetattr(m_ttyFd, &termio);
155 
156   // setup for a 'raw' mode.  81N, no echo or special character
157   // handling, such as flow control.
158   cfmakeraw(&termio);
159 
160   // set our baud rates
161   cfsetispeed(&termio, baud);
162   cfsetospeed(&termio, baud);
163 
164   // make it so
165   if (tcsetattr(m_ttyFd, TCSAFLUSH, &termio) < 0)
166     {
167       throw std::runtime_error(std::string(__FUNCTION__) +
168                                ": tcsetattr() failed: " +
169                                string(strerror(errno)));
170       return false;
171     }
172 
173   return true;
174 }
175 
checkOK()176 bool HMTRP::checkOK()
177 {
178   char buf[4];
179 
180   int rv = readData(buf, 4, defaultDelay);
181 
182   if (rv != 4)
183     {
184       cerr << __FUNCTION__ << ": failed to receive OK response, rv = "
185            << rv << ", expected 4" << endl;
186       return false;
187     }
188 
189   // looking for "OK\r\n"
190   if (buf[0] == 'O' && buf[1] == 'K' &&
191       buf[2] == '\r' && buf[3] == '\n')
192     return true;
193   else
194     return false;
195 }
196 
reset()197 bool HMTRP::reset()
198 {
199   char pkt[3];
200 
201   pkt[0] = HMTRP_START1;
202   pkt[1] = HMTRP_START2;
203   pkt[2] = RESET;
204 
205   writeData(pkt, 3);
206 
207   return checkOK();
208 }
209 
getConfig(uint32_t * freq,uint32_t * dataRate,uint16_t * rxBandwidth,uint8_t * modulation,uint8_t * txPower,uint32_t * uartBaud)210 bool HMTRP::getConfig(uint32_t *freq, uint32_t *dataRate,
211                       uint16_t *rxBandwidth, uint8_t *modulation,
212                       uint8_t *txPower, uint32_t *uartBaud)
213 {
214   char pkt[3];
215   pkt[0] = HMTRP_START1;
216   pkt[1] = HMTRP_START2;
217   pkt[2] = GET_CONFIG;
218 
219   writeData(pkt, 3);
220   usleep(100000);
221 
222   // now read back a 16 byte response
223   char buf[16];
224   int rv = readData(buf, 16, defaultDelay);
225 
226   if (rv != 16)
227     {
228       cerr << __FUNCTION__ << ": failed to receive correct response: rv = "
229            << rv << ", expected 16" << endl;
230       return false;
231     }
232 
233   // now decode
234   if (freq)
235     {
236       *freq = ( ((buf[0] & 0xff) << 24) |
237                 ((buf[1] & 0xff) << 16) |
238                 ((buf[2] & 0xff) << 8)  |
239                  (buf[3] & 0xff) );
240     }
241 
242   if (dataRate)
243     {
244       *dataRate = ( ((buf[4] & 0xff) << 24) |
245                     ((buf[5] & 0xff) << 16) |
246                     ((buf[6] & 0xff) << 8)  |
247                      (buf[7] & 0xff) );
248     }
249 
250   if (rxBandwidth)
251     {
252       *rxBandwidth = ( ((buf[8] & 0xff) << 8) |
253                         (buf[9] & 0xff) );
254     }
255 
256   if (modulation)
257     {
258       *modulation = buf[10] & 0xff;
259     }
260 
261   if (txPower)
262     {
263       *txPower = buf[11] & 0xff;
264     }
265 
266   if (uartBaud)
267     {
268       *uartBaud = ( ((buf[12] & 0xff) << 24) |
269                     ((buf[13] & 0xff) << 16) |
270                     ((buf[14] & 0xff) << 8)  |
271                      (buf[15] & 0xff) );
272     }
273 
274   return true;
275 }
276 
setFrequency(uint32_t freq)277 bool HMTRP::setFrequency(uint32_t freq)
278 {
279   char pkt[7];
280 
281   pkt[0] = HMTRP_START1;
282   pkt[1] = HMTRP_START2;
283   pkt[2] = SET_FREQUENCY;
284 
285   pkt[3] = ( ((freq & 0xff000000) >> 24) & 0xff );
286   pkt[4] = ( ((freq & 0x00ff0000) >> 16) & 0xff );
287   pkt[5] = ( ((freq & 0x0000ff00) >> 8)  & 0xff );
288   pkt[6] = ( (freq & 0x000000ff) & 0xff );
289 
290   writeData(pkt, 7);
291 
292   return checkOK();
293 }
294 
setRFDataRate(uint32_t rate)295 bool HMTRP::setRFDataRate(uint32_t rate)
296 {
297   //  Valid values are between 1200-115200
298 
299   if (rate < 1200 || rate > 115200)
300     {
301       throw std::out_of_range(std::string(__FUNCTION__) +
302                               ": Valid rate values are between 1200-115200");
303       return false;
304     }
305 
306   char pkt[7];
307 
308   pkt[0] = HMTRP_START1;
309   pkt[1] = HMTRP_START2;
310   pkt[2] = SET_RF_DATARATE;
311 
312   pkt[3] = ( ((rate & 0xff000000) >> 24) & 0xff );
313   pkt[4] = ( ((rate & 0x00ff0000) >> 16) & 0xff );
314   pkt[5] = ( ((rate & 0x0000ff00) >> 8)  & 0xff );
315   pkt[6] = ( (rate & 0x000000ff) & 0xff );
316 
317   writeData(pkt, 7);
318 
319   return checkOK();
320 }
321 
setRXBandwidth(uint16_t rxBand)322 bool HMTRP::setRXBandwidth(uint16_t rxBand)
323 {
324   //  Valid values are between 30-620 (in Khz)
325 
326   if (rxBand < 30 || rxBand > 620)
327     {
328       throw std::out_of_range(std::string(__FUNCTION__) +
329                               ": Valid rxBand values are between 30-620");
330       return false;
331     }
332 
333   char pkt[5];
334 
335   pkt[0] = HMTRP_START1;
336   pkt[1] = HMTRP_START2;
337   pkt[2] = SET_RX_BW;
338 
339   pkt[3] = ( ((rxBand & 0xff00) >> 8) & 0xff );
340   pkt[4] = ( rxBand & 0xff );
341 
342   writeData(pkt, 5);
343 
344   return checkOK();
345 }
346 
setFrequencyModulation(uint8_t modulation)347 bool HMTRP::setFrequencyModulation(uint8_t modulation)
348 {
349   //  Valid values are between 10-160 (in Khz)
350 
351   if (modulation < 10 || modulation > 160)
352     {
353       throw std::out_of_range(std::string(__FUNCTION__) +
354                               ": Valid modulation values are between 10-160");
355       return false;
356     }
357 
358   char pkt[4];
359 
360   pkt[0] = HMTRP_START1;
361   pkt[1] = HMTRP_START2;
362   pkt[2] = SET_FREQ_MODULATION;
363 
364   pkt[3] = modulation;
365 
366   writeData(pkt, 4);
367 
368   return checkOK();
369 }
370 
setTransmitPower(uint8_t power)371 bool HMTRP::setTransmitPower(uint8_t power)
372 {
373   //  Valid values are between 0-7
374 
375   if (power > 7)
376     {
377       throw std::out_of_range(std::string(__FUNCTION__) +
378                               ": Valid power values are between 0-7");
379       return false;
380     }
381 
382   char pkt[4];
383 
384   pkt[0] = HMTRP_START1;
385   pkt[1] = HMTRP_START2;
386   pkt[2] = SET_TX_POWER;
387 
388   pkt[3] = power;
389 
390   writeData(pkt, 4);
391 
392   return checkOK();
393 }
394 
setUARTSpeed(uint32_t speed)395 bool HMTRP::setUARTSpeed(uint32_t speed)
396 {
397   //  Valid values are between 1200-115200
398 
399   if (speed < 1200 || speed > 115200)
400     {
401       throw std::out_of_range(std::string(__FUNCTION__) +
402                               ": Valid speed values are between 1200-115200");
403       return false;
404     }
405 
406   char pkt[7];
407 
408   pkt[0] = HMTRP_START1;
409   pkt[1] = HMTRP_START2;
410   pkt[2] = SET_UART_SPEED;
411 
412   pkt[3] = ( ((speed & 0xff000000) >> 24) & 0xff );
413   pkt[4] = ( ((speed & 0x00ff0000) >> 16) & 0xff );
414   pkt[5] = ( ((speed & 0x0000ff00) >> 8)  & 0xff );
415   pkt[6] = ( (speed & 0x000000ff) & 0xff );
416 
417   writeData(pkt, 7);
418 
419   return checkOK();
420 }
421 
422 
getRFSignalStrength(uint8_t * strength)423 bool HMTRP::getRFSignalStrength(uint8_t *strength)
424 {
425   if (!strength)
426     return false;
427 
428   *strength = 0;
429 
430   char pkt[3];
431   pkt[0] = HMTRP_START1;
432   pkt[1] = HMTRP_START2;
433   pkt[2] = GET_RF_SIGNAL_STR;
434 
435   writeData(pkt, 3);
436   usleep(100000);
437 
438   // now read back a 1 byte response
439   char buf;
440   int rv = readData(&buf, 1, defaultDelay);
441 
442   if (rv != 1)
443     {
444       cerr << __FUNCTION__ << ": failed to receive correct response: rv = "
445            << rv << ", expected 1" << endl;
446       return false;
447     }
448 
449   // now decode
450   *strength = (uint8_t)buf;
451 
452   return true;
453 }
454 
getModSignalStrength(uint8_t * strength)455 bool HMTRP::getModSignalStrength(uint8_t *strength)
456 {
457   if (!strength)
458     return false;
459 
460   *strength = 0;
461 
462   char pkt[3];
463   pkt[0] = HMTRP_START1;
464   pkt[1] = HMTRP_START2;
465   pkt[2] = GET_MOD_SIGNAL_STR;
466 
467   writeData(pkt, 3);
468   usleep(100000);
469 
470   // now read back a 1 byte response
471   char buf;
472   int rv = readData(&buf, 1, defaultDelay);
473 
474   if (rv != 1)
475     {
476       cerr << __FUNCTION__ << ": failed to receive correct response: rv = "
477            << rv << ", expected 1" << endl;
478       return false;
479     }
480 
481   // now decode
482   *strength = (uint8_t)buf;
483 
484   return true;
485 }
486 
487