Skip to content

Commit a07ac72

Browse files
committed
Improve the USB vid:pid duplicate checker
To me, it made more sense to track which boards go together in a cluster; when reviewing a request to actually use a duplicate vid/pid, you want to know what board(s) it is aliasing. I also revamped the detection of non-USB boards so that a board .mk file that couldn't be parsed by the code here would raise a problem instead of just being skipped for the purposes of checking. There were some lines with comments on the end, and some variation in capitalization of the IDs. These are all normalized and a (sometimes unfriendly!) error printed when it's incorrect. Before this, here were some ways to trick the duplicate vid/pid checker: ``` USB_PID = 0XABCD USB_PID = 0xAbCd USB_PID = 0xABCD # harmless comment? ``` None of these things were ever done on purpose.
1 parent b439464 commit a07ac72

File tree

4 files changed

+61
-75
lines changed

4 files changed

+61
-75
lines changed

ports/atmel-samd/boards/sparkfun_samd51_micromod/mpconfigboard.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
LD_FILE = boards/samd51x20-bootloader-external-flash.ld
22
USB_VID = 0x1b4f
3-
USB_PID = 0x0020 # Used by uf2 bootloader
3+
# Used by uf2 bootloader
4+
USB_PID = 0x0020
45
USB_PRODUCT = "SparkFun MicroMod SAMD51 Processor"
56
USB_MANUFACTURER = "SparkFun Electronics"
67

ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
LD_FILE = boards/samd51x20-bootloader-external-flash.ld
22
USB_VID = 0x1b4f
3-
USB_PID = 0x0016 # Used by uf2 bootloader
3+
# Used by uf2 bootloader
4+
USB_PID = 0x0016
45
USB_PRODUCT = "SparkFun SAMD51 Thing+"
56
USB_MANUFACTURER = "SparkFun Electronics"
67

ports/nrf/boards/particle_xenon/mpconfigboard.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
USB_VID = 0x2b04
2-
USB_PID = 0xc00e # argon is 0xc00c
2+
# argon is 0xc00c
3+
USB_PID = 0xc00e
34
USB_PRODUCT = "Xenon"
45
USB_MANUFACTURER = "Particle"
56

tools/ci_check_duplicate_usb_vid_pid.py

Lines changed: 55 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -24,57 +24,40 @@
2424
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2525
# THE SOFTWARE.
2626

27+
from collections import defaultdict
2728
import argparse
2829
import pathlib
2930
import re
3031
import sys
3132

32-
DEFAULT_IGNORELIST = [
33-
"circuitplayground_express",
34-
"circuitplayground_express_crickit",
35-
"circuitplayground_express_displayio",
36-
"pycubed",
37-
"pycubed_mram",
38-
"pycubed_v05",
39-
"pycubed_mram_v05",
40-
"pygamer",
41-
"pygamer_advance",
42-
"trinket_m0",
43-
"trinket_m0_haxpress",
44-
"sparkfun_qwiic_micro_with_flash",
45-
"sparkfun_qwiic_micro_no_flash",
46-
"feather_m0_express",
47-
"feather_m0_supersized",
48-
"cp32-m4",
49-
"metro_m4_express",
50-
"unexpectedmaker_feathers2",
51-
"unexpectedmaker_feathers2_prerelease",
52-
"espressif_kaluga_1",
53-
"espressif_kaluga_1.3",
54-
"espressif_esp32s2_devkitc_1_n4r2",
55-
"espressif_esp32s3_devkitc_1_n8",
56-
"espressif_esp32s3_devkitc_1_n8r2",
57-
"espressif_esp32s3_devkitc_1_n8r8",
58-
"espressif_saola_1_wrover",
59-
"jpconstantineau_pykey18",
60-
"jpconstantineau_pykey44",
61-
"jpconstantineau_pykey60",
62-
"jpconstantineau_pykey87",
63-
]
33+
DEFAULT_CLUSTERLIST = {
34+
"0x04D8:0xEC44": ["pycubed", "pycubed_mram", "pycubed_mram_v05", "pycubed_v05"],
35+
"0x1B4F:0x8D24": ["sparkfun_qwiic_micro_no_flash", "sparkfun_qwiic_micro_with_flash"],
36+
"0x1D50:0x6153": [
37+
"jpconstantineau_pykey18",
38+
"jpconstantineau_pykey44",
39+
"jpconstantineau_pykey60",
40+
"jpconstantineau_pykey87",
41+
],
42+
"0x239A:0x8019": [
43+
"circuitplayground_express",
44+
"circuitplayground_express_crickit",
45+
"circuitplayground_express_displayio",
46+
],
47+
"0x239A:0x801F": ["trinket_m0_haxpress", "trinket_m0"],
48+
"0x239A:0x8021": ["metro_m4_express", "cp32-m4"],
49+
"0x239A:0x8023": ["feather_m0_express", "feather_m0_supersized"],
50+
"0x239A:0x80A6": ["espressif_esp32s2_devkitc_1_n4r2", "espressif_saola_1_wrover"],
51+
"0x239A:0x80AC": ["unexpectedmaker_feathers2", "unexpectedmaker_feathers2_prerelease"],
52+
"0x239A:0x80C8": ["espressif_kaluga_1", "espressif_kaluga_1.3"],
53+
"0x303A:0x7003": [
54+
"espressif_esp32s3_devkitc_1_n8",
55+
"espressif_esp32s3_devkitc_1_n8r2",
56+
"espressif_esp32s3_devkitc_1_n8r8",
57+
],
58+
}
6459

