Source code for qcodes.instrument_drivers.Keysight.keysight_34980a

import logging
import re
import warnings
from functools import wraps
from typing import TYPE_CHECKING, TypeVar

from typing_extensions import ParamSpec

from qcodes import validators as vals
from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs

from .keysight_34934a import Keysight34934A
from .keysight_34980a_submodules import Keysight34980ASwitchMatrixSubModule

if TYPE_CHECKING:
    from collections.abc import Callable
    from typing import Concatenate

    from typing_extensions import Unpack

KEYSIGHT_MODELS = {"34934A": Keysight34934A}

S = TypeVar("S", bound="Keysight34980A")
P = ParamSpec("P")
T = TypeVar("T")


def post_execution_status_poll(
    func: "Callable[Concatenate[S, P], T]",
) -> "Callable[Concatenate[S, P], T]":
    """
    Generates a decorator that clears the instrument's status registers
    before executing the actual call and reads the status register after the
    function call to determine whether an error occurs.

    Args:
        func: function to wrap

    """

    @wraps(func)
    def wrapper(self: S, *args: P.args, **kwargs: P.kwargs) -> T:
        self.clear_status()
        retval = func(self, *args, **kwargs)

        stb = self.get_status()
        if stb:
            warnings.warn(
                f"Instrument status byte indicates an error occurred "
                f"(value of STB was: {stb})! Use `get_error` method "
                f"to poll error message.",
                stacklevel=2,
            )
        return retval

    return wrapper


[docs] class Keysight34980A(VisaInstrument): """ QCodes driver for 34980A switch/measure unit """ default_terminator = "\n" def __init__( self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]" ): """ Create an instance of the instrument. Args: name: Name of the instrument instance address: Visa-resolvable instrument address. **kwargs: kwargs are forwarded to base class. """ super().__init__(name, address, **kwargs) self._total_slot = 8 self._system_slots_info_dict: dict[int, dict[str, str]] | None = None self.module = dict.fromkeys(self.system_slots_info.keys()) self.scan_slots() self.connect_message()
[docs] def get_status(self) -> int: """ Queries status register Returns: 0 if there is no error """ msg = super().ask("*ESR?") nums = list(map(int, re.findall(r"\d+", msg))) return nums[0]
[docs] def get_error(self) -> str: """ Queries error queue Returns: error message, or '+0,"No error"' if there is no error """ msg = super().ask(":SYST:ERR?") return msg
[docs] def clear_status(self) -> None: """ Clears status register and error queue of the instrument. """ super().write("*CLS")
[docs] def reset(self) -> None: """ Performs an instrument reset. Does not reset error queue! """ super().write("*RST")
[docs] @post_execution_status_poll def ask(self, cmd: str) -> str: return super().ask(cmd)
[docs] @post_execution_status_poll def write(self, cmd: str) -> None: return super().write(cmd)
[docs] def scan_slots(self) -> None: """ Scan the occupied slots and make an object for each switch matrix module installed """ for slot in self.system_slots_info.keys(): model_string = self.system_slots_info[slot]["model"] for model in KEYSIGHT_MODELS: if model in model_string: sub_module_name = f"slot_{slot}_{model}" sub_module = KEYSIGHT_MODELS[model](self, sub_module_name, slot) self.module[slot] = sub_module self.add_submodule(sub_module_name, sub_module) break if self.module[slot] is None: sub_module_name = f"slot_{slot}_{model_string}_no_driver" sub_module_no_driver = Keysight34980ASwitchMatrixSubModule( self, sub_module_name, slot ) self.module[slot] = sub_module_no_driver self.add_submodule(sub_module_name, sub_module_no_driver) logging.warning( f"can not find driver for {model_string} in slot {slot}" )
@property def system_slots_info(self) -> dict[int, dict[str, str]]: if self._system_slots_info_dict is None: self._system_slots_info_dict = self._system_slots_info() return self._system_slots_info_dict def _system_slots_info(self) -> dict[int, dict[str, str]]: """ the command SYST:CTYP? returns the following: Agilent Technologies,<Model Number>,<Serial Number>,<Firmware Rev> where <Model Number> is '0' if there is no module connected to the given slot Returns: a dictionary, with slot numbers as the keys, and vendor/model/ serial/firmware dictionaries as the values """ slots_dict = {} keys = ["vendor", "model", "serial", "firmware"] for i in range(1, self._total_slot + 1): identity = self.ask(f"SYST:CTYP? {i}").strip('"').split(",") if identity[1] != "0": slots_dict[i] = dict(zip(keys, identity)) return slots_dict
[docs] def disconnect_all(self, slot: int | None = None) -> None: """ to open/disconnect all connections on select module Args: slot: slot number, between 1 and 8 (self._total_slot), default value is None, which means all slots """ cmd = "ROUT:OPEN:ALL" if slot is None: self.write(cmd) else: vals.Ints(min_value=1, max_value=self._total_slot).validate(slot) self.write(f"ROUT:OPEN:ALL {slot}")