dls-dodal 1.36.2__py3-none-any.whl → 1.37.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.
Files changed (54) hide show
  1. {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/METADATA +4 -4
  2. {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/RECORD +54 -38
  3. {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/WHEEL +1 -1
  4. dodal/_version.py +2 -2
  5. dodal/beamlines/i02_1.py +37 -0
  6. dodal/beamlines/i03.py +20 -3
  7. dodal/beamlines/i04.py +3 -3
  8. dodal/beamlines/i10.py +179 -7
  9. dodal/beamlines/i22.py +15 -0
  10. dodal/beamlines/i24.py +2 -2
  11. dodal/beamlines/p99.py +6 -2
  12. dodal/common/crystal_metadata.py +3 -3
  13. dodal/common/udc_directory_provider.py +3 -1
  14. dodal/devices/aperturescatterguard.py +3 -0
  15. dodal/devices/apple2_undulator.py +9 -9
  16. dodal/devices/{attenuator.py → attenuator/attenuator.py} +29 -1
  17. dodal/devices/attenuator/filter.py +11 -0
  18. dodal/devices/attenuator/filter_selections.py +72 -0
  19. dodal/devices/bimorph_mirror.py +151 -0
  20. dodal/devices/current_amplifiers/__init__.py +34 -0
  21. dodal/devices/current_amplifiers/current_amplifier.py +103 -0
  22. dodal/devices/current_amplifiers/current_amplifier_detector.py +109 -0
  23. dodal/devices/current_amplifiers/femto.py +143 -0
  24. dodal/devices/current_amplifiers/sr570.py +214 -0
  25. dodal/devices/current_amplifiers/struck_scaler_counter.py +79 -0
  26. dodal/devices/detector/det_dim_constants.py +15 -0
  27. dodal/devices/eiger_odin.py +3 -3
  28. dodal/devices/fast_grid_scan.py +8 -3
  29. dodal/devices/i03/beamstop.py +85 -0
  30. dodal/devices/i04/transfocator.py +67 -53
  31. dodal/devices/i10/i10_setting_data.py +3 -3
  32. dodal/devices/i10/mirrors.py +24 -0
  33. dodal/devices/i10/rasor/rasor_current_amp.py +72 -0
  34. dodal/devices/i10/rasor/rasor_motors.py +62 -0
  35. dodal/devices/i10/rasor/rasor_scaler_cards.py +12 -0
  36. dodal/devices/i10/slits.py +37 -0
  37. dodal/devices/i24/dual_backlight.py +1 -0
  38. dodal/devices/i24/focus_mirrors.py +12 -12
  39. dodal/devices/linkam3.py +2 -2
  40. dodal/devices/p99/sample_stage.py +2 -28
  41. dodal/devices/robot.py +2 -2
  42. dodal/devices/slits.py +29 -7
  43. dodal/devices/tetramm.py +16 -16
  44. dodal/devices/undulator_dcm.py +9 -11
  45. dodal/devices/util/test_utils.py +2 -2
  46. dodal/devices/xspress3/xspress3.py +3 -3
  47. dodal/devices/zebra.py +19 -14
  48. dodal/devices/zocalo/zocalo_interaction.py +2 -1
  49. dodal/devices/zocalo/zocalo_results.py +22 -2
  50. dodal/log.py +2 -2
  51. dodal/plans/wrapped.py +3 -3
  52. {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/LICENSE +0 -0
  53. {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/entry_points.txt +0 -0
  54. {dls_dodal-1.36.2.dist-info → dls_dodal-1.37.0.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,18 @@
1
+ import asyncio
1
2
  import math
2
- from time import sleep, time
3
3
 
4
- from ophyd import Component as Cpt
5
- from ophyd import Device, EpicsSignal, EpicsSignalRO, Kind
6
- from ophyd.status import DeviceStatus
4
+ from ophyd_async.core import (
5
+ AsyncStatus,
6
+ StandardReadable,
7
+ observe_value,
8
+ wait_for_value,
9
+ )
10
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
7
11
 
8
12
  from dodal.log import LOGGER
9
13
 
10
14
 
11
- class Transfocator(Device):
15
+ class Transfocator(StandardReadable):
12
16
  """The transfocator is a device that puts a number of lenses in the beam to change
13
17
  its shape.
14
18
 
@@ -18,34 +22,50 @@ class Transfocator(Device):
18
22
  my_transfocator.set(vert_beamsize_microns)
19
23
  """
20
24
 
21
- beamsize_set_microns = Cpt(EpicsSignal, "VERT_REQ", kind=Kind.hinted)
22
- predicted_vertical_num_lenses = Cpt(EpicsSignal, "LENS_PRED")
23
-
24
- number_filters_sp = Cpt(EpicsSignal, "NUM_FILTERS")
25
-
26
- start = Cpt(EpicsSignal, "START.PROC")
27
- start_rbv = Cpt(EpicsSignalRO, "START_RBV")
28
-
29
- vertical_lens_rbv = Cpt(EpicsSignalRO, "VER", kind=Kind.hinted)
25
+ def __init__(self, prefix: str, name: str = ""):
26
+ with self.add_children_as_readables():
27
+ self.beamsize_set_microns = epics_signal_rw(float, prefix + "VERT_REQ")
28
+ self.predicted_vertical_num_lenses = epics_signal_rw(
29
+ float, prefix + "LENS_PRED"
30
+ )
31
+ self.number_filters_sp = epics_signal_rw(int, prefix + "NUM_FILTERS")
32
+ self.start = epics_signal_rw(int, prefix + "START.PROC")
33
+ self.start_rbv = epics_signal_r(int, prefix + "START_RBV")
34
+ self.vertical_lens_rbv = epics_signal_r(float, prefix + "VER")
30
35
 
31
- TIMEOUT = 120
32
- _POLLING_WAIT = 0.01
36
+ self.TIMEOUT = 120
33
37
 
34
- def polling_wait_on_start_rbv(self, for_value):
35
- # For some reason couldn't get monitors working on START_RBV
36
- # (See https://github.com/DiamondLightSource/dodal/issues/152)
37
- start_time = time()
38
- while time() < start_time + self.TIMEOUT:
39
- RBV_value = self.start_rbv.get()
40
- if RBV_value == for_value:
41
- return
42
- sleep(self._POLLING_WAIT)
38
+ super().__init__(name=name)
43
39
 
44
- # last try
45
- if self.start_rbv.get() != for_value:
46
- raise TimeoutError()
40
+ async def _observe_beamsize_microns(self):
41
+ is_set_filters_done = False
47
42
 
48
- def set(self, beamsize_microns: float) -> DeviceStatus:
43
+ async def set_based_on_prediction(value: float):
44
+ if not math.isclose(
45
+ self.latest_pred_vertical_num_lenses, value, abs_tol=1e-8
46
+ ):
47
+ # We can only put an integer number of lenses in the beam but the
48
+ # calculation in the IOC returns the theoretical float number of lenses
49
+ nonlocal is_set_filters_done
50
+ value = round(value)
51
+ LOGGER.info(f"Transfocator setting {value} filters")
52
+ await self.number_filters_sp.set(value)
53
+ await self.start.set(1)
54
+ LOGGER.info("Waiting for start_rbv to change to 1")
55
+ await wait_for_value(self.start_rbv, 1, self.TIMEOUT)
56
+ LOGGER.info("Waiting for start_rbv to change to 0")
57
+ await wait_for_value(self.start_rbv, 0, self.TIMEOUT)
58
+ self.latest_pred_vertical_num_lenses = value
59
+ is_set_filters_done = True
60
+
61
+ # The value hasn't changed so assume the device is already set up correctly
62
+ async for value in observe_value(self.predicted_vertical_num_lenses):
63
+ await set_based_on_prediction(value)
64
+ if is_set_filters_done:
65
+ break
66
+
67
+ @AsyncStatus.wrap
68
+ async def set(self, value: float):
49
69
  """To set the beamsize on the transfocator we must:
50
70
  1. Set the beamsize in the calculator part of the transfocator
51
71
  2. Get the predicted number of lenses needed from this calculator
@@ -53,30 +73,24 @@ class Transfocator(Device):
53
73
  4. Start the device moving
54
74
  5. Wait for the start_rbv goes high and low again
55
75
  """
56
- subscriber: int
57
- status = DeviceStatus(self, timeout=self.TIMEOUT)
76
+ self.latest_pred_vertical_num_lenses = (
77
+ await self.predicted_vertical_num_lenses.get_value()
78
+ )
58
79
 
59
- def set_based_on_predicition(old_value, value, *args, **kwargs):
60
- if not math.isclose(old_value, value, abs_tol=1e-8):
61
- self.predicted_vertical_num_lenses.unsubscribe(subscriber)
80
+ LOGGER.info(f"Transfocator setting {value} beamsize")
62
81
 
63
- # We can only put an integer number of lenses in the beam but the
64
- # calculation in the IOC returns the theoretical float number of lenses
65
- value = round(value)
66
- LOGGER.info(f"Transfocator setting {value} filters")
67
- self.number_filters_sp.set(value).wait()
68
- self.start.set(1).wait()
69
- self.polling_wait_on_start_rbv(1)
70
- self.polling_wait_on_start_rbv(0)
71
- # The value hasn't changed so assume the device is already set up correctly
72
- status.set_finished()
73
-
74
- LOGGER.info(f"Transfocator setting {beamsize_microns} beamsize")
75
- if self.beamsize_set_microns.get() != beamsize_microns:
76
- subscriber = self.predicted_vertical_num_lenses.subscribe(
77
- set_based_on_predicition, run=False
82
+ if await self.beamsize_set_microns.get_value() != value:
83
+ # Logic in the IOC calculates predicted_vertical_num_lenses when beam_set_microns changes
84
+ await asyncio.gather(
85
+ self.beamsize_set_microns.set(value),
86
+ self._observe_beamsize_microns(),
78
87
  )
79
- self.beamsize_set_microns.set(beamsize_microns)
80
- else:
81
- status.set_finished()
82
- return status
88
+
89
+ number_filters_rbv, vertical_lens_size_rbv = await asyncio.gather(
90
+ self.number_filters_sp.get_value(),
91
+ self.vertical_lens_rbv.get_value(),
92
+ )
93
+
94
+ LOGGER.info(
95
+ f"Transfocator set complete. Number of filters is: {number_filters_rbv} and Vertical beam size is: {vertical_lens_size_rbv}"
96
+ )
@@ -2,6 +2,6 @@ from ophyd_async.core import StrictEnum
2
2
 
3
3
 
4
4
  class I10Grating(StrictEnum):
5
- Au400 = "400 line/mm Au"
6
- Si400 = "400 line/mm Si"
7
- Au1200 = "1200 line/mm Au"
5
+ AU_400 = "400 line/mm Au"
6
+ SI_400 = "400 line/mm Si"
7
+ AU_1200 = "1200 line/mm Au"
@@ -0,0 +1,24 @@
1
+ from ophyd_async.core import StandardReadable
2
+ from ophyd_async.epics.core import epics_signal_rw
3
+ from ophyd_async.epics.motor import Motor
4
+
5
+
6
+ class PiezoMirror(StandardReadable):
7
+ def __init__(
8
+ self,
9
+ prefix: str,
10
+ name: str = "",
11
+ ):
12
+ with self.add_children_as_readables():
13
+ self.x = Motor(prefix + "X")
14
+ self.y = Motor(prefix + "Y")
15
+ self.z = Motor(prefix + "Z")
16
+ self.yaw = Motor(prefix + "YAW")
17
+ self.pitch = Motor(prefix + "PITCH")
18
+ self.roll = Motor(prefix + "ROLL")
19
+ self.fine_pitch = epics_signal_rw(
20
+ float,
21
+ read_pv=prefix + "FPITCH:RBV:AI",
22
+ write_pv=prefix + "FPITCH:DMD:AO",
23
+ )
24
+ super().__init__(name=name)
@@ -0,0 +1,72 @@
1
+ from ophyd_async.core import Device
2
+
3
+ from dodal.devices.current_amplifiers import (
4
+ SR570,
5
+ Femto3xxGainTable,
6
+ Femto3xxGainToCurrentTable,
7
+ Femto3xxRaiseTime,
8
+ FemtoDDPCA,
9
+ SR570FineGainTable,
10
+ SR570FullGainTable,
11
+ SR570GainTable,
12
+ SR570GainToCurrentTable,
13
+ SR570RaiseTimeTable,
14
+ )
15
+
16
+
17
+ class RasorFemto(Device):
18
+ def __init__(self, prefix: str, suffix: str = "GAIN", name: str = "") -> None:
19
+ self.ca1 = FemtoDDPCA(
20
+ prefix + "-01:",
21
+ suffix=suffix,
22
+ gain_table=Femto3xxGainTable,
23
+ gain_to_current_table=Femto3xxGainToCurrentTable,
24
+ raise_timetable=Femto3xxRaiseTime,
25
+ )
26
+ self.ca2 = FemtoDDPCA(
27
+ prefix + "-02:",
28
+ suffix=suffix,
29
+ gain_table=Femto3xxGainTable,
30
+ gain_to_current_table=Femto3xxGainToCurrentTable,
31
+ raise_timetable=Femto3xxRaiseTime,
32
+ )
33
+ self.ca3 = FemtoDDPCA(
34
+ prefix + "-03:",
35
+ suffix=suffix,
36
+ gain_table=Femto3xxGainTable,
37
+ gain_to_current_table=Femto3xxGainToCurrentTable,
38
+ raise_timetable=Femto3xxRaiseTime,
39
+ )
40
+ super().__init__(name)
41
+
42
+
43
+ class RasorSR570(Device):
44
+ def __init__(self, prefix: str, suffix: str = "SENS:SEL", name: str = "") -> None:
45
+ self.ca1 = SR570(
46
+ prefix + "-04:",
47
+ suffix=suffix,
48
+ fine_gain_table=SR570FineGainTable,
49
+ coarse_gain_table=SR570GainTable,
50
+ combined_table=SR570FullGainTable,
51
+ gain_to_current_table=SR570GainToCurrentTable,
52
+ raise_timetable=SR570RaiseTimeTable,
53
+ )
54
+ self.ca2 = SR570(
55
+ prefix + "-05:",
56
+ suffix=suffix,
57
+ fine_gain_table=SR570FineGainTable,
58
+ coarse_gain_table=SR570GainTable,
59
+ combined_table=SR570FullGainTable,
60
+ gain_to_current_table=SR570GainToCurrentTable,
61
+ raise_timetable=SR570RaiseTimeTable,
62
+ )
63
+ self.ca3 = SR570(
64
+ prefix + "-06:",
65
+ suffix=suffix,
66
+ fine_gain_table=SR570FineGainTable,
67
+ coarse_gain_table=SR570GainTable,
68
+ combined_table=SR570FullGainTable,
69
+ gain_to_current_table=SR570GainToCurrentTable,
70
+ raise_timetable=SR570RaiseTimeTable,
71
+ )
72
+ super().__init__(name)
@@ -0,0 +1,62 @@
1
+ from ophyd_async.core import StandardReadable
2
+ from ophyd_async.epics.motor import Motor
3
+
4
+
5
+ class PinHole(StandardReadable):
6
+ "Two motors stage for rasor pinhole"
7
+
8
+ def __init__(
9
+ self,
10
+ prefix: str,
11
+ name: str = "",
12
+ ):
13
+ with self.add_children_as_readables():
14
+ self.x = Motor(prefix + "X")
15
+ self.y = Motor(prefix + "Y")
16
+ super().__init__(name=name)
17
+
18
+
19
+ class Diffractometer(StandardReadable):
20
+ def __init__(
21
+ self,
22
+ prefix: str,
23
+ name: str = "",
24
+ ):
25
+ with self.add_children_as_readables():
26
+ self.tth = Motor(prefix + "TWOTHETA")
27
+ self.th = Motor(prefix + "THETA")
28
+ self.chi = Motor(prefix + "CHI")
29
+ self.chamber_x = Motor(prefix + "X")
30
+ self.alpha = Motor(prefix + "ALPHA")
31
+ super().__init__(name=name)
32
+
33
+
34
+ class DetSlits(StandardReadable):
35
+ "Detector slits"
36
+
37
+ def __init__(
38
+ self,
39
+ prefix: str,
40
+ name: str = "",
41
+ ):
42
+ with self.add_children_as_readables():
43
+ self.upstream = Motor(prefix + "1:TRANS")
44
+ self.downstream = Motor(prefix + "2:TRANS")
45
+ super().__init__(name=name)
46
+
47
+
48
+ class PaStage(StandardReadable):
49
+ "Rasor detector stage"
50
+
51
+ def __init__(
52
+ self,
53
+ prefix: str,
54
+ name: str = "",
55
+ ):
56
+ with self.add_children_as_readables():
57
+ self.ttp = Motor(prefix + "TWOTHETA")
58
+ self.thp = Motor(prefix + "THETA")
59
+ self.py = Motor(prefix + "Y")
60
+ self.pz = Motor(prefix + "Z")
61
+ self.eta = Motor(prefix + "ETA")
62
+ super().__init__(name=name)
@@ -0,0 +1,12 @@
1
+ from ophyd_async.core import Device
2
+
3
+ from dodal.devices.current_amplifiers import StruckScaler
4
+
5
+
6
+ class RasorScalerCard1(Device):
7
+ def __init__(self, prefix, name: str = "") -> None:
8
+ self.mon = StruckScaler(prefix=prefix, suffix=".16")
9
+ self.det = StruckScaler(prefix=prefix, suffix=".17")
10
+ self.fluo = StruckScaler(prefix=prefix, suffix=".18")
11
+ self.drain = StruckScaler(prefix=prefix, suffix=".19")
12
+ super().__init__(name)
@@ -0,0 +1,37 @@
1
+ from ophyd_async.epics.motor import Motor
2
+
3
+ from dodal.devices.slits import Slits
4
+
5
+
6
+ class I10Slits(Slits):
7
+ def __init__(self, prefix: str, name: str = "") -> None:
8
+ with self.add_children_as_readables():
9
+ self.x_ring_blade = Motor(prefix + "XRING")
10
+ self.x_hall_blade = Motor(prefix + "XHALL")
11
+ self.y_top_blade = Motor(prefix + "YPLUS")
12
+ self.y_bot_blade = Motor(prefix + "YMINUS")
13
+ super().__init__(
14
+ prefix=prefix,
15
+ x_gap="XSIZE",
16
+ x_centre="XCENTRE",
17
+ y_gap="YSIZE",
18
+ y_centre="YCENTRE",
19
+ name=name,
20
+ )
21
+
22
+
23
+ class I10PrimarySlits(Slits):
24
+ def __init__(self, prefix: str, name: str = "") -> None:
25
+ with self.add_children_as_readables():
26
+ self.x_aptr_1 = Motor(prefix + "APTR1:X")
27
+ self.x_aptr_2 = Motor(prefix + "APTR2:X")
28
+ self.y_aptr_1 = Motor(prefix + "APTR1:Y")
29
+ self.y_aptr_1 = Motor(prefix + "APTR2:Y")
30
+ super().__init__(
31
+ prefix=prefix,
32
+ x_gap="XSIZE",
33
+ x_centre="XCENTRE",
34
+ y_gap="YSIZE",
35
+ y_centre="YCENTRE",
36
+ name=name,
37
+ )
@@ -8,6 +8,7 @@ class BacklightPositions(StrictEnum):
8
8
  LOAD_CHECK = "LoadCheck"
9
9
  OAV2 = "OAV2"
10
10
  DIODE = "Diode"
11
+ WHITE_IN = "White In"
11
12
 
12
13
 
13
14
  class LEDStatus(StrictEnum):
@@ -5,21 +5,21 @@ from dodal.common.signal_utils import create_hardware_backed_soft_signal
5
5
 
6
6
 
7
7
  class HFocusMode(StrictEnum):
8
- focus10 = "HMFMfocus10"
9
- focus20d = "HMFMfocus20d"
10
- focus30d = "HMFMfocus30d"
11
- focus50d = "HMFMfocus50d"
12
- focus1050d = "HMFMfocus1030d"
13
- focus3010d = "HMFMfocus3010d"
8
+ FOCUS_10 = "HMFMfocus10"
9
+ FOCUS_20D = "HMFMfocus20d"
10
+ FOCUS_30D = "HMFMfocus30d"
11
+ FOCUS_50D = "HMFMfocus50d"
12
+ FOCUS_1050D = "HMFMfocus1030d"
13
+ FOCUS_3010D = "HMFMfocus3010d"
14
14
 
15
15
 
16
16
  class VFocusMode(StrictEnum):
17
- focus10 = "VMFMfocus10"
18
- focus20d = "VMFMfocus20d"
19
- focus30d = "VMFMfocus30d"
20
- focus50d = "VMFMfocus50d"
21
- focus1030d = "VMFMfocus1030d"
22
- focus3010d = "VMFMfocus3010d"
17
+ FOCUS_10 = "VMFMfocus10"
18
+ FOCUS_20D = "VMFMfocus20d"
19
+ FOCUS_30D = "VMFMfocus30d"
20
+ FOCUS_50D = "VMFMfocus50d"
21
+ FOCUS_1030D = "VMFMfocus1030d"
22
+ FOCUS_3010D = "VMFMfocus3010d"
23
23
 
24
24
 
25
25
  BEAM_SIZES = {
dodal/devices/linkam3.py CHANGED
@@ -14,8 +14,8 @@ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
14
14
 
15
15
 
16
16
  class PumpControl(StrictEnum):
17
- Manual = "Manual"
18
- Auto = "Auto"
17
+ MANUAL = "Manual"
18
+ AUTO = "Auto"
19
19
 
20
20
 
21
21
  class Linkam3(StandardReadable):
@@ -1,5 +1,5 @@
1
- from ophyd_async.core import StandardReadable, SubsetEnum
2
- from ophyd_async.epics.core import epics_signal_rw, epics_signal_rw_rbv
1
+ from ophyd_async.core import StandardReadable
2
+ from ophyd_async.epics.core import epics_signal_rw_rbv
3
3
 
4
4
 
5
5
  class SampleAngleStage(StandardReadable):
@@ -9,29 +9,3 @@ class SampleAngleStage(StandardReadable):
9
9
  self.roll = epics_signal_rw_rbv(float, prefix + "WRITEROLL", ":RBV")
10
10
  self.pitch = epics_signal_rw_rbv(float, prefix + "WRITEPITCH", ":RBV")
11
11
  super().__init__(name=name)
12
-
13
-
14
- class p99StageSelections(SubsetEnum):
15
- Empty = "Empty"
16
- Mn5um = "Mn 5um"
17
- Fe = "Fe (empty)"
18
- Co5um = "Co 5um"
19
- Ni5um = "Ni 5um"
20
- Cu5um = "Cu 5um"
21
- Zn5um = "Zn 5um"
22
- Zr = "Zr (empty)"
23
- Mo = "Mo (empty)"
24
- Rh = "Rh (empty)"
25
- Pd = "Pd (empty)"
26
- Ag = "Ag (empty)"
27
- Cd25um = "Cd 25um"
28
- W = "W (empty)"
29
- Pt = "Pt (empty)"
30
- User = "User"
31
-
32
-
33
- class FilterMotor(StandardReadable):
34
- def __init__(self, prefix: str, name: str = ""):
35
- with self.add_children_as_readables():
36
- self.user_setpoint = epics_signal_rw(p99StageSelections, prefix)
37
- super().__init__(name=name)
dodal/devices/robot.py CHANGED
@@ -70,8 +70,8 @@ class BartRobot(StandardReadable, Movable):
70
70
  self.program_running = epics_signal_r(bool, prefix + "PROGRAM_RUNNING")
71
71
  self.program_name = epics_signal_r(str, prefix + "PROGRAM_NAME")
72
72
  self.error_str = epics_signal_r(str, prefix + "PRG_ERR_MSG")
73
- # Change error_code to int type when https://github.com/bluesky/ophyd-async/issues/280 released
74
- self.error_code = epics_signal_r(float, prefix + "PRG_ERR_CODE")
73
+ self.error_code = epics_signal_r(int, prefix + "PRG_ERR_CODE")
74
+ self.reset = epics_signal_x(prefix + "RESET.PROC")
75
75
  super().__init__(name=name)
76
76
 
77
77
  async def pin_mounted_or_no_pin_found(self):
dodal/devices/slits.py CHANGED
@@ -2,16 +2,38 @@ from ophyd_async.core import StandardReadable
2
2
  from ophyd_async.epics.motor import Motor
3
3
 
4
4
 
5
- class Slits(StandardReadable):
5
+ class MinimalSlits(StandardReadable):
6
+ """Gap only X Y slits."""
7
+
8
+ def __init__(
9
+ self,
10
+ prefix: str,
11
+ x_gap: str = "X:SIZE",
12
+ y_gap: str = "Y:SIZE",
13
+ name: str = "",
14
+ ) -> None:
15
+ with self.add_children_as_readables():
16
+ self.x_gap = Motor(prefix + x_gap)
17
+ self.y_gap = Motor(prefix + y_gap)
18
+ super().__init__(name=name)
19
+
20
+
21
+ class Slits(MinimalSlits):
6
22
  """
7
23
  Representation of a 4-blade set of slits. Allows control/readout of the gap
8
24
  between each pair of blades.
9
25
  """
10
26
 
11
- def __init__(self, prefix: str, name: str = "") -> None:
27
+ def __init__(
28
+ self,
29
+ prefix: str,
30
+ x_gap: str = "X:SIZE",
31
+ y_gap: str = "Y:SIZE",
32
+ x_centre: str = "X:CENTRE",
33
+ y_centre: str = "Y:CENTRE",
34
+ name: str = "",
35
+ ) -> None:
12
36
  with self.add_children_as_readables():
13
- self.x_gap = Motor(prefix + "X:SIZE")
14
- self.y_gap = Motor(prefix + "Y:SIZE")
15
- self.x_centre = Motor(prefix + "X:CENTRE")
16
- self.y_centre = Motor(prefix + "Y:CENTRE")
17
- super().__init__(name)
37
+ self.x_centre = Motor(prefix + x_centre)
38
+ self.y_centre = Motor(prefix + y_centre)
39
+ super().__init__(prefix=prefix, x_gap=x_gap, y_gap=y_gap, name=name)
dodal/devices/tetramm.py CHANGED
@@ -22,31 +22,31 @@ from ophyd_async.epics.core import (
22
22
 
23
23
 
24
24
  class TetrammRange(StrictEnum):
25
- uA = "+- 120 uA"
26
- nA = "+- 120 nA"
25
+ UA = "+- 120 uA"
26
+ NA = "+- 120 nA"
27
27
 
28
28
 
29
29
  class TetrammTrigger(StrictEnum):
30
- FreeRun = "Free run"
31
- ExtTrigger = "Ext. trig."
32
- ExtBulb = "Ext. bulb"
33
- ExtGate = "Ext. gate"
30
+ FREE_RUN = "Free run"
31
+ EXT_TRIGGER = "Ext. trig."
32
+ EXT_BULB = "Ext. bulb"
33
+ EXT_GATE = "Ext. gate"
34
34
 
35
35
 
36
36
  class TetrammChannels(StrictEnum):
37
- One = "1"
38
- Two = "2"
39
- Four = "4"
37
+ ONE = "1"
38
+ TWO = "2"
39
+ FOUR = "4"
40
40
 
41
41
 
42
42
  class TetrammResolution(StrictEnum):
43
- SixteenBits = "16 bits"
44
- TwentyFourBits = "24 bits"
43
+ SIXTEEN_BITS = "16 bits"
44
+ TWENTY_FOUR_BITS = "24 bits"
45
45
 
46
46
 
47
47
  class TetrammGeometry(StrictEnum):
48
- Diamond = "Diamond"
49
- Square = "Square"
48
+ DIAMOND = "Diamond"
49
+ SQUARE = "Square"
50
50
 
51
51
 
52
52
  class TetrammDriver(Device):
@@ -118,7 +118,7 @@ class TetrammController(DetectorController):
118
118
  assert trigger_info.livetime is not None
119
119
 
120
120
  # trigger mode must be set first and on its own!
121
- await self._drv.trigger_mode.set(TetrammTrigger.ExtTrigger)
121
+ await self._drv.trigger_mode.set(TetrammTrigger.EXT_TRIGGER)
122
122
 
123
123
  await asyncio.gather(
124
124
  self._drv.averaging_time.set(trigger_info.livetime),
@@ -134,8 +134,8 @@ class TetrammController(DetectorController):
134
134
 
135
135
  def _validate_trigger(self, trigger: DetectorTrigger) -> None:
136
136
  supported_trigger_types = {
137
- DetectorTrigger.edge_trigger,
138
- DetectorTrigger.constant_gate,
137
+ DetectorTrigger.EDGE_TRIGGER,
138
+ DetectorTrigger.CONSTANT_GATE,
139
139
  }
140
140
 
141
141
  if trigger not in supported_trigger_types:
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
 
3
3
  from bluesky.protocols import Movable
4
- from ophyd_async.core import AsyncStatus, StandardReadable
4
+ from ophyd_async.core import AsyncStatus, Reference, StandardReadable
5
5
 
6
6
  from dodal.common.beamlines.beamline_parameters import get_beamline_parameters
7
7
 
@@ -33,12 +33,8 @@ class UndulatorDCM(StandardReadable, Movable):
33
33
  prefix: str = "",
34
34
  name: str = "",
35
35
  ):
36
- super().__init__(name)
37
-
38
- # Attributes are set after super call so they are not renamed to
39
- # <name>-undulator, etc.
40
- self.undulator = undulator
41
- self.dcm = dcm
36
+ self.undulator_ref = Reference(undulator)
37
+ self.dcm_ref = Reference(dcm)
42
38
 
43
39
  # These attributes are just used by hyperion for lookup purposes
44
40
  self.pitch_energy_table_path = (
@@ -53,13 +49,15 @@ class UndulatorDCM(StandardReadable, Movable):
53
49
  daq_configuration_path + "/domain/beamlineParameters"
54
50
  )["DCM_Perp_Offset_FIXED"]
55
51
 
52
+ super().__init__(name)
53
+
56
54
  @AsyncStatus.wrap
57
55
  async def set(self, value: float):
58
- await self.undulator.raise_if_not_enabled()
56
+ await self.undulator_ref().raise_if_not_enabled()
59
57
  await asyncio.gather(
60
- self.dcm.energy_in_kev.set(value, timeout=ENERGY_TIMEOUT_S),
61
- self.undulator.set(value),
58
+ self.dcm_ref().energy_in_kev.set(value, timeout=ENERGY_TIMEOUT_S),
59
+ self.undulator_ref().set(value),
62
60
  )
63
61
  # DCM Perp pitch
64
62
  LOGGER.info(f"Adjusting DCM offset to {self.dcm_fixed_offset_mm} mm")
65
- await self.dcm.offset_in_mm.set(self.dcm_fixed_offset_mm)
63
+ await self.dcm_ref().offset_in_mm.set(self.dcm_fixed_offset_mm)
@@ -1,8 +1,8 @@
1
- from ophyd_async.core import (
1
+ from ophyd_async.epics.motor import Motor
2
+ from ophyd_async.testing import (
2
3
  callback_on_mock_put,
3
4
  set_mock_value,
4
5
  )
5
- from ophyd_async.epics.motor import Motor
6
6
 
7
7
 
8
8
  def patch_motor(motor: Motor, initial_position=0):
@@ -26,12 +26,12 @@ class TriggerMode(StrictEnum):
26
26
  SOFTWARE = "Software"
27
27
  HARDWARE = "Hardware"
28
28
  BURST = "Burst"
29
- TTL_Veto_Only = "TTL Veto Only"
29
+ TTL_VETO_ONLY = "TTL Veto Only"
30
30
  IDC = "IDC"
31
31
  SOTWARE_START_STOP = "Software Start/Stop"
32
32
  TTL_BOTH = "TTL Both"
33
33
  LVDS_VETO_ONLY = "LVDS Veto Only"
34
- LVDS_both = "LVDS Both"
34
+ LVDS_BOTH = "LVDS Both"
35
35
 
36
36
 
37
37
  class UpdateRBV(StrictEnum):
@@ -49,7 +49,7 @@ class DetectorState(StrictEnum):
49
49
  ACQUIRE = "Acquire"
50
50
  READOUT = "Readout"
51
51
  CORRECT = "Correct"
52
- Saving = "Saving"
52
+ SAVING = "Saving"
53
53
  ABORTING = "Aborting"
54
54
  ERROR = "Error"
55
55
  WAITING = "Waiting"