Source code for qblox_instruments.ieee488_2.cluster_dummy_transport

# ----------------------------------------------------------------------------
# Description    : Transport layer (abstract, IP, file, dummy)
# Git repository : https://gitlab.com/qblox/packages/software/qblox_instruments.git
# Copyright (C) Qblox BV (2020)
# ----------------------------------------------------------------------------


# -- include -----------------------------------------------------------------

import json

from typing import Dict, Optional, Union, Iterable
from qblox_instruments import ClusterType
from qblox_instruments.ieee488_2 import (
        DummyTransport,
        QcmQrmDummyTransport,
        DummyBinnedAcquisitionData,
        DummyScopeAcquisitionData,
)


# -- class -------------------------------------------------------------------

[docs]class ClusterDummyTransport(DummyTransport): """ Class to replace Cluster device with dummy device to support software stack testing without hardware. The class implements all mandatory, required and Cluster specific SCPI calls. Call reponses are largely artifically constructed to be inline with the call's functionality (e.g. `*IDN?` returns valid, but artificial IDN data.) To assist development, the Q1ASM assembler has been completely implemented. Please have a look at the call's implentation to know what to expect from its response. """ # ------------------------------------------------------------------------
[docs] def __init__( self, dummy_cfg: Dict[Union[str,int],ClusterType], scope_acq_cfg_format: str, qcm_seq_cfg_format: str, qrm_seq_cfg_format: str, ): """ Create Cluster dummy transport class. Parameters ---------- dummy_cfg : Dict Dictionary of dummy module types (e.g. Cluster QCM, Cluster QRM). Each key of the dictionary is a slot index with a dummy type specification of type :class:`~qblox_instruments.ClusterType`. scope_acq_cfg_format : str Configuration format based on `struct.pack <https://docs.python.org/3/library/struct.html>`_ format used to calculate scope acquisition configuration transaction size. qcm_seq_cfg_format : str QCM sequencer configuration format based on `struct.pack <https://docs.python.org/3/library/struct.html>`_ format used to calculate scope acquisition configuration transaction size. qrm_seq_cfg_format : str QRM sequencer configuration format based on `struct.pack <https://docs.python.org/3/library/struct.html>`_ format used to calculate scope acquisition configuration transaction size. Returns ---------- Raises ---------- """ # Initialize base class super().__init__( dummy_cfg["0"] if "0" in dummy_cfg else ClusterType._CLUSTER_MM ) # Set number of slots self._num_slots = 20 # Configure module dummy transports self._modules = {str(slot_idx): None for slot_idx in range(self._num_slots)} for slot_idx in dummy_cfg: if str(slot_idx) in self._modules: self._modules[str(slot_idx)] = QcmQrmDummyTransport( dummy_cfg[slot_idx], scope_acq_cfg_format, qcm_seq_cfg_format, qrm_seq_cfg_format, ) # Set command list self._cmds["STATus:GENeral:STATE?"] = self._get_system_state self._cmds["*MODS?"] = self._get_mods_info self._cmds["BP:MODules?"] = self._get_modules_present
# ------------------------------------------------------------------------ def _execute_cmd( self, cmd_parts: list, cmd_params: list, cmd_args: list, bin_in: Optional[bytes] = None ) -> None: """ Execute associated command method found in command dictionary. If the command is intended for a slot as indicated by the first command part being "SLOT#", the command is executed by the associated module. Parameters ---------- cmd_parts : list Reformated command sections cmd_params : list Command parameters cmd_args : list Command arguments bin_in : Optional[bytes] Binary data that needs to be send by the command. Returns ---------- Raises ---------- """ # If command is intended for a slot, remove the slot specification # and execute the command on the module instead. if cmd_parts[0] == "SLOT#": cmd_parts.pop(0) slot = cmd_params.pop(0) if slot in self._modules: mod = self._modules[slot] mod._execute_cmd(cmd_parts, cmd_params, cmd_args, bin_in) # Copy results and errors from module. self._data_out = mod._data_out self._bin_out = mod._bin_out for error in mod._system_error: self._system_error.append(error) mod._system_error = [] else: self._system_error.append( "Module in slot {} is not available.".format(slot) ) else: super()._execute_cmd(cmd_parts, cmd_params, cmd_args, bin_in) # ------------------------------------------------------------------------ def _get_system_state(self, cmd_params: list, cmd_args: list, bin_in: bytes) -> None: """ Get system status. Parameters ---------- cmd_params : list Command parameters indicated by '#' in the command. cmd_args : list Command arguments. bin_in : bytes Binary input data. Returns ---------- Raises ---------- """ super()._get_system_state(cmd_params, cmd_args, bin_in) for slot_idx in self._modules: if self._modules[slot_idx] is not None: self._modules[slot_idx]._get_system_state( cmd_params, cmd_args, bin_in ) flags = self._modules[slot_idx]._data_out.split(";")[1] flags = flags.split(",")[:-1] flags = ["SLOT {} {}".format(slot_idx, flag) for flag in flags] self._data_out += ",".join(flags) if len(flags) > 0: self._data_out += "," # ------------------------------------------------------------------------ def _get_mods_info(self, cmd_params: list, cmd_args: list, bin_in: bytes) -> None: """ Get information about the modules in the Cluster (i.e. IDN and RF indication). Parameters ---------- cmd_params : list Command parameters indicated by '#' in the command. cmd_args : list Command arguments. bin_in : bytes Binary input data. Returns ---------- Raises ---------- """ mod_info = {} for slot_idx in self._modules: if self._modules[slot_idx] is not None: self._modules[slot_idx]._get_idn([], [], None) mod_info["SLOT " + slot_idx] = { "IDN": self._modules[slot_idx]._data_out, "RF": self._modules[slot_idx].is_rf_type } self._bin_out = self._encode_bin(json.dumps(mod_info).encode("utf-8")) # ------------------------------------------------------------------------ def _get_modules_present(self, cmd_params: list, cmd_args: list, bin_in: bytes) -> None: """ Get modules present in the Cluster. Parameters ---------- cmd_params : list Command parameters indicated by '#' in the command. cmd_args : list Command arguments. bin_in : bytes Binary input data. Returns ---------- Raises ---------- """ mod_present = 0 for slot_idx in self._modules: if self._modules[slot_idx] is not None: mod_present |= 1 << (int(slot_idx) - 1) self._data_out = mod_present # ------------------------------------------------------------------------
[docs] def set_dummy_binned_acquisition_data( self, slot_idx: int, sequencer: int, acq_index_name: str, data: Iterable[Union[DummyBinnedAcquisitionData, None]]): """ Set dummy binned acquisition data for the dummy. Parameters ---------- slot_idx : int Slot of the hardware you want to set the data to on a cluster. sequencer : int Sequencer. acq_index_name : str Acquisition index name. data : Iterable[Union[DummyBinnedAcquisitionData, None]] Dummy data for the binned acquisition. An iterable of all the bin values. Returns ---------- Raises ---------- """ self._modules[str(slot_idx)].set_dummy_binned_acquisition_data(sequencer, acq_index_name, data)
# ------------------------------------------------------------------------
[docs] def set_dummy_scope_acquisition_data( self, slot_idx: int, data: DummyScopeAcquisitionData): """ Set dummy scope acquisition data for the dummy. Parameters ---------- slot_idx : int Slot of the hardware you want to set the data to on a cluster. data : DummyScopeAcquisitionData Dummy data for the scope acquisition. Returns ---------- Raises ---------- """ self._modules[str(slot_idx)].set_dummy_scope_acquisition_data(data)