Skip to content

USBPort: high-throughput readStream(), serial matching, endpoint-by-address - #120

Merged
dccote merged 1 commit into
masterfrom
improve-usbport-streaming
Oct 21, 2026
Merged

dccote merged 1 commit into
masterfrom
improve-usbport-streaming

Conversation

@dccote

@dccote dccote commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator

Motivation

USBPort.readData() reads one wMaxPacketSize packet at a time into an internal buffer — right for a command/response dialog, but far too slow to drain a high-bandwidth bulk IN stream. A device that bursts faster than the host reads (a camera reading out its sensor) overruns its FIFO, and the data comes back corrupted (periodic striping). So USBPort, as it was, could speak to a camera's command channel but not read its images.

Changes (backward compatible)

  • readStream(length, endPoint=None, chunkSize=None, timeout=None) — read length bytes in large chunks (default wMaxPacketSize * 16 = 16 KB, one SuperSpeed burst) in a tight loop, trimming the final short read. Independent of the internal buffer used by readData.
  • open() now honors serialNumber (via custom_match) so a specific unit can be selected when several identical devices are connected. It was stored but ignored before.
  • endPointForAddress(address) — resolve an endpoint by its USB address (e.g. 0x83), clearer than an interface index on multi-endpoint devices. readData/writeData/flush now accept an endpoint object as well as an index.

Validation (real hardware)

Tested on a ThorLabs Kiralux CS505MUP1 (5 MP polarization camera, VID/PID 1313:4001, USB 3.0, 5 endpoints):

endpoints resolved by address: 0x2 0x82 0x83
sernum: 18658 | model: CS505MUP1
readStream: 7536640/7536640 (100.0%) in 124 ms = 60.9 MB/s
decoded 2047 rows, vmed = 3.0 (clean)

The command dialog runs on EP 0x02/0x82; readStream delivers a full 7.5 MB frame on EP 0x83 at ~61 MB/s with no corruption — where packet-sized readData could not keep up. Driver/context: https://github.com/DCC-Lab/Kiralux-python

🤖 Generated with Claude Code

…tching and endpoint-by-address

readData() reads one wMaxPacketSize packet at a time into an internal buffer, which
is right for a command/response dialog but far too slow to drain a high-bandwidth
bulk IN stream: a device that bursts faster than the host reads (a camera reading
out its sensor) overruns its FIFO and the data comes back corrupted.

- readStream(length, endPoint, chunkSize, timeout): read `length` bytes in large
  chunks (default wMaxPacketSize*16 = 16 KB, a SuperSpeed burst) in a tight loop,
  trimming the final short read. Independent of the internal buffer.
- open() now honors serialNumber (via custom_match) so a specific unit can be
  selected when several identical devices are present; previously it was ignored.
- endPointForAddress(address): resolve an endpoint by its USB address (e.g. 0x83),
  clearer than an interface index on multi-endpoint devices. readData/writeData/
  flush now accept an endpoint object as well as an index (backward compatible).

Validated on a ThorLabs Kiralux CS505MUP1 (5 MP polarization camera): command
dialog on EP 0x02/0x82, and readStream on EP 0x83 delivering a full 7.5 MB frame at
~61 MB/s with no corruption, where packet-sized readData could not keep up.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cwn4LmnBsBpXbQKRh6ByZr
@dccote
dccote merged commit 07567fa into master Oct 21, 2026
14 checks passed
@dccote
dccote deleted the improve-usbport-streaming branch October 21, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant