4343}
4444
4545# Entries here are safe to show without a TTY because the VID/PID identifies a
46- # development-board function rather than an arbitrary USB peripheral.
46+ # known development board, USB function, or bootloader rather than an arbitrary
47+ # USB peripheral.
4748BOARD_IDS = {
48- ("0483" , "5740" ): ("STM32 Virtual COM Port" , "serial" ),
49- ("0483" , "df11" ): ("STM32 DFU Bootloader" , "dfu" ),
50- ("0d28" , "0204" ): ("Arm DAPLink / micro:bit" , "debug" ),
51- ("16c0" , "0478" ): ("Teensy HalfKay Bootloader" , "bootloader" ),
52- ("16c0" , "0483" ): ("Teensy" , "serial" ),
53- ("2341" , "003d" ): ("Arduino Due Programming Port" , "serial" ),
54- ("2341" , "003e" ): ("Arduino Due Native Port" , "serial" ),
55- ("2341" , "0042" ): ("Arduino Mega 2560" , "serial" ),
56- ("2341" , "0043" ): ("Arduino Uno" , "serial" ),
57- ("2341" , "0058" ): ("Arduino Nano Every" , "serial" ),
58- ("2341" , "0070" ): ("Arduino Nano ESP32" , "serial" ),
59- ("2e8a" , "0003" ): ("Raspberry Pi RP2 Bootloader" , "bootloader" ),
60- ("2e8a" , "0005" ): ("Raspberry Pi Pico" , "serial" ),
61- ("2e8a" , "000a" ): ("Raspberry Pi Pico SDK" , "serial" ),
62- ("303a" , "1001" ): ("Espressif USB JTAG/Serial" , "debug" ),
49+ ("0483" , "5740" ): ("STM32 Virtual COM Port" , "serial" , "function" ),
50+ ("0483" , "df11" ): ("STM32 DFU Bootloader" , "dfu" , "bootloader" ),
51+ ("0d28" , "0204" ): ("Arm DAPLink / micro:bit" , "debug" , "function" ),
52+ ("16c0" , "0478" ): ("Teensy HalfKay Bootloader" , "bootloader" , "bootloader" ),
53+ ("16c0" , "0483" ): ("Teensy" , "serial" , "function" ),
54+ ("2341" , "003d" ): ("Arduino Due Programming Port" , "serial" , "board" ),
55+ ("2341" , "003e" ): ("Arduino Due Native Port" , "serial" , "board" ),
56+ ("2341" , "0042" ): ("Arduino Mega 2560" , "serial" , "board" ),
57+ ("2341" , "0043" ): ("Arduino Uno" , "serial" , "board" ),
58+ ("2341" , "0058" ): ("Arduino Nano Every" , "serial" , "board" ),
59+ ("2341" , "0070" ): ("Arduino Nano ESP32" , "serial" , "board" ),
60+ ("2e8a" , "0003" ): ("Raspberry Pi RP2 Bootloader" , "bootloader" , "bootloader" ),
61+ ("2e8a" , "0005" ): ("Raspberry Pi Pico" , "serial" , "function" ),
62+ ("2e8a" , "000a" ): ("Raspberry Pi Pico SDK" , "serial" , "function" ),
63+ ("303a" , "1001" ): ("Espressif USB JTAG/Serial" , "debug" , "function" ),
6364}
6465
6566BOARD_VENDORS = {
@@ -124,18 +125,18 @@ def infer_mode(usb_product: str, has_serial: bool) -> str:
124125 return "serial" if has_serial else "usb"
125126
126127
127- def identify_board_evidence (
128+ def identify_board_details (
128129 vendor : str ,
129130 product : str ,
130131 manufacturer : str ,
131132 usb_product : str ,
132- ) -> tuple [str , str , str ]:
133- """Return board label, confidence, and the evidence used for identification."""
133+ ) -> tuple [str , str , str , str ]:
134+ """Return board label, confidence, evidence, and identification scope ."""
134135
135136 description = f"{ manufacturer } { usb_product } " .lower ()
136137 exact = BOARD_IDS .get ((vendor , product ))
137138 if exact :
138- return exact [0 ], "exact" , "vid-pid"
139+ return exact [0 ], "exact" , "vid-pid" , exact [ 2 ]
139140
140141 names = (
141142 ("nano esp32" , "Arduino Nano ESP32" ),
@@ -147,20 +148,32 @@ def identify_board_evidence(
147148 )
148149 for marker , name in names :
149150 if marker in description :
150- return name , "probable" , "descriptor"
151+ return name , "probable" , "descriptor" , "board"
151152
152153 if "arduino nano" in description :
153- return "Arduino Nano" , "probable" , "descriptor"
154+ return "Arduino Nano" , "probable" , "descriptor" , "board"
154155 if vendor in BOARD_VENDORS :
155156 board = clean_name (usb_product )
156157 if board :
157- return board , "probable" , "descriptor"
158- return BOARD_VENDORS [vendor ], "probable" , "vendor"
158+ return board , "probable" , "descriptor" , "family"
159+ return BOARD_VENDORS [vendor ], "probable" , "vendor" , "family"
159160
160161 bridge = BRIDGES .get ((vendor , product ), "" )
161162 if bridge :
162- return f"Serial development board ({ bridge } )" , "bridge-only" , "bridge"
163- return clean_name (usb_product ) or "USB serial device" , "unknown" , "unknown"
163+ return f"Serial development board ({ bridge } )" , "bridge-only" , "bridge" , "bridge"
164+ return clean_name (usb_product ) or "USB serial device" , "unknown" , "unknown" , "unknown"
165+
166+
167+ def identify_board_evidence (
168+ vendor : str ,
169+ product : str ,
170+ manufacturer : str ,
171+ usb_product : str ,
172+ ) -> tuple [str , str , str ]:
173+ board , confidence , evidence , _scope = identify_board_details (
174+ vendor , product , manufacturer , usb_product
175+ )
176+ return board , confidence , evidence
164177
165178
166179def identify_board (
@@ -284,10 +297,10 @@ def device_identity(
284297def base_device (usb : Path , details : dict [str , str ], has_serial : bool ) -> dict [str , object ]:
285298 vendor = details ["vendor" ]
286299 product = details ["product" ]
287- board , confidence , identification_evidence = identify_board_evidence (
300+ board , confidence , identification_evidence , identification_scope = identify_board_details (
288301 vendor , product , details ["manufacturer" ], details ["usb_product" ]
289302 )
290- known_mode = BOARD_IDS .get ((vendor , product ), ("" , "" ))[1 ]
303+ known_mode = BOARD_IDS .get ((vendor , product ), ("" , "" , "" ))[1 ]
291304 mode = known_mode or infer_mode (details ["usb_product" ], has_serial )
292305 serial = details ["serial" ]
293306 identity_key , identity_evidence , identity_port_bound = device_identity (
@@ -301,6 +314,7 @@ def base_device(usb: Path, details: dict[str, str], has_serial: bool) -> dict[st
301314 "board" : board ,
302315 "confidence" : confidence ,
303316 "identificationEvidence" : identification_evidence ,
317+ "identificationScope" : identification_scope ,
304318 "connected" : True ,
305319 "serialAvailable" : has_serial ,
306320 "mode" : mode ,
0 commit comments