Working config again

This commit is contained in:
gac-x05la
2025-01-20 15:29:49 +01:00
parent 650fa3f4a3
commit e1c866fd30
6 changed files with 299 additions and 156 deletions

View File

@@ -49,9 +49,9 @@ femto_mean_curr:
softwareTrigger: false
es1_roty:
readoutPriority: baseline
readoutPriority: monitored
description: 'Test rotation stage'
deviceClass: tomcat_bec.devices.psimotor.EpicsMotorMR
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: X02DA-ES1-SMP1:ROTY
deviceTags:
@@ -61,59 +61,59 @@ es1_roty:
readOnly: false
softwareTrigger: false
es1_ismc:
description: 'Automation1 iSMC interface'
deviceClass: tomcat_bec.devices.aa1Controller
deviceConfig:
prefix: 'X02DA-ES1-SMP1:CTRL:'
deviceTags:
- es1
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false
# es1_ismc:
# description: 'Automation1 iSMC interface'
# deviceClass: tomcat_bec.devices.aa1Controller
# deviceConfig:
# prefix: 'X02DA-ES1-SMP1:CTRL:'
# deviceTags:
# - es1
# enabled: true
# onFailure: buffer
# readOnly: false
# readoutPriority: monitored
# softwareTrigger: false
es1_tasks:
description: 'Automation1 task management interface'
deviceClass: tomcat_bec.devices.aa1Tasks
deviceConfig:
prefix: 'X02DA-ES1-SMP1:TASK:'
deviceTags:
- es1
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false
# es1_tasks:
# description: 'Automation1 task management interface'
# deviceClass: tomcat_bec.devices.aa1Tasks
# deviceConfig:
# prefix: 'X02DA-ES1-SMP1:TASK:'
# deviceTags:
# - es1
# enabled: true
# onFailure: buffer
# readOnly: false
# readoutPriority: monitored
# softwareTrigger: false
es1_psod:
description: 'AA1 PSO output interface (trigger)'
deviceClass: tomcat_bec.devices.aa1AxisPsoDistance
deviceConfig:
prefix: 'X02DA-ES1-SMP1:ROTY:PSO:'
deviceTags:
- es1
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: true
# es1_psod:
# description: 'AA1 PSO output interface (trigger)'
# deviceClass: tomcat_bec.devices.aa1AxisPsoDistance
# deviceConfig:
# prefix: 'X02DA-ES1-SMP1:ROTY:PSO:'
# deviceTags:
# - es1
# enabled: true
# onFailure: buffer
# readOnly: false
# readoutPriority: monitored
# softwareTrigger: true
es1_ddaq:
description: 'Automation1 position recording interface'
deviceClass: tomcat_bec.devices.aa1AxisDriveDataCollection
deviceConfig:
prefix: 'X02DA-ES1-SMP1:ROTY:DDC:'
deviceTags:
- es1
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false
# es1_ddaq:
# description: 'Automation1 position recording interface'
# deviceClass: tomcat_bec.devices.aa1AxisDriveDataCollection
# deviceConfig:
# prefix: 'X02DA-ES1-SMP1:ROTY:DDC:'
# deviceTags:
# - es1
# enabled: true
# onFailure: buffer
# readOnly: false
# readoutPriority: monitored
# softwareTrigger: false
#camera:

View File

