24
24
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
25
# THE SOFTWARE.
26
26
27
+ from collections import defaultdict
27
28
import argparse
28
29
import pathlib
29
30
import re
30
31
import sys
31
32
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
+ }
64
59
65
60
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
- )
78
61
79
62
80
63
def configboard_files ():
@@ -87,48 +70,49 @@ def configboard_files():
87
70
return working_dir .glob ("ports/**/boards/**/mpconfigboard.mk" )
88
71
89
72
90
- def check_vid_pid (files , ignorelist ):
73
+ def check_vid_pid (files , clusterlist ):
91
74
"""Compiles a list of USB VID & PID values for all boards, and checks
92
75
for duplicates. Exits with ``sys.exit()`` (non-zero exit code)
93
76
if duplicates are found, and lists the duplicates.
94
77
"""
95
78
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 )
102
82
83
+ usb_ids = defaultdict (set )
103
84
for board_config in files :
104
85
src_text = board_config .read_text ()
105
86
106
87
usb_vid = vid_pattern .search (src_text )
107
88
usb_pid = pid_pattern .search (src_text )
108
-
89
+ non_usb = usb_pattern . search ( src_text )
109
90
board_name = board_config .parts [- 2 ]
110
91
111
- board_ignorelisted = False
112
- if board_name in ignorelist :
113
- board_ignorelisted = True
114
- board_name += " (ignorelisted)"
115
-
116
92
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 ))} " )
120
111
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 ))} " )
131
113
114
+ if duplicates :
115
+ duplicates = "\n " .join (duplicates )
132
116
duplicate_message = (
133
117
f"Duplicate VID/PID usage found!\n { duplicates } \n "
134
118
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):
143
127
arguments = cli_parser .parse_args ()
144
128
145
129
print ("Running USB VID/PID Duplicate Checker..." )
146
- print (f"Ignoring the following boards: { ', ' .join (arguments .ignorelist )} " , end = "\n \n " )
147
130
148
131
board_files = configboard_files ()
149
- check_vid_pid (board_files , arguments . ignorelist )
132
+ check_vid_pid (board_files , DEFAULT_CLUSTERLIST )
0 commit comments