Parent directory

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)}")