dls-dodal 1.34.1__py3-none-any.whl → 1.36.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.34.1.dist-info → dls_dodal-1.36.0.dist-info}/METADATA +4 -2
- dls_dodal-1.36.0.dist-info/RECORD +152 -0
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.36.0.dist-info}/WHEEL +1 -1
- dodal/_version.py +2 -2
- dodal/beamlines/i22.py +24 -11
- dodal/beamlines/i24.py +4 -4
- dodal/beamlines/p38.py +23 -11
- dodal/common/beamlines/beamline_utils.py +1 -2
- dodal/common/crystal_metadata.py +61 -0
- dodal/common/signal_utils.py +10 -14
- dodal/devices/CTAB.py +1 -1
- dodal/devices/aperture.py +1 -1
- dodal/devices/aperturescatterguard.py +20 -8
- dodal/devices/apple2_undulator.py +30 -29
- dodal/devices/areadetector/plugins/CAM.py +3 -5
- dodal/devices/areadetector/plugins/MJPG.py +1 -1
- dodal/devices/attenuator.py +1 -1
- dodal/devices/backlight.py +4 -5
- 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 +3 -4
- dodal/devices/eiger.py +88 -49
- dodal/devices/fast_grid_scan.py +1 -1
- dodal/devices/fluorescence_detector_motion.py +5 -7
- dodal/devices/focusing_mirror.py +12 -11
- dodal/devices/hutch_shutter.py +4 -5
- dodal/devices/i10/i10_apple2.py +20 -19
- dodal/devices/i10/i10_setting_data.py +2 -2
- dodal/devices/i22/dcm.py +43 -75
- 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 +4 -6
- 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_detector.py +3 -3
- dodal/devices/oav/oav_to_redis_forwarder.py +8 -7
- dodal/devices/oav/pin_image_recognition/__init__.py +9 -7
- dodal/devices/oav/snapshots/grid_overlay.py +16 -16
- dodal/devices/oav/snapshots/snapshot_with_beam_centre.py +5 -5
- dodal/devices/oav/snapshots/snapshot_with_grid.py +6 -6
- dodal/devices/oav/utils.py +2 -2
- dodal/devices/p99/sample_stage.py +3 -5
- dodal/devices/pgm.py +5 -6
- dodal/devices/qbpm.py +1 -1
- dodal/devices/robot.py +3 -3
- dodal/devices/smargon.py +1 -1
- dodal/devices/synchrotron.py +9 -4
- dodal/devices/tetramm.py +7 -7
- dodal/devices/thawer.py +13 -7
- dodal/devices/undulator.py +5 -5
- dodal/devices/util/epics_util.py +1 -1
- 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 +7 -6
- 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 +92 -79
- dodal/plan_stubs/__init__.py +0 -0
- dodal/{plans/data_session_metadata.py → plan_stubs/data_session.py} +2 -2
- dodal/{plans/motor_util_plans.py → plan_stubs/motor_utils.py} +2 -2
- dodal/plan_stubs/wrapped.py +150 -0
- dodal/plans/__init__.py +4 -0
- dodal/plans/scanspec.py +66 -0
- dodal/plans/wrapped.py +57 -0
- dodal/utils.py +4 -0
- dls_dodal-1.34.1.dist-info/RECORD +0 -144
- dodal/devices/i24/i24_vgonio.py +0 -17
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.36.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.36.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.36.0.dist-info}/top_level.txt +0 -0
- /dodal/{plans → plan_stubs}/check_topup.py +0 -0
dodal/devices/focusing_mirror.py
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
|
|
3
1
|
from ophyd_async.core import (
|
|
4
2
|
AsyncStatus,
|
|
5
|
-
ConfigSignal,
|
|
6
3
|
Device,
|
|
7
4
|
DeviceVector,
|
|
8
|
-
HintedSignal,
|
|
9
5
|
StandardReadable,
|
|
6
|
+
StandardReadableFormat,
|
|
7
|
+
StrictEnum,
|
|
10
8
|
observe_value,
|
|
11
9
|
soft_signal_r_and_setter,
|
|
12
10
|
)
|
|
13
|
-
from ophyd_async.epics.
|
|
14
|
-
from ophyd_async.epics.signal import (
|
|
11
|
+
from ophyd_async.epics.core import (
|
|
15
12
|
epics_signal_r,
|
|
16
13
|
epics_signal_rw,
|
|
17
14
|
epics_signal_x,
|
|
18
15
|
)
|
|
16
|
+
from ophyd_async.epics.motor import Motor
|
|
19
17
|
|
|
20
18
|
from dodal.log import LOGGER
|
|
21
19
|
|
|
@@ -25,20 +23,20 @@ VOLTAGE_POLLING_DELAY_S = 0.5
|
|
|
25
23
|
DEFAULT_SETTLE_TIME_S = 60
|
|
26
24
|
|
|
27
25
|
|
|
28
|
-
class MirrorType(
|
|
26
|
+
class MirrorType(StrictEnum):
|
|
29
27
|
"""See https://manual.nexusformat.org/classes/base_classes/NXmirror.html"""
|
|
30
28
|
|
|
31
29
|
SINGLE = "single"
|
|
32
30
|
MULTI = "multi"
|
|
33
31
|
|
|
34
32
|
|
|
35
|
-
class MirrorStripe(
|
|
33
|
+
class MirrorStripe(StrictEnum):
|
|
36
34
|
RHODIUM = "Rhodium"
|
|
37
35
|
BARE = "Bare"
|
|
38
36
|
PLATINUM = "Platinum"
|
|
39
37
|
|
|
40
38
|
|
|
41
|
-
class MirrorVoltageDemand(
|
|
39
|
+
class MirrorVoltageDemand(StrictEnum):
|
|
42
40
|
N_A = "N/A"
|
|
43
41
|
OK = "OK"
|
|
44
42
|
FAIL = "FAIL"
|
|
@@ -151,8 +149,11 @@ class FocusingMirror(StandardReadable):
|
|
|
151
149
|
# regardless of orientation of the mirror
|
|
152
150
|
self.incident_angle = Motor(prefix + "PITCH")
|
|
153
151
|
|
|
154
|
-
self.add_readables(
|
|
155
|
-
|
|
152
|
+
self.add_readables(
|
|
153
|
+
[self.incident_angle.user_readback],
|
|
154
|
+
format=StandardReadableFormat.HINTED_SIGNAL,
|
|
155
|
+
)
|
|
156
|
+
self.add_readables([self.type], format=StandardReadableFormat.CONFIG_SIGNAL)
|
|
156
157
|
super().__init__(name)
|
|
157
158
|
|
|
158
159
|
|
dodal/devices/hutch_shutter.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
|
|
3
1
|
from bluesky.protocols import Movable
|
|
4
2
|
from ophyd_async.core import (
|
|
5
3
|
DEFAULT_TIMEOUT,
|
|
6
4
|
AsyncStatus,
|
|
7
5
|
StandardReadable,
|
|
6
|
+
StrictEnum,
|
|
8
7
|
wait_for_value,
|
|
9
8
|
)
|
|
10
|
-
from ophyd_async.epics.
|
|
9
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_w
|
|
11
10
|
|
|
12
11
|
HUTCH_SAFE_FOR_OPERATIONS = 0 # Hutch is locked and can't be entered
|
|
13
12
|
|
|
@@ -16,13 +15,13 @@ class ShutterNotSafeToOperateError(Exception):
|
|
|
16
15
|
pass
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
class ShutterDemand(
|
|
18
|
+
class ShutterDemand(StrictEnum):
|
|
20
19
|
OPEN = "Open"
|
|
21
20
|
CLOSE = "Close"
|
|
22
21
|
RESET = "Reset"
|
|
23
22
|
|
|
24
23
|
|
|
25
|
-
class ShutterState(
|
|
24
|
+
class ShutterState(StrictEnum):
|
|
26
25
|
FAULT = "Fault"
|
|
27
26
|
OPEN = "Open"
|
|
28
27
|
OPENING = "Opening"
|
dodal/devices/i10/i10_apple2.py
CHANGED
|
@@ -2,14 +2,15 @@ import asyncio
|
|
|
2
2
|
import csv
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any, SupportsFloat
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
from bluesky.protocols import Movable
|
|
9
9
|
from ophyd_async.core import (
|
|
10
10
|
AsyncStatus,
|
|
11
|
-
|
|
11
|
+
Reference,
|
|
12
12
|
StandardReadable,
|
|
13
|
+
StandardReadableFormat,
|
|
13
14
|
soft_signal_r_and_setter,
|
|
14
15
|
soft_signal_rw,
|
|
15
16
|
)
|
|
@@ -118,14 +119,15 @@ class I10Apple2(Apple2):
|
|
|
118
119
|
name=name,
|
|
119
120
|
)
|
|
120
121
|
with self.add_children_as_readables():
|
|
121
|
-
self.id_jaw_phase = id_jaw_phase
|
|
122
|
+
self.id_jaw_phase = Reference(id_jaw_phase)
|
|
122
123
|
|
|
123
124
|
@AsyncStatus.wrap
|
|
124
|
-
async def set(self, value:
|
|
125
|
+
async def set(self, value: SupportsFloat) -> None:
|
|
125
126
|
"""
|
|
126
127
|
Check polarisation state and use it together with the energy(value)
|
|
127
128
|
to calculate the required gap and phases before setting it.
|
|
128
129
|
"""
|
|
130
|
+
value = float(value)
|
|
129
131
|
if self.pol is None:
|
|
130
132
|
LOGGER.warning("Polarisation not set attempting to read from hardware")
|
|
131
133
|
pol, phase = await self.determinePhaseFromHardware()
|
|
@@ -146,8 +148,8 @@ class I10Apple2(Apple2):
|
|
|
146
148
|
LOGGER.info(f"Setting polarisation to {self.pol}, with {id_set_val}")
|
|
147
149
|
await self._set(value=id_set_val, energy=value)
|
|
148
150
|
if self.pol != "la":
|
|
149
|
-
await self.id_jaw_phase.set(0)
|
|
150
|
-
await self.id_jaw_phase.set_move.set(1)
|
|
151
|
+
await self.id_jaw_phase().set(0)
|
|
152
|
+
await self.id_jaw_phase().set_move.set(1)
|
|
151
153
|
|
|
152
154
|
def update_lookuptable(self):
|
|
153
155
|
"""
|
|
@@ -195,18 +197,17 @@ class I10Apple2PGM(StandardReadable, Movable):
|
|
|
195
197
|
New device name.
|
|
196
198
|
"""
|
|
197
199
|
super().__init__(name=name)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
with self.add_children_as_readables(HintedSignal):
|
|
200
|
+
self.id_ref = Reference(id)
|
|
201
|
+
self.pgm_ref = Reference(pgm)
|
|
202
|
+
with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
|
|
202
203
|
self.energy_offset = soft_signal_rw(float, initial_value=0)
|
|
203
204
|
|
|
204
205
|
@AsyncStatus.wrap
|
|
205
206
|
async def set(self, value: float) -> None:
|
|
206
207
|
LOGGER.info(f"Moving f{self.name} energy to {value}.")
|
|
207
208
|
await asyncio.gather(
|
|
208
|
-
self.
|
|
209
|
-
self.
|
|
209
|
+
self.id_ref().set(value=value + await self.energy_offset.get_value()),
|
|
210
|
+
self.pgm_ref().energy.set(value),
|
|
210
211
|
)
|
|
211
212
|
|
|
212
213
|
|
|
@@ -273,22 +274,22 @@ class LinearArbitraryAngle(StandardReadable, Movable):
|
|
|
273
274
|
polynomial parameters highest power first.
|
|
274
275
|
"""
|
|
275
276
|
super().__init__(name=name)
|
|
276
|
-
|
|
277
|
-
self.id = id
|
|
277
|
+
self.id_ref = Reference(id)
|
|
278
278
|
self.jaw_phase_from_angle = np.poly1d(jaw_phase_poly_param)
|
|
279
279
|
self.angle_threshold_deg = angle_threshold_deg
|
|
280
280
|
self.jaw_phase_limit = jaw_phase_limit
|
|
281
|
-
with self.add_children_as_readables(
|
|
281
|
+
with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
|
|
282
282
|
self.angle, self._angle_set = soft_signal_r_and_setter(
|
|
283
283
|
float, initial_value=None
|
|
284
284
|
)
|
|
285
285
|
|
|
286
286
|
@AsyncStatus.wrap
|
|
287
|
-
async def set(self, value:
|
|
288
|
-
|
|
287
|
+
async def set(self, value: SupportsFloat) -> None:
|
|
288
|
+
value = float(value)
|
|
289
|
+
pol = self.id_ref().pol
|
|
289
290
|
if pol != "la":
|
|
290
291
|
raise RuntimeError(
|
|
291
|
-
f"Angle control is not available in polarisation {pol} with {self.
|
|
292
|
+
f"Angle control is not available in polarisation {pol} with {self.id_ref().name}"
|
|
292
293
|
)
|
|
293
294
|
# Moving to real angle which is 210 to 30.
|
|
294
295
|
alpha_real = value if value > self.angle_threshold_deg else value + ALPHA_OFFSET
|
|
@@ -298,7 +299,7 @@ class LinearArbitraryAngle(StandardReadable, Movable):
|
|
|
298
299
|
f"jaw_phase position for angle ({value}) is outside permitted range"
|
|
299
300
|
f" [-{self.jaw_phase_limit}, {self.jaw_phase_limit}]"
|
|
300
301
|
)
|
|
301
|
-
await self.
|
|
302
|
+
await self.id_ref().id_jaw_phase().set(jaw_phase)
|
|
302
303
|
self._angle_set(value)
|
|
303
304
|
|
|
304
305
|
|
dodal/devices/i22/dcm.py
CHANGED
|
@@ -1,32 +1,24 @@
|
|
|
1
1
|
import time
|
|
2
|
-
from collections.abc import Sequence
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing import Literal
|
|
5
2
|
|
|
3
|
+
import numpy as np
|
|
6
4
|
from bluesky.protocols import Reading
|
|
7
5
|
from event_model.documents.event_descriptor import DataKey
|
|
8
|
-
from ophyd_async.core import
|
|
6
|
+
from ophyd_async.core import (
|
|
7
|
+
Array1D,
|
|
8
|
+
StandardReadable,
|
|
9
|
+
StandardReadableFormat,
|
|
10
|
+
soft_signal_r_and_setter,
|
|
11
|
+
)
|
|
12
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
9
13
|
from ophyd_async.epics.motor import Motor
|
|
10
|
-
|
|
14
|
+
|
|
15
|
+
from dodal.common.crystal_metadata import CrystalMetadata
|
|
11
16
|
|
|
12
17
|
# Conversion constant for energy and wavelength, taken from the X-Ray data booklet
|
|
13
18
|
# Converts between energy in KeV and wavelength in angstrom
|
|
14
19
|
_CONVERSION_CONSTANT = 12.3984
|
|
15
20
|
|
|
16
21
|
|
|
17
|
-
@dataclass(frozen=True, unsafe_hash=True)
|
|
18
|
-
class CrystalMetadata:
|
|
19
|
-
"""
|
|
20
|
-
Metadata used in the NeXus format,
|
|
21
|
-
see https://manual.nexusformat.org/classes/base_classes/NXcrystal.html
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
usage: Literal["Bragg", "Laue"] | None = None
|
|
25
|
-
type: str | None = None
|
|
26
|
-
reflection: tuple[int, int, int] | None = None
|
|
27
|
-
d_spacing: tuple[float, str] | None = None
|
|
28
|
-
|
|
29
|
-
|
|
30
22
|
class DoubleCrystalMonochromator(StandardReadable):
|
|
31
23
|
"""
|
|
32
24
|
A double crystal monochromator (DCM), used to select the energy of the beam.
|
|
@@ -40,8 +32,8 @@ class DoubleCrystalMonochromator(StandardReadable):
|
|
|
40
32
|
def __init__(
|
|
41
33
|
self,
|
|
42
34
|
temperature_prefix: str,
|
|
43
|
-
crystal_1_metadata: CrystalMetadata
|
|
44
|
-
crystal_2_metadata: CrystalMetadata
|
|
35
|
+
crystal_1_metadata: CrystalMetadata,
|
|
36
|
+
crystal_2_metadata: CrystalMetadata,
|
|
45
37
|
prefix: str = "",
|
|
46
38
|
name: str = "",
|
|
47
39
|
) -> None:
|
|
@@ -69,61 +61,37 @@ class DoubleCrystalMonochromator(StandardReadable):
|
|
|
69
61
|
|
|
70
62
|
# Soft metadata
|
|
71
63
|
# If supplied include crystal details in output of read_configuration
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
str, initial_value=crystal_2_metadata.usage
|
|
104
|
-
)
|
|
105
|
-
else:
|
|
106
|
-
self.crystal_2_usage = None
|
|
107
|
-
if crystal_2_metadata.type is not None:
|
|
108
|
-
self.crystal_2_type, _ = soft_signal_r_and_setter(
|
|
109
|
-
str, initial_value=crystal_2_metadata.type
|
|
110
|
-
)
|
|
111
|
-
else:
|
|
112
|
-
self.crystal_2_type = None
|
|
113
|
-
if crystal_2_metadata.reflection is not None:
|
|
114
|
-
self.crystal_2_reflection, _ = soft_signal_r_and_setter(
|
|
115
|
-
Sequence[int], initial_value=list(crystal_2_metadata.reflection)
|
|
116
|
-
)
|
|
117
|
-
else:
|
|
118
|
-
self.crystal_2_reflection = None
|
|
119
|
-
if crystal_2_metadata.d_spacing is not None:
|
|
120
|
-
self.crystal_2_d_spacing, _ = soft_signal_r_and_setter(
|
|
121
|
-
float,
|
|
122
|
-
initial_value=crystal_2_metadata.d_spacing[0],
|
|
123
|
-
units=crystal_2_metadata.d_spacing[1],
|
|
124
|
-
)
|
|
125
|
-
else:
|
|
126
|
-
self.crystal_2_d_spacing = None
|
|
64
|
+
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
65
|
+
self.crystal_1_usage, _ = soft_signal_r_and_setter(
|
|
66
|
+
str, initial_value=crystal_1_metadata.usage
|
|
67
|
+
)
|
|
68
|
+
self.crystal_1_type, _ = soft_signal_r_and_setter(
|
|
69
|
+
str, initial_value=crystal_1_metadata.type
|
|
70
|
+
)
|
|
71
|
+
self.crystal_1_reflection, _ = soft_signal_r_and_setter(
|
|
72
|
+
Array1D[np.int32],
|
|
73
|
+
initial_value=np.array(crystal_1_metadata.reflection),
|
|
74
|
+
)
|
|
75
|
+
self.crystal_1_d_spacing, _ = soft_signal_r_and_setter(
|
|
76
|
+
float,
|
|
77
|
+
initial_value=crystal_1_metadata.d_spacing[0],
|
|
78
|
+
units=crystal_1_metadata.d_spacing[1],
|
|
79
|
+
)
|
|
80
|
+
self.crystal_2_usage, _ = soft_signal_r_and_setter(
|
|
81
|
+
str, initial_value=crystal_2_metadata.usage
|
|
82
|
+
)
|
|
83
|
+
self.crystal_2_type, _ = soft_signal_r_and_setter(
|
|
84
|
+
str, initial_value=crystal_2_metadata.type
|
|
85
|
+
)
|
|
86
|
+
self.crystal_2_reflection, _ = soft_signal_r_and_setter(
|
|
87
|
+
Array1D[np.int32],
|
|
88
|
+
initial_value=np.array(crystal_2_metadata.reflection),
|
|
89
|
+
)
|
|
90
|
+
self.crystal_2_d_spacing, _ = soft_signal_r_and_setter(
|
|
91
|
+
float,
|
|
92
|
+
initial_value=crystal_2_metadata.d_spacing[0],
|
|
93
|
+
units=crystal_2_metadata.d_spacing[1],
|
|
94
|
+
)
|
|
127
95
|
|
|
128
96
|
super().__init__(name)
|
|
129
97
|
|
dodal/devices/i22/fswitch.py
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import time
|
|
3
|
-
from enum import Enum
|
|
4
3
|
|
|
5
4
|
from bluesky.protocols import Reading
|
|
6
5
|
from event_model import DataKey
|
|
7
6
|
from ophyd_async.core import (
|
|
8
|
-
ConfigSignal,
|
|
9
7
|
DeviceVector,
|
|
10
8
|
StandardReadable,
|
|
9
|
+
StandardReadableFormat,
|
|
10
|
+
StrictEnum,
|
|
11
11
|
soft_signal_r_and_setter,
|
|
12
12
|
)
|
|
13
|
-
from ophyd_async.epics.
|
|
13
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
class FilterState(
|
|
16
|
+
class FilterState(StrictEnum):
|
|
17
17
|
"""
|
|
18
18
|
Note that the in/out here refers to the internal rocker
|
|
19
19
|
position so a PV value of IN implies a filter OUT of beam
|
|
@@ -54,7 +54,7 @@ class FSwitch(StandardReadable):
|
|
|
54
54
|
for i in range(FSwitch.NUM_FILTERS)
|
|
55
55
|
}
|
|
56
56
|
)
|
|
57
|
-
with self.add_children_as_readables(
|
|
57
|
+
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
58
58
|
if lens_geometry is not None:
|
|
59
59
|
self.lens_geometry, _ = soft_signal_r_and_setter(
|
|
60
60
|
str, initial_value=lens_geometry
|
dodal/devices/i24/aperture.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from ophyd_async.core import StandardReadable
|
|
1
|
+
from ophyd_async.core import StandardReadable, StrictEnum
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
4
3
|
from ophyd_async.epics.motor import Motor
|
|
5
|
-
from ophyd_async.epics.signal import epics_signal_rw
|
|
6
4
|
|
|
7
5
|
|
|
8
|
-
class AperturePositions(
|
|
6
|
+
class AperturePositions(StrictEnum):
|
|
9
7
|
IN = "In"
|
|
10
8
|
OUT = "Out"
|
|
11
9
|
ROBOT = "Robot"
|
dodal/devices/i24/beamstop.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from ophyd_async.core import StandardReadable
|
|
1
|
+
from ophyd_async.core import StandardReadable, StrictEnum
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
4
3
|
from ophyd_async.epics.motor import Motor
|
|
5
|
-
from ophyd_async.epics.signal import epics_signal_rw
|
|
6
4
|
|
|
7
5
|
|
|
8
|
-
class BeamstopPositions(
|
|
6
|
+
class BeamstopPositions(StrictEnum):
|
|
9
7
|
CHECK_BEAM = "CheckBeam"
|
|
10
8
|
DATA_COLLECTION = "Data Collection"
|
|
11
9
|
DATA_COLLECTION_FAR = "Data Collection Far"
|
dodal/devices/i24/dcm.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ophyd_async.core import AsyncStatus, StandardReadable, StrictEnum
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
2
3
|
|
|
3
|
-
from ophyd_async.core import AsyncStatus, StandardReadable
|
|
4
|
-
from ophyd_async.epics.signal import epics_signal_rw
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
class BacklightPositions(str, Enum):
|
|
5
|
+
class BacklightPositions(StrictEnum):
|
|
8
6
|
OUT = "Out"
|
|
9
7
|
IN = "In"
|
|
10
8
|
LOAD_CHECK = "LoadCheck"
|
|
@@ -12,7 +10,7 @@ class BacklightPositions(str, Enum):
|
|
|
12
10
|
DIODE = "Diode"
|
|
13
11
|
|
|
14
12
|
|
|
15
|
-
class LEDStatus(
|
|
13
|
+
class LEDStatus(StrictEnum):
|
|
16
14
|
OFF = "OFF"
|
|
17
15
|
ON = "ON"
|
|
18
16
|
|
dodal/devices/i24/pmac.py
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
from asyncio import sleep
|
|
2
2
|
from enum import Enum, IntEnum
|
|
3
3
|
|
|
4
|
-
from bluesky.protocols import Flyable, Triggerable
|
|
4
|
+
from bluesky.protocols import Flyable, Movable, Triggerable
|
|
5
5
|
from ophyd_async.core import (
|
|
6
|
-
CALCULATE_TIMEOUT,
|
|
7
6
|
DEFAULT_TIMEOUT,
|
|
8
7
|
AsyncStatus,
|
|
9
|
-
|
|
8
|
+
Device,
|
|
9
|
+
Reference,
|
|
10
10
|
SignalR,
|
|
11
11
|
SignalRW,
|
|
12
|
-
SoftSignalBackend,
|
|
13
12
|
StandardReadable,
|
|
14
13
|
soft_signal_rw,
|
|
15
14
|
wait_for_value,
|
|
16
15
|
)
|
|
16
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
17
17
|
from ophyd_async.epics.motor import Motor
|
|
18
|
-
from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw
|
|
19
18
|
|
|
20
19
|
HOME_STR = r"\#1hmz\#2hmz\#3hmz" # Command to home the PMAC motors
|
|
21
20
|
ZERO_STR = "!x0y0z0" # Command to blend any ongoing move into new position
|
|
@@ -64,61 +63,53 @@ class PMACStringMove(Triggerable):
|
|
|
64
63
|
pmac_str_sig: SignalRW,
|
|
65
64
|
string_to_send: str,
|
|
66
65
|
) -> None:
|
|
67
|
-
self.
|
|
66
|
+
self.signal_ref = Reference(pmac_str_sig)
|
|
68
67
|
self.cmd_string = string_to_send
|
|
69
68
|
|
|
70
69
|
@AsyncStatus.wrap
|
|
71
70
|
async def trigger(self):
|
|
72
|
-
await self.
|
|
71
|
+
await self.signal_ref().set(self.cmd_string, wait=True)
|
|
73
72
|
|
|
74
73
|
|
|
75
|
-
class PMACStringLaser(
|
|
74
|
+
class PMACStringLaser(Device, Movable):
|
|
76
75
|
"""Set the pmac_string to control the laser."""
|
|
77
76
|
|
|
78
77
|
def __init__(
|
|
79
78
|
self,
|
|
80
79
|
pmac_str_sig: SignalRW,
|
|
81
|
-
backend: SignalBackend,
|
|
82
|
-
timeout: float | None = DEFAULT_TIMEOUT,
|
|
83
80
|
name: str = "",
|
|
84
81
|
) -> None:
|
|
85
|
-
self.
|
|
86
|
-
super().__init__(
|
|
82
|
+
self._signal_ref = Reference(pmac_str_sig)
|
|
83
|
+
super().__init__(name)
|
|
87
84
|
|
|
88
85
|
@AsyncStatus.wrap
|
|
89
86
|
async def set(
|
|
90
87
|
self,
|
|
91
88
|
value: LaserSettings,
|
|
92
|
-
wait=True,
|
|
93
|
-
timeout=CALCULATE_TIMEOUT,
|
|
94
89
|
):
|
|
95
|
-
await self.
|
|
90
|
+
await self._signal_ref().set(value.value)
|
|
96
91
|
|
|
97
92
|
|
|
98
|
-
class PMACStringEncReset(
|
|
93
|
+
class PMACStringEncReset(Device, Movable):
|
|
99
94
|
"""Set a pmac_string to control the encoder channels in the controller."""
|
|
100
95
|
|
|
101
96
|
def __init__(
|
|
102
97
|
self,
|
|
103
98
|
pmac_str_sig: SignalRW,
|
|
104
|
-
backend: SignalBackend,
|
|
105
|
-
timeout: float | None = DEFAULT_TIMEOUT,
|
|
106
99
|
name: str = "",
|
|
107
100
|
) -> None:
|
|
108
|
-
self.
|
|
109
|
-
super().__init__(
|
|
101
|
+
self._signal_ref = Reference(pmac_str_sig)
|
|
102
|
+
super().__init__(name)
|
|
110
103
|
|
|
111
104
|
@AsyncStatus.wrap
|
|
112
105
|
async def set(
|
|
113
106
|
self,
|
|
114
107
|
value: EncReset,
|
|
115
|
-
wait=True,
|
|
116
|
-
timeout=CALCULATE_TIMEOUT,
|
|
117
108
|
):
|
|
118
|
-
await self.
|
|
109
|
+
await self._signal_ref().set(value.value)
|
|
119
110
|
|
|
120
111
|
|
|
121
|
-
class ProgramRunner(
|
|
112
|
+
class ProgramRunner(Device, Flyable):
|
|
122
113
|
"""Run the collection by setting the program number on the PMAC string.
|
|
123
114
|
|
|
124
115
|
Once the program number has been set, wait for the collection to be complete.
|
|
@@ -131,21 +122,18 @@ class ProgramRunner(SignalRW, Flyable):
|
|
|
131
122
|
status_sig: SignalR,
|
|
132
123
|
prog_num_sig: SignalRW,
|
|
133
124
|
collection_time_sig: SignalRW,
|
|
134
|
-
backend: SignalBackend,
|
|
135
|
-
timeout: float | None = DEFAULT_TIMEOUT,
|
|
136
125
|
name: str = "",
|
|
137
126
|
) -> None:
|
|
138
|
-
self.
|
|
139
|
-
self.
|
|
140
|
-
self.
|
|
127
|
+
self._signal_ref = Reference(pmac_str_sig)
|
|
128
|
+
self._status_ref = Reference(status_sig)
|
|
129
|
+
self._prog_num_ref = Reference(prog_num_sig)
|
|
141
130
|
|
|
142
|
-
self.
|
|
143
|
-
self.KICKOFF_TIMEOUT = timeout
|
|
131
|
+
self._collection_time_ref = Reference(collection_time_sig)
|
|
144
132
|
|
|
145
|
-
super().__init__(
|
|
133
|
+
super().__init__(name)
|
|
146
134
|
|
|
147
135
|
async def _get_prog_number_string(self) -> str:
|
|
148
|
-
prog_num = await self.
|
|
136
|
+
prog_num = await self._prog_num_ref().get_value()
|
|
149
137
|
return f"&2b{prog_num}r"
|
|
150
138
|
|
|
151
139
|
@AsyncStatus.wrap
|
|
@@ -154,11 +142,11 @@ class ProgramRunner(SignalRW, Flyable):
|
|
|
154
142
|
wait for the scan status PV to go to 1.
|
|
155
143
|
"""
|
|
156
144
|
prog_num_str = await self._get_prog_number_string()
|
|
157
|
-
await self.
|
|
145
|
+
await self._signal_ref().set(prog_num_str, wait=True)
|
|
158
146
|
await wait_for_value(
|
|
159
|
-
self.
|
|
147
|
+
self._status_ref(),
|
|
160
148
|
ScanState.RUNNING,
|
|
161
|
-
timeout=
|
|
149
|
+
timeout=DEFAULT_TIMEOUT,
|
|
162
150
|
)
|
|
163
151
|
|
|
164
152
|
@AsyncStatus.wrap
|
|
@@ -169,8 +157,10 @@ class ProgramRunner(SignalRW, Flyable):
|
|
|
169
157
|
complete_time (float): total time required by the collection to \
|
|
170
158
|
finish correctly.
|
|
171
159
|
"""
|
|
172
|
-
scan_complete_time = await self.
|
|
173
|
-
await wait_for_value(
|
|
160
|
+
scan_complete_time = await self._collection_time_ref().get_value()
|
|
161
|
+
await wait_for_value(
|
|
162
|
+
self._status_ref(), ScanState.DONE, timeout=scan_complete_time
|
|
163
|
+
)
|
|
174
164
|
|
|
175
165
|
|
|
176
166
|
class ProgramAbort(Triggerable):
|
|
@@ -183,16 +173,16 @@ class ProgramAbort(Triggerable):
|
|
|
183
173
|
pmac_str_sig: SignalRW,
|
|
184
174
|
status_sig: SignalR,
|
|
185
175
|
) -> None:
|
|
186
|
-
self.
|
|
187
|
-
self.
|
|
176
|
+
self._signal_ref = Reference(pmac_str_sig)
|
|
177
|
+
self._status_ref = Reference(status_sig)
|
|
188
178
|
|
|
189
179
|
@AsyncStatus.wrap
|
|
190
180
|
async def trigger(self):
|
|
191
|
-
await self.
|
|
181
|
+
await self._signal_ref().set("A", wait=True)
|
|
192
182
|
await sleep(1.0) # TODO Check with scientist what this sleep is really for.
|
|
193
|
-
await self.
|
|
183
|
+
await self._signal_ref().set("P2401=0", wait=True)
|
|
194
184
|
await wait_for_value(
|
|
195
|
-
self.
|
|
185
|
+
self._status_ref(),
|
|
196
186
|
ScanState.DONE,
|
|
197
187
|
timeout=DEFAULT_TIMEOUT,
|
|
198
188
|
)
|
|
@@ -209,10 +199,10 @@ class PMAC(StandardReadable):
|
|
|
209
199
|
)
|
|
210
200
|
self.to_xyz_zero = PMACStringMove(self.pmac_string, ZERO_STR)
|
|
211
201
|
|
|
212
|
-
self.laser = PMACStringLaser(self.pmac_string
|
|
202
|
+
self.laser = PMACStringLaser(self.pmac_string)
|
|
213
203
|
|
|
214
204
|
self.enc_reset = PMACStringEncReset(
|
|
215
|
-
self.pmac_string,
|
|
205
|
+
self.pmac_string,
|
|
216
206
|
)
|
|
217
207
|
|
|
218
208
|
self.x = Motor(prefix + "X")
|
|
@@ -234,7 +224,6 @@ class PMAC(StandardReadable):
|
|
|
234
224
|
self.scanstatus,
|
|
235
225
|
self.program_number,
|
|
236
226
|
self.collection_time,
|
|
237
|
-
backend=SoftSignalBackend(str),
|
|
238
227
|
)
|
|
239
228
|
self.abort_program = ProgramAbort(self.pmac_string, self.scanstatus)
|
|
240
229
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.motor import Motor
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class VerticalGoniometer(StandardReadable):
|
|
6
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
7
|
+
self.x = Motor(prefix + "PINX")
|
|
8
|
+
self.z = Motor(prefix + "PINZ")
|
|
9
|
+
self.yh = Motor(prefix + "PINYH")
|
|
10
|
+
self.omega = Motor(prefix + "OMEGA")
|
|
11
|
+
|
|
12
|
+
self.real_x = Motor(prefix + "PINXS")
|
|
13
|
+
self.real_z = Motor(prefix + "PINZS")
|
|
14
|
+
self.fast_y = Motor(prefix + "PINYS")
|
|
15
|
+
|
|
16
|
+
super().__init__(name)
|