Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
laeWd.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // File: laeWd.cxx
6 //
7 /*! \file
8  *
9  * \brief Laelaps WatchDog software class implementation.
10  *
11  * The class provides the interface between the library software and the
12  * Arduino sub-processor.
13  *
14  * The Wd class is safe multi-threading.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \par Copyright
19  * \h_copy 2015-2017. RoadNarrows LLC.\n
20  * http://www.roadnarrows.com\n
21  * All Rights Reserved
22  */
23 /*
24  * @EulaBegin@
25  *
26  * Unless otherwise stated explicitly, all materials contained are copyrighted
27  * and may not be used without RoadNarrows LLC's written consent,
28  * except as provided in these terms and conditions or in the copyright
29  * notice (documents and software) or other proprietary notice provided with
30  * the relevant materials.
31  *
32  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
33  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
34  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
35  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
36  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
37  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
40  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
41  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
42  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
43  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
44  *
45  * @EulaEnd@
46  */
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 #include <sys/types.h>
50 #include <unistd.h>
51 #include <pthread.h>
52 
53 #include <string>
54 
55 #include "rnr/rnrconfig.h"
56 #include "rnr/log.h"
57 #include "rnr/appkit/Time.h"
58 
59 #include "Laelaps/laelaps.h"
60 #include "Laelaps/laeUtils.h"
61 #include "Laelaps/laeDesc.h"
62 #include "Laelaps/laeTune.h"
63 #include "Laelaps/laeDb.h"
64 #include "Laelaps/laeI2C.h"
65 #include "Laelaps/laeWatchDog.h"
66 #include "Laelaps/laeWd.h"
67 
68 using namespace std;
69 using namespace laelaps;
70 
71 #undef WD_DBG_ENABLE ///< debug switch
72 #ifdef WD_DBG_ENABLE
73 
74 /*!
75  * \brief Debug print response buffer
76  * \param cmd Command number.
77  * \param buf Buffer to print.
78  * \param len Buffer length.
79  * \param fmt Format string.
80  * \param ... Optional variable arguments for fmt.
81  */
82 #define WD_DBG_BUF(cmd, buf, len, fmt, ...) \
83  do \
84  { \
85  fprintf(stderr, "DBG: %s[%d]: Wd: Cmd=%d " fmt, \
86  __FILE__, __LINE__, cmd, ##__VA_ARGS__); \
87  for(int i=0;i<len; ++i) { fprintf(stderr, "0x%02x ", buf[i]); } \
88  fprintf(stderr, "\n"); \
89  } while(0)
90 
91 #else
92 
93 /*!
94  * \brief Debug print disabled.
95  */
96 #define WD_DBG_BUF(cmd, buf, len, fmt, ...)
97 
98 #endif // WD_DBG_ENABLE
99 
100 //
101 // Local data.
102 //
103 static uint_t FWVER_UNKNOWN = 0; ///< unknown firmware version
104 
105 static long TStd = 100; ///< standard wait time between write_read (usec)
106 static long TMc = 250000; ///< motor controller power up wait time (usec)
107 
108 
109 //------------------------------------------------------------------------------
110 // LaeWd Class
111 //------------------------------------------------------------------------------
112 
113 LaeWd::LaeWd(LaeI2C &i2cBus, uint_t addr) :
114  m_i2cBus(i2cBus), m_addrSubProc(addr)
115 {
116  // shadow values
119  m_bBatteryIsCharging = false;
120  m_fBatteryVoltage = 0.0;
121  m_fJackVoltage = 0.0;
124  m_bMotorCtlrEn = false;
125  m_bAuxPortBattEn = false;
126  m_bAuxPort5vEn = false;
127 
133 
134  pthread_mutex_init(&m_mutex, NULL);
135 }
136 
138 {
139  pthread_mutex_destroy(&m_mutex);
140 }
141 
143 {
144  uint_t uFwVer;
145  double fJackV, fBattV;
146 
147  cmdGetFwVersion(uFwVer); // must be first
148  cmdEnableMotorCtlrs(false);
149  cmdEnableAuxPort5V(true);
150  cmdEnableAuxPortBatt(true);
151  cmdReadVoltages(fJackV, fBattV);
154  cmdResetRgbLed();
156  cmdPetTheDog();
157 }
158 
159 int LaeWd::configure(const LaeDesc &desc)
160 {
161  return LAE_OK;
162 }
163 
164 int LaeWd::configure(const LaeTunes &tunes)
165 {
166  unsigned long uTimeout;
167  int rc;
168 
169  // convert to milliseconds
170  uTimeout = (unsigned long)(tunes.getWatchDogTimeout() * 1000.0);
171 
172  rc = cmdConfigOperation(uTimeout);
173 
174  if( rc == LAE_OK )
175  {
176  LOGDIAG2("Tuned WatchDog.");
177  }
178 
179  return rc;
180 }
181 
182 int LaeWd::reload(const LaeTunes &tunes)
183 {
184  LOGDIAG2("Reloading WatchDog tuning parameters...");
185  return configure(tunes);
186 }
187 
189 {
190  uint_t uBattSoC;
191  uint_t uAlarms;
192  double fJackV, fBattV;
193  bool bMotorCtlrEn, bAuxPort5vEn, bAuxPortBattEn;
194 
195  cmdPetTheDog();
196 
197  cmdReadVoltages(fJackV, fBattV);
198  cmdReadEnables(bMotorCtlrEn, bAuxPort5vEn, bAuxPortBattEn);
199 
200  uBattSoC = (uint_t)RtDb.m_energy.m_fBatterySoC;
201 
202  if( uBattSoC != m_uBatterySoC )
203  {
204  cmdSetBatterySoC(uBattSoC);
205  }
206 
207  uAlarms = determineAlarms();
208 
209  if( uAlarms != m_uAlarms )
210  {
211  cmdSetAlarms(uAlarms);
212  }
213 }
214 
216 {
217  byte_t cmd[LaeWdMaxCmdLen];
218  byte_t rsp[LaeWdMaxRspLen];
219  size_t lenCmd = 0;
220  size_t lenRsp;
221  bool bBatteryIsCharging;
222  int n;
223  int rc;
224 
225  lock();
226 
227  cmd[lenCmd++] = LaeWdCmdIdPetDog;
228 
229  // unknown version
230  if( m_uFwVer == FWVER_UNKNOWN )
231  {
232  rc = LAE_OK;
233  }
234 
235  // version 1
236  else if( m_uFwVer <= 1 )
237  {
238  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
239 
240  rc = (n == (int)lenCmd)? LAE_OK: -LAE_ECODE_IO;
241  }
242 
243  // versions 2+
244  else
245  {
246  lenRsp = LaeWdRspLenPetDog_2;
247 
248  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
249 
250  if( rc == LAE_OK )
251  {
252  bBatteryIsCharging = rsp[0] == LaeWdArgDPinValHigh? true: false;
253  m_bBatteryIsCharging = bBatteryIsCharging;
255  }
256  }
257 
258  unlock();
259 
260  return rc;
261 }
262 
263 int LaeWd::cmdGetFwVersion(uint_t &uVerNum)
264 {
265  byte_t cmd[LaeWdMaxCmdLen];
266  byte_t rsp[LaeWdMaxRspLen];
267  size_t lenCmd = 0;
268  size_t lenRsp = LaeWdRspLenGetVersion;
269  int rc;
270 
271  lock();
272 
273  cmd[lenCmd++] = LaeWdCmdIdGetVersion;
274 
275  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
276 
277  if( rc == LAE_OK )
278  {
279  uVerNum = (uint_t)rsp[0];
280  m_uFwVer = uVerNum;
282  }
283 
284  unlock();
285 
286  return rc;
287 }
288 
289 int LaeWd::cmdSetBatterySoC(uint_t uBatterySoC)
290 {
291  byte_t cmd[LaeWdMaxCmdLen];
292  size_t lenCmd = 0;
293  int n;
294  int rc;
295 
296  lock();
297 
298  if( uBatterySoC > LaeWdArgBattSoCMax )
299  {
300  uBatterySoC = LaeWdArgBattSoCMax;
301  }
302 
303  cmd[lenCmd++] = LaeWdCmdIdSetBattCharge;
304  cmd[lenCmd++] = (byte_t)uBatterySoC;
305 
306  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
307 
308  if( n == (int)lenCmd )
309  {
310  m_uBatterySoC = uBatterySoC;
311  rc = LAE_OK;
312  }
313  else
314  {
315  rc = -LAE_ECODE_IO;
316  }
317 
318  unlock();
319 
320  return rc;
321 }
322 
323 int LaeWd::cmdSetAlarms(uint_t uAlarms)
324 {
325  byte_t cmd[LaeWdMaxCmdLen];
326  size_t lenCmd = 0;
327  int n;
328  int rc;
329 
330  lock();
331 
332  cmd[lenCmd++] = LaeWdCmdIdSetAlarms;
333  cmd[lenCmd++] = (byte_t)((uAlarms >> 8) & 0xff);
334  cmd[lenCmd++] = (byte_t)(uAlarms & 0xff);
335 
336  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
337 
338  if( n == (int)lenCmd )
339  {
340  m_uAlarms = uAlarms;
341  rc = LAE_OK;
342  }
343  else
344  {
345  rc = -LAE_ECODE_IO;
346  }
347 
348  unlock();
349 
350  return rc;
351 }
352 
353 int LaeWd::cmdSetRgbLed(uint_t red, uint_t green, uint_t blue)
354 {
355  byte_t cmd[LaeWdMaxCmdLen];
356  size_t lenCmd = 0;
357  int n;
358  int rc;
359 
360  lock();
361 
362  cmd[lenCmd++] = LaeWdCmdIdSetRgbLed;
363  cmd[lenCmd++] = (byte_t)red;
364  cmd[lenCmd++] = (byte_t)green;
365  cmd[lenCmd++] = (byte_t)blue;
366 
367  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
368 
369  rc = (n == (int)lenCmd)? LAE_OK: -LAE_ECODE_IO;
370 
371  unlock();
372 
373  return rc;
374 }
375 
377 {
378  byte_t cmd[LaeWdMaxCmdLen];
379  size_t lenCmd = 0;
380  int n;
381  int rc;
382 
383  lock();
384 
385  cmd[lenCmd++] = LaeWdCmdIdResetRgbLed;
386 
387  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
388 
389  rc = (n == (int)lenCmd)? LAE_OK: -LAE_ECODE_IO;
390 
391  unlock();
392 
393  return rc;
394 }
395 
396 int LaeWd::cmdConfigDPin(uint_t pin, uint_t dir)
397 {
398  byte_t cmd[LaeWdMaxCmdLen];
399  size_t lenCmd = 0;
400  int n;
401  int rc;
402 
403  lock();
404 
405  // unknown firmware version
406  if( m_uFwVer == FWVER_UNKNOWN )
407  {
408  rc = LAE_OK;
409  }
410 
411  // deprecated
412  else if( m_uFwVer >= 3 )
413  {
414  rc = LAE_OK;
415  }
416 
417  // supported
418  else
419  {
420  if( (pin < LaeWdArgDPinNumWMin) || (pin > LaeWdArgDPinNumWMax) )
421  {
422  LOGERROR("Pin %u: Out-of-range.", pin);
423  rc = -LAE_ECODE_BAD_VAL;
424  }
425 
426  else
427  {
428  dir = dir > 0? LaeWdArgDPinDirOut: LaeWdArgDPinDirIn;
429 
430  cmd[lenCmd++] = LaeWdCmdIdConfigDPin;
431  cmd[lenCmd++] = (byte_t)pin;
432  cmd[lenCmd++] = (byte_t)dir;
433 
434  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
435 
436  rc = (n == (int)lenCmd)? LAE_OK: -LAE_ECODE_IO;
437  }
438  }
439 
440  unlock();
441 
442  return rc;
443 }
444 
445 int LaeWd::cmdReadDPin(uint_t pin, uint_t &val)
446 {
447  byte_t cmd[LaeWdMaxCmdLen];
448  byte_t rsp[LaeWdMaxRspLen];
449  size_t lenCmd = 0;
450  size_t lenRsp = LaeWdRspLenReadDPin;
451  int rc;
452 
453  lock();
454 
455  // unknown firmware version
456  if( m_uFwVer == FWVER_UNKNOWN )
457  {
458  val = 0;
459  rc = LAE_OK;
460  }
461 
462  // deprecated
463  else if( m_uFwVer >= 3 )
464  {
465  val = 0;
466  rc = LAE_OK;
467  }
468 
469  // supported
470  else
471  {
472  if( (pin < LaeWdArgDPinNumMin) || (pin > LaeWdArgDPinNumMax) )
473  {
474  LOGERROR("Pin %u: Out-of-range.", pin);
475  rc = -LAE_ECODE_BAD_VAL;
476  }
477 
478  else
479  {
480  cmd[lenCmd++] = LaeWdCmdIdReadDPin;
481  cmd[lenCmd++] = (byte_t)pin;
482 
483  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
484 
485  if( rc == LAE_OK )
486  {
487  if( (uint_t)rsp[0] != pin )
488  {
489  WD_DBG_BUF(LaeWdCmdIdReadDPin, rsp, n, "pin=%d rsp=", pin);
490  LOGERROR("Response pin %u != pin %u.", (uint_t)rsp[0], pin);
491  rc = -LAE_ECODE_BAD_VAL;
492  }
493  else
494  {
495  val = (uint_t)rsp[1];
496  }
497  }
498  }
499  }
500 
501  unlock();
502 
503  return rc;
504 }
505 
506 int LaeWd::cmdWriteDPin(uint_t pin, uint_t val)
507 {
508  byte_t cmd[LaeWdMaxCmdLen];
509  size_t lenCmd = 0;
510  int n;
511  int rc;
512 
513  lock();
514 
515  // unknown firmware version
516  if( m_uFwVer == FWVER_UNKNOWN )
517  {
518  rc = LAE_OK;
519  }
520 
521  // deprecated
522  else if( m_uFwVer >= 3 )
523  {
524  rc = LAE_OK;
525  }
526 
527  // supported
528  else
529  {
530  if( (pin < LaeWdArgDPinNumWMin) || (pin > LaeWdArgDPinNumWMax) )
531  {
532  LOGERROR("Pin %u: Out-of-range.", pin);
533  rc = -LAE_ECODE_BAD_VAL;
534  }
535 
536  else
537  {
538  val = val > 0? LaeWdArgDPinValHigh: LaeWdArgDPinValLow;
539 
540  cmd[lenCmd++] = LaeWdCmdIdWriteDPin;
541  cmd[lenCmd++] = (byte_t)pin;
542  cmd[lenCmd++] = (byte_t)val;
543 
544  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
545 
546  rc = (n == (int)lenCmd)? LAE_OK: -LAE_ECODE_IO;
547  }
548  }
549 
550  unlock();
551 
552  return rc;
553 }
554 
555 int LaeWd::cmdReadAPin(uint_t pin, uint_t &val)
556 {
557  byte_t cmd[LaeWdMaxCmdLen];
558  byte_t rsp[LaeWdMaxRspLen];
559  size_t lenCmd = 0;
560  size_t lenRsp = LaeWdRspLenReadAPin;
561  int rc;
562 
563  lock();
564 
565  // unknown firmware version
566  if( m_uFwVer == FWVER_UNKNOWN )
567  {
568  val = 0;
569  rc = LAE_OK;
570  }
571 
572  // deprecated
573  else if( m_uFwVer >= 3 )
574  {
575  val = 0;
576  rc = LAE_OK;
577  }
578 
579  // supported
580  else
581  {
582  if( (pin < LaeWdArgAInPinNumMin) || (pin > LaeWdArgAInPinNumMax) )
583  {
584  LOGERROR("Pin %u: Out-of-range.", pin);
585  rc = -LAE_ECODE_BAD_VAL;
586  }
587 
588  else
589  {
590  cmd[lenCmd++] = LaeWdCmdIdReadAPin;
591  cmd[lenCmd++] = (byte_t)pin;
592 
593  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
594 
595  if( rc == LAE_OK )
596  {
597  if( (uint_t)rsp[0] != pin )
598  {
599  WD_DBG_BUF(LaeWdCmdIdReadAPin, rsp, n, "pin=%d rsp=", pin);
600  LOGERROR("Response pin %u != pin %u.", (uint_t)rsp[0], pin);
601  rc = -LAE_ECODE_BAD_VAL;
602  }
603  else
604  {
605  val = (uint_t)((((uint_t)rsp[1]) << 8) | (((uint_t)rsp[2]) & 0xff));
606  }
607  }
608  }
609  }
610 
611  unlock();
612 
613  return rc;
614 }
615 
616 int LaeWd::cmdWriteAPin(uint_t pin, uint_t val)
617 {
618  byte_t cmd[LaeWdMaxCmdLen];
619  size_t lenCmd = 0;
620  int n;
621  int rc;
622 
623  lock();
624 
625  // unknown firmware version
626  if( m_uFwVer == FWVER_UNKNOWN )
627  {
628  rc = LAE_OK;
629  }
630 
631  // deprecated
632  else if( m_uFwVer >= 3 )
633  {
634  rc = LAE_OK;
635  }
636 
637  // supported
638  else
639  {
640  if( (pin < LaeWdArgAOutPinNumMin) || (pin > LaeWdArgAOutPinNumMax) )
641  {
642  LOGERROR("Pin %u: Out-of-range.", pin);
643  rc = -LAE_ECODE_BAD_VAL;
644  }
645 
646  else
647  {
648  if( val > LaeWdArgAOutPinValMax )
649  {
650  val = LaeWdArgAOutPinValMax;
651  }
652 
653  cmd[lenCmd++] = LaeWdCmdIdWriteAPin;
654  cmd[lenCmd++] = (byte_t)pin;
655  cmd[lenCmd++] = (byte_t)val;
656 
657  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
658 
659  rc = (n == (int)lenCmd)? LAE_OK: -LAE_ECODE_IO;
660  }
661  }
662 
663  unlock();
664 
665  return rc;
666 }
667 
668 int LaeWd::cmdEnableMotorCtlrs(bool bEnable)
669 {
670  byte_t cmd[LaeWdMaxCmdLen];
671  byte_t rsp[LaeWdMaxRspLen];
672  size_t lenCmd = 0;
673  size_t lenRsp = LaeWdRspLenEnableMotorCtlrs;
674  bool bPass;
675  int nTries;
676  int nMaxTries = 3;
677  int rc;
678 
679  lock();
680 
681  // old versions had no hardware control to enable power - always enabled
682  if( m_uFwVer < 2 )
683  {
684  bEnable = true;
685  rc = LAE_OK;
686  }
687 
688  // new versions control in-power to motor controllers
689  else
690  {
691  cmd[lenCmd++] = LaeWdCmdIdEnableMotorCtlrs;
692  cmd[lenCmd++] = bEnable? LaeWdArgDPinValHigh: LaeWdArgDPinValLow;
693 
694  // really try to set the motor controller power-in state
695  for(nTries = 0, bPass = false; (nTries < nMaxTries) && !bPass; ++nTries)
696  {
697  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, 5000);
698 
699  if( (rc == LAE_OK) && (rsp[0] == LaeWdArgPass) )
700  {
701  bPass = true;
702  }
703  else
704  {
705  usleep(50);
706  }
707  }
708 
709  // pass
710  if( bPass )
711  {
712  // give time for motor controllers to power up
713  if( bEnable )
714  {
715  usleep(TMc);
716  }
717 
718  rc = LAE_OK;
719  }
720 
721  // fail
722  else
723  {
724  rc = -LAE_ECODE_IO;
725  }
726  }
727 
728  if( rc == LAE_OK )
729  {
730  // disable to enable
731  if( !m_bMotorCtlrEn && bEnable)
732  {
733  LOGDIAG1("Enabled motor controllers.");
734  m_timeMotorCtlrs.markNow();
735  }
736 
737  // enable to disable
738  else if( m_bMotorCtlrEn && !bEnable )
739  {
740  double t = m_timeMotorCtlrs.now();
741  LOGDIAG1("Motor controllers disabled: Uptime: %.4lfs.",
742  t - m_timeMotorCtlrs.t());
743  }
744 
745  m_bMotorCtlrEn = bEnable;
747  }
748 
749  else
750  {
751  LOGERROR("Failed to %s motor controllers.", (bEnable? "enable": "disable"));
752  }
753 
754  unlock();
755 
756  return rc;
757 }
758 
759 int LaeWd::cmdEnableAuxPort5V(bool bEnable)
760 {
761  byte_t cmd[LaeWdMaxCmdLen];
762  size_t lenCmd = 0;
763  int n;
764  int rc;
765 
766  lock();
767 
768  // old versions had no hardware control to enable power - always enabled
769  if( m_uFwVer < 2 )
770  {
771  bEnable = true;
772  rc = LAE_OK;
773  }
774 
775  // new versions control out-power to deck auxilliary ports
776  else
777  {
778  cmd[lenCmd++] = LaeWdCmdIdEnableAuxPort;
779  cmd[lenCmd++] = LaeWdArgAuxPort5V;
780  cmd[lenCmd++] = bEnable? LaeWdArgDPinValHigh: LaeWdArgDPinValLow;
781 
782  // enable/disable aux port
783  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
784 
785  rc = (n == (int)lenCmd)? LAE_OK: -LAE_ECODE_IO;
786  }
787 
788  if( rc == LAE_OK )
789  {
790  if( m_bAuxPort5vEn != bEnable )
791  {
792  LOGDIAG2("%s 5V aux port.", (bEnable? "Enabled": "Disabled"));
793  }
794  m_bAuxPort5vEn = bEnable;
796  }
797 
798  else
799  {
800  LOGERROR("Failed to %s 5V aux port.", (bEnable? "enable": "disable"));
801  }
802 
803  unlock();
804 
805  return rc;
806 }
807 
809 {
810  byte_t cmd[LaeWdMaxCmdLen];
811  size_t lenCmd = 0;
812  int n;
813  int rc;
814 
815  lock();
816 
817  // old versions had no hardware control to enable power - always enabled
818  if( m_uFwVer < 2 )
819  {
820  bEnable = true;
821  rc = LAE_OK;
822  }
823 
824  // new versions control out-power to deck auxilliary ports
825  else
826  {
827  cmd[lenCmd++] = LaeWdCmdIdEnableAuxPort;
828  cmd[lenCmd++] = LaeWdArgAuxPortBatt;
829  cmd[lenCmd++] = bEnable? LaeWdArgDPinValHigh: LaeWdArgDPinValLow;
830 
831  // enable/disable aux port
832  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
833 
834  rc = (n == (int)lenCmd)? LAE_OK: -LAE_ECODE_IO;
835  }
836 
837  if( rc == LAE_OK )
838  {
839  if( m_bAuxPortBattEn != bEnable )
840  {
841  LOGDIAG2("%s battery aux port.", (bEnable? "Enabled": "Disabled"));
842  }
843  m_bAuxPortBattEn = bEnable;
845  }
846 
847  else
848  {
849  LOGERROR("Failed to %s battery aux port.", (bEnable? "enable": "disable"));
850  }
851 
852  unlock();
853 
854  return rc;
855 }
856 
857 int LaeWd::cmdReadEnables(bool &bMotorCtlrEn,
858  bool &bAuxPort5vEn,
859  bool &bAuxPortBattEn)
860 {
861  byte_t cmd[LaeWdMaxCmdLen];
862  byte_t rsp[LaeWdMaxRspLen];
863  size_t lenCmd = 0;
864  size_t lenRsp = LaeWdRspLenReadEnables;
865  int rc;
866 
867  lock();
868 
869  // old versions had no hardware control to enable power - always enabled
870  if( m_uFwVer < 2 )
871  {
872  // return values
873  bMotorCtlrEn = true;
874  bAuxPort5vEn = true;
875  bAuxPortBattEn = true;
876  rc = LAE_OK;
877  }
878 
879  // new versions control power enable lines
880  else
881  {
882  cmd[lenCmd++] = LaeWdCmdIdReadEnables;
883 
884  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
885 
886  if( rc == LAE_OK )
887  {
888  // return values
889  bMotorCtlrEn = rsp[0] > 0? true: false;
890  bAuxPort5vEn = rsp[1] > 0? true: false;
891  bAuxPortBattEn = rsp[2] > 0? true: false;
892  }
893  }
894 
895  if( rc == LAE_OK )
896  {
897  // disable to enable
898  if( !m_bMotorCtlrEn && bMotorCtlrEn )
899  {
900  LOGDIAG1("Motor controllers enabled.");
901  m_timeMotorCtlrs.markNow();
902  }
903 
904  // enable to disable
905  else if( m_bMotorCtlrEn && !bMotorCtlrEn )
906  {
907  double t = m_timeMotorCtlrs.now();
908  LOGDIAG1("Motor controllers disabled: Uptime: %.4lfs.",
909  t - m_timeMotorCtlrs.t());
910  }
911 
912  // shadow
913  m_bMotorCtlrEn = bMotorCtlrEn;
914  m_bAuxPort5vEn = bAuxPort5vEn;
915  m_bAuxPortBattEn = bAuxPortBattEn;
916 
917  // real-time db
921  }
922 
923  else
924  {
925  LOGERROR("Failed to read enable lines.");
926  }
927 
928  unlock();
929 
930  return rc;
931 }
932 
933 int LaeWd::cmdReadVoltages(double &fJackV, double &fBattV)
934 {
935  byte_t cmd[LaeWdMaxCmdLen];
936  byte_t rsp[LaeWdMaxRspLen];
937  size_t lenCmd = 0;
938  size_t lenRsp = LaeWdRspLenReadVolts;
939  int rc;
940 
941  lock();
942 
943  // old versions had no hardware to sense voltages
944  if( m_uFwVer < 2 )
945  {
946  fJackV = 0.0;
947  fBattV = 0.0;
948  rc = LAE_OK;
949  }
950 
951  // new versions can sense input jack and battery output voltages
952  else
953  {
954  cmd[lenCmd++] = LaeWdCmdIdReadVolts;
955 
956  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
957 
958  if( rc == LAE_OK )
959  {
960  fJackV = (double)(rsp[0]) * LaeWdArgVScale;
961  fBattV = (double)(rsp[1]) * LaeWdArgVScale;
962  }
963  }
964 
965  if( rc == LAE_OK )
966  {
967  m_fBatteryVoltage = fBattV;
968  m_fJackVoltage = fJackV;
969 
972  }
973 
974  else
975  {
976  LOGERROR("Failed to read voltages.");
977  }
978 
979  unlock();
980 
981  return rc;
982 }
983 
984 int LaeWd::cmdTest(uint_t &uSeqNum,
985  uint_t &uOpState,
986  uint_t &uAlarms,
987  uint_t &uLedIndex)
988 {
989  byte_t cmd[LaeWdMaxCmdLen];
990  byte_t rsp[LaeWdMaxRspLen];
991  size_t lenCmd = 0;
992  size_t lenRsp = LaeWdRspLenTest;
993  int rc;
994 
995  lock();
996 
997  // old versions had a test command - deprecated
998  if( (m_uFwVer != FWVER_UNKNOWN) && (m_uFwVer < 3) )
999  {
1000  cmd[lenCmd++] = LaeWdCmdIdTest;
1001 
1002  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
1003 
1004  if( rc == LAE_OK )
1005  {
1006  uSeqNum = (uint_t)rsp[0];
1007  uOpState = (uint_t)rsp[1];
1008  uAlarms = (uint_t)((((uint_t)rsp[2]) << 8) | (((uint_t)rsp[3]) & 0xff));
1009  uLedIndex = (uint_t)rsp[4];
1010  }
1011  }
1012 
1013  // deprecated
1014  else
1015  {
1016  uSeqNum = 0;
1017  uOpState = 0;
1018  uAlarms = 0;
1019  uLedIndex = 0;
1020  rc = LAE_OK;
1021  }
1022 
1023  unlock();
1024 
1025  return rc;
1026 }
1027 
1028 int LaeWd::cmdConfigOperation(unsigned long uTimeout)
1029 {
1030  byte_t cmd[LaeWdMaxCmdLen];
1031  size_t lenCmd = 0;
1032  int n;
1033  int rc;
1034 
1035  lock();
1036 
1037  // no support in older versions
1038  if( m_uFwVer < 3 )
1039  {
1041  rc = LAE_OK;
1042  }
1043 
1044  else
1045  {
1046  cmd[lenCmd++] = LaeWdCmdIdConfigFw;
1047  cmd[lenCmd++] = (byte_t)((uTimeout >> 8) & 0xff);
1048  cmd[lenCmd++] = (byte_t)(uTimeout & 0xff);
1049 
1050  n = m_i2cBus.write(m_addrSubProc, cmd, lenCmd);
1051 
1052  if( n == (int)lenCmd )
1053  {
1054  m_uWatchdogTimeout = uTimeout;
1055  rc = LAE_OK;
1056  }
1057  else
1058  {
1059  rc = -LAE_ECODE_IO;
1060  }
1061  }
1062 
1063  if( rc == LAE_OK )
1064  {
1066  }
1067 
1068  unlock();
1069 
1070  return rc;
1071 }
1072 
1074 {
1075  uint_t uAlarms = LaeWdArgAlarmNone;
1076 
1077  //
1078  // Alarms.
1079  //
1081  {
1082  uAlarms |= LaeWdArgAlarmBatt;
1083  }
1085  {
1086  uAlarms |= LaeWdArgAlarmTemp;
1087  }
1089  {
1090  uAlarms |= LaeWdArgAlarmEStop;
1091  }
1092  if( RtDb.m_alarms.m_system.m_uAlarms & ~uAlarms )
1093  {
1094  uAlarms |= LaeWdArgAlarmGen;
1095  }
1096 
1097  //
1098  // Critical.
1099  //
1101  (uAlarms & ~((uint_t)LaeWdArgAlarmBatt)) )
1102  {
1103  uAlarms |= LaeWdArgAlarmCrit;
1104  }
1106  {
1107  uAlarms |= LaeWdArgAlarmBattCrit;
1108  }
1109 
1110  return uAlarms;
1111 }
1112 
1113 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1114 // Static functions.
1115 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1116 
1117 int LaeWd::enableMotorCtlrs(void *pArg, bool bEnable)
1118 {
1119  return ((LaeWd *)pArg)->cmdEnableMotorCtlrs(bEnable);
1120 }
const unsigned long LaeWdTimeoutDft
watchdog timeout default
Definition: laeWatchDog.h:83
const byte_t LaeWdCmdIdReadVolts
command id
Definition: laeWatchDog.h:425
virtual int cmdEnableMotorCtlrs(bool bEnable)
Enable/disable power in to motor controllers.
Definition: laeWd.cxx:668
ulong_t m_uWatchdogTimeout
watchdog timeout (msec)
Definition: laeWd.h:393
virtual int cmdReadDPin(uint_t pin, uint_t &val)
Read the value of a digital pin command.
Definition: laeWd.cxx:445
void lock()
Lock the shared resource.
Definition: laeWd.h:418
static long TMc
motor controller power up wait time (usec)
Definition: laeWd.cxx:106
#define WD_DBG_BUF(cmd, buf, len, fmt,...)
< debug switch
Definition: laeWd.cxx:96
double getWatchDogTimeout() const
Get watchdog timeout (seconds).
Definition: laeTune.cxx:334
uint_t m_uAlarms
alarms
Definition: laeWd.h:398
uint_t m_uBatterySoC
battery state of charge
Definition: laeWd.h:397
Laelaps tuning data class.
Definition: laeTune.h:566
const byte_t LaeWdArgDPinNumMin
min pin number
Definition: laeWatchDog.h:115
const int LaeWdArgAOutPinValMax
analog output maximum value
Definition: laeWatchDog.h:139
Laelaps robotic mobile platform full description class.
Definition: laeDesc.h:451
LaeDbProduct m_product
product data
Definition: laeDb.h:227
virtual int write_read(uint_t addr, const byte_t wbuf[], size_t wlen, byte_t rbuf[], size_t rlen, long usec=0)
Perform a write/read transaction to/from an I2C slave endpoint device.
Definition: laeI2C.cxx:249
bool m_bBatteryIsCharging
battery is [not] charging
Definition: laeWd.h:394
static long TStd
standard wait time between write_read (usec)
Definition: laeWd.cxx:105
const byte_t LaeWdArgDPinNumMax
max pin number
Definition: laeWatchDog.h:118
bool m_bMotorCtlrEn
motor controller enable
Definition: laeWd.h:399
const byte_t LaeWdCmdIdEnableMotorCtlrs
command id
Definition: laeWatchDog.h:365
double m_fJackVoltage
sensed power supply jack voltage
Definition: laeWd.h:396
const float LaeWdArgVScale
voltage scaler
Definition: laeWatchDog.h:430
const byte_t LaeWdCmdIdSetRgbLed
command id
Definition: laeWatchDog.h:248
const unsigned int LaeWdArgAlarmCrit
crit alarm modifier
Definition: laeWatchDog.h:102
const byte_t LaeWdArgAOutPinNumMin
analog output min pin number
Definition: laeWatchDog.h:135
const byte_t LaeWdCmdIdTest
command id
Definition: laeWatchDog.h:450
double m_fBatteryVoltage
sensed battery subsystem voltage (V)
Definition: laeDb.h:201
const unsigned int LaeWdArgAlarmEStop
emergency stop
Definition: laeWatchDog.h:100
static const int LAE_ECODE_IO
I/O error.
Definition: laelaps.h:98
virtual int cmdWriteDPin(uint_t pin, uint_t val)
Write a value to a digital pin command.
Definition: laeWd.cxx:506
virtual int configure(const LaeDesc &desc)
Configure watchdog from product description.
Definition: laeWd.cxx:159
const unsigned int LaeWdArgBattSoCMax
100% charge
Definition: laeWatchDog.h:91
const byte_t LaeWdRspLenEnableMotorCtlrs
response length (bytes)
Definition: laeWatchDog.h:367
double m_fBatterySoC
estimated battery state of charge (%)
Definition: laeDb.h:202
bool m_bBatteryIsCharging
batteries are [not] being charged
Definition: laeDb.h:199
virtual ~LaeWd()
Destructor.
Definition: laeWd.cxx:137
Laelaps WatchDog software class interface.
LaeAlarmInfo m_battery
battery subsystem alarm state
Definition: laeDb.h:213
const byte_t LaeWdArgAInPinNumMax
analog input max pin number
Definition: laeWatchDog.h:130
uint_t m_uFwVer
firmware version number
Definition: laeWd.h:390
virtual int cmdPetTheDog()
Pet the watchdog command.
Definition: laeWd.cxx:215
LaeDb RtDb
The real-time database.
Definition: laeDb.h:244
pthread_mutex_t m_mutex
mutex
Definition: laeWd.h:407
const byte_t LaeWdArgDPinValHigh
pin is high (Vcc)
Definition: laeWatchDog.h:124
const byte_t LaeWdRspLenTest
v1 response length (bytes)
Definition: laeWatchDog.h:452
const byte_t LaeWdCmdIdGetVersion
command id
Definition: laeWatchDog.h:200
Laelaps I2C class interface.
virtual int cmdEnableAuxPort5V(bool bEnable)
Enable/disable regulated 5 volt auxilliary port power out.
Definition: laeWd.cxx:759
LaeAlarmInfo m_system
system alarm summary state
Definition: laeDb.h:212
const byte_t LaeWdArgDPinDirIn
input
Definition: laeWatchDog.h:120
bool m_bAuxPortBatt
battery auxilliary port [not] enabled
Definition: laeDb.h:122
virtual int cmdResetRgbLed()
Reset the LED RGB color to state defaults.
Definition: laeWd.cxx:376
bool m_bIsCritical
is [not] critical alarm
Definition: laeAlarms.h:159
LaeI2C & m_i2cBus
bound I2C bus instance
Definition: laeWd.h:388
virtual int cmdSetBatterySoC(uint_t uBatterySoC)
Set battery&#39;s state of charge state command.
Definition: laeWd.cxx:289
virtual int cmdSetRgbLed(uint_t red, uint_t green, uint_t blue)
Set the LED RGB color command.
Definition: laeWd.cxx:353
const byte_t LaeWdRspLenGetVersion
response length (bytes)
Definition: laeWatchDog.h:202
const byte_t LaeWdCmdIdSetBattCharge
command id
Definition: laeWatchDog.h:215
double m_fWatchDogTimeout
watchdog timeout (seconds)
Definition: laeDb.h:98
const byte_t LaeWdCmdIdConfigFw
command id
Definition: laeWatchDog.h:471
const unsigned int LaeWdArgAlarmBatt
battery low alarm
Definition: laeWatchDog.h:98
void unlock()
Unlock the shared resource.
Definition: laeWd.h:429
const unsigned int LaeWdArgAlarmNone
no/clear alarms
Definition: laeWatchDog.h:96
bool m_bAuxPortBattEn
battery auxilliary port enable
Definition: laeWd.h:400
const byte_t LaeWdRspLenReadDPin
response length (bytes)
Definition: laeWatchDog.h:298
LaeDbEnable m_enable
key gpio state data
Definition: laeDb.h:230
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
Definition: laeAlarms.h:64
virtual int write(uint_t addr, const byte_t buf[], size_t len)
Write to an I2C slave endpoint device.
Definition: laeI2C.cxx:194
Laelaps robotic base mobile platform description class interface.
const byte_t LaeWdCmdIdConfigDPin
command id
Definition: laeWatchDog.h:278
const unsigned int LaeWdArgAlarmBattCrit
batt crit modifier
Definition: laeWatchDog.h:101
virtual int cmdReadVoltages(double &fJackV, double &fBattV)
Read sensed voltages.
Definition: laeWd.cxx:933
static const u32_t LAE_ALARM_TEMP
temperature alarm
Definition: laeAlarms.h:82
rnr::chronos::Time m_timeMotorCtlrs
motor controller up time
Definition: laeWd.h:404
double m_fBatteryVoltage
sensed battery voltage
Definition: laeWd.h:395
LaeDbEnergy m_energy
battery and energy data
Definition: laeDb.h:237
const byte_t LaeWdArgAuxPort5V
regulated 5 volt auxilliary port
Definition: laeWatchDog.h:386
double m_fJackVoltage
sensed power supply jack voltage
Definition: laeDb.h:200
Laelaps common utilities.
virtual int cmdTest(uint_t &uSeqNum, uint_t &uOpState, uint_t &uAlarms, uint_t &uLedIndex)
Test the firmware state command.
Definition: laeWd.cxx:984
const byte_t LaeWdCmdIdPetDog
command id
Definition: laeWatchDog.h:184
bool m_bAuxPort5vEn
5 volt auxilliary port enable
Definition: laeWd.h:401
uint_t m_uWatchDogFwVer
watchdog sub-processor firmware version
Definition: laeDb.h:84
const byte_t LaeWdCmdIdWriteDPin
command id
Definition: laeWatchDog.h:314
const byte_t LaeWdArgDPinNumWMax
max write/modify pin number
Definition: laeWatchDog.h:117
u32_t m_uAlarms
alarm or&#39;ed bits
Definition: laeAlarms.h:160
virtual int cmdReadAPin(uint_t pin, uint_t &val)
Read the value of an analog pin command.
Definition: laeWd.cxx:555
Laelaps tuning.
virtual void exec()
Execute cycle to pet/read/update Watchdog sub-processor.
Definition: laeWd.cxx:188
static const u32_t LAE_ALARM_ESTOP
emergency stop
Definition: laeAlarms.h:80
bool m_bMotorCtlr
motor controller [not] enabled
Definition: laeDb.h:121
const byte_t LaeWdArgAOutPinNumMax
analog output max pin number
Definition: laeWatchDog.h:136
const byte_t LaeWdCmdIdWriteAPin
command id
Definition: laeWatchDog.h:349
const byte_t LaeWdCmdIdSetAlarms
command id
Definition: laeWatchDog.h:231
Laelaps built-in Arduino sub-processor.
const byte_t LaeWdArgDPinNumWMin
min write/modify pin number
Definition: laeWatchDog.h:116
virtual int cmdGetFwVersion(uint_t &uVerNum)
Get the firmware version command.
Definition: laeWd.cxx:263
static const u32_t LAE_ALARM_BATT
battery low alarm
Definition: laeAlarms.h:81
static const int LAE_ECODE_BAD_VAL
bad value general error
Definition: laelaps.h:76
const byte_t LaeWdArgAuxPortBatt
battery auxlliary port
Definition: laeWatchDog.h:385
virtual int cmdReadEnables(bool &bMotorCtlrEn, bool &bAuxPort5vEn, bool &bAuxPortBattEn)
Read enable lines.
Definition: laeWd.cxx:857
const unsigned int LaeWdArgAlarmTemp
temperature alarm
Definition: laeWatchDog.h:99
uint_t m_addrSubProc
I2C sub-processor address.
Definition: laeWd.h:389
const byte_t LaeWdRspLenPetDog_2
v2 response length (bytes)
Definition: laeWatchDog.h:187
const byte_t LaeWdCmdIdReadAPin
command id
Definition: laeWatchDog.h:333
uint_t determineAlarms()
Determine watchdog alarm state.
Definition: laeWd.cxx:1073
const byte_t LaeWdCmdIdEnableAuxPort
command id
Definition: laeWatchDog.h:381
const byte_t LaeWdArgPass
command success response
Definition: laeWatchDog.h:78
virtual int cmdConfigDPin(uint_t pin, uint_t dir)
Configure a digital pin command.
Definition: laeWd.cxx:396
const byte_t LaeWdCmdIdReadDPin
command id
Definition: laeWatchDog.h:296
virtual int cmdConfigOperation(unsigned long uTimeout)
Configure firmware operation.
Definition: laeWd.cxx:1028
static uint_t FWVER_UNKNOWN
unknown firmware version
Definition: laeWd.cxx:103
LaeDbAlarms m_alarms
alarm state data
Definition: laeDb.h:238
bool m_bAuxPort5v
5 volt auxilliary port [not] enabled
Definition: laeDb.h:123
const int LaeWdMaxRspLen
maximum response length
Definition: laeWatchDog.h:168
const byte_t LaeWdCmdIdReadEnables
command id
Definition: laeWatchDog.h:401
const byte_t LaeWdArgDPinDirOut
output
Definition: laeWatchDog.h:121
virtual int cmdWriteAPin(uint_t pin, uint_t val)
Write the value to an analog pin command.
Definition: laeWd.cxx:616
LaeDbConfig m_config
configuration data
Definition: laeDb.h:228
const byte_t LaeWdCmdIdResetRgbLed
command id
Definition: laeWatchDog.h:260
const unsigned int LaeWdArgAlarmGen
general alarm
Definition: laeWatchDog.h:97
const byte_t LaeWdRspLenReadEnables
response length (bytes)
Definition: laeWatchDog.h:403
static int enableMotorCtlrs(void *pArg, bool bEnable)
Enable/disable power in to motor controllers.
Definition: laeWd.cxx:1117
virtual int cmdEnableAuxPortBatt(bool bEnable)
Enable/disable battery auxilliary port power out.
Definition: laeWd.cxx:808
Laelaps real-time "database".
const int LaeWdMaxCmdLen
maximum command length
Definition: laeWatchDog.h:167
const byte_t LaeWdArgAInPinNumMin
analog input min pin number
Definition: laeWatchDog.h:129
virtual void sync()
Synchronize watchdog state with subprocessor state.
Definition: laeWd.cxx:142
virtual int reload(const LaeTunes &tunes)
Reload with new configuration.
Definition: laeWd.cxx:182
Top-level package include file.
const byte_t LaeWdRspLenReadAPin
response length (bytes)
Definition: laeWatchDog.h:335
const byte_t LaeWdRspLenReadVolts
response length (bytes)
Definition: laeWatchDog.h:427
virtual int cmdSetAlarms(uint_t uAlarms)
Set (clear) alarms command.
Definition: laeWd.cxx:323
static const int LAE_OK
not an error, success
Definition: laelaps.h:71
const byte_t LaeWdArgDPinValLow
pin is low (0V)
Definition: laeWatchDog.h:123