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

473 create a device for xpress3 areadetector #524

Merged
merged 49 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
b87b45d
Merge pull request #518 from DiamondLightSource/main
stan-dot May 9, 2024
7000811
first attempt
Relm-Arrowny May 10, 2024
ff04eac
first attempt
Relm-Arrowny May 10, 2024
29dc4da
Xspress3Mini/Xspress3 with ophyd_async
Relm-Arrowny May 13, 2024
9c80e3b
Xspress3Mini/Xspress3 with ophyd_async
Relm-Arrowny May 13, 2024
4b021db
Xspress3Mini/Xspress3 with ophyd_async
Relm-Arrowny May 13, 2024
0ee8d5e
Xspress3Mini/Xspress3 with ophyd_async
Relm-Arrowny May 13, 2024
da6174b
Xspress3Mini/Xspress3 with ophyd_async
Relm-Arrowny May 13, 2024
630f8f2
added missing _ and fix lint
Relm-Arrowny May 13, 2024
c2a37a9
Change to xspress3 with extra channels for MCA plus PR feedback
Relm-Arrowny May 13, 2024
cb3d02d
grouping up all the channels
Relm-Arrowny May 14, 2024
e120df7
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny May 14, 2024
4c46d52
added xspress in i03.py i20-1 and fixed all the incorrect pvs
Relm-Arrowny May 14, 2024
a7208a3
change num to num_channels
Relm-Arrowny May 14, 2024
22d721e
correct i03.py xspress3mini to xspress
Relm-Arrowny May 14, 2024
b31a03f
correct i03.py xspress3mini to xspress
Relm-Arrowny May 14, 2024
404c52b
fix spelling
Relm-Arrowny May 15, 2024
67fcb8d
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny May 15, 2024
f6a829e
remove enum from xspress3. EraseState
Relm-Arrowny May 15, 2024
2bb0ac5
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny May 16, 2024
1adba5d
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny May 30, 2024
fc0f508
adding docstring
Relm-Arrowny May 30, 2024
d757e40
fixing docstrings
Relm-Arrowny May 30, 2024
f24095f
removed xpress3_mini
Relm-Arrowny May 30, 2024
3997024
removed xpress3_mini
Relm-Arrowny May 30, 2024
66a4a28
putting EraseState enum back in as it is need to connect
Relm-Arrowny May 30, 2024
4921c36
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny May 30, 2024
492084b
Fix EraseState issue
Relm-Arrowny May 30, 2024
9fcd060
Merge branch '473-create-a-device-for-xpress3-areadetector' of github…
Relm-Arrowny May 30, 2024
96b2c73
erase still an issue
Relm-Arrowny May 30, 2024
76b3646
removed erase signal
Relm-Arrowny May 31, 2024
df27b1a
fixing stage and test
Relm-Arrowny May 31, 2024
7b0204a
correct logic to wait for the rbv rather than the set
Relm-Arrowny Jun 1, 2024
9527f20
make device stageable and fixed tests
Relm-Arrowny Jun 3, 2024
152132d
removed duplicated test
Relm-Arrowny Jun 3, 2024
17a9228
changed with suggestion
Relm-Arrowny Jun 3, 2024
8f3b0d2
add unstage and completed RE test
Relm-Arrowny Jun 3, 2024
2897a05
add more assert to RE test
Relm-Arrowny Jun 3, 2024
5a1acf8
Fix lint
Relm-Arrowny Jun 3, 2024
3f5f53f
make test run faster and remove dubicated test
Relm-Arrowny Jun 4, 2024
6500e57
Merge branch '473-create-a-device-for-xpress3-areadetector' of github…
Relm-Arrowny Jun 4, 2024
4d6a3e8
lint
Relm-Arrowny Jun 4, 2024
a93e60d
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny Jun 4, 2024
489e8ca
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny Jun 6, 2024
5c1e703
increase timeout to 0.1 as it timed out before change happens
Relm-Arrowny Jun 6, 2024
a3787c3
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
DominicOram Jun 10, 2024
f5cb74e
increase time out to 1s and change time out test to 0.1
Relm-Arrowny Jun 10, 2024
12335d0
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny Jun 13, 2024
97c91be
Merge branch 'main' into 473-create-a-device-for-xpress3-areadetector
Relm-Arrowny Jun 19, 2024
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
4 changes: 3 additions & 1 deletion .vscode/settings.json
Relm-Arrowny marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"python.testing.pytestArgs": [],
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"editor.formatOnSave": true,
Expand Down
6 changes: 3 additions & 3 deletions src/dodal/beamlines/i03.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from dodal.devices.undulator_dcm import UndulatorDCM
from dodal.devices.webcam import Webcam
from dodal.devices.xbpm_feedback import XBPMFeedback
from dodal.devices.xspress3_mini.xspress3_mini import Xspress3Mini
from dodal.devices.xspress3.xspress3 import Xspress3
from dodal.devices.zebra import Zebra
from dodal.devices.zebra_controlled_shutter import ZebraShutter
from dodal.devices.zocalo import ZocaloResults
Expand Down Expand Up @@ -362,12 +362,12 @@ def zebra(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -

def xspress3mini(
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
) -> Xspress3Mini:
) -> Xspress3:
"""Get the i03 Xspress3Mini device, instantiate it if it hasn't already been.
If this is called when already instantiated in i03, it will return the existing object.
"""
return device_instantiation(
Xspress3Mini,
Xspress3,
"xspress3mini",
"-EA-XSP3-01:",
wait_for_connection,
Expand Down
18 changes: 18 additions & 0 deletions src/dodal/beamlines/i20_1.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from dodal.common.beamlines.beamline_utils import device_instantiation
from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
from dodal.devices.turbo_slit import TurboSlit
from dodal.devices.xspress3.xspress3 import Xspress3
from dodal.log import set_beamline as set_log_beamline
from dodal.utils import get_beamline_name

Expand All @@ -23,3 +24,20 @@ def turbo_slit(
wait=wait_for_connection,
fake=fake_with_ophyd_sim,
)


def express3(
Relm-Arrowny marked this conversation as resolved.
Show resolved Hide resolved
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
) -> Xspress3:
"""
16 channels Xspress3 detector
"""

return device_instantiation(
Xspress3,
prefix="-EA-DET-03:",
name="Xspress3",
num_channels=16,
wait=wait_for_connection,
fake=fake_with_ophyd_sim,
)
150 changes: 150 additions & 0 deletions src/dodal/devices/xspress3/xspress3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
from enum import Enum

from bluesky.protocols import Stageable
from numpy import float64
from numpy.typing import NDArray
from ophyd_async.core import (
AsyncStatus,
Device,
DeviceVector,
wait_for_value,
)
from ophyd_async.epics.signal.signal import (
epics_signal_r,
epics_signal_rw,
epics_signal_rw_rbv,
)

from dodal.devices.xspress3.xspress3_channel import (
AcquireState,
Xspress3Channel,
Xspress3ROIChannel,
)
from dodal.log import LOGGER


class TriggerMode(str, Enum):
SOFTWARE = "Software"
HARDWARE = "Hardware"
BURST = "Burst"
TTL_Veto_Only = "TTL Veto Only"
IDC = "IDC"
SOTWARE_START_STOP = "Software Start/Stop"
TTL_BOTH = "TTL Both"
LVDS_VETO_ONLY = "LVDS Veto Only"
LVDS_both = "LVDS Both"


class UpdateRBV(str, Enum):
DISABLED = "Disabled"
ENABLED = "Enabled"


class AcquireRBVState(str, Enum):
DONE = "Done"
ACQUIRE = "Acquiring"


class DetectorState(str, Enum):
IDLE = "Idle"
ACQUIRE = "Acquire"
READOUT = "Readout"
CORRECT = "Correct"
Saving = "Saving"
ABORTING = "Aborting"
ERROR = "Error"
WAITING = "Waiting"
INTILTIALIZING = "Initializing"
DISCONNECTED = "Disconnected"
ABORTED = "Aborted"


class Xspress3(Device, Stageable):
"""Xpress/XpressMini is a region of interest (ROI) picker that sums the detector
output into a scaler with user-defined regions. It is often used as a signal
discriminator to provide better energy resolution and signal to noise in X-ray detection experiments.
This currently only provide staging functionality.

Parameters
----------
prefix:
Beamline part of PV
name:
Name of the device
num_channels:
Number of channel xspress3 has, default is 1 for mini.
timeout:
How long to wait for before timing out for staging/arming of detector default is 1 sec
"""

def __init__(
self, prefix: str, name: str = "", num_channels: int = 1, timeout: float = 1
) -> None:
self.channels = DeviceVector(
{i: Xspress3Channel(f"{prefix}C{i}_") for i in range(1, num_channels + 1)}
)
"""MCA on/off switch readback"""
self.get_roi_calc_status = DeviceVector(
{
i: epics_signal_rw(float, f"{prefix}MCA{i}:Enable_RBV")
for i in range(1, num_channels + 1)
}
)
"""start and size of the multi-channel analyzer (MCA) array"""
self.roi_mca = DeviceVector(
{
i: Xspress3ROIChannel(f"{prefix}ROISUM{i}:")
for i in range(1, num_channels + 1)
}
)

"""signal for the corrected MCA spectrum (1d array)"""
self.dt_corrected_latest_mca = DeviceVector(
{
i: epics_signal_r(NDArray[float64], f"{prefix}ARR{i}:ArrayData")
for i in range(1, num_channels + 1)
}
)

"""Shared controls for triggering detection"""
self.timeout = timeout
self.acquire_time = epics_signal_rw(float, prefix + "AcquireTime")
self.max_num_channels = epics_signal_r(int, prefix + "MAX_NUM_CHANNELS_RBV")
# acquire and acquire readback has a different enum
self.acquire = epics_signal_rw(AcquireState, prefix + "Acquire")
self.acquire_rbv = epics_signal_r(AcquireRBVState, prefix + "Acquire_RBV")
self.trigger_mode = epics_signal_rw_rbv(TriggerMode, prefix + "TriggerMode")

self.detector_state = epics_signal_r(
DetectorState, prefix + "DetectorState_RBV"
)

self.set_num_images = epics_signal_rw(int, prefix + "NumImages")
self.detector_busy_states = [
DetectorState.ACQUIRE,
DetectorState.CORRECT,
DetectorState.ABORTING,
]
super().__init__(name=name)

@AsyncStatus.wrap
async def stage(self) -> None:
LOGGER.info("Arming Xspress3 detector...")
await self.trigger_mode.set(TriggerMode.BURST)
await wait_for_value(
self.detector_state,
lambda v: v in self.detector_busy_states,
timeout=self.timeout,
)
await self.acquire.set(AcquireState.ACQUIRE)
await wait_for_value(
self.acquire_rbv, AcquireRBVState.ACQUIRE, timeout=self.timeout
)

await wait_for_value(
self.acquire_rbv, AcquireRBVState.DONE, timeout=self.timeout
)

@AsyncStatus.wrap
async def unstage(self) -> None:
LOGGER.info("unstaging Xspress3 detector...")
42 changes: 42 additions & 0 deletions src/dodal/devices/xspress3/xspress3_channel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from enum import Enum

from ophyd_async.core import Device
from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw


class AcquireState(str, Enum):
DONE = "Done"
ACQUIRE = "Acquire"


class Xspress3Channel(Device):
"""
Xspress3 Channel contains the truncated detector data and its collection conditions
including the definition of ROI(region of interest).
"""

def __init__(self, prefix: str, name: str = "") -> None:
self.update_arrays = epics_signal_rw(AcquireState, prefix + "SCAS:TS:TSAcquire")

self.roi_high_limit = epics_signal_rw(int, prefix + "SCA5_HLM")
self.roi_low_limit = epics_signal_rw(int, prefix + "SCA5_LLM")
self.time = epics_signal_r(int, prefix + "SCA0:Value_RBV")
self.reset_ticks = epics_signal_r(int, prefix + "SCA1:Value_RBV")
self.reset_count = epics_signal_r(int, prefix + "SCA2:Value_RBV")
self.all_event = epics_signal_r(int, prefix + "SCA3:Value_RBV")
self.all_good = epics_signal_r(int, prefix + "SCA4:Value_RBV")
self.pileup = epics_signal_r(int, prefix + "SCA7:Value_RBV")
self.total_time = epics_signal_r(int, prefix + "SCA8:Value_RBV")
self.mca_roi1_LLM = epics_signal_r(int, prefix + "SCA8:Value_RBV")
super().__init__(name=name)


class Xspress3ROIChannel(Device):
"""
This is the Xspress3 multi-channel analyzer range
"""

def __init__(self, prefix: str, name: str = "") -> None:
self.roi_start_x = epics_signal_rw(int, prefix + "MinX")
self.roi_size_x = epics_signal_rw(int, prefix + "SizeX")
super().__init__(name=name)
103 changes: 0 additions & 103 deletions src/dodal/devices/xspress3_mini/xspress3_mini.py

This file was deleted.

24 changes: 0 additions & 24 deletions src/dodal/devices/xspress3_mini/xspress3_mini_channel.py

This file was deleted.

Loading
Loading