PyUSB backend that connects to a USB/IP server as a client, using Linux-kernel-compatible USB/IP wire protocol messages.
OP_REQ_DEVLIST+OP_REQ_IMPORT- USB/IP URB submit/reply flow
- PyUSB backend interface implementation (
usb.backend.IBackend) - Control transfers over EP0
- Descriptor discovery over control requests
- mDNS discovery helper for
_usbip._tcpservices - CLI for backend testing
- Wireshark capture (pcapng) of USB URBs to file or live via named pipe
- ESP syslog receiver (RFC 5424 over TCP), printed to console and captured alongside USB traffic
discover uses the cross-platform Python zeroconf library (no shelling out to Avahi tools).
python -m pip install -e .Discover USB/IP servers advertised via mDNS:
usbip-pyusb-test discoverList exported devices:
usbip-pyusb-test --host <server-ip> listProbe a device through PyUSB:
usbip-pyusb-test --host <server-ip> probe --vid 0x303a --pid 0x4004 --get-device-descIssue a control IN transfer:
usbip-pyusb-test --host <server-ip> control \
--vid 0x303a --pid 0x4004 \
--direction in \
--bm-request-type 0x80 --b-request 0x06 --w-value 0x0100 --length 18Add --pcap <path> to any CLI command to log USB URBs in pcapng format.
Add --syslog to also receive ESP log output (RFC 5424 over TCP port 1514)
and include it in the capture.
The pcapng file contains two interfaces that Wireshark displays together:
usbip0-- USB URB trafficsyslog0-- ESP syslog messages (decoded by Wireshark's syslog dissector)
usbip-pyusb-test --host <server-ip> --pcap capture.pcapng --syslog \
probe --vid 0x303a --pid 0x4004
wireshark capture.pcapngUse a named pipe so Wireshark displays packets as they happen:
mkfifo /tmp/usb.pcap
wireshark -k -i /tmp/usb.pcap &
usbip-pyusb-test --host <server-ip> --pcap /tmp/usb.pcap --syslog \
probe --vid 0x303a --pid 0x4004Print ESP logs to stderr without capturing:
usbip-pyusb-test --host <server-ip> --syslog list# Capture USB + syslog to file
python test_integration.py 192.168.1.94 --pcap capture.pcapng --syslog
# Live view
mkfifo /tmp/usb.pcap
wireshark -k -i /tmp/usb.pcap &
python test_integration.py 192.168.1.94 --pcap /tmp/usb.pcap --syslogfrom usbip_backend.pcap import PcapWriter
from usbip_backend.syslog import SyslogReceiver
from usbip_backend import get_backend
pcap = PcapWriter(open("capture.pcapng", "wb"))
syslog = SyslogReceiver("192.168.1.20", pcap=pcap)
syslog.start()
backend = get_backend("192.168.1.20", pcap=pcap)
dev = usb.core.find(backend=backend, idVendor=0x303A, idProduct=0x4004)
# USB URBs and syslog messages are both logged to capture.pcapngimport usb.core
from usbip_backend import get_backend
backend = get_backend("192.168.1.20")
dev = usb.core.find(backend=backend, idVendor=0x303A, idProduct=0x4004)
if dev is not None:
data = dev.ctrl_transfer(0x80, 0x06, 0x0100, 0, 18)
print(bytes(data))If you want esptool / idf.py to open a custom URL like usbip://...,
PySerial supports this via protocol handler modules discovered by
serial.serial_for_url().
serial_for_url("<scheme>://...")extracts<scheme>.- It tries to import
protocol_<scheme>from each package listed inserial.protocol_handler_packages. - The handler module must provide a
Serialclass implementing the PySerial API (typically by subclassingserial.serialutil.SerialBase).
So for usbip://..., PySerial looks for protocol_usbip.py.
src/
yourpkg/
urlhandler/
__init__.py
protocol_usbip.py # defines class Serial(...)
import serial
# package containing protocol_usbip.py
serial.protocol_handler_packages.append("yourpkg.urlhandler")
ser = serial.serial_for_url("usbip://192.168.1.20/1-2.3", timeout=1)# src/yourpkg/urlhandler/protocol_usbip.py
from serial.serialutil import SerialBase
class Serial(SerialBase):
def open(self):
if self.is_open:
return
# parse self.portstr (usbip://...)
# connect transport
self.is_open = True
def close(self):
self.is_open = False
def read(self, size=1):
return b"" # return up to size bytes
def write(self, data):
return len(data)
@property
def in_waiting(self):
return 0
def reset_input_buffer(self):
pass
def reset_output_buffer(self):
passFor reliable ESP bootloader entry, implement DTR/RTS semantics correctly
(ser.dtr = ..., ser.rts = ...) and honor read/write timeout behavior.
esptool relies on these during connect/reset.