Skip to content

Commit

Permalink
Merge pull request #877 from spc-group/delay
Browse files Browse the repository at this point in the history
Support for DG-645 digital delay/pulse generator
  • Loading branch information
canismarko authored Aug 30, 2023
2 parents 1351d03 + 0220a8a commit 134b2ad
Show file tree
Hide file tree
Showing 4 changed files with 284 additions and 0 deletions.
2 changes: 2 additions & 0 deletions apstools/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
from .axis_tuner import AxisTunerException
from .axis_tuner import AxisTunerMixin

from .delay import DG645Delay

from .description_mixin import EpicsDescriptionMixin

from .dict_device_support import dict_device_factory
Expand Down
109 changes: 109 additions & 0 deletions apstools/devices/delay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""Ophyd definitions for digital delay and pulse generators."""

from ophyd import Device, Component as Cpt, EpicsSignal, EpicsSignalRO, Kind


__all__ = ["DG645Delay"]


class EpicsSignalWithIO(EpicsSignal):
# An EPICS signal that simply uses the DG-645 convention of
# 'AO' being the setpoint and 'AI' being the read-back

def __init__(self, prefix, **kwargs):
super().__init__(f"{prefix}I", write_pv=f"{prefix}O", **kwargs)


class DG645Channel(Device):
reference = Cpt(EpicsSignalWithIO, "ReferenceM", kind=Kind.config)
delay = Cpt(EpicsSignalWithIO, "DelayA", kind=Kind.normal)


class DG645Output(Device):
output_mode_ttl = Cpt(EpicsSignal, "OutputModeTtlSS.PROC", kind=Kind.omitted)
output_mode_nim = Cpt(EpicsSignal, "OutputModeNimSS.PROC", kind=Kind.omitted)
polarity = Cpt(EpicsSignalWithIO, "OutputPolarityB", kind=Kind.config)
amplitude = Cpt(EpicsSignalWithIO, "OutputAmpA", kind=Kind.config)
offset = Cpt(EpicsSignalWithIO, "OutputOffsetA", kind=Kind.config)


class DG645DelayOutput(DG645Output):
trigger_prescale = Cpt(EpicsSignalWithIO, "TriggerPrescaleL", kind=Kind.config)
trigger_phase = Cpt(EpicsSignalWithIO, "TriggerPhaseL", kind=Kind.config)


class DG645Delay(Device):
"""An SRS DG-645 digial delay/pulse generator.
This device has four delayed outputs: AB, CD, EF, GH.
Configuration of the output parameters (e.g. amplitude, polarity)
is done using components ``output_AB``, etc. The individual delays
for the start and end of the output pulse are configured using
individual channels ``channel_A`` etc.
There is also a ``T0`` output which is the reference pulses used
for the remaining delayed outputs.
"""

# Individual delay channels
channel_A = Cpt(DG645Channel, "A")
channel_B = Cpt(DG645Channel, "B")
channel_C = Cpt(DG645Channel, "C")
channel_D = Cpt(DG645Channel, "D")
channel_E = Cpt(DG645Channel, "E")
channel_F = Cpt(DG645Channel, "F")
channel_G = Cpt(DG645Channel, "G")
channel_H = Cpt(DG645Channel, "H")

# 2-channel delay outputs
output_T0 = Cpt(DG645Output, "T0", kind=Kind.config)
output_AB = Cpt(DG645DelayOutput, "AB", kind=Kind.config)
output_CD = Cpt(DG645DelayOutput, "CD", kind=Kind.config)
output_EF = Cpt(DG645DelayOutput, "EF", kind=Kind.config)
output_GH = Cpt(DG645DelayOutput, "GH", kind=Kind.config)

# General settings
label = Cpt(EpicsSignal, "Label", kind=Kind.config)
status = Cpt(EpicsSignalRO, "StatusSI", kind=Kind.omitted)
clear_error = Cpt(EpicsSignal, "StatusClearBO", kind=Kind.omitted)
device_id = Cpt(EpicsSignalRO, "IdentSI", kind=Kind.config)
goto_remote = Cpt(EpicsSignal, "GotoRemoteBO", kind=Kind.omitted)
goto_local = Cpt(EpicsSignal, "GotoLocalBO", kind=Kind.omitted)
reset = Cpt(EpicsSignal, "ResetBO", kind=Kind.omitted)
status_checking = Cpt(EpicsSignal, "StatusCheckingBO", kind=Kind.omitted)
reset_serial = Cpt(EpicsSignal, "IfaceSerialResetBO", kind=Kind.omitted)
serial_state = Cpt(EpicsSignalWithIO, "IfaceSerialStateB", kind=Kind.config)
serial_baud = Cpt(EpicsSignalWithIO, "IfaceSerialBaudM", kind=Kind.config)
reset_gpib = Cpt(EpicsSignal, "IfaceGpibResetBO", kind=Kind.omitted)
gpib_state = Cpt(EpicsSignalWithIO, "IfaceGpibStateB", kind=Kind.config)
gpib_address = Cpt(EpicsSignalWithIO, "IfaceGpibAddrL", kind=Kind.config)
reset_lan = Cpt(EpicsSignal, "IfaceLanResetBO", kind=Kind.omitted)
mac_address = Cpt(EpicsSignalRO, "IfaceMacAddrSI", kind=Kind.config)
lan_state = Cpt(EpicsSignalWithIO, "IfaceLanStateB", kind=Kind.config)
dhcp_state = Cpt(EpicsSignalWithIO, "IfaceDhcpStateB", kind=Kind.config)
autoip_state = Cpt(EpicsSignalWithIO, "IfaceAutoIpStateB", kind=Kind.config)
static_ip_state = Cpt(EpicsSignalWithIO, "IfaceStaticIpStateB", kind=Kind.config)
bare_socket_state = Cpt(EpicsSignalWithIO, "IfaceBareSocketStateB", kind=Kind.config)
telnet_state = Cpt(EpicsSignalWithIO, "IfaceTelnetStateB", kind=Kind.config)
vxi11_state = Cpt(EpicsSignalWithIO, "IfaceVxiStateB", kind=Kind.config)
ip_address = Cpt(EpicsSignalWithIO, "IfaceIpAddrS", kind=Kind.config)
network_mask = Cpt(EpicsSignalWithIO, "IfaceNetMaskS", kind=Kind.config)
gateway = Cpt(EpicsSignalWithIO, "IfaceGatewayS", kind=Kind.config)

# Trigger control
trigger_source = Cpt(EpicsSignalWithIO, "TriggerSourceM", kind=Kind.config)
trigger_inhibit = Cpt(EpicsSignalWithIO, "TriggerInhibitM", kind=Kind.config)
trigger_level = Cpt(EpicsSignalWithIO, "TriggerLevelA", kind=Kind.config)
trigger_rate = Cpt(EpicsSignalWithIO, "TriggerRateA", kind=Kind.config)
trigger_advanced_mode = Cpt(EpicsSignalWithIO, "TriggerAdvancedModeB", kind=Kind.config)
trigger_holdoff = Cpt(EpicsSignalWithIO, "TriggerHoldoffA", kind=Kind.config)
trigger_prescale = Cpt(EpicsSignalWithIO, "TriggerPrescaleL", kind=Kind.config)

# Burst settings
burst_mode = Cpt(EpicsSignalWithIO, "BurstModeB", kind=Kind.config)
burst_count = Cpt(EpicsSignalWithIO, "BurstCountL", kind=Kind.config)
burst_mode = Cpt(EpicsSignalWithIO, "BurstConfigB", kind=Kind.config)
burst_delay = Cpt(EpicsSignalWithIO, "BurstDelayA", kind=Kind.config)
burst_period = Cpt(EpicsSignalWithIO, "BurstPeriodA", kind=Kind.config)
166 changes: 166 additions & 0 deletions apstools/devices/tests/test_delay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
"""
test the SRS DG-645 digital delay device support
Hardware is not available so test with best efforts
"""

from ...tests import IOC_GP
from .. import delay

PV_PREFIX = f"phony:{IOC_GP}DG645:"


def test_dg645_device():
dg645 = delay.DG645Delay(PV_PREFIX, name="delay")
assert not dg645.connected

read_names = [
"channel_A",
"channel_A.delay",
"channel_B",
"channel_B.delay",
"channel_C",
"channel_C.delay",
"channel_D",
"channel_D.delay",
"channel_E",
"channel_E.delay",
"channel_F",
"channel_F.delay",
"channel_G",
"channel_G.delay",
"channel_H",
"channel_H.delay",
]
assert sorted(dg645.read_attrs) == sorted(read_names)

cfg_names = [
"autoip_state",
"bare_socket_state",
"burst_count",
"burst_delay",
"burst_mode",
"burst_period",
"channel_A",
"channel_A.reference",
"channel_B",
"channel_B.reference",
"channel_C",
"channel_C.reference",
"channel_D",
"channel_D.reference",
"channel_E",
"channel_E.reference",
"channel_F",
"channel_F.reference",
"channel_G",
"channel_G.reference",
"channel_H",
"channel_H.reference",
"device_id",
"dhcp_state",
"gateway",
"gpib_address",
"gpib_state",
"ip_address",
"label",
"lan_state",
"mac_address",
"network_mask",
"output_AB",
"output_AB.amplitude",
"output_AB.offset",
"output_AB.polarity",
"output_AB.trigger_phase",
"output_AB.trigger_prescale",
"output_CD",
"output_CD.amplitude",
"output_CD.offset",
"output_CD.polarity",
"output_CD.trigger_phase",
"output_CD.trigger_prescale",
"output_EF",
"output_EF.amplitude",
"output_EF.offset",
"output_EF.polarity",
"output_EF.trigger_phase",
"output_EF.trigger_prescale",
"output_GH",
"output_GH.amplitude",
"output_GH.offset",
"output_GH.polarity",
"output_GH.trigger_phase",
"output_GH.trigger_prescale",
"output_T0",
"output_T0.amplitude",
"output_T0.offset",
"output_T0.polarity",
"serial_baud",
"serial_state",
"static_ip_state",
"telnet_state",
"trigger_advanced_mode",
"trigger_holdoff",
"trigger_inhibit",
"trigger_level",
"trigger_prescale",
"trigger_rate",
"trigger_source",
"vxi11_state",
]
assert sorted(dg645.configuration_attrs) == sorted(cfg_names)

# List all the components
cpt_names = [
"autoip_state",
"bare_socket_state",
"burst_count",
"burst_delay",
"burst_mode",
"burst_period",
"channel_A",
"channel_B",
"channel_C",
"channel_D",
"channel_E",
"channel_F",
"channel_G",
"channel_H",
"clear_error",
"device_id",
"dhcp_state",
"gateway",
"goto_local",
"goto_remote",
"gpib_address",
"gpib_state",
"ip_address",
"label",
"lan_state",
"mac_address",
"network_mask",
"output_AB",
"output_CD",
"output_EF",
"output_GH",
"output_T0",
"reset",
"reset_gpib",
"reset_lan",
"reset_serial",
"serial_baud",
"serial_state",
"static_ip_state",
"status",
"status_checking",
"telnet_state",
"trigger_advanced_mode",
"trigger_holdoff",
"trigger_inhibit",
"trigger_level",
"trigger_prescale",
"trigger_rate",
"trigger_source",
"vxi11_state",
]
assert sorted(dg645.component_names) == sorted(cpt_names)
7 changes: 7 additions & 0 deletions docs/source/api/_devices.rst
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ Other Support
~apstools.devices.flyer_motor_scaler.SignalValueStack
~apstools.devices.srs570_preamplifier.SRS570_PreAmplifier
~apstools.devices.struck3820.Struck3820
~apstools.devices.delay.DG645Delay

Internal Routines
+++++++++++++++++
Expand Down Expand Up @@ -256,6 +257,12 @@ All Submodules
:show-inheritance:
:inherited-members:

.. automodule:: apstools.devices.delay
:members:
:private-members:
:show-inheritance:
:inherited-members:

.. automodule:: apstools.devices.description_mixin
:members:
:private-members:
Expand Down

0 comments on commit 134b2ad

Please sign in to comment.