diff --git a/bumble/transport/pyusb.py b/bumble/transport/pyusb.py index 5e686d11..2426b751 100644 --- a/bumble/transport/pyusb.py +++ b/bumble/transport/pyusb.py @@ -216,6 +216,15 @@ async def open_pyusb_transport(spec: str) -> Transport: if ':' in spec: vendor_id, product_id = spec.split(':') device = usb_find(idVendor=int(vendor_id, 16), idProduct=int(product_id, 16)) + elif '-' in spec: + + def device_path(device): + if device.port_numbers: + return f'{device.bus}-{".".join(map(str, device.port_numbers))}' + else: + return str(device.bus) + + device = usb_find(custom_match=lambda device: device_path(device) == spec) else: device_index = int(spec) devices = list( diff --git a/bumble/transport/usb.py b/bumble/transport/usb.py index 12572604..6479016c 100644 --- a/bumble/transport/usb.py +++ b/bumble/transport/usb.py @@ -396,6 +396,16 @@ async def open_usb_transport(spec: str) -> Transport: break device_index -= 1 device.close() + elif '-' in spec: + + def device_path(device): + return f'{device.getBusNumber()}-{".".join(map(str, device.getPortNumberList()))}' + + for device in context.getDeviceIterator(skip_on_error=True): + if device_path(device) == spec: + found = device + break + device.close() else: # Look for a compatible device by index def device_is_bluetooth_hci(device): diff --git a/docs/mkdocs/src/transports/usb.md b/docs/mkdocs/src/transports/usb.md index e4006302..08949f0a 100644 --- a/docs/mkdocs/src/transports/usb.md +++ b/docs/mkdocs/src/transports/usb.md @@ -10,6 +10,7 @@ The moniker for a USB transport is either: * `usb::` * `usb::/` * `usb::#` + * `usb:-` with `` as a 0-based index (0 being the first one) to select amongst all the matching devices when there are more than one. In the `usb:` form, matching devices are the ones supporting Bluetooth HCI, as declared by their Class, Subclass and Protocol. @@ -17,6 +18,8 @@ In the `usb::#` form, matching devices are the ones with `` and `` are a vendor ID and product ID in hexadecimal. +with `` as a list of all port numbers from root separated with dots `.` + In addition, if the moniker ends with the symbol "!", the device will be used in "forced" mode: the first USB interface of the device will be used, regardless of the interface class/subclass. This may be useful for some devices that use a custom class/subclass but may nonetheless work as-is. @@ -37,6 +40,9 @@ This may be useful for some devices that use a custom class/subclass but may non `usb:0B05:17CB!` The BT USB dongle vendor=0B05 and product=17CB, in "forced" mode. + `usb:3-3.4.1` + The BT USB dongle on bus 3 on port path 3, 4, 1. + ## Alternative The library includes two different implementations of the USB transport, implemented using different python bindings for `libusb`.