refactor!: moved to new ophyd_devices repo structure

BREAKING CHANGE: cleaned up and migrated to the new repo structure. Only shared devices will be hosted in ophyd_devices. Everything else will be in the beamline-specific repositories
This commit is contained in:
wakonig_k 2024-05-08 11:37:51 +02:00
parent be689baa29
commit 3415ae2007
38 changed files with 119 additions and 4434 deletions

View File

@ -138,7 +138,7 @@ pytest:
config_test:
stage: test
script:
- ophyd_test --config ./ophyd_devices/epics/db/ --output ./config_tests
- ophyd_test --config ./ophyd_devices/configs/ --output ./config_tests
artifacts:
paths:
- ./config_tests

View File

@ -2,7 +2,7 @@ from .ophyd_patch import monkey_patch_ophyd
monkey_patch_ophyd()
from .epics import *
from .devices.sls_devices import SLSInfo, SLSOperatorMessages
from .sim.sim import SimCamera
from .sim.sim import SimFlyer
from .sim.sim import SimFlyer as SynFlyer
@ -15,7 +15,6 @@ from .sim.sim import SimWaveform, SynDeviceOPAAS
from .sim.sim_frameworks import DeviceProxy, H5ImageReplayProxy, SlitProxy
from .sim.sim_signals import ReadOnlySignal
from .sim.sim_signals import ReadOnlySignal as SynSignalRO
from .sls_devices.sls_devices import SLSInfo, SLSOperatorMessages
from .utils.bec_device_base import BECDeviceBase
from .utils.dynamic_pseudo import ComputedSignal
from .utils.static_device_test import launch

View File

@ -0,0 +1,91 @@
eiger:
readoutPriority: monitored
deviceClass: ophyd_devices.SimCamera
deviceConfig:
device_access: true
deviceTags:
- detector
enabled: true
readOnly: false
softwareTrigger: true
dyn_signals:
readoutPriority: baseline
deviceClass: ophyd_devices.sim.sim.SynDynamicComponents
deviceConfig:
enabled: true
readOnly: false
pseudo_signal1:
deviceClass: ophyd_devices.ComputedSignal
deviceConfig:
compute_method: "def compute_signals(signal1, signal2):\n return signal1.get()*signal2.get()\n"
input_signals:
- "bpm4i_readback"
- "bpm5i_readback"
enabled: true
readOnly: false
readoutPriority: baseline
hexapod:
readoutPriority: baseline
deviceClass: ophyd_devices.SynDeviceOPAAS
deviceConfig:
deviceTags:
- user motors
enabled: true
readOnly: false
eyefoc:
readoutPriority: baseline
deviceClass: ophyd_devices.SimPositioner
deviceConfig:
delay: 1
limits:
- -50
- 50
tolerance: 0.01
update_frequency: 400
deviceTags:
- user motors
enabled: true
readOnly: false
flyer_sim:
readoutPriority: on_request
deviceClass: ophyd_devices.SynFlyer
deviceConfig:
delay: 1
device_access: true
update_frequency: 400
deviceTags:
- flyer
enabled: true
readOnly: false
bpm4i:
readoutPriority: monitored
deviceClass: ophyd_devices.SimMonitor
deviceConfig:
deviceTags:
- beamline
enabled: true
readOnly: false
bpm5i:
readoutPriority: monitored
deviceClass: ophyd_devices.SimMonitor
deviceConfig:
deviceTags:
- beamline
enabled: true
readOnly: false
ring_current_sim:
readoutPriority: monitored
deviceClass: ophyd_devices.ReadOnlySignal
deviceConfig:
deviceTags:
- beamline
enabled: true
readOnly: false

View File

@ -0,0 +1,19 @@
sls_info:
readoutPriority: on_request
description: 'sls info'
deviceClass: ophyd_devices.SLSInfo
deviceConfig: {}
onFailure: buffer
enabled: true
readOnly: false
softwareTrigger: false
sls_operator:
readoutPriority: on_request
description: 'sls operator messages'
deviceClass: ophyd_devices.SLSOperatorMessages
deviceConfig: {}
onFailure: buffer
enabled: true
readOnly: false
softwareTrigger: false

View File

