Skip to content

Commit dab479d

Browse files
authored
Merge pull request #9 from Neradoc/add-usb-location
Add usb location
2 parents 8442438 + f805cb4 commit dab479d

File tree

6 files changed

+79
-20
lines changed

6 files changed

+79
-20
lines changed

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ Devices list (MacOS)
102102
'mains': ['code.py'],
103103
'mount_point': '/Volumes/CIRCUITPY',
104104
'name': 'CIRCUITPY'
105-
}]
105+
}],
106+
'usb_location': '0x14630000'
106107
}]
107108
```
108109

@@ -118,6 +119,23 @@ Devices list (MacOS)
118119
### The DeviceInfoDict class
119120
The device list is actually a list of DeviceInfoDict, a subclass of dictionary that adds a few properties as shortcuts for paths in the dictionary, with a default value of `None`.
120121

122+
Dictionary entries:
123+
- **`name`**: USB name of the board (str).
124+
- **`manufacturer`**: USB manufacturer of the board (str).
125+
- **`product_id`**: USB Product ID (int).
126+
- **`vendor_id`**: USB Vendor ID (int).
127+
- **`serial_num`**: USB Serial number of the board (str).
128+
- **`version`**: Circuitpython version, if found.
129+
- **`ports`**: list of serial ports found on the board, dictionaries.
130+
- **`dev`**: port device, used to connect to the port. COM port on windows, dev path on linux (str).
131+
- **`iface`**: interface name for the serial port (str).
132+
- **`volumes`**: list of mounted drives from the board, dictionaries.
133+
- **`name`**: drive name, usually `CIRCUITPY` for Circuitpython or `*BOOT` for a UF2 bootloader drive (str).
134+
- **`mount_point`**: mount path of the drive, letter on windows (str).
135+
- **`mains`**: list of "main" files for Circuitpython (code.py etc.), by order of priority.
136+
- **`usb_location`**: an identifier for the USB port the board is connected to, should be consistent across reboots and modes (bootloader/application).
137+
138+
Shortcuts:
121139
- **`repl`**: REPL port, if any.
122140
- **`data`**: data port, if any.
123141
- **`drive`** and **`volume`**: board drive path.

discotool/usbinfos/usb_descriptor_win32.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@ class DeviceInfo:
2222
"""
2323
Device information class
2424
"""
25-
def __init__(self, vid, pid, manufacturer, product, serial_number):
25+
def __init__(self, vid, pid, manufacturer, product, serial_number, location):
2626
self.vid = vid
2727
self.pid = pid
2828
self.manufacturer = manufacturer
2929
self.product = product
30-
self.serial_number = serial_number
30+
if serial_number == 0:
31+
self.serial_number = ""
32+
else:
33+
self.serial_number = str(serial_number).upper()
34+
self.location = ".".join(f"{i}" for i in location)
3135

3236
def __repr__(self):
3337
return (
@@ -37,6 +41,7 @@ def __repr__(self):
3741
f"\tmanufacturer:{repr(self.manufacturer)},\n"
3842
f"\tproduct:{repr(self.product)},\n"
3943
f"\tserial number:{repr(self.serial_number)}\n"
44+
f"\tlocation:{repr(self.location)}\n"
4045
"}"
4146
)
4247

@@ -147,7 +152,7 @@ def get_str_desc(handle, conn_idx, str_idx):
147152
return ''
148153

149154

150-
def exam_hub(name, level):
155+
def exam_hub(name, level, location):
151156
handle = open_dev(r'\\.\{}'.format(name))
152157
if not handle:
153158
return
@@ -156,11 +161,11 @@ def exam_hub(name, level):
156161
None,
157162
76,
158163
None)
159-
devices = get_hub_ports(handle, buf[6], level)
164+
devices = get_hub_ports(handle, buf[6], level, location)
160165
handle.close()
161166
return devices
162167

163-
def get_hub_ports(handle, num_ports, level):
168+
def get_hub_ports(handle, num_ports, level, location):
164169
devices = []
165170
for idx in range(1, num_ports+1):
166171
info = chr(idx) + '\0'*34
@@ -177,7 +182,7 @@ def get_hub_ports(handle, num_ports, level):
177182
_, vid, pid, vers, manu, prod, seri, _, ishub, _, stat = struct.unpack('=12sHHHBBB3s?6sL', buf[:35])
178183

179184
if ishub:
180-
devices += exam_hub(get_ext_hub_name(handle, idx), level)
185+
devices += exam_hub(get_ext_hub_name(handle, idx), level + 1, location + (idx,))
181186
elif stat == 1:
182187
if (manu != 0 or prod != 0 or seri != 0):
183188
# print('{} [Port{}] {}'.format(' '*level, idx, get_driverkey_name(handle, idx)))
@@ -187,7 +192,7 @@ def get_hub_ports(handle, num_ports, level):
187192
prod = get_str_desc(handle, idx, prod)
188193
if seri != 0:
189194
seri = get_str_desc(handle, idx, seri)
190-
devices.append(DeviceInfo(vid, pid, manu, prod, seri))
195+
devices.append(DeviceInfo(vid, pid, manu, prod, seri, location + (idx,)))
191196
return devices
192197

193198

@@ -213,10 +218,10 @@ def get_all_devices():
213218
None,
214219
76,
215220
None)
216-
devices += get_hub_ports(dev_handle, buf[6], 0)
221+
devices += get_hub_ports(dev_handle, buf[6], 0, (i,))
217222
dev_handle.close()
218223
handle.close()
219-
224+
220225
return [dev for dev in devices if dev.serial_number not in ("","0","''")]
221226

222227
def main():

discotool/usbinfos/usbinfos_linux.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,20 @@ def get_devices_list(drive_info=False):
7575
'mains': mains,
7676
})
7777
#
78-
# go through parents and find "devpath", remove matching parents
78+
# the issue is that we might find duplicates of devices, by finding
79+
# a parent and treating it as the device. So, when we find a device
80+
# that has parents that are previously found devices, we remove
81+
# said parents.
7982
def noParent(dev):
80-
for papa in device.traverse():
81-
if devpath.startswith(dev['devpath']):
82-
return False
83+
# test if the already found device is a parent of the current device
84+
# do we need to loop through its parents ?
85+
if devpath.startswith(dev['devpath']):
86+
return False
8387
return True
84-
deviceList = list(filter(noParent,deviceList))
88+
deviceList = list(filter(noParent, deviceList))
8589
#
86-
if vid not in VIDS and len(ttys) == 0: continue
90+
if vid not in VIDS and len(ttys) == 0:
91+
continue
8792
#
8893
curDevice = {}
8994
curDevice['version'] = version
@@ -95,6 +100,7 @@ def noParent(dev):
95100
curDevice['serial_num'] = SN
96101
curDevice['ports'] = ttys
97102
curDevice['manufacturer'] = manufacturer
103+
curDevice['usb_location'] = devpath.split("/", 4)[-1]
98104
deviceList.append(curDevice)
99105
#
100106
for i in range(len(deviceList)):

discotool/usbinfos/usbinfos_macos.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ def readSysProfile(profile, devices, allMounts, drive_info):
123123
})
124124
curDevice['volumes'] = deviceVolumes
125125
curDevice['version'] = version
126+
curDevice['usb_location'] = subGroup['location_id'].split(" ")[0]
126127
devices += [curDevice]
127128
return devices
128129

discotool/usbinfos/usbinfos_win32.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,13 @@ def get_devices_list(drive_info=False):
6969
curDevice = {}
7070
deviceVolumes = []
7171
name = ""
72-
SN = device
72+
SN = device.upper()
7373

7474
ttys = []
7575
vid = "0"
7676
pid = "0"
7777
manufacturer = ""
78+
location = ""
7879
for port in list(remainingPorts):
7980
if port.serial_number == SN:
8081
vid = port.vid
@@ -121,15 +122,17 @@ def get_devices_list(drive_info=False):
121122
desc = descriptors[uid]
122123
manufacturer = desc.manufacturer or manufacturer
123124
name = desc.product or name
125+
location = desc.location or location
124126

125-
curDevice['version'] = version
126-
curDevice['volumes'] = deviceVolumes
127127
curDevice['name'] = name
128+
curDevice['manufacturer'] = manufacturer
128129
curDevice['vendor_id'] = int(vid)
129130
curDevice['product_id'] = int(pid)
130131
curDevice['serial_num'] = SN
132+
curDevice['volumes'] = deviceVolumes
131133
curDevice['ports'] = ttys
132-
curDevice['manufacturer'] = manufacturer
134+
curDevice['version'] = version
135+
curDevice['usb_location'] = location
133136
deviceList.append(curDevice)
134137

135138
rp = [port.device for port in remainingPorts]

tests/locations.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import discotool
2+
3+
def display(texte):
4+
print(("-" * 70) + "\n-", texte.ljust(70-3) + "-\n" + ("-" * 70))
5+
6+
# display('get_devices_list() ')
7+
# deviceList,remainingPorts = discotool.get_devices_list()
8+
# print(deviceList)
9+
# print(remainingPorts)
10+
11+
# display('Device class/dictionnary ')
12+
for device in discotool.get_identified_devices():
13+
display(device.name)
14+
# print(type(device))
15+
# print("Attributes:")
16+
# print(sorted([
17+
# attr for
18+
# attr in set(dir(device)) - set(dir({"un":1}))
19+
# if attr[0:2] != "__"
20+
# ]))
21+
print("Dict indexes:")
22+
# for x in device:
23+
# print(f"{x:12s} : {device[x]}")
24+
print("location :", device["usb_location"])
25+
26+
display("")

0 commit comments

Comments
 (0)