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