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.

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