@ -1,10 +1,11 @@
# Standard ophyd classes
from ophyd import EpicsMotor, EpicsSignal, EpicsSignalRO
from ophyd.quadem import QuadEM
from ophyd.sim import SynAxis, SynPeriodicSignal, SynSignal
from .devices.slits import SlitH, SlitV
from .devices.specMotors import (
from .epics_motor_ex import EpicsMotorEx
from .slits import SlitH, SlitV
from .sls_devices import SLSInfo, SLSOperatorMessages
from .specMotors import (
Bpm4i,
EnergyKev,
GirderMotorPITCH,
@ -17,8 +18,4 @@ from .devices.specMotors import (
PmDetectorRotation,
PmMonoBender,
)
from .devices.SpmBase import SpmBase
# X07MA specific devices
from .devices.X07MADevices import *
from .devices.XbpmBase import XbpmBase, XbpmCsaxsOp
from .SpmBase import SpmBase

View File

@ -1,66 +0,0 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Oct 13 17:06:51 2021
@author: mohacsi_i
"""
import os
import yaml
from devices import *
from ophyd.ophydobj import OphydObject
# ####################################################
# Test connection to beamline devices
# ####################################################
# Current file path
path = os.path.dirname(os.path.abspath(__file__))
# Load simulated device database
fp = open(f"{path}/db/test_database.yml", "r")
lut_db = yaml.load(fp, Loader=yaml.Loader)
# Load beamline specific database
bl = os.getenv("BEAMLINE_XNAME", "TESTENV")
if bl != "TESTENV":
fp = open(f"{path}/db/{bl.lower()}_database.yml", "r")
lut_db.update(yaml.load(fp, Loader=yaml.Loader))
def createProxy(name: str, connect=True) -> OphydObject:
"""Create an ophyd device from its alias
Factory routine that uses the beamline database to instantiate
ophyd devices from their alias and pre-defined configuration.
Does nothing if the device is already an OphydObject!
"""
if issubclass(type(name), OphydObject):
return name
entry = lut_db[name]
# Yeah, using global namespace
cls_candidate = globals()[entry["type"]]
# print(f"Class candidate: {cls_candidate}")
if issubclass(cls_candidate, OphydObject):
ret = cls_candidate(**entry["config"])
if connect:
ret.wait_for_connection(timeout=5)
return ret
else:
raise RuntimeError(f"Unsupported return class: {entry['type']}")
if __name__ == "__main__":
num_errors = 0
for key in lut_db:
try:
dut = createProxy(str(key))
print(f"{key}\t: {type(dut)}\t{dut.read()}")
# print(f"{key}\t: {type(dut)}")
except Exception as ex:
num_errors += 1
print(key)
print(ex)
print(f"\nTotal number of errors: {num_errors}")

View File

@ -1,56 +0,0 @@
es1_roty:
description: 'Test rotation stage'
# deviceClass: EpicsMotor
deviceClass: ophyd_devices.epics.devices.EpicsMotorX
deviceConfig: {prefix: 'X02DA-ES1-SMP1:ROTY'}
onFailure: buffer
enabled: true
readoutPriority: monitored
es1_aa1:
description: 'Rotation stage controller status'
deviceClass: ophyd_devices.epics.devices.aa1Controller
deviceConfig: {prefix: 'X02DA-ES1-SMP1:CTRL:'}
onFailure: buffer
enabled: true
readoutPriority: monitored
es1_aa1Tasks:
description: 'AA1 task management interface'
deviceClass: ophyd_devices.epics.devices.aa1Tasks
deviceConfig: {prefix: 'X02DA-ES1-SMP1:TASK:'}
onFailure: buffer
enabled: true
readoutPriority: monitored
es1_aa1GlobalVar:
description: 'AA1 global variables interface'
deviceClass: ophyd_devices.epics.devices.aa1GlobalVariables
deviceConfig: {prefix: 'X02DA-ES1-SMP1:VAR:'}
onFailure: buffer
enabled: true
readoutPriority: monitored
es1_aa1GlobalMon:
description: 'AA1 polled global variable interface'
deviceClass: ophyd_devices.epics.devices.aa1GlobalVariableBindings
deviceConfig: {prefix: 'X02DA-ES1-SMP1:VAR:'}
onFailure: buffer
enabled: true
readoutPriority: monitored
es1_psod:
description: 'AA1 PSO output interface'
deviceClass: ophyd_devices.epics.devices.aa1AxisPsoDistance
deviceConfig: {prefix: 'X02DA-ES1-SMP1:ROTY:PSO:'}
onFailure: buffer
enabled: true
readoutPriority: monitored
es1_ddaq:
description: 'AA1 drive data collection interface'
deviceClass: ophyd_devices.epics.devices.aa1AxisDriveDataCollection
deviceConfig: {prefix: 'X02DA-ES1-SMP1:ROTY:DDC:'}
onFailure: buffer
enabled: true
readoutPriority: monitored

View File

@ -1,274 +0,0 @@
slsinfo:
readoutPriority: baseline
description: 'SLS beam info'
deviceClass: ophyd_devices.SLSInfo
deviceConfig: {}
onFailure: buffer
enabled: true
readOnly: false
softwareTrigger: false
undulator:
readoutPriority: baseline
description: 'Undulator'
deviceClass: ophyd_devices.X07MAUndulator
deviceConfig:
prefix: 'X07MA-ID:'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
aperture:
readoutPriority: baseline
description: 'Frontend aperture'
deviceClass: ophyd.EpicsSignal
deviceConfig:
read_pv: 'X07MA-FE-DSAPER'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
mono:
readoutPriority: baseline
description: 'PGM Monochromator'
deviceClass: ophyd_devices.PGMMonochromator
deviceConfig:
prefix: 'X07MA-'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
otf:
readoutPriority: baseline
description: 'PGM on-the-fly scan'
deviceClass: ophyd_devices.PGMOtFScan
deviceConfig: {}
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
valve:
readoutPriority: baseline
description: 'Endstation valve'
deviceClass: ophyd_devices.VacuumValve
deviceConfig:
prefix: 'X07MA-OP-VG13:'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
exit_slit:
readoutPriority: baseline
description: 'Exit slit'
deviceClass: ophyd_devices.X07MAExitSlit
deviceConfig:
prefix: 'X07MA-OP-SL1SV1:'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
goldmesh1:
readoutPriority: baseline
description: 'Gold mesh 1'
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X07MA-OP-IO1:TR1'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
goldmesh2:
readoutPriority: baseline
description: 'Gold mesh 2'
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X07MA-OP-IO2:TR1'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
field_x:
readoutPriority: baseline
description: 'Magnetic field x'
deviceClass: ophyd_devices.X07MAMagnetAxis
deviceConfig:
axis_id: X
ps_prefix: "X07MA-PC-PS2:"
prefix: 'X07MA-PC-MAG:'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
field_z:
readoutPriority: baseline
description: 'Magnetic field z'
deviceClass: ophyd_devices.X07MAMagnetAxis
deviceConfig:
axis_id: Z
ps_prefix: "X07MA-PC-PS1:"
prefix: 'X07MA-PC-MAG:'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
signals:
readoutPriority: baseline
description: 'ADC signals'
deviceClass: ophyd_devices.X07MAAnalogSignals
deviceConfig:
prefix: 'X07MA-ES1-AI:'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
sample_hor:
readoutPriority: baseline
description: 'Horizontal sample position'
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X07MA-ES1-MAG:TRZS'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
sample_vert:
readoutPriority: baseline
description: 'Horizontal sample position'
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X07MA-ES1-MAG:TRY1'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
sample_rot:
readoutPriority: baseline
description: 'Horizontal sample position'
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: 'X07MA-ES1-MAG:ROY1'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
harmonic:
readoutPriority: baseline
description: 'ID harmonic'
deviceClass: ophyd.EpicsSignal
deviceConfig:
read_pv: 'X07MA-ID:HARMONIC'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
energy:
readoutPriority: baseline
description: 'Energy in eV'
deviceClass: ophyd.EpicsSignal
deviceConfig:
read_pv: 'X07MA-PHS-E:GO.A'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
energy_mode:
readoutPriority: baseline
description: 'Energy mode. Either PGM = 0 or PGM+ID = 1'
deviceClass: ophyd.EpicsSignal
deviceConfig:
read_pv: 'X07MA-PHS-E:OPT'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
keithley_1:
readoutPriority: baseline
description: 'Keithley 1 / 428 tey'
deviceClass: ophyd.EpicsSignal
deviceConfig:
read_pv: 'X07MA-PC-K428:1:setGain'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
keithley_2:
readoutPriority: baseline
description: 'Keithley 2 / 428 i0'
deviceClass: ophyd.EpicsSignal
deviceConfig:
read_pv: 'X07MA-PC-K428:2:setGain'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
keithley_3:
readoutPriority: baseline
description: 'Keithley 3 / 428 diode'
deviceClass: ophyd.EpicsSignal
deviceConfig:
read_pv: 'X07MA-PC-K428:3:setGain'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
temperature:
readoutPriority: baseline
description: 'Temperature controller'
deviceClass: ophyd_devices.X07MATemperatureController
deviceConfig:
prefix: 'X07MA-PC-TC:'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
tcontrol:
readoutPriority: baseline
description: 'Automatic temperature control'
deviceClass: ophyd_devices.X07MAAutoTemperatureControl
deviceConfig:
prefix: 'X07MA-ES1-TEMP:'
onFailure: retry
enabled: true
readOnly: false
softwareTrigger: false
sls_info:
readoutPriority: on_request
description: 'sls info'
deviceClass: ophyd_devices.SLSInfo
deviceConfig: {}
onFailure: buffer
enabled: true
readOnly: false
softwareTrigger: false
sls_operator:
readoutPriority: on_request
description: 'sls operator messages'
deviceClass: ophyd_devices.SLSOperatorMessages
deviceConfig: {}
onFailure: buffer
enabled: true
readOnly: false
softwareTrigger: false

View File

@ -1,410 +0,0 @@
"""
ophyd device classes for X07MA beamline
"""
import time
import traceback
from collections import OrderedDict
from typing import Any
from bec_lib import bec_logger
from ophyd import Component as Cpt
from ophyd import Device, EpicsMotor, EpicsSignal, EpicsSignalRO
from ophyd import FormattedComponent as FCpt
from ophyd import Kind, PVPositioner, Signal
from ophyd.flyers import FlyerInterface
from ophyd.pv_positioner import PVPositionerComparator
from ophyd.status import DeviceStatus, SubscriptionStatus
logger = bec_logger.logger
__all__ = [
"X07MAUndulator",
"PGMMonochromator",
"PGMOtFScan",
"VacuumValve",
"X07MAExitSlit",
"X07MAMagnetAxis",
"X07MAAnalogSignals",
"X07MASampleManipulator",
"X07MATemperatureController",
"X07MAAutoTemperatureControl",
]
class X07MAUndulator(PVPositioner):
"""
X07MA undulator
"""
setpoint = Cpt(EpicsSignal, "ENERGY", auto_monitor=True)
readback = Cpt(EpicsSignalRO, "ENERGY-READ", kind=Kind.hinted, auto_monitor=True)
done = Cpt(EpicsSignalRO, "DONE", kind=Kind.omitted, auto_monitor=True)
stop_signal = Cpt(EpicsSignal, "STOP", kind=Kind.omitted)
energy_offset = Cpt(EpicsSignal, "ENERGY-OFFS", kind=Kind.config)
pol_mode = Cpt(EpicsSignal, "MODE")
pol_angle = Cpt(EpicsSignal, "ALPHA")
harmonic = Cpt(EpicsSignal, "HARMONIC")
def __init__(
self,
prefix="",
*,
limits=None,
name=None,
read_attrs=None,
configuration_attrs=None,
parent=None,
egu="",
**kwargs,
):
super().__init__(
prefix,
limits=limits,
name=name,
read_attrs=read_attrs,
configuration_attrs=configuration_attrs,
parent=parent,
egu=egu,
**kwargs,
)
self.readback.name = self.name
class PGMMonochromator(PVPositioner):
"""
PGM monochromator
"""
setpoint = Cpt(EpicsSignal, "PHS-E:GO.A", auto_monitor=True)
readback = Cpt(EpicsSignalRO, "PGM:CERBK", kind=Kind.hinted, auto_monitor=True)
done = Cpt(EpicsSignalRO, "PHS:alldone", kind=Kind.omitted, auto_monitor=True)
stop_signal = Cpt(EpicsSignal, "PGM:stop", kind=Kind.omitted)
cff = Cpt(EpicsSignal, "PGM:rbkcff", write_pv="PGM:cff.A", kind=Kind.config)
with_undulator = Cpt(EpicsSignal, "PHS-E:OPT", kind=Kind.config)
def __init__(
self,
prefix="",
*,
limits=None,
name=None,
read_attrs=None,
configuration_attrs=None,
parent=None,
egu="",
**kwargs,
):
super().__init__(
prefix,
limits=limits,
name=name,
read_attrs=read_attrs,
configuration_attrs=configuration_attrs,
parent=parent,
egu=egu,
**kwargs,
)
self.readback.name = self.name
class PGMOtFScan(FlyerInterface, Device):
"""
PGM on-the-fly scan
"""
SUB_VALUE = "value"
SUB_FLYER = "flyer"
_default_sub = SUB_VALUE
e1 = Cpt(EpicsSignal, "E1", kind=Kind.config)
e2 = Cpt(EpicsSignal, "E2", kind=Kind.config)
time = Cpt(EpicsSignal, "TIME", kind=Kind.config)
folder = Cpt(EpicsSignal, "FOLDER", kind=Kind.config)
file = Cpt(EpicsSignal, "FILE", kind=Kind.config)
acquire = Cpt(EpicsSignal, "START", auto_monitor=True)
edata = Cpt(EpicsSignalRO, "EDATA", kind=Kind.hinted, auto_monitor=True)
data = Cpt(EpicsSignalRO, "DATA", kind=Kind.hinted, auto_monitor=True)
idata = Cpt(EpicsSignalRO, "IDATA", kind=Kind.hinted, auto_monitor=True)
fdata = Cpt(EpicsSignalRO, "FDATA", kind=Kind.hinted, auto_monitor=True)
count = Cpt(EpicsSignalRO, "COUNT", kind=Kind.omitted, auto_monitor=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._start_time = 0
self.acquire.subscribe(self._update_status, run=False)
self.count.subscribe(self._update_data, run=False)
def kickoff(self):
self._start_time = time.time()
self.acquire.put(1, use_complete=True)
status = DeviceStatus(self)
status.set_finished()
return status
def complete(self):
def check_value(*, old_value, value, **kwargs):
return old_value == 1 and value == 0
status = SubscriptionStatus(self.acquire, check_value, event_type=self.acquire.SUB_VALUE)
return status
def collect(self):
data = {"time": self._start_time, "data": {}, "timestamps": {}}
for attr in ("edata", "data", "idata", "fdata"):
obj = getattr(self, attr)
data["data"][obj.name] = obj.get()
data["timestamps"][obj.name] = obj.timestamp
return data
def describe_collect(self):
desc = OrderedDict()
for attr in ("edata", "data", "idata", "fdata"):
desc.update(getattr(self, attr).describe())
return desc
def _update_status(self, *, old_value, value, **kwargs):
if old_value == 1 and value == 0:
self._update_data(100) # make sure that the last entries are also emitted
self._done_acquiring()
def _update_data(self, value, **kwargs):
try:
if value == 0:
return
data = self.collect()
# FIXME: to avoid emitting outdated / stale data, wait until all signals report > 10 entries
if any(len(val) < 10 for val in data["data"].values()) or value < 10:
return
self._run_subs(sub_type=self.SUB_FLYER, value=data)
except Exception as exc:
content = traceback.format_exc()
logger.error(content)
class VacuumValve(PVPositionerComparator):
"""
EPS vacuum valve.
The setpoint is of 2 choices
0 - Close
1 - Try open
The readback is of 8 choices
0 - TO CONNECT
1 - MAN OPEN
2 - CLOSED
3 - ERROR
4 - MOVING
5 - OPEN
6 - ERROR
7 - ERROR
"""
setpoint = Cpt(EpicsSignal, "WT_SET")
readback = Cpt(EpicsSignalRO, "POSITION")
def __init__(self, prefix: str, *, name: str, **kwargs):
kwargs.update({"limits": (0, 1)})
super().__init__(prefix, name=name, **kwargs)
self.readback.name = self.name
def done_comparator(self, readback: Any, setpoint: Any) -> bool:
return readback != 4
class X07MAExitSlit(PVPositioner):
"""
Exit slit
"""
setpoint = Cpt(EpicsSignal, "TR_AP")
readback = Cpt(EpicsSignalRO, "TR_ISAP", kind=Kind.hinted, auto_monitor=True)
done = Cpt(EpicsSignalRO, "TR.DMOV", kind=Kind.omitted, auto_monitor=True)
def __init__(
self,
prefix="",
*,
limits=None,
name=None,
read_attrs=None,
configuration_attrs=None,
parent=None,
egu="",
**kwargs,
):
super().__init__(
prefix,
limits=limits,
name=name,
read_attrs=read_attrs,
configuration_attrs=configuration_attrs,
parent=parent,
egu=egu,
**kwargs,
)
self.readback.name = self.name
# class X07MAMagnet(Device):
# """
# Magnet fields.
# """
class X07MAMagnetAxis(PVPositioner):
"""
A single magnet field axis.
"""
done_value = 1
actuate_value = 1
setpoint = FCpt(EpicsSignal, "{prefix}{_axis_id}:DMD")
readback = FCpt(EpicsSignalRO, "{prefix}{_axis_id}:RBV", kind=Kind.hinted, auto_monitor=True)
actuate = Cpt(EpicsSignal, "STARTRAMP.PROC", kind=Kind.omitted)
done = FCpt(EpicsSignalRO, "{prefix}{_axis_id}:RAMP:DONE", auto_monitor=True)
ramprate = FCpt(
EpicsSignal, "{_ps_prefix}STS:RAMPRATE:TPM", write_pv="{_ps_prefix}SET:DMD:RAMPRATE:TPM"
)
def __init__(self, prefix="", axis_id="", ps_prefix="", *, name=None, **kwargs):
self._axis_id = axis_id
self._ps_prefix = ps_prefix
super().__init__(prefix, name=name, **kwargs)
self.readback.name = self.name
def _setup_move(self, position):
# If the setpoint is close to the current readback, the controller will not do anything,
# and the done value will not change. So we simply say is done.
if abs(position - self.readback.get()) < max(0.004, position * 0.0025):
self._done_moving(success=True, time=time.ctime(), value=position)
else:
super()._setup_move(position)
# x = Cpt(MagnetAxis, "", axis_id="X", ps_prefix="X07MA-PC-PS2:", name="x")
# z = Cpt(MagnetAxis, "", axis_id="Z", ps_prefix="X07MA-PC-PS1:", name="z")
class NormSignal(Signal):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._metadata.update(write_access=False)
def wait_for_connection(self, timeout=0):
super().wait_for_connection(timeout)
self._metadata.update(connected=True)
def get(self, **kwargs):
val1 = self.parent.signal1.get()
val2 = self.parent.signal2.get()
return val1 / val2 if val2 != 0 else 0
def describe(self):
desc = {
"shape": [],
"dtype": "number",
"source": "PV: {} / {}".format(self.parent.signal1.pvname, self.parent.signal2.pvname),
"units": "",
"precision": self.parent.signal1.precision,
}
return desc
class NormTEYSignals(Device):
signal1 = Cpt(EpicsSignalRO, name="signal1", read_pv="X07MA-ES1-AI:SIGNAL1", kind="omitted")
signal2 = Cpt(EpicsSignalRO, name="signal2", read_pv="X07MA-ES1-AI:SIGNAL2", kind="omitted")
norm = Cpt(NormSignal, name="norm", kind="hinted")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.norm.name = self.name
class NormDIODESignals(Device):
signal1 = Cpt(EpicsSignalRO, name="signal1", read_pv="X07MA-ES1-AI:SIGNAL3", kind="omitted")
signal2 = Cpt(EpicsSignalRO, name="signal2", read_pv="X07MA-ES1-AI:SIGNAL2", kind="omitted")
norm = Cpt(NormSignal, name="norm", kind="hinted")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.norm.name = self.name
class X07MAAnalogSignals(Device):
"""
ADC inputs
"""
s1 = Cpt(EpicsSignalRO, "SIGNAL0", kind=Kind.hinted, auto_monitor=True)
s2 = Cpt(EpicsSignalRO, "SIGNAL1", kind=Kind.hinted, auto_monitor=True)
s3 = Cpt(EpicsSignalRO, "SIGNAL2", kind=Kind.hinted, auto_monitor=True)
s4 = Cpt(EpicsSignalRO, "SIGNAL3", kind=Kind.hinted, auto_monitor=True)
s5 = Cpt(EpicsSignalRO, "SIGNAL4", kind=Kind.hinted, auto_monitor=True)
s6 = Cpt(EpicsSignalRO, "SIGNAL5", kind=Kind.hinted, auto_monitor=True)
s7 = Cpt(EpicsSignalRO, "SIGNAL6", kind=Kind.hinted, auto_monitor=True)
norm_tey = Cpt(NormTEYSignals, name="norm_tey", kind=Kind.hinted)
norm_diode = Cpt(NormDIODESignals, name="norm_tey", kind=Kind.hinted)
# Aliases
# tey = s1
# i0 = s2
# trans = s3
# field_z = s4
# field_x = s5
class X07MASampleManipulator(Device):
"""
Sample manipulator
"""
hor = Cpt(EpicsMotor, "TRZS")
vert = Cpt(EpicsMotor, "TRY1")
rot = Cpt(EpicsMotor, "ROY1")
class X07MATemperatureController(Device):
"""
Temperature controller
"""
needle_valve = Cpt(EpicsSignal, "STS:LOOP2:MANUAL", write_pv="DMD:LOOP2:MANUAL")
setpoint = Cpt(EpicsSignal, "STS:LOOP1:SETPOINT", write_pv="DMD:LOOP1:SETPOINT")
readback = Cpt(EpicsSignalRO, "STS:T1", kind=Kind.hinted, auto_monitor=True)
def __init__(
self,
prefix="",
*,
name,
kind=None,
read_attrs=None,
configuration_attrs=None,
parent=None,
**kwargs,
):
super().__init__(
prefix,
name=name,
kind=kind,
read_attrs=read_attrs,
configuration_attrs=configuration_attrs,
parent=parent,
**kwargs,
)
self.readback.name = self.name
class X07MAAutoTemperatureControl(Device):
"""
Automatic temperature control.
"""
control = Cpt(EpicsSignal, "CONTROL")
status = Cpt(EpicsSignalRO, "STATUS", string=True, auto_monitor=True)

View File

@ -1,34 +0,0 @@
# Standard ophyd classes
from ophyd import EpicsMotor, EpicsSignal, EpicsSignalRO
from ophyd.quadem import QuadEM
from ophyd.sim import SynAxis, SynPeriodicSignal, SynSignal
from .aerotech.AerotechAutomation1 import (
EpicsMotorX,
aa1AxisDriveDataCollection,
aa1AxisPsoDistance,
aa1Controller,
aa1GlobalVariableBindings,
aa1GlobalVariables,
aa1Tasks,
)
# cSAXS
from .epics_motor_ex import EpicsMotorEx
from .grashopper_tomcat import GrashopperTOMCAT
from .psi_detector_base import CustomDetectorMixin, PSIDetectorBase
from .slits import SlitH, SlitV
from .specMotors import (
Bpm4i,
EnergyKev,
GirderMotorPITCH,
GirderMotorROLL,
GirderMotorX1,
GirderMotorY1,
GirderMotorYAW,
MonoTheta1,
MonoTheta2,
PmDetectorRotation,
PmMonoBender,
)
from .SpmBase import SpmBase

File diff suppressed because it is too large Load Diff

View File

@ -1,901 +0,0 @@
from enum import Enum
class TomcatSequencerState:
IDLE = 0
READY = 1
ARMED = 2
RUNNING = 3
CHANGING = 4
ERROR = 15
class AxisDataSignal:
PositionFeedback = 0
PositionCommand = 1
PositionError = 2
VelocityFeedback = 3
VelocityCommand = 4
VelocityError = 5
AccelerationCommand = 6
CurrentError = 9
PositionCommandRaw = 12
VelocityCommandRaw = 13
AuxiliaryFeedback = 14
DigitalInput = 15
DigitalOutput = 16
FixtureOffset = 18
CoordinatedPositionTarget = 41
DriveStatus = 42
AxisStatus = 43
AxisFault = 44
AccelerationCommandRaw = 45
PositionCalibrationAll = 50
PositionFeedbackRollover = 63
PositionCommandRollover = 64
VelocityFeedbackAverage = 65
CurrentFeedbackAverage = 66
AxisParameter = 68
Backlash = 72
HomeState = 73
PositionCalibration2D = 74
NormalcyDebug = 75
TotalMoveTime = 76
JerkCommandRaw = 78
ProgramPositionCommand = 79
PositionOffset = 80
PositionCommandRawBackwardsDiff = 82
VelocityCommandRawBackwardsDiffDelta = 83
DriveStatusActual = 85
ProgramPositionFeedback = 89
JogTrajectoryStatus = 94
PingTest = 95
AccelerationTime = 109
DecelerationTime = 110
AccelerationRate = 111
DecelerationRate = 112
AccelerationType = 113
DecelerationType = 114
AccelerationMode = 115
DecelerationMode = 116
ProgramPosition = 124
SpeedTarget = 128
PositionCommandPacket = 131
DriveSmcMotionState = 132
PositionCommandRawCal = 140
VelocityCommandRawCal = 141
VelocityCommandDrive = 142
AccelerationCommandDrive = 143
GalvoLaserOutputRaw = 144
DriveInterfacePacketInt32 = 147
DriveInterfacePacketInt16 = 148
DriveInterfacePacketInt8 = 149
DriveInterfacePacketDouble = 150
DriveInterfacePacketFloat = 151
DriveInterfaceCommandCode = 152
AccelerationFeedback = 153
AccelerationCommandRawCal = 154
PositionCalibrationAllDrive = 155
BacklashTarget = 156
DriveMotionRate = 158
DriveMotionDelay = 159
CalibrationAdjustmentValue = 160
ServoRounding = 161
FeedforwardCurrent = 162
DriveInterfacePacketInfoBitValue = 164
AccelerationError = 165
SuppressedFaults = 167
DriveInterfacePacketStreamingData = 168
PositionCommandRawUnfiltered = 169
TransitionOffsetErrors = 170
FreezeVelocityCommand = 179
FreezeVelocityFeedback = 180
InternalPositionOffsets = 181
StatusHighLevelOffsetsLastMsec = 182
ProgramVelocityCommand = 183
ProgramVelocityFeedback = 184
DriveMotionDelayLive = 185
DriveCommunicationDelay = 186
DriveCommunicationDelayLive = 187
DriveInterfacePacketResponseInt32 = 189
DriveInterfacePacketResponseInt16 = 190
DriveInterfacePacketResponseInt8 = 191
DriveInterfacePacketResponseDouble = 192
DriveInterfacePacketResponseFloat = 193
DriveInterfacePacketBit = 194
DriveInterfacePacketResponseBit = 195
SpeedTargetActual = 196
CoordinatedDistanceRemaining = 199
SafeZoneState = 230
PositionErrorGalvo = 235
MoveReferencePosition = 237
MoveReferenceCutterOffset = 250
MoveReferenceCornerOffset = 251
MoveReferenceTotalOffset = 252
DistanceLog = 264
AutoFocusError = 295
GalvoLaserOutputRawAdvance = 296
GalvoLaserOnDelay = 297
GalvoLaserOffDelay = 298
CalibrationAdjustmentState = 301
AccuracyCorrectionStartingPosition = 302
AccuracyCorrectionEndingPosition = 303
DriveCommandsDelayed = 309
DriveCommandsLost = 310
StoStatus = 327
DriveAssert = 336
PrimaryFeedback = 366
AccelerationSCurvePercentage = 371
DecelerationSCurvePercentage = 372
GantryMarkerDifference = 390
PrimaryFeedbackStatus = 392
HomeTargetPosition = 398
GantryRealignmentMoveTargetPosition = 399
GantryDriveControlRealignmentState = 400
DriveInterfacePositionCommandPhysical = 434
DriveControlReason = 435
CurrentFeedback = 7
CurrentCommand = 8
AnalogInput0 = 10
AnalogInput1 = 11
PhaseACurrentFeedback = 19
PhaseBCurrentFeedback = 20
EncoderSine = 21
EncoderCosine = 22
AnalogInput2 = 23
AnalogInput3 = 24
FrequencyResponseBefore = 25
FrequencyResponseAfter = 26
AnalogOutput0 = 31
AnalogOutput1 = 32
AnalogOutput2 = 33
AnalogOutput3 = 34
DriveMemoryInt32 = 35
DriveMemoryFloat = 36
DriveMemoryDouble = 37
PsoStatus = 38
DriveTimerDebug = 39
PositionFeedbackDrive = 77
PositionCommandDrive = 84
DriveMemoryInt16 = 125
DriveMemoryInt8 = 126
PsoCounter0 = 171
PsoCounter1 = 172
PsoCounter2 = 173
PsoWindow0 = 174
PsoWindow1 = 175
DriveDataCaptureSamples = 176
PositionCommandGalvo = 178
PrimaryEnDatAbsolutePosition = 197
ControlEffort = 201
PhaseAVoltageCommand = 208
PhaseBVoltageCommand = 209
PhaseCVoltageCommand = 210
AmplifierPeakCurrent = 211
FpgaVersion = 212
DriveTypeId = 213
PsoWindow0ArrayIndex = 214
PsoWindow1ArrayIndex = 215
PsoDistanceArrayIndex = 216
AmplifierTemperature = 217
PsoBitArrayIndex = 218
MxAbsolutePosition = 219
ServoUpdateRate = 220
SettlingTime = 221
InternalStatusCode = 222
FirmwareVersionMajor = 223
FirmwareVersionMinor = 224
FirmwareVersionPatch = 225
FirmwareVersionBuild = 226
DriveTimerDebugMax = 227
MarkerSearchDistance = 228
PositionFeedbackGalvo = 234
LatchedMarkerPosition = 236
PrimaryBissAbsolutePosition = 255
FaultPositionFeedback = 258
MotorCommutationAngle = 259
ExpansionBoardOption = 260
BusVoltage = 261
PiezoVoltageCommand = 262
PiezoVoltageFeedback = 263
TimeSinceReset = 273
MaximumVoltage = 274
CommandOutputType = 275
DriveFeedforwardOutput = 290
LastTickCounter = 291
BoardRevision = 292
GalvoLaserOutput = 294
GalvoLaserPowerCorrectionOutput = 299
CapacitanceSensorRawPosition = 300
PositionCalibrationGalvo = 304
BusVoltageNegative = 325
ProcessorTemperature = 326
InternalStatusTimestamp = 328
AnalogSensorInput = 329
MotorTemperature = 330
PrimaryBissStatus = 332
PsoExternalSyncFrequency = 337
EncoderSineRaw = 346
EncoderCosineRaw = 347
FpgaTemperature = 353
PrimaryEnDatStatus = 355
DriveTimerHighPriorityThread = 356
DriveTimerLowPriorityThread = 357
DriveTimerLowPriorityPacket = 358
DriveTimerServoPacket = 359
DriveTimerServoThread = 360
DriveTimerCurrentPacket = 361
DriveTimerCommonCoreThread = 362
DriveTimerServoCorePacket0 = 363
DriveTimerServoCorePacket1 = 364
MultiplierOption = 365
ServoLoopFeedbackInput0 = 367
ServoLoopFeedbackInput1 = 368
FaultSubcode = 376
ProcessorTemperatureMax = 378
DriveTimerHyperWireDma = 381
AmplifierTemperatureMax = 382
AuxiliaryEnDatAbsolutePosition = 383
AuxiliaryEnDatStatus = 384
AuxiliaryBissAbsolutePosition = 385
AuxiliaryBissStatus = 386
PsoOption = 387
DriveArraySize = 388
RatedMotorSupplyVoltageOption = 389
AbsoluteEncoderOption = 391
AuxiliaryFeedbackStatus = 393
AmplifierStatus = 394
LatchedCwLimitPosition = 395
LatchedCcwLimitPosition = 396
GalvoLaserFpgaTransitionDelay = 397
PiezoAccumulatedCharge = 401
PiezoChargingTime = 402
PrimarySsiAbsolutePosition = 403
PrimarySsiStatus = 404
AuxiliarySsiAbsolutePosition = 405
AuxiliarySsiStatus = 406
PsoDistanceActiveDistance = 407
PsoWindow0ActiveLowerBound = 408
PsoWindow0ActiveUpperBound = 409
PsoWindow1ActiveLowerBound = 410
PsoWindow1ActiveUpperBound = 411
PsoWaveformActiveTotalTime = 412
PsoWaveformActiveOnTime = 413
PsoWaveformActivePulseCount = 414
PsoEventActiveBitValue = 415
DriveTimerDriveBasedControllerOutputDma = 419
DriveTimerPcieInboundFsm = 420
PrimaryFeedbackServo = 425
AuxiliaryFeedbackServo = 426
DriveStackUsage = 427
ShuntResistorTemperature = 436
class TaskDataSignal:
ProgramLineNumber = 17
CoordinatedFlags = 40
CoordinatedArcStartAngle = 53
CoordinatedArcEndAngle = 54
CoordinatedArcRadius = 55
CoordinatedArcRadiusError = 56
CoordinatedPositionCommand = 57
CoordinatedSpeedCommand = 58
CoordinatedAccelerationCommand = 59
CoordinatedTotalDistance = 60
CoordinatedPercentDone = 61
CoordinatedPositionCommandBackwardsDiff = 62
TaskParameter = 69
TaskError = 70
TaskWarning = 71
CoordinatedSpeedTargetActual = 86
DependentCoordinatedSpeedTargetActual = 87
ActiveFixtureOffset = 88
TaskStatus0 = 90
TaskStatus1 = 91
TaskStatus2 = 92
SpindleSpeedTarget = 93
CoordinateSystem1I = 96
CoordinateSystem1J = 97
CoordinateSystem1K = 98
CoordinateSystem1Plane = 99
ToolNumberActive = 100
Mfo = 101
CoordinatedSpeedTarget = 102
DependentCoordinatedSpeedTarget = 103
CoordinatedAccelerationRate = 104
CoordinatedDecelerationRate = 105
CoordinatedAccelerationTime = 106
CoordinatedDecelerationTime = 107
TaskMode = 108
TaskState = 117
TaskStateInternal = 118
ExecutionMode = 121
EnableAlignmentAxes = 127
CoordinatedGalvoLaserOutput = 133
CoordinatedMotionRate = 145
CoordinatedTaskCommand = 146
EnableState = 166
LookaheadMovesExamined = 200
ProfileControlMask = 231
CoordinatedArcRadiusReciprocal = 253
MotionEngineStage = 254
CoordinatedTimeScale = 256
CoordinatedTimeScaleDerivative = 257
IfovSpeedScale = 266
IfovSpeedScaleAverage = 267
IfovGenerationFrameCounter = 268
IfovGenerationTimeOriginal = 269
IfovGenerationTimeModified = 270
IfovCoordinatedPositionCommand = 271
IfovCoordinatedSpeedCommand = 272
IfovCenterPointH = 276
IfovCenterPointV = 277
IfovTrajectoryCount = 278
IfovTrajectoryIndex = 279
IfovAttemptCode = 280
IfovGenerationFrameIndex = 281
IfovMaximumVelocity = 282
IfovIdealVelocity = 283
TaskInternalDebug = 284
IfovCoordinatedAccelerationCommand = 285
IfovFovPositionH = 286
IfovFovPositionV = 287
IfovFovDimensionH = 288
IfovFovDimensionV = 289
MotionBufferElements = 311
MotionBufferMoves = 312
MotionLineNumber = 313
MotionBufferRetraceMoves = 314
MotionBufferRetraceElements = 315
MotionBufferIndex = 316
MotionBufferIndexLookahead = 317
MotionBufferProcessingBlocked = 318
ActiveMoveValid = 319
TaskExecutionLines = 320
SchedulerTaskHolds = 321
SchedulerProgramLoopRuns = 322
SchedulerTaskBlocked = 323
CriticalSectionsActive = 324
AxesSlowdownReason = 331
TaskExecutionTime = 333
TaskExecutionTimeMaximum = 334
TaskExecutionLinesMaximum = 335
LookaheadDecelReason = 338
LookaheadDecelMoves = 339
LookaheadDecelDistance = 340
ProgramCounter = 341
StackPointer = 342
FramePointer = 343
StringStackPointer = 344
ProgramLineNumberSourceFileId = 349
MotionLineNumberSourceFileId = 350
ProgramLineNumberSourcePathId = 351
MotionLineNumberSourcePathId = 352
StringArgumentStackPointer = 354
CoordinatedAccelerationSCurvePercentage = 369
CoordinatedDecelerationSCurvePercentage = 370
DependentCoordinatedAccelerationRate = 373
DependentCoordinatedDecelerationRate = 374
CriticalSectionTimeout = 375
CommandQueueCapacity = 421
CommandQueueUnexecutedCount = 422
CommandQueueTimesEmptied = 423
CommandQueueExecutedCount = 424
class SystemDataSignal:
VirtualBinaryInput = 46
VirtualBinaryOutput = 47
VirtualRegisterInput = 48
VirtualRegisterOutput = 49
Timer = 51
TimerPerformance = 52
GlobalReal = 67
CommunicationRealTimeErrors = 81
LibraryCommand = 119
DataCollectionSampleTime = 120
DataCollectionSampleIndex = 129
ModbusClientConnected = 134
ModbusServerConnected = 135
ModbusClientError = 136
ModbusServerError = 137
StopWatchTimer = 157
ScopetrigId = 163
EstimatedProcessorUsage = 177
DataCollectionStatus = 188
SignalLogState = 198
SafeZoneViolationMask = 207
SafeZoneActiveMask = 229
ModbusClientInputWords = 240
ModbusClientOutputWords = 241
ModbusClientInputBits = 242
ModbusClientOutputBits = 243
ModbusClientOutputBitsStatus = 244
ModbusClientOutputWordsStatus = 245
ModbusServerInputWords = 246
ModbusServerOutputWords = 247
ModbusServerInputBits = 248
ModbusServerOutputBits = 249
SystemParameter = 265
ThermoCompSensorTemperature = 305
ThermoCompControllingTemperature = 306
ThermoCompCompensatingTemperature = 307
ThermoCompStatus = 308
GlobalInteger = 345
AliveAxesMask = 348
SignalLogPointsStored = 377
ControllerInitializationWarning = 379
StopWatchTimerMin = 416
StopWatchTimerMax = 417
StopWatchTimerAvg = 418
EthercatEnabled = 428
EthercatError = 429
EthercatTxPdo = 430
EthercatTxPdoSize = 431
EthercatRxPdo = 432
EthercatRxPdoSize = 433
EthercatState = 437
ModbusClientEnabled = 438
ModbusServerEnabled = 439
class DataCollectionFrequency:
Undefined = 0
Fixed1kHz = 1
Fixed10kHz = 2
Fixed20kHz = 3
Fixed100kHz = 4
Fixed200kHz = 5
class DataCollectionMode:
Snapshot = 0
Continouous = 1
# Specifies the PSO distance input settings for the XC4e drive.
class PsoDistanceInput:
XC4PrimaryFeedback = 130
XC4AuxiliaryFeedback = 131
XC4SyncPortA = 132
XC4SyncPortB = 133
XC4DrivePulseStream = 134
XC4ePrimaryFeedback = 135
XC4eAuxiliaryFeedback = 136
XC4eSyncPortA = 137
XC4eSyncPortB = 138
XC4eDrivePulseStream = 139
class PsoWindowInput:
XC4PrimaryFeedback = 130
XC4AuxiliaryFeedback = 131
XC4SyncPortA = 132
XC4SyncPortB = 133
XC4DrivePulseStream = 134
XC4ePrimaryFeedback = 135
XC4eAuxiliaryFeedback = 136
XC4eSyncPortA = 137
XC4eSyncPortB = 138
XC4eDrivePulseStream = 139
XL5ePrimaryFeedback = (145,)
XL5eAuxiliaryFeedback = (146,)
XL5eSyncPortA = (147,)
XL5eSyncPortB = (148,)
XL5eDrivePulseStream = (149,)
# @brief Specifies the PSO output pin settings for each drive.
class XC4ePsoOutputPin:
DedicatedOutput = 111
AuxiliaryMarkerDifferential = 112
AuxiliaryMarkerSingleEnded = 113
class XC4PsoOutputPin:
DedicatedOutput = 108
AuxiliaryMarkerDifferential = 109
AuxiliaryMarkerSingleEnded = 110
"""
# @brief Specifies the PSO distance input settings for each drive.
class Automation1PsoDistanceInput:
Automation1PsoDistanceInput_GL4PrimaryFeedbackAxis1 = 100,
Automation1PsoDistanceInput_GL4PrimaryFeedbackAxis2 = 101,
Automation1PsoDistanceInput_GL4IfovFeedbackAxis1 = 102,
Automation1PsoDistanceInput_GL4IfovFeedbackAxis2 = 103,
Automation1PsoDistanceInput_GL4AuxiliaryFeedbackAxis1 = 104,
Automation1PsoDistanceInput_GL4AuxiliaryFeedbackAxis2 = 105,
Automation1PsoDistanceInput_GL4SyncPortA = 106,
Automation1PsoDistanceInput_GL4SyncPortB = 107,
Automation1PsoDistanceInput_GL4DrivePulseStreamAxis1 = 108,
Automation1PsoDistanceInput_GL4DrivePulseStreamAxis2 = 109,
Automation1PsoDistanceInput_XL4sPrimaryFeedback = 110,
Automation1PsoDistanceInput_XL4sAuxiliaryFeedback = 111,
Automation1PsoDistanceInput_XL4sSyncPortA = 112,
Automation1PsoDistanceInput_XL4sSyncPortB = 113,
Automation1PsoDistanceInput_XL4sDrivePulseStream = 114,
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis1 = 115,
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis2 = 116,
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis3 = 117,
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis4 = 118,
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis5 = 119,
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis6 = 120,
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis1 = 121,
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis2 = 122,
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis3 = 123,
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis4 = 124,
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis5 = 125,
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis6 = 126,
Automation1PsoDistanceInput_XR3SyncPortA = 127,
Automation1PsoDistanceInput_XR3SyncPortB = 128,
Automation1PsoDistanceInput_XR3DrivePulseStream = 129,
Automation1PsoDistanceInput_XC4PrimaryFeedback = 130,
Automation1PsoDistanceInput_XC4AuxiliaryFeedback = 131,
Automation1PsoDistanceInput_XC4SyncPortA = 132,
Automation1PsoDistanceInput_XC4SyncPortB = 133,
Automation1PsoDistanceInput_XC4DrivePulseStream = 134,
XC4ePrimaryFeedback = 135,
XC4eAuxiliaryFeedback = 136,
XC4eSyncPortA = 137,
XC4eSyncPortB = 138,
XC4eDrivePulseStream = 139,
Automation1PsoDistanceInput_XC6ePrimaryFeedback = 140,
Automation1PsoDistanceInput_XC6eAuxiliaryFeedback = 141,
Automation1PsoDistanceInput_XC6eSyncPortA = 142,
Automation1PsoDistanceInput_XC6eSyncPortB = 143,
Automation1PsoDistanceInput_XC6eDrivePulseStream = 144,
Automation1PsoDistanceInput_XL5ePrimaryFeedback = 145,
Automation1PsoDistanceInput_XL5eAuxiliaryFeedback = 146,
Automation1PsoDistanceInput_XL5eSyncPortA = 147,
Automation1PsoDistanceInput_XL5eSyncPortB = 148,
Automation1PsoDistanceInput_XL5eDrivePulseStream = 149,
Automation1PsoDistanceInput_XC2PrimaryFeedback = 150,
Automation1PsoDistanceInput_XC2AuxiliaryFeedback = 151,
Automation1PsoDistanceInput_XC2DrivePulseStream = 152,
Automation1PsoDistanceInput_XC2ePrimaryFeedback = 153,
Automation1PsoDistanceInput_XC2eAuxiliaryFeedback = 154,
Automation1PsoDistanceInput_XC2eDrivePulseStream = 155,
Automation1PsoDistanceInput_XL2ePrimaryFeedback = 156,
Automation1PsoDistanceInput_XL2eAuxiliaryFeedback = 157,
Automation1PsoDistanceInput_XL2eSyncPortA = 158,
Automation1PsoDistanceInput_XL2eSyncPortB = 159,
Automation1PsoDistanceInput_XL2eDrivePulseStream = 160,
Automation1PsoDistanceInput_XI4PrimaryFeedbackAxis1 = 161,
Automation1PsoDistanceInput_XI4PrimaryFeedbackAxis2 = 162,
Automation1PsoDistanceInput_XI4PrimaryFeedbackAxis3 = 163,
Automation1PsoDistanceInput_XI4PrimaryFeedbackAxis4 = 164,
Automation1PsoDistanceInput_XI4AuxiliaryFeedback1 = 165,
Automation1PsoDistanceInput_XI4AuxiliaryFeedback2 = 166,
Automation1PsoDistanceInput_XI4AuxiliaryFeedback3 = 167,
Automation1PsoDistanceInput_XI4AuxiliaryFeedback4 = 168,
Automation1PsoDistanceInput_XI4SyncPortA = 169,
Automation1PsoDistanceInput_XI4SyncPortB = 170,
Automation1PsoDistanceInput_XI4DrivePulseStreamAxis1 = 171,
Automation1PsoDistanceInput_XI4DrivePulseStreamAxis2 = 172,
Automation1PsoDistanceInput_XI4DrivePulseStreamAxis3 = 173,
Automation1PsoDistanceInput_XI4DrivePulseStreamAxis4 = 174,
Automation1PsoDistanceInput_iXC4PrimaryFeedback = 175,
Automation1PsoDistanceInput_iXC4AuxiliaryFeedback = 176,
Automation1PsoDistanceInput_iXC4SyncPortA = 177,
Automation1PsoDistanceInput_iXC4SyncPortB = 178,
Automation1PsoDistanceInput_iXC4DrivePulseStream = 179,
Automation1PsoDistanceInput_iXC4ePrimaryFeedback = 180,
Automation1PsoDistanceInput_iXC4eAuxiliaryFeedback = 181,
Automation1PsoDistanceInput_iXC4eSyncPortA = 182,
Automation1PsoDistanceInput_iXC4eSyncPortB = 183,
Automation1PsoDistanceInput_iXC4eDrivePulseStream = 184,
Automation1PsoDistanceInput_iXC6ePrimaryFeedback = 185,
Automation1PsoDistanceInput_iXC6eAuxiliaryFeedback = 186,
Automation1PsoDistanceInput_iXC6eSyncPortA = 187,
Automation1PsoDistanceInput_iXC6eSyncPortB = 188,
Automation1PsoDistanceInput_iXC6eDrivePulseStream = 189,
Automation1PsoDistanceInput_iXL5ePrimaryFeedback = 190,
Automation1PsoDistanceInput_iXL5eAuxiliaryFeedback = 191,
Automation1PsoDistanceInput_iXL5eSyncPortA = 192,
Automation1PsoDistanceInput_iXL5eSyncPortB = 193,
Automation1PsoDistanceInput_iXL5eDrivePulseStream = 194,
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis1 = 195,
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis2 = 196,
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis3 = 197,
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis4 = 198,
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis5 = 199,
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis6 = 200,
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis1 = 201,
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis2 = 202,
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis3 = 203,
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis4 = 204,
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis5 = 205,
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis6 = 206,
Automation1PsoDistanceInput_iXR3SyncPortA = 207,
Automation1PsoDistanceInput_iXR3SyncPortB = 208,
Automation1PsoDistanceInput_iXR3DrivePulseStream = 209,
Automation1PsoDistanceInput_GI4DrivePulseStreamAxis1 = 210,
Automation1PsoDistanceInput_GI4DrivePulseStreamAxis2 = 211,
Automation1PsoDistanceInput_GI4DrivePulseStreamAxis3 = 212,
Automation1PsoDistanceInput_iXC2PrimaryFeedback = 213,
Automation1PsoDistanceInput_iXC2AuxiliaryFeedback = 214,
Automation1PsoDistanceInput_iXC2DrivePulseStream = 215,
Automation1PsoDistanceInput_iXC2ePrimaryFeedback = 216,
Automation1PsoDistanceInput_iXC2eAuxiliaryFeedback = 217,
Automation1PsoDistanceInput_iXC2eDrivePulseStream = 218,
Automation1PsoDistanceInput_iXL2ePrimaryFeedback = 219,
Automation1PsoDistanceInput_iXL2eAuxiliaryFeedback = 220,
Automation1PsoDistanceInput_iXL2eSyncPortA = 221,
Automation1PsoDistanceInput_iXL2eSyncPortB = 222,
Automation1PsoDistanceInput_iXL2eDrivePulseStream = 223,
Automation1PsoDistanceInput_iXI4PrimaryFeedbackAxis1 = 224,
Automation1PsoDistanceInput_iXI4PrimaryFeedbackAxis2 = 225,
Automation1PsoDistanceInput_iXI4PrimaryFeedbackAxis3 = 226,
Automation1PsoDistanceInput_iXI4PrimaryFeedbackAxis4 = 227,
Automation1PsoDistanceInput_iXI4AuxiliaryFeedback1 = 228,
Automation1PsoDistanceInput_iXI4AuxiliaryFeedback2 = 229,
Automation1PsoDistanceInput_iXI4AuxiliaryFeedback3 = 230,
Automation1PsoDistanceInput_iXI4AuxiliaryFeedback4 = 231,
Automation1PsoDistanceInput_iXI4SyncPortA = 232,
Automation1PsoDistanceInput_iXI4SyncPortB = 233,
Automation1PsoDistanceInput_iXI4DrivePulseStreamAxis1 = 234,
Automation1PsoDistanceInput_iXI4DrivePulseStreamAxis2 = 235,
Automation1PsoDistanceInput_iXI4DrivePulseStreamAxis3 = 236,
Automation1PsoDistanceInput_iXI4DrivePulseStreamAxis4 = 237,
# @brief Specifies the PSO window input settings for each drive.
class Automation1PsoWindowInput:
Automation1PsoWindowInput_GL4PrimaryFeedbackAxis1 = 100,
Automation1PsoWindowInput_GL4PrimaryFeedbackAxis2 = 101,
Automation1PsoWindowInput_GL4IfovFeedbackAxis1 = 102,
Automation1PsoWindowInput_GL4IfovFeedbackAxis2 = 103,
Automation1PsoWindowInput_GL4AuxiliaryFeedbackAxis1 = 104,
Automation1PsoWindowInput_GL4AuxiliaryFeedbackAxis2 = 105,
Automation1PsoWindowInput_GL4SyncPortA = 106,
Automation1PsoWindowInput_GL4SyncPortB = 107,
Automation1PsoWindowInput_GL4DrivePulseStreamAxis1 = 108,
Automation1PsoWindowInput_GL4DrivePulseStreamAxis2 = 109,
Automation1PsoWindowInput_XL4sPrimaryFeedback = 110,
Automation1PsoWindowInput_XL4sAuxiliaryFeedback = 111,
Automation1PsoWindowInput_XL4sSyncPortA = 112,
Automation1PsoWindowInput_XL4sSyncPortB = 113,
Automation1PsoWindowInput_XL4sDrivePulseStream = 114,
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis1 = 115,
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis2 = 116,
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis3 = 117,
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis4 = 118,
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis5 = 119,
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis6 = 120,
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis1 = 121,
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis2 = 122,
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis3 = 123,
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis4 = 124,
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis5 = 125,
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis6 = 126,
Automation1PsoWindowInput_XR3SyncPortA = 127,
Automation1PsoWindowInput_XR3SyncPortB = 128,
Automation1PsoWindowInput_XR3DrivePulseStream = 129,
Automation1PsoWindowInput_XC4PrimaryFeedback = 130,
Automation1PsoWindowInput_XC4AuxiliaryFeedback = 131,
Automation1PsoWindowInput_XC4SyncPortA = 132,
Automation1PsoWindowInput_XC4SyncPortB = 133,
Automation1PsoWindowInput_XC4DrivePulseStream = 134,
XC4ePrimaryFeedback = 135,
XC4eAuxiliaryFeedback = 136,
XC4eSyncPortA = 137,
XC4eSyncPortB = 138,
XC4eDrivePulseStream = 139,
Automation1PsoWindowInput_XC6ePrimaryFeedback = 140,
Automation1PsoWindowInput_XC6eAuxiliaryFeedback = 141,
Automation1PsoWindowInput_XC6eSyncPortA = 142,
Automation1PsoWindowInput_XC6eSyncPortB = 143,
Automation1PsoWindowInput_XC6eDrivePulseStream = 144,
Automation1PsoWindowInput_XL5ePrimaryFeedback = 145,
Automation1PsoWindowInput_XL5eAuxiliaryFeedback = 146,
Automation1PsoWindowInput_XL5eSyncPortA = 147,
Automation1PsoWindowInput_XL5eSyncPortB = 148,
Automation1PsoWindowInput_XL5eDrivePulseStream = 149,
Automation1PsoWindowInput_XC2PrimaryFeedback = 150,
Automation1PsoWindowInput_XC2AuxiliaryFeedback = 151,
Automation1PsoWindowInput_XC2DrivePulseStream = 152,
Automation1PsoWindowInput_XC2ePrimaryFeedback = 153,
Automation1PsoWindowInput_XC2eAuxiliaryFeedback = 154,
Automation1PsoWindowInput_XC2eDrivePulseStream = 155,
Automation1PsoWindowInput_XL2ePrimaryFeedback = 156,
Automation1PsoWindowInput_XL2eAuxiliaryFeedback = 157,
Automation1PsoWindowInput_XL2eSyncPortA = 158,
Automation1PsoWindowInput_XL2eSyncPortB = 159,
Automation1PsoWindowInput_XL2eDrivePulseStream = 160,
Automation1PsoWindowInput_XI4PrimaryFeedbackAxis1 = 161,
Automation1PsoWindowInput_XI4PrimaryFeedbackAxis2 = 162,
Automation1PsoWindowInput_XI4PrimaryFeedbackAxis3 = 163,
Automation1PsoWindowInput_XI4PrimaryFeedbackAxis4 = 164,
Automation1PsoWindowInput_XI4AuxiliaryFeedback1 = 165,
Automation1PsoWindowInput_XI4AuxiliaryFeedback2 = 166,
Automation1PsoWindowInput_XI4AuxiliaryFeedback3 = 167,
Automation1PsoWindowInput_XI4AuxiliaryFeedback4 = 168,
Automation1PsoWindowInput_XI4SyncPortA = 169,
Automation1PsoWindowInput_XI4SyncPortB = 170,
Automation1PsoWindowInput_XI4DrivePulseStreamAxis1 = 171,
Automation1PsoWindowInput_XI4DrivePulseStreamAxis2 = 172,
Automation1PsoWindowInput_XI4DrivePulseStreamAxis3 = 173,
Automation1PsoWindowInput_XI4DrivePulseStreamAxis4 = 174,
Automation1PsoWindowInput_iXC4PrimaryFeedback = 175,
Automation1PsoWindowInput_iXC4AuxiliaryFeedback = 176,
Automation1PsoWindowInput_iXC4SyncPortA = 177,
Automation1PsoWindowInput_iXC4SyncPortB = 178,
Automation1PsoWindowInput_iXC4DrivePulseStream = 179,
Automation1PsoWindowInput_iXC4ePrimaryFeedback = 180,
Automation1PsoWindowInput_iXC4eAuxiliaryFeedback = 181,
Automation1PsoWindowInput_iXC4eSyncPortA = 182,
Automation1PsoWindowInput_iXC4eSyncPortB = 183,
Automation1PsoWindowInput_iXC4eDrivePulseStream = 184,
Automation1PsoWindowInput_iXC6ePrimaryFeedback = 185,
Automation1PsoWindowInput_iXC6eAuxiliaryFeedback = 186,
Automation1PsoWindowInput_iXC6eSyncPortA = 187,
Automation1PsoWindowInput_iXC6eSyncPortB = 188,
Automation1PsoWindowInput_iXC6eDrivePulseStream = 189,
Automation1PsoWindowInput_iXL5ePrimaryFeedback = 190,
Automation1PsoWindowInput_iXL5eAuxiliaryFeedback = 191,
Automation1PsoWindowInput_iXL5eSyncPortA = 192,
Automation1PsoWindowInput_iXL5eSyncPortB = 193,
Automation1PsoWindowInput_iXL5eDrivePulseStream = 194,
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis1 = 195,
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis2 = 196,
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis3 = 197,
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis4 = 198,
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis5 = 199,
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis6 = 200,
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis1 = 201,
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis2 = 202,
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis3 = 203,
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis4 = 204,
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis5 = 205,
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis6 = 206,
Automation1PsoWindowInput_iXR3SyncPortA = 207,
Automation1PsoWindowInput_iXR3SyncPortB = 208,
Automation1PsoWindowInput_iXR3DrivePulseStream = 209,
Automation1PsoWindowInput_GI4DrivePulseStreamAxis1 = 210,
Automation1PsoWindowInput_GI4DrivePulseStreamAxis2 = 211,
Automation1PsoWindowInput_GI4DrivePulseStreamAxis3 = 212,
Automation1PsoWindowInput_iXC2PrimaryFeedback = 213,
Automation1PsoWindowInput_iXC2AuxiliaryFeedback = 214,
Automation1PsoWindowInput_iXC2DrivePulseStream = 215,
Automation1PsoWindowInput_iXC2ePrimaryFeedback = 216,
Automation1PsoWindowInput_iXC2eAuxiliaryFeedback = 217,
Automation1PsoWindowInput_iXC2eDrivePulseStream = 218,
Automation1PsoWindowInput_iXL2ePrimaryFeedback = 219,
Automation1PsoWindowInput_iXL2eAuxiliaryFeedback = 220,
Automation1PsoWindowInput_iXL2eSyncPortA = 221,
Automation1PsoWindowInput_iXL2eSyncPortB = 222,
Automation1PsoWindowInput_iXL2eDrivePulseStream = 223,
Automation1PsoWindowInput_iXI4PrimaryFeedbackAxis1 = 224,
Automation1PsoWindowInput_iXI4PrimaryFeedbackAxis2 = 225,
Automation1PsoWindowInput_iXI4PrimaryFeedbackAxis3 = 226,
Automation1PsoWindowInput_iXI4PrimaryFeedbackAxis4 = 227,
Automation1PsoWindowInput_iXI4AuxiliaryFeedback1 = 228,
Automation1PsoWindowInput_iXI4AuxiliaryFeedback2 = 229,
Automation1PsoWindowInput_iXI4AuxiliaryFeedback3 = 230,
Automation1PsoWindowInput_iXI4AuxiliaryFeedback4 = 231,
Automation1PsoWindowInput_iXI4SyncPortA = 232,
Automation1PsoWindowInput_iXI4SyncPortB = 233,
Automation1PsoWindowInput_iXI4DrivePulseStreamAxis1 = 234,
Automation1PsoWindowInput_iXI4DrivePulseStreamAxis2 = 235,
Automation1PsoWindowInput_iXI4DrivePulseStreamAxis3 = 236,
Automation1PsoWindowInput_iXI4DrivePulseStreamAxis4 = 237,
# @brief Specifies the PSO output pin settings for each drive.
class Automation1PsoOutputPin:
Automation1PsoOutputPin_GL4None = 100,
Automation1PsoOutputPin_GL4LaserOutput0 = 101,
Automation1PsoOutputPin_XL4sNone = 102,
Automation1PsoOutputPin_XL4sLaserOutput0 = 103,
Automation1PsoOutputPin_XR3None = 104,
Automation1PsoOutputPin_XR3PsoOutput1 = 105,
Automation1PsoOutputPin_XR3PsoOutput2 = 106,
Automation1PsoOutputPin_XR3PsoOutput3 = 107,
Automation1PsoOutputPin_XC4DedicatedOutput = 108,
Automation1PsoOutputPin_XC4AuxiliaryMarkerDifferential = 109,
Automation1PsoOutputPin_XC4AuxiliaryMarkerSingleEnded = 110,
XC4eDedicatedOutput = 111,
XC4eAuxiliaryMarkerDifferential = 112,
XC4eAuxiliaryMarkerSingleEnded = 113,
Automation1PsoOutputPin_XC6eDedicatedOutput = 114,
Automation1PsoOutputPin_XC6eAuxiliaryMarkerDifferential = 115,
Automation1PsoOutputPin_XC6eAuxiliaryMarkerSingleEnded = 116,
Automation1PsoOutputPin_XL5eDedicatedOutput = 117,
Automation1PsoOutputPin_XL5eAuxiliaryMarkerDifferential = 118,
Automation1PsoOutputPin_XL5eAuxiliaryMarkerSingleEnded = 119,
Automation1PsoOutputPin_XC2DedicatedOutput = 120,
Automation1PsoOutputPin_XC2eDedicatedOutput = 121,
Automation1PsoOutputPin_XL2eDedicatedOutput = 122,
Automation1PsoOutputPin_XI4DedicatedOutput = 123,
Automation1PsoOutputPin_iXC4DedicatedOutput = 124,
Automation1PsoOutputPin_iXC4AuxiliaryMarkerDifferential = 125,
Automation1PsoOutputPin_iXC4AuxiliaryMarkerSingleEnded = 126,
Automation1PsoOutputPin_iXC4eDedicatedOutput = 127,
Automation1PsoOutputPin_iXC4eAuxiliaryMarkerDifferential = 128,
Automation1PsoOutputPin_iXC4eAuxiliaryMarkerSingleEnded = 129,
Automation1PsoOutputPin_iXC6eDedicatedOutput = 130,
Automation1PsoOutputPin_iXC6eAuxiliaryMarkerDifferential = 131,
Automation1PsoOutputPin_iXC6eAuxiliaryMarkerSingleEnded = 132,
Automation1PsoOutputPin_iXL5eDedicatedOutput = 133,
Automation1PsoOutputPin_iXL5eAuxiliaryMarkerDifferential = 134,
Automation1PsoOutputPin_iXL5eAuxiliaryMarkerSingleEnded = 135,
Automation1PsoOutputPin_iXR3None = 136,
Automation1PsoOutputPin_iXR3PsoOutput1 = 137,
Automation1PsoOutputPin_iXR3PsoOutput2 = 138,
Automation1PsoOutputPin_iXR3PsoOutput3 = 139,
Automation1PsoOutputPin_GI4None = 140,
Automation1PsoOutputPin_GI4LaserOutput0 = 141,
Automation1PsoOutputPin_iXC2eDedicatedOutput = 143,
Automation1PsoOutputPin_iXL2eDedicatedOutput = 144,
Automation1PsoOutputPin_iXI4DedicatedOutput = 145,
"""
class DriveDataCaptureInput:
PositionCommand = 0
PrimaryFeedback = 1
AuxiliaryFeedback = 2
AnalogInput0 = 3
AnalogInput1 = 4
AnalogInput2 = 5
AnalogInput3 = 6
class DriveDataCaptureTrigger:
PsoOutput = 0
PsoEvent = 1
HighSpeedInput0RisingEdge = 2
HighSpeedInput0FallingEdge = 3
HighSpeedInput1RisingEdge = 4
HighSpeedInput1FallingEdge = 5
AuxiliaryMarkerRisingEdge = 6
AuxiliaryMarkerFallingEdge = 7
class PsoOutputPin:
GL4None = (100,)
GL4LaserOutput0 = (101,)
XL4sNone = (102,)
XL4sLaserOutput0 = (103,)
XR3None = (104,)
XR3PsoOutput1 = (105,)
XR3PsoOutput2 = (106,)
XR3PsoOutput3 = (107,)
XC4DedicatedOutput = (108,)
XC4AuxiliaryMarkerDifferential = (109,)
XC4AuxiliaryMarkerSingleEnded = (110,)
XC4eDedicatedOutput = (111,)
XC4eAuxiliaryMarkerDifferential = (112,)
XC4eAuxiliaryMarkerSingleEnded = (113,)
XC6eDedicatedOutput = (114,)
XC6eAuxiliaryMarkerDifferential = (115,)
XC6eAuxiliaryMarkerSingleEnded = (116,)
XL5eDedicatedOutput = (117,)
XL5eAuxiliaryMarkerDifferential = (118,)
XL5eAuxiliaryMarkerSingleEnded = (119,)
XC2DedicatedOutput = (120,)
XC2eDedicatedOutput = (121,)
XL2eDedicatedOutput = (122,)
XI4DedicatedOutput = (123,)
iXC4DedicatedOutput = (124,)
iXC4AuxiliaryMarkerDifferential = (125,)
iXC4AuxiliaryMarkerSingleEnded = (126,)
iXC4eDedicatedOutput = (127,)
iXC4eAuxiliaryMarkerDifferential = (128,)
iXC4eAuxiliaryMarkerSingleEnded = (129,)
iXC6eDedicatedOutput = (130,)
iXC6eAuxiliaryMarkerDifferential = (131,)
iXC6eAuxiliaryMarkerSingleEnded = (132,)
iXL5eDedicatedOutput = (133,)
iXL5eAuxiliaryMarkerDifferential = (134,)
iXL5eAuxiliaryMarkerSingleEnded = (135,)
iXR3None = (136,)
iXR3PsoOutput1 = (137,)
iXR3PsoOutput2 = (138,)
iXR3PsoOutput3 = (139,)
GI4None = (140,)
GI4LaserOutput0 = (141,)
iXC2DedicatedOutput = (142,)
iXC2eDedicatedOutput = (143,)
iXL2eDedicatedOutput = (144,)
iXI4DedicatedOutput = (145,)

View File

@ -1,140 +0,0 @@
// Test program for simple zig-zag line scanning with PSO window output
// "enable" signal and DDC synchronized to external trigger input.
// The file expects external parameter validation
// The PSO locations arrays are set externally from EPICS PV
//
enum ScanType
Pos = 0
Neg = 1
PosNeg = 2
NegPos = 3
end
program
//////////////////////////////////////////////////////////////////////////
// External parameters - USE THEESE
var $fStartPosition as real = {{ scan.startpos }}
var $fScanRange as real = $fStartPosition + {{ scan.scanrange }}
var $iNumRepeat as integer = {{ scan.nrepeat }}
var $eScanType as ScanType = ScanType.{{ scan.scandir or 'Pos' }}
var $iNumDdcRead as integer = {{ scan.npoints }}
var $fVelJog as real = {{ scan.jogvel or 200 }}
var $fVelScan as real = {{ scan.scanvel }}
var $fAcceleration = {{ scan.scanacc or 500 }}
var $fSafeDist = 10.0
//////////////////////////////////////////////////////////////////////////
// Internal parameters - dont use
var $axis as axis = ROTY
var $ii as integer
var $iDdcSafeSpace as integer = 4096
// Set acceleration
SetupAxisRampType($axis, RampType.Linear)
SetupAxisRampValue($axis,0,$fAcceleration)
var $fAccDistance as real = 0.5 * $fVelScan * $fVelScan / $fAcceleration + $fSafeDist
// set the actual scan range
var $fPosStart as real
var $fPosEnd as real
if $eScanType == ScanType.Pos
$fPosStart = $fStartPosition - $fAccDistance
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
elseif $eScanType == ScanType.Neg
$fPosStart = $fStartPosition + $fAccDistance
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
elseif $eScanType == ScanType.PosNeg
$fPosStart = $fStartPosition - $fAccDistance
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
elseif $eScanType == ScanType.NegPos
$fPosStart = $fStartPosition + $fAccDistance
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
end
// Move to start position before the scan
MoveAbsolute($axis, $fPosStart, $fVelJog)
WaitForInPosition($axis)
// Configure PSO
PsoDistanceCounterOff($axis)
PsoDistanceEventsOff($axis)
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
PsoWaveformOff($axis)
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
var $iPsoArrayAddr as integer = 0
// Simple PSO trigger pattern
var $iPsoArrayPos[] as real = [{% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsPos[-1] }})]
// var $iPsoArrayPos[] as real = [UnitsToCounts($axis, $fAccDistance), {% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, psoDist), {% endfor %}]
// var $iPsoArrayNeg[] as real = [UnitsToCounts($axis, $fAccDistance), {% for psoDist in scan.psoBoundsNeg[:-1] %} UnitsToCounts($axis, psoDist), {% endfor %}]
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, length($iPsoArrayPos), 0)
PsoDistanceEventsOn($axis)
PsoWaveformConfigureMode($axis, PsoWaveformMode.Toggle)
PsoWaveformOn($axis)
// Configure Drive Data Collection
var $iDdcArrayAddr as integer = 8388608
var $iDdcArraySize as integer = $iNumDdcRead
DriveDataCaptureConfigureInput($axis, 0, DriveDataCaptureInput.PrimaryFeedback);
DriveDataCaptureConfigureInput($axis, 1, DriveDataCaptureInput.AnalogInput0 );
DriveDataCaptureConfigureTrigger($axis, 0, DriveDataCaptureTrigger.PsoOutput );
DriveDataCaptureConfigureTrigger($axis, 1, DriveDataCaptureTrigger.PsoOutput );
DriveDataCaptureConfigureArray($axis, 0, $iDdcArrayAddr, $iDdcArraySize);
DriveDataCaptureConfigureArray($axis, 1, $iDdcArrayAddr + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
// Directly before scan
PsoDistanceCounterOn($axis)
DriveDataCaptureOn($axis, 0)
DriveDataCaptureOn($axis, 1)
///////////////////////////////////////////////////////////
// Start the actual scanning
///////////////////////////////////////////////////////////
for $ii = 0 to ($iNumRepeat-1)
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, length($iPsoArrayPos), 0)
if $eScanType == ScanType.Pos
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForInPosition($axis)
MoveAbsolute($axis, $fPosStart, $fVelScan)
WaitForInPosition($axis)
elseif $eScanType == ScanType.Neg
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForInPosition($axis)
MoveAbsolute($axis, $fPosStart, $fVelScan)
WaitForInPosition($axis)
elseif $eScanType == ScanType.PosNeg
if ($ii % 2) == 0
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForInPosition($axis)
elseif ($ii % 2) == 1
MoveAbsolute($axis, $fPosStart, $fVelScan)
WaitForInPosition($axis)
end
elseif $eScanType == ScanType.NegPos
if ($ii % 2) == 0
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForInPosition($axis)
elseif ($ii % 2) == 1
MoveAbsolute($axis, $fPosStart, $fVelScan)
WaitForInPosition($axis)
end
end
Dwell(0.2)
end
// Directly after scan
PsoDistanceCounterOff($axis)
DriveDataCaptureOff($axis, 0)
DriveDataCaptureOff($axis, 1)
end

