DAq commissioning
This commit is contained in:
@@ -9,7 +9,7 @@ Created on Thu Jun 27 17:28:43 2024
|
||||
import json
|
||||
from time import sleep
|
||||
from threading import Thread
|
||||
from ophyd import Device, Signal, Component, Kind, DeviceStatus
|
||||
from ophyd import Device, Signal, Component, Kind, DeviceStatus, Staged
|
||||
from websockets.sync.client import connect
|
||||
from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError
|
||||
|
||||
@@ -74,6 +74,10 @@ class StdDaqClient(Device):
|
||||
self._client = None
|
||||
self.connect()
|
||||
|
||||
def __del__(self) -> None:
|
||||
self._client.close()
|
||||
return super().__del__()
|
||||
|
||||
def connect(self):
|
||||
"""Connect to the StdDAQ's websockets interface
|
||||
|
||||
@@ -130,13 +134,34 @@ class StdDaqClient(Device):
|
||||
self.output_file.set(str(d['file_path']))
|
||||
# Configure DAQ
|
||||
if 'pixel_width' in d or 'pixel_height' in d:
|
||||
self.stop()
|
||||
sleep(1)
|
||||
# Safe stop before configure (see 'reset')
|
||||
self.reset()
|
||||
self.config.configure(d)
|
||||
|
||||
new_config = self.read_configuration()
|
||||
return (old_config, new_config)
|
||||
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
|
||||
The current stdDAQ refuses connection if another session is running. This is safety so
|
||||
we don't accidentally kill a running exposure. But this also means that we have to wait
|
||||
until a dead session dies of timeout.
|
||||
|
||||
NOTE: REST reconfiguration restarts with systemd and can corrupt currently written files.
|
||||
"""
|
||||
try:
|
||||
if self._client is not None:
|
||||
self._client.close()
|
||||
self._client = connect(self._ws_url)
|
||||
msg = json.dumps({"command": "stop"})
|
||||
self._client.send(msg)
|
||||
except (ConnectionClosedError, ConnectionClosedOK, ConnectionRefusedError):
|
||||
pass
|
||||
self._staged = Staged.no
|
||||
sleep(1)
|
||||
|
||||
def stage(self) -> list:
|
||||
"""Start a new run with the standard DAQ
|
||||
|
||||
@@ -145,7 +170,6 @@ class StdDaqClient(Device):
|
||||
not, we can't query if not running.
|
||||
"""
|
||||
if self._staged:
|
||||
self.unstage()
|
||||
self._client.close()
|
||||
|
||||
file_path = self.file_path.get()
|
||||
@@ -188,6 +212,7 @@ class StdDaqClient(Device):
|
||||
self.message(message, wait_reply=False)
|
||||
except RuntimeError:
|
||||
pass
|
||||
self._client.close()
|
||||
return super().unstage()
|
||||
|
||||
def kickoff(self) -> DeviceStatus:
|
||||
|
||||
@@ -38,7 +38,7 @@ class StdDaqRestClient(Device):
|
||||
"""
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
|
||||
USER_ACCESS = ["write_daq_config"]
|
||||
USER_ACCESS = ["set_daq_config", "get_daq_config", "reset"]
|
||||
|
||||
# Status attributes
|
||||
rest_url = Component(Signal, kind=Kind.config)
|
||||
@@ -74,14 +74,15 @@ class StdDaqRestClient(Device):
|
||||
"""
|
||||
r = requests.get(
|
||||
self.rest_url.get() + '/api/config/get',
|
||||
params={'config_file': "/etc/std_daq/configs/gf1.json", 'user': "ioc"},
|
||||
params={'user': "ioc"},
|
||||
# params={'config_file': "/etc/std_daq/configs/gf.json", 'user': "ioc"},
|
||||
timeout=2
|
||||
)
|
||||
if r.status_code != 200:
|
||||
raise ConnectionError(f"[{self.name}] Error {r.status_code}:\t{r.text}")
|
||||
return r.json()
|
||||
|
||||
def read_daq_config(self) -> None:
|
||||
def read_daq_config(self) -> dict:
|
||||
"""Extract the current configuration from the JSON file
|
||||
"""
|
||||
cfg = self.get_daq_config()
|
||||
@@ -122,13 +123,10 @@ class StdDaqRestClient(Device):
|
||||
config = orig.update(config)
|
||||
return config
|
||||
|
||||
def write_daq_config(self):
|
||||
def set_daq_config(self, config):
|
||||
"""Write configuration ased on current PV values. Some fields might be
|
||||
unchangeable.
|
||||
"""
|
||||
orig = self.get_daq_config()
|
||||
config = self._build_config(orig)
|
||||
|
||||
params = {"user": "ioc"}
|
||||
r = requests.post(
|
||||
self.rest_url.get() + '/api/config/set',
|
||||
@@ -139,7 +137,15 @@ class StdDaqRestClient(Device):
|
||||
)
|
||||
if r.status_code != 200:
|
||||
raise ConnectionError(f"[{self.name}] Error {r.status_code}:\t{r.text}")
|
||||
return r
|
||||
return r.json()
|
||||
|
||||
def write_daq_config(self):
|
||||
"""Write configuration ased on current PV values. Some fields might be
|
||||
unchangeable.
|
||||
"""
|
||||
orig = self.get_daq_config()
|
||||
config = self._build_config(orig)
|
||||
return self.set_daq_config(config)
|
||||
|
||||
def configure(self, d: dict = None):
|
||||
"""Configure the next scan with the GigaFRoST camera
|
||||
@@ -179,6 +185,11 @@ class StdDaqRestClient(Device):
|
||||
new = self.read_configuration()
|
||||
return old, new
|
||||
|
||||
def reset(self):
|
||||
""" Reconfigures the stdDAQ to restart the services"""
|
||||
cfg = self.get_daq_config()
|
||||
self.set_daq_config(cfg)
|
||||
|
||||
def read(self):
|
||||
self.read_daq_config()
|
||||
return super().read()
|
||||
|
||||
@@ -7,6 +7,8 @@ from bec_server.scan_server.scans import Acquire, AsyncFlyScanBase
|
||||
|
||||
class AcquireDark(Acquire):
|
||||
scan_name = "acquire_dark"
|
||||
required_kwargs = ["num"]
|
||||
gui_config = {"Acquisition parameters": ["num"]}
|
||||
|
||||
def __init__(self, num: int, **kwargs):
|
||||
"""
|
||||
@@ -35,6 +37,8 @@ class AcquireDark(Acquire):
|
||||
|
||||
class AcquireFlat(Acquire):
|
||||
scan_name = "acquire_flat"
|
||||
required_kwargs = ["num"]
|
||||
gui_config = {"Acquisition parameters": ["num"]}
|
||||
|
||||
def __init__(self, num: int, out_position: float, **kwargs):
|
||||
"""
|
||||
@@ -69,6 +73,8 @@ class AcquireFlat(Acquire):
|
||||
|
||||
class TutorialFlyScanContLine(AsyncFlyScanBase):
|
||||
scan_name = "tutorial_cont_line_fly_scan"
|
||||
required_kwargs = ["motor"]
|
||||
gui_config = {"Acquisition parameters": ["motor"]}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user