polling_rate.py
2833 bytes
1#!/usr/bin/env python3
2
3import usb
4
5USB_INTERFACE_CLASS_HID = 0x03
6
7def usb_device_spec(spec):
8 major = spec >> 8
9 minor = (spec >> 4) & 0xF
10 return f"{major}.{minor}"
11
12def usb_device_speed(speed):
13 if speed == 1:
14 return "Low-speed"
15 elif speed == 2:
16 return "Full-speed"
17 elif speed == 3:
18 return "High-speed"
19 elif speed == 4:
20 return "SuperSpeed"
21 elif speed == 5:
22 return "SuperSpeed+"
23
24 return "Speed unknown"
25
26def usb_hid_interface_subclass(subclass):
27 if subclass == 0x00:
28 return "None"
29 elif subclass == 0x01:
30 return "Boot"
31 else:
32 return f"Unknown (0x{subclass:02X})"
33
34def usb_hid_interface_protocol(subclass, protocol):
35 if subclass == 0x00 and protocol == 0x00:
36 return "None"
37 elif subclass == 0x01:
38 if protocol == 0x00:
39 return "None"
40 elif protocol == 0x01:
41 return "Keyboard"
42 elif protocol == 0x02:
43 return "Mouse"
44
45 return f"Unknown (0x{protocol:02X})"
46
47def usb_interface_polling_rate(speed, interval):
48 if speed >= 3:
49 return f"{interval * 125} μs ({8000 // interval} Hz)"
50 else:
51 return f"{interval} ms ({1000 // interval} Hz)"
52
53if __name__ == '__main__':
54 devices = usb.core.find(find_all=True)
55
56 for device in devices:
57 try:
58 configuration = device.get_active_configuration()
59 except NotImplementedError:
60 continue
61
62 hid_interfaces = []
63 for interface in configuration.interfaces():
64 if interface.bInterfaceClass == USB_INTERFACE_CLASS_HID:
65 hid_interfaces.append(interface)
66
67 if len(hid_interfaces) > 0:
68 print(f"{device.manufacturer} {device.product} ({device.idVendor:04X}:{device.idProduct:04X}:{device.bcdDevice:04X}), {usb_device_spec(device.bcdUSB)} {usb_device_speed(device.speed)}")
69
70 for interface in hid_interfaces:
71 print(f"└─ HID Interface {interface.bInterfaceNumber}")
72 subclass = interface.bInterfaceSubClass
73 protocol = interface.bInterfaceProtocol
74 print(f" ├─ Subclass: {usb_hid_interface_subclass(subclass)}")
75 print(f" ├─ Protocol: {usb_hid_interface_protocol(subclass, protocol)}")
76
77 for endpoint in interface.endpoints():
78 endpoint_address = endpoint.bEndpointAddress & 0xF
79 endpoint_direction = "IN" if endpoint.bEndpointAddress & 0x80 else "OUT"
80 print(f" └─ Endpoint {endpoint_address} {endpoint_direction}")
81 print(f" ├─ Endpoint Size: {endpoint.wMaxPacketSize} bytes")
82 print(f" └─ Polling Rate: {usb_interface_polling_rate(device.speed, endpoint.bInterval)}")