@@ -0,0 +1,186 @@
eyex:
readoutPriority: baseline
description: X-ray eye axis X
deviceClass: tomcat_bec.devices.psimotor.EpicsMotorEC
deviceConfig:
prefix: MTEST-X05LA-ES2-XRAYEYE:M1
deviceTags:
- xray-eye
onFailure: buffer
enabled: true
readOnly: false
softwareTrigger: false
# eyey:
# readoutPriority: baseline
# description: X-ray eye axis Y
# deviceClass: tomcat_bec.devices.psimotor.EpicsMotorEC
# deviceConfig:
# prefix: MTEST-X05LA-ES2-XRAYEYE:M2
# deviceTags:
# - xray-eye
# onFailure: buffer
# enabled: true
# readOnly: false
# softwareTrigger: false
# eyez:
# readoutPriority: baseline
# description: X-ray eye axis Z
# deviceClass: tomcat_bec.devices.psimotor.EpicsMotorEC
# deviceConfig:
# prefix: MTEST-X05LA-ES2-XRAYEYE:M3
# deviceTags:
# - xray-eye
# onFailure: buffer
# enabled: true
# readOnly: false
# softwareTrigger: false
femto_mean_curr:
readoutPriority: monitored
description: Femto mean current
deviceClass: ophyd.EpicsSignal
deviceConfig:
auto_monitor: true
read_pv: MTEST-X05LA-ES2-XRAYEYE:FEMTO-MEAN-CURR
deviceTags:
- xray-eye
onFailure: buffer
enabled: true
readOnly: true
softwareTrigger: false
es1_roty:
readoutPriority: baseline
description: 'Test rotation stage'
deviceClass: tomcat_bec.devices.psimotor.EpicsMotorMR
deviceConfig:
prefix: X02DA-ES1-SMP1:ROTY
deviceTags:
- es1-sam
onFailure: buffer
enabled: true
readOnly: false
softwareTrigger: false
es1_ismc:
description: 'Automation1 iSMC interface'
deviceClass: tomcat_bec.devices.aa1Controller
deviceConfig:
prefix: 'X02DA-ES1-SMP1:CTRL:'
deviceTags:
- es1
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false
es1_tasks:
description: 'Automation1 task management interface'
deviceClass: tomcat_bec.devices.aa1Tasks
deviceConfig:
prefix: 'X02DA-ES1-SMP1:TASK:'
deviceTags:
- es1
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false
es1_psod:
description: 'AA1 PSO output interface (trigger)'
deviceClass: tomcat_bec.devices.aa1AxisPsoDistance
deviceConfig:
prefix: 'X02DA-ES1-SMP1:ROTY:PSO:'
deviceTags:
- es1
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: true
es1_ddaq:
description: 'Automation1 position recording interface'
deviceClass: tomcat_bec.devices.aa1AxisDriveDataCollection
deviceConfig:
prefix: 'X02DA-ES1-SMP1:ROTY:DDC:'
deviceTags:
- es1
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false
#camera:
# description: Grashopper Camera
# deviceClass: tomcat_bec.devices.GrashopperTOMCAT
# deviceConfig:
# prefix: 'X02DA-PG-USB:'
# deviceTags:
# - camera
# enabled: true
# onFailure: buffer
# readOnly: false
# readoutPriority: monitored
# softwareTrigger: true
gfcam:
description: GigaFrost camera client
deviceClass: tomcat_bec.devices.GigaFrostCamera
deviceConfig:
prefix: 'X02DA-CAM-GF2:'
backend_url: 'http://sls-daq-001:8080'
auto_soft_enable: true
deviceTags:
- camera
- trigger
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: true
gfdaq:
description: GigaFrost stdDAQ client
deviceClass: tomcat_bec.devices.StdDaqClient
deviceConfig:
ws_url: 'ws://129.129.95.111:8080'
rest_url: 'http://129.129.95.111:5000'
deviceTags:
- std-daq
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false
daq_stream0:
description: stdDAQ preview (2 every 555)
deviceClass: tomcat_bec.devices.StdDaqPreviewDetector
deviceConfig:
url: 'tcp://129.129.95.111:20000'
deviceTags:
- std-daq
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false
daq_stream1:
description: stdDAQ preview (1 at 5 Hz)
deviceClass: tomcat_bec.devices.StdDaqPreviewDetector
deviceConfig:
url: 'tcp://129.129.95.111:20001'
deviceTags:
- std-daq
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: monitored
softwareTrigger: false

View File

@@ -256,7 +256,7 @@ class GigaFrostCamera(PSIDetectorBase):
# pylint: disable=too-many-instance-attributes
custom_prepare_cls = GigaFrostCameraMixin
USER_ACCESS = [""]
USER_ACCESS = ["initialize"]
_initialized = False
infoBusyFlag = Component(EpicsSignalRO, "BUSY_STAT", auto_monitor=True)
@@ -466,7 +466,7 @@ class GigaFrostCamera(PSIDetectorBase):
def initialize(self):
""" Initialization in separate command"""
self.custom_prepare_cls._init_gigafrost()
self.custom_prepare._init_gigafrost()
self._initialized = True
def trigger(self) -> DeviceStatus:

View File

@@ -56,10 +56,10 @@ class StdDaqMixin(CustomDeviceMixin):
if "steps" in scanargs and scanargs['steps'] is not None:
num_points *= scanargs["steps"]
points_valid = True
elif "exp_burst" in scanargs and scanargs['exp_burst'] is not None:
if "exp_burst" in scanargs and scanargs['exp_burst'] is not None:
num_points *= scanargs["exp_burst"]
points_valid = True
elif "repeats" in scanargs and scanargs['repeats'] is not None:
if "repeats" in scanargs and scanargs['repeats'] is not None:
num_points *= scanargs["repeats"]
points_valid = True
if points_valid:
@@ -67,19 +67,16 @@ class StdDaqMixin(CustomDeviceMixin):
# Perform bluesky-style configuration
if len(d) > 0:
print('Reconfiguring')
# Stop if current status is not idle
if self.parent.state() != "idle":
self.parent.blueunstage()
# Configure new run (will restart the stdDAQ)
logger.warning(f"[{self.parent.name}] Configuring with:\n{d}")
logger.warning(f"[{self.parent.name}] stdDAQ needs reconfiguring with:\n{d}")
self.parent.configure(d=d)
# Wait for REST API to kill the DAQ
sleep(0.5)
# Try to start a new run
# Try to start a new run (reconnects)
self.parent.bluestage()
# And start status monitoring
self._mon = Thread(target=self.poll, daemon=True)
self._mon = Thread(target=self.monitor, daemon=True)
self._mon.start()
def on_unstage(self):
@@ -93,7 +90,7 @@ class StdDaqMixin(CustomDeviceMixin):
"""
self.parent.blueunstage()
def poll(self) -> None:
def monitor(self) -> None:
""" Monitor status messages while connection is open. This will block the reply monitoring
to calling unstage() might throw. Status updates are sent every 1 seconds, but finishing
acquisition means StdDAQ will close connection, so there's no idle state polling.
@@ -269,8 +266,6 @@ class StdDaqClient(PSIDeviceBase):
* 4: Invert pixel values, but do not apply any linearity correction
* 5: Apply the full linearity correction
"""
print('This is d')
print(d)
if 'image_width' in d and d['image_width']!=None:
self.cfg_pixel_width.set(d['image_width']).wait()
if 'image_height' in d and d['image_height']!=None:
@@ -283,9 +278,6 @@ class StdDaqClient(PSIDeviceBase):
# Restart the DAQ if resolution changed
cfg = self.get_daq_config()
print(cfg)
print(cfg['number_of_writers'])
print(self.cfg_nr_writers.get())
if cfg['image_pixel_height'] != self.cfg_pixel_height.get() or \
cfg['image_pixel_width'] != self.cfg_pixel_width.get() or \
cfg['bit_depth'] != self.cfg_bit_depth.get() or \
@@ -293,29 +285,22 @@ class StdDaqClient(PSIDeviceBase):
# Stop if current status is not idle
status = self.state()
print(status)
if self.state() != "idle":
raise RuntimeWarning(f"[{self.name}] stdDAQ reconfiguration might corrupt files")
# Stop running acquisition
try:
self.stop()
except RuntimeError:
raise RuntimeWarning(f"[{self.name}] Told ya!")
# if self.state() != "idle":
# if status != "idle":
# self.surestop()
status = self.state()
print(status)
# Stop running acquisition
print('Before unstage')
self.unstage()
print('After unstage')
# Update retrieved config
cfg['image_pixel_height'] = int(self.cfg_pixel_height.get())
cfg['image_pixel_width'] = int(self.cfg_pixel_width.get())
cfg['bit_depth'] = int(self.cfg_bit_depth.get())
cfg['number_of_writers'] = int(self.cfg_nr_writers.get())
print(cfg)
r = self.set_daq_config(cfg)
print(r)
cfg=self.read_daq_config()
print(cfg)
def bluestage(self):
""" Stages the stdDAQ
@@ -324,34 +309,37 @@ class StdDaqClient(PSIDeviceBase):
the current configuration. It waits for the first reply and checks
it for obvious failures.
"""
# Can't stage into a running exposure
if self.state() != 'idle':
raise RuntimeError(f"[{self.name}] stdDAQ can't stage from state: {self.state()}")
file_path = self.file_path.get()
num_images = self.num_images.get()
# New connection
self.connect()
message = {"command": "start", "path": file_path, "n_image": num_images, }
reply = self.message(message)
ii = 0
while ii<5:
self.connect()
reply = self.message(message)
if reply is not None:
reply = json.loads(reply)
self.status.set(reply["status"], force=True).wait()
logger.info(f"[{self.name}] Start DAQ reply: {reply}")
if reply is not None:
reply = json.loads(reply)
self.status.set(reply["status"], force=True).wait()
logger.info(f"[{self.name}] Start DAQ reply: {reply}")
# Give it more time to reconfigure
if reply["status"] in ("rejected"):
# FIXME: running exposure is a nogo
if reply['reason'] == "driver is busy!":
raise RuntimeError(f"[{self.name}] Start stdDAQ command rejected: already running")
else:
# Give it more time to consolidate
sleep(1)
# Give it more time to reconfigure
if reply["status"] in ("rejected"):
# FIXME: running exposure is a nogo
if reply['reason'] == "driver is busy!":
raise RuntimeError(f"[{self.name}] Start stdDAQ command rejected: already running")
else:
# Success!!!
print(f"[{self.name}] Started stdDAQ on try {ii} in: {reply['status']}")
return
ii += 1
raise RuntimeError(f"[{self.name}] Failed to start the stdDAQ in 5 tries, reason: {reply['reason']}")
# Give it more time to consolidate
sleep(1)
else:
# Success!!!
print(f"[{self.name}] Started stdDAQ in: {reply['status']}")
return
raise RuntimeError(f"[{self.name}] Failed to start the stdDAQ in 1 tries, reason: {reply['reason']}")
def blueunstage(self):
""" Unstages the stdDAQ
@@ -439,11 +427,14 @@ class StdDaqClient(PSIDeviceBase):
headers = {'Content-type': 'application/json'}
)
def nuke(self):
""" Reconfigures the stdDAQ to restart the services
def nuke(self, restarttime=5):
""" Reconfigures the stdDAQ to restart the services. This causes
systemd to kill the current DAQ service and restart it with the same
configuration. Which might corrupt the currently written file...
"""
cfg = self.get_daq_config()
self.set_daq_config(cfg)
sleep(restarttime)
def state(self) -> str | None:
""" Querry the current system state"""
@@ -458,45 +449,6 @@ class StdDaqClient(PSIDeviceBase):
except ConnectionRefusedError:
raise
def surestop(self, timeout=5):
""" Stops a running acquisition
REST reconfiguration restarts with systemd and can corrupt currently written files.
"""
# Retries to steal connection from poller
for rr in range(5):
client = connect(self.ws_url.get())
msg = json.dumps({"command": "stop_all"})
client.send(msg)
reply = client.recv(timeout=1)
reply = json.loads(reply)
# logger.warning(reply)
# if r['status'] == 'success':
# break
sleep(0.5)
client = connect(self.ws_url.get())
msg = json.dumps({"command": "status"})
client.send(msg)
reply = client.recv(timeout=1)
reply = json.loads(reply)
print(reply['status'])
if reply['status'] in ['idle', 'stoped']:
logger.warning(f"[{self.name}] Stop-all command finished in {reply['status']}")
return
# If stop_all didn't stop, nuke the whole thing
logger.error(f"[{self.name}] Don't stop, make it rock!!!")
self.nuke()
sleep(timeout)
# Automatically connect to microXAS testbench if directly invoked
if __name__ == "__main__":

View File

@@ -102,6 +102,7 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
self.parent.frame.put(header['frame'], force=True)
self.parent.image_shape.put(header['shape'], force=True)
self.parent.image.put(image, force=True)
self.parent._last_image = image
self.parent._run_subs(sub_type=self.parent.SUB_MONITOR, value=image)
t_last = t_curr
logger.info(
@@ -134,7 +135,7 @@ class StdDaqPreviewDetector(PSIDetectorBase):
cam_widget = gui.add_dock('cam_dock1').add_widget('BECFigure').image('daq_stream1')
"""
# Subscriptions for plotting image
USER_ACCESS = ["kickoff"]
USER_ACCESS = ["kickoff", "get_last_image"]
SUB_MONITOR = "device_monitor_2d"
_default_sub = SUB_MONITOR
@@ -147,7 +148,8 @@ class StdDaqPreviewDetector(PSIDetectorBase):
frame = Component(Signal, kind=Kind.hinted)
image_shape = Component(Signal, kind=Kind.normal)
# FIXME: The BEC client caches the read()s from the last 50 scans
image = Component(Signal, kind=Kind.config)
image = Component(Signal, kind=Kind.omitted)
_last_image = None
def __init__(
self, *args, url: str = "tcp://129.129.95.38:20000", parent: Device = None, **kwargs
@@ -180,6 +182,9 @@ class StdDaqPreviewDetector(PSIDetectorBase):
sleep(1)
self._socket.connect(self.url.get())
def get_image(self):
return self._last_image
def kickoff(self) -> DeviceStatus:
""" The DAQ was not meant to be toggled"""
return DeviceStatus(self, done=True, success=True, settle_time=0.1)

View File

@@ -14,8 +14,8 @@
def dev_disable_all():
"""Disable all devices """
for d in dev:
d.enabled = False
for k in dev:
dev[k].enabled = False
@@ -41,12 +41,12 @@ def anotherstepscan(
--------
demostepscan(scan_start=-32, scan_end=148, steps=180, exp_time=0.005, exp_burst=5)
"""
if not bl_check_beam():
raise RuntimeError("Beamline is not in ready state")
dev.es1_tasks.enabled = False
dev.es1_psod.enabled = False
dev.es1_ddaq.enabled = True
# if not bl_check_beam():
# raise RuntimeError("Beamline is not in ready state")
dev_disable_all()
dev.es1_roty.enabled = True
#dev.es1_ddaq.enabled = True
dev.gfcam.enabled = True
dev.gfdaq.enabled = True
dev.daq_stream0.enabled = True