dls-dodal 1.53.0__py3-none-any.whl → 1.54.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.53.0.dist-info → dls_dodal-1.54.0.dist-info}/METADATA +4 -6
- {dls_dodal-1.53.0.dist-info → dls_dodal-1.54.0.dist-info}/RECORD +52 -46
- dodal/_version.py +2 -2
- dodal/beamlines/__init__.py +1 -0
- dodal/beamlines/b01_1.py +2 -2
- dodal/beamlines/b07.py +6 -3
- dodal/beamlines/b07_1.py +17 -6
- dodal/beamlines/b21.py +4 -4
- dodal/beamlines/i04.py +12 -7
- dodal/beamlines/i05.py +22 -0
- dodal/beamlines/i05_1.py +17 -0
- dodal/beamlines/i09.py +7 -3
- dodal/beamlines/i09_1.py +6 -3
- dodal/beamlines/i19_1.py +1 -1
- dodal/beamlines/i20_1.py +38 -9
- dodal/beamlines/p60.py +13 -3
- dodal/common/beamlines/beamline_parameters.py +1 -1
- dodal/devices/b07/__init__.py +2 -2
- dodal/devices/b07/enums.py +15 -0
- dodal/devices/b07_1/__init__.py +10 -1
- dodal/devices/b07_1/ccmc.py +79 -0
- dodal/devices/b07_1/enums.py +3 -0
- dodal/devices/electron_analyser/abstract/base_driver_io.py +25 -48
- dodal/devices/electron_analyser/abstract/base_region.py +9 -11
- dodal/devices/electron_analyser/abstract/types.py +12 -0
- dodal/devices/electron_analyser/specs/detector.py +9 -9
- dodal/devices/electron_analyser/specs/driver_io.py +54 -21
- dodal/devices/electron_analyser/specs/region.py +13 -8
- dodal/devices/electron_analyser/types.py +15 -6
- dodal/devices/electron_analyser/vgscienta/detector.py +18 -8
- dodal/devices/electron_analyser/vgscienta/driver_io.py +62 -24
- dodal/devices/electron_analyser/vgscienta/region.py +33 -16
- dodal/devices/i05/__init__.py +3 -0
- dodal/devices/i05/enums.py +8 -0
- dodal/devices/i09/__init__.py +2 -2
- dodal/devices/i09/enums.py +16 -0
- dodal/devices/i09_1/__init__.py +2 -2
- dodal/devices/i09_1/enums.py +13 -0
- dodal/devices/i13_1/merlin_controller.py +1 -1
- dodal/devices/i19/beamstop.py +2 -2
- dodal/devices/i24/aperture.py +1 -1
- dodal/devices/oav/oav_to_redis_forwarder.py +1 -1
- dodal/devices/oav/pin_image_recognition/__init__.py +1 -2
- dodal/devices/p60/__init__.py +8 -2
- dodal/devices/p60/enums.py +16 -0
- dodal/devices/robot.py +6 -3
- dodal/devices/tetramm.py +1 -2
- dodal/utils.py +3 -10
- {dls_dodal-1.53.0.dist-info → dls_dodal-1.54.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.53.0.dist-info → dls_dodal-1.54.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.53.0.dist-info → dls_dodal-1.54.0.dist-info}/licenses/LICENSE +0 -0
- {dls_dodal-1.53.0.dist-info → dls_dodal-1.54.0.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,11 @@ from typing import Generic
|
|
|
3
3
|
|
|
4
4
|
from ophyd_async.core import SignalR
|
|
5
5
|
|
|
6
|
-
from dodal.devices.electron_analyser.abstract.
|
|
6
|
+
from dodal.devices.electron_analyser.abstract.types import (
|
|
7
|
+
TLensMode,
|
|
8
|
+
TPassEnergyEnum,
|
|
9
|
+
TPsuMode,
|
|
10
|
+
)
|
|
7
11
|
from dodal.devices.electron_analyser.detector import (
|
|
8
12
|
ElectronAnalyserDetector,
|
|
9
13
|
)
|
|
@@ -18,20 +22,26 @@ from dodal.devices.electron_analyser.vgscienta.region import (
|
|
|
18
22
|
|
|
19
23
|
class VGScientaDetector(
|
|
20
24
|
ElectronAnalyserDetector[
|
|
21
|
-
VGScientaAnalyserDriverIO[TLensMode],
|
|
22
|
-
VGScientaSequence[TLensMode],
|
|
23
|
-
VGScientaRegion[TLensMode],
|
|
25
|
+
VGScientaAnalyserDriverIO[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
26
|
+
VGScientaSequence[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
27
|
+
VGScientaRegion[TLensMode, TPassEnergyEnum],
|
|
24
28
|
],
|
|
25
|
-
Generic[TLensMode],
|
|
29
|
+
Generic[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
26
30
|
):
|
|
27
31
|
def __init__(
|
|
28
32
|
self,
|
|
29
33
|
prefix: str,
|
|
30
34
|
lens_mode_type: type[TLensMode],
|
|
35
|
+
psu_mode_type: type[TPsuMode],
|
|
36
|
+
pass_energy_type: type[TPassEnergyEnum],
|
|
31
37
|
energy_sources: Mapping[str, SignalR[float]],
|
|
32
38
|
name: str = "",
|
|
33
39
|
):
|
|
34
|
-
driver = VGScientaAnalyserDriverIO[TLensMode](
|
|
35
|
-
prefix, lens_mode_type, energy_sources
|
|
40
|
+
driver = VGScientaAnalyserDriverIO[TLensMode, TPsuMode, TPassEnergyEnum](
|
|
41
|
+
prefix, lens_mode_type, psu_mode_type, pass_energy_type, energy_sources
|
|
42
|
+
)
|
|
43
|
+
super().__init__(
|
|
44
|
+
VGScientaSequence[lens_mode_type, psu_mode_type, pass_energy_type],
|
|
45
|
+
driver,
|
|
46
|
+
name,
|
|
36
47
|
)
|
|
37
|
-
super().__init__(VGScientaSequence[lens_mode_type], driver, name)
|
|
@@ -15,54 +15,96 @@ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
|
15
15
|
from dodal.devices.electron_analyser.abstract.base_driver_io import (
|
|
16
16
|
AbstractAnalyserDriverIO,
|
|
17
17
|
)
|
|
18
|
-
from dodal.devices.electron_analyser.abstract.
|
|
18
|
+
from dodal.devices.electron_analyser.abstract.types import (
|
|
19
|
+
TLensMode,
|
|
20
|
+
TPassEnergyEnum,
|
|
21
|
+
TPsuMode,
|
|
22
|
+
)
|
|
19
23
|
from dodal.devices.electron_analyser.util import to_kinetic_energy
|
|
20
|
-
from dodal.devices.electron_analyser.vgscienta.enums import
|
|
21
|
-
|
|
24
|
+
from dodal.devices.electron_analyser.vgscienta.enums import (
|
|
25
|
+
AcquisitionMode,
|
|
22
26
|
DetectorMode,
|
|
27
|
+
)
|
|
28
|
+
from dodal.devices.electron_analyser.vgscienta.region import (
|
|
23
29
|
VGScientaRegion,
|
|
24
30
|
)
|
|
25
31
|
|
|
26
32
|
|
|
27
33
|
class VGScientaAnalyserDriverIO(
|
|
28
|
-
AbstractAnalyserDriverIO[
|
|
29
|
-
|
|
34
|
+
AbstractAnalyserDriverIO[
|
|
35
|
+
VGScientaRegion[TLensMode, TPassEnergyEnum],
|
|
36
|
+
AcquisitionMode,
|
|
37
|
+
TLensMode,
|
|
38
|
+
TPsuMode,
|
|
39
|
+
TPassEnergyEnum,
|
|
40
|
+
],
|
|
41
|
+
Generic[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
30
42
|
):
|
|
31
43
|
def __init__(
|
|
32
44
|
self,
|
|
33
45
|
prefix: str,
|
|
34
46
|
lens_mode_type: type[TLensMode],
|
|
47
|
+
psu_mode_type: type[TPsuMode],
|
|
48
|
+
pass_energy_type: type[TPassEnergyEnum],
|
|
35
49
|
energy_sources: Mapping[str, SignalR[float]],
|
|
36
50
|
name: str = "",
|
|
37
51
|
) -> None:
|
|
38
52
|
with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
|
|
39
53
|
# Used for setting up region data acquisition.
|
|
40
|
-
self.centre_energy = epics_signal_rw(float, prefix + "CENTRE_ENERGY")
|
|
41
|
-
self.first_x_channel = epics_signal_rw(int, prefix + "MinX")
|
|
42
|
-
self.first_y_channel = epics_signal_rw(int, prefix + "MinY")
|
|
43
|
-
self.x_channel_size = epics_signal_rw(int, prefix + "SizeX")
|
|
44
|
-
self.y_channel_size = epics_signal_rw(int, prefix + "SizeY")
|
|
45
54
|
self.detector_mode = epics_signal_rw(DetectorMode, prefix + "DETECTOR_MODE")
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
self.region_min_x = epics_signal_rw(int, prefix + "MinX")
|
|
57
|
+
self.region_size_x = epics_signal_rw(int, prefix + "SizeX")
|
|
58
|
+
self.sensor_max_size_x = epics_signal_rw(int, prefix + "MaxSizeX")
|
|
59
|
+
|
|
60
|
+
self.region_min_y = epics_signal_rw(int, prefix + "MinY")
|
|
61
|
+
self.region_size_y = epics_signal_rw(int, prefix + "SizeY")
|
|
62
|
+
self.sensor_max_size_y = epics_signal_rw(int, prefix + "MaxSizeY")
|
|
63
|
+
|
|
64
|
+
super().__init__(
|
|
65
|
+
prefix,
|
|
66
|
+
AcquisitionMode,
|
|
67
|
+
lens_mode_type,
|
|
68
|
+
psu_mode_type,
|
|
69
|
+
pass_energy_type,
|
|
70
|
+
energy_sources,
|
|
71
|
+
name,
|
|
72
|
+
)
|
|
48
73
|
|
|
49
74
|
@AsyncStatus.wrap
|
|
50
|
-
async def set(self, region: VGScientaRegion[TLensMode]):
|
|
51
|
-
|
|
75
|
+
async def set(self, region: VGScientaRegion[TLensMode, TPassEnergyEnum]):
|
|
76
|
+
source = self._get_energy_source(region.excitation_energy_source)
|
|
77
|
+
excitation_energy = await source.get_value() # eV
|
|
52
78
|
|
|
53
|
-
|
|
79
|
+
low_energy = to_kinetic_energy(
|
|
80
|
+
region.low_energy, region.energy_mode, excitation_energy
|
|
81
|
+
)
|
|
54
82
|
centre_energy = to_kinetic_energy(
|
|
55
|
-
region.
|
|
83
|
+
region.centre_energy, region.energy_mode, excitation_energy
|
|
84
|
+
)
|
|
85
|
+
high_energy = to_kinetic_energy(
|
|
86
|
+
region.high_energy, region.energy_mode, excitation_energy
|
|
56
87
|
)
|
|
57
88
|
await asyncio.gather(
|
|
89
|
+
self.region_name.set(region.name),
|
|
90
|
+
self.energy_mode.set(region.energy_mode),
|
|
91
|
+
self.low_energy.set(low_energy),
|
|
58
92
|
self.centre_energy.set(centre_energy),
|
|
93
|
+
self.high_energy.set(high_energy),
|
|
94
|
+
self.slices.set(region.slices),
|
|
95
|
+
self.lens_mode.set(region.lens_mode),
|
|
96
|
+
self.pass_energy.set(region.pass_energy),
|
|
97
|
+
self.iterations.set(region.iterations),
|
|
98
|
+
self.acquisition_mode.set(region.acquisition_mode),
|
|
99
|
+
self.excitation_energy.set(excitation_energy),
|
|
100
|
+
self.excitation_energy_source.set(source.name),
|
|
59
101
|
self.energy_step.set(region.energy_step),
|
|
60
|
-
self.first_x_channel.set(region.first_x_channel),
|
|
61
|
-
self.first_y_channel.set(region.first_y_channel),
|
|
62
|
-
self.x_channel_size.set(region.x_channel_size()),
|
|
63
|
-
self.y_channel_size.set(region.y_channel_size()),
|
|
64
|
-
self.detector_mode.set(region.detector_mode),
|
|
65
102
|
self.image_mode.set(ADImageMode.SINGLE),
|
|
103
|
+
self.detector_mode.set(region.detector_mode),
|
|
104
|
+
self.region_min_x.set(region.min_x),
|
|
105
|
+
self.region_size_x.set(region.size_x),
|
|
106
|
+
self.region_min_y.set(region.min_y),
|
|
107
|
+
self.region_size_y.set(region.size_y),
|
|
66
108
|
)
|
|
67
109
|
|
|
68
110
|
def _create_energy_axis_signal(self, prefix: str) -> SignalR[Array1D[np.float64]]:
|
|
@@ -70,7 +112,3 @@ class VGScientaAnalyserDriverIO(
|
|
|
70
112
|
|
|
71
113
|
def _create_angle_axis_signal(self, prefix: str) -> SignalR[Array1D[np.float64]]:
|
|
72
114
|
return epics_signal_r(Array1D[np.float64], prefix + "Y_SCALE_RBV")
|
|
73
|
-
|
|
74
|
-
@property
|
|
75
|
-
def pass_energy_type(self) -> type:
|
|
76
|
-
return str
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import uuid
|
|
2
2
|
from typing import Generic
|
|
3
3
|
|
|
4
|
-
from pydantic import Field
|
|
4
|
+
from pydantic import Field, field_validator
|
|
5
5
|
|
|
6
6
|
from dodal.devices.electron_analyser.abstract.base_region import (
|
|
7
7
|
AbstractBaseRegion,
|
|
8
8
|
AbstractBaseSequence,
|
|
9
9
|
JavaToPythonModel,
|
|
10
|
+
)
|
|
11
|
+
from dodal.devices.electron_analyser.abstract.types import (
|
|
10
12
|
TLensMode,
|
|
13
|
+
TPassEnergyEnum,
|
|
14
|
+
TPsuMode,
|
|
11
15
|
)
|
|
12
16
|
from dodal.devices.electron_analyser.vgscienta.enums import (
|
|
13
17
|
AcquisitionMode,
|
|
@@ -17,33 +21,43 @@ from dodal.devices.electron_analyser.vgscienta.enums import (
|
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
class VGScientaRegion(
|
|
20
|
-
AbstractBaseRegion[AcquisitionMode, TLensMode
|
|
24
|
+
AbstractBaseRegion[AcquisitionMode, TLensMode, TPassEnergyEnum],
|
|
25
|
+
Generic[TLensMode, TPassEnergyEnum],
|
|
21
26
|
):
|
|
22
27
|
# Override defaults of base region class
|
|
23
28
|
lens_mode: TLensMode
|
|
24
|
-
pass_energy:
|
|
29
|
+
pass_energy: TPassEnergyEnum
|
|
25
30
|
acquisition_mode: AcquisitionMode = AcquisitionMode.SWEPT
|
|
26
31
|
low_energy: float = 8.0
|
|
27
32
|
high_energy: float = 10.0
|
|
28
33
|
step_time: float = 1.0
|
|
29
34
|
energy_step: float = Field(default=200.0)
|
|
35
|
+
centre_energy: float = Field(alias="fix_energy", default=9)
|
|
30
36
|
# Specific to this class
|
|
31
37
|
id: str = Field(default=str(uuid.uuid4()), alias="region_id")
|
|
32
|
-
fix_energy: float = 9.0
|
|
33
38
|
total_steps: float = 13.0
|
|
34
39
|
total_time: float = 13.0
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
min_x: int = Field(alias="first_x_channel", default=1)
|
|
41
|
+
sensor_max_size_x: int = Field(alias="last_x_channel", default=1000)
|
|
42
|
+
min_y: int = Field(alias="first_y_channel", default=101)
|
|
43
|
+
sensor_max_size_y: int = Field(alias="last_y_channel", default=800)
|
|
39
44
|
detector_mode: DetectorMode = DetectorMode.ADC
|
|
40
45
|
status: Status = Status.READY
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
@property
|
|
48
|
+
def size_x(self) -> int:
|
|
49
|
+
return self.sensor_max_size_x - self.min_x + 1
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def size_y(self) -> int:
|
|
53
|
+
return self.sensor_max_size_y - self.min_y + 1
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
@field_validator("pass_energy", mode="before")
|
|
56
|
+
@classmethod
|
|
57
|
+
def validate_pass_energy(cls, val):
|
|
58
|
+
# This is needed because if the value is a number, it can't be casted to the
|
|
59
|
+
# enum correctly.
|
|
60
|
+
return str(val)
|
|
47
61
|
|
|
48
62
|
|
|
49
63
|
class VGScientaExcitationEnergySource(JavaToPythonModel):
|
|
@@ -53,16 +67,19 @@ class VGScientaExcitationEnergySource(JavaToPythonModel):
|
|
|
53
67
|
|
|
54
68
|
|
|
55
69
|
class VGScientaSequence(
|
|
56
|
-
AbstractBaseSequence[VGScientaRegion,
|
|
70
|
+
AbstractBaseSequence[VGScientaRegion[TLensMode, TPassEnergyEnum]],
|
|
71
|
+
Generic[TLensMode, TPsuMode, TPassEnergyEnum],
|
|
57
72
|
):
|
|
58
|
-
|
|
73
|
+
psu_mode: TPsuMode = Field(alias="element_set")
|
|
59
74
|
excitation_energy_sources: list[VGScientaExcitationEnergySource] = Field(
|
|
60
75
|
default_factory=lambda: []
|
|
61
76
|
)
|
|
62
|
-
regions: list[VGScientaRegion[TLensMode]] = Field(
|
|
77
|
+
regions: list[VGScientaRegion[TLensMode, TPassEnergyEnum]] = Field(
|
|
78
|
+
default_factory=lambda: []
|
|
79
|
+
)
|
|
63
80
|
|
|
64
81
|
def get_excitation_energy_source_by_region(
|
|
65
|
-
self, region: VGScientaRegion[TLensMode]
|
|
82
|
+
self, region: VGScientaRegion[TLensMode, TPassEnergyEnum]
|
|
66
83
|
) -> VGScientaExcitationEnergySource:
|
|
67
84
|
value = next(
|
|
68
85
|
(
|
dodal/devices/i09/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
from dodal.devices.i09.dcm import DCM
|
|
2
|
-
from dodal.devices.i09.enums import Grating, LensMode
|
|
2
|
+
from dodal.devices.i09.enums import Grating, LensMode, PassEnergy, PsuMode
|
|
3
3
|
|
|
4
|
-
__all__ = ["DCM", "Grating", "LensMode"]
|
|
4
|
+
__all__ = ["DCM", "Grating", "LensMode", "PsuMode", "PassEnergy"]
|
dodal/devices/i09/enums.py
CHANGED
|
@@ -13,3 +13,19 @@ class LensMode(StrictEnum):
|
|
|
13
13
|
ANGULAR60 = "Angular60"
|
|
14
14
|
ANGULAR56 = "Angular56"
|
|
15
15
|
ANGULAR45VUV = "Angular45VUV"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PsuMode(StrictEnum):
|
|
19
|
+
HIGH = "High"
|
|
20
|
+
LOW = "Low"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PassEnergy(StrictEnum):
|
|
24
|
+
E5 = 5
|
|
25
|
+
E10 = 10
|
|
26
|
+
E20 = 20
|
|
27
|
+
E50 = 50
|
|
28
|
+
E70 = 70
|
|
29
|
+
E100 = 100
|
|
30
|
+
E200 = 200
|
|
31
|
+
E500 = 500
|
dodal/devices/i09_1/__init__.py
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from .enums import LensMode
|
|
1
|
+
from .enums import LensMode, PsuMode
|
|
2
2
|
|
|
3
|
-
__all__ = ["LensMode"]
|
|
3
|
+
__all__ = ["LensMode", "PsuMode"]
|
dodal/devices/i09_1/enums.py
CHANGED
|
@@ -16,4 +16,17 @@ class LensMode(SupersetEnum):
|
|
|
16
16
|
LOW_MAGNIFICATION = "LowMagnification"
|
|
17
17
|
HIGH_MAGNIFICATION2 = "HighMagnification2"
|
|
18
18
|
RAMP_MODE = "RampMode"
|
|
19
|
+
# This is connected to the device separately and will only have "Not connected" as
|
|
20
|
+
# option if disconnected. Once it is connected, "Not connected" is replaced with the
|
|
21
|
+
# options above. This is also why this must be a SupersetEnum.
|
|
22
|
+
NOT_CONNECTED = "Not connected"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PsuMode(SupersetEnum):
|
|
26
|
+
V3500 = "3.5kV"
|
|
27
|
+
V1500 = "1.5kV"
|
|
28
|
+
V400 = "400V"
|
|
29
|
+
# This is connected to the device separately and will only have "Not connected" as
|
|
30
|
+
# option if disconnected. Once it is connected, "Not connected" is replaced with the
|
|
31
|
+
# options above. This is also why this must be a SupersetEnum.
|
|
19
32
|
NOT_CONNECTED = "Not connected"
|
dodal/devices/i19/beamstop.py
CHANGED
|
@@ -6,7 +6,7 @@ from dodal.devices.motors import XYZStage
|
|
|
6
6
|
|
|
7
7
|
class HomeGroup(StrictEnum):
|
|
8
8
|
NONE = "none"
|
|
9
|
-
ALL = "
|
|
9
|
+
ALL = "ALL"
|
|
10
10
|
X = "X"
|
|
11
11
|
Y = "Y"
|
|
12
12
|
Z = "Z"
|
|
@@ -23,4 +23,4 @@ class BeamStop(XYZStage):
|
|
|
23
23
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
24
24
|
self.homing = HomingControl(f"{prefix}HM", name)
|
|
25
25
|
|
|
26
|
-
super().__init__(name)
|
|
26
|
+
super().__init__(prefix, name)
|
dodal/devices/i24/aperture.py
CHANGED
|
@@ -110,11 +110,11 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
|
|
|
110
110
|
pickled numpy array of pixel values but raw byes are more space efficient. There
|
|
111
111
|
may be better ways of doing this, see https://github.com/DiamondLightSource/mx-bluesky/issues/592"""
|
|
112
112
|
jpeg_bytes = await get_next_jpeg(response)
|
|
113
|
-
self.uuid_setter(redis_uuid)
|
|
114
113
|
sample_id = await self.sample_id.get_value()
|
|
115
114
|
redis_key = f"murko:{sample_id}:raw"
|
|
116
115
|
await self.redis_client.hset(redis_key, redis_uuid, jpeg_bytes) # type: ignore
|
|
117
116
|
await self.redis_client.expire(redis_key, timedelta(days=self.DATA_EXPIRY_DAYS))
|
|
117
|
+
self.uuid_setter(redis_uuid)
|
|
118
118
|
|
|
119
119
|
async def _open_connection_and_do_function(
|
|
120
120
|
self, function_to_do: Callable[[ClientResponse, OAVSource], Awaitable]
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import asyncio
|
|
2
1
|
import time
|
|
3
2
|
|
|
4
3
|
import numpy as np
|
|
@@ -160,7 +159,7 @@ class PinTipDetection(StandardReadable):
|
|
|
160
159
|
)
|
|
161
160
|
else:
|
|
162
161
|
break
|
|
163
|
-
except
|
|
162
|
+
except TimeoutError:
|
|
164
163
|
LOGGER.error(
|
|
165
164
|
f"No tip found in {await self.validity_timeout.get_value()} seconds."
|
|
166
165
|
)
|
dodal/devices/p60/__init__.py
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
from .enums import LensMode
|
|
1
|
+
from .enums import LensMode, PassEnergy, PsuMode
|
|
2
2
|
from .lab_xray_source import LabXraySource, LabXraySourceReadable
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"LensMode",
|
|
6
|
+
"PsuMode",
|
|
7
|
+
"PassEnergy",
|
|
8
|
+
"LabXraySource",
|
|
9
|
+
"LabXraySourceReadable",
|
|
10
|
+
]
|
dodal/devices/p60/enums.py
CHANGED
|
@@ -8,3 +8,19 @@ class LensMode(StrictEnum):
|
|
|
8
8
|
ANGULAR30 = "Angular30"
|
|
9
9
|
ANGULAR30_SMALLSPOT = "Angular30_SmallSpot"
|
|
10
10
|
ANGULAR14_SMALLSPOT = "Angular14_SmallSpot"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PsuMode(StrictEnum):
|
|
14
|
+
HIGH = "High Pass (XPS)"
|
|
15
|
+
LOW = "Low Pass (UPS)"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PassEnergy(StrictEnum):
|
|
19
|
+
E1 = 1
|
|
20
|
+
E2 = 2
|
|
21
|
+
E5 = 5
|
|
22
|
+
E10 = 10
|
|
23
|
+
E20 = 20
|
|
24
|
+
E50 = 50
|
|
25
|
+
E100 = 100
|
|
26
|
+
E200 = 200
|
dodal/devices/robot.py
CHANGED
|
@@ -21,6 +21,9 @@ from ophyd_async.epics.core import (
|
|
|
21
21
|
|
|
22
22
|
from dodal.log import LOGGER
|
|
23
23
|
|
|
24
|
+
WAIT_FOR_OLD_PIN_MSG = "Waiting on old pin unloaded"
|
|
25
|
+
WAIT_FOR_NEW_PIN_MSG = "Waiting on new pin loaded"
|
|
26
|
+
|
|
24
27
|
|
|
25
28
|
class RobotLoadFailed(Exception):
|
|
26
29
|
error_code: int
|
|
@@ -144,6 +147,7 @@ class BartRobot(StandardReadable, Movable[SampleLocation]):
|
|
|
144
147
|
# in the current task, when it propagates to here we should cancel all pending tasks before bubbling up
|
|
145
148
|
for task in tasks:
|
|
146
149
|
task.cancel()
|
|
150
|
+
|
|
147
151
|
raise
|
|
148
152
|
|
|
149
153
|
async def _load_pin_and_puck(self, sample_location: SampleLocation):
|
|
@@ -164,9 +168,9 @@ class BartRobot(StandardReadable, Movable[SampleLocation]):
|
|
|
164
168
|
)
|
|
165
169
|
await self.load.trigger()
|
|
166
170
|
if await self.gonio_pin_sensor.get_value() == PinMounted.PIN_MOUNTED:
|
|
167
|
-
LOGGER.info(
|
|
171
|
+
LOGGER.info(WAIT_FOR_OLD_PIN_MSG)
|
|
168
172
|
await wait_for_value(self.gonio_pin_sensor, PinMounted.NO_PIN_MOUNTED, None)
|
|
169
|
-
LOGGER.info(
|
|
173
|
+
LOGGER.info(WAIT_FOR_NEW_PIN_MSG)
|
|
170
174
|
|
|
171
175
|
await self.pin_mounted_or_no_pin_found()
|
|
172
176
|
|
|
@@ -178,7 +182,6 @@ class BartRobot(StandardReadable, Movable[SampleLocation]):
|
|
|
178
182
|
timeout=self.LOAD_TIMEOUT + self.NOT_BUSY_TIMEOUT,
|
|
179
183
|
)
|
|
180
184
|
except TimeoutError as e:
|
|
181
|
-
# Will only need to catch asyncio.TimeoutError after https://github.com/bluesky/ophyd-async/issues/572
|
|
182
185
|
await self.prog_error.raise_if_error(e)
|
|
183
186
|
await self.controller_error.raise_if_error(e)
|
|
184
187
|
raise RobotLoadFailed(0, "Robot timed out") from e
|
dodal/devices/tetramm.py
CHANGED
|
@@ -22,9 +22,8 @@ from ophyd_async.epics.adcore import (
|
|
|
22
22
|
NDArrayBaseIO,
|
|
23
23
|
NDFileHDFIO,
|
|
24
24
|
NDPluginBaseIO,
|
|
25
|
-
stop_busy_record,
|
|
26
25
|
)
|
|
27
|
-
from ophyd_async.epics.core import PvSuffix
|
|
26
|
+
from ophyd_async.epics.core import PvSuffix, stop_busy_record
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
class TetrammRange(StrictEnum):
|
dodal/utils.py
CHANGED
|
@@ -426,16 +426,9 @@ def is_v2_device_type(obj: type[Any]) -> bool:
|
|
|
426
426
|
# This is all very badly documented and possibly prone to change in future versions of Python
|
|
427
427
|
non_parameterized_class = obj.__origin__
|
|
428
428
|
if non_parameterized_class:
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
)
|
|
433
|
-
except TypeError:
|
|
434
|
-
# Python 3.10 will return inspect.isclass(t) == True but then
|
|
435
|
-
# raise TypeError: issubclass() arg 1 must be a class
|
|
436
|
-
# when inspecting device_factory decorator function itself
|
|
437
|
-
# Later versions of Python seem not to be affected
|
|
438
|
-
pass
|
|
429
|
+
return non_parameterized_class and issubclass(
|
|
430
|
+
non_parameterized_class, OphydV2Device
|
|
431
|
+
)
|
|
439
432
|
|
|
440
433
|
return False
|
|
441
434
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|