From cef09c1de1c0dda1f1b47ee1db243cdc77d413b7 Mon Sep 17 00:00:00 2001 From: Kaushik Malapati Date: Wed, 25 Oct 2023 13:46:23 -0700 Subject: [PATCH 1/6] Initial commit for tpr class (broken) --- pcdsdevices/tpr.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 pcdsdevices/tpr.py diff --git a/pcdsdevices/tpr.py b/pcdsdevices/tpr.py new file mode 100644 index 00000000000..054958678b3 --- /dev/null +++ b/pcdsdevices/tpr.py @@ -0,0 +1,83 @@ +from ophyd import Component as Cpt +from ophyd import Device, EpicsSignal, EpicsSignalRO +from ophyd import FormattedComponent as FCpt + +from .interface import BaseInterface +from .pv_positioner import PVPositionerIsClose +from .signal import MultiDerivedSignal +from .type_hints import SignalToValue + +TPR_TICK_NS = 5.384 +TPR_TAP_NS = 0.08 + + +def _get_delay(mds: MultiDerivedSignal, items: SignalToValue) -> float: + return items[mds.attrs[0]] * TPR_TICK_NS + items[mds.attrs[1] * TPR_TAP_NS] + + +def _get_width(mds: MultiDerivedSignal, items: SignalToValue) -> float: + return items[mds.attrs[0]] * TPR_TICK_NS + + +def _put_last(mds: MultiDerivedSignal, value: float) -> SignalToValue: + return {mds.attrs[-1]: value} + + +class TprMotor(PVPositionerIsClose): + """ + PV Positioner for adjusting an TPR channel. + + Moves that are less than one tick + are considered immediately complete. + """ + setpoint = FCpt(EpicsSignal, "{self.prefix}{self.sys}TDES", kind="normal") + readback = Cpt(EpicsSignalRO, ":BW_TDES", kind="hinted") + atol = TPR_TICK_NS + rtol = 0 + + def __init__(self, prefix, *, sys, name, **kwargs): + self.sys = sys + super().__init__(prefix, name=name, **kwargs) + + +class TprTrigger(BaseInterface, Device): + """Class for an individual TprTrigger.""" + eventcode = FCpt(EpicsSignal, '{self.prefix}{self.ch}EVCODE', kind="config") + eventrate = FCpt(EpicsSignalRO, '{self.prefix}{self.ch}RATE', kind="normal") + label = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys}TCTL.DESC', kind="omitted") + label2 = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys2}TCTL.DESC', kind="omitted") + ns_delay = FCpt( + EpicsSignal, + ':BW_TDES', + write_pv=':TDES', + tolerance=TPR_TICK_NS, + kind="hinted", + ) + ns_delay_scan = FCpt(TprMotor, '', sys='{self.sys}', kind="omitted") + polarity = FCpt(EpicsSignal, '{self.prefix}{self.trg}TPOL', kind="config") + width = FCpt( + MultiDerivedSignal, + attrs=['{self.prefix}{self.trg}TWIDTICKS', '{self.prefix}{self.sys}TWID'], + calculate_on_get=_get_width, + calculate_on_put=_put_last, + ) + enable_cmd = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys}TCTL', kind="omitted") + enable_cmd2 = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys2}TCTL', kind="omitted") + + tab_whitelist = ['enable', 'disable'] + tab_component_names = True + + def __init__(self, prefix, *, channel, name, **kwargs): + self.ch = f':CH{channel:02}_' + self.trg = f':TRG{channel:02}_' + self.sys = 'SYS0_' + self.sys2 = 'SYS2_' + super().__init__(prefix, name=name, **kwargs) + + def enable(self): + """Enable the trigger.""" + self.enable_cmd.put(1) + + def disable(self): + """Disable the trigger.""" + self.enable_cmd.put(0) From 2e738c249808eb7138b622a925018957d952c4cc Mon Sep 17 00:00:00 2001 From: Kaushik Malapati Date: Wed, 25 Oct 2023 14:07:49 -0700 Subject: [PATCH 2/6] TST: adding basic tpr test --- pcdsdevices/tests/test_tpr.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 pcdsdevices/tests/test_tpr.py diff --git a/pcdsdevices/tests/test_tpr.py b/pcdsdevices/tests/test_tpr.py new file mode 100644 index 00000000000..c65618c2a68 --- /dev/null +++ b/pcdsdevices/tests/test_tpr.py @@ -0,0 +1,22 @@ +import pytest +from ophyd.sim import make_fake_device + +from ..tpr import TprTrigger + + +@pytest.fixture(scope='function') +def fake_trigger(): + cls = make_fake_device(TprTrigger) + return cls('TST:TPR', channel=1, name='trig_a') + + +def test_enable(fake_trigger): + fake_trigger.enable() + assert fake_trigger.enable_cmd.get() == 1 + fake_trigger.disable() + assert fake_trigger.enable_cmd.get() == 0 + + +@pytest.mark.timeout(5) +def test_disconnected_trigger(): + TprTrigger('TST', channel=1, name='test') From fc15600848e57fc69147c9ab06ac5b3e14cd4645 Mon Sep 17 00:00:00 2001 From: Kaushik Malapati Date: Wed, 25 Oct 2023 15:37:26 -0700 Subject: [PATCH 3/6] DEV: added more signals, fixed MixedDerivedSignals --- pcdsdevices/tpr.py | 63 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/pcdsdevices/tpr.py b/pcdsdevices/tpr.py index 054958678b3..dc67f497df7 100644 --- a/pcdsdevices/tpr.py +++ b/pcdsdevices/tpr.py @@ -4,7 +4,7 @@ from .interface import BaseInterface from .pv_positioner import PVPositionerIsClose -from .signal import MultiDerivedSignal +from .signal import MultiDerivedSignal, MultiDerivedSignalRO from .type_hints import SignalToValue TPR_TICK_NS = 5.384 @@ -31,33 +31,68 @@ class TprMotor(PVPositionerIsClose): are considered immediately complete. """ setpoint = FCpt(EpicsSignal, "{self.prefix}{self.sys}TDES", kind="normal") - readback = Cpt(EpicsSignalRO, ":BW_TDES", kind="hinted") + delay_ticks = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTICKS', kind="omitted") + delay_taps = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTAPS', kind="omitted") + readback = Cpt( + MultiDerivedSignalRO, + attrs=['delay_ticks', 'delay_taps'], + calculate_on_get=_get_delay + ) atol = TPR_TICK_NS rtol = 0 - def __init__(self, prefix, *, sys, name, **kwargs): + def __init__(self, prefix, *, sys, trg, name, **kwargs): + self.prefix = prefix self.sys = sys + self.trg = trg super().__init__(prefix, name=name, **kwargs) class TprTrigger(BaseInterface, Device): """Class for an individual TprTrigger.""" + ratemode = FCpt(EpicsSignal, '{self.prefix}{self.ch}RATECODE', kind="config") + group = FCpt(EpicsSignal, '{self.prefix}{self.ch}GROUP', kind="omitted") + seqcode = FCpt(EpicsSignal, '{self.prefix}{self.ch}SEQCODE', kind="omitted") + fixedrate = FCpt(EpicsSignal, '{self.prefix}{self.ch}FIXEDRATE', kind="omitted") + count = FCpt(EpicsSignal, '{self.prefix}{self.ch}COUNT', kind="omitted") + destmask = FCpt(EpicsSignal, '{self.prefix}{self.ch}DESTMASK', kind="omitted") + destmode = FCpt(EpicsSignal, '{self.prefix}{self.ch}DESTMODE', kind="omitted") + src = FCpt(EpicsSignal, '{self.prefix}{self.trg}SOURCE', kind="omitted") eventcode = FCpt(EpicsSignal, '{self.prefix}{self.ch}EVCODE', kind="config") eventrate = FCpt(EpicsSignalRO, '{self.prefix}{self.ch}RATE', kind="normal") label = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys}TCTL.DESC', kind="omitted") label2 = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys2}TCTL.DESC', kind="omitted") - ns_delay = FCpt( - EpicsSignal, - ':BW_TDES', - write_pv=':TDES', - tolerance=TPR_TICK_NS, - kind="hinted", + delay_ticks = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTICKS', kind="omitted") + delay_taps = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTAPS', kind="omitted") + delay_setpoint = FCpt(EpicsSignal, '{self.prefix}{self.sys}TDES', kind="omitted") + delay_setpoint2 = FCpt(EpicsSignal, '{self.prefix}{self.sys2}TDES', kind="omitted") + ns_delay = Cpt( + MultiDerivedSignal, + attrs=['delay_ticks', 'delay_taps', 'delay_setpoint'], + calculate_on_get=_get_delay, + calculate_on_put=_put_last, ) - ns_delay_scan = FCpt(TprMotor, '', sys='{self.sys}', kind="omitted") + ns_delay2 = Cpt( + MultiDerivedSignal, + attrs=['delay_ticks', 'delay_taps', 'delay_setpoint2'], + calculate_on_get=_get_delay, + calculate_on_put=_put_last, + ) + ns_delay_scan = FCpt(TprMotor, '{self.prefix}', sys='{self.sys}', trg='{self.trg}', kind="omitted") + ns_delay_scan2 = FCpt(TprMotor, '{self.prefix}', sys='{self.sys2}', trg='{self.trg}', kind="omitted") polarity = FCpt(EpicsSignal, '{self.prefix}{self.trg}TPOL', kind="config") - width = FCpt( + width_setpoint = FCpt(EpicsSignal, '{self.prefix}{self.sys}TWID', kind="omitted") + width_setpoint2 = FCpt(EpicsSignal, '{self.prefix}{self.sys2}TWID', kind="omitted") + width_ticks = FCpt(EpicsSignalRO, '{self.prefix}{self.trg}TWIDTICKS', kind="omitted") + width = Cpt( + MultiDerivedSignal, + attrs=['width_ticks', 'width_setpoint'], + calculate_on_get=_get_width, + calculate_on_put=_put_last, + ) + width2 = Cpt( MultiDerivedSignal, - attrs=['{self.prefix}{self.trg}TWIDTICKS', '{self.prefix}{self.sys}TWID'], + attrs=['width_ticks', 'width_setpoint2'], calculate_on_get=_get_width, calculate_on_put=_put_last, ) @@ -68,10 +103,10 @@ class TprTrigger(BaseInterface, Device): tab_component_names = True def __init__(self, prefix, *, channel, name, **kwargs): - self.ch = f':CH{channel:02}_' - self.trg = f':TRG{channel:02}_' self.sys = 'SYS0_' self.sys2 = 'SYS2_' + self.ch = f':CH{channel:02}_' + self.trg = f':TRG{channel:02}_' super().__init__(prefix, name=name, **kwargs) def enable(self): From e7a1a8204a1d462ce08f94d554e649d7e8ae8995 Mon Sep 17 00:00:00 2001 From: Kaushik Malapati Date: Wed, 25 Oct 2023 15:45:17 -0700 Subject: [PATCH 4/6] DOC: added release notes --- .../1178-new-tpr-class.rst | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/source/upcoming_release_notes/1178-new-tpr-class.rst diff --git a/docs/source/upcoming_release_notes/1178-new-tpr-class.rst b/docs/source/upcoming_release_notes/1178-new-tpr-class.rst new file mode 100644 index 00000000000..a83795ee0c8 --- /dev/null +++ b/docs/source/upcoming_release_notes/1178-new-tpr-class.rst @@ -0,0 +1,31 @@ +1178 new-tpr-class +################# + +API Breaks +---------- +- N/A + +Features +-------- +- New TprTrigger and TprMotor device classes in tpr.py +- Analogous to Trigger and EvrMotor from evr.py + +Device Updates +-------------- +- N/A + +New Devices +----------- +- N/A + +Bugfixes +-------- +- N/A + +Maintenance +----------- +- N/A + +Contributors +------------ +- KaushikMalapati From 2eceb5f599dbc0a8fc73e795be1dd6e370ead6d5 Mon Sep 17 00:00:00 2001 From: Kaushik Malapati Date: Wed, 25 Oct 2023 15:48:18 -0700 Subject: [PATCH 5/6] DOC: added docstrings --- pcdsdevices/tpr.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pcdsdevices/tpr.py b/pcdsdevices/tpr.py index dc67f497df7..f18ae78527e 100644 --- a/pcdsdevices/tpr.py +++ b/pcdsdevices/tpr.py @@ -12,14 +12,17 @@ def _get_delay(mds: MultiDerivedSignal, items: SignalToValue) -> float: + """Calculates delay in ns from ticks and taps""" return items[mds.attrs[0]] * TPR_TICK_NS + items[mds.attrs[1] * TPR_TAP_NS] def _get_width(mds: MultiDerivedSignal, items: SignalToValue) -> float: + """Calculates width in ns from ticks""" return items[mds.attrs[0]] * TPR_TICK_NS def _put_last(mds: MultiDerivedSignal, value: float) -> SignalToValue: + """Only writes value to last attr""" return {mds.attrs[-1]: value} From 03a1ba6727eec4126d16c37e25f577d5f4731575 Mon Sep 17 00:00:00 2001 From: Kaushik Malapati Date: Tue, 31 Oct 2023 13:56:52 -0700 Subject: [PATCH 6/6] DEV/DOC: Specify lcls 1 or 2 timing in initializer, updated documentation --- .../1178-new-tpr-class.rst | 6 +- pcdsdevices/tests/test_tpr.py | 12 +- pcdsdevices/tpr.py | 111 ++++++++++-------- 3 files changed, 74 insertions(+), 55 deletions(-) diff --git a/docs/source/upcoming_release_notes/1178-new-tpr-class.rst b/docs/source/upcoming_release_notes/1178-new-tpr-class.rst index a83795ee0c8..88713fe3dcf 100644 --- a/docs/source/upcoming_release_notes/1178-new-tpr-class.rst +++ b/docs/source/upcoming_release_notes/1178-new-tpr-class.rst @@ -7,8 +7,7 @@ API Breaks Features -------- -- New TprTrigger and TprMotor device classes in tpr.py -- Analogous to Trigger and EvrMotor from evr.py +- N/A Device Updates -------------- @@ -16,7 +15,8 @@ Device Updates New Devices ----------- -- N/A +- New TprTrigger and TprMotor device classes in tpr.py +- Analogous to Trigger and EvrMotor from evr.py Bugfixes -------- diff --git a/pcdsdevices/tests/test_tpr.py b/pcdsdevices/tests/test_tpr.py index c65618c2a68..4d87931cc3d 100644 --- a/pcdsdevices/tests/test_tpr.py +++ b/pcdsdevices/tests/test_tpr.py @@ -1,22 +1,24 @@ import pytest from ophyd.sim import make_fake_device -from ..tpr import TprTrigger +from ..tpr import TimingMode, TprTrigger @pytest.fixture(scope='function') def fake_trigger(): cls = make_fake_device(TprTrigger) - return cls('TST:TPR', channel=1, name='trig_a') + return cls('TST:TPR', channel=10, timing_mode=TimingMode.LCLS2, name='trig_a') def test_enable(fake_trigger): fake_trigger.enable() - assert fake_trigger.enable_cmd.get() == 1 + assert fake_trigger.enable_ch_cmd.get() == 1 + assert fake_trigger.enable_trg_cmd.get() == 1 fake_trigger.disable() - assert fake_trigger.enable_cmd.get() == 0 + assert fake_trigger.enable_ch_cmd.get() == 0 + assert fake_trigger.enable_trg_cmd.get() == 0 @pytest.mark.timeout(5) def test_disconnected_trigger(): - TprTrigger('TST', channel=1, name='test') + TprTrigger('TST', channel=1, timing_mode=TimingMode.LCLS1, name='test') diff --git a/pcdsdevices/tpr.py b/pcdsdevices/tpr.py index f18ae78527e..3b161e52873 100644 --- a/pcdsdevices/tpr.py +++ b/pcdsdevices/tpr.py @@ -1,3 +1,5 @@ +from enum import Enum + from ophyd import Component as Cpt from ophyd import Device, EpicsSignal, EpicsSignalRO from ophyd import FormattedComponent as FCpt @@ -6,11 +8,17 @@ from .pv_positioner import PVPositionerIsClose from .signal import MultiDerivedSignal, MultiDerivedSignalRO from .type_hints import SignalToValue +from .variety import set_metadata TPR_TICK_NS = 5.384 TPR_TAP_NS = 0.08 +class TimingMode(Enum): + LCLS1 = 1 + LCLS2 = 2 + + def _get_delay(mds: MultiDerivedSignal, items: SignalToValue) -> float: """Calculates delay in ns from ticks and taps""" return items[mds.attrs[0]] * TPR_TICK_NS + items[mds.attrs[1] * TPR_TAP_NS] @@ -33,9 +41,9 @@ class TprMotor(PVPositionerIsClose): Moves that are less than one tick are considered immediately complete. """ - setpoint = FCpt(EpicsSignal, "{self.prefix}{self.sys}TDES", kind="normal") - delay_ticks = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTICKS', kind="omitted") - delay_taps = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTAPS', kind="omitted") + setpoint = FCpt(EpicsSignal, "{self.prefix}{self.sys}TDES", kind="normal", doc="Trigger delay setpoint in nsec") + delay_ticks = FCpt(EpicsSignal, '{self.prefix}TDESTICKS', kind="omitted", doc="Trigger delay in clock ticks") + delay_taps = FCpt(EpicsSignal, '{self.prefix}TDESTAPS', kind="omitted", doc="Trigger delay in delay taps") readback = Cpt( MultiDerivedSignalRO, attrs=['delay_ticks', 'delay_taps'], @@ -44,78 +52,87 @@ class TprMotor(PVPositionerIsClose): atol = TPR_TICK_NS rtol = 0 - def __init__(self, prefix, *, sys, trg, name, **kwargs): + def __init__(self, prefix, *, sys, name, **kwargs): self.prefix = prefix self.sys = sys - self.trg = trg super().__init__(prefix, name=name, **kwargs) class TprTrigger(BaseInterface, Device): """Class for an individual TprTrigger.""" - ratemode = FCpt(EpicsSignal, '{self.prefix}{self.ch}RATECODE', kind="config") - group = FCpt(EpicsSignal, '{self.prefix}{self.ch}GROUP', kind="omitted") - seqcode = FCpt(EpicsSignal, '{self.prefix}{self.ch}SEQCODE', kind="omitted") - fixedrate = FCpt(EpicsSignal, '{self.prefix}{self.ch}FIXEDRATE', kind="omitted") - count = FCpt(EpicsSignal, '{self.prefix}{self.ch}COUNT', kind="omitted") - destmask = FCpt(EpicsSignal, '{self.prefix}{self.ch}DESTMASK', kind="omitted") - destmode = FCpt(EpicsSignal, '{self.prefix}{self.ch}DESTMODE', kind="omitted") - src = FCpt(EpicsSignal, '{self.prefix}{self.trg}SOURCE', kind="omitted") - eventcode = FCpt(EpicsSignal, '{self.prefix}{self.ch}EVCODE', kind="config") - eventrate = FCpt(EpicsSignalRO, '{self.prefix}{self.ch}RATE', kind="normal") - label = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys}TCTL.DESC', kind="omitted") - label2 = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys2}TCTL.DESC', kind="omitted") - delay_ticks = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTICKS', kind="omitted") - delay_taps = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTAPS', kind="omitted") - delay_setpoint = FCpt(EpicsSignal, '{self.prefix}{self.sys}TDES', kind="omitted") - delay_setpoint2 = FCpt(EpicsSignal, '{self.prefix}{self.sys2}TDES', kind="omitted") + ratemode = FCpt(EpicsSignal, '{self.prefix}{self.ch}RATEMODE', kind="config", doc="Channel rate mode selector") + group = FCpt(EpicsSignal, '{self.prefix}{self.ch}GROUP', kind="omitted", doc="Channel group Bit") + seqcode = FCpt(EpicsSignal, '{self.prefix}{self.ch}SEQCODE', kind="omitted", doc="Channel sequence code") + fixedrate = FCpt(EpicsSignal, '{self.prefix}{self.ch}FIXEDRATE', kind="omitted", doc="Channel Fxed rate selector") + count = FCpt(EpicsSignal, '{self.prefix}{self.ch}CNT', kind="omitted", doc="Channel counter") + destmask = FCpt(EpicsSignal, '{self.prefix}{self.ch}DESTMASK', kind="omitted", doc="Channel destination mask") + destmode = FCpt(EpicsSignal, '{self.prefix}{self.ch}DESTMODE', kind="omitted", doc="Channel destination mode selector") + src = FCpt(EpicsSignal, '{self.prefix}{self.trg}SOURCE', kind="omitted", doc="Trigger source") + eventcode = FCpt(EpicsSignal, '{self.prefix}{self.ch}EVCODE', kind="config", doc="Channel LCLS1 event code") + eventrate = FCpt(EpicsSignalRO, '{self.prefix}{self.ch}RATE', kind="normal", doc="Channel event rates") + label = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys}TCTL.DESC', kind="omitted", doc="Enable/disable") + delay_ticks = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTICKS', kind="omitted", doc="Trigger delay in clock ticks") + delay_taps = FCpt(EpicsSignal, '{self.prefix}{self.trg}TDESTAPS', kind="omitted", doc="Trigger delay in delay taps") + delay_setpoint = FCpt(EpicsSignal, '{self.prefix}{self.trg}{self.sys}TDES', kind="omitted", doc="Trigger delay setpoint in nsec") ns_delay = Cpt( MultiDerivedSignal, attrs=['delay_ticks', 'delay_taps', 'delay_setpoint'], calculate_on_get=_get_delay, calculate_on_put=_put_last, + doc="Get/set trigger delay in ns", ) - ns_delay2 = Cpt( - MultiDerivedSignal, - attrs=['delay_ticks', 'delay_taps', 'delay_setpoint2'], - calculate_on_get=_get_delay, - calculate_on_put=_put_last, - ) - ns_delay_scan = FCpt(TprMotor, '{self.prefix}', sys='{self.sys}', trg='{self.trg}', kind="omitted") - ns_delay_scan2 = FCpt(TprMotor, '{self.prefix}', sys='{self.sys2}', trg='{self.trg}', kind="omitted") - polarity = FCpt(EpicsSignal, '{self.prefix}{self.trg}TPOL', kind="config") - width_setpoint = FCpt(EpicsSignal, '{self.prefix}{self.sys}TWID', kind="omitted") - width_setpoint2 = FCpt(EpicsSignal, '{self.prefix}{self.sys2}TWID', kind="omitted") - width_ticks = FCpt(EpicsSignalRO, '{self.prefix}{self.trg}TWIDTICKS', kind="omitted") + ns_delay_scan = FCpt(TprMotor, '{self.prefix}{self.trg}', sys='{self.sys}', kind="omitted", doc="Motor-like tpr interface") + polarity = FCpt(EpicsSignal, '{self.prefix}{self.trg}TPOL', kind="config", doc="Trigger description") + width_setpoint = FCpt(EpicsSignal, '{self.prefix}{self.trg}{self.sys}TWID', kind="omitted", doc="Trigger width in ns") + width_ticks = FCpt(EpicsSignalRO, '{self.prefix}{self.trg}TWIDTICKS', kind="omitted", doc="Trigger width in clock ticks") width = Cpt( MultiDerivedSignal, attrs=['width_ticks', 'width_setpoint'], calculate_on_get=_get_width, calculate_on_put=_put_last, + doc="Get/set trigger width in nsec", ) - width2 = Cpt( - MultiDerivedSignal, - attrs=['width_ticks', 'width_setpoint2'], - calculate_on_get=_get_width, - calculate_on_put=_put_last, - ) - enable_cmd = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys}TCTL', kind="omitted") - enable_cmd2 = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys2}TCTL', kind="omitted") + enable_ch_cmd = FCpt(EpicsSignal, '{self.prefix}{self.ch}{self.sys}TCTL', kind="omitted", doc="Channel enable/disable") + set_metadata(enable_ch_cmd, dict(variety='command-proc', value=1)) + enable_trg_cmd = FCpt(EpicsSignal, '{self.prefix}{self.trg}{self.sys}TCTL', kind="omitted", doc="Trigger enable/disable") + set_metadata(enable_trg_cmd, dict(variety='command-proc', value=1)) tab_whitelist = ['enable', 'disable'] tab_component_names = True - def __init__(self, prefix, *, channel, name, **kwargs): - self.sys = 'SYS0_' - self.sys2 = 'SYS2_' + def __init__(self, prefix, *, channel, timing_mode, name, **kwargs): + if timing_mode == TimingMode.LCLS1: + self.sys = 'SYS0_' + elif timing_mode == TimingMode.LCLS2: + self.sys = 'SYS2_' + else: + raise TypeError("timing_mode must be TimingMode.LCLS1 or TimingMode.LCLS2") self.ch = f':CH{channel:02}_' self.trg = f':TRG{channel:02}_' super().__init__(prefix, name=name, **kwargs) def enable(self): - """Enable the trigger.""" - self.enable_cmd.put(1) + """Enable the channel and trigger.""" + self.enable_ch() + self.enable_trg() def disable(self): + """Disable the channel and trigger.""" + self.disable_ch() + self.disable_trg() + + def enable_ch(self): + """Enable the channel.""" + self.enable_ch_cmd.put(1) + + def disable_ch(self): + """Disable the channel.""" + self.enable_ch_cmd.put(0) + + def enable_trg(self): + """Enable the trigger.""" + self.enable_trg_cmd.put(1) + + def disable_trg(self): """Disable the trigger.""" - self.enable_cmd.put(0) + self.enable_trg_cmd.put(0)