mirror of
https://github.com/bec-project/ophyd_devices.git
synced 2026-02-20 09:18:42 +01:00
fix(panda-box): add signal_alias to map PandaBlock names ot beamline signal names.
This commit is contained in:
@@ -1,434 +0,0 @@
|
||||
Checking eiger...
|
||||
OK
|
||||
Checking dyn_signals...
|
||||
OK
|
||||
Checking pseudo_signal1...
|
||||
OK
|
||||
Checking hexapod...
|
||||
OK
|
||||
Checking eyefoc...
|
||||
OK
|
||||
Checking eyex...
|
||||
OK
|
||||
Checking eyey...
|
||||
OK
|
||||
Checking flyer_sim...
|
||||
OK
|
||||
Checking hrox...
|
||||
OK
|
||||
Checking hroy...
|
||||
OK
|
||||
Checking hroz...
|
||||
OK
|
||||
Checking hx...
|
||||
OK
|
||||
Checking hy...
|
||||
OK
|
||||
Checking hz...
|
||||
OK
|
||||
Checking mbsx...
|
||||
OK
|
||||
Checking mbsy...
|
||||
OK
|
||||
Checking pinx...
|
||||
OK
|
||||
Checking piny...
|
||||
OK
|
||||
Checking pinz...
|
||||
OK
|
||||
Checking samx...
|
||||
OK
|
||||
Checking samy...
|
||||
OK
|
||||
Checking samz...
|
||||
OK
|
||||
Checking bpm3a...
|
||||
OK
|
||||
Checking bpm3b...
|
||||
OK
|
||||
Checking bpm3c...
|
||||
OK
|
||||
Checking bpm3d...
|
||||
OK
|
||||
Checking bpm3i...
|
||||
OK
|
||||
Checking bpm3x...
|
||||
OK
|
||||
Checking bpm3y...
|
||||
OK
|
||||
Checking bpm3z...
|
||||
OK
|
||||
Checking bpm4a...
|
||||
OK
|
||||
Checking bpm4b...
|
||||
OK
|
||||
Checking bpm4c...
|
||||
OK
|
||||
Checking bpm4d...
|
||||
OK
|
||||
Checking bpm4i...
|
||||
OK
|
||||
Checking bpm4s...
|
||||
OK
|
||||
Checking bpm4x...
|
||||
OK
|
||||
Checking bpm4xf...
|
||||
OK
|
||||
Checking bpm4xm...
|
||||
OK
|
||||
Checking bpm4y...
|
||||
OK
|
||||
Checking bpm4yf...
|
||||
OK
|
||||
Checking bpm4ym...
|
||||
OK
|
||||
Checking bpm4z...
|
||||
OK
|
||||
Checking bpm5a...
|
||||
OK
|
||||
Checking bpm5b...
|
||||
OK
|
||||
Checking bpm5c...
|
||||
OK
|
||||
Checking bpm5d...
|
||||
OK
|
||||
Checking bpm5i...
|
||||
OK
|
||||
Checking bpm5x...
|
||||
OK
|
||||
Checking bpm5y...
|
||||
OK
|
||||
Checking bpm5z...
|
||||
OK
|
||||
Checking bpm6a...
|
||||
OK
|
||||
Checking bpm6b...
|
||||
OK
|
||||
Checking bpm6c...
|
||||
OK
|
||||
Checking bpm6d...
|
||||
OK
|
||||
Checking bpm6i...
|
||||
OK
|
||||
Checking bpm6x...
|
||||
OK
|
||||
Checking bpm6y...
|
||||
OK
|
||||
Checking bpm6z...
|
||||
OK
|
||||
Checking curr...
|
||||
OK
|
||||
Checking diode...
|
||||
OK
|
||||
Checking ebpmdx...
|
||||
OK
|
||||
Checking ebpmdy...
|
||||
OK
|
||||
Checking ebpmux...
|
||||
OK
|
||||
Checking ebpmuy...
|
||||
OK
|
||||
Checking ftp...
|
||||
OK
|
||||
Checking temp...
|
||||
OK
|
||||
Checking transd...
|
||||
OK
|
||||
Checking aptrx...
|
||||
OK
|
||||
Checking aptry...
|
||||
OK
|
||||
Checking bim2x...
|
||||
OK
|
||||
Checking bim2y...
|
||||
OK
|
||||
Checking bm1trx...
|
||||
OK
|
||||
Checking bm1try...
|
||||
OK
|
||||
Checking bm2trx...
|
||||
OK
|
||||
Checking bm2try...
|
||||
OK
|
||||
Checking bm3trx...
|
||||
OK
|
||||
Checking bm3try...
|
||||
OK
|
||||
Checking bm4trx...
|
||||
OK
|
||||
Checking bm4try...
|
||||
OK
|
||||
Checking bm5trx...
|
||||
OK
|
||||
Checking bm5try...
|
||||
OK
|
||||
Checking bm6trx...
|
||||
OK
|
||||
Checking bm6try...
|
||||
OK
|
||||
Checking bpm4r...
|
||||
OK
|
||||
Checking bpm5r...
|
||||
OK
|
||||
Checking bs1x...
|
||||
OK
|
||||
Checking bs1y...
|
||||
OK
|
||||
Checking bs2x...
|
||||
OK
|
||||
Checking bs2y...
|
||||
OK
|
||||
Checking burstn...
|
||||
OK
|
||||
Checking burstr...
|
||||
OK
|
||||
Checking ddg1a...
|
||||
OK
|
||||
Checking ddg1b...
|
||||
OK
|
||||
Checking ddg1c...
|
||||
OK
|
||||
Checking ddg1d...
|
||||
OK
|
||||
Checking ddg1e...
|
||||
OK
|
||||
Checking ddg1f...
|
||||
OK
|
||||
Checking ddg1g...
|
||||
OK
|
||||
Checking ddg1h...
|
||||
OK
|
||||
Checking dettrx...
|
||||
OK
|
||||
Checking di2trx...
|
||||
OK
|
||||
Checking di2try...
|
||||
OK
|
||||
Checking dtpush...
|
||||
OK
|
||||
Checking dtth...
|
||||
OK
|
||||
Checking dttrx...
|
||||
OK
|
||||
Checking dttry...
|
||||
OK
|
||||
Checking dttrz...
|
||||
OK
|
||||
Checking ebcsx...
|
||||
OK
|
||||
Checking ebcsy...
|
||||
OK
|
||||
Checking ebfi1...
|
||||
OK
|
||||
Checking ebfi2...
|
||||
OK
|
||||
Checking ebfi3...
|
||||
OK
|
||||
Checking ebfi4...
|
||||
OK
|
||||
Checking ebfzpx...
|
||||
OK
|
||||
Checking ebfzpy...
|
||||
OK
|
||||
Checking ebtrx...
|
||||
OK
|
||||
Checking ebtry...
|
||||
OK
|
||||
Checking ebtrz...
|
||||
OK
|
||||
Checking fi1try...
|
||||
OK
|
||||
Checking fi2try...
|
||||
OK
|
||||
Checking fi3try...
|
||||
OK
|
||||
Checking fsh1x...
|
||||
OK
|
||||
Checking fsh2x...
|
||||
OK
|
||||
Checking ftrans...
|
||||
OK
|
||||
Checking fttrx1...
|
||||
OK
|
||||
Checking fttrx2...
|
||||
OK
|
||||
Checking fttry1...
|
||||
OK
|
||||
Checking fttry2...
|
||||
OK
|
||||
Checking fttrz...
|
||||
OK
|
||||
Checking idgap...
|
||||
OK
|
||||
Checking mibd...
|
||||
OK
|
||||
Checking mibd1...
|
||||
OK
|
||||
Checking mibd2...
|
||||
OK
|
||||
Checking miroll...
|
||||
OK
|
||||
Checking mith...
|
||||
OK
|
||||
Checking mitrx...
|
||||
OK
|
||||
Checking mitry...
|
||||
OK
|
||||
Checking mitry1...
|
||||
OK
|
||||
Checking mitry2...
|
||||
OK
|
||||
Checking mitry3...
|
||||
OK
|
||||
Checking mobd...
|
||||
OK
|
||||
Checking mobdai...
|
||||
OK
|
||||
Checking mobdbo...
|
||||
OK
|
||||
Checking mobdco...
|
||||
OK
|
||||
Checking mobddi...
|
||||
OK
|
||||
Checking mokev...
|
||||
OK
|
||||
Checking mopush1...
|
||||
OK
|
||||
Checking mopush2...
|
||||
OK
|
||||
Checking moroll1...
|
||||
OK
|
||||
Checking moroll2...
|
||||
OK
|
||||
Checking moth1...
|
||||
OK
|
||||
Checking moth1e...
|
||||
OK
|
||||
Checking moth2...
|
||||
OK
|
||||
Checking moth2e...
|
||||
OK
|
||||
Checking motrx2...
|
||||
OK
|
||||
Checking motry...
|
||||
OK
|
||||
Checking motry2...
|
||||
OK
|
||||
Checking motrz1...
|
||||
OK
|
||||
Checking motrz1e...
|
||||
OK
|
||||
Checking moyaw2...
|
||||
OK
|
||||
Checking sl0ch...
|
||||
OK
|
||||
Checking sl0trxi...
|
||||
OK
|
||||
Checking sl0trxo...
|
||||
OK
|
||||
Checking sl0wh...
|
||||
OK
|
||||
Checking sl1ch...
|
||||
OK
|
||||
Checking sl1cv...
|
||||
OK
|
||||
Checking sl1trxi...
|
||||
OK
|
||||
Checking sl1trxo...
|
||||
OK
|
||||
Checking sl1tryb...
|
||||
OK
|
||||
Checking sl1tryt...
|
||||
OK
|
||||
Checking sl1wh...
|
||||
OK
|
||||
Checking sl1wv...
|
||||
OK
|
||||
Checking sl2ch...
|
||||
OK
|
||||
Checking sl2cv...
|
||||
OK
|
||||
Checking sl2trxi...
|
||||
OK
|
||||
Checking sl2trxo...
|
||||
OK
|
||||
Checking sl2tryb...
|
||||
OK
|
||||
Checking sl2tryt...
|
||||
OK
|
||||
Checking sl2wh...
|
||||
OK
|
||||
Checking sl2wv...
|
||||
OK
|
||||
Checking sl3ch...
|
||||
OK
|
||||
Checking sl3cv...
|
||||
OK
|
||||
Checking sl3trxi...
|
||||
OK
|
||||
Checking sl3trxo...
|
||||
OK
|
||||
Checking sl3tryb...
|
||||
OK
|
||||
Checking sl3tryt...
|
||||
OK
|
||||
Checking sl3wh...
|
||||
OK
|
||||
Checking sl3wv...
|
||||
OK
|
||||
Checking sl4ch...
|
||||
OK
|
||||
Checking sl4cv...
|
||||
OK
|
||||
Checking sl4trxi...
|
||||
OK
|
||||
Checking sl4trxo...
|
||||
OK
|
||||
Checking sl4tryb...
|
||||
OK
|
||||
Checking sl4tryt...
|
||||
OK
|
||||
Checking sl4wh...
|
||||
OK
|
||||
Checking sl4wv...
|
||||
OK
|
||||
Checking sl5ch...
|
||||
OK
|
||||
Checking sl5cv...
|
||||
OK
|
||||
Checking sl5trxi...
|
||||
OK
|
||||
Checking sl5trxo...
|
||||
OK
|
||||
Checking sl5tryb...
|
||||
OK
|
||||
Checking sl5tryt...
|
||||
OK
|
||||
Checking sl5wh...
|
||||
OK
|
||||
Checking sl5wv...
|
||||
OK
|
||||
Checking strox...
|
||||
OK
|
||||
Checking stroy...
|
||||
OK
|
||||
Checking stroz...
|
||||
OK
|
||||
Checking sttrx...
|
||||
OK
|
||||
Checking sttry...
|
||||
OK
|
||||
Checking ring_current_sim...
|
||||
OK
|
||||
Checking monitor_async...
|
||||
OK
|
||||
Checking rt_controller...
|
||||
OK
|
||||
Checking waveform...
|
||||
OK
|
||||
|
||||
|
||||
|
||||
========================================
|
||||
Summary:
|
||||
All devices passed the test.
|
||||
@@ -11,7 +11,7 @@ into the on_connected, stage, unstage, pre_scan, kickoff, complete methods as ne
|
||||
be aware that the on_connected method is wrapped in here and should therefore always call
|
||||
super().on_connected(). Child integrations should register data callbacks to handle incoming
|
||||
data from the PandaBox during acquisition, and set the respective data on their ophyd signals.
|
||||
The utility method _compile_frame_data_to_dict can be used to convert FrameData objects received
|
||||
The utility method convert_frame_data can be used to convert FrameData objects received
|
||||
to the expected signal dict format. Please be aware that naming conventions here map to the
|
||||
names of the blocks, and should be mapped to the beamline specific signal names in the child class.
|
||||
|
||||
@@ -31,11 +31,14 @@ from typing import TYPE_CHECKING, Any, Callable, TypeAlias, Union
|
||||
|
||||
import pandablocks.commands as pbc
|
||||
from bec_lib import bec_logger
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import Staged
|
||||
from ophyd.status import WaitTimeoutError
|
||||
from pandablocks.blocking import BlockingClient
|
||||
from pandablocks.responses import Data, EndData, FrameData, ReadyData, StartData
|
||||
|
||||
from ophyd_devices import PSIDeviceBase, StatusBase
|
||||
from ophyd_devices import DynamicSignal, PSIDeviceBase, StatusBase
|
||||
from ophyd_devices.devices.panda_box.utils import get_pcap_capture_fields
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from bec_lib.devicemanager import ScanInfo
|
||||
@@ -153,8 +156,23 @@ class PandaBox(PSIDeviceBase):
|
||||
to integrate pre-defined PandaBox layout directly into the BEC scan interface, stage/unstage,
|
||||
trigger/complete, pre_scan or kickoff methods.
|
||||
|
||||
A signal_alias can be provided during initialization to specify the mapping from PandaBox signal names to
|
||||
beamline specific signal names. Any signal that is found in the data frames will be automatically
|
||||
mapped to the provided signal names. If data is received for a signal that is not included in the signal_alias,
|
||||
the original name from the PandaBox will be used as the signal name. Signal config should be provided as a
|
||||
dict with keys corresponding to the signal names from the PandaBox, and values corresponding to the desired
|
||||
signal names to be used in the data frames.
|
||||
"""
|
||||
|
||||
data = Cpt(
|
||||
DynamicSignal,
|
||||
name="data",
|
||||
ndim=0,
|
||||
max_size=1000,
|
||||
signals=get_pcap_capture_fields(),
|
||||
async_update={"type": "add", "max_shape": [None]},
|
||||
)
|
||||
|
||||
USER_ACCESS = ["send_raw", "add_status_callback", "remove_status_callback", "get_panda_state"]
|
||||
|
||||
def __init__(
|
||||
@@ -162,10 +180,15 @@ class PandaBox(PSIDeviceBase):
|
||||
*,
|
||||
name: str,
|
||||
host: str,
|
||||
signal_alias: dict[str, str] | None = None,
|
||||
scan_info: ScanInfo | None = None,
|
||||
device_manager: DeviceManagerDS | None = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
self.signal_alias = signal_alias if signal_alias is not None else {}
|
||||
kwargs.pop(
|
||||
"signal_alias", None
|
||||
) # Remove signal_alias from kwargs to avoid issues with super().__init__()
|
||||
super().__init__(name=name, scan_info=scan_info, device_manager=device_manager, **kwargs)
|
||||
self.host = host
|
||||
|
||||
@@ -186,6 +209,19 @@ class PandaBox(PSIDeviceBase):
|
||||
self.data_thread_kill_event = threading.Event()
|
||||
self.data_thread_run_event = threading.Event()
|
||||
|
||||
# Acquisition group of the PandaBox data.
|
||||
self._acquisition_group = "panda"
|
||||
|
||||
def on_init(self):
|
||||
"""Initialize the PandaBox device. This method can be used to perform any additional initialization logic."""
|
||||
super().on_init()
|
||||
new_names = [
|
||||
self.signal_alias.get(original_name, original_name)
|
||||
for original_name, _ in self.data.signals
|
||||
]
|
||||
# Unify names for data
|
||||
self.data.signals = self.data._unify_signals(new_names)
|
||||
|
||||
##########################
|
||||
### Public API methods ###
|
||||
##########################
|
||||
@@ -486,6 +522,13 @@ class PandaBox(PSIDeviceBase):
|
||||
raise e from e
|
||||
super().on_connected()
|
||||
self.data_thread.start()
|
||||
self.add_data_callback(data_type=PandaState.FRAME.value, callback=self._receive_frame_data)
|
||||
|
||||
def _receive_frame_data(self, data: FrameData) -> None:
|
||||
logger.info(f"Received frame data with signals {data}")
|
||||
out = self.convert_frame_data(frame_data=data)
|
||||
logger.info(f"Compiled data {out}")
|
||||
self.data.put(out, acquisition_group=self._acquisition_group)
|
||||
|
||||
def stop(self, *, success=False):
|
||||
"""
|
||||
@@ -493,8 +536,8 @@ class PandaBox(PSIDeviceBase):
|
||||
We call this prior to the super().stop() call to ensure that the PandaBox
|
||||
is disarmed before any additional stopping logic from child classes is executed.
|
||||
"""
|
||||
super().stop(success=success)
|
||||
self._disarm()
|
||||
super().stop(success=success)
|
||||
|
||||
def destroy(self):
|
||||
"""
|
||||
@@ -522,6 +565,9 @@ class PandaBox(PSIDeviceBase):
|
||||
list[object] | StatusBase: The result of the super().stage() call.
|
||||
"""
|
||||
# First make sure that the data readout loop is not running
|
||||
if self.staged != Staged.no:
|
||||
return super().stage()
|
||||
self.stopped = False
|
||||
status = StatusBase(obj=self)
|
||||
self.add_status_callback(status=status, success=[PandaState.DISARMED], failure=[])
|
||||
try:
|
||||
@@ -530,7 +576,7 @@ class PandaBox(PSIDeviceBase):
|
||||
logger.error(f"PandaBox {self.name} did not disarm before staging.")
|
||||
# pylint: disable=raise-from-missing
|
||||
raise RuntimeError(
|
||||
f"PandaBox {self.name} did not disarm properly. Please connection and the device integration."
|
||||
f"PandaBox {self.name} did not disarm properly. Please check the connection and the device integration."
|
||||
)
|
||||
|
||||
ret = super().stage()
|
||||
@@ -545,9 +591,6 @@ class PandaBox(PSIDeviceBase):
|
||||
"""
|
||||
status = super().pre_scan()
|
||||
status_ready_data_received = StatusBase(obj=self)
|
||||
self.cancel_on_stop(
|
||||
status_ready_data_received
|
||||
) # Make sure we cancel if the scan is stopped
|
||||
status_ready_data_received.add_callback(self._pre_scan_status_callback)
|
||||
self.add_status_callback(
|
||||
status=status_ready_data_received,
|
||||
@@ -559,6 +602,7 @@ class PandaBox(PSIDeviceBase):
|
||||
ret_status = status_ready_data_received & status
|
||||
else:
|
||||
ret_status = status_ready_data_received
|
||||
self.cancel_on_stop(ret_status) # Make sure status is cancelled if externally stopped
|
||||
return ret_status
|
||||
|
||||
def unstage(self) -> list[object] | StatusBase:
|
||||
@@ -584,33 +628,30 @@ class PandaBox(PSIDeviceBase):
|
||||
ret = self.send_raw("*CAPTURE?")
|
||||
return [key.split(" ")[0].strip("!") for key in ret if key.strip(".")]
|
||||
|
||||
def _compile_frame_data_to_dict(
|
||||
self, frame_data: FrameData, signal_name_key_mapping: dict[str, str] | None = None
|
||||
) -> dict[str, Any]:
|
||||
def convert_frame_data(self, frame_data: FrameData) -> dict[str, Any]:
|
||||
"""
|
||||
Compile the data from a FrameData object into a dictionary with expected OPHYD
|
||||
Convert the data from a FrameData object into a dictionary with expected OPHYD
|
||||
read format, e.g. signal {signal_name: {"value": [...]}}.
|
||||
|
||||
Args:
|
||||
frame_data (FrameData): The FrameData object received from the PandaBox.
|
||||
|
||||
Returns:
|
||||
dict[str, Any]: The compiled data in OPHYD read format.
|
||||
dict[str, Any]: The converted data in OPHYD read format.
|
||||
"""
|
||||
if signal_name_key_mapping is None:
|
||||
signal_name_key_mapping = {}
|
||||
# Create output dict
|
||||
out = {}
|
||||
data = frame_data.data
|
||||
keys = data.dtype.names
|
||||
# Map keys if mapping is provided
|
||||
mapped_key = [signal_name_key_mapping.get(key, key) for key in keys]
|
||||
mapped_key = [self.signal_alias.get(key, key) for key in keys]
|
||||
# Initialize lists for each key, consider adjusting names to match
|
||||
for k in mapped_key:
|
||||
out[k] = {"value": []} # Timestamp?
|
||||
for entry in data:
|
||||
for i, k in enumerate(mapped_key):
|
||||
out[k]["value"].append(entry[i]) # Fill values from data
|
||||
return out
|
||||
|
||||
def _pre_scan_status_callback(self, status: StatusBase):
|
||||
"""
|
||||
@@ -635,3 +676,10 @@ class PandaBox(PSIDeviceBase):
|
||||
def _disarm(self) -> None:
|
||||
"""Disarm the PandaBox device."""
|
||||
self._send_command(pbc.Disarm())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage of the PandaBox class
|
||||
panda_box = PandaBox(
|
||||
name="PandaBox1", host="localhost", signal_alias={"long_list": "mapped_signal_name"}
|
||||
)
|
||||
|
||||
50
ophyd_devices/devices/panda_box/utils.py
Normal file
50
ophyd_devices/devices/panda_box/utils.py
Normal file
@@ -0,0 +1,50 @@
|
||||
PANDA_AVAIL_PCAP_BLOCKS = [
|
||||
"INENC1.VAL",
|
||||
"INENC2.VAL",
|
||||
"INENC3.VAL",
|
||||
"INENC4.VAL",
|
||||
"PCAP.TS_START",
|
||||
"PCAP.TS_END",
|
||||
"PCAP.TS_TRIG",
|
||||
"PCAP.GATE_DURATION",
|
||||
"PCAP.BITS0",
|
||||
"PCAP.BITS1",
|
||||
"PCAP.BITS2",
|
||||
"PCAP.BITS3",
|
||||
"CALC1.OUT",
|
||||
"CALC2.OUT",
|
||||
"COUNTER1.OUT",
|
||||
"COUNTER2.OUT",
|
||||
"COUNTER3.OUT",
|
||||
"COUNTER4.OUT",
|
||||
"COUNTER5.OUT",
|
||||
"COUNTER6.OUT",
|
||||
"COUNTER7.OUT",
|
||||
"COUNTER8.OUT",
|
||||
"FILTER1.OUT",
|
||||
"FILTER2.OUT",
|
||||
"PGEN1.OUT",
|
||||
"PGEN2.OUT",
|
||||
"FMC_IN.VAL1",
|
||||
"FMC_IN.VAL2",
|
||||
"FMC_IN.VAL3",
|
||||
"FMC_IN.VAL4",
|
||||
"FMC_IN.VAL5",
|
||||
"FMC_IN.VAL6",
|
||||
"FMC_IN.VAL7",
|
||||
"FMC_IN.VAL8",
|
||||
"SFP3_SYNC_IN.POS1",
|
||||
"SFP3_SYNC_IN.POS2",
|
||||
"SFP3_SYNC_IN.POS3",
|
||||
"SFP3_SYNC_IN.POS4",
|
||||
]
|
||||
|
||||
PANDA_AVAIL_PCAP_CAPTURE_FIELDS = ["Value", "Diff", "Sum", "Mean", "Min", "Max"]
|
||||
|
||||
|
||||
def get_pcap_capture_fields():
|
||||
out = []
|
||||
for block in PANDA_AVAIL_PCAP_BLOCKS:
|
||||
for field in PANDA_AVAIL_PCAP_CAPTURE_FIELDS:
|
||||
out.append(f"{block}.{field}")
|
||||
return out
|
||||
Reference in New Issue
Block a user