diff --git a/ophyd_devices/epics/__init__.py b/ophyd_devices/epics/__init__.py index b422915..acc98fd 100644 --- a/ophyd_devices/epics/__init__.py +++ b/ophyd_devices/epics/__init__.py @@ -21,3 +21,6 @@ from .devices.specMotors import ( ) from .devices.SpmBase import SpmBase from .devices.XbpmBase import XbpmBase, XbpmCsaxsOp + +# X07MA specific devices +from .devices.X07MADevices import * diff --git a/ophyd_devices/epics/db/x07ma_database.yml b/ophyd_devices/epics/db/x07ma_database.yml new file mode 100644 index 0000000..13718cd --- /dev/null +++ b/ophyd_devices/epics/db/x07ma_database.yml @@ -0,0 +1,111 @@ +slsinfo: + desc: 'SLS beam info' + deviceClass: SLSInfo + deviceConfig: {name: slsinfo} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +undulator: + desc: 'Undulator' + deviceClass: X07MAUndulator + deviceConfig: {name: undulator, prefix: 'X07MA-ID:'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +aperture: + desc: 'Frontend aperture' + deviceClass: EpicsSignal + deviceConfig: {name: aperture, read_pv: 'X07MA-FE-DSAPER'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +mono: + desc: 'PGM Monochromator' + deviceClass: PGMMonochromator + deviceConfig: {name: mono, prefix: 'X07MA-'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +otf: + desc: 'PGM on-the-fly scan' + deviceClass: PGMOtFScan + deviceConfig: {name: temperature} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +valve: + desc: 'Endstation valve' + deviceClass: VacuumValve + deviceConfig: {name: valve, prefix: 'X07MA-OP-VG13:'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +exit_slit: + desc: 'Exit slit' + deviceClass: X07MAExitSlit + deviceConfig: {name: exit_slit, prefix: 'X07MA-OP-SL1SV1:'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +goldmesh1: + desc: 'Gold mesh 1' + deviceClass: EpicsMotor + deviceConfig: {name: goldmesh1, prefix: 'X07MA-OP-IO1:TR1'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +goldmesh2: + desc: 'Gold mesh 2' + deviceClass: EpicsMotor + deviceConfig: {name: goldmesh2, prefix: 'X07MA-OP-IO2:TR1'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +field: + desc: 'Magnetic field' + deviceClass: X07MAMagnet + deviceConfig: {name: field, prefix: 'X07MA-PC-MAG:'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +signals: + desc: 'ADC signals' + deviceClass: X07MAAnalogSignals + deviceConfig: {name: signals, prefix: 'X07MA-ES1-AI:'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +manipulator: + desc: 'Sample Manipulator' + deviceClass: X07MASampleManipulator + deviceConfig: {name: manipulator, prefix: 'X07MA-ES1-MAG'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +temperature: + desc: 'Temperature controller' + deviceClass: X07MATemperatureController + deviceConfig: {name: temperature, prefix: 'X07MA-PC-TC:'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} + +TControl: + desc: 'Automatic temperature control' + deviceClass: X07MAAutoTemperatureControl + deviceConfig: {name: 'TControl', prefix: 'X07MA-ES1-TEMP:'} + acquisitionConfig: {acquisitionGroup: monitor, readoutPriority: baseline, schedule: sync} + onFailure: raise + status: {enabled: true} diff --git a/ophyd_devices/epics/devices/X07MADevices.py b/ophyd_devices/epics/devices/X07MADevices.py new file mode 100644 index 0000000..5a5c115 --- /dev/null +++ b/ophyd_devices/epics/devices/X07MADevices.py @@ -0,0 +1,161 @@ +""" +ophyd device classes for X07MA beamline +""" +from typing import Any + +from ophyd import Component as Cpt +from ophyd import FormattedComponent as FCpt + +from ophyd import ( + Device, + EpicsSignal, + EpicsSignalRO, + Kind, + PVPositioner, + EpicsMotor +) +from ophyd.pv_positioner import PVPositionerComparator + +__all__ = ["X07MAUndulator", "PGMMonochromator", "PGMOtFScan", "VacuumValve", "X07MAExitSlit", + "X07MAMagnet", "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") + error = Cpt(EpicsSignal, "ERROR", auto_monitor=True) + +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, "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) + +class PGMOtFScan(Device): + """ + PGM on-the-fly scan + """ + e1 = Cpt(EpicsSignal, "E1") + e2 = Cpt(EpicsSignal, "E2") + time = Cpt(EpicsSignal, 'TIME') + folder = Cpt(EpicsSignal, 'FOLDER') + file = Cpt(EpicsSignal, 'FILE') + start = Cpt(EpicsSignal, 'START') + +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) + + 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) + +class X07MAMagnet(Device): + """ + Magnet fields. + """ + class MagnetAxis(PVPositioner): + """ + A single magnet field axis. + """ + done_value = 2 + 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, '{_ps_prefix}STS:RAMP:MADE', kind=Kind.omitted, 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) + + 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 X07MAAnalogSignals(Device): + """ + ADC inputs + """ + s1 = Cpt(EpicsSignalRO, "SIGNAL0") + s2 = Cpt(EpicsSignalRO, "SIGNAL1") + s3 = Cpt(EpicsSignalRO, "SIGNAL2") + s4 = Cpt(EpicsSignalRO, "SIGNAL3") + s5 = Cpt(EpicsSignalRO, "SIGNAL4") + s6 = Cpt(EpicsSignalRO, "SIGNAL5") + s7 = Cpt(EpicsSignalRO, "SIGNAL6") + s8 = Cpt(EpicsSignalRO, "SIGNAL7") + + # 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 + """ + manual_output = 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) + +class X07MAAutoTemperatureControl(Device): + """ + Automatic temperature control. + """ + control = Cpt(EpicsSignal, 'CONTROL') + status = Cpt(EpicsSignalRO, 'STATUS', kind=Kind.hinted, auto_monitor=True)