Getting good, now debugging daq
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user