6560
cli_parser = argparse.ArgumentParser(description="USB VID/PID Duplicate Checker")
66-
cli_parser.add_argument(
67-
"--ignorelist",
68-
dest="ignorelist",
69-
nargs="?",
70-
action="store",
71-
default=DEFAULT_IGNORELIST,
72-
help=(
73-
"Board names to ignore duplicate VID/PID combinations. Pass an empty "
74-
"string to disable all duplicate ignoring. Defaults are: "
75-
f"{', '.join(DEFAULT_IGNORELIST)}"
76-
),
77-
)
7861

7962

8063
def configboard_files():
@@ -87,48 +70,49 @@ def configboard_files():
8770
return working_dir.glob("ports/**/boards/**/mpconfigboard.mk")
8871

8972

90-
def check_vid_pid(files, ignorelist):
73+
def check_vid_pid(files, clusterlist):
9174
"""Compiles a list of USB VID & PID values for all boards, and checks
9275
for duplicates. Exits with ``sys.exit()`` (non-zero exit code)
9376
if duplicates are found, and lists the duplicates.
9477
"""
9578

96-
duplicates_found = False
97-
98-
usb_ids = {}
99-
100-
vid_pattern = re.compile(r"^USB_VID\s*\=\s*(.*)", flags=re.M)
101-
pid_pattern = re.compile(r"^USB_PID\s*\=\s*(.*)", flags=re.M)
79+
vid_pattern = re.compile(r"^USB_VID\s*=\s*(.*)", flags=re.M)
80+
pid_pattern = re.compile(r"^USB_PID\s*=\s*(.*)", flags=re.M)
81+
usb_pattern = re.compile(r"^CIRCUITPY_USB\s*=\s*0$|^IDF_TARGET = esp32c3$", flags=re.M)
10282

83+
usb_ids = defaultdict(set)
10384
for board_config in files:
10485
src_text = board_config.read_text()
10586

10687
usb_vid = vid_pattern.search(src_text)
10788
usb_pid = pid_pattern.search(src_text)
108-
89+
non_usb = usb_pattern.search(src_text)
10990
board_name = board_config.parts[-2]
11091

111-
board_ignorelisted = False
112-
if board_name in ignorelist:
113-
board_ignorelisted = True
114-
board_name += " (ignorelisted)"
115-
11692
if usb_vid and usb_pid:
117-
id_group = f"{usb_vid.group(1)}:{usb_pid.group(1)}"
118-
if id_group not in usb_ids:
119-
usb_ids[id_group] = {"boards": [board_name], "duplicate": False}
93+
id_group = f"0x{int(usb_vid.group(1), 16):04X}:0x{int(usb_pid.group(1), 16):04X}"
94+
elif non_usb:
95+
continue
96+
else:
97+
raise SystemExit(f"Could not parse {board_config}")
98+
99+
usb_ids[id_group].add(board_name)
100+
101+
duplicates = []
102+
for key, boards in usb_ids.items():
103+
if len(boards) == 1:
104+
continue
105+
106+
# It is a cluster
107+
cluster = set(clusterlist.get(key, []))
108+
if cluster != boards:
109+
if key == "":
110+
duplicates.append(f"- Non-USB:\n" f" Boards: {', '.join(sorted(boards))}")
120111
else:
121-
usb_ids[id_group]["boards"].append(board_name)
122-
if not board_ignorelisted:
123-
usb_ids[id_group]["duplicate"] = True
124-
duplicates_found = True
125-
126-
if duplicates_found:
127-
duplicates = ""
128-
for key, value in usb_ids.items():
129-
if value["duplicate"]:
130-
duplicates += f"- VID/PID: {key}\n" f" Boards: {', '.join(value['boards'])}\n"
112+
duplicates.append(f"- VID/PID: {key}\n" f" Boards: {', '.join(sorted(boards))}")
131113

114+
if duplicates:
115+
duplicates = "\n".join(duplicates)
132116
duplicate_message = (
133117
f"Duplicate VID/PID usage found!\n{duplicates}\n"
134118
f"If you are open source maker, then you can request a PID from http://pid.codes\n"
@@ -143,7 +127,6 @@ def check_vid_pid(files, ignorelist):
143127
arguments = cli_parser.parse_args()
144128

145129
print("Running USB VID/PID Duplicate Checker...")
146-
print(f"Ignoring the following boards: {', '.join(arguments.ignorelist)}", end="\n\n")
147130

148131
board_files = configboard_files()
149-
check_vid_pid(board_files, arguments.ignorelist)
132+
check_vid_pid(board_files, DEFAULT_CLUSTERLIST)

0 commit comments

Comments
 (0)