Getting good, now debugging daq

This commit is contained in:
gac-x05la
2024-08-23 15:57:56 +02:00
committed by mohacsi_i
parent fa2e5c1fd0
commit 069c902be2
5 changed files with 79 additions and 49 deletions

View File

@@ -128,7 +128,7 @@ daq_stream0:
description: Standard DAQ preview stream 2 frames every 1000 image
deviceClass: tomcat_bec.devices.gigafrost.stddaq_preview.StdDaqPreview
deviceConfig:
url: 'tcp://129.129.95.38:20000'
url: 'tcp://129.129.95.38:20002'
deviceTags:
- std-daq
enabled: true
@@ -150,3 +150,17 @@ daq_stream1:
readoutPriority: monitored
softwareTrigger: false
daq_stream2:
description: Standard DAQ preview stream from first server
deviceClass: tomcat_bec.devices.gigafrost.stddaq_preview.StdDaqPreview
deviceConfig:
url: 'tcp://129.129.95.40:20001'
deviceTags:
- std-daq
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false

View File

@@ -198,8 +198,8 @@ class GigaFrostClient(PSIDetectorBase):
return old, new
def stage(self):
px_daq_h = self.daq.config.cfg_image_pixel_height.get()
px_daq_w = self.daq.config.cfg_image_pixel_width.get()
px_daq_h = self.daq.config.cfg_pixel_height.get()
px_daq_w = self.daq.config.cfg_pixel_width.get()
px_gf_w = self.cam.cfgRoiX.get()
px_gf_h = self.cam.cfgRoiY.get()

View File

