Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
WatchDog.py
Go to the documentation of this file.
1 ###############################################################################
2 #
3 # Module: Laelaps.WatchDog
4 #
5 # Package: RoadNarrows Laelaps Robotic Mobile Platform Package
6 #
7 # Link: https://github.com/roadnarrows-robotics/laelaps
8 #
9 # File: WatchDog.py
10 #
11 ## \file
12 ##
13 ## $LastChangedDate: 2015-07-23 16:47:32 -0600 (Thu, 23 Jul 2015) $
14 ## $Rev: 4038 $
15 ##
16 ## \brief Laelaps WatchDog subprocessor Interface.
17 ##
18 ## The main processors communicates with the subprocessor via a Two-Wire
19 ## (I2C, SMBus) Interface.
20 ##
21 ## \author Robin Knight (robin.knight@roadnarrows.com)
22 ##
23 ## \par Copyright
24 ## \h_copy 2015-2017. RoadNarrows LLC.\n
25 ## http://www.roadnarrows.com\n
26 ## All Rights Reserved
27 ##
28 # @EulaBegin@
29 #
30 # Permission is hereby granted, without written agreement and without
31 # license or royalty fees, to use, copy, modify, and distribute this
32 # software and its documentation for any purpose, provided that
33 # (1) The above copyright notice and the following two paragraphs
34 # appear in all copies of the source code and (2) redistributions
35 # including binaries reproduces these notices in the supporting
36 # documentation. Substantial modifications to this software may be
37 # copyrighted by their authors and need not follow the licensing terms
38 # described here, provided that the new terms are clearly indicated in
39 # all files where they apply.
40 #
41 # IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
42 # OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
43 # PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
44 # DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
45 # EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
46 # THE POSSIBILITY OF SUCH DAMAGE.
47 #
48 # THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
49 # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
50 # FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
51 # "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
52 # PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
53 #
54 # @EulaEnd@
55 #
56 ###############################################################################
57 
58 import sys
59 import os
60 import time
61 
62 import rnr.i2c as i2c
63 
64 import Laelaps.SysConf as SysConf
65 from Laelaps.WatchDogMsgs import *
66 
67 
68 # ------------------------------------------------------------------------------
69 # Global Data
70 # ------------------------------------------------------------------------------
71 
72 # return codes
73 WDRcOk = 'ok' ## success
74 WDRcErr = 'error' ## operation failed
75 
76 # error messages
77 _WDErrMsgOpen = 'No open I2C bus device.'
78 
79 
80 # ------------------------------------------------------------------------------
81 # Class WatchDog
82 # ------------------------------------------------------------------------------
83 
84 #
85 ## \brief Laelaps WatchDog Interface Class.
86 #
87 class WatchDog:
88 
89  #
90  ## \brief Constructor
91  #
92  def __init__(self):
93  self.m_i2c = None
94  self.m_addr = LaeI2CAddrArduino
95  self.m_owner = False
96 
97  # shadow data
98  self.m_fw = {
99  'version': 0,
100  'battery_is_charging':False,
101  'battery_soc': LaeWdArgBattChargeMax,
102  'alarms': LaeWdArgAlarmNone,
103  'rgb': {'override': False, 'red':0, 'green':0, 'blue':0},
104  'digital': {},
105  'analog': {},
106  'enables': {'motor_ctlr_en': False,
107  'aux_port_batt_en': False,
108  'aux_port_5v_en': False},
109  'voltages': {'jack': 0.0, 'batt': 0.0} }
110 
111  for pin in range(LaeWdArgDPinNumMin, LaeWdArgDPinNumMax+1):
112  self.m_fw['digital'][pin] = {'dir': LaeWdArgDPinDirIn, 'val': 0}
113 
114  for pin in range(LaeWdArgAInPinNumMin, LaeWdArgAInPinNumMax+1):
115  self.m_fw['analog'][pin] = {'dir': LaeWdArgDPinDirIn, 'val': 0}
116 
117  #
118  ## \brief Attach the open I2C object.
119  ##
120  ## \param i2cbus An rnr.i2c.i2c() constructed and open object.
121  #
122  def attach(self, i2cbus):
123  self.close()
124  self.m_i2c = i2cbus
125  self.m_owner = False
126 
127  #
128  ## \brief Open the I2C bus device.
129  ##
130  ## \param devName Device name.
131  ##
132  ## \return True on success, False on failure.
133  #
134  def open(self, devName):
135  self.close()
136  try:
137  self.m_i2c = i2c.i2c()
138  self.m_i2c.open(devName)
139  except i2c.I2CException, inst:
140  self.printError("open", inst.message)
141  rc = False
142  else:
143  self.m_owner = True
144  rc = True
145  return rc
146 
147  #
148  ## \brief Close the I2C bus device.
149  ##
150  ## The device must be owned by this class instance.
151  #
152  def close(self):
153  if self.m_i2c is None:
154  return
155  elif not self.m_i2c.is_open():
156  return
157  elif not self.m_owner:
158  return
159  self.m_i2c.close()
160 
161  #
162  ## \brief Test if the open/attached I2C bus device is open.
163  ##
164  ## \return True or False.
165  #
166  def isOpen(self):
167  if self.m_i2c is None:
168  return False
169  else:
170  return self.m_i2c.is_open()
171 
172  #
173  ## \brief Synchronize watchdog state with the subprocessor state.
174  #
175  def sync(self):
176  self.cmdGetFwVersion() # must be first
177  self.cmdEnableMotorCtlrs(False)
178  self.cmdEnableAuxPort5V(True)
179  self.cmdEnableAuxPortBatt(True)
180  self.cmdSetBatterySoC(LaeWdArgBattChargeMax)
181  self.cmdSetAlarms(LaeWdArgAlarmNone)
182  self.cmdResetRgbLed()
183  self.cmdPetTheDog()
184 
185  #
186  ## \brief Get the shadowed subprocessor value.
187  ##
188  ## No I/O is performed.
189  ##
190  ## \return Dictionary of shadowed values.
191  #
192  def getShadow(self):
193  return self.m_fw
194 
195  #
196  ## \brief Execute command to pet the watchdog.
197  ##
198  ## \return {'rc': rc, key: value}\n
199  #
200  def cmdPetTheDog(self):
201  cmdId = LaeWdCmdIdPetDog
202 
203  key = 'battery_is_charging'
204  ret = {'rc': WDRcOk, key: self.m_fw[key]}
205 
206  # check connection
207  if not self.isOpen():
208  self.printError(_WDErrMsgOpen)
209  ret['rc'] = WDRcErr
210  return ret
211 
212  cmd = [chr(cmdId)]
213 
214  # send command (and receive response)
215  if self.m_fw['version'] <= 1:
216  try:
217  self.m_i2c.write(self.m_addr, cmd)
218  except i2c.I2CException, inst:
219  self.printError("CmdId %d" % (cmdId), inst.message)
220  ret['rc'] = WDRcErr
221  else: # versions 2+
222  rspLen = LaeWdRspLenPetDog_2
223  try:
224  rsp = self.m_i2c.write_read(self.m_addr, cmd, rspLen)
225  except i2c.I2CException, inst:
226  self.printError("CmdId %d" % (cmdId), inst.message)
227  ret['rc'] = WDRcErr
228  else:
229  if len(rsp) == rspLen:
230  if rsp[0]:
231  self.m_fw[key] = True
232  else:
233  self.m_fw[key] = False
234  ret[key] = self.m_fw[key]
235 
236  return ret
237 
238  #
239  ## \brief Execute command to get the firmware version.
240  ##
241  ## \return {'rc': rc, key: value}
242  #
243  def cmdGetFwVersion(self):
244  cmdId = LaeWdCmdIdGetVersion
245  rspLen = LaeWdRspLenGetVersion
246 
247  key = 'version'
248  ret = {'rc': WDRcOk, key: self.m_fw[key]}
249 
250  # check connection
251  if not self.isOpen():
252  self.printError(_WDErrMsgOpen)
253  ret['rc'] = WDRcErr
254  return ret
255 
256  cmd = [chr(cmdId)]
257 
258  # send command and receive response
259  try:
260  rsp = self.m_i2c.write_read(self.m_addr, cmd, rspLen)
261  except i2c.I2CException, inst:
262  self.printError("CmdId %d" % (cmdId), inst.message)
263  ret['rc'] = WDRcErr
264  else:
265  if len(rsp) == rspLen:
266  self.m_fw[key] = ord(rsp[0])
267  ret[key] = self.m_fw[key]
268 
269  return ret
270 
271  #
272  ## \brief Execute command to set the battery state of charge.
273  ##
274  ## \param soc State of charge [0-100].
275  ##
276  ## \return {'rc': rc, key: value}
277  #
278  def cmdSetBatterySoC(self, soc):
279  cmdId = LaeWdCmdIdSetAlarms
280 
281  key = 'battery_soc'
282  ret = {'rc': WDRcOk, key: self.m_fw[key]}
283 
284  # check connection
285  if not self.isOpen():
286  self.printError(_WDErrMsgOpen)
287  ret['rc'] = WDRcErr
288  return ret
289 
290  if soc < LaeWdArgBattChargeMin:
291  soc = LaeWdArgBattChargeMin
292  elif soc > LaeWdArgBattChargeMax:
293  soc = LaeWdArgBattChargeMax
294  else:
295  soc = int(soc)
296 
297  cmd = [chr(cmdId), chr(soc)]
298 
299  # send command
300  try:
301  self.m_i2c.write(self.m_addr, cmd)
302  except i2c.I2CException, inst:
303  self.printError("CmdId %d" % (cmdId), inst.message)
304  ret['rc'] = WDRcErr
305  else:
306  self.m_fw[key] = soc
307  ret[key] = self.m_fw[key]
308 
309  return ret
310 
311  #
312  ## \brief Execute command to set/clear alarms.
313  ##
314  ## \param alarms Or'ed alarm bits.
315  ##
316  ## \return {'rc': rc, key: value}
317  #
318  def cmdSetAlarms(self, alarms):
319  cmdId = LaeWdCmdIdSetAlarms
320 
321  key = 'alarms'
322  ret = {'rc': WDRcOk, key: self.m_fw[key]}
323 
324  # check connection
325  if not self.isOpen():
326  self.printError(_WDErrMsgOpen)
327  ret['rc'] = WDRcErr
328  return ret
329 
330  alarms &= LaeWdArgAlarmMask
331 
332  b1 = chr(((alarms >> 8) & 0xff))
333  b2 = chr(((alarms) & 0xff))
334  cmd = [chr(cmdId), b1, b2]
335 
336  # send command
337  try:
338  self.m_i2c.write(self.m_addr, cmd)
339  except i2c.I2CException, inst:
340  self.printError("CmdId %d" % (cmdId), inst.message)
341  ret['rc'] = WDRcErr
342  else:
343  self.m_fw[key] = alarms
344  ret[key] = self.m_fw[key]
345 
346  return ret
347 
348  #
349  ## \brief Execute command to set the RGB LED.
350  ##
351  ## \param red Red component [0-255]
352  ## \param green Green component [0-255]
353  ## \param blue Blue component [0-255]
354  ##
355  ## \return {'rc': rc, key: value}
356  #
357  def cmdSetRgbLed(self, red, green, blue):
358  cmdId = LaeWdCmdIdSetRgbLed
359 
360  key = 'rgb'
361  ret = {'rc': WDRcOk, key: self.m_fw[key]}
362 
363  # check connection
364  if not self.isOpen():
365  self.printError(_WDErrMsgOpen)
366  ret['rc'] = WDRcErr
367  return ret
368 
369  red &= 0xff
370  green &= 0xff
371  blue &= 0xff
372 
373  b1 = chr(red)
374  b2 = chr(green)
375  b3 = chr(blue)
376  cmd = [chr(cmdId), b1, b2, b3]
377 
378  # send command
379  try:
380  self.m_i2c.write(self.m_addr, cmd)
381  except i2c.I2CException, inst:
382  self.printError("CmdId %d" % (cmdId), inst.message)
383  ret['rc'] = WDRcErr
384  else:
385  self.m_fw[key]['override'] = True
386  self.m_fw[key]['red'] = red
387  self.m_fw[key]['green'] = green
388  self.m_fw[key]['blue'] = blue
389  ret[key] = self.m_fw[key]
390 
391  return ret
392 
393  #
394  ## \brief Reset the RGB LED to state defaults.
395  ##
396  ## \return {'rc': rc, key: value}
397  #
398  def cmdResetRgbLed(self):
399  cmdId = LaeWdCmdIdResetRgbLed
400 
401  key = 'rgb'
402  ret = {'rc': WDRcOk, key: self.m_fw[key]}
403 
404  # check connection
405  if not self.isOpen():
406  self.printError(_WDErrMsgOpen)
407  ret['rc'] = WDRcErr
408  return ret
409 
410  cmd = [chr(cmdId)]
411 
412  # send command
413  try:
414  self.m_i2c.write(self.m_addr, cmd)
415  except i2c.I2CException, inst:
416  self.printError("CmdId %d" % (cmdId), inst.message)
417  ret['rc'] = WDRcErr
418  else:
419  self.m_fw[key]['override'] = False
420  ret[key] = self.m_fw[key]
421 
422  return ret
423 
424  #
425  ## \brief Execute command to configure a digital I/O pin.
426  ##
427  ## \param pin Digital pin number.
428  ## \param direction Pin direction. 0 == input, 1 == output.
429  ##
430  ## \return {'rc': rc, key: value}
431  #
432  def cmdConfigDPin(self, pin, direction):
433  cmdId = LaeWdCmdIdConfigDPin
434 
435  key = 'digital'
436  ret = {'rc': WDRcOk, key: {}}
437 
438  if (pin < LaeWdArgDPinNumWMin) or (pin > LaeWdArgDPinNumWMax):
439  self.printError("CmdId %d" % (cmdId), "Pin %d invalid" % (pin))
440  ret['rc'] = WDRcErr
441  return ret
442 
443  ret[key] = self.m_fw[key][pin]
444 
445  # check connection
446  if not self.isOpen():
447  self.printError(_WDErrMsgOpen)
448  ret['rc'] = WDRcErr
449  return ret
450 
451  if direction > 0:
452  direction = LaeWdArgDPinDirOut
453  else:
454  direction = LaeWdArgDPinDirIn
455 
456  b1 = chr(pin)
457  b2 = chr(direction)
458  cmd = [chr(cmdId), b1, b2]
459 
460  # send command
461  try:
462  self.m_i2c.write(self.m_addr, cmd)
463  except i2c.I2CException, inst:
464  self.printError("CmdId %d" % (cmdId), inst.message)
465  ret['rc'] = WDRcErr
466  else:
467  self.m_fw[key][pin]['dir'] = direction
468  ret[key] = self.m_fw[key][pin]
469 
470  return ret
471 
472  #
473  ## \brief Execute command to read a digital I/O pin's value.
474  ##
475  ## \param pin Digital pin number.
476  ##
477  ## \return {'rc': rc, key: value}
478  #
479  def cmdReadDPin(self, pin):
480  cmdId = LaeWdCmdIdReadDPin
481  rspLen = LaeWdRspLenReadDPin
482 
483  key = 'digital'
484  ret = {'rc': WDRcOk, key: {}}
485 
486  if (pin < LaeWdArgDPinNumMin) or (pin > LaeWdArgDPinNumMax):
487  self.printError("CmdId %d" % (cmdId), "Pin %d invalid" % (pin))
488  ret['rc'] = WDRcErr
489  return ret
490 
491  ret[key] = self.m_fw[key][pin]
492 
493  # check connection
494  if not self.isOpen():
495  self.printError(_WDErrMsgOpen)
496  ret['rc'] = WDRcErr
497  return ret
498 
499  b1 = chr(pin)
500  cmd = [chr(cmdId), b1]
501 
502  # send command
503  try:
504  rsp = self.m_i2c.write_read(self.m_addr, cmd, rspLen)
505  except i2c.I2CException, inst:
506  self.printError("CmdId %d" % (cmdId), inst.message)
507  ret['rc'] = WDRcErr
508  else:
509  if len(rsp) == rspLen:
510  self.m_fw[key][pin]['val'] = ord(rsp[1])
511  ret[key] = self.m_fw[key][pin]
512 
513  return ret
514 
515  #
516  ## \brief Execute command to wite a value to a digital I/O pin.
517  ##
518  ## \param pin Digital pin number.
519  ## \param value Pin value. 0 == low, 1 == high.
520  ##
521  ## \return {'rc': rc, key: value}
522  #
523  def cmdWriteDPin(self, pin, val):
524  cmdId = LaeWdCmdIdWriteDPin
525 
526  key = 'digital'
527  ret = {'rc': WDRcOk, key: {}}
528 
529  if (pin < LaeWdArgDPinNumWMin) or (pin > LaeWdArgDPinNumWMax):
530  self.printError("CmdId %d" % (cmdId), "Pin %d invalid" % (pin))
531  ret['rc'] = WDRcErr
532  return ret
533 
534  ret[key] = self.m_fw[key][pin]
535 
536  # check connection
537  if not self.isOpen():
538  self.printError(_WDErrMsgOpen)
539  ret['rc'] = WDRcErr
540  return ret
541 
542  if val > 0:
543  val = LaeWdArgDPinValHigh
544  else:
545  val = LaeWdArgDPinValLow
546 
547  b1 = chr(pin)
548  b2 = chr(val)
549  cmd = [chr(cmdId), b1, b2]
550 
551  # send command
552  try:
553  self.m_i2c.write(self.m_addr, cmd)
554  except i2c.I2CException, inst:
555  self.printError("CmdId %d" % (cmdId), inst.message)
556  ret['rc'] = WDRcErr
557  else:
558  self.m_fw[key][pin]['val'] = val
559  ret[key] = self.m_fw[key][pin]
560 
561  return ret
562 
563 
564  #
565  ## \brief Execute command to read an analog I/O pin.
566  ##
567  ## \param pin Analog pin number.
568  ##
569  ## \return {'rc': rc, key: value}
570  #
571  def cmdReadAPin(self, pin):
572  cmdId = LaeWdCmdIdReadAPin
573  rspLen = LaeWdRspLenReadAPin
574 
575  key = 'analog'
576  ret = {'rc': WDRcOk, key: {}}
577 
578  if (pin < LaeWdArgAInPinNumMin) or (pin > LaeWdArgAInPinNumMax):
579  self.printError("CmdId %d" % (cmdId), "Pin %d invalid" % (pin))
580  ret['rc'] = WDRcErr
581  return ret
582 
583  ret[key] = self.m_fw[key][pin]
584 
585  # check connection
586  if not self.isOpen():
587  self.printError(_WDErrMsgOpen)
588  ret['rc'] = WDRcErr
589  return ret
590 
591  b1 = chr(pin)
592  cmd = [chr(cmdId), b1]
593 
594  # send command
595  try:
596  rsp = self.m_i2c.write_read(self.m_addr, cmd, rspLen)
597  except i2c.I2CException, inst:
598  self.printError("CmdId %d" % (cmdId), inst.message)
599  ret['rc'] = WDRcErr
600  else:
601  if len(rsp) == rspLen:
602  b1 = ord(rsp[1])
603  b2 = ord(rsp[2])
604  val = b1 << 8 | b2
605  self.m_fw[key][pin]['fal'] = val
606  ret[key] = self.m_fw[key][pin]
607 
608  return ret
609 
610  #
611  ## \brief Execute command to enable/disable power to motor controllers.
612  ##
613  ## \param enable Enable (True) or disable (False).
614  ##
615  ## \return {'rc': rc, key: value}
616  #
617  def cmdEnableMotorCtlrs(self, enable):
618  cmdId = LaeWdCmdIdEnableMotorCtlrs
619  rspLen = LaeWdRspLenEnableMotorCtlrs
620 
621  key = 'enables'
622  subkey = 'motor_ctlr_en'
623  ret = {'rc': WDRcOk, subkey: self.m_fw[key][subkey]}
624 
625  # check connection
626  if not self.isOpen():
627  self.printError(_WDErrMsgOpen)
628  ret['rc'] = WDRcErr
629  return ret
630 
631  # unknown firmware
632  if self.m_fw['version'] == 0:
633  return ret
634  # always enabled
635  elif self.m_fw['version'] == 1:
636  self.m_fw[key][subkey] = True
637  ret[subkey] = self.m_fw[key][subkey]
638  return ret
639 
640  if enable:
641  val = LaeWdArgDPinValHigh
642  else:
643  val = LaeWdArgDPinValLow
644 
645  b1 = chr(val)
646  cmd = [chr(cmdId), b1]
647 
648  # send command
649  try:
650  rsp = self.m_i2c.write_read(self.m_addr, cmd, rspLen)
651  except i2c.I2CException, inst:
652  self.printError("CmdId %d" % (cmdId), inst.message)
653  ret['rc'] = WDRcErr
654  else:
655  if (len(rsp) == rspLen) and (ord(rsp[0]) == LaeWdArgPass):
656  self.m_fw[key][subkey] = enable
657  ret[subkey] = self.m_fw[key][subkey]
658 
659  return ret
660 
661  #
662  ## \brief Execute command to enable/disable regulated 5V output to aux. port.
663  ##
664  ## \param enable Enable (True) or disable (False).
665  ##
666  ## \return {'rc': rc, key: value}
667  #
668  def cmdEnableAuxPort5V(self, enable):
669  cmdId = LaeWdCmdIdEnableAuxPort
670 
671  key = 'enables'
672  subkey = 'aux_port_5v_en'
673  ret = {'rc': WDRcOk, subkey: self.m_fw[key][subkey]}
674 
675  # check connection
676  if not self.isOpen():
677  self.printError(_WDErrMsgOpen)
678  ret['rc'] = WDRcErr
679  return ret
680 
681  # unknown firmware
682  if self.m_fw['version'] == 0:
683  return ret
684  # always enabled
685  elif self.m_fw['version'] == 1:
686  self.m_fw[key][subkey] = True
687  ret[subkey] = self.m_fw[key][subkey]
688  return ret
689 
690  if enable:
691  val = LaeWdArgDPinValHigh
692  else:
693  val = LaeWdArgDPinValLow
694 
695  b1 = chr(LaeWdArgAuxPort5V)
696  b2 = chr(val)
697  cmd = [chr(cmdId), b1, b2]
698 
699  # send command
700  try:
701  self.m_i2c.write(self.m_addr, cmd)
702  except i2c.I2CException, inst:
703  self.printError("CmdId %d" % (cmdId), inst.message)
704  ret['rc'] = WDRcErr
705  else:
706  self.m_fw[key][subkey] = enable
707  ret[subkey] = self.m_fw[key][subkey]
708 
709  return ret
710 
711  #
712  ## \brief Execute command to enable/disable battery output to aux. port.
713  ##
714  ## \param enable Enable (True) or disable (False).
715  ##
716  ## \return {'rc': rc, key: value}
717  #
718  def cmdEnableAuxPortBatt(self, enable):
719  cmdId = LaeWdCmdIdEnableAuxPort
720 
721  key = 'enables'
722  subkey = 'aux_port_batt_en'
723  ret = {'rc': WDRcOk, subkey: self.m_fw[key][subkey]}
724 
725  # check connection
726  if not self.isOpen():
727  self.printError(_WDErrMsgOpen)
728  ret['rc'] = WDRcErr
729  return ret
730 
731  # unknown firmware
732  if self.m_fw['version'] == 0:
733  return ret
734  # always enabled
735  elif self.m_fw['version'] == 1:
736  self.m_fw[key][subkey] = True
737  ret[subkey] = self.m_fw[key][subkey]
738  return ret
739 
740  if enable:
741  val = LaeWdArgDPinValHigh
742  else:
743  val = LaeWdArgDPinValLow
744 
745  b1 = chr(LaeWdArgAuxPortBatt)
746  b2 = chr(val)
747  cmd = [chr(cmdId), b1, b2]
748 
749  # send command
750  try:
751  self.m_i2c.write(self.m_addr, cmd)
752  except i2c.I2CException, inst:
753  self.printError("CmdId %d" % (cmdId), inst.message)
754  ret['rc'] = WDRcErr
755  else:
756  self.m_fw[key][subkey] = enable
757  ret[subkey] = self.m_fw[key][subkey]
758 
759  return ret
760 
761  #
762  ## \brief Execute command to read enable lines.
763  ##
764  ## \return {'rc': rc, key: value}
765  #
766  def cmdReadEnables(self):
767  cmdId = LaeWdCmdIdReadEnables
768  rspLen = LaeWdRspLenReadEnables
769 
770  key = 'enables'
771  ret = {'rc': WDRcOk, key: self.m_fw[key]}
772 
773  # check connection
774  if not self.isOpen():
775  self.printError(_WDErrMsgOpen)
776  ret['rc'] = WDRcErr
777  return ret
778 
779  # unknown firmware or unsupported feature
780  if self.m_fw['version'] < 2:
781  return ret
782 
783  cmd = [chr(cmdId)]
784 
785  # send command
786  try:
787  rsp = self.m_i2c.write_read(self.m_addr, cmd, rspLen)
788  except i2c.I2CException, inst:
789  self.printError("CmdId %d" % (cmdId), inst.message)
790  ret['rc'] = WDRcErr
791  else:
792  if len(rsp) == rspLen:
793  val0 = ord(rsp[0])
794  val1 = ord(rsp[1])
795  val2 = ord(rsp[2])
796  if val0:
797  self.m_fw[key]['motor_ctlr_en'] = True
798  else:
799  self.m_fw[key]['motor_ctlr_en'] = False
800  if val1:
801  self.m_fw[key]['aux_port_batt_en'] = True
802  else:
803  self.m_fw[key]['aux_port_batt_en'] = False
804  if val2:
805  self.m_fw[key]['aux_port_5v_en'] = True
806  else:
807  self.m_fw[key]['aux_port_5v_en'] = False
808  ret[key] = self.m_fw[key]
809 
810  return ret
811 
812  #
813  ## \brief Execute command to read sensed voltages.
814  ##
815  ## \return {'rc': rc, key: value}
816  #
817  def cmdReadVoltages(self):
818  cmdId = LaeWdCmdIdReadVolts
819  rspLen = LaeWdRspLenReadVolts
820 
821  key = 'voltages'
822  ret = {'rc': WDRcOk, key: self.m_fw[key]}
823 
824  # check connection
825  if not self.isOpen():
826  self.printError(_WDErrMsgOpen)
827  ret['rc'] = WDRcErr
828  return ret
829 
830  # unknown firmware or unsupported feature
831  if self.m_fw['version'] < 2:
832  return ret
833 
834  cmd = [chr(cmdId)]
835 
836  # send command
837  try:
838  rsp = self.m_i2c.write_read(self.m_addr, cmd, rspLen)
839  except i2c.I2CException, inst:
840  self.printError("CmdId %d" % (cmdId), inst.message)
841  ret['rc'] = WDRcErr
842  else:
843  if len(rsp) == rspLen:
844  val0 = ord(rsp[0])
845  val1 = ord(rsp[1])
846  self.m_fw[key]['jack'] = val0 * LaeWdargVScale
847  self.m_fw[key]['batt'] = val1 * LaeWdargVScale
848  ret[key] = self.m_fw[key]
849 
850  return ret
851 
852  #
853  ## \brief Print error to stderr.
854  ##
855  ## \param emsg1 Error message one (required).
856  ## \param emsg2 Error message two (optional).
857  #
858  def printError(self, emsg1, emsg2=None):
859  if emsg2 is None:
860  print >>sys.stderr, "Error: WatchDog: {0}".format(emsg1)
861  else:
862  print >>sys.stderr, "Error: WatchDog: {0}: {1}".format(emsg1, emsg2)
def cmdGetFwVersion(self)
Execute command to get the firmware version.
Definition: WatchDog.py:243
def cmdSetRgbLed(self, red, green, blue)
Execute command to set the RGB LED.
Definition: WatchDog.py:357
def cmdEnableAuxPortBatt(self, enable)
Execute command to enable/disable battery output to aux.
Definition: WatchDog.py:718
def isOpen(self)
Test if the open/attached I2C bus device is open.
Definition: WatchDog.py:166
def cmdPetTheDog(self)
Execute command to pet the watchdog.
Definition: WatchDog.py:200
def open(self, devName)
Open the I2C bus device.
Definition: WatchDog.py:134
def printError(self, emsg1, emsg2=None)
Print error to stderr.
Definition: WatchDog.py:858
def cmdReadAPin(self, pin)
Execute command to read an analog I/O pin.
Definition: WatchDog.py:571
def cmdEnableAuxPort5V(self, enable)
Execute command to enable/disable regulated 5V output to aux.
Definition: WatchDog.py:668
def cmdEnableMotorCtlrs(self, enable)
Execute command to enable/disable power to motor controllers.
Definition: WatchDog.py:617
def cmdSetBatterySoC(self, soc)
Execute command to set the battery state of charge.
Definition: WatchDog.py:278
def cmdResetRgbLed(self)
Reset the RGB LED to state defaults.
Definition: WatchDog.py:398
def cmdReadVoltages(self)
Execute command to read sensed voltages.
Definition: WatchDog.py:817
def cmdConfigDPin(self, pin, direction)
Execute command to configure a digital I/O pin.
Definition: WatchDog.py:432
def sync(self)
Synchronize watchdog state with the subprocessor state.
Definition: WatchDog.py:175
Laelaps WatchDog Interface Class.
Definition: WatchDog.py:87
def __init__(self)
Constructor.
Definition: WatchDog.py:92
def cmdWriteDPin(self, pin, val)
Execute command to wite a value to a digital I/O pin.
Definition: WatchDog.py:523
def getShadow(self)
Get the shadowed subprocessor value.
Definition: WatchDog.py:192
def cmdReadDPin(self, pin)
Execute command to read a digital I/O pin&#39;s value.
Definition: WatchDog.py:479
def cmdSetAlarms(self, alarms)
Execute command to set/clear alarms.
Definition: WatchDog.py:318
def attach(self, i2cbus)
Attach the open I2C object.
Definition: WatchDog.py:122
def close(self)
Close the I2C bus device.
Definition: WatchDog.py:152
def cmdReadEnables(self)
Execute command to read enable lines.
Definition: WatchDog.py:766