Python toolkit for controlling lab test instruments (oscilloscopes, power supplies, logic analyzers) over VISA and sigrok. Built for hardware reverse engineering and automated test workflows.
- Python 3.13+
- uv (for dependency management)
- Instruments accessible via VISA (TCP/IP or serial) or sigrok-supported logic analyzers
# Clone the repository
git clone https://github.com/wrongbaud/conduit.git
cd conduit
# Install dependencies with uv
uv syncScopeControl wraps a VISA-connected oscilloscope (tested with Rigol) and provides methods for:
- Capturing screenshots (
get_screenshot) - Extracting raw waveform data from analog channels (
extract_waveform) - Extracting raw data from digital/logic channels (
extract_logic) - Saving waveforms as WMF or CSV to instrument storage (
save_wav,save_csv) - Toggling channel display (
channel_display) - Setting single-shot triggers (
set_single_trigger) - Interposing multi-channel captures for import into PulseView (
interpose_analog_captures,interpose_digital_captures)
PowerControl wraps a VISA-connected programmable power supply and provides methods for:
- Setting voltage and current (
set_voltage,set_current) - Reading configured voltage and current (
get_voltage,get_current) - Measuring actual output voltage and current (
measure_voltage,measure_current) - Toggling output on/off (
turn_output_on,turn_output_off)
SigrokController wraps the sigrok-cli command-line tool and provides methods for:
- Scanning for connected devices (
scan) - Listing supported hardware and protocol decoders (
list_supported) - Performing captures with configurable sample rate, channel selection, triggers, and protocol decoders (
capture) - Outputting to
.srsession files for use with PulseView
Connect to a network-attached oscilloscope, extract a waveform from channel 1, and save a screenshot:
from conduit.scopectl import ScopeControl
scope = ScopeControl("TCPIP::192.168.0.103::INSTR")
scope.extract_waveform(["1"], "output-captures")
scope.get_screenshot("capture.png")Connect to a serial power supply, configure voltage/current limits, and cycle the output:
from conduit.powerctl import PowerControl
import time
power = PowerControl("ASRL/dev/ttyUSB1::INSTR")
power.inst.baud_rate = 115200
power.set_voltage(12.0, channel=1)
power.set_current(1.0, channel=1)
power.turn_output_on(channel=1)
time.sleep(10)
power.turn_output_off(channel=1)Use both the power supply and oscilloscope together to capture UART boot output from a target device:
from conduit.scopectl import ScopeControl
from conduit.powerctl import PowerControl
import time
power = PowerControl("ASRL/dev/ttyUSB1::INSTR")
power.inst.baud_rate = 115200
scope = ScopeControl("TCPIP::192.168.0.105::INSTR")
# Configure power supply
power.set_voltage(5.0, channel=1)
power.set_current(0.5, channel=1)
# Arm scope in single-trigger mode, power on the target, and capture
scope.set_single_trigger()
power.turn_output_off(channel=1)
time.sleep(0.5)
power.turn_output_on(channel=1)
# Extract waveform data and a screenshot after trigger fires
scope.extract_waveform(["1"], "boot-capture")
scope.get_screenshot("boot-capture.png")
power.turn_output_off(channel=1)