View File

@ -1,87 +0,0 @@
// Snap-and-step
// Test program for high speed step scanning with individual triggers on PSO output.
// The file expects external parameter validation.
program
// External parameters
var $fStartPosition as real = {{ scan.startpos }}
var $iNumSteps as integer = {{ scan.numsteps }}
var $fStepSize as real = {{ scan.stepsize }}
var $fExposureTimeSec as real = {{ scan.exptime }}
var $fVelJog as real = {{ scan.travel or 200 }}
var $fVelScan as real = {{ scan.velocity or 50 }}
var $fAcceleration = {{ scan.acceleration or 500 }}
// Internal
var $axis as axis = ROTY
var $ii as integer
// Set acceleration
SetupAxisRampType($axis, RampType.Linear)
SetupAxisRampValue($axis,0,$fAcceleration)
// Move to start position before the scan
var $fPosNext as real = $fStartPosition
MoveAbsolute($axis, $fPosNext, $fVelJog)
WaitForInPosition($axis)
// Configure PSO (to manual event generation)
PsoDistanceEventsOff($axis)
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
PsoWaveformConfigurePulseFixedTotalTime($axis, 50)
PsoWaveformConfigurePulseFixedOnTime($axis, 20)
PsoWaveformConfigurePulseFixedCount($axis, 1)
PsoWaveformApplyPulseConfiguration($axis)
PsoWaveformConfigureMode($axis, PsoWaveformMode.Pulse)
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
PsoWaveformOn($axis)
// Configure Drive Data Collection
var $iDdcArrayAddr as integer = 8388608
var $iDdcArraySize as integer = iMaximum(5000, $iNumSteps)
var $iDdcSafeSpace as integer = 4096
DriveDataCaptureConfigureInput($axis, 0, DriveDataCaptureInput.PrimaryFeedback);
DriveDataCaptureConfigureInput($axis, 1, DriveDataCaptureInput.AnalogInput0 );
DriveDataCaptureConfigureTrigger($axis, 0, DriveDataCaptureTrigger.PsoOutput );
DriveDataCaptureConfigureTrigger($axis, 1, DriveDataCaptureTrigger.PsoOutput );
DriveDataCaptureConfigureArray($axis, 0, $iDdcArrayAddr, $iDdcArraySize);
DriveDataCaptureConfigureArray($axis, 1, $iDdcArrayAddr + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
// Directly before scan
PsoDistanceCounterOn($axis)
DriveDataCaptureOn($axis, 0)
DriveDataCaptureOn($axis, 1)
///////////////////////////////////////////////////////////
// Start the actual scanning
///////////////////////////////////////////////////////////
for $ii = 0 to ($iNumSteps-1)
MoveAbsolute($axis, $fPosNext, $fVelScan)
WaitForInPosition($axis)
PsoEventGenerateSingle($axis)
Dwell($fExposureTimeSec)
$fPosNext = $fPosNext + $fStepSize
end
// Directly after scan
PsoWaveformOff($axis)
DriveDataCaptureOff($axis, 0)
DriveDataCaptureOff($axis, 1)
end
// Demonstrates using a switch/case conditional.
function iMaximum($A as integer, $B as integer) as integer
var $retVal
if ($A > $B)
$retVal = $A
else
$retVal = $B
end
return $retVal
end

View File

@ -1,434 +0,0 @@
import enum
import os
import threading
import time as ttime
from bec_lib.logger import bec_logger
# from typing import Any
from ophyd import ADComponent as ADCpt
from ophyd import Component as Cpt
from ophyd import Device, EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV
# import numpy as np
from ophyd.ophydobj import Kind
from ophyd_devices.epics.devices.psi_detector_base import CustomDetectorMixin, PSIDetectorBase
# os.environ["EPICS_CA_AUTO_ADDR_LIST"] = "No"
# os.environ["EPICS_CA_ADDR_LIST"] = "129.129.208.143"
logger = bec_logger.logger
class GrashopperError(Exception):
"""Base class for Grashopper detector errors."""
class GrashopperTimeoutError(GrashopperError):
"""Base class for Grashopper detector errors."""
class AutoMode(enum.IntEnum):
"""Acquire time auto for Grashopper detector.
class for acquire_auto and gain_auto
Off: Gain tap balancing is user controlled using Gain.
Once: Gain tap balancing is automatically adjusted once by the device.
Once it has converged, it automatically returns to the Off state.
Continuous: Gain tap balancing is constantly adjusted by the device.
"""
OFF = 0
ONCE = 1
CONTINUOUS = 2
class ImageMode(enum.IntEnum):
"""Image mode for Grashopper detector.
Single: Acquire a single image, ignores NumImages PV
Multiple: Acquire NumImages images
Continuous: Acquire images continuously
"""
SINGLE = 0
MULTIPLE = 1
CONTINUOUS = 2
class DetectorState(enum.IntEnum):
"""Detector states for Grashopper detector"""
IDLE = 0
ACQUIRE = 1
READOUT = 2
CORRECT = 3
SAVING = 4
ABORTING = 5
ERROR = 6
WAITING = 7
INITIALIZING = 8
DISCONNECTED = 9
ABORTED = 10
class ImageBinning(enum.IntEnum):
"""Image binning for Grashopper detector"""
X1 = 1
X2 = 2
X4 = 4
class VideoMode(enum.IntEnum):
"""Video mode for Grashopper detector.
For details, consult EPICs IOC manual.
"""
MODE0 = 0
MODE1 = 1
MODE2 = 2
MODE3 = 3
class PixelFormat(enum.IntEnum):
"""Pixel format for Grashopper detector."""
MONO8 = 0
MONO12PACKED = 1
MONO12P = 2
MONO16 = 3
class COLORMODE(enum.IntEnum):
"""Color mode for Grashopper detector.
Only for readback values from color_mode RO PV.
"""
MONO = 0
BAYER = 1
RGB1 = 2
RGB2 = 3
RGB3 = 4
YUV444 = 5
YUV422 = 6
YUV421 = 7
class TriggerSource(enum.IntEnum):
"""Trigger signals for Grashopper detector"""
SOFTWARE = 0
LINE0 = 1
LINE2 = 2
LINE3 = 3
class MemoryPolling(enum.IntEnum):
"""Memory polling for Grashopper detector.
Defines update rate of memory polling for IOC (1s suggested).
"""
PASSIVE = 0
EVENT = 1
IOINTR = 2
SECONDS10 = 3
SECONDS5 = 4
SECONDS2 = 5
SECONDS1 = 6
SECONDS05 = 7
SECONDS02 = 8
SECONDS01 = 9
class GrashopperTOMCATSetup(CustomDetectorMixin):
"""Mixin class to setup TOMCAT specific implementations of the detector.
This class will be called by the custom_prepare_cls attribute of the detector class.
"""
def __init__(self, *_args, parent: Device = None, **_kwargs) -> None:
super().__init__(*_args, parent=parent, **_kwargs)
self.image_shape = (self.parent.cam.image_size_y.get(), self.parent.cam.image_size_x.get())
self.monitor_thread = None
self.stop_monitor = False
self.update_frequency = 1
self.low_frame_rate = 80
def initialize_detector(self) -> None:
"""Initialize detector."""
self.parent.cam.acquire.put(0)
self.parent.cam.acquire_time_auto.put(AutoMode.CONTINUOUS)
self.parent.cam.gain_auto.put(AutoMode.CONTINUOUS)
self.parent.cam.image_mode.put(ImageMode.MULTIPLE)
self.parent.cam.image_binning.put(ImageBinning.X1)
self.parent.cam.video_mode.put(VideoMode.MODE0)
self.parent.cam.pixel_format.put(PixelFormat.MONO16)
self.parent.cam.trigger_source.put(TriggerSource.SOFTWARE)
self.parent.cam.memory_polling.put(MemoryPolling.SECONDS1)
self.parent.cam.set_image_counter.put(0)
def initialize_detector_backend(self) -> None:
self.parent.image.queue_size.put(5)
self.parent.image.array_port.put(self.parent.cam.port_name.get())
self.parent.image.enable_cb.put(1)
self.parent.image.set_array_counter.put(0)
def set_exposure_time(self, exposure_time: float) -> None:
"""Set the detector framerate.
Args:
framerate (float): Desired framerate in Hz smallest is 87Hz
"""
framerate = 1 / exposure_time
if framerate > self.low_frame_rate:
raise GrashopperError(
f"Trying to set exposure time to {exposure_time}s, this is below the lowest"
f" possible exposure of {1/self.low_frame_rate}s"
)
self.parent.cam.frame_rate.put(framerate)
def prepare_detector(self) -> None:
"""Prepare detector for acquisition."""
self.parent.cam.image_mode.put(ImageMode.MULTIPLE)
self.parent.cam.acquire_time_auto.put(AutoMode.CONTINUOUS)
self.set_exposure_time(self.parent.scaninfo.exp_time)
self.parent.set_trigger(TriggerSource.SOFTWARE)
self.parent.cam.set_image_counter.put(0)
self.set_acquisition_params()
def set_acquisition_params(self) -> None:
"""Set acquisition parameters for the detector"""
# Set number of images and frames (frames is for internal burst of detector)
self.parent.cam.num_images.put(
int(self.parent.scaninfo.num_points * self.parent.scaninfo.frames_per_trigger)
)
def prepare_detector_backend(self) -> None:
"""Prepare detector backend for acquisition."""
self.parent.image.set_array_counter.put(0)
self.monitor_thread = None
self.stop_monitor = False
# self.run_monitor()
def arm_acquisition(self) -> None:
"""Arm grashopper detector for acquisition"""
self.parent.cam.acquire.put(1)
signal_conditions = [(self.parent.cam.detector_state.get, DetectorState.WAITING)]
if not self.wait_for_signals(
signal_conditions=signal_conditions,
timeout=self.parent.timeout,
check_stopped=True,
all_signals=False,
):
raise GrashopperTimeoutError(
f"Failed to arm the acquisition. Detector state {signal_conditions[0][0]}"
)
def on_trigger(self) -> None:
"""Trigger the detector"""
if self.parent.cam.trigger_source.get() == TriggerSource.SOFTWARE:
self.parent.cam.software_trigger_device.put(1)
ttime.sleep(0.1)
self.send_data()
def run_monitor(self) -> None:
"""
Run the monitor loop in a separate thread.
"""
self.monitor_thread = threading.Thread(target=self.monitor_loop, daemon=True)
self.monitor_thread.start()
def monitor_loop(self) -> None:
"""
Monitor the detector status and send data.
"""
while True:
self.send_data()
ttime.sleep(1 / self.update_frequency)
if self.parent.stopped:
break
def send_data(self) -> None:
"""Send data to monitor endpoint in redis."""
try:
img = self.parent.image.array_data.get().reshape(self.image_shape)
# pylint: disable=protected-access
self.parent._run_subs(sub_type=self.parent.SUB_VALUE, value=img)
except Exception as e:
logger.debug(f"{e} for image with shape {self.parent.image.array_data.get().shape}")
def stop_detector(self) -> None:
"""Stop detector."""
self.parent.cam.acquire.put(0)
signal_conditions = [(self.parent.cam.detector_state.get, DetectorState.IDLE)]
if not self.wait_for_signals(
signal_conditions=signal_conditions,
timeout=self.parent.timeout - self.parent.timeout // 2,
check_stopped=True,
all_signals=False,
):
# Retry stop detector and wait for remaining time
self.parent.cam.acquire.put(0)
if not self.wait_for_signals(
signal_conditions=signal_conditions,
timeout=self.parent.timeout - self.parent.timeout // 2,
check_stopped=True,
all_signals=False,
):
raise GrashopperTimeoutError(
f"Failed to stop detector, detector state {signal_conditions[0][0]}"
)
def stop_detector_backend(self) -> None:
"""Stop the data backend sending data."""
self.stop_monitor = True
class SLSDetectorCam(Device):
"""
SLS Detector Camera - Grashoppter
Base class to map EPICS PVs to ophyd signals.
"""
## Deprecated PVs, to be checked!
# acquire_time = ADCpt(EpicsSignal, "AcquireTime", kind=Kind.omitted)
# num_exposures = ADCpt(EpicsSignal, "NumExposures", kind=Kind.omitted)
# acquire_period = ADCpt(EpicsSignalWithRBV, "AcquirePeriod", kind=Kind.config)
# Control PVs
acquire_time_auto = ADCpt(EpicsSignal, "AcquireTimeAuto", kind=Kind.config)
frame_rate = ADCpt(EpicsSignalWithRBV, "FrameRate", kind=Kind.normal)
num_images = ADCpt(EpicsSignalWithRBV, "NumImages", kind=Kind.normal)
num_images_counter = ADCpt(EpicsSignalRO, "NumImagesCounter_RBV", kind=Kind.normal)
image_mode = ADCpt(EpicsSignalWithRBV, "ImageMode", kind=Kind.config)
acquire = ADCpt(EpicsSignalWithRBV, "Acquire", kind=Kind.config)
detector_state = ADCpt(EpicsSignalRO, "DetectorState_RBV", kind=Kind.normal)
status_message = ADCpt(EpicsSignalRO, "StatusMessage_RBV", string=True, kind=Kind.config)
set_image_counter = ADCpt(EpicsSignal, "ArrayCounter", kind=Kind.config)
image_counter = ADCpt(EpicsSignal, "ArrayCounter_RBV", kind=Kind.normal)
image_rate = ADCpt(EpicsSignalRO, "ArrayRate_RBV", kind=Kind.omitted)
# Asyn Port name
port_name = ADCpt(EpicsSignalRO, "PortName_RBV", string=True, kind=Kind.omitted)
# Readout related PVs
max_image_size_x = ADCpt(EpicsSignalRO, "MaxSizeX_RBV", kind=Kind.config)
max_image_size_y = ADCpt(EpicsSignalRO, "MaxSizeY_RBV", kind=Kind.config)
image_size_x = ADCpt(EpicsSignalRO, "ArraySizeX_RBV", kind=Kind.config)
image_size_y = ADCpt(EpicsSignalRO, "ArraySizeY_RBV", kind=Kind.config)
# Only BinY PV is working, sets both
image_binning = ADCpt(EpicsSignalWithRBV, "BinY", kind=Kind.config)
gain = ADCpt(EpicsSignalWithRBV, "Gain", kind=Kind.config)
gain_auto = ADCpt(EpicsSignalWithRBV, "GainAuto", kind=Kind.config)
video_mode = ADCpt(EpicsSignalWithRBV, "VideoMode", kind=Kind.config)
pixel_format = ADCpt(EpicsSignalWithRBV, "PixelFormat", kind=Kind.config)
# Desired to set this in future?
color_mode = ADCpt(EpicsSignalRO, "ColorMode_RBV", kind=Kind.config)
# HW Status PVs
temperature_actual = ADCpt(EpicsSignal, "TemperatureActual", kind=Kind.omitted)
# Trigger
trigger_mode_active = ADCpt(EpicsSignalWithRBV, "TriggerMode", kind=Kind.config)
trigger_source = ADCpt(EpicsSignalWithRBV, "TriggerSource", kind=Kind.config)
trigger_delay = ADCpt(EpicsSignalWithRBV, "TriggerDelay", kind=Kind.omitted)
exposure_mode = ADCpt(EpicsSignalWithRBV, "ExposureMode", kind=Kind.omitted)
software_trigger_device = ADCpt(EpicsSignal, "SoftwareTrigger", kind=Kind.config)
# buffer
memory_polling = ADCpt(EpicsSignal, "PoolUsedMem.SCAN", kind=Kind.omitted)
class SLSImagePlugin(Device):
"""SLS Image Plugin
Image plugin for SLS detector imitating the behaviour of ImagePlugin from
ophyd's areadetector plugins.
"""
# Control
array_port = Cpt(EpicsSignal, "NDArrayPort", kind=Kind.omitted, string=True)
enable_cb = Cpt(EpicsSignal, "EnableCallbacks", kind=Kind.config)
queue_size = Cpt(EpicsSignal, "QueueSize", kind=Kind.config)
set_array_counter = Cpt(EpicsSignal, "ArrayCounter", kind=Kind.config)
array_counter = Cpt(EpicsSignal, "ArrayCounter_RBV", kind=Kind.normal)
set_dropped_arrays = Cpt(EpicsSignal, "DroppedArrays", kind=Kind.config)
dropped_arrays = Cpt(EpicsSignal, "DroppedArrays_RBV", kind=Kind.normal)
image_id = Cpt(EpicsSignal, "UniqueId_RBV", kind=Kind.normal)
# Data
array_data = Cpt(EpicsSignal, "ArrayData", kind=Kind.omitted)
# Size related PVs from Plugin
array_size_0 = Cpt(EpicsSignalRO, "ArraySize0_RBV", kind=Kind.omitted)
array_size_1 = Cpt(EpicsSignalRO, "ArraySize1_RBV", kind=Kind.omitted)
array_size_2 = Cpt(EpicsSignalRO, "ArraySize2_RBV", kind=Kind.omitted)
array_dimension_size = Cpt(EpicsSignalRO, "NDimensions_RBV", kind=Kind.omitted)
class GrashopperTOMCAT(PSIDetectorBase):
"""
Grashopper detector for TOMCAT
Parent class: PSIDetectorBase
class attributes:
custom_prepare_cls (GrashopperTOMCATSetup) : Custom detector setup class for TOMCAT,
inherits from CustomDetectorMixin
cam (SLSDetectorCam) : Detector camera
image (SLSImagePlugin) : Image plugin for detector
"""
# Specify which functions are revealed to the user in BEC client
USER_ACCESS = ["describe"]
SUB_MONITOR = "monitor"
SUB_VALUE = "value"
_default_sub = SUB_VALUE
# specify Setup class
custom_prepare_cls = GrashopperTOMCATSetup
# specify minimum readout time for detector
MIN_READOUT = 0
# specify class attributes
cam = ADCpt(SLSDetectorCam, "cam1:")
image = ADCpt(SLSImagePlugin, "image1:")
def stage(self) -> list[object]:
rtr = super().stage()
self.custom_prepare.arm_acquisition()
return rtr
def unstage(self) -> list[object]:
rtr = super().unstage()
self.custom_prepare.stop_monitor = True
return rtr
def set_trigger(self, trigger_source: TriggerSource) -> None:
"""Set trigger source for the detector.
Check the TriggerSource enum for possible values
Args:
trigger_source (TriggerSource): Trigger source for the detector
"""
value = trigger_source
self.cam.trigger_source.put(value)
if __name__ == "__main__":
hopper = GrashopperTOMCAT(name="hopper", prefix="X02DA-PG-USB:", sim_mode=True)
hopper.wait_for_connection(all_signals=True)

View File

@ -1,59 +0,0 @@
""" TODO This class was never properly tested, it is solely a first draft and should be tested and extended before use! """
from ophyd import Component as Cpt
from ophyd import Device, EpicsSignal, EpicsSignalRO
class SequencerX12SA(Device):
"""Sequencer for flyscans with epics motor controller and owis stages"""
desired_output_link_1 = Cpt(Signal, "DOL1")
desired_output_value_1 = Cpt(EpicsSignal, "DO1")
output_link_1 = Cpt(EpicsSignal, "LNK1")
delay_time_1 = Cpt(EpicsSignal, "DLY1")
desired_output_link_2 = Cpt(EpicsSignal, "DOL2")
desired_output_value_2 = Cpt(EpicsSignal, "DO2")
output_link_2 = Cpt(EpicsSignal, "LNK2")
delay_time_2 = Cpt(EpicsSignal, "DLY2")
select_mechanism = Cpt(EpicsSignal, "SELM", string=True)
link_selection = Cpt(EpicsSignal, "SELN")
process = Cpt(EpicsSignal, "PROC", string=True)
status = Cpt(EpicsSignalRO, "STAT", string=True)
processing_active = Cpt(EpicsSignalRO, "PACT")
# def __init__(
# self,
# prefix="",
# *,
# name,
# kind=None,
# read_attrs=None,
# configuration_attrs=None,
# parent=None,
# **kwargs
# ):
# # get configuration attributes from kwargs and then remove them
# attrs = {}
# for key, value in kwargs.items():
# if hasattr(EpicsMotorEx, key) and isinstance(getattr(EpicsMotorEx, key), Cpt):
# attrs[key] = value
# for key in attrs:
# kwargs.pop(key)
# super().__init__(
# prefix,
# name=name,
# kind=kind,
# read_attrs=read_attrs,
# configuration_attrs=configuration_attrs,
# parent=parent,
# **kwargs
# )
# # set configuration attributes
# for key, value in attrs.items():
# # print out attributes that are being configured
# print("setting ", key, "=", value)
# getattr(self, key).put(value)

View File

@ -5,7 +5,7 @@ from ophyd import Component as Cpt
from ophyd import EpicsMotor
from typeguard import typechecked
from ophyd_devices.ophyd_base_devices.bec_protocols import BECRotationProtocol
from ophyd_devices.interfaces.protocols.bec_protocols import BECRotationProtocol
from ophyd_devices.utils.bec_utils import ConfigSignal
logger = bec_logger.logger

View File

@ -1,10 +0,0 @@
from .bec_protocols import (
BECDeviceProtocol,
BECFlyerProtocol,
BECMixinProtocol,
BECPositionerProtocol,
BECRotationProtocol,
BECScanProtocol,
BECSignalProtocol,
)
from .tomcat_rotation_motors import TomcatAerotechRotation

View File

@ -1,183 +0,0 @@
""" Module for Tomcat rotation motors.
The following classes implement the rotation motors for:
- AerotechAutomation1 (Tomcat), based on EpicsMotorIOC.
"""
import threading
import time
import numpy as np
from bec_lib import threadlocked
from ophyd import DeviceStatus
from ophyd_devices.ophyd_base_devices.bec_protocols import BECFlyerProtocol, BECScanProtocol
from ophyd_devices.ophyd_base_devices.ophyd_rotation_base import EpicsRotationBase
class TomcatAerotechRotation(EpicsRotationBase, BECFlyerProtocol, BECScanProtocol):
"""Special motor class that provides flyer interface and progress bar."""
SUB_PROGRESS = "progress"
def __init__(
self,
prefix="",
*,
name,
kind=None,
read_attrs=None,
configuration_attrs=None,
parent=None,
**kwargs,
):
"""Implementation of the Tomcat AerotechAutomation 1 rotation motor class.
This motor class is based on EpicsRotationBase and provides in addition the flyer interface for BEC
and a progress update.
"""
super().__init__(
prefix=prefix,
name=name,
kind=kind,
read_attrs=read_attrs,
configuration_attrs=configuration_attrs,
parent=parent,
**kwargs,
)
self._start_position = None
self._target_position = None
self._stopped = False
self._rlock = threading.RLock()
self.subscribe(self._progress_update, run=False)
# ------------------ alternative to using configure method --------------------- #
@property
def start_position(self) -> float:
"""Get the start position."""
return self._start_position
@start_position.setter
def start_position(self, value: float) -> None:
"""Set the start position."""
self._start_position = value
@property
def target_position(self) -> float:
"""Get the start position."""
return self._target_position
@target_position.setter
def target_position(self, value: float) -> None:
"""Set the start position."""
self._target_position = value
# ------------------ alternative to using configure method --------------------- #
# configure method is optional for flyers within BEC, you can use stage method or pre_scan method to
# set relevant parameters on the device.
# def configure(self, d: dict) -> dict:
# """Configure method from the device.
# This method is usually used to set configuration parameters for the device.
# Args:
# d (dict): Dictionary with configuration parameters.
# """
# if "target" in d:
# self._target_position = d["target"]
# del d["target"]
# if "position" in d:
# self._target_position = d["position"]
# del d["position"]
# return super().configure(d)
def pre_scan(self):
"""Perform pre-scan operation, e.g. move to start position."""
if self._start_position:
self.move(self._start_position, wait=True)
def kickoff(self) -> DeviceStatus:
"""Kickoff the scan.
The kickoff method should return a status object that is set to finish once the flyer flys, and is ready for the next actions.
I would consider the following implementation.
"""
self._start_position = float(self.position)
self.move(self._target_position, wait=False)
status = DeviceStatus(self)
status.set_finished()
return status
def complete(self) -> DeviceStatus:
"""Complete method of the scan.
This will be called in a fly scan after the kickoff, thus, the stage will be moving to it's target position.
It should
The complete method should return a status object that is set to finish once the flyer is done and the scan is complete.
I would consider the following implementation.
"""
threading.Thread(target=self._is_motor_moving, daemon=True).start()
status = DeviceStatus(self)
self.subscribe(status.set_finished, event_type=self.SUB_DONE, run=False)
return status
def stage(self) -> list[object]:
"""Stage the scan.
We add here in addition the setting of the _stopped flag to False for the thread.
"""
self._stopped = False
return super().stage()
def stop(self, success: bool = False) -> None:
"""Stop the scan.
If the device is stopped, the _stopped flag is set to True.
"""
self._stopped = True
super().stop(success=success)
@threadlocked
def _is_motor_moving(self):
"""Function to check if the motor is moving.
This function is used in a thread to check if the motor is moving.
It resolves by running"""
while self.motor_done_move.get():
if self._stopped:
self._done_moving(success=False)
return
time.sleep(0.1)
self._done_moving(success=True)
# TODO This logic could be refined to be more robust for various scan types, i.e. at the moment it just takes
# the start and target position and calculates the progress based on the current position.
def _progress_update(self, value, **kwargs) -> None:
"""Progress update on the scan.
Runs the progress update on the device progress during the scan.
It uses the SUB_PROGRESS event from ophyd to update BEC about the progress.
Scans need to be aware which device progress is relevant for the scan.
Args:
value (float): The value of the motor position.
"""
if (self._start_position is None) or (self._target_position is None) or (not self.moving):
self._run_subs(sub_type=self.SUB_PROGRESS, value=1, max_value=1, done=1)
return
progress = np.abs(
(value - self._start_position) / (self._target_position - self._start_position)
)
max_value = 100
self._run_subs(
sub_type=self.SUB_PROGRESS,
value=int(100 * progress),
max_value=max_value,
done=int(np.isclose(max_value, progress, 1e-3)),
)

View File

@ -1,51 +0,0 @@
import inspect
import lmfit
class LmfitModelMixin:
# def __init__(self):
# self.model = lmfit.models.GaussianModel()
# self.params = self.model.make_params()
# self.params["center"].set(value=0)
# self.params["amplitude"].set(value=1)
# self.params["sigma"].set(value=1)
@staticmethod
def available_models() -> dict:
"""
Get available models from lmfit.models.
Exclude Gaussian2dModel, ExpressionModel, Model, SplineModel.
"""
avail_models = {}
for name, model_cls in inspect.getmembers(lmfit.models):
try:
is_model = issubclass(model_cls, lmfit.model.Model)
except TypeError:
is_model = False
if is_model and name not in [
"Gaussian2dModel",
"ExpressionModel",
"Model",
"SplineModel",
]:
avail_models[name] = model_cls
return avail_models
def create_properties(self):
"""
Create properties for model parameters.
"""
for name in self.available_models():
setattr(self, name, param)
@staticmethod
def get_model(model: str) -> lmfit.Model:
"""Get model for given string."""
if isinstance(model, str):
model = getattr(lmfit.models, model, None)
if not model:
raise ValueError(f"Model {model} not found.")
return model

View File

@ -1,226 +0,0 @@
# pylint: skip-file
from unittest import mock
import pytest
from ophyd_devices.epics.devices.grashopper_tomcat import (
COLORMODE,
AutoMode,
DetectorState,
GrashopperError,
GrashopperTimeoutError,
GrashopperTOMCATSetup,
ImageBinning,
ImageMode,
MemoryPolling,
PixelFormat,
TriggerSource,
VideoMode,
)
def patch_dual_pvs(device):
for walk in device.walk_signals():
if not hasattr(walk.item, "_read_pv"):
continue
if not hasattr(walk.item, "_write_pv"):
continue
if walk.item._read_pv.pvname.endswith("_RBV"):
walk.item._read_pv = walk.item._write_pv
@pytest.fixture(scope="function")
def mock_GrashopperSetup():
mock_Grashopper = mock.MagicMock()
yield GrashopperTOMCATSetup(parent=mock_Grashopper)
# Fixture for scaninfo
@pytest.fixture(
params=[
{
"scan_id": "1234",
"scan_type": "step",
"num_points": 500,
"frames_per_trigger": 1,
"exp_time": 0.1,
"readout_time": 0.1,
},
{
"scan_id": "1234",
"scan_type": "step",
"num_points": 500,
"frames_per_trigger": 5,
"exp_time": 0.01,
"readout_time": 0,
},
{
"scan_id": "1234",
"scan_type": "fly",
"num_points": 500,
"frames_per_trigger": 1,
"exp_time": 1,
"readout_time": 0.2,
},
{
"scan_id": "1234",
"scan_type": "fly",
"num_points": 500,
"frames_per_trigger": 5,
"exp_time": 0.1,
"readout_time": 0.4,
},
]
)
def scaninfo(request):
return request.param
def test_initialize_detector(mock_GrashopperSetup):
"""Test the initialize_detector method."""
# Call the function you want to test
mock_GrashopperSetup.initialize_detector()
# Assert the correct methods are called with the expected arguments
mock_GrashopperSetup.parent.cam.acquire.put.assert_called_once_with(0)
mock_GrashopperSetup.parent.cam.acquire_time_auto.put.assert_called_once_with(
AutoMode.CONTINUOUS
)
mock_GrashopperSetup.parent.cam.gain_auto.put.assert_called_once_with(AutoMode.CONTINUOUS)
mock_GrashopperSetup.parent.cam.image_mode.put.assert_called_once_with(ImageMode.MULTIPLE)
mock_GrashopperSetup.parent.cam.image_binning.put.assert_called_once_with(ImageBinning.X1)
mock_GrashopperSetup.parent.cam.video_mode.put.assert_called_once_with(VideoMode.MODE0)
mock_GrashopperSetup.parent.cam.pixel_format.put.assert_called_once_with(PixelFormat.MONO16)
mock_GrashopperSetup.parent.cam.trigger_source.put.assert_called_once_with(
TriggerSource.SOFTWARE
)
mock_GrashopperSetup.parent.cam.memory_polling.put.assert_called_once_with(
MemoryPolling.SECONDS1
)
mock_GrashopperSetup.parent.cam.set_image_counter.put.assert_called_once_with(0)
def test_initialize_detector_backend(mock_GrashopperSetup):
"""Test the initialize_detector_backend method."""
# Call the function you want to test
mock_GrashopperSetup.initialize_detector_backend()
# Assert the correct methods are called with the expected arguments
mock_GrashopperSetup.parent.image.queue_size.put.assert_called_once_with(5)
mock_GrashopperSetup.parent.image.array_port.put.assert_called_once_with(
mock_GrashopperSetup.parent.cam.port_name.get()
)
mock_GrashopperSetup.parent.image.enable_cb.put.assert_called_once_with(1)
mock_GrashopperSetup.parent.image.set_array_counter.put.assert_called_once_with(0)
@pytest.mark.parametrize("exposure_time", [1, 0.1, 0.01, 0.001, 0.0001])
def test_set_exposure_time(mock_GrashopperSetup, exposure_time):
"""Test the set_exposure_time method."""
# Call the function you want to test
frame_rate = 1 / exposure_time
if frame_rate > mock_GrashopperSetup.low_frame_rate:
with pytest.raises(GrashopperError):
mock_GrashopperSetup.set_exposure_time(exposure_time)
else:
mock_GrashopperSetup.set_exposure_time(exposure_time)
mock_GrashopperSetup.parent.cam.frame_rate.put.assert_called_once_with(frame_rate)
def test_prepare_detector(mock_GrashopperSetup, scaninfo):
"""Test the prepare_detector method."""
# setup scaninof
for k, v in scaninfo.items():
setattr(mock_GrashopperSetup.parent.scaninfo, k, v)
# Call the function you want to test
with (
mock.patch.object(
mock_GrashopperSetup, "set_acquisition_params"
) as mock_set_acquisition_params,
mock.patch.object(mock_GrashopperSetup, "set_exposure_time") as mock_set_exposure_time,
):
mock_GrashopperSetup.prepare_detector()
# Assert the correct methods are called with the expected arguments
mock_GrashopperSetup.parent.cam.image_mode.put.assert_called_once_with(ImageMode.MULTIPLE)
mock_GrashopperSetup.parent.cam.acquire_time_auto.put.assert_called_once_with(
AutoMode.CONTINUOUS
)
mock_GrashopperSetup.parent.set_trigger.assert_called_once_with(TriggerSource.SOFTWARE)
mock_GrashopperSetup.parent.cam.set_image_counter.put.assert_called_once_with(0)
mock_set_acquisition_params.assert_called_once()
mock_set_exposure_time.assert_called_once_with(scaninfo["exp_time"])
def test_prepare_detector_backend(mock_GrashopperSetup):
"""Test the prepare_detector_backend method."""
# Call the function you want to test
mock_GrashopperSetup.prepare_detector_backend()
mock_GrashopperSetup.parent.image.set_array_counter.put.assert_called_once_with(0)
assert mock_GrashopperSetup.monitor_thread is None
assert not mock_GrashopperSetup.stop_monitor
@pytest.mark.parametrize("detector_state", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
def test_arm_acquisition(mock_GrashopperSetup, detector_state):
"""Test the arm_acquisition method."""
# Call the function you want to test
mock_GrashopperSetup.parent.cam.detector_state.get.return_value = detector_state
mock_GrashopperSetup.parent.timeout = 0.1
if detector_state != DetectorState.WAITING:
with pytest.raises(GrashopperTimeoutError):
mock_GrashopperSetup.arm_acquisition()
assert mock_GrashopperSetup.parent.cam.acquire.put.call_count == 1
assert mock_GrashopperSetup.parent.cam.acquire.put.call_args == mock.call(1)
else:
mock_GrashopperSetup.arm_acquisition()
assert mock_GrashopperSetup.parent.cam.acquire.put.call_count == 1
assert mock_GrashopperSetup.parent.cam.acquire.put.call_args == mock.call(1)
@pytest.mark.parametrize("trigger_source", [0, 1, 2, 3])
def test_on_trigger(mock_GrashopperSetup, trigger_source):
"""Test the on_trigger method."""
# Call the function you want to test
mock_GrashopperSetup.parent.cam.trigger_source.get.return_value = trigger_source
with mock.patch.object(mock_GrashopperSetup, "send_data") as mock_send_data:
mock_GrashopperSetup.on_trigger()
# Assert the correct methods are called with the expected arguments
if trigger_source == TriggerSource.SOFTWARE:
mock_GrashopperSetup.parent.cam.software_trigger_device.put.assert_called_once_with(1)
assert mock_send_data.call_count == 1
def test_set_acquisition_params(mock_GrashopperSetup, scaninfo):
"""Test the set_acquisition_params method."""
# Setup scaninfo
mock_GrashopperSetup.parent.scaninfo.num_points = scaninfo["num_points"]
mock_GrashopperSetup.parent.scaninfo.frames_per_trigger = scaninfo["frames_per_trigger"]
# Call the function you want to test
mock_GrashopperSetup.set_acquisition_params()
# Assert the correct methods are called with the expected arguments
expected_num_images = scaninfo["num_points"] * scaninfo["frames_per_trigger"]
mock_GrashopperSetup.parent.cam.num_images.put.assert_called_once_with(expected_num_images)
@pytest.mark.parametrize("detector_state", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
def test_stop_detector(mock_GrashopperSetup, detector_state):
"""Test the arm_acquisition method."""
# Call the function you want to test
mock_GrashopperSetup.parent.cam.detector_state.get.return_value = detector_state
mock_GrashopperSetup.parent.timeout = 0.1
if detector_state != DetectorState.IDLE:
with pytest.raises(GrashopperTimeoutError):
mock_GrashopperSetup.stop_detector()
assert mock_GrashopperSetup.parent.cam.acquire.put.call_count == 2
assert mock_GrashopperSetup.parent.cam.acquire.put.call_args == mock.call(0)
else:
mock_GrashopperSetup.stop_detector()
assert mock_GrashopperSetup.parent.cam.acquire.put.call_count == 1
assert mock_GrashopperSetup.parent.cam.acquire.put.call_args == mock.call(0)

View File

@ -10,7 +10,7 @@ import pytest
from bec_server.device_server.tests.utils import DMMock
from ophyd import Device, Signal
from ophyd_devices.ophyd_base_devices.bec_protocols import (
from ophyd_devices.interfaces.protocols.bec_protocols import (
BECDeviceProtocol,
BECFlyerProtocol,
BECPositionerProtocol,