From b836c348a3f7e586c89719c38e88bf7d0a9ec435 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Tue, 3 Feb 2026 21:15:16 +0100 Subject: [PATCH 1/9] Fix unresolved types in Keysight_344xxA_submodules --- .../Keysight/private/Keysight_344xxA_submodules.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/private/Keysight_344xxA_submodules.py b/src/qcodes/instrument_drivers/Keysight/private/Keysight_344xxA_submodules.py index 2fcf0bca27a..4166adca35f 100644 --- a/src/qcodes/instrument_drivers/Keysight/private/Keysight_344xxA_submodules.py +++ b/src/qcodes/instrument_drivers/Keysight/private/Keysight_344xxA_submodules.py @@ -553,9 +553,8 @@ def _acquire_time_trace(self) -> npt.NDArray[np.float64]: npts = self.instrument.timetrace_npts() meas_time = npts * dt disp_text = f"Acquiring {npts} samples" # display limit: 40 characters - new_timeout = max( - self._acquire_timeout_fudge_factor * meas_time, self.instrument.timeout() - ) + old_timeout = self.instrument.timeout() or float("inf") + new_timeout = max(self._acquire_timeout_fudge_factor * meas_time, old_timeout) with ExitStack() as stack: stack.enter_context(self.instrument.trigger.count.set_to(1)) @@ -583,7 +582,7 @@ def get_raw(self) -> npt.NDArray[np.float64]: return data -class TimeAxis(Parameter): +class TimeAxis(Parameter[npt.NDArray, "Keysight344xxA"]): """ A simple :class:`.Parameter` that holds all the times (relative to the measurement start) at which the points of the time trace were acquired. From 08592be7a767becb4088de71c27cf27789e8ff0d Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Tue, 3 Feb 2026 21:37:14 +0100 Subject: [PATCH 2/9] Fix unresolved types in Keysight N52xx --- .../instrument_drivers/Keysight/N52xx.py | 27 +++++++++++++++---- .../keysightb1500/KeysightB1500_base.py | 2 +- .../keysightb1500/KeysightB1500_module.py | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/N52xx.py b/src/qcodes/instrument_drivers/Keysight/N52xx.py index 9ebc10609a8..cdca5202340 100644 --- a/src/qcodes/instrument_drivers/Keysight/N52xx.py +++ b/src/qcodes/instrument_drivers/Keysight/N52xx.py @@ -8,6 +8,7 @@ from qcodes.instrument import ( ChannelList, + ChannelTuple, InstrumentBaseKWArgs, InstrumentChannel, VisaInstrument, @@ -69,7 +70,7 @@ def get_raw(self) -> npt.NDArray: return np.linspace(0, self._stopparam(), self._pointsparam()) -class FormattedSweep(ParameterWithSetpoints): +class FormattedSweep(ParameterWithSetpoints[npt.NDArray, "KeysightPNATrace"]): """ Mag will run a sweep, including averaging, before returning data. As such, wait time in a loop is not needed. @@ -96,7 +97,7 @@ def setpoints(self) -> "Sequence[ParameterBase]": """ if self.instrument is None: raise RuntimeError("Cannot return setpoints if not attached to instrument") - root_instrument: KeysightPNABase = self.root_instrument # type: ignore[assignment] + root_instrument: KeysightPNABase = self.root_instrument sweep_type = root_instrument.sweep_type() if sweep_type == "LIN": return (root_instrument.frequency_axis,) @@ -115,10 +116,16 @@ def setpoints(self, setpoints: Any) -> None: """ return + @property + def root_instrument(self) -> "KeysightPNABase": + root_instrument = super().root_instrument + assert isinstance(root_instrument, KeysightPNABase) + return root_instrument + def get_raw(self) -> npt.NDArray: if self.instrument is None: raise RuntimeError("Cannot get data without instrument") - root_instr = self.instrument.root_instrument + root_instr = self.root_instrument # Check if we should run a new sweep auto_sweep = root_instr.auto_sweep() @@ -182,7 +189,7 @@ def _set_power_limits(self, min_power: float, max_power: float) -> None: "Alis for backwards compatibility" -class KeysightPNATrace(InstrumentChannel): +class KeysightPNATrace(InstrumentChannel["KeysightPNABase"]): """ Allow operations on individual PNA traces. """ @@ -292,6 +299,12 @@ def __init__( ) """Parameter polar""" + @property + def root_instrument(self) -> "KeysightPNABase": + root_instrument = super().root_instrument + assert isinstance(root_instrument, KeysightPNABase) + return root_instrument + def disable(self) -> None: """ Disable this trace on the PNA @@ -438,7 +451,11 @@ def __init__( ) ports.append(port) self.add_submodule(f"port{port_num}", port) - self.add_submodule("ports", ports.to_channel_tuple()) + + self.ports: ChannelTuple[KeysightPNAPort] = self.add_submodule( + "ports", ports.to_channel_tuple() + ) + """Tuple of KeysightPNAPort submodules""" # RF output self.output: Parameter = self.add_parameter( diff --git a/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_base.py b/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_base.py index e24ac2addf1..d25f4a970cb 100644 --- a/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_base.py +++ b/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_base.py @@ -340,7 +340,7 @@ def self_calibration( """ msg = MessageBuilder().cal_query(slot=slot) - with self.root_instrument.timeout.set_to(self.calibration_time_out): + with self.timeout.set_to(self.calibration_time_out): response = self.ask(msg.message) return constants.CALResponse(int(response)) diff --git a/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_module.py b/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_module.py index 458bc0c75f7..9a219dc378c 100644 --- a/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_module.py +++ b/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_module.py @@ -373,7 +373,7 @@ def clear_timer_count(self) -> None: is not effective for the 4 byte binary data output format (FMT3 and FMT4). """ - self.root_instrument.clear_timer_count(chnum=self.channels) + self.parent.clear_timer_count(chnum=self.channels) class StatusMixin: From 16de596416db83ba1385c6143877ec31cc496e4c Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Tue, 3 Feb 2026 21:39:20 +0100 Subject: [PATCH 3/9] Fix unresolved types in Keysight 33xxx --- .../instrument_drivers/Keysight/KeysightAgilent_33XXX.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/KeysightAgilent_33XXX.py b/src/qcodes/instrument_drivers/Keysight/KeysightAgilent_33XXX.py index ae980f494cb..1a6a7cf5b70 100644 --- a/src/qcodes/instrument_drivers/Keysight/KeysightAgilent_33XXX.py +++ b/src/qcodes/instrument_drivers/Keysight/KeysightAgilent_33XXX.py @@ -4,7 +4,6 @@ from qcodes import validators as vals from qcodes.instrument import ( - Instrument, InstrumentBaseKWArgs, InstrumentChannel, VisaInstrument, @@ -26,14 +25,14 @@ # 33200, 33500, and 33600 -class Keysight33xxxOutputChannel(InstrumentChannel): +class Keysight33xxxOutputChannel(InstrumentChannel["Keysight33xxx"]): """ Class to hold the output channel of a Keysight 33xxxx waveform generator. """ def __init__( self, - parent: Instrument, + parent: "Keysight33xxx", name: str, channum: int, **kwargs: "Unpack[InstrumentBaseKWArgs]", @@ -317,7 +316,7 @@ def val_parser(parser: type, inputstring: str) -> float | int: OutputChannel = Keysight33xxxOutputChannel -class Keysight33xxxSyncChannel(InstrumentChannel): +class Keysight33xxxSyncChannel(InstrumentChannel["Keysight33xxx"]): """ Class to hold the sync output of a Keysight 33xxxx waveform generator. Has very few parameters for single channel instruments. @@ -325,7 +324,7 @@ class Keysight33xxxSyncChannel(InstrumentChannel): def __init__( self, - parent: Instrument, + parent: "Keysight33xxx", name: str, **kwargs: "Unpack[InstrumentBaseKWArgs]", ): From f41e6d1ad6dcaf20dab5ec71a64f42ebbb35dfb6 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Tue, 3 Feb 2026 21:42:09 +0100 Subject: [PATCH 4/9] Fix unresolved types in Keysight 34934a --- src/qcodes/instrument_drivers/Keysight/keysight_34934a.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/keysight_34934a.py b/src/qcodes/instrument_drivers/Keysight/keysight_34934a.py index a1dcdfbf1ae..2ac7a6e7dec 100644 --- a/src/qcodes/instrument_drivers/Keysight/keysight_34934a.py +++ b/src/qcodes/instrument_drivers/Keysight/keysight_34934a.py @@ -13,11 +13,11 @@ from qcodes.instrument import ( InstrumentBaseKWArgs, - InstrumentChannel, - VisaInstrument, ) from qcodes.parameters import Parameter + from .keysight_34980a import Keysight34980A + class Keysight34934A(Keysight34980ASwitchMatrixSubModule): """ @@ -32,7 +32,7 @@ class Keysight34934A(Keysight34980ASwitchMatrixSubModule): def __init__( self, - parent: "VisaInstrument | InstrumentChannel", + parent: "Keysight34980A", name: str, slot: int, **kwargs: "Unpack[InstrumentBaseKWArgs]", From cae121bf411d312d83061c7bb6157a396e1690c5 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Tue, 3 Feb 2026 21:42:29 +0100 Subject: [PATCH 5/9] Fix unresolved types in Keysight 34980a submodules --- .../Keysight/keysight_34980a_submodules.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/keysight_34980a_submodules.py b/src/qcodes/instrument_drivers/Keysight/keysight_34980a_submodules.py index 27cc8f87996..094154a5319 100644 --- a/src/qcodes/instrument_drivers/Keysight/keysight_34980a_submodules.py +++ b/src/qcodes/instrument_drivers/Keysight/keysight_34980a_submodules.py @@ -1,15 +1,17 @@ from typing import TYPE_CHECKING -from qcodes.instrument import InstrumentBaseKWArgs, InstrumentChannel, VisaInstrument +from qcodes.instrument import InstrumentBaseKWArgs, InstrumentChannel if TYPE_CHECKING: from typing_extensions import Unpack + from .keysight_34980a import Keysight34980A -class Keysight34980ASwitchMatrixSubModule(InstrumentChannel): + +class Keysight34980ASwitchMatrixSubModule(InstrumentChannel["Keysight34980A"]): def __init__( self, - parent: VisaInstrument | InstrumentChannel, + parent: "Keysight34980A", name: str, slot: int, **kwargs: "Unpack[InstrumentBaseKWArgs]", From 7a2167a38eaed62f2719fd723ce321fdac342971 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Tue, 3 Feb 2026 21:58:46 +0100 Subject: [PATCH 6/9] Fix unresolved types in Keysight 9030B submodules --- .../Keysight/Keysight_N9030B.py | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py b/src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py index 51244963d6b..eed00159df4 100644 --- a/src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py +++ b/src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py @@ -98,7 +98,6 @@ def __init__( **kwargs: Unpack[InstrumentBaseKWArgs], ): super().__init__(parent, name, *arg, **kwargs) - self.root_instrument: KeysightN9030B self._additional_wait = additional_wait self._min_freq = -8e7 @@ -111,7 +110,7 @@ def __init__( } opt: str | None = None for hw_opt_for_max_freq in self._valid_max_freq: - if hw_opt_for_max_freq in self.root_instrument.options(): + if hw_opt_for_max_freq in self.parent.options(): opt = hw_opt_for_max_freq assert opt is not None self._max_freq = self._valid_max_freq[opt] @@ -454,23 +453,22 @@ def _get_data(self, trace_num: int) -> npt.NDArray[np.float64]: """ Gets data from the measurement. """ - root_instr = self.root_instrument # Check if we should run a new sweep - auto_sweep = root_instr.auto_sweep() + auto_sweep = self.parent.auto_sweep() if auto_sweep: # If we need to run a sweep, we need to set the timeout to take into account # the sweep time timeout = self.sweep_time() + self._additional_wait - with root_instr.timeout.set_to(timeout): - data = root_instr.visa_handle.query_binary_values( - f":READ:{root_instr.measurement()}{trace_num}?", + with self.parent.timeout.set_to(timeout): + data = self.parent.visa_handle.query_binary_values( + f":READ:{self.parent.measurement()}{trace_num}?", datatype="d", is_big_endian=False, ) else: - data = root_instr.visa_handle.query_binary_values( - f":FETC:{root_instr.measurement()}{trace_num}?", + data = self.parent.visa_handle.query_binary_values( + f":FETC:{self.parent.measurement()}{trace_num}?", datatype="d", is_big_endian=False, ) @@ -491,9 +489,9 @@ def setup_swept_sa_sweep(self, start: float, stop: float, npts: int) -> None: """ Sets up the Swept SA measurement sweep for Spectrum Analyzer Mode. """ - self.root_instrument.mode("SA") - if "SAN" in self.root_instrument.available_meas(): - self.root_instrument.measurement("SAN") + self.parent.mode("SA") + if "SAN" in self.parent.available_meas(): + self.parent.measurement("SAN") else: raise RuntimeError( "Swept SA measurement is not available on your " @@ -537,7 +535,7 @@ def __init__( } opt: str | None = None for hw_opt_for_max_freq in self._valid_max_freq: - if hw_opt_for_max_freq in self.root_instrument.options(): + if hw_opt_for_max_freq in self.parent.options(): opt = hw_opt_for_max_freq assert opt is not None self._max_freq = self._valid_max_freq[opt] @@ -668,9 +666,8 @@ def _get_data(self, trace_num: int) -> ParamRawDataType: """ Gets data from the measurement. """ - root_instr = self.root_instrument - measurement = root_instr.measurement() - raw_data = root_instr.visa_handle.query_binary_values( + measurement = self.parent.measurement() + raw_data = self.parent.visa_handle.query_binary_values( f":READ:{measurement}1?", datatype="d", is_big_endian=False, @@ -684,7 +681,7 @@ def _get_data(self, trace_num: int) -> ParamRawDataType: return -1 * np.ones(self.npts()) try: - data = root_instr.visa_handle.query_binary_values( + data = self.parent.visa_handle.query_binary_values( f":READ:{measurement}{trace_num}?", datatype="d", is_big_endian=False, @@ -701,9 +698,9 @@ def setup_log_plot_sweep( """ Sets up the Log Plot measurement sweep for Phase Noise Mode. """ - self.root_instrument.mode("PNOISE") - if "LPL" in self.root_instrument.available_meas(): - self.root_instrument.measurement("LPL") + self.parent.mode("PNOISE") + if "LPL" in self.parent.available_meas(): + self.parent.measurement("LPL") else: raise RuntimeError( "Log Plot measurement is not available on your " From 791e6a75eb6688d88f68a4afa42e6c1263d2dc78 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Tue, 3 Feb 2026 22:07:08 +0100 Subject: [PATCH 7/9] Add Settings for Infiniium --- .../instrument_drivers/Keysight/Infiniium.py | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/Infiniium.py b/src/qcodes/instrument_drivers/Keysight/Infiniium.py index 4f559ea0974..1c4310701ff 100644 --- a/src/qcodes/instrument_drivers/Keysight/Infiniium.py +++ b/src/qcodes/instrument_drivers/Keysight/Infiniium.py @@ -13,6 +13,7 @@ import qcodes.validators as vals from qcodes.instrument import ( ChannelList, + ChannelTuple, InstrumentBase, InstrumentBaseKWArgs, InstrumentChannel, @@ -89,7 +90,11 @@ def get_raw(self) -> npt.NDArray: ) -class DSOTraceParam(ParameterWithSetpoints): +class DSOTraceParam( + ParameterWithSetpoints[ + npt.NDArray, "KeysightInfiniiumChannel | KeysightInfiniiumFunction" + ] +): """ Trace parameter for the Infiniium series DSO """ @@ -180,7 +185,7 @@ def update_setpoints(self, preamble: "Sequence[str] | None" = None) -> None: acquisition if instr.cache_setpoints is False """ instrument: KeysightInfiniiumChannel | KeysightInfiniiumFunction - instrument = self.instrument # type: ignore[assignment] + instrument = self.instrument if preamble is None: instrument.write(f":WAV:SOUR {self._channel}") preamble = instrument.ask(":WAV:PRE?").strip().split(",") @@ -257,6 +262,7 @@ def __init__( self, parent: InstrumentBase, name: str, + channel: str, **kwargs: "Unpack[InstrumentBaseKWArgs]", ) -> None: """ @@ -264,6 +270,7 @@ def __init__( directly, rather initialize BoundMeasurementSubsystem or UnboundMeasurementSubsystem. """ + self._channel = channel super().__init__(parent, name, **kwargs) ################################### @@ -477,11 +484,8 @@ def __init__( """ Initialize measurement subsystem bound to a specific channel """ - # Bind the channel - self._channel = parent.channel_name - # Initialize measurement parameters - super().__init__(parent, name, **kwargs) + super().__init__(parent, name, channel=parent.channel_name, **kwargs) BoundMeasurement = KeysightInfiniiumBoundMeasurement @@ -500,11 +504,8 @@ def __init__( """ Initialize measurement subsystem where target is set by the parameter `source`. """ - # Blank channel - self._channel = "" - # Initialize measurement parameters - super().__init__(parent, name, **kwargs) + super().__init__(parent, name, channel="", **kwargs) self.source = Parameter( name="source", @@ -515,6 +516,12 @@ def __init__( snapshot_value=False, ) + @property + def root_instrument(self) -> "KeysightInfiniium": + root_instrument = super().root_instrument + assert isinstance(root_instrument, KeysightInfiniium) + return root_instrument + def _validate_source(self, source: str) -> str: """Validate and set the source.""" valid_channels = f"CHAN[1-{self.root_instrument.no_channels}]" @@ -692,7 +699,7 @@ def _get_func(self) -> str: """ -class KeysightInfiniiumChannel(InstrumentChannel): +class KeysightInfiniiumChannel(InstrumentChannel["KeysightInfiniium"]): def __init__( self, parent: "KeysightInfiniium", @@ -1081,7 +1088,10 @@ def __init__( channel = KeysightInfiniiumChannel(self, f"chan{i}", i) _channels.append(channel) self.add_submodule(f"ch{i}", channel) - self.add_submodule("channels", _channels.to_channel_tuple()) + self.channels: ChannelTuple[KeysightInfiniiumChannel] = self.add_submodule( + "channels", _channels.to_channel_tuple() + ) + """Tuple of oscilloscope channels.""" # Functions _functions = ChannelList( @@ -1093,11 +1103,17 @@ def __init__( self.add_submodule(f"func{i}", function) # Have to call channel list "funcs" here as functions is a # reserved name in Instrument. - self.add_submodule("funcs", _functions.to_channel_tuple()) + self.funcs: ChannelTuple[KeysightInfiniiumFunction] = self.add_submodule( + "funcs", _functions.to_channel_tuple() + ) + """Tuple of oscilloscope functions.""" # Submodules meassubsys = KeysightInfiniiumUnboundMeasurement(self, "measure") - self.add_submodule("measure", meassubsys) + self.measure: KeysightInfiniiumUnboundMeasurement = self.add_submodule( + "measure", meassubsys + ) + """Unbound measurement subsystem.""" def _query_capabilities(self) -> None: """ From fecefe0c90d9bfe91eb65a2e10700a5fe72fa264 Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Thu, 5 Mar 2026 10:45:33 +0100 Subject: [PATCH 8/9] Work around mypy limitations --- src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py | 4 ++-- src/qcodes/instrument_drivers/Keysight/N52xx.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py b/src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py index eed00159df4..4680cf1c17c 100644 --- a/src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py +++ b/src/qcodes/instrument_drivers/Keysight/Keysight_N9030B.py @@ -686,11 +686,11 @@ def _get_data(self, trace_num: int) -> ParamRawDataType: datatype="d", is_big_endian=False, ) - data = np.array(data).reshape((-1, 2)) + data_array = np.array(data).reshape((-1, 2)) except TimeoutError as e: raise TimeoutError("Couldn't receive any data. Command timed out.") from e - return data[:, 1] + return data_array[:, 1] def setup_log_plot_sweep( self, start_offset: float, stop_offset: float, npts: int diff --git a/src/qcodes/instrument_drivers/Keysight/N52xx.py b/src/qcodes/instrument_drivers/Keysight/N52xx.py index cdca5202340..d7c3e4cfdda 100644 --- a/src/qcodes/instrument_drivers/Keysight/N52xx.py +++ b/src/qcodes/instrument_drivers/Keysight/N52xx.py @@ -137,12 +137,12 @@ def get_raw(self) -> npt.NDArray: data = root_instr.visa_handle.query_binary_values( "CALC:DATA? FDATA", datatype="f", is_big_endian=True ) - data = np.array(data) + data_array = np.array(data) # Restore previous state if it was changed if auto_sweep: root_instr.sweep_mode(prev_mode) - return data + return data_array class KeysightPNAPort(InstrumentChannel): From 1815e0b78fbf1cfbbf3b762663636a81e7ba6f5e Mon Sep 17 00:00:00 2001 From: "Jens H. Nielsen" Date: Thu, 5 Mar 2026 10:57:13 +0100 Subject: [PATCH 9/9] Keysight b1500 fix resetting multiple channels --- .../Keysight/keysightb1500/KeysightB1500_base.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_base.py b/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_base.py index d25f4a970cb..a14786bcf7f 100644 --- a/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_base.py +++ b/src/qcodes/instrument_drivers/Keysight/keysightb1500/KeysightB1500_base.py @@ -377,7 +377,7 @@ def clear_buffer_of_error_message(self) -> None: msg = MessageBuilder().err_query() self.write(msg.message) - def clear_timer_count(self, chnum: int | None = None) -> None: + def clear_timer_count(self, chnum: "int | Sequence[int] | None" = None) -> None: """ This command clears the timer count. This command is effective for all measurement modes, regardless of the TSC setting. This command @@ -391,13 +391,23 @@ def clear_timer_count(self, chnum: int | None = None) -> None: source output start by the DV, DI, or DCV command for the specified channel. The channel output switch of the specified channel must be ON when the timer count is - cleared. + cleared. Alternatively a sequence of channels + can be passed to clear the timer count for multiple + channels at the same time. If chnum is not specified, this command clears the timer count immediately, """ - msg = MessageBuilder().tsr(chnum=chnum) + msg = MessageBuilder() + if chnum is None: + chnum_internal: Sequence[int | None] = [None] + elif isinstance(chnum, int): + chnum_internal = [chnum] + else: + chnum_internal = chnum + for ch in chnum_internal: + msg.tsr(chnum=ch) self.write(msg.message) def set_measurement_mode(