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.

159 lines
4.3 KiB

  1. import usb.core
  2. import usb.util
  3. import time
  4. import threading
  5. from pyftdi.pyftdi.ftdi import *
  6. from pyftdi.pyftdi.usbtools import *
  7. from . import util
  8. from .event import event
  9. class USBDevice(object):
  10. FTDI_VENDOR_ID = 0x0403
  11. FTDI_PRODUCT_ID = 0x6001
  12. BAUDRATE = 115200
  13. on_open = event.Event('Called when the device has been opened')
  14. on_close = event.Event('Called when the device has been closed')
  15. on_read = event.Event('Called when a line has been read from the device')
  16. on_write = event.Event('Called when data has been written to the device')
  17. @staticmethod
  18. def find_all():
  19. devices = []
  20. try:
  21. devices = Ftdi.find_all([(USBDevice.FTDI_VENDOR_ID, USBDevice.FTDI_PRODUCT_ID)], nocache=True)
  22. except (usb.core.USBError, FtdiError), err:
  23. raise util.CommError('Error enumerating AD2USB devices: {0}'.format(str(err)))
  24. return devices
  25. def __init__(self, vid=FTDI_VENDOR_ID, pid=FTDI_PRODUCT_ID, serial=None, description=None):
  26. self._vendor_id = vid
  27. self._product_id = pid
  28. self._serial_number = serial
  29. self._description = description
  30. self._buffer = ''
  31. self._device = Ftdi()
  32. self._running = False
  33. self._read_thread = USBDevice.ReadThread(self)
  34. def open(self, baudrate=BAUDRATE, interface=0, index=0):
  35. self._running = True
  36. try:
  37. self._device.open(self._vendor_id,
  38. self._product_id,
  39. interface,
  40. index,
  41. self._serial_number,
  42. self._description)
  43. self._device.set_baudrate(baudrate)
  44. except (usb.core.USBError, FtdiError), err:
  45. self.on_close()
  46. raise util.CommError('Error opening AD2USB device: {0}'.format(str(err)))
  47. else:
  48. self._read_thread.start()
  49. self.on_open((self._serial_number, self._description))
  50. def close(self):
  51. try:
  52. self._running = False
  53. self._read_thread.stop()
  54. self._device.close()
  55. except (FtdiError, usb.core.USBError):
  56. pass
  57. self.on_close()
  58. def write(self, data):
  59. self._device.write_data(data)
  60. self.on_write(data)
  61. def read_line(self, timeout=0.0):
  62. start_time = time.time()
  63. got_line = False
  64. ret = None
  65. try:
  66. while self._running:
  67. buf = self._device.read_data(1)
  68. self._buffer += buf
  69. if buf == "\n":
  70. if len(self._buffer) > 1:
  71. if self._buffer[-2] == "\r":
  72. self._buffer = self._buffer[:-2]
  73. # ignore if we just got \r\n with nothing else in the buffer.
  74. if len(self._buffer) != 0:
  75. got_line = True
  76. break
  77. else:
  78. self._buffer = self._buffer[:-1]
  79. if timeout > 0 and time.time() - start_time > timeout:
  80. break
  81. time.sleep(0.01)
  82. except (usb.core.USBError, FtdiError), err:
  83. self.close()
  84. raise util.CommError('Error reading from AD2USB device: {0}'.format(str(err)))
  85. else:
  86. if got_line:
  87. ret = self._buffer
  88. self._buffer = ''
  89. self.on_read(ret)
  90. return ret
  91. class ReadThread(threading.Thread):
  92. def __init__(self, device):
  93. threading.Thread.__init__(self)
  94. self._device = device
  95. self._running = False
  96. def stop(self):
  97. self._running = False
  98. def run(self):
  99. self._running = True
  100. while self._running:
  101. try:
  102. self._device.read_line()
  103. except util.CommError, err:
  104. self.stop()
  105. time.sleep(0.25)
  106. class SerialDevice(object):
  107. BAUDRATE = 9600
  108. def __init__(self):
  109. pass
  110. def __del__(self):
  111. pass
  112. def open(self, port, baudrate=BAUDRATE):
  113. pass
  114. def close(self):
  115. pass
  116. def write(self, data):
  117. pass
  118. def read_line(self, data):
  119. pass