@@ -43,7 +43,7 @@ class StdDaqPreview(Device):
# pylint: disable=too-many-instance-attributes
# Subscriptions for plotting image
SUB_MONITOR = "monitor"
SUB_MONITOR = "device_monitor_2d"
_default_sub = SUB_MONITOR
# Status attributes
@@ -229,7 +229,7 @@ class StdDaqPreviewDetector(PSIDetectorBase):
cam_widget = gui.add_dock('cam_dock1').add_widget('BECFigure').image('daq_stream1')
"""
# Subscriptions for plotting image
SUB_MONITOR = "monitor"
SUB_MONITOR = "device_monitor_2d"
_default_sub = SUB_MONITOR
custom_prepare_cls = StdDaqPreviewMixin

View File

@@ -10,7 +10,6 @@ from time import sleep
from ophyd import Device, Signal, Component, Kind
import requests
try:
from bec_lib import bec_logger
logger = bec_logger.logger
@@ -19,25 +18,37 @@ except ModuleNotFoundError:
logger = logging.getLogger("GfCam")
class StdDaqRestClient(Device):
"""Wrapper class around the new StdDaq REST interface.
This was meant to replace or extend the websocket inteface that replaced
the documented python client. We can finally read configuration through
standard HTTP requests, although the secondary server is not reachable
at the time.
This was meant to extend the websocket inteface that replaced the documented
python client. It is used as a part of the StdDaqClient aggregator class.
Good to know that the stdDAQ restarts all services after reconfiguration.
The standard DAQ configuration is a single JSON file locally autodeployed
to the DAQ servers (as root!!!). It can only be written through the REST API
via standard HTTP requests. The DAQ might be distributed across several servers,
we'll only interface with the primary REST interface will synchronize with
all secondary REST servers. In the past this was a source of problems.
Example:
'''
daqcfg = StdDaqRestClient(name="daqcfg", rest_url="http://xbl-daq-29:5000")
'''
"""
# pylint: disable=too-many-instance-attributes
USER_ACCESS = ["write_daq_config"]
_config_read = False
# Status attributes
rest_url = Component(Signal, kind=Kind.config)
cfg_detector_name = Component(Signal, kind=Kind.config)
cfg_detector_type = Component(Signal, kind=Kind.config)
cfg_n_modules = Component(Signal, kind=Kind.config)
cfg_bit_depth = Component(Signal, kind=Kind.config)
cfg_image_pixel_height = Component(Signal, kind=Kind.config)
cfg_image_pixel_width = Component(Signal, kind=Kind.config)
cfg_pixel_height = Component(Signal, kind=Kind.config)
cfg_pixel_width = Component(Signal, kind=Kind.config)
cfg_start_udp_port = Component(Signal, kind=Kind.config)
cfg_writer_user_id = Component(Signal, kind=Kind.config)
cfg_submodule_info = Component(Signal, kind=Kind.config)
@@ -46,8 +57,6 @@ class StdDaqRestClient(Device):
cfg_module_sync_queue_size = Component(Signal, kind=Kind.config)
cfg_module_positions = Component(Signal, kind=Kind.config)
_config_read = False
def __init__(
self, *args, rest_url: str = "http://localhost:5000", parent: Device = None, **kwargs
) -> None:
@@ -58,7 +67,7 @@ class StdDaqRestClient(Device):
# Connect ro the DAQ and initialize values
self.read_daq_config()
def read_daq_config(self):
def read_daq_config(self) -> dict:
"""Read the current configuration from the JSON file
"""
r = requests.get(
@@ -75,8 +84,8 @@ class StdDaqRestClient(Device):
self.cfg_n_modules.set(cfg['n_modules']).wait()
self.cfg_bit_depth.set(cfg['bit_depth']).wait()
self.cfg_image_pixel_height.set(cfg['image_pixel_height']).wait()
self.cfg_image_pixel_width.set(cfg['image_pixel_width']).wait()
self.cfg_pixel_height.set(cfg['image_pixel_height']).wait()
self.cfg_pixel_width.set(cfg['image_pixel_width']).wait()
self.cfg_start_udp_port.set(cfg['start_udp_port']).wait()
self.cfg_writer_user_id.set(cfg['writer_user_id']).wait()
#self.cfg_submodule_info.set(cfg['submodule_info']).wait()
@@ -88,14 +97,14 @@ class StdDaqRestClient(Device):
self._config_read = True
return r
def _build_config(self):
def _build_config(self) -> dict:
config = {
'detector_name': str(self.cfg_detector_name.get()),
'detector_type': str(self.cfg_detector_type.get()),
'n_modules': int(self.cfg_n_modules.get()),
'bit_depth': int(self.cfg_bit_depth.get()),
'image_pixel_height': int(self.cfg_image_pixel_height.get()),
'image_pixel_width': int(self.cfg_image_pixel_width.get()),
'image_pixel_height': int(self.cfg_pixel_height.get()),
'image_pixel_width': int(self.cfg_pixel_width.get()),
'start_udp_port': int(self.cfg_start_udp_port.get()),
'writer_user_id': int(self.cfg_writer_user_id.get()),
'log_level': "debug",
@@ -139,6 +148,7 @@ class StdDaqRestClient(Device):
pixel_height : int, optional
Image size in the y-direction [pixels] (default = 2016)
"""
# Reads the current config
old = self.read_configuration()
# If Bluesky style configure
@@ -150,13 +160,14 @@ class StdDaqRestClient(Device):
pixel_width = d.get('image_width', pixel_width)
pixel_height = d.get('image_height', pixel_height)
self.cfg_image_pixel_height.set(pixel_height).wait()
self.cfg_image_pixel_width.set(pixel_width).wait()
if self.cfg_pixel_height.get()!=pixel_height or self.cfg_pixel_width.get() != pixel_width:
self.cfg_pixel_height.set(pixel_height).wait()
self.cfg_pixel_width.set(pixel_width).wait()
self.write_daq_config()
logger.info(f"[{self.name}] Reconfigured the StdDAQ")
# No feedback on restart, we just sleep
sleep(3)
self.write_daq_config()
logger.info(f"[{self.name}] Reconfigured the StdDAQ")
# No feedback on restart, we just sleep
sleep(3)
new = self.read_configuration()
return old, new
@@ -175,14 +186,12 @@ class StdDaqRestClient(Device):
self.read_daq_config()
return super().stage()
def unstage(self):
"""Unstage op: Read the current configuration from the DAQ
"""
self.read_daq_config()
return super().unstage()
def stop(self, success=False):
"""Stop op: Read the current configuration from the DAQ
"""

