Hekateros  3.4.3
RoadNarrows Robotics Robot Arm Project
hekUno.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Hekateros
4 //
5 // Library: libhekateros
6 //
7 // File: hekUno.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2013-07-11 14:17:34 -0600 (Thu, 11 Jul 2013) $
12  * $Rev: 3113 $
13  *
14  * \brief \h_hek Arduino Uno compatible I/O board class implementation.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  * \author Daniel Packard (daniel@roadnarrows.com)
18  *
19  * \copyright
20  * \h_copy 2013-2017. RoadNarrows LLC.\n
21  * http://www.roadnarrows.com\n
22  * All Rights Reserved
23  */
24 /*
25  * @EulaBegin@
26  *
27  * Unless otherwise stated explicitly, all materials contained are copyrighted
28  * and may not be used without RoadNarrows LLC's written consent,
29  * except as provided in these terms and conditions or in the copyright
30  * notice (documents and software) or other proprietary notice provided with
31  * the relevant materials.
32  *
33  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
34  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
35  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
36  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
37  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
38  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
41  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
42  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
43  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
44  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
45  *
46  * @EulaEnd@
47  */
48 ////////////////////////////////////////////////////////////////////////////////
49 
50 #include <string>
51 #include <sstream>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <stdio.h>
55 
56 #include "rnr/rnrconfig.h"
57 #include "rnr/log.h"
58 #include "rnr/serdev.h"
59 
60 #include "Hekateros/hekateros.h"
61 #include "Hekateros/hekUno.h"
62 
63 using namespace std;
64 using namespace hekateros;
65 
66 HekUno::HekUno()
67 {
68  m_fd = -1;
69  m_uHekHwVer = 0;
70  m_nFwVer = 0;
71 
72  m_nFwOpState = -1;
73  m_nFwSeqNum = 0;
74 }
75 
76 HekUno::~HekUno()
77 {
78  close();
79 }
80 
81 int HekUno::open(uint_t uHekHwVer, const string& dev, int baud)
82 {
83  m_uHekHwVer = uHekHwVer;
84 
85  if( (m_fd = SerDevOpen(dev.c_str(), baud, 8, 'N', 1, 0, 0) ) == -1 )
86  {
87  LOGERROR("Failed to open Arduino digital I/O board");
88  return -HEK_ECODE_SYS;
89  }
90 
91  SerDevFIFOInputFlush(m_fd);
92 
93  // flush any residuals
94  cmdNull();
95 
96  //SerDevFIFOInputFlush(m_fd);
97 
98  LOGDIAG3("Opened Arduino compatible device: %s@%d", dev.c_str(), baud);
99 
100  return HEK_OK;
101 }
102 
103 int HekUno::close()
104 {
105  if( m_fd >= 0 )
106  {
107  ::close(m_fd);
108  m_fd = -1;
109  LOGDIAG3("Closed Arduino compatible device.");
110  }
111  m_uHekHwVer = 0;
112  m_nFwVer = 0;
113 }
114 
115 int HekUno::scan()
116 {
117  LOGDIAG3("Scanning Arduino digital I/O board capabilities.");
118 
119  //
120  // Read firmware version. Do this a few times to flush out any residual
121  // characters in arduino command pipeline.
122  //
123  for(int i=0; i<3; ++i)
124  {
125  cmdReadFwVersion(m_nFwVer);
126  cmdReadLimits();
127  if( m_nFwVer != 0 )
128  {
129  break;
130  }
131  }
132 
133  LOGDIAG3("Arduino firmware version %d.", m_nFwVer);
134 
135  return HEK_OK;
136 }
137 
138 int HekUno::cmdReadFwVersion(int &ver)
139 {
140  char cmd[] = "!v\r";
141  char rsp[16];
142  int n;
143 
144  ver = 0;
145 
146  sendCommand(cmd, strlen(cmd));
147 
148  n = recvResponse(rsp, sizeof(rsp), 200000);
149 
150  if( n > 1 )
151  {
152  ver = atoi(rsp+1);
153  return HEK_OK;
154  }
155  else
156  {
157  LOGERROR("Failed to read firmware version.");
158  return -HEK_ECODE_NO_EXEC;
159  }
160 }
161 
162 byte_t HekUno::cmdReadLimits()
163 {
164  char cmd[] = "!o\r";
165  char rsp[16];
166  int n;
167  byte_t val = 0;
168 
169  sendCommand(cmd, strlen(cmd));
170 
171  n = recvResponse(rsp, sizeof(rsp));
172 
173  if( n > 2 )
174  {
175  val = unpackHex(rsp+1);
176  }
177  else
178  {
179  LOGERROR("Failed to read optical limits.");
180  return -HEK_ECODE_NO_EXEC;
181  }
182 
183 //fprintf(stderr, "received %x from uno.\n", val);
184 
185  return val;
186 }
187 
188 byte_t HekUno::cmdReadAux()
189 {
190  char cmd[] = "!e\r";
191  char rsp[16];
192  int n;
193  byte_t val = 0;
194 
195  sendCommand(cmd, strlen(cmd));
196 
197  n = recvResponse(rsp, sizeof(rsp));
198 
199  if( n > 2 )
200  {
201  val = unpackHex(rsp+1);
202  }
203 
204  return val;
205 }
206 
207 int HekUno::cmdReadPin(int id)
208 {
209  char cmd[16];
210  char rsp[16];
211  int n;
212  int val;
213 
214  sprintf(cmd, "!r %d\r", id);
215  sendCommand(cmd, strlen(cmd));
216 
217  n = recvResponse(rsp, sizeof(rsp));
218 
219  if( n > 1 )
220  {
221  val = atoi(rsp);
222  }
223 
224  return val;
225 }
226 
227 int HekUno::cmdWritePin(int id, int val)
228 {
229  char cmd[16];
230  char rsp[16];
231  int n;
232 
233  sprintf(cmd, "!w %d %d\r", id, val? 1: 0);
234  sendCommand(cmd, strlen(cmd));
235 
236  n = recvResponse(rsp, sizeof(rsp));
237 
238  if( (n < 1) || (rsp[0] != '@') )
239  {
240  return -HEK_ECODE_NO_EXEC;
241  }
242  else
243  {
244  return HEK_OK;
245  }
246 }
247 
248 int HekUno::cmdConfigPin(int id, char dir)
249 {
250  char cmd[16];
251  char rsp[16];
252  int c;
253  int n;
254 
255  if( dir == 'i' )
256  {
257  c = 0;
258  }
259  else if( dir == 'o' )
260  {
261  c = 1;
262  }
263  else
264  {
265  return -HEK_ECODE_BAD_VAL;
266  }
267 
268  sprintf(cmd, "!c %d %d\r", id, c);
269  sendCommand(cmd, strlen(cmd));
270 
271  n = recvResponse(rsp, sizeof(rsp));
272 
273  if( (n < 1) || (rsp[0] != '@') )
274  {
275  return -HEK_ECODE_NO_EXEC;
276  }
277  else
278  {
279  return HEK_OK;
280  }
281 }
282 
283 int HekUno::cmdSetAlarmLED(int val)
284 {
285  char cmd[16];
286  char rsp[16];
287  int n;
288 
289  if( m_uHekHwVer < HEK_VERSION(1, 2, 0) )
290  {
291  return cmdWritePin(5, val);
292  }
293 
294  sprintf(cmd, "!l 1 %d\r", val? 1: 0);
295  sendCommand(cmd, strlen(cmd));
296 
297  n = recvResponse(rsp, sizeof(rsp));
298 
299  if( (n < 1) || (rsp[0] != '@') )
300  {
301  return -HEK_ECODE_NO_EXEC;
302  }
303  else
304  {
305  return HEK_OK;
306  }
307 }
308 
309 int HekUno::cmdSetStatusLED(int val)
310 {
311  char cmd[16];
312  char rsp[16];
313  int n;
314 
315  if( m_uHekHwVer < HEK_VERSION(1, 2, 0) )
316  {
317  return HEK_OK;
318  }
319 
320  sprintf(cmd, "!l 2 %d\r", val? 1: 0);
321  sendCommand(cmd, strlen(cmd));
322 
323  n = recvResponse(rsp, sizeof(rsp));
324 
325  if( (n < 1) || (rsp[0] != '@') )
326  {
327  return -HEK_ECODE_NO_EXEC;
328  }
329  else
330  {
331  return HEK_OK;
332  }
333 }
334 
335 int HekUno::cmdSetHaltedState()
336 {
337  char cmd[] = "!h\r";
338  char rsp[16];
339  int n;
340 
341  if( m_uHekHwVer < HEK_VERSION(1, 2, 0) )
342  {
343  return HEK_OK;
344  }
345 
346  sendCommand(cmd, strlen(cmd));
347 
348  n = recvResponse(rsp, sizeof(rsp));
349 
350  if( (n < 1) || (rsp[0] != '@') )
351  {
352  return -HEK_ECODE_NO_EXEC;
353  }
354  else
355  {
356  return HEK_OK;
357  }
358 }
359 
360 int HekUno::cmdTestInterface()
361 {
362  char cmd[] = "!t\r";
363  char rsp[16];
364  int n;
365  int nOpState;
366  int nSeqNum;
367 
368  if( m_nFwVer >= 3 )
369  {
370  sendCommand(cmd, strlen(cmd));
371 
372  n = recvResponse(rsp, sizeof(rsp));
373 
374  if( (n < 1) || (rsp[0] != '@') )
375  {
376  return -HEK_ECODE_NO_EXEC;
377  }
378 
379  n = sscanf(&rsp[1], "%d %d", &nOpState, &nSeqNum);
380 
381  if( n != 2 )
382  {
383  LOGERROR("Failed test of interface: bad response.");
384  return -HEK_ECODE_NO_EXEC;
385  }
386 
387  if( nOpState != m_nFwOpState )
388  {
389  fprintf(stderr, "ARDUINO TEST: New OpState=%d\n", m_nFwOpState);
390  }
391 
392  if( nSeqNum != m_nFwSeqNum )
393  {
394  fprintf(stderr, "ARDUINO TEST: Lost sync: Sequence number received=%d, "
395  "expected=%d\n", nSeqNum, m_nFwSeqNum);
396  }
397 
398  m_nFwOpState = nOpState;
399  m_nFwSeqNum = (nSeqNum + 1) & 0xff;
400  }
401 
402  return HEK_OK;
403 }
404 
405 int HekUno::cmdNull()
406 {
407  char cmd[] = "\r";
408  char rsp[16];
409  int n;
410 
411  sendCommand(cmd, strlen(cmd));
412 
413  n = recvResponse(rsp, sizeof(rsp), 2000000);
414 
415  return HEK_OK;
416 }
417 
418 int HekUno::sendCommand(char *buf, size_t nBytes, uint_t timeout)
419 {
420  SerDevWrite(m_fd, (byte_t *)buf, nBytes, timeout);
421  SerDevFIFOOutputDrain(m_fd);
422  return HEK_OK;
423 }
424 
425 int HekUno::recvResponse(char buf[], size_t count, uint_t timeout)
426 {
427  char c;
428  ssize_t nBytes=0;
429 
430  // grab actual response
431  nBytes = SerDevReadLine(m_fd, buf, count, (char *)"\n\r", timeout);
432 
433 #ifdef MON_DEBUG
434  fprintf(stderr, "DBG - received(%zd): ", nBytes);
435  for(ssize_t i=0; i<nBytes; ++i)
436  {
437  fprintf(stderr, "%x ", buf[i]);
438  }
439  fprintf(stderr, "\n");
440 #endif // MON_DEBUG
441 
442  return (int)nBytes;
443 }
444 
445 byte_t HekUno::unpackHex(char buf[])
446 {
447  byte_t val = 0;
448 
449  //
450  // Parse 2 character hex.
451  //
452  for(int i=0; i<2; ++i)
453  {
454  val *= 16;
455  if(buf[i] >= '0' && buf[i] <='9')
456  {
457  val += buf[i] - '0';
458  }
459 
460  else if (buf[i] >= 'A' && buf[i] <= 'F')
461  {
462  val += buf[i] -'A'+10;
463  }
464 
465  else if (buf[i] >= 'a' && buf[i] <= 'f')
466  {
467  val += buf[i] -'a'+10;
468  }
469  }
470 
471  return val;
472 }
<b><i>Hekateros</i></b> Arduino Uno compatible I/O board class interface.
Top-level package include file.
#define HEK_VERSION(major, minor, revision)
Convert version triplet to integer equivalent.
Definition: hekateros.h:185
The <b><i>Hekateros</i></b> namespace encapsulates all <b><i>Hekateros</i></b> related constructs...
Definition: hekateros.h:56