"""Siglent SPD3303X-E PSU controller over VXI-11 / SCPI. Drives the display 3.3 V rail so the master loop can power-cycle the PCB between captures. """ from __future__ import annotations import logging import time import vxi11 from config import ( PSU_CHANNEL_DISPLAY, PSU_DISPLAY_CURRENT, PSU_DISPLAY_VOLTAGE, PSU_POWER_CYCLE_DELAY_S, ) log = logging.getLogger(__name__) class PSUController: def __init__(self, ip: str) -> None: self.ip = ip self._inst = vxi11.Instrument(ip) idn = self._inst.ask("*IDN?").strip() log.info("PSU connected: %s", idn) self.idn = idn ch = PSU_CHANNEL_DISPLAY self._inst.write(f"CH{ch}:VOLTage {PSU_DISPLAY_VOLTAGE}") self._inst.write(f"CH{ch}:CURRent {PSU_DISPLAY_CURRENT}") self.output_off() def output_on(self) -> None: self._inst.write(f"OUTPut CH{PSU_CHANNEL_DISPLAY},ON") def output_off(self) -> None: self._inst.write(f"OUTPut CH{PSU_CHANNEL_DISPLAY},OFF") def power_cycle(self, delay_s: float = PSU_POWER_CYCLE_DELAY_S) -> None: self.output_off() time.sleep(delay_s) self.output_on() def measure(self) -> dict: ch = PSU_CHANNEL_DISPLAY voltage = float(self._inst.ask(f"MEASure:VOLTage? CH{ch}")) current = float(self._inst.ask(f"MEASure:CURRent? CH{ch}")) return {"voltage_v": voltage, "current_a": current} def close(self) -> None: try: self._inst.close() except Exception: pass