Skip to content

Discover the Millennia eV port by its STM32 USB-CDC VID/PID#108

Merged
dccote merged 1 commit into
masterfrom
millennia-vidpid-discovery
Jul 7, 2026
Merged

Discover the Millennia eV port by its STM32 USB-CDC VID/PID#108
dccote merged 1 commit into
masterfrom
millennia-vidpid-discovery

Conversation

@dccote

@dccote dccote commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Problem

MillenniaEv25Device could only be constructed with an explicit portPathdoInitializeDevice opened SerialPort(portPath=...) and never fell back to VID/PID discovery. A caller (e.g. the MillenniaUI app) had to know the OS port name up front, and the class set no classIdVendor/classIdProduct to identify the device.

Solution

  • Set classIdVendor = 0x0483 / classIdProduct = 0x5740 — the STM32 Virtual COM Port identity the lab eV25s enumerates as (confirmed on the bench).
  • doInitializeDevice now discovers the port by that identity when no portPath is given, mirroring FieldMasterDevice: it builds SerialPort(idVendor, idProduct, serialNumber)matchAnyPort over pyserial's comports(), and raises a clear UnableToInitialize naming the identity when nothing matches.

Precedence for the UI:

  • MillenniaDevice(portPath=...) → uses that exact port (still wins).
  • MillenniaDevice() → auto-discovers by 0x0483:0x5740.
  • MillenniaDevice(serialNumber="3239") → discovery narrowed by USB descriptor serial (for hosts with more than one STM32 CDC port).

serialNumber is forwarded only when it actually narrows, so matchPorts stays on its vid/pid path and never regex-matches a possibly-None descriptor serial.

Caveat (documented in code)

0x0483:0x5740 is STMicro's generic STM32 VCP identity, shared by many unrelated STM32 boards. On a host with another STM32 CDC device, discovery could bind to the wrong port — pin portPath (or pass serialNumber) there.

Tests

DebugMillenniaEv25Device is unaffected (it overrides doInitializeDevice and keeps its own fake identity). Smoke-checked: identity resolves, discovery raises cleanly with no hardware, debug device initializes. testMillennia.py: 14 passed, 6 skipped.

🤖 Generated with Claude Code

Problem: MillenniaEv25Device could only be constructed with an explicit
portPath; doInitializeDevice opened SerialPort(portPath=...) and never fell
back to VID/PID discovery, so a caller (e.g. the MillenniaUI app) had to know
the OS port name up front. The class did not set classIdVendor/classIdProduct,
so nothing identified the device by its USB descriptor.

Solution: Set classIdVendor = 0x0483 / classIdProduct = 0x5740 (the STM32
Virtual COM Port identity the lab eV25s enumerates as) and have
doInitializeDevice discover the port by that identity when no portPath is
given, mirroring FieldMasterDevice: it builds SerialPort(idVendor, idProduct,
serialNumber) -> matchAnyPort over pyserial's comports(), and raises a clear
UnableToInitialize naming the identity when nothing matches. An explicit
portPath still wins; a serialNumber narrows discovery when several STM32 CDC
ports are present. serialNumber is passed only when it actually narrows, so
matchPorts stays on its vid/pid path and never regex-matches a possibly-None
descriptor serial. The generic-STM32-VCP caveat is documented in the code.

DebugMillenniaEv25Device is unaffected: it overrides doInitializeDevice and
keeps its own fake identity. testMillennia.py passes (14 passed, 6 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dccote
dccote merged commit 16b7306 into master Jul 7, 2026
14 checks passed
@dccote
dccote deleted the millennia-vidpid-discovery branch July 7, 2026 04:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant