Problem
When a shared-transport device (e.g. the bidirectional EA PSB10000, which vends both a PSUDriverBase .source view and an ELoadDriverBase .sink view over one VisaDriver) has publishers/background daemons running on more than one of its Instro* views, each view's Instrument background daemon runs on its own independent thread with its own poll_interval, unaware of any sibling instrument sharing the same underlying transport.
TransportBase/VisaDriver (instro/lib/transports/) already serialize concurrent access with a per-call RLock, so wire bytes never interleave — but nothing limits the combined rate of commands issued against one transport. Two independently-polling views can issue back-to-back commands fast enough to overrun the physical device's command/error-queue buffer. On the EA PSB10000 specifically, SYST:ERR? is queried immediately after every write/query (EAPSB10000Visa._write_checked/_query_checked), and the device queues errors asynchronously (~10-15ms per manual, ~100ms empirically safe per tests/psu/ea/test_ea_psb10000_hardware.py) — so concurrent pollers can outrun that queue and corrupt/drop error-check reads.
This isn't PSB-specific: any device class that vends multiple category views over one shared transport (per the "device serving more than one category" pattern in AGENTS.md) is exposed to the same failure once more than one view runs a background daemon/publisher.
Fix direction
Add a minimum inter-command spacing enforced inside the transport's own locked critical section (TransportBase/VisaDriver), so it throttles at the shared-resource level regardless of how many Instrument instances/threads are contending for it. This generalizes to any shared-transport driver without touching per-instrument polling config or the Instrument daemon architecture.
Repro
- Construct an
EAPSB10000Visa, get both .source (wrap in InstroPSU) and .sink (wrap in InstroELoad), attach publishers/background daemons to both, start() both with default poll_interval=1.0.
- Observe
SYST:ERR? failures / dropped or garbled responses on the shared VISA line as both daemons' ticks race.
Problem
When a shared-transport device (e.g. the bidirectional EA PSB10000, which vends both a
PSUDriverBase.sourceview and anELoadDriverBase.sinkview over oneVisaDriver) has publishers/background daemons running on more than one of itsInstro*views, each view'sInstrumentbackground daemon runs on its own independent thread with its ownpoll_interval, unaware of any sibling instrument sharing the same underlying transport.TransportBase/VisaDriver(instro/lib/transports/) already serialize concurrent access with a per-callRLock, so wire bytes never interleave — but nothing limits the combined rate of commands issued against one transport. Two independently-polling views can issue back-to-back commands fast enough to overrun the physical device's command/error-queue buffer. On the EA PSB10000 specifically,SYST:ERR?is queried immediately after every write/query (EAPSB10000Visa._write_checked/_query_checked), and the device queues errors asynchronously (~10-15ms per manual, ~100ms empirically safe pertests/psu/ea/test_ea_psb10000_hardware.py) — so concurrent pollers can outrun that queue and corrupt/drop error-check reads.This isn't PSB-specific: any device class that vends multiple category views over one shared transport (per the "device serving more than one category" pattern in
AGENTS.md) is exposed to the same failure once more than one view runs a background daemon/publisher.Fix direction
Add a minimum inter-command spacing enforced inside the transport's own locked critical section (
TransportBase/VisaDriver), so it throttles at the shared-resource level regardless of how manyInstrumentinstances/threads are contending for it. This generalizes to any shared-transport driver without touching per-instrument polling config or theInstrumentdaemon architecture.Repro
EAPSB10000Visa, get both.source(wrap inInstroPSU) and.sink(wrap inInstroELoad), attach publishers/background daemons to both,start()both with defaultpoll_interval=1.0.SYST:ERR?failures / dropped or garbled responses on the shared VISA line as both daemons' ticks race.