diff --git a/cpdctrl/led_control_device/__init__.py b/cpdctrl/led_control_device/__init__.py index e7d07bf..7a688f2 100644 --- a/cpdctrl/led_control_device/__init__.py +++ b/cpdctrl/led_control_device/__init__.py @@ -23,7 +23,8 @@ def list_devices() -> dict[str,list[str]]: } try: from .impl import thorlabs_ledd1b as th - devices[TYPENAME_LEDD1B] = ["Thorlabs LEDD1B"] #keithley2700.enumerate_devices() + # devices[TYPENAME_LEDD1B] = ["Thorlabs LEDD1B"] #keithley2700.enumerate_devices() + devices[TYPENAME_LEDD1B] = th.LEDD1B.enumerate_devices() except ImportError: pass try: @@ -52,7 +53,10 @@ def connect_device(type_name: str, device_name: str) -> LedControlDevice: elif type_name == TYPENAME_LEDD1B: try: from .impl import thorlabs_ledd1b as th - return th.LEDD1B() + dev = th.LEDD1B.connect_device(device_name) + # make sure a potential software mismatch is being logged + dev.check_has_correct_software(no_error=True) + return dev except ImportError as e: raise ValueError(f"Arduino devices not available: {e}") elif type_name == TYPENAME_DC2200: diff --git a/cpdctrl/led_control_device/impl/thorlabs_ledd1b.py b/cpdctrl/led_control_device/impl/thorlabs_ledd1b.py index 1561698..be46b59 100644 --- a/cpdctrl/led_control_device/impl/thorlabs_ledd1b.py +++ b/cpdctrl/led_control_device/impl/thorlabs_ledd1b.py @@ -1,4 +1,5 @@ import serial +import serial.tools.list_ports from ..base import LedControlDevice @@ -14,15 +15,18 @@ class LEDD1B(LedControlDevice): Note: This currently has COM4 hardcoded """ - def __init__(self, port="COM4"): - self.arduino = serial.Serial(port=port, baudrate=9600, timeout=.1) - self._check_arduino_software() - + def __init__(self, port="COM4"): + super().__init__() + self.arduino = serial.Serial(port=port, baudrate=9600, timeout=0.1) + # flush input + while self.arduino.read(1): + pass + def __del__(self): self.off() self.arduino.close() - def _check_arduino_software(self): + def check_has_correct_software(self, no_error=False): """ Run the identify command and raise an Exception if the Arduino does not reply with the expected output. @@ -31,17 +35,20 @@ class LEDD1B(LedControlDevice): lines = self.read() if len(lines) < 1 or not lines[-1].startswith(bytes(ARDUINO_SOFTWARE_VERSION_STRING, "utf-8")): log.error(f"Arduino did not return the expected output - does it have the correct software loaded?\nExpected: '{ARDUINO_SOFTWARE_VERSION_STRING}'\nReceived:{lines}") - raise ConnectionError("Arduino did not return the expected output - does it have the correct software loaded?") + if not no_error: + raise ConnectionError("Arduino did not return the expected output - does it have the correct software loaded?") def test_connection(self) -> None: try: - self._check_arduino_software() + self._write('i') + lines = self.read() except Exception as e: - log.error(f"Failed to query *IDN?:", e) + log.error(f"Failed to query 'i':", e) raise ConnectionError def _write(self, val): - self.arduino.write(bytes(val, 'utf-8')) + self.arduino.write(bytes(val, 'utf-8')) + self.arduino.flush() def read(self): data = self.arduino.readlines() @@ -60,6 +67,23 @@ class LEDD1B(LedControlDevice): def __str__(self): return "Thorlabs LEDD1B" + @staticmethod + def enumerate_devices() -> list[str]: + devs = [] + coms = serial.tools.list_ports.comports() + # Require a device with no product field and empty serial number + # Change these conditions to support different devices + for com in coms: + if com.product is not None: continue + if com.serial_number: continue + if com.manufacturer not in ["wch.cn"]: continue + devs.append(com.device) + return devs + + @staticmethod + def connect_device(name: str): + return LEDD1B(port=name) + if __name__ == '__main__': led = LEDD1B() \ No newline at end of file