Skip to content

Commit 16b7306

Browse files
authored
Merge pull request #108 from DCC-Lab/millennia-vidpid-discovery
Discover the Millennia eV port by its STM32 USB-CDC VID/PID
2 parents d4c4a5b + 8dfb156 commit 16b7306

1 file changed

Lines changed: 28 additions & 9 deletions

File tree

hardwarelibrary/sources/millennia.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,24 @@ class MillenniaEv25Device(LaserSourceDevice, OnOffControl, ShutterControl, Power
3131

3232
# The lab eV25s enumerates its back-panel USB port as a native STM32
3333
# USB-CDC device: VID 0x0483, PID 0x5740 (confirmed on the bench, firmware
34-
# SW214-00.004.096). MillenniaEv25Device is still instantiated by portPath
35-
# (like CoboltDevice) rather than discovered by VID/PID, because 0x0483:0x5740
36-
# is STMicroelectronics' *generic* STM32 Virtual COM Port identity, shared by
37-
# many unrelated STM32-based USB-CDC boards; matching on it via
38-
# SerialPort.matchAnyPort would risk binding to the wrong device. If a host
39-
# only ever has this one STM32 CDC port, set classIdVendor = 0x0483 and
40-
# classIdProduct = 0x5740 to enable discovery; otherwise pin the portPath.
41-
# To re-derive on another unit:
34+
# SW214-00.004.096). doInitializeDevice discovers the port by this identity
35+
# when no portPath is given.
36+
#
37+
# Caveat: 0x0483:0x5740 is STMicroelectronics' *generic* STM32 Virtual COM
38+
# Port identity, shared by many unrelated STM32-based USB-CDC boards. On a
39+
# host that also has another STM32 CDC device, discovery could bind to the
40+
# wrong port; pin it with an explicit portPath (or narrow with a
41+
# serialNumber) in that case. A given portPath always wins over discovery.
42+
# To re-derive the identity on another unit:
4243
#
4344
# system_profiler SPUSBDataType | grep -A 12 -i millennia
4445
# .venv/bin/python -c "from serial.tools.list_ports import comports; \
4546
# [print(p.device, hex(p.vid or 0), hex(p.pid or 0), p.serial_number) \
4647
# for p in comports()]"
4748

49+
classIdVendor = 0x0483 # STMicroelectronics
50+
classIdProduct = 0x5740 # STM32 Virtual COM Port (generic STM32 CDC identity)
51+
4852
defaultBaudRate = 115200
4953
commandTerminator = "\r" # the eV accepts <CR>, <LF>, or both
5054
minPower = 0.05 # documented eV/Pro-s lower bound
@@ -76,8 +80,23 @@ def __init__(self, portPath=None, serialNumber=None, idProduct=None, idVendor=No
7680
self.laserSerialNumber = None
7781

7882
def doInitializeDevice(self):
79-
try:
83+
if self.portPath is not None:
8084
self.port = SerialPort(portPath=self.portPath)
85+
else:
86+
# Discover by the STM32 USB-CDC identity. serialNumber is a regex
87+
# (PhysicalDevice turns the default into ".*"); pass it only when it
88+
# actually narrows, so SerialPort.matchPorts stays on its vid/pid
89+
# path and never regex-matches against a possibly-None descriptor
90+
# serial.
91+
serialNumber = None if self.serialNumber in (None, ".*") else self.serialNumber
92+
self.port = SerialPort(idVendor=self.idVendor, idProduct=self.idProduct,
93+
serialNumber=serialNumber)
94+
if self.port.portPath is None:
95+
raise PhysicalDevice.UnableToInitialize(
96+
"No Millennia eV found by USB identity {0:#06x}:{1:#06x}. "
97+
"Pass an explicit portPath if several STM32 USB-CDC ports "
98+
"are present.".format(self.idVendor, self.idProduct))
99+
try:
81100
self.port.open(baudRate=self.defaultBaudRate)
82101
self.readIdentity()
83102
except Exception as error:

0 commit comments

Comments
 (0)