From 46a19092960b88df4355c977e1d32023b01d5bb8 Mon Sep 17 00:00:00 2001 From: x12sa Date: Wed, 1 Jul 2026 11:12:27 +0200 Subject: [PATCH] command history --- csaxs_bec/devices/omny/galil/fgalil_ophyd.py | 4 +- csaxs_bec/devices/omny/galil/fupr_ophyd.py | 3 +- csaxs_bec/devices/omny/galil/galil_ophyd.py | 18 ++----- csaxs_bec/devices/omny/galil/galil_rio.py | 9 ++-- csaxs_bec/devices/omny/galil/lgalil_ophyd.py | 32 +++++++----- csaxs_bec/devices/omny/galil/ogalil_ophyd.py | 19 +------ csaxs_bec/devices/omny/galil/sgalil_ophyd.py | 24 +++------ csaxs_bec/devices/omny/rt/rt_flomni_ophyd.py | 3 +- csaxs_bec/devices/omny/rt/rt_lamni_ophyd.py | 51 +++++++------------ csaxs_bec/devices/omny/rt/rt_omny_ophyd.py | 5 +- csaxs_bec/devices/omny/rt/rt_ophyd.py | 18 +------ .../devices/smaract/smaract_controller.py | 18 ++----- 12 files changed, 64 insertions(+), 140 deletions(-) diff --git a/csaxs_bec/devices/omny/galil/fgalil_ophyd.py b/csaxs_bec/devices/omny/galil/fgalil_ophyd.py index 7b79edd..0444295 100644 --- a/csaxs_bec/devices/omny/galil/fgalil_ophyd.py +++ b/csaxs_bec/devices/omny/galil/fgalil_ophyd.py @@ -7,7 +7,7 @@ from ophyd import Component as Cpt from ophyd import Device, PositionerBase, Signal from ophyd.status import wait as status_wait from ophyd.utils import LimitError -from ophyd_devices.utils.controller import threadlocked +from ophyd_devices.utils.controller import retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO, raise_if_disconnected from csaxs_bec.devices.omny.galil.galil_ophyd import ( @@ -19,7 +19,6 @@ from csaxs_bec.devices.omny.galil.galil_ophyd import ( GalilMotorResolution, GalilSetpointSignal, GalilSignalRO, - retry_once, ) logger = bec_logger.logger @@ -41,6 +40,7 @@ class FlomniGalilController(GalilController): "all_axes_referenced", "lights_off", "lights_on", + "print_command_history", ] def is_axis_moving(self, axis_Id, axis_Id_numeric) -> bool: diff --git a/csaxs_bec/devices/omny/galil/fupr_ophyd.py b/csaxs_bec/devices/omny/galil/fupr_ophyd.py index 2b693dd..9ce0545 100644 --- a/csaxs_bec/devices/omny/galil/fupr_ophyd.py +++ b/csaxs_bec/devices/omny/galil/fupr_ophyd.py @@ -7,7 +7,7 @@ from ophyd import Component as Cpt from ophyd import Device, PositionerBase, Signal from ophyd.status import wait as status_wait from ophyd.utils import LimitError -from ophyd_devices.utils.controller import threadlocked +from ophyd_devices.utils.controller import retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO, raise_if_disconnected from csaxs_bec.devices.omny.galil.galil_ophyd import ( @@ -19,7 +19,6 @@ from csaxs_bec.devices.omny.galil.galil_ophyd import ( GalilMotorResolution, GalilSetpointSignal, GalilSignalRO, - retry_once, ) logger = bec_logger.logger diff --git a/csaxs_bec/devices/omny/galil/galil_ophyd.py b/csaxs_bec/devices/omny/galil/galil_ophyd.py index b1b7b4a..217bd6f 100644 --- a/csaxs_bec/devices/omny/galil/galil_ophyd.py +++ b/csaxs_bec/devices/omny/galil/galil_ophyd.py @@ -8,7 +8,7 @@ from typing import Any from bec_lib import bec_logger from ophyd.utils import ReadOnlyError -from ophyd_devices.utils.controller import Controller, threadlocked +from ophyd_devices.utils.controller import Controller, retry_once, threadlocked from ophyd_devices.utils.socket import SocketSignal from prettytable import PrettyTable @@ -27,20 +27,6 @@ class BECConfigError(Exception): pass -def retry_once(fcn): - """Decorator to rerun a function in case a Galil communication error was raised. This may happen if the buffer was not empty.""" - - @functools.wraps(fcn) - def wrapper(self, *args, **kwargs): - try: - val = fcn(self, *args, **kwargs) - except (GalilCommunicationError, GalilError): - val = fcn(self, *args, **kwargs) - return val - - return wrapper - - class GalilController(Controller): """ Base class for Galil controllers. This class provides the basic functionality for Galil controllers and should be subclassed for specific devices. @@ -59,6 +45,7 @@ class GalilController(Controller): "is_motor_on", "is_thread_active", "all_axes_referenced", + "print_command_history", ] OKBLUE = "\033[94m" @@ -70,6 +57,7 @@ class GalilController(Controller): @threadlocked def socket_put(self, val: str) -> None: + self.command_history.append(f"[PUT]: {val}") self.sock.put(f"{val}\r".encode()) @retry_once diff --git a/csaxs_bec/devices/omny/galil/galil_rio.py b/csaxs_bec/devices/omny/galil/galil_rio.py index dd0313e..9be4f1d 100644 --- a/csaxs_bec/devices/omny/galil/galil_rio.py +++ b/csaxs_bec/devices/omny/galil/galil_rio.py @@ -21,14 +21,10 @@ from ophyd import DynamicDeviceComponent as DDC from ophyd import Kind from ophyd.utils import ReadOnlyError from ophyd_devices import PSIDeviceBase -from ophyd_devices.utils.controller import Controller, threadlocked +from ophyd_devices.utils.controller import Controller, retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO -from csaxs_bec.devices.omny.galil.galil_ophyd import ( - GalilCommunicationError, - GalilSignalBase, - retry_once, -) +from csaxs_bec.devices.omny.galil.galil_ophyd import GalilCommunicationError, GalilSignalBase if TYPE_CHECKING: # pragma: no cover from bec_lib.devicemanager import ScanInfo @@ -43,6 +39,7 @@ class GalilRIOController(Controller): @threadlocked def socket_put(self, val: str) -> None: """Socker put method.""" + self.command_history.append(f"[PUT]: {val}") self.sock.put(f"{val}\r".encode()) @retry_once diff --git a/csaxs_bec/devices/omny/galil/lgalil_ophyd.py b/csaxs_bec/devices/omny/galil/lgalil_ophyd.py index bff1cd6..b86a86d 100644 --- a/csaxs_bec/devices/omny/galil/lgalil_ophyd.py +++ b/csaxs_bec/devices/omny/galil/lgalil_ophyd.py @@ -7,7 +7,7 @@ from ophyd import Component as Cpt from ophyd import Device, PositionerBase, Signal from ophyd.status import wait as status_wait from ophyd.utils import LimitError -from ophyd_devices.utils.controller import threadlocked +from ophyd_devices.utils.controller import retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO, raise_if_disconnected from csaxs_bec.devices.omny.galil.galil_ophyd import ( @@ -17,7 +17,6 @@ from csaxs_bec.devices.omny.galil.galil_ophyd import ( GalilMotorIsMoving, GalilSetpointSignal, GalilSignalRO, - retry_once, ) logger = bec_logger.logger @@ -29,15 +28,19 @@ class GalilMotorResolution(GalilSignalRO): def _socket_get(self): if self.parent.axis_Id_numeric < 6: return float( - self.controller.socket_put_and_receive(f"MG encpermm[{self.parent.axis_Id_numeric}]") + self.controller.socket_put_and_receive( + f"MG encpermm[{self.parent.axis_Id_numeric}]" + ) ) else: return float( - self.controller.socket_put_and_receive(f"MG stppermm[{self.parent.axis_Id_numeric}]") + self.controller.socket_put_and_receive( + f"MG stppermm[{self.parent.axis_Id_numeric}]" + ) ) -class LamniGalilController(GalilController): +class LamniGalilController(GalilController): # ============================================================ # Error status @@ -51,7 +54,7 @@ class LamniGalilController(GalilController): 0x10: "Cap1 exceeded allowed left-stop boundary during movement", 0x20: "Cap2 exceeded allowed left-stop boundary during movement (disabled in code)", 0x40: "Cap1 did not respond to test movement", - 0x80: "Cap2 did not respond to test movement" + 0x80: "Cap2 did not respond to test movement", } allaxrer_table = { @@ -61,10 +64,9 @@ class LamniGalilController(GalilController): 4: "Pressure valve mismatch (OUT13=0 but IN13=1)", 5: "Capacitive sensor boundary violations (caperr > 0)", 6: "Emergency Stop triggered (IN[5]=0)", - 7: "Following error detected on one or more axes" + 7: "Following error detected on one or more axes", } - USER_ACCESS = [ "describe", "show_running_threads", @@ -78,7 +80,8 @@ class LamniGalilController(GalilController): "is_motor_on", "all_axes_referenced", "lamni_lights_off", - "lamni_lights_on" + "lamni_lights_on", + "print_command_history", ] def show_status_other(self): @@ -107,7 +110,9 @@ class LamniGalilController(GalilController): if allaxref == 1: print(f"Allaxref = 1, all OK.") else: - print(f"Allaxref = {allaxref}. Not all axes are referenced or error introduced preventing motion.") + print( + f"Allaxref = {allaxref}. Not all axes are referenced or error introduced preventing motion." + ) allaxrer = int(float(self.socket_put_and_receive("MGallaxrer"))) print("\nallaxrer =", allaxrer) print(self.decode_allaxrer(allaxrer)) @@ -143,7 +148,6 @@ class LamniGalilController(GalilController): print("\n==================================\n") - def lamni_lights_off(self): self.socket_put_confirmed("SB1") @@ -170,14 +174,16 @@ class LamniGalilReadbackSignal(GalilSignalRO): current_pos = float(self.controller.socket_put_and_receive(f"TP{self.parent.axis_Id}")) current_pos *= self.parent.sign encoder_resolution = self.parent.motor_resolution.get() - logger.info(f"Read galil encoder position of axis {self.parent.axis_Id_numeric} to be TP {current_pos} with resolution {encoder_resolution}") + logger.info( + f"Read galil encoder position of axis {self.parent.axis_Id_numeric} to be TP {current_pos} with resolution {encoder_resolution}" + ) return current_pos / encoder_resolution else: current_pos = float(self.controller.socket_put_and_receive(f"TD{self.parent.axis_Id}")) current_pos *= self.parent.sign step_mm = self.parent.motor_resolution.get() return current_pos / step_mm - + def read(self): self._metadata["timestamp"] = time.time() val = super().read() diff --git a/csaxs_bec/devices/omny/galil/ogalil_ophyd.py b/csaxs_bec/devices/omny/galil/ogalil_ophyd.py index a7086ab..88bf839 100644 --- a/csaxs_bec/devices/omny/galil/ogalil_ophyd.py +++ b/csaxs_bec/devices/omny/galil/ogalil_ophyd.py @@ -10,15 +10,13 @@ from ophyd import Component as Cpt from ophyd import Device, PositionerBase, Signal from ophyd.status import wait as status_wait from ophyd.utils import LimitError -from ophyd_devices.utils.controller import threadlocked +from ophyd_devices.utils.controller import retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO, raise_if_disconnected from csaxs_bec.devices.omny.galil.galil_ophyd import ( BECConfigError, GalilAxesReferenced, - GalilCommunicationError, GalilController, - GalilError, GalilMotorIsMoving, GalilSetpointSignal, GalilSignalRO, @@ -27,20 +25,6 @@ from csaxs_bec.devices.omny.galil.galil_ophyd import ( logger = bec_logger.logger -def retry_once(fcn): - """Decorator to rerun a function in case a Galil communication error was raised. This may happen if the buffer was not empty.""" - - @functools.wraps(fcn) - def wrapper(self, *args, **kwargs): - try: - val = fcn(self, *args, **kwargs) - except (GalilCommunicationError, GalilError): - val = fcn(self, *args, **kwargs) - return val - - return wrapper - - class GalilMotorResolution(GalilSignalRO): @retry_once @threadlocked @@ -130,6 +114,7 @@ class OMNYGalilController(GalilController): "get_motor_limit_switch", "is_motor_on", "all_axes_referenced", + "print_command_history", "_ogalil_switchsocket", "_ogalil_switchsocket_switch_all_on", "_ogalil_switchsocket_status", diff --git a/csaxs_bec/devices/omny/galil/sgalil_ophyd.py b/csaxs_bec/devices/omny/galil/sgalil_ophyd.py index 16b1c93..ff7cf48 100644 --- a/csaxs_bec/devices/omny/galil/sgalil_ophyd.py +++ b/csaxs_bec/devices/omny/galil/sgalil_ophyd.py @@ -8,7 +8,7 @@ from ophyd import Component as Cpt from ophyd import Device, DeviceStatus, PositionerBase, Signal from ophyd.status import wait as status_wait from ophyd.utils import LimitError, ReadOnlyError -from ophyd_devices.utils.controller import Controller, threadlocked +from ophyd_devices.utils.controller import Controller, retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected from prettytable import PrettyTable @@ -27,20 +27,6 @@ class BECConfigError(Exception): pass -def retry_once(fcn): - """Decorator to rerun a function in case a Galil communication error was raised. This may happen if the buffer was not empty.""" - - @functools.wraps(fcn) - def wrapper(self, *args, **kwargs): - try: - val = fcn(self, *args, **kwargs) - except (GalilCommunicationError, GalilError): - val = fcn(self, *args, **kwargs) - return val - - return wrapper - - class GalilController(Controller): USER_ACCESS = [ "describe", @@ -51,6 +37,7 @@ class GalilController(Controller): "sgalil_reference", "fly_grid_scan", "read_encoder_position", + "print_command_history", ] _axes_per_controller = 8 @@ -84,19 +71,22 @@ class GalilController(Controller): @threadlocked def socket_put(self, val: str) -> None: time.sleep(0.01) + self.command_history.append(f"[PUT]: {val}") self.sock.put(f"{val}\r".encode()) @threadlocked def socket_get(self) -> str: time.sleep(0.01) - return self.sock.receive().decode() + response = self.sock.receive().decode() + self.command_history.append(f"[GET]: {response}") + return response @retry_once @threadlocked def socket_put_and_receive(self, val: str, remove_trailing_chars=True) -> str: self.socket_put(val) if remove_trailing_chars: - return self._remove_trailing_characters(self.sock.receive().decode()) + return self._remove_trailing_characters(self.socket_get()) return self.socket_get() @retry_once diff --git a/csaxs_bec/devices/omny/rt/rt_flomni_ophyd.py b/csaxs_bec/devices/omny/rt/rt_flomni_ophyd.py index 3e7fea9..4f8f183 100644 --- a/csaxs_bec/devices/omny/rt/rt_flomni_ophyd.py +++ b/csaxs_bec/devices/omny/rt/rt_flomni_ophyd.py @@ -8,7 +8,7 @@ from ophyd import Device, PositionerBase, Signal from ophyd.status import wait as status_wait from ophyd.utils import LimitError from ophyd_devices import AsyncMultiSignal, DeviceStatus, ProgressSignal -from ophyd_devices.utils.controller import Controller, threadlocked +from ophyd_devices.utils.controller import Controller, retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO, raise_if_disconnected from prettytable import PrettyTable @@ -18,7 +18,6 @@ from csaxs_bec.devices.omny.rt.rt_ophyd import ( RtReadbackSignal, RtSetpointSignal, RtSignalRO, - retry_once, ) logger = bec_logger.logger diff --git a/csaxs_bec/devices/omny/rt/rt_lamni_ophyd.py b/csaxs_bec/devices/omny/rt/rt_lamni_ophyd.py index e69207a..3a3f6b0 100644 --- a/csaxs_bec/devices/omny/rt/rt_lamni_ophyd.py +++ b/csaxs_bec/devices/omny/rt/rt_lamni_ophyd.py @@ -9,7 +9,7 @@ from ophyd import Device, DeviceStatus, PositionerBase, Signal from ophyd.status import wait as status_wait from ophyd.utils import LimitError, ReadOnlyError from ophyd_devices.utils.bec_signals import AsyncMultiSignal, ProgressSignal -from ophyd_devices.utils.controller import Controller, threadlocked +from ophyd_devices.utils.controller import Controller, retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected from prettytable import PrettyTable @@ -30,20 +30,6 @@ class BECConfigError(Exception): pass -def retry_once(fcn): - """Decorator to rerun a function in case a CommunicationError was raised. This may happen if the buffer was not empty.""" - - @functools.wraps(fcn) - def wrapper(self, *args, **kwargs): - try: - val = fcn(self, *args, **kwargs) - except (RtLamniCommunicationError, RtLamniError): - val = fcn(self, *args, **kwargs) - return val - - return wrapper - - class RtLamniController(Controller): """ RT-Lamni controller class for all rt devices. @@ -133,7 +119,7 @@ class RtLamniController(Controller): @threadlocked def _position_sampling_single_read(self): - (number_of_samples, sum0, sum0_2, sum1, sum1_2, sum2, sum2_2) = self.socket_put_and_receive( + number_of_samples, sum0, sum0_2, sum1, sum1_2, sum2, sum2_2 = self.socket_put_and_receive( f"Sr" ).split(",") avg_x = float(sum1) / int(number_of_samples) @@ -187,7 +173,7 @@ class RtLamniController(Controller): parent._min_scan_buffer_reached = False for pos_index, pos in enumerate(positions): cmd = f"s{pos[0]:.05f},{pos[1]:.05f},0" - parent.socket_put_and_receive(cmd) + parent.socket_put_and_receive(cmd) if pos_index > 100: parent._min_scan_buffer_reached = True parent._min_scan_buffer_reached = True @@ -224,7 +210,7 @@ class RtLamniController(Controller): "Cannot start scan because feedback loop is not running or there is an interferometer error." ) # here exception - (mode, number_of_positions_planned, current_position_in_scan) = self.get_scan_status() + mode, number_of_positions_planned, current_position_in_scan = self.get_scan_status() if number_of_positions_planned == 0: logger.error("Cannot start scan because no target positions are planned.") @@ -241,24 +227,25 @@ class RtLamniController(Controller): if self.feedback_is_running(): print("Loop is running, no error on interferometer.") else: - print("Loop is not running, either it is turned off or an interferometer error occurred.") - + print( + "Loop is not running, either it is turned off or an interferometer error occurred." + ) def show_analog_signals(self) -> dict: self.socket_put("As") # start sampling time.sleep(0.01) return_table = (self.socket_put_and_receive("Ar")).split(",") - + number_of_samples = int(float(return_table[0])) signals = { - "number_of_samples": number_of_samples, - "piezo_0": float(return_table[1]), - "piezo_1": float(return_table[2]), - "cap_0": float(return_table[3]), - "cap_1": float(return_table[4]), - "cap_2": float(return_table[5]), - "cap_3": float(return_table[6]), - "cap_4": float(return_table[7]), + "number_of_samples": number_of_samples, + "piezo_0": float(return_table[1]), + "piezo_1": float(return_table[2]), + "cap_0": float(return_table[3]), + "cap_1": float(return_table[4]), + "cap_2": float(return_table[5]), + "cap_3": float(return_table[6]), + "cap_4": float(return_table[7]), } t = PrettyTable() @@ -294,8 +281,8 @@ class RtLamniController(Controller): t = PrettyTable() t.title = "Interferometer signal strength" t.field_names = ["Axis", "Description", "Value", "Running"] - t.add_row([0, "ST FZP horizontal", ssi_0, "-"]) - t.add_row([1, "ST FZP vertical", ssi_1, "-"]) + t.add_row([0, "ST FZP horizontal", ssi_0, "-"]) + t.add_row([1, "ST FZP vertical", ssi_1, "-"]) t.add_row([2, "Angle interferometer", angle_signal, angle_running]) print(t) @@ -318,7 +305,7 @@ class RtLamniController(Controller): print(t) print(f"Feedback loop running: {loop_status}") - return {"x": pos_x, "y": pos_y, "loop_running": loop_status} + return {"x": pos_x, "y": pos_y, "loop_running": loop_status} def feedback_enable_with_reset(self): if not self.feedback_status_angle_lamni(): diff --git a/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py b/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py index f84441b..f2566f2 100644 --- a/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py +++ b/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py @@ -10,7 +10,7 @@ from ophyd import Device, DeviceStatus, PositionerBase, Signal from ophyd.status import wait as status_wait from ophyd.utils import LimitError from ophyd_devices import AsyncMultiSignal, ProgressSignal -from ophyd_devices.utils.controller import Controller, threadlocked +from ophyd_devices.utils.controller import Controller, retry_once, threadlocked from ophyd_devices.utils.socket import SocketIO, raise_if_disconnected from prettytable import PrettyTable @@ -27,7 +27,6 @@ from csaxs_bec.devices.omny.rt.rt_ophyd import ( RtReadbackSignal, RtSetpointSignal, RtSignalRO, - retry_once, ) logger = bec_logger.logger @@ -853,7 +852,7 @@ class RtOMNYController(Controller): " interferometer error." ) # here exception - (mode, number_of_positions_planned, current_position_in_scan) = self.get_scan_status() + mode, number_of_positions_planned, current_position_in_scan = self.get_scan_status() if number_of_positions_planned == 0: logger.error("Cannot start scan because no target positions are planned.") diff --git a/csaxs_bec/devices/omny/rt/rt_ophyd.py b/csaxs_bec/devices/omny/rt/rt_ophyd.py index 1948b08..f456729 100644 --- a/csaxs_bec/devices/omny/rt/rt_ophyd.py +++ b/csaxs_bec/devices/omny/rt/rt_ophyd.py @@ -1,5 +1,5 @@ """ -This module contains base signals for RT devices. Controller and motors are implemented in the +This module contains base signals for RT devices. Controller and motors are implemented in the bespoke modules such as `rt_flomni_ophyd.py` or `rt_lamni_ophyd.py`. """ @@ -8,7 +8,7 @@ import time from bec_lib import bec_logger from ophyd.utils import ReadOnlyError -from ophyd_devices.utils.controller import ControllerCommunicationError, threadlocked +from ophyd_devices.utils.controller import ControllerCommunicationError, retry_once, threadlocked from ophyd_devices.utils.socket import SocketSignal logger = bec_logger.logger @@ -26,20 +26,6 @@ class BECConfigError(Exception): pass -def retry_once(fcn): - """Decorator to rerun a function in case a CommunicationError was raised. This may happen if the buffer was not empty.""" - - @functools.wraps(fcn) - def wrapper(self, *args, **kwargs): - try: - val = fcn(self, *args, **kwargs) - except (RtCommunicationError, RtError): - val = fcn(self, *args, **kwargs) - return val - - return wrapper - - class RtSignalBase(SocketSignal): def __init__(self, signal_name, **kwargs): self.signal_name = signal_name diff --git a/csaxs_bec/devices/smaract/smaract_controller.py b/csaxs_bec/devices/smaract/smaract_controller.py index 6107329..9226207 100644 --- a/csaxs_bec/devices/smaract/smaract_controller.py +++ b/csaxs_bec/devices/smaract/smaract_controller.py @@ -6,7 +6,7 @@ import os import time import numpy as np -from ophyd_devices.utils.controller import Controller, axis_checked, threadlocked +from ophyd_devices.utils.controller import Controller, axis_checked, retry_once, threadlocked from prettytable import PrettyTable from typeguard import typechecked @@ -20,20 +20,6 @@ class SmaractCommunicationMode(enum.Enum): ASYNC = 1 -def retry_once(fcn): - """Decorator to rerun a function in case a SmaractCommunicationError was raised. This may happen if the buffer was not empty.""" - - @functools.wraps(fcn) - def wrapper(self, *args, **kwargs): - try: - val = fcn(self, *args, **kwargs) - except (SmaractCommunicationError, SmaractErrorCode): - val = fcn(self, *args, **kwargs) - return val - - return wrapper - - class SmaractChannelStatus(enum.Enum): STOPPED = 0 STEPPING = 1 @@ -82,6 +68,7 @@ class SmaractController(Controller): "all_axes_referenced", "set_closed_loop_move_speed", "is_axis_moving", + "print_command_history", ] def __init__( @@ -113,6 +100,7 @@ class SmaractController(Controller): @threadlocked def socket_put(self, val: str): + self.command_history.append(f"[PUT]: {val}") self.sock.put(f":{val}\n".encode()) @threadlocked