Skip to content

Commit

Permalink
try removing optional for daq and awg module
Browse files Browse the repository at this point in the history
  • Loading branch information
rbudhrani committed May 21, 2024
1 parent 7283835 commit 17e5d1f
Showing 1 changed file with 57 additions and 56 deletions.
113 changes: 57 additions & 56 deletions qmi/instruments/zurich_instruments/hdawg.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def _import_modules() -> None:
# Status enumerations.
class CompilerStatus(enum.IntEnum):
"""Enumeration of compiler process status."""

IDLE = -1
SUCCESS = 0
FAILED = 1
Expand All @@ -69,6 +70,7 @@ class CompilerStatus(enum.IntEnum):

class UploadStatus(enum.IntEnum):
"""Enumeration of ELF upload process status."""

WAITING = -1
DONE = 0
FAILED = 1
Expand All @@ -82,7 +84,7 @@ class ZurichInstruments_HDAWG(QMI_Instrument):
NUM_CHANNELS = 8
NUM_CHANNELS_PER_AWG = 2

CONNECTION_INTERFACE = "1GbE" # For Ethernet and USB the connection interface is 1GbE
CONNECTION_INTERFACE = "1GbE" # For Ethernet and USB the connection interface is 1GbE

# Node paths
AWG_DEVICE = "awgModule/device"
Expand Down Expand Up @@ -110,8 +112,8 @@ def __init__(self, context: QMI_Context, name: str, server_host: str, server_por
self._server_port = server_port
self._device_name = device_name

self._daq_server: Optional[zhinst.ziPython.ziDAQServer] = None
self._awg_module: Optional[zhinst.ziPython.AwgModule] = None
self._daq_server: zhinst.ziPython.ziDAQServer
self._awg_module: zhinst.ziPython.AwgModule

self._last_compilation_successful = False

Expand All @@ -127,7 +129,7 @@ def _check_data_server_exists(self) -> None:
"""
if not self._daq_server:
raise QMI_InstrumentException("Could not connect to Zurich Instruments Data Server")

def _check_awg_module_exists(self) -> None:
"""
Check if the AwgModule exists.
Expand All @@ -138,19 +140,20 @@ def _check_awg_module_exists(self) -> None:
if not self._awg_module:
raise QMI_InstrumentException("Could not create an AwgModule")

assert self._awg_module is not None

@rpc_method
def open(self) -> None:

self._check_is_closed()
_logger.info("[%s] Opening connection to instrument", self._name)

# Connect to Zurich Instruments Data Server
self._daq_server = zhinst.core.ziDAQServer(self._server_host, self._server_port)
self._daq_server = zhinst.core.ziDAQServer(self._server_host, self._server_port, 6)

self._check_data_server_exists()

# Connect to the device via Ethernet.
self._daq_server.connectDevice(self._device_name, self.CONNECTION_INTERFACE)
self._daq_server.connectDevice(self._device_name, "1GbE")

# Create an AwgModule object
self._awg_module = self._daq_server.awgModule()
Expand Down Expand Up @@ -191,11 +194,8 @@ def close(self) -> None:
if not self._awg_module.finished():
raise QMI_InstrumentException("AWG thread still running")

self._awg_module = None

self._check_data_server_exists()
self._daq_server.disconnect()
self._daq_server = None

super().close()

Expand All @@ -207,7 +207,7 @@ def _set_dev_value(self, node_path: str, value: Union[int, float, str]) -> None:
value: Value to write.
"""
self._check_data_server_exists()
self._daq_server.set('/' + self._device_name + '/' + node_path, value)
self._daq_server.set("/" + self._device_name + "/" + node_path, value)

def _set_dev_int(self, node_path: str, value: int) -> None:
"""Set an integer value in the device node tree.
Expand All @@ -217,7 +217,7 @@ def _set_dev_int(self, node_path: str, value: int) -> None:
value: Integer value to write.
"""
self._check_data_server_exists()
self._daq_server.setInt('/' + self._device_name + '/' + node_path, value)
self._daq_server.setInt("/" + self._device_name + "/" + node_path, value)

def _set_dev_double(self, node_path: str, value: float) -> None:
"""Set a floating point value in the device node tree.
Expand All @@ -227,7 +227,7 @@ def _set_dev_double(self, node_path: str, value: float) -> None:
value: Floating point value to write.
"""
self._check_data_server_exists()
self._daq_server.setDouble('/' + self._device_name + '/' + node_path, value)
self._daq_server.setDouble("/" + self._device_name + "/" + node_path, value)

def _get_dev_int(self, node_path: str) -> int:
"""Return an integer value from the device node tree.
Expand All @@ -236,7 +236,7 @@ def _get_dev_int(self, node_path: str) -> int:
node_path: Path in the device tree, relative to the "/devNNNN/" subtree.
"""
self._check_data_server_exists()
return self._daq_server.getInt('/' + self._device_name + '/' + node_path)
return self._daq_server.getInt("/" + self._device_name + "/" + node_path)

def _get_dev_double(self, node_path: str) -> float:
"""Return a floating point value from the device node tree.
Expand All @@ -245,17 +245,19 @@ def _get_dev_double(self, node_path: str) -> float:
node_path: Path in the device tree, relative to the "/devNNNN/" subtree.
"""
self._check_data_server_exists()
return self._daq_server.getDouble('/' + self._device_name + '/' + node_path)
return self._daq_server.getDouble("/" + self._device_name + "/" + node_path)

@staticmethod
def _process_parameter_replacements(sequencer_program: str, replacements: Dict[str, Union[str, int, float]]) -> str:
def _process_parameter_replacements(
sequencer_program: str, replacements: Dict[str, Union[str, int, float]]
) -> str:
"""
Process parameter replacements for sequencer code.
Parameters:
sequencer_program: Sequencer program to process.
replacements: Dictionary of replacements.
Returns:
sequencer program with repelacements
"""
Expand All @@ -279,25 +281,29 @@ def _process_parameter_replacements(sequencer_program: str, replacements: Dict[s
# Check if there are any unreplaced parameters left in the source code; this will not compile.
leftover_parameters = SEQC_PAR_PATTERN.findall(sequencer_program)
if leftover_parameters:
raise KeyError("Variables left in sequencer program that were not in replacement dictionary: {}".format(
', '.join(leftover_parameters)
))
raise KeyError(
"Variables left in sequencer program that were not in replacement dictionary: {}".format(
", ".join(leftover_parameters)
)
)

return sequencer_program

@staticmethod
def _check_program_not_empty(sequencer_program: str) -> None:
"""
Check if the program is non-empty (compiler silently ignores empty programs).
Parameters:
sequencer_program: Sequencer program to check.
"""
# Filter out lines that start with // or /* (comments) or are empty.
seqc_statements = list(filter(
lambda s: not (s.startswith("//") or s.startswith("/*") or len(s) == 0),
[s.strip() for s in sequencer_program.split('\n')]
))
seqc_statements = list(
filter(
lambda s: not (s.startswith("//") or s.startswith("/*") or len(s) == 0),
[s.strip() for s in sequencer_program.split("\n")],
)
)

# Check if there are any lines left (we do not check if that is executable code; the compiler will do that).
if len(seqc_statements) == 0:
Expand All @@ -306,7 +312,7 @@ def _check_program_not_empty(sequencer_program: str) -> None:
def _wait_compile(self, sequencer_program: str) -> CompilerStatus:
"""
Start a compilation of a sequencer program.
Parameters:
sequencer_program: Sequencer program to check.
Expand Down Expand Up @@ -335,15 +341,15 @@ def _wait_compile(self, sequencer_program: str) -> CompilerStatus:
_logger.debug(
"Compilation finished in %.1f seconds (status=%d)",
compilation_end_time - compilation_start_time,
compilation_status
compilation_status,
)

return compilation_status

def _wait_upload(self) -> UploadStatus:
"""
Poll ELF upload progress and check result.
Returns:
Upload status.
"""
Expand All @@ -364,9 +370,7 @@ def _wait_upload(self) -> UploadStatus:
raise RuntimeError("Upload process timed out (timeout={})".format(_UPLOAD_TIMEOUT))
upload_end_time = time.monotonic()
_logger.debug(
"ELF upload finished in %.1f seconds (status=%d)",
upload_end_time - upload_start_time,
upload_status
"ELF upload finished in %.1f seconds (status=%d)", upload_end_time - upload_start_time, upload_status
)

return upload_status
Expand All @@ -377,7 +381,7 @@ def _interpret_compilation_result_is_ok(self, compilation_result: CompilerStatus
Parameters:
compilation_result: Result of the compilation.
Returns:
True if compilation succeed, else False.
Expand All @@ -404,10 +408,10 @@ def _interpret_compilation_result_is_ok(self, compilation_result: CompilerStatus
def _interpret_upload_result_is_ok(self, upload_result: UploadStatus) -> bool:
"""
Interpret upload result.
Parameters:
upload_result: Result of the upload.
Returns:
True if compilation succeed, else False.
Expand Down Expand Up @@ -490,10 +494,9 @@ def set_node_double(self, node_path: str, value: float) -> None:
self._set_dev_double(node_path, value)

@rpc_method
def compile_and_upload(self,
sequencer_program: str,
replacements: Optional[Dict[str, Union[str, int, float]]] = None
) -> None:
def compile_and_upload(
self, sequencer_program: str, replacements: Optional[Dict[str, Union[str, int, float]]] = None
) -> None:
"""Compile and upload the sequencer_program, after performing textual replacements.
This function combines compilation followed by upload to the AWG if compilation was successful. This is forced
Expand Down Expand Up @@ -551,13 +554,14 @@ def compilation_successful(self) -> bool:
return self._last_compilation_successful

@rpc_method
def upload_waveform(self,
awg_index: int,
waveform_index: int,
wave1: np.ndarray,
wave2: Optional[np.ndarray] = None,
markers: Optional[np.ndarray] = None
) -> None:
def upload_waveform(
self,
awg_index: int,
waveform_index: int,
wave1: np.ndarray,
wave2: Optional[np.ndarray] = None,
markers: Optional[np.ndarray] = None,
) -> None:
"""
Upload new waveform data to the AWG.
Expand Down Expand Up @@ -593,9 +597,9 @@ def upload_waveform(self,

@rpc_method
def upload_waveforms(
self,
unpacked_waveforms: List[Tuple[int, int, np.ndarray, Optional[np.ndarray], Optional[np.ndarray]]],
batch_size: int = 50
self,
unpacked_waveforms: List[Tuple[int, int, np.ndarray, Optional[np.ndarray], Optional[np.ndarray]]],
batch_size: int = 50,
) -> None:
"""Upload a set of new waveform data to the AWG. Works as singular waveform uploading, but creating a
list of tuple sets of waveforms, and uploading all in one command, speeds up the upload significantly.
Expand All @@ -615,7 +619,7 @@ def upload_waveforms(
for wf_count, sequence in enumerate(unpacked_waveforms):
awg_index, waveform_index, wave1, wave2, markers = sequence
wave_raw = zhinst.utils.convert_awg_waveform(wave1, wave2, markers)
waveform_address = f'/{self._device_name}/awgs/{awg_index}/waveform/waves/{waveform_index}'
waveform_address = f"/{self._device_name}/awgs/{awg_index}/waveform/waves/{waveform_index}"
waves_set.append((waveform_address, wave_raw))
# Check set size against batch size
if wf_count % batch_size == batch_size - 1:
Expand Down Expand Up @@ -659,16 +663,14 @@ def upload_command_table(self, awg_index: int, command_table_entries: List[Dict[
# Create the command table from the provided entries.
command_table = {
"$schema": "http://docs.zhinst.com/hdawg/commandtable/v2/schema",
"header": {
"version": "0.2"
},
"table": command_table_entries
"header": {"version": "0.2"},
"table": command_table_entries,
}

# Load the validation schema.
validation_schema_file = _DEFAULT_CT_TABLE_SCHEMA_PATH
try:
with open(validation_schema_file, 'r') as fhandle:
with open(validation_schema_file, "r") as fhandle:
validation_schema = json.load(fhandle)
except json.JSONDecodeError as exc:
_logger.exception("Error in decoding validation schema", exc_info=exc)
Expand All @@ -691,8 +693,7 @@ def upload_command_table(self, awg_index: int, command_table_entries: List[Dict[
raise ValueError("Invalid value in command table") from exc

self._daq_server.setVector(
"/{}/awgs/{}/commandtable/data".format(self._device_name, awg_index),
command_table_as_json
"/{}/awgs/{}/commandtable/data".format(self._device_name, awg_index), command_table_as_json
)

@rpc_method
Expand Down

0 comments on commit 17e5d1f

Please sign in to comment.