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
31using namespace upm;
32using namespace std;
33
34static const int defaultDelay = 100;     // max wait time for read
35
36// protocol start code
37const uint8_t HMTRP_START1 = 0xaa;
38const uint8_t HMTRP_START2 = 0xfa;
39
40HMTRP::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
72HMTRP::~HMTRP()
73{
74  if (m_ttyFd != -1)
75    close(m_ttyFd);
76}
77
78bool 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
101int 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
126int 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
146bool 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
176bool 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
197bool 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
210bool 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
277bool 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
295bool 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
322bool 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
347bool 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
371bool 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
395bool 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
423bool 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
455bool 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