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

Hinted signals for the ion chambers #302

Merged
merged 12 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ dependencies:
- bluesky-adaptive
- bluesky >=1.8.1
- ophyd >=1.6.3
- ophyd-async >= 0.6.0
# - ophyd-async > 0.8.0a4
- git+https://github.com/bluesky/ophyd-async.git # switch back to pip once a new release (0.8.0a5) is available
- apstools == 1.6.20 # Leave at 1.6.20 until this is fixed: https://github.com/BCDA-APS/apstools/issues/1022
- pcdsdevices # For extra signal types
- pydm >=1.18.0
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ classifiers = [
"Topic :: System :: Hardware",
]
keywords = ["synchrotron", "xray", "bluesky"]
dependencies = ["aioca", "aiokafka", "bluesky", "ophyd", "ophyd-async>=0.7.0", "databroker", "apsbss", "xraydb",
dependencies = ["aioca", "aiokafka", "bluesky", "ophyd", "ophyd-async>=0.8.0a3", "databroker", "apsbss", "xraydb",
"mergedeep", "xrayutilities", "bluesky-queueserver-api", "tomlkit",
"apstools", "databroker", "ophyd-registry", "caproto", "pcdsdevices",
"strenum", "bluesky-adaptive", "tiled[client]"]
Expand Down
115 changes: 67 additions & 48 deletions src/haven/devices/delay.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
from typing import Type

from ophyd_async.core import (
ConfigSignal,
DeviceVector,
SignalRW,
StandardReadable,
StandardReadableFormat,
StrictEnum,
SubsetEnum,
T,
)
from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw, epics_signal_x
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_x


class StrEnum(str, enum.Enum):
Expand All @@ -36,22 +36,31 @@ def epics_signal_io(datatype: Type[T], prefix: str, name: str = "") -> SignalRW[


class DG645Channel(StandardReadable):
Reference = SubsetEnum["T0", "A", "B", "C", "D", "E", "F", "G", "H"]
class Reference(StrictEnum):
T0 = "T0"
A = "A"
B = "B"
C = "C"
D = "D"
E = "E"
F = "F"
G = "G"
H = "H"

def __init__(self, prefix: str, name: str = ""):
with self.add_children_as_readables(ConfigSignal):
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
self.reference = epics_signal_io(self.Reference, f"{prefix}ReferenceM")
self.delay = epics_signal_io(float, f"{prefix}DelayA")
super().__init__(name=name)


class DG645Output(StandardReadable):
class Polarity(StrEnum):
class Polarity(StrictEnum):
NEG = "NEG"
POS = "POS"

def __init__(self, prefix: str, name: str = ""):
with self.add_children_as_readables(ConfigSignal):
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
self.polarity = epics_signal_io(self.Polarity, f"{prefix}OutputPolarityB")
self.amplitude = epics_signal_io(float, f"{prefix}OutputAmpA")
self.offset = epics_signal_io(float, f"{prefix}OutputOffsetA")
Expand All @@ -62,16 +71,46 @@ def __init__(self, prefix: str, name: str = ""):

class DG645DelayOutput(DG645Output):
def __init__(self, prefix: str, name: str = ""):
with self.add_children_as_readables(ConfigSignal):
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
self.trigger_prescale = epics_signal_io(int, f"{prefix}TriggerPrescaleL")
self.trigger_phase = epics_signal_io(int, f"{prefix}TriggerPhaseL")
super().__init__(prefix=prefix, name=name)


class DG645Delay(StandardReadable):

class BaudRate(SubsetEnum):
B4800 = "4800"
B9600 = "9600"
B19200 = "19200"
B38400 = "38400"
B57600 = "57600"
B115200 = "115200"

class TriggerSource(SubsetEnum):
INTERNAL = "Internal"
EXT_RISING_EDGE = "Ext rising edge"
EXT_FALLING_EDGE = "Ext falling edge"
SS_EXT_RISE_EDGE = "SS ext rise edge"
SS_EXT_FALL_EDGE = "SS ext fall edge"
SINGLE_SHOT = "Single shot"
LINE = "Line"

class TriggerInhibit(SubsetEnum):
OFF = "Off"
TRIGGERS = "Triggers"
AB = "AB"
AB_CD = "AB,CD"
AB_CD_EF = "AB,CD,EF"
AB_CD_EF_GH = "AB,CD,EF,GH"

class BurstConfig(SubsetEnum):
ALL_CYCLES = "All Cycles"
FIRST_CYCLE = "1st Cycle"

def __init__(self, prefix: str, name: str = ""):
# Conventional signals
with self.add_children_as_readables(ConfigSignal):
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
self.label = epics_signal_rw(str, f"{prefix}Label")
self.device_id = epics_signal_r(str, f"{prefix}IdentSI")
self.status = epics_signal_r(str, f"{prefix}StatusSI")
Expand All @@ -82,10 +121,7 @@ def __init__(self, prefix: str, name: str = ""):
self.status_checking = epics_signal_rw(bool, f"{prefix}StatusCheckingBO")
self.reset_serial = epics_signal_x(f"{prefix}IfaceSerialResetBO")
self.serial_state = epics_signal_io(bool, f"{prefix}IfaceSerialStateB")
self.serial_baud = epics_signal_io(
SubsetEnum["4800", "9600", "19200", "38400", "57600", "115200"],
f"{prefix}IfaceSerialBaudM",
)
self.serial_baud = epics_signal_io(self.BaudRate, f"{prefix}IfaceSerialBaudM")
self.reset_gpib = epics_signal_x(f"{prefix}IfaceGpibResetBO")
self.gpib_state = epics_signal_io(bool, f"{prefix}IfaceGpibStateB")
self.gpib_address = epics_signal_io(int, f"{prefix}IfaceGpibAddrL")
Expand All @@ -103,46 +139,29 @@ def __init__(self, prefix: str, name: str = ""):
self.gateway = epics_signal_io(str, f"{prefix}IfaceGatewayS")
# Individual delay channels
with self.add_children_as_readables():
self.channels = DeviceVector(
{
"A": DG645Channel(f"{prefix}A"),
"B": DG645Channel(f"{prefix}B"),
"C": DG645Channel(f"{prefix}C"),
"D": DG645Channel(f"{prefix}D"),
"E": DG645Channel(f"{prefix}E"),
"F": DG645Channel(f"{prefix}F"),
"G": DG645Channel(f"{prefix}G"),
"H": DG645Channel(f"{prefix}H"),
}
)
self.channel_A = DG645Channel(f"{prefix}A")
self.channel_B = DG645Channel(f"{prefix}B")
self.channel_C = DG645Channel(f"{prefix}C")
self.channel_D = DG645Channel(f"{prefix}D")
self.channel_E = DG645Channel(f"{prefix}E")
self.channel_F = DG645Channel(f"{prefix}F")
self.channel_G = DG645Channel(f"{prefix}G")
self.channel_H = DG645Channel(f"{prefix}H")
# 2-channel delay outputs
with self.add_children_as_readables():
self.outputs = DeviceVector(
{
"T0": DG645Output(f"{prefix}T0"),
"AB": DG645DelayOutput(f"{prefix}AB"),
"CD": DG645DelayOutput(f"{prefix}CD"),
"EF": DG645DelayOutput(f"{prefix}EF"),
"GH": DG645DelayOutput(f"{prefix}GH"),
}
)
self.output_T0 = DG645Output(f"{prefix}T0")
self.output_AB = DG645DelayOutput(f"{prefix}AB")
self.output_CD = DG645DelayOutput(f"{prefix}CD")
self.output_EF = DG645DelayOutput(f"{prefix}EF")
self.output_GH = DG645DelayOutput(f"{prefix}GH")
# Trigger control
with self.add_children_as_readables(ConfigSignal):
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
self.trigger_source = epics_signal_io(
SubsetEnum[
"Internal",
"Ext rising edge",
"Ext falling edge",
"SS ext rise edge",
"SS ext fall edge",
"Single shot",
"Line",
],
self.TriggerSource,
f"{prefix}TriggerSourceM",
)
self.trigger_inhibit = epics_signal_io(
SubsetEnum["Off", "Triggers", "AB", "AB,CD", "AB,CD,EF", "AB,CD,EF,GH"],
f"{prefix}TriggerInhibitM",
self.TriggerInhibit, f"{prefix}TriggerInhibitM"
)
self.trigger_level = epics_signal_io(float, f"{prefix}TriggerLevelA")
self.trigger_rate = epics_signal_io(float, f"{prefix}TriggerRateA")
Expand All @@ -152,11 +171,11 @@ def __init__(self, prefix: str, name: str = ""):
self.trigger_holdoff = epics_signal_io(float, f"{prefix}TriggerHoldoffA")
self.trigger_prescale = epics_signal_io(int, f"{prefix}TriggerPrescaleL")
# Burst settings
with self.add_children_as_readables(ConfigSignal):
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
self.burst_mode = epics_signal_io(bool, f"{prefix}BurstModeB")
self.burst_count = epics_signal_io(int, f"{prefix}BurstCountL")
self.burst_config = epics_signal_io(
SubsetEnum["All Cycles", "1st Cycle"], f"{prefix}BurstConfigB"
self.BurstConfig, f"{prefix}BurstConfigB"
)
self.burst_delay = epics_signal_io(float, f"{prefix}BurstDelayA")
self.burst_period = epics_signal_io(float, f"{prefix}BurstPeriodA")
Expand Down
7 changes: 5 additions & 2 deletions src/haven/devices/detectors/aravis.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from ophyd_async.core import SubsetEnum
from ophyd_async.epics.adaravis import AravisDetector as DetectorBase
from ophyd_async.epics.signal import epics_signal_rw_rbv
from ophyd_async.epics.core import epics_signal_rw_rbv

from .area_detectors import HavenDetector

AravisTriggerSource = SubsetEnum["Software", "Line1"]

class AravisTriggerSource(SubsetEnum):
SOFTWARE = "Software"
LINE1 = "Line1"


class AravisDetector(HavenDetector, DetectorBase):
Expand Down
4 changes: 2 additions & 2 deletions src/haven/devices/energy_positioner.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
CALCULATE_TIMEOUT,
AsyncStatus,
CalculatableTimeout,
HintedSignal,
Signal,
StandardReadableFormat,
)

from ..positioner import Positioner
Expand Down Expand Up @@ -78,7 +78,7 @@ def __init__(
forward=self.set_energy,
inverse=self.get_energy,
)
with self.add_children_as_readables(HintedSignal):
with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
self.readback = derived_signal_r(
float,
derived_from={"mono": self.monochromator.energy.user_readback},
Expand Down
Loading