A clone of: https://github.com/nutechsoftware/alarmdecoder This is requires as they dropped support for older firmware releases w/o building in backward compatibility code, and they had previously hardcoded pyserial to a python2 only version.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
3.7 KiB

  1. """
  2. Provides utility classes for the AD2USB devices.
  3. """
  4. import ad2usb
  5. import time
  6. import traceback
  7. class NoDeviceError(Exception):
  8. """
  9. No devices found.
  10. """
  11. pass
  12. class CommError(Exception):
  13. """
  14. There was an error communicating with the device.
  15. """
  16. pass
  17. class TimeoutError(Exception):
  18. """
  19. There was a timeout while trying to communicate with the device.
  20. """
  21. pass
  22. class InvalidMessageError(Exception):
  23. """
  24. The format of the panel message was invalid.
  25. """
  26. pass
  27. class Firmware(object):
  28. """
  29. Represents firmware for the AD2USB/AD2SERIAL devices.
  30. """
  31. # Constants
  32. STAGE_START = 0
  33. STAGE_WAITING = 1
  34. STAGE_BOOT = 2
  35. STAGE_LOAD = 3
  36. STAGE_UPLOADING = 4
  37. STAGE_DONE = 5
  38. def __init__(self):
  39. """
  40. Constructor
  41. """
  42. pass
  43. def __del__(self):
  44. """
  45. Destructor
  46. """
  47. pass
  48. @staticmethod
  49. def upload(dev, filename, progress_callback=None):
  50. """
  51. Uploads firmware to an AD2USB/AD2SERIAL device.
  52. """
  53. def do_upload():
  54. """
  55. Perform the actual firmware upload to the device.
  56. """
  57. with open(filename) as f:
  58. for line in f:
  59. line = line.rstrip()
  60. if line[0] == ':':
  61. dev.write(line + "\r")
  62. res = dev.read_line()
  63. if progress_callback is not None:
  64. progress_callback(Firmware.STAGE_UPLOADING)
  65. time.sleep(0.05)
  66. def read_until(pattern, timeout=0.0):
  67. """
  68. Read characters until a specific pattern is found or the timeout is hit.
  69. """
  70. start_time = time.time()
  71. buf = ''
  72. position = 0
  73. while True:
  74. try:
  75. char = dev.read()
  76. if char is not None and char != '':
  77. if char == pattern[position]:
  78. position = position + 1
  79. if position == len(pattern):
  80. break
  81. else:
  82. position = 0
  83. except Exception, err:
  84. traceback.print_exc(err) # TEMP
  85. if timeout > 0 and time.time() - start_time > timeout:
  86. raise TimeoutError('Timed out waiting for pattern: {0}'.format(pattern))
  87. def stage_callback(stage):
  88. if progress_callback is not None:
  89. progress_callback(stage)
  90. if dev is None:
  91. raise NoDeviceError('No device specified for firmware upload.')
  92. stage_callback(Firmware.STAGE_START)
  93. # Close the reader thread and wait for it to die, otherwise
  94. # it interferes with our reading.
  95. dev.close_reader()
  96. while dev._read_thread.is_alive():
  97. stage_callback(Firmware.STAGE_WAITING)
  98. time.sleep(1)
  99. try:
  100. # Reboot the device and wait for the boot loader.
  101. stage_callback(Firmware.STAGE_BOOT)
  102. dev.write("=")
  103. read_until('!boot', timeout=10.0)
  104. # Get ourselves into the boot loader and wait for indication
  105. # that it's ready for the firmware upload.
  106. stage_callback(Firmware.STAGE_LOAD)
  107. dev.write("=")
  108. read_until('!load', timeout=10.0)
  109. # And finally do the upload.
  110. do_upload()
  111. stage_callback(Firmware.STAGE_DONE)
  112. except TimeoutError, err:
  113. print traceback.print_exc(err) # TEMP
  114. pass