Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Waverunner: Add functions for load/store of setups to local file #162

Merged
merged 1 commit into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions cw/test_waverunner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

"""Test WaveRunner class."""

from datetime import datetime

from waverunner import WaveRunner

if __name__ == '__main__':
waverunner = WaveRunner("172.26.111.125")

# Save WaveRunner setup to timestamped file
now = datetime.now()
now_str = now.strftime("%Y-%m-%d_%H:%M:%S")
file_name_local = f"scope_config_{now_str}.lss"
waverunner.save_setup_to_local_file(file_name_local)

# Write setup to local file for later restore (no time-stamps)
file_name_local = "scope_config.lss"
waverunner.save_setup_to_local_file(file_name_local)
# Load setup from local file
waverunner.load_setup_from_local_file(file_name_local)
76 changes: 74 additions & 2 deletions cw/waverunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ def __init__(self, ip_addr):
self._instr = vxi11.Instrument(self._ip_addr)
self._populate_device_info()
self._print_device_info()
self._configure()
# Commented out since default configuration is highly specific
# Class will be used more general
# self._configure()

@property
def num_segments_max(self):
Expand All @@ -93,6 +95,74 @@ def _ask(self, cmd):
def _ask_raw(self, cmd):
return self._instr.ask_raw(cmd)

def _get_and_print_cmd_error(self):
"""Get command error status for last command. On error, displays error message."""
# from p.328
# https://cdn.teledynelecroy.com/files/manuals/maui-remote-control-and-automation-manual.pdf
# Note: beware of numbering; idx starts at 0
error_msg = ["OK.",
"Unrecognized command/query header.",
"Illegal header path.",
"Illegal number.",
"Illegal number suffix.",
"Unrecognized keyword.",
"String error.",
"GET embedded in another message.",
"",
"",
"Arbitrary data block expected.",
"Non-digit character in byte count field of arbitrary data block.",
"EOI detected during definite length data block transfer.",
"Extra bytes detected during definite length data block transfer"]
return_code = int((re.findall(r'\d+', self._ask("CMR?")))[0])
if return_code > 13 or return_code in [8, 9]:
return_msg = f"{return_code} Unkown error code"
else:
return_msg = f"{return_code} {error_msg[return_code]}"
if return_code != 0:
print("WAVERUNNER: ERROR in last command: " + return_msg)

def _fetch_file_from_scope(self, file_name_scope):
fetched_file = self._ask("TRANSFER_FILE? DISK,HDD,FILE," + file_name_scope)
# remove echoed command characters from beginning
fetched_file = fetched_file[5:]
self._get_and_print_cmd_error()
return fetched_file

def _write_to_file_on_scope(self, file_name_scope, data):
self._write("TRANSFER_FILE DISK,HDD,FILE," + file_name_scope + "," + data)
self._get_and_print_cmd_error()

def _delete_file_on_scope(self, file_name_scope):
self._write("DELETE_FILE DISK,HDD,FILE," + file_name_scope)
self._get_and_print_cmd_error()

def _store_setup_to_file_on_scope(self, file_name_scope):
self._write("STORE_PANEL DISK,HDD,FILE," + file_name_scope)
self._get_and_print_cmd_error()

def _recall_setup_from_file_on_scope(self, file_name_scope):
self._write("RECALL_PANEL DISK,HDD,FILE," + file_name_scope)
self._get_and_print_cmd_error()

def save_setup_to_local_file(self, file_name_local):
setup_data = self._ask("PANEL_SETUP?")
self._get_and_print_cmd_error()
# remove echoed command characters from beginning
setup_data = setup_data[5:]
local_file = open(file_name_local, "w", encoding='utf-8')
local_file.write(setup_data)
local_file.close()

def load_setup_from_local_file(self, file_name_local):
# Note: Preserve line endings so that lenght matches
# File probably received/stored from Windows scope with \r\n
local_file = open(file_name_local, "r", newline='')
data_read_from_file = local_file.read()
file_name_scope = "'D:\\Temporary_setup.lss'"
self._write_to_file_on_scope(file_name_scope, data_read_from_file)
self._recall_setup_from_file_on_scope(file_name_scope)

def _populate_device_info(self):
manufacturer, model, serial, version = re.match(
"([^,]*),([^,]*),([^,]*),([^,]*)", self._ask("*IDN?")
Expand All @@ -111,7 +181,9 @@ def print_info(manufacturer, model, serial, version, opts):
# TODO: logging
print(f"Connected to {manufacturer} {model} (ip: {self._ip_addr}, serial: {serial}, "
f"version: {version}, options: {opts})")

if opts == "WARNING : CURRENT REMOTE CONTROL INTERFACE IS TCPIP":
print("ERROR: WAVERUNNER: Must set remote control to VXI11 on scope under: "
"Utilities > Utilities Setup > Remote")
print_info(**self._device_info)

def _default_setup(self):
Expand Down