dls-dodal 1.33.0__py3-none-any.whl → 1.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/METADATA +3 -3
- dls_dodal-1.35.0.dist-info/RECORD +147 -0
- {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/WHEEL +1 -1
- dodal/__init__.py +8 -0
- dodal/_version.py +2 -2
- dodal/beamline_specific_utils/i03.py +6 -2
- dodal/beamlines/__init__.py +2 -3
- dodal/beamlines/i03.py +41 -9
- dodal/beamlines/i04.py +26 -4
- dodal/beamlines/i10.py +257 -0
- dodal/beamlines/i22.py +25 -13
- dodal/beamlines/i24.py +11 -11
- dodal/beamlines/p38.py +24 -13
- dodal/common/beamlines/beamline_utils.py +1 -2
- dodal/common/crystal_metadata.py +61 -0
- dodal/common/signal_utils.py +10 -14
- dodal/common/types.py +2 -7
- dodal/devices/CTAB.py +1 -1
- dodal/devices/aperture.py +1 -1
- dodal/devices/aperturescatterguard.py +20 -8
- dodal/devices/apple2_undulator.py +603 -0
- dodal/devices/areadetector/plugins/CAM.py +29 -0
- dodal/devices/areadetector/plugins/MJPG.py +51 -106
- dodal/devices/attenuator.py +1 -1
- dodal/devices/backlight.py +11 -11
- dodal/devices/cryostream.py +3 -5
- dodal/devices/dcm.py +26 -2
- dodal/devices/detector/detector_motion.py +3 -5
- dodal/devices/diamond_filter.py +46 -0
- dodal/devices/eiger.py +6 -2
- dodal/devices/eiger_odin.py +48 -39
- dodal/devices/fast_grid_scan.py +1 -1
- dodal/devices/fluorescence_detector_motion.py +5 -7
- dodal/devices/focusing_mirror.py +26 -19
- dodal/devices/hutch_shutter.py +4 -5
- dodal/devices/i10/i10_apple2.py +399 -0
- dodal/devices/i10/i10_setting_data.py +7 -0
- dodal/devices/i22/dcm.py +50 -83
- dodal/devices/i22/fswitch.py +5 -5
- dodal/devices/i24/aperture.py +3 -5
- dodal/devices/i24/beamstop.py +3 -5
- dodal/devices/i24/dcm.py +1 -1
- dodal/devices/i24/dual_backlight.py +9 -11
- dodal/devices/i24/pmac.py +35 -46
- dodal/devices/i24/vgonio.py +16 -0
- dodal/devices/ipin.py +5 -3
- dodal/devices/linkam3.py +7 -7
- dodal/devices/oav/oav_calculations.py +22 -0
- dodal/devices/oav/oav_detector.py +118 -83
- dodal/devices/oav/oav_parameters.py +50 -104
- dodal/devices/oav/oav_to_redis_forwarder.py +77 -35
- dodal/devices/oav/pin_image_recognition/__init__.py +9 -7
- dodal/devices/oav/{grid_overlay.py → snapshots/grid_overlay.py} +16 -59
- dodal/devices/oav/snapshots/snapshot_with_beam_centre.py +64 -0
- dodal/devices/oav/snapshots/snapshot_with_grid.py +57 -0
- dodal/devices/oav/utils.py +28 -27
- dodal/devices/p99/sample_stage.py +3 -5
- dodal/devices/pgm.py +40 -0
- dodal/devices/qbpm.py +18 -0
- dodal/devices/robot.py +5 -5
- dodal/devices/smargon.py +3 -3
- dodal/devices/synchrotron.py +9 -4
- dodal/devices/tetramm.py +9 -9
- dodal/devices/thawer.py +13 -7
- dodal/devices/undulator.py +7 -6
- dodal/devices/util/adjuster_plans.py +1 -1
- dodal/devices/util/epics_util.py +1 -1
- dodal/devices/util/lookup_tables.py +4 -5
- dodal/devices/watsonmarlow323_pump.py +45 -0
- dodal/devices/webcam.py +9 -2
- dodal/devices/xbpm_feedback.py +3 -5
- dodal/devices/xspress3/xspress3.py +8 -9
- dodal/devices/xspress3/xspress3_channel.py +3 -5
- dodal/devices/zebra.py +12 -8
- dodal/devices/zebra_controlled_shutter.py +5 -6
- dodal/devices/zocalo/__init__.py +2 -2
- dodal/devices/zocalo/zocalo_constants.py +3 -0
- dodal/devices/zocalo/zocalo_interaction.py +2 -1
- dodal/devices/zocalo/zocalo_results.py +105 -89
- dodal/plans/data_session_metadata.py +2 -2
- dodal/plans/motor_util_plans.py +11 -9
- dodal/utils.py +11 -0
- dls_dodal-1.33.0.dist-info/RECORD +0 -136
- dodal/beamlines/i04_1.py +0 -140
- dodal/devices/i24/i24_vgonio.py +0 -17
- dodal/devices/oav/oav_errors.py +0 -35
- {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/top_level.txt +0 -0
dodal/devices/oav/utils.py
CHANGED
|
@@ -5,8 +5,11 @@ import bluesky.plan_stubs as bps
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
from bluesky.utils import Msg
|
|
7
7
|
|
|
8
|
-
from dodal.devices.oav.oav_calculations import
|
|
9
|
-
|
|
8
|
+
from dodal.devices.oav.oav_calculations import (
|
|
9
|
+
calculate_beam_distance,
|
|
10
|
+
camera_coordinates_to_xyz,
|
|
11
|
+
)
|
|
12
|
+
from dodal.devices.oav.oav_detector import OAV
|
|
10
13
|
from dodal.devices.oav.pin_image_recognition import PinTipDetection
|
|
11
14
|
from dodal.devices.smargon import Smargon
|
|
12
15
|
|
|
@@ -36,21 +39,6 @@ def bottom_right_from_top_left(
|
|
|
36
39
|
)
|
|
37
40
|
|
|
38
41
|
|
|
39
|
-
class ColorMode(IntEnum):
|
|
40
|
-
"""
|
|
41
|
-
Enum to store the various color modes of the camera. We use RGB1.
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
MONO = 0
|
|
45
|
-
BAYER = 1
|
|
46
|
-
RGB1 = 2
|
|
47
|
-
RGB2 = 3
|
|
48
|
-
RGB3 = 4
|
|
49
|
-
YUV444 = 5
|
|
50
|
-
YUV422 = 6
|
|
51
|
-
YUV421 = 7
|
|
52
|
-
|
|
53
|
-
|
|
54
42
|
class EdgeOutputArrayImageType(IntEnum):
|
|
55
43
|
"""
|
|
56
44
|
Enum to store the types of image to tweak the output array. We use Original.
|
|
@@ -64,7 +52,7 @@ class EdgeOutputArrayImageType(IntEnum):
|
|
|
64
52
|
|
|
65
53
|
|
|
66
54
|
def get_move_required_so_that_beam_is_at_pixel(
|
|
67
|
-
smargon: Smargon, pixel: Pixel,
|
|
55
|
+
smargon: Smargon, pixel: Pixel, oav: OAV
|
|
68
56
|
) -> Generator[Msg, None, np.ndarray]:
|
|
69
57
|
"""Calculate the required move so that the given pixel is in the centre of the beam."""
|
|
70
58
|
|
|
@@ -78,22 +66,35 @@ def get_move_required_so_that_beam_is_at_pixel(
|
|
|
78
66
|
)
|
|
79
67
|
current_angle = yield from bps.rd(smargon.omega)
|
|
80
68
|
|
|
81
|
-
|
|
69
|
+
beam_x = yield from bps.rd(oav.beam_centre_i)
|
|
70
|
+
beam_y = yield from bps.rd(oav.beam_centre_j)
|
|
71
|
+
microns_per_pixel_x = yield from bps.rd(oav.microns_per_pixel_x)
|
|
72
|
+
microns_per_pixel_y = yield from bps.rd(oav.microns_per_pixel_y)
|
|
73
|
+
|
|
74
|
+
return calculate_x_y_z_of_pixel(
|
|
75
|
+
current_motor_xyz,
|
|
76
|
+
current_angle,
|
|
77
|
+
pixel,
|
|
78
|
+
(beam_x, beam_y),
|
|
79
|
+
(microns_per_pixel_x, microns_per_pixel_y),
|
|
80
|
+
)
|
|
82
81
|
|
|
83
82
|
|
|
84
83
|
def calculate_x_y_z_of_pixel(
|
|
85
|
-
current_x_y_z,
|
|
84
|
+
current_x_y_z,
|
|
85
|
+
current_omega,
|
|
86
|
+
pixel: Pixel,
|
|
87
|
+
beam_centre: tuple[int, int],
|
|
88
|
+
microns_per_pixel: tuple[float, float],
|
|
86
89
|
) -> np.ndarray:
|
|
87
|
-
beam_distance_px: Pixel =
|
|
90
|
+
beam_distance_px: Pixel = calculate_beam_distance(beam_centre, *pixel)
|
|
88
91
|
|
|
89
|
-
assert oav_params.micronsPerXPixel
|
|
90
|
-
assert oav_params.micronsPerYPixel
|
|
91
92
|
return current_x_y_z + camera_coordinates_to_xyz(
|
|
92
93
|
beam_distance_px[0],
|
|
93
94
|
beam_distance_px[1],
|
|
94
95
|
current_omega,
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
microns_per_pixel[0],
|
|
97
|
+
microns_per_pixel[1],
|
|
97
98
|
)
|
|
98
99
|
|
|
99
100
|
|
|
@@ -102,8 +103,8 @@ def wait_for_tip_to_be_found(
|
|
|
102
103
|
) -> Generator[Msg, None, Pixel]:
|
|
103
104
|
yield from bps.trigger(ophyd_pin_tip_detection, wait=True)
|
|
104
105
|
found_tip = yield from bps.rd(ophyd_pin_tip_detection.triggered_tip)
|
|
105
|
-
if found_tip == ophyd_pin_tip_detection.INVALID_POSITION:
|
|
106
|
+
if all(found_tip == ophyd_pin_tip_detection.INVALID_POSITION):
|
|
106
107
|
timeout = yield from bps.rd(ophyd_pin_tip_detection.validity_timeout)
|
|
107
108
|
raise PinNotFoundException(f"No pin found after {timeout} seconds")
|
|
108
109
|
|
|
109
|
-
return found_tip
|
|
110
|
+
return Pixel((int(found_tip[0]), int(found_tip[1])))
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from ophyd_async.core import Device
|
|
4
|
-
from ophyd_async.epics.signal import epics_signal_rw
|
|
1
|
+
from ophyd_async.core import Device, SubsetEnum
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
5
3
|
|
|
6
4
|
|
|
7
5
|
class SampleAngleStage(Device):
|
|
@@ -18,7 +16,7 @@ class SampleAngleStage(Device):
|
|
|
18
16
|
super().__init__(name=name)
|
|
19
17
|
|
|
20
18
|
|
|
21
|
-
class p99StageSelections(
|
|
19
|
+
class p99StageSelections(SubsetEnum):
|
|
22
20
|
Empty = "Empty"
|
|
23
21
|
Mn5um = "Mn 5um"
|
|
24
22
|
Fe = "Fe (empty)"
|
dodal/devices/pgm.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from ophyd_async.core import (
|
|
2
|
+
StandardReadable,
|
|
3
|
+
StandardReadableFormat,
|
|
4
|
+
StrictEnum,
|
|
5
|
+
)
|
|
6
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
7
|
+
from ophyd_async.epics.motor import Motor
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PGM(StandardReadable):
|
|
11
|
+
"""
|
|
12
|
+
Plane grating monochromator, it is use in soft x-ray beamline to generate monochromic beam.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
prefix: str,
|
|
18
|
+
grating: type[StrictEnum],
|
|
19
|
+
gratingPv: str,
|
|
20
|
+
name: str = "",
|
|
21
|
+
) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
prefix:
|
|
26
|
+
Beamline specific part of the PV
|
|
27
|
+
grating:
|
|
28
|
+
The Enum for the grating table.
|
|
29
|
+
gratingPv:
|
|
30
|
+
The suffix pv part of grating Pv
|
|
31
|
+
name:
|
|
32
|
+
Name of the device
|
|
33
|
+
"""
|
|
34
|
+
with self.add_children_as_readables():
|
|
35
|
+
self.energy = Motor(prefix + "ENERGY")
|
|
36
|
+
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
37
|
+
self.grating = epics_signal_rw(grating, prefix + gratingPv)
|
|
38
|
+
self.cff = epics_signal_rw(float, prefix + "CFF")
|
|
39
|
+
|
|
40
|
+
super().__init__(name=name)
|
dodal/devices/qbpm.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class QBPM(StandardReadable):
|
|
6
|
+
"""
|
|
7
|
+
A beam position monitor that gives a position and intensity of the beam.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
prefix: str,
|
|
13
|
+
name: str = "",
|
|
14
|
+
) -> None:
|
|
15
|
+
with self.add_children_as_readables():
|
|
16
|
+
self.intensity_uA = epics_signal_r(float, f"{prefix}INTEN")
|
|
17
|
+
|
|
18
|
+
super().__init__(name)
|
dodal/devices/robot.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from asyncio import FIRST_COMPLETED, CancelledError, Task, wait_for
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from enum import Enum
|
|
5
4
|
|
|
6
5
|
from bluesky.protocols import Movable
|
|
7
6
|
from ophyd_async.core import (
|
|
8
7
|
AsyncStatus,
|
|
9
8
|
StandardReadable,
|
|
9
|
+
StrictEnum,
|
|
10
10
|
set_and_wait_for_value,
|
|
11
11
|
wait_for_value,
|
|
12
12
|
)
|
|
13
|
-
from ophyd_async.epics.
|
|
13
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw_rbv, epics_signal_x
|
|
14
14
|
|
|
15
15
|
from dodal.log import LOGGER
|
|
16
16
|
|
|
@@ -33,7 +33,7 @@ class SampleLocation:
|
|
|
33
33
|
pin: int
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class PinMounted(
|
|
36
|
+
class PinMounted(StrictEnum):
|
|
37
37
|
NO_PIN_MOUNTED = "No Pin Mounted"
|
|
38
38
|
PIN_MOUNTED = "Pin Mounted"
|
|
39
39
|
|
|
@@ -63,8 +63,8 @@ class BartRobot(StandardReadable, Movable):
|
|
|
63
63
|
self.current_puck = epics_signal_r(float, prefix + "CURRENT_PUCK_RBV")
|
|
64
64
|
self.current_pin = epics_signal_r(float, prefix + "CURRENT_PIN_RBV")
|
|
65
65
|
|
|
66
|
-
self.next_sample_id = epics_signal_rw_rbv(
|
|
67
|
-
self.sample_id = epics_signal_r(
|
|
66
|
+
self.next_sample_id = epics_signal_rw_rbv(int, prefix + "NEXT_ID")
|
|
67
|
+
self.sample_id = epics_signal_r(int, prefix + "CURRENT_ID_RBV")
|
|
68
68
|
|
|
69
69
|
self.load = epics_signal_x(prefix + "LOAD.PROC")
|
|
70
70
|
self.program_running = epics_signal_r(bool, prefix + "PROGRAM_RUNNING")
|
dodal/devices/smargon.py
CHANGED
|
@@ -7,8 +7,8 @@ from typing import cast
|
|
|
7
7
|
from bluesky import plan_stubs as bps
|
|
8
8
|
from bluesky.utils import Msg
|
|
9
9
|
from ophyd_async.core import AsyncStatus, Device, StandardReadable, wait_for_value
|
|
10
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
10
11
|
from ophyd_async.epics.motor import Motor
|
|
11
|
-
from ophyd_async.epics.signal import epics_signal_r
|
|
12
12
|
|
|
13
13
|
from dodal.devices.util.epics_util import SetWhenEnabled
|
|
14
14
|
|
|
@@ -40,8 +40,8 @@ class StubOffsets(Device):
|
|
|
40
40
|
super().__init__(name)
|
|
41
41
|
|
|
42
42
|
@AsyncStatus.wrap
|
|
43
|
-
async def set(self,
|
|
44
|
-
if
|
|
43
|
+
async def set(self, value: StubPosition):
|
|
44
|
+
if value == StubPosition.CURRENT_AS_CENTER:
|
|
45
45
|
await self.center_at_current_position.set(1)
|
|
46
46
|
smargon = cast(Smargon, self.parent)
|
|
47
47
|
await wait_for_value(
|
dodal/devices/synchrotron.py
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
-
from ophyd_async.core import
|
|
4
|
-
|
|
3
|
+
from ophyd_async.core import (
|
|
4
|
+
StandardReadable,
|
|
5
|
+
StandardReadableFormat,
|
|
6
|
+
StrictEnum,
|
|
7
|
+
soft_signal_r_and_setter,
|
|
8
|
+
)
|
|
9
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
5
10
|
|
|
6
11
|
|
|
7
12
|
class Prefix(str, Enum):
|
|
@@ -19,7 +24,7 @@ class Suffix(str, Enum):
|
|
|
19
24
|
END_COUNTDOWN = "ENDCOUNTDN"
|
|
20
25
|
|
|
21
26
|
|
|
22
|
-
class SynchrotronMode(
|
|
27
|
+
class SynchrotronMode(StrictEnum):
|
|
23
28
|
SHUTDOWN = "Shutdown"
|
|
24
29
|
INJECTION = "Injection"
|
|
25
30
|
NOBEAM = "No Beam"
|
|
@@ -44,7 +49,7 @@ class Synchrotron(StandardReadable):
|
|
|
44
49
|
self.current = epics_signal_r(float, signal_prefix + Suffix.SIGNAL)
|
|
45
50
|
self.energy = epics_signal_r(float, status_prefix + Suffix.BEAM_ENERGY)
|
|
46
51
|
|
|
47
|
-
with self.add_children_as_readables(
|
|
52
|
+
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
48
53
|
self.probe, _ = soft_signal_r_and_setter(str, initial_value="x-ray")
|
|
49
54
|
self.type, _ = soft_signal_r_and_setter(
|
|
50
55
|
str, initial_value="Synchrotron X-ray Source"
|
dodal/devices/tetramm.py
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from enum import Enum
|
|
3
2
|
|
|
4
3
|
from bluesky.protocols import Hints
|
|
5
4
|
from ophyd_async.core import (
|
|
6
5
|
DatasetDescriber,
|
|
7
|
-
|
|
6
|
+
DetectorController,
|
|
8
7
|
DetectorTrigger,
|
|
9
8
|
Device,
|
|
10
9
|
PathProvider,
|
|
11
10
|
StandardDetector,
|
|
11
|
+
StrictEnum,
|
|
12
12
|
TriggerInfo,
|
|
13
13
|
set_and_wait_for_value,
|
|
14
14
|
soft_signal_r_and_setter,
|
|
15
15
|
)
|
|
16
16
|
from ophyd_async.epics.adcore import ADHDFWriter, NDFileHDFIO, stop_busy_record
|
|
17
|
-
from ophyd_async.epics.
|
|
17
|
+
from ophyd_async.epics.core import (
|
|
18
18
|
epics_signal_r,
|
|
19
19
|
epics_signal_rw,
|
|
20
20
|
epics_signal_rw_rbv,
|
|
21
21
|
)
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
class TetrammRange(
|
|
24
|
+
class TetrammRange(StrictEnum):
|
|
25
25
|
uA = "+- 120 uA"
|
|
26
26
|
nA = "+- 120 nA"
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class TetrammTrigger(
|
|
29
|
+
class TetrammTrigger(StrictEnum):
|
|
30
30
|
FreeRun = "Free run"
|
|
31
31
|
ExtTrigger = "Ext. trig."
|
|
32
32
|
ExtBulb = "Ext. bulb"
|
|
33
33
|
ExtGate = "Ext. gate"
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class TetrammChannels(
|
|
36
|
+
class TetrammChannels(StrictEnum):
|
|
37
37
|
One = "1"
|
|
38
38
|
Two = "2"
|
|
39
39
|
Four = "4"
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
class TetrammResolution(
|
|
42
|
+
class TetrammResolution(StrictEnum):
|
|
43
43
|
SixteenBits = "16 bits"
|
|
44
44
|
TwentyFourBits = "24 bits"
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
class TetrammGeometry(
|
|
47
|
+
class TetrammGeometry(StrictEnum):
|
|
48
48
|
Diamond = "Diamond"
|
|
49
49
|
Square = "Square"
|
|
50
50
|
|
|
@@ -80,7 +80,7 @@ class TetrammDriver(Device):
|
|
|
80
80
|
super().__init__(name=name)
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
class TetrammController(
|
|
83
|
+
class TetrammController(DetectorController):
|
|
84
84
|
"""Controller for a TetrAMM current monitor
|
|
85
85
|
|
|
86
86
|
Attributes:
|
dodal/devices/thawer.py
CHANGED
|
@@ -1,36 +1,42 @@
|
|
|
1
1
|
from asyncio import Task, create_task, sleep
|
|
2
|
-
from enum import Enum
|
|
3
2
|
|
|
4
3
|
from bluesky.protocols import Stoppable
|
|
5
|
-
from ophyd_async.core import
|
|
6
|
-
|
|
4
|
+
from ophyd_async.core import (
|
|
5
|
+
AsyncStatus,
|
|
6
|
+
Device,
|
|
7
|
+
Reference,
|
|
8
|
+
SignalRW,
|
|
9
|
+
StandardReadable,
|
|
10
|
+
StrictEnum,
|
|
11
|
+
)
|
|
12
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
7
13
|
|
|
8
14
|
|
|
9
15
|
class ThawingException(Exception):
|
|
10
16
|
pass
|
|
11
17
|
|
|
12
18
|
|
|
13
|
-
class ThawerStates(
|
|
19
|
+
class ThawerStates(StrictEnum):
|
|
14
20
|
OFF = "Off"
|
|
15
21
|
ON = "On"
|
|
16
22
|
|
|
17
23
|
|
|
18
24
|
class ThawingTimer(Device, Stoppable):
|
|
19
25
|
def __init__(self, control_signal: SignalRW[ThawerStates]) -> None:
|
|
20
|
-
self.
|
|
26
|
+
self._control_signal_ref = Reference(control_signal)
|
|
21
27
|
self._thawing_task: Task | None = None
|
|
22
28
|
super().__init__("thaw_for_time_s")
|
|
23
29
|
|
|
24
30
|
@AsyncStatus.wrap
|
|
25
31
|
async def set(self, time_to_thaw_for: float):
|
|
26
|
-
await self.
|
|
32
|
+
await self._control_signal_ref().set(ThawerStates.ON)
|
|
27
33
|
if self._thawing_task and not self._thawing_task.done():
|
|
28
34
|
raise ThawingException("Thawing task already in progress")
|
|
29
35
|
self._thawing_task = create_task(sleep(time_to_thaw_for))
|
|
30
36
|
try:
|
|
31
37
|
await self._thawing_task
|
|
32
38
|
finally:
|
|
33
|
-
await self.
|
|
39
|
+
await self._control_signal_ref().set(ThawerStates.OFF)
|
|
34
40
|
|
|
35
41
|
@AsyncStatus.wrap
|
|
36
42
|
async def stop(self, *args, **kwargs):
|
dodal/devices/undulator.py
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import os
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from bluesky.protocols import Movable
|
|
5
5
|
from numpy import argmin, ndarray
|
|
6
6
|
from ophyd_async.core import (
|
|
7
7
|
AsyncStatus,
|
|
8
|
-
ConfigSignal,
|
|
9
8
|
StandardReadable,
|
|
9
|
+
StandardReadableFormat,
|
|
10
|
+
StrictEnum,
|
|
10
11
|
soft_signal_r_and_setter,
|
|
11
12
|
)
|
|
13
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
12
14
|
from ophyd_async.epics.motor import Motor
|
|
13
|
-
from ophyd_async.epics.signal import epics_signal_r
|
|
14
15
|
|
|
15
16
|
from dodal.log import LOGGER
|
|
16
17
|
|
|
@@ -32,7 +33,7 @@ UNDULATOR_DISCREPANCY_THRESHOLD_MM = 2e-3
|
|
|
32
33
|
STATUS_TIMEOUT_S: float = 10.0
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
class UndulatorGapAccess(
|
|
36
|
+
class UndulatorGapAccess(StrictEnum):
|
|
36
37
|
ENABLED = "ENABLED"
|
|
37
38
|
DISABLED = "DISABLED"
|
|
38
39
|
|
|
@@ -54,7 +55,7 @@ class Undulator(StandardReadable, Movable):
|
|
|
54
55
|
def __init__(
|
|
55
56
|
self,
|
|
56
57
|
prefix: str,
|
|
57
|
-
id_gap_lookup_table_path: str,
|
|
58
|
+
id_gap_lookup_table_path: str = os.devnull,
|
|
58
59
|
name: str = "",
|
|
59
60
|
poles: int | None = None,
|
|
60
61
|
length: float | None = None,
|
|
@@ -74,7 +75,7 @@ class Undulator(StandardReadable, Movable):
|
|
|
74
75
|
self.current_gap = epics_signal_r(float, prefix + "CURRGAPD")
|
|
75
76
|
self.gap_access = epics_signal_r(UndulatorGapAccess, prefix + "IDBLENA")
|
|
76
77
|
|
|
77
|
-
with self.add_children_as_readables(
|
|
78
|
+
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
78
79
|
self.gap_discrepancy_tolerance_mm, _ = soft_signal_r_and_setter(
|
|
79
80
|
float,
|
|
80
81
|
initial_value=UNDULATOR_DISCREPANCY_THRESHOLD_MM,
|
|
@@ -21,6 +21,6 @@ def lookup_table_adjuster(
|
|
|
21
21
|
def adjust(group=None) -> Generator[Msg, None, None]:
|
|
22
22
|
setpoint = lookup_table(input)
|
|
23
23
|
LOGGER.info(f"lookup_table_adjuster setting {output_device.name} to {setpoint}")
|
|
24
|
-
yield from bps.abs_set(output_device, setpoint, group=group)
|
|
24
|
+
yield from bps.abs_set(output_device, setpoint, group=group) # type: ignore # See: https://github.com/DiamondLightSource/dodal/issues/827
|
|
25
25
|
|
|
26
26
|
return adjust
|
dodal/devices/util/epics_util.py
CHANGED
|
@@ -7,7 +7,7 @@ from ophyd import Device as OphydDevice
|
|
|
7
7
|
from ophyd.status import Status, StatusBase
|
|
8
8
|
from ophyd_async.core import AsyncStatus, wait_for_value
|
|
9
9
|
from ophyd_async.core import Device as OphydAsyncDevice
|
|
10
|
-
from ophyd_async.epics.
|
|
10
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
11
11
|
|
|
12
12
|
from dodal.log import LOGGER
|
|
13
13
|
|
|
@@ -33,7 +33,10 @@ async def energy_distance_table(lookup_table_path: str) -> np.ndarray:
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def linear_interpolation_lut(filename: str) -> Callable[[float], float]:
|
|
36
|
-
"""Returns a callable that converts values by linear interpolation of lookup table
|
|
36
|
+
"""Returns a callable that converts values by linear interpolation of lookup table
|
|
37
|
+
values.
|
|
38
|
+
|
|
39
|
+
If the value falls outside the lookup table then the closest value will be used."""
|
|
37
40
|
LOGGER.info(f"Using lookup table {filename}")
|
|
38
41
|
s_and_t_vals = zip(*loadtxt(filename, comments=["#", "Units"]), strict=False)
|
|
39
42
|
|
|
@@ -54,10 +57,6 @@ def linear_interpolation_lut(filename: str) -> Callable[[float], float]:
|
|
|
54
57
|
)
|
|
55
58
|
|
|
56
59
|
def s_to_t2(s: float) -> float:
|
|
57
|
-
if s < s_values[0] or s > s_values[len(s_values) - 1]:
|
|
58
|
-
raise ValueError(
|
|
59
|
-
f"Lookup table does not support extrapolation from file {filename}, s={s}"
|
|
60
|
-
)
|
|
61
60
|
return float(interp(s, s_values, t_values))
|
|
62
61
|
|
|
63
62
|
return s_to_t2
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from ophyd_async.core import StandardReadable, StandardReadableFormat, StrictEnum
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class WatsonMarlow323PumpEnable(StrictEnum):
|
|
6
|
+
DISABLED = "Disabled"
|
|
7
|
+
ENABLED = "Enabled"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class WatsonMarlow323PumpDirection(StrictEnum):
|
|
11
|
+
CLOCKWISE = "CW"
|
|
12
|
+
COUNTER_CLOCKWISE = "CCW"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class WatsonMarlow323PumpState(StrictEnum):
|
|
16
|
+
STOPPED = "STOP"
|
|
17
|
+
STARTED = "START"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class WatsonMarlow323Pump(StandardReadable):
|
|
21
|
+
"""Watson Marlow 323 Peristaltic Pump device"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
24
|
+
with self.add_children_as_readables():
|
|
25
|
+
self.direction = epics_signal_rw(
|
|
26
|
+
WatsonMarlow323PumpDirection,
|
|
27
|
+
read_pv=prefix + "INFO:DIR",
|
|
28
|
+
write_pv=prefix + "SET:DIR",
|
|
29
|
+
)
|
|
30
|
+
self.state = epics_signal_rw(
|
|
31
|
+
WatsonMarlow323PumpState,
|
|
32
|
+
read_pv=prefix + "INFO:RUN",
|
|
33
|
+
write_pv=prefix + "SET:RUN",
|
|
34
|
+
)
|
|
35
|
+
self.speed = epics_signal_rw(
|
|
36
|
+
float, read_pv=prefix + "INFO:SPD", write_pv=prefix + "SET:SPD"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
40
|
+
self.enabled = epics_signal_rw(
|
|
41
|
+
WatsonMarlow323PumpEnable,
|
|
42
|
+
prefix + "DISABLE",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
super().__init__(name=name)
|
dodal/devices/webcam.py
CHANGED
|
@@ -5,7 +5,12 @@ from pathlib import Path
|
|
|
5
5
|
import aiofiles
|
|
6
6
|
from aiohttp import ClientSession
|
|
7
7
|
from bluesky.protocols import Triggerable
|
|
8
|
-
from ophyd_async.core import
|
|
8
|
+
from ophyd_async.core import (
|
|
9
|
+
AsyncStatus,
|
|
10
|
+
StandardReadable,
|
|
11
|
+
StandardReadableFormat,
|
|
12
|
+
soft_signal_rw,
|
|
13
|
+
)
|
|
9
14
|
from PIL import Image
|
|
10
15
|
|
|
11
16
|
from dodal.log import LOGGER
|
|
@@ -27,7 +32,9 @@ class Webcam(StandardReadable, Triggerable):
|
|
|
27
32
|
self.directory = soft_signal_rw(str, name="directory")
|
|
28
33
|
self.last_saved_path = soft_signal_rw(str, name="last_saved_path")
|
|
29
34
|
|
|
30
|
-
self.add_readables(
|
|
35
|
+
self.add_readables(
|
|
36
|
+
[self.last_saved_path], format=StandardReadableFormat.HINTED_SIGNAL
|
|
37
|
+
)
|
|
31
38
|
super().__init__(name=name)
|
|
32
39
|
|
|
33
40
|
async def _write_image(self, file_path: str, image: ByteString):
|
dodal/devices/xbpm_feedback.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
|
|
3
1
|
from bluesky.protocols import Triggerable
|
|
4
|
-
from ophyd_async.core import AsyncStatus, Device, observe_value
|
|
5
|
-
from ophyd_async.epics.
|
|
2
|
+
from ophyd_async.core import AsyncStatus, Device, StrictEnum, observe_value
|
|
3
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
6
4
|
|
|
7
5
|
|
|
8
|
-
class Pause(
|
|
6
|
+
class Pause(StrictEnum):
|
|
9
7
|
PAUSE = "Paused" # 0
|
|
10
8
|
RUN = "Ok to Run" # 1
|
|
11
9
|
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
|
|
3
1
|
from bluesky.protocols import Stageable
|
|
4
2
|
from numpy import float64
|
|
5
|
-
from numpy.typing import NDArray
|
|
6
3
|
from ophyd_async.core import (
|
|
4
|
+
Array1D,
|
|
7
5
|
AsyncStatus,
|
|
8
6
|
Device,
|
|
9
7
|
DeviceVector,
|
|
8
|
+
StrictEnum,
|
|
10
9
|
wait_for_value,
|
|
11
10
|
)
|
|
12
|
-
from ophyd_async.epics.
|
|
11
|
+
from ophyd_async.epics.core import (
|
|
13
12
|
epics_signal_r,
|
|
14
13
|
epics_signal_rw,
|
|
15
14
|
epics_signal_rw_rbv,
|
|
@@ -23,7 +22,7 @@ from dodal.devices.xspress3.xspress3_channel import (
|
|
|
23
22
|
from dodal.log import LOGGER
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
class TriggerMode(
|
|
25
|
+
class TriggerMode(StrictEnum):
|
|
27
26
|
SOFTWARE = "Software"
|
|
28
27
|
HARDWARE = "Hardware"
|
|
29
28
|
BURST = "Burst"
|
|
@@ -35,17 +34,17 @@ class TriggerMode(str, Enum):
|
|
|
35
34
|
LVDS_both = "LVDS Both"
|
|
36
35
|
|
|
37
36
|
|
|
38
|
-
class UpdateRBV(
|
|
37
|
+
class UpdateRBV(StrictEnum):
|
|
39
38
|
DISABLED = "Disabled"
|
|
40
39
|
ENABLED = "Enabled"
|
|
41
40
|
|
|
42
41
|
|
|
43
|
-
class AcquireRBVState(
|
|
42
|
+
class AcquireRBVState(StrictEnum):
|
|
44
43
|
DONE = "Done"
|
|
45
44
|
ACQUIRE = "Acquiring"
|
|
46
45
|
|
|
47
46
|
|
|
48
|
-
class DetectorState(
|
|
47
|
+
class DetectorState(StrictEnum):
|
|
49
48
|
IDLE = "Idle"
|
|
50
49
|
ACQUIRE = "Acquire"
|
|
51
50
|
READOUT = "Readout"
|
|
@@ -101,7 +100,7 @@ class Xspress3(Device, Stageable):
|
|
|
101
100
|
"""signal for the corrected MCA spectrum (1d array)"""
|
|
102
101
|
self.dt_corrected_latest_mca = DeviceVector(
|
|
103
102
|
{
|
|
104
|
-
i: epics_signal_r(
|
|
103
|
+
i: epics_signal_r(Array1D[float64], f"{prefix}ARR{i}:ArrayData")
|
|
105
104
|
for i in range(1, num_channels + 1)
|
|
106
105
|
}
|
|
107
106
|
)
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ophyd_async.core import Device, StrictEnum
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
2
3
|
|
|
3
|
-
from ophyd_async.core import Device
|
|
4
|
-
from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
class AcquireState(str, Enum):
|
|
5
|
+
class AcquireState(StrictEnum):
|
|
8
6
|
DONE = "Done"
|
|
9
7
|
ACQUIRE = "Acquire"
|
|
10
8
|
|