Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for DG-645 digital delay/pulse generator #877

Merged
merged 4 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
1 change: 1 addition & 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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


Internal Routines
+++++++++++++++++
Expand Down
Loading