dls-dodal 1.34.1__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.34.1.dist-info → dls_dodal-1.35.0.dist-info}/METADATA +2 -2
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/RECORD +70 -67
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.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/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/utils.py +4 -0
- dodal/devices/i24/i24_vgonio.py +0 -17
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/top_level.txt +0 -0
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)
|
dodal/devices/ipin.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
from ophyd_async.core import
|
|
2
|
-
from ophyd_async.epics.
|
|
1
|
+
from ophyd_async.core import StandardReadable, StandardReadableFormat
|
|
2
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class IPin(StandardReadable):
|
|
6
6
|
"""Simple device to get the ipin reading"""
|
|
7
7
|
|
|
8
8
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
9
|
-
with self.add_children_as_readables(
|
|
9
|
+
with self.add_children_as_readables(
|
|
10
|
+
format=StandardReadableFormat.HINTED_SIGNAL
|
|
11
|
+
):
|
|
10
12
|
self.pin_readback = epics_signal_r(float, prefix + "I")
|
|
11
13
|
super().__init__(name)
|
dodal/devices/linkam3.py
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import time
|
|
3
|
-
from enum import Enum
|
|
4
3
|
|
|
5
4
|
from bluesky.protocols import Location
|
|
6
5
|
from ophyd_async.core import (
|
|
7
|
-
ConfigSignal,
|
|
8
|
-
HintedSignal,
|
|
9
6
|
StandardReadable,
|
|
7
|
+
StandardReadableFormat,
|
|
8
|
+
StrictEnum,
|
|
10
9
|
WatchableAsyncStatus,
|
|
11
10
|
WatcherUpdate,
|
|
12
11
|
observe_value,
|
|
13
12
|
)
|
|
14
|
-
from ophyd_async.epics.
|
|
13
|
+
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
class PumpControl(
|
|
16
|
+
class PumpControl(StrictEnum):
|
|
18
17
|
Manual = "Manual"
|
|
19
18
|
Auto = "Auto"
|
|
20
19
|
|
|
@@ -62,9 +61,10 @@ class Linkam3(StandardReadable):
|
|
|
62
61
|
# status is a bitfield stored in a double?
|
|
63
62
|
self.status = epics_signal_r(float, prefix + "STATUS:")
|
|
64
63
|
|
|
65
|
-
self.add_readables((self.temp,),
|
|
64
|
+
self.add_readables((self.temp,), format=StandardReadableFormat.HINTED_SIGNAL)
|
|
66
65
|
self.add_readables(
|
|
67
|
-
(self.ramp_rate, self.speed, self.set_point),
|
|
66
|
+
(self.ramp_rate, self.speed, self.set_point),
|
|
67
|
+
format=StandardReadableFormat.CONFIG_SIGNAL,
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
super().__init__(name=name)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from enum import IntEnum
|
|
2
2
|
|
|
3
|
-
from ophyd_async.core import DEFAULT_TIMEOUT, AsyncStatus, StandardReadable
|
|
4
|
-
from ophyd_async.epics.
|
|
3
|
+
from ophyd_async.core import DEFAULT_TIMEOUT, AsyncStatus, LazyMock, StandardReadable
|
|
4
|
+
from ophyd_async.epics.core import epics_signal_rw
|
|
5
5
|
|
|
6
6
|
from dodal.common.signal_utils import create_hardware_backed_soft_signal
|
|
7
7
|
from dodal.devices.areadetector.plugins.CAM import Cam
|
|
@@ -118,7 +118,7 @@ class OAV(StandardReadable):
|
|
|
118
118
|
|
|
119
119
|
async def connect(
|
|
120
120
|
self,
|
|
121
|
-
mock: bool = False,
|
|
121
|
+
mock: bool | LazyMock = False,
|
|
122
122
|
timeout: float = DEFAULT_TIMEOUT,
|
|
123
123
|
force_reconnect: bool = False,
|
|
124
124
|
):
|
|
@@ -14,7 +14,7 @@ from ophyd_async.core import (
|
|
|
14
14
|
soft_signal_r_and_setter,
|
|
15
15
|
soft_signal_rw,
|
|
16
16
|
)
|
|
17
|
-
from ophyd_async.epics.
|
|
17
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
18
18
|
from redis.asyncio import StrictRedis
|
|
19
19
|
|
|
20
20
|
from dodal.log import LOGGER
|
|
@@ -42,6 +42,7 @@ class OAVSource(StandardReadable):
|
|
|
42
42
|
):
|
|
43
43
|
self.url = epics_signal_r(str, f"{prefix}MJPG_URL_RBV")
|
|
44
44
|
self.oav_name = oav_name
|
|
45
|
+
super().__init__()
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
@@ -78,13 +79,13 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
|
78
79
|
"""
|
|
79
80
|
self.counter = epics_signal_r(int, f"{prefix}CAM:ArrayCounter_RBV")
|
|
80
81
|
|
|
81
|
-
self.
|
|
82
|
+
self.sources = DeviceVector(
|
|
82
83
|
{
|
|
83
84
|
Source.ROI.value: OAVSource(f"{prefix}MJPG:", "roi"),
|
|
84
85
|
Source.FULL_SCREEN.value: OAVSource(f"{prefix}XTAL:", "fullscreen"),
|
|
85
86
|
}
|
|
86
87
|
)
|
|
87
|
-
self.selected_source = soft_signal_rw(
|
|
88
|
+
self.selected_source = soft_signal_rw(int)
|
|
88
89
|
|
|
89
90
|
self.forwarding_task = None
|
|
90
91
|
self.redis_client = StrictRedis(
|
|
@@ -118,11 +119,11 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
|
118
119
|
async def _open_connection_and_do_function(
|
|
119
120
|
self, function_to_do: Callable[[ClientResponse, OAVSource], Awaitable]
|
|
120
121
|
):
|
|
121
|
-
|
|
122
|
+
source_idx = await self.selected_source.get_value()
|
|
122
123
|
LOGGER.info(
|
|
123
|
-
f"Forwarding data from sample {await self.sample_id.get_value()} and OAV {
|
|
124
|
+
f"Forwarding data from sample {await self.sample_id.get_value()} and OAV {source_idx}"
|
|
124
125
|
)
|
|
125
|
-
source = self.
|
|
126
|
+
source = self.sources[source_idx]
|
|
126
127
|
stream_url = await source.url.get_value()
|
|
127
128
|
async with ClientSession() as session:
|
|
128
129
|
async with session.get(stream_url) as response:
|
|
@@ -164,7 +165,7 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
|
164
165
|
async def stop(self, success=True):
|
|
165
166
|
if self.forwarding_task:
|
|
166
167
|
LOGGER.info(
|
|
167
|
-
f"Stopping forwarding for {await self.selected_source.get_value()}"
|
|
168
|
+
f"Stopping forwarding for source id {await self.selected_source.get_value()}"
|
|
168
169
|
)
|
|
169
170
|
self._stop_flag.set()
|
|
170
171
|
await self.forwarding_task
|
|
@@ -4,14 +4,15 @@ import time
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from numpy.typing import NDArray
|
|
6
6
|
from ophyd_async.core import (
|
|
7
|
+
Array1D,
|
|
7
8
|
AsyncStatus,
|
|
8
|
-
HintedSignal,
|
|
9
9
|
StandardReadable,
|
|
10
|
+
StandardReadableFormat,
|
|
10
11
|
observe_value,
|
|
11
12
|
soft_signal_r_and_setter,
|
|
12
13
|
soft_signal_rw,
|
|
13
14
|
)
|
|
14
|
-
from ophyd_async.epics.
|
|
15
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
15
16
|
|
|
16
17
|
from dodal.devices.oav.pin_image_recognition.utils import (
|
|
17
18
|
ARRAY_PROCESSING_FUNCTIONS_MAP,
|
|
@@ -22,7 +23,8 @@ from dodal.devices.oav.pin_image_recognition.utils import (
|
|
|
22
23
|
)
|
|
23
24
|
from dodal.log import LOGGER
|
|
24
25
|
|
|
25
|
-
Tip
|
|
26
|
+
# Tip position in x, y pixel coordinates
|
|
27
|
+
Tip = Array1D[np.int32]
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
class InvalidPinException(Exception):
|
|
@@ -45,7 +47,7 @@ class PinTipDetection(StandardReadable):
|
|
|
45
47
|
no tip is found after this time it will not error but instead return {INVALID_POSITION}.
|
|
46
48
|
"""
|
|
47
49
|
|
|
48
|
-
INVALID_POSITION = (
|
|
50
|
+
INVALID_POSITION = np.array([np.iinfo(np.int32).min, np.iinfo(np.int32).min])
|
|
49
51
|
|
|
50
52
|
def __init__(self, prefix: str, name: str = ""):
|
|
51
53
|
self._prefix: str = prefix
|
|
@@ -84,16 +86,16 @@ class PinTipDetection(StandardReadable):
|
|
|
84
86
|
self.triggered_top_edge,
|
|
85
87
|
self.triggered_bottom_edge,
|
|
86
88
|
],
|
|
87
|
-
|
|
89
|
+
format=StandardReadableFormat.HINTED_SIGNAL,
|
|
88
90
|
)
|
|
89
91
|
|
|
90
92
|
super().__init__(name=name)
|
|
91
93
|
|
|
92
94
|
def _set_triggered_values(self, results: SampleLocation):
|
|
93
|
-
|
|
94
|
-
if tip == self.INVALID_POSITION:
|
|
95
|
+
if results.tip_x is None or results.tip_y is None:
|
|
95
96
|
raise InvalidPinException
|
|
96
97
|
else:
|
|
98
|
+
tip = np.array([results.tip_x, results.tip_y])
|
|
97
99
|
self._tip_setter(tip)
|
|
98
100
|
self._top_edge_setter(results.edge_top)
|
|
99
101
|
self._bottom_edge_setter(results.edge_bottom)
|