View File

@@ -19,25 +19,28 @@ except ModuleNotFoundError:
from tomcat_bec.devices.gigafrost.stddaq_rest import StdDaqRestClient
class StdDaqClient(Device):
"""StdDaq API
This class combines the new websocket and REST interfaces that were meant
to replace the documented python client. The websocket interface starts
and stops the acquisition and provides status, while the REST interface
can read and write the configuration.
This class combines the new websocket and REST interfaces of the stdDAQ that
were meant to replace the documented python client. The websocket interface
starts and stops the acquisition and provides status, while the REST
interface can read and write the configuration. The DAQ needs to restart
all services to reconfigure with a new config.
The websocket provides status updates about a running acquisition but the
interface breaks connection at the end of the run.
The standard DAQ configuration is a single JSON file locally autodeployed
to the DAQ servers (as root!!!). It can only be written through a primary
REST API that is semi-supported, as there's no frontend group. The DAQ
might be distributed across several servers, meaning that the primary REST
interface will try to synchronize with secondary REST servers, but this
might fail, yielding a flawed configuration.
daq = StdDaqWsClient(name="daq", ws_url="ws://xbl-daq-29:8080", rest_url="http://xbl-daq-29:5000")
to the DAQ servers (as root!!!). It can only be written through a REST API
that is semi-supported. The DAQ might be distributed across several servers,
we'll only interface with the primary REST interface will synchronize with
all secondary REST servers. In the past this was a source of problems.
Example:
'''
daq = StdDaqClient(name="daq", ws_url="ws://xbl-daq-29:8080", rest_url="http://xbl-daq-29:5000")
'''
"""
# pylint: disable=too-many-instance-attributes
@@ -45,7 +48,7 @@ class StdDaqClient(Device):
status = Component(Signal, value="unknown", kind=Kind.normal)
n_total = Component(Signal, value=10000, kind=Kind.config)
file_path = Component(Signal, value="/gpfs/test/test-beamline", kind=Kind.config)
# Configuration
config = Component(StdDaqRestClient, kind=Kind.config)
def __init__(
@@ -70,8 +73,8 @@ class StdDaqClient(Device):
def connect(self):
"""Connect to te StDAQs websockets interface
StdDAQ may reject connection for a few seconds, so if it fails, wait
a bit and try to connect again.
StdDAQ may reject connection for a few seconds after restart,
so if it fails, wait a bit and try to connect again.
"""
num_retry = 0
while num_retry < 5:
@@ -113,7 +116,6 @@ class StdDaqClient(Device):
backend speed). (default = 10000)
file_path : string, optional
Save file path. (default = '/gpfs/test/test-beamline')
"""
old_config = self.read_configuration()
@@ -157,7 +159,6 @@ class StdDaqClient(Device):
self._mon = Thread(target=self.poll, daemon=True)
self._mon.start()
sleep(3)
return super().stage()
def unstage(self):
@@ -208,9 +209,13 @@ class StdDaqClient(Device):
return reply
def poll(self):
"""Monitor status messages until connection is open"""
"""Monitor status messages until connection is open
This will block the reply monitoring to calling unstage() might throw.
Status updates are sent every 1 seconds
"""
try:
sleep(0.1)
sleep(1.2)
for msg in self._client:
try:
message = json.loads(msg)
@@ -220,6 +225,8 @@ class StdDaqClient(Device):
except Exception as ex:
print(ex)
return
except (ConnectionClosedError, ConnectionClosedOK):
return
finally:
self._mon = None