Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions hardwarelibrary/sources/millennia.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,24 @@ class MillenniaEv25Device(LaserSourceDevice, OnOffControl, ShutterControl, Power

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

classIdVendor = 0x0483 # STMicroelectronics
classIdProduct = 0x5740 # STM32 Virtual COM Port (generic STM32 CDC identity)

defaultBaudRate = 115200
commandTerminator = "\r" # the eV accepts <CR>, <LF>, or both
minPower = 0.05 # documented eV/Pro-s lower bound
Expand Down Expand Up @@ -76,8 +80,23 @@ def __init__(self, portPath=None, serialNumber=None, idProduct=None, idVendor=No
self.laserSerialNumber = None

def doInitializeDevice(self):
try:
if self.portPath is not None:
self.port = SerialPort(portPath=self.portPath)
else:
# Discover by the STM32 USB-CDC identity. serialNumber is a regex
# (PhysicalDevice turns the default into ".*"); pass it only when it
# actually narrows, so SerialPort.matchPorts stays on its vid/pid
# path and never regex-matches against a possibly-None descriptor
# serial.
serialNumber = None if self.serialNumber in (None, ".*") else self.serialNumber
self.port = SerialPort(idVendor=self.idVendor, idProduct=self.idProduct,
serialNumber=serialNumber)
if self.port.portPath is None:
raise PhysicalDevice.UnableToInitialize(
"No Millennia eV found by USB identity {0:#06x}:{1:#06x}. "
"Pass an explicit portPath if several STM32 USB-CDC ports "
"are present.".format(self.idVendor, self.idProduct))
try:
self.port.open(baudRate=self.defaultBaudRate)
self.readIdentity()
except Exception as error:
Expand Down
Loading