command history

This commit is contained in:
x12sa
2026-07-01 11:19:27 +02:00
committed by wakonig_k
parent 9796bcb73f
commit 46a1909296
12 changed files with 64 additions and 140 deletions
+2 -2
View File
@@ -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:
+1 -2
View File
@@ -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
+3 -15
View File
@@ -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
+3 -6
View File
@@ -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
+19 -13
View File
@@ -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()
+2 -17
View File
@@ -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",
+7 -17
View File
@@ -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
+1 -2
View File
@@ -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
+19 -32
View File
@@ -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():
+2 -3
View File
@@ -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.")
+2 -16
View File
@@ -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
@@ -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