Upgraed DDC
This commit is contained in:
@@ -38,72 +38,72 @@ femto_mean_curr:
|
||||
readOnly: true
|
||||
softwareTrigger: false
|
||||
|
||||
# es1_roty:
|
||||
# readoutPriority: monitored
|
||||
# description: 'Test rotation stage'
|
||||
# deviceClass: ophyd.EpicsMotor
|
||||
# deviceConfig:
|
||||
# prefix: X02DA-ES1-SMP1:ROTY
|
||||
# deviceTags:
|
||||
# - es1-sam
|
||||
# onFailure: buffer
|
||||
# enabled: true
|
||||
# readOnly: false
|
||||
# softwareTrigger: false
|
||||
es1_roty:
|
||||
readoutPriority: monitored
|
||||
description: 'Test rotation stage'
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
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_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: false
|
||||
# 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: false
|
||||
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:
|
||||
@@ -119,25 +119,25 @@ femto_mean_curr:
|
||||
# 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
|
||||
std_daq_live: 'tcp://129.129.95.111:20000'
|
||||
std_daq_ws: 'ws://129.129.95.111:8080'
|
||||
std_daq_rest: 'http://129.129.95.111:5000'
|
||||
deviceTags:
|
||||
- camera
|
||||
- trigger
|
||||
- gfcam
|
||||
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
|
||||
# std_daq_live: 'tcp://129.129.95.111:20000'
|
||||
# std_daq_ws: 'ws://129.129.95.111:8080'
|
||||
# std_daq_rest: 'http://129.129.95.111:5000'
|
||||
# deviceTags:
|
||||
# - camera
|
||||
# - trigger
|
||||
# - gfcam
|
||||
# enabled: true
|
||||
# onFailure: buffer
|
||||
# readOnly: false
|
||||
# readoutPriority: monitored
|
||||
# softwareTrigger: true
|
||||
|
||||
# gfdaq:
|
||||
# description: GigaFrost stdDAQ client
|
||||
|
||||
@@ -8,68 +8,17 @@ drive data collection (DDC) interface.
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
|
||||
from ophyd import Component, EpicsSignal, EpicsSignalRO, Kind
|
||||
from ophyd import Device, Component, EpicsSignal, EpicsSignalRO, Kind
|
||||
from ophyd.status import SubscriptionStatus
|
||||
|
||||
from ophyd_devices.interfaces.base_classes.psi_detector_base import PSIDetectorBase as PSIDeviceBase
|
||||
from ophyd_devices.interfaces.base_classes.psi_detector_base import (
|
||||
CustomDetectorMixin as CustomDeviceMixin,
|
||||
)
|
||||
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
|
||||
|
||||
from bec_lib import bec_logger
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class AerotechDriveDataCollectionMixin(CustomDeviceMixin):
|
||||
"""Mixin class for self-configuration and staging
|
||||
|
||||
NOTE: scripted scans start drive data collection internally
|
||||
"""
|
||||
# parent : aa1Tasks
|
||||
def on_stage(self) -> None:
|
||||
"""Configuration and staging"""
|
||||
|
||||
# Fish out configuration from scaninfo (does not need to be full configuration)
|
||||
d = {}
|
||||
if "kwargs" in self.parent.scaninfo.scan_msg.info:
|
||||
scanargs = self.parent.scaninfo.scan_msg.info["kwargs"]
|
||||
# NOTE: Scans don't have to fully configure the device
|
||||
if "ddc_trigger" in scanargs:
|
||||
d["ddc_trigger"] = scanargs["ddc_trigger"]
|
||||
if "ddc_num_points" in scanargs:
|
||||
d["num_points_total"] = scanargs["ddc_num_points"]
|
||||
else:
|
||||
# Try to figure out number of points
|
||||
num_points = 1
|
||||
points_valid = False
|
||||
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:
|
||||
num_points *= scanargs["exp_burst"]
|
||||
points_valid = True
|
||||
elif "repeats" in scanargs and scanargs['repeats'] is not None:
|
||||
num_points *= scanargs["repeats"]
|
||||
points_valid = True
|
||||
if points_valid:
|
||||
d["num_points_total"] = num_points
|
||||
|
||||
# Perform bluesky-style configuration
|
||||
if len(d) > 0:
|
||||
logger.warning(f"[{self.parent.name}] Configuring with:\n{d}")
|
||||
self.parent.configure(d=d)
|
||||
|
||||
# Stage the data collection if not in internally launced mode
|
||||
# NOTE: Scripted scans start acquiring from the scrits
|
||||
if self.parent.scaninfo.scan_type not in ("script", "scripted"):
|
||||
self.parent.bluestage()
|
||||
|
||||
def on_unstage(self):
|
||||
"""Standard bluesky unstage"""
|
||||
self.parent._switch.set("Stop", settle_time=0.2).wait()
|
||||
|
||||
|
||||
class aa1AxisDriveDataCollection(PSIDeviceBase):
|
||||
class aa1AxisDriveDataCollection(PSIDeviceBase, Device):
|
||||
"""Axis data collection
|
||||
|
||||
This class provides convenience wrappers around the Aerotech API's axis
|
||||
@@ -88,9 +37,10 @@ class aa1AxisDriveDataCollection(PSIDeviceBase):
|
||||
...
|
||||
ret = yield from ddc.collect()
|
||||
|
||||
NOTE: scripted scans start drive data collection internally
|
||||
|
||||
NOTE: Expected behavior is that the device is disabled when not in use,
|
||||
i.e. there's avtive enable/disable management.
|
||||
i.e. there's active enable/disable management.
|
||||
"""
|
||||
|
||||
# ########################################################################
|
||||
@@ -111,8 +61,31 @@ class aa1AxisDriveDataCollection(PSIDeviceBase):
|
||||
_buffer0 = Component(EpicsSignalRO, "BUFFER0", auto_monitor=True, kind=Kind.normal)
|
||||
_buffer1 = Component(EpicsSignalRO, "BUFFER1", auto_monitor=True, kind=Kind.normal)
|
||||
|
||||
custom_prepare_cls = AerotechDriveDataCollectionMixin
|
||||
USER_ACCESS = ["configure", "reset"]
|
||||
USER_ACCESS = ["configure", "reset", "arm", "disarm"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
prefix="",
|
||||
*,
|
||||
name,
|
||||
kind=None,
|
||||
read_attrs=None,
|
||||
configuration_attrs=None,
|
||||
parent=None,
|
||||
scan_info=None,
|
||||
**kwargs,
|
||||
):
|
||||
# super() will call the mixin class
|
||||
super().__init__(
|
||||
prefix=prefix,
|
||||
name=name,
|
||||
kind=kind,
|
||||
read_attrs=read_attrs,
|
||||
configuration_attrs=configuration_attrs,
|
||||
parent=parent,
|
||||
scan_info=scan_info,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def configure(self, d: dict = None) -> tuple:
|
||||
"""Configure data capture
|
||||
@@ -128,21 +101,68 @@ class aa1AxisDriveDataCollection(PSIDeviceBase):
|
||||
if "num_points_total" in d:
|
||||
self.npoints.set(d["num_points_total"]).wait()
|
||||
if "ddc_trigger" in d:
|
||||
self._trigger.set(d['ddc_trigger']).wait()
|
||||
self._trigger.set(d["ddc_trigger"]).wait()
|
||||
if "ddc_source0" in d:
|
||||
self._input0.set(d['ddc_source0']).wait()
|
||||
self._input0.set(d["ddc_source0"]).wait()
|
||||
if "ddc_source1" in d:
|
||||
self._input1.set(d['ddc_source1']).wait()
|
||||
self._input1.set(d["ddc_source1"]).wait()
|
||||
|
||||
# Reset incremental readback
|
||||
self._switch.set("ResetRB", settle_time=0.1).wait()
|
||||
new = self.read_configuration()
|
||||
return (old, new)
|
||||
|
||||
def bluestage(self) -> None:
|
||||
def on_stage(self) -> None:
|
||||
"""Configuration and staging"""
|
||||
# Fish out configuration from scaninfo (does not need to be full configuration)
|
||||
d = {}
|
||||
if "kwargs" in self.scaninfo.scan_msg.info:
|
||||
scanargs = self.scaninfo.scan_msg.info["kwargs"]
|
||||
# NOTE: Scans don't have to fully configure the device
|
||||
if "ddc_trigger" in scanargs:
|
||||
d["ddc_trigger"] = scanargs["ddc_trigger"]
|
||||
if "ddc_num_points" in scanargs:
|
||||
d["num_points_total"] = scanargs["ddc_num_points"]
|
||||
else:
|
||||
# Try to figure out number of points
|
||||
num_points = 1
|
||||
points_valid = False
|
||||
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:
|
||||
num_points *= scanargs["exp_burst"]
|
||||
points_valid = True
|
||||
elif "repeats" in scanargs and scanargs["repeats"] is not None:
|
||||
num_points *= scanargs["repeats"]
|
||||
points_valid = True
|
||||
if points_valid:
|
||||
d["num_points_total"] = num_points
|
||||
|
||||
# Perform bluesky-style configuration
|
||||
if len(d) > 0:
|
||||
logger.warning(f"[{self.name}] Configuring with:\n{d}")
|
||||
self.configure(d=d)
|
||||
|
||||
# Stage the data collection if not in internally launced mode
|
||||
# NOTE: Scripted scans start acquiring from the scrits
|
||||
if self.scaninfo.scan_type not in ("script", "scripted"):
|
||||
self.arm()
|
||||
# Reset readback
|
||||
self.reset()
|
||||
|
||||
def on_unstage(self):
|
||||
"""Standard bluesky unstage"""
|
||||
self.disarm()
|
||||
|
||||
def arm(self) -> None:
|
||||
"""Bluesky-style stage"""
|
||||
self._switch.set("Start", settle_time=0.2).wait()
|
||||
|
||||
def disarm(self):
|
||||
"""Standard bluesky unstage"""
|
||||
self._switch.set("Stop", settle_time=0.2).wait()
|
||||
|
||||
def reset(self):
|
||||
"""Reset incremental readback"""
|
||||
self._switch.set("ResetRB", settle_time=0.1).wait()
|
||||
@@ -164,20 +184,22 @@ class aa1AxisDriveDataCollection(PSIDeviceBase):
|
||||
timestamp_ = timestamp
|
||||
return result
|
||||
|
||||
status = None
|
||||
if index == 0:
|
||||
status = SubscriptionStatus(self._readstatus0, neg_edge, settle_time=0.5)
|
||||
self._readback0.set(1).wait()
|
||||
elif index == 1:
|
||||
status = SubscriptionStatus(self._readstatus1, neg_edge, settle_time=0.5)
|
||||
self._readback1.set(1).wait()
|
||||
else:
|
||||
raise RuntimeError(f"Unsupported drive data collection channel: {index}")
|
||||
|
||||
# Start asynchronous readback
|
||||
status.wait()
|
||||
return status
|
||||
|
||||
def describe_collect(self) -> OrderedDict:
|
||||
"""Describes collected array format according to JSONschema
|
||||
"""
|
||||
"""Describes collected array format according to JSONschema"""
|
||||
ret = OrderedDict()
|
||||
ret["buffer0"] = {
|
||||
"source": "internal",
|
||||
|
||||
Reference in New Issue
Block a user