dls-dodal 1.37.0__py3-none-any.whl → 1.38.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.37.0.dist-info → dls_dodal-1.38.0.dist-info}/METADATA +2 -1
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.38.0.dist-info}/RECORD +26 -20
- dodal/_version.py +2 -2
- dodal/beamlines/i03.py +14 -2
- dodal/beamlines/i04.py +13 -2
- dodal/beamlines/i13_1.py +20 -2
- dodal/beamlines/i24.py +13 -1
- dodal/beamlines/training_rig.py +10 -1
- dodal/devices/flux.py +10 -3
- dodal/devices/i13_1/__init__.py +0 -0
- dodal/devices/i13_1/merlin.py +33 -0
- dodal/devices/i13_1/merlin_controller.py +52 -0
- dodal/devices/i13_1/merlin_io.py +17 -0
- dodal/devices/i24/beam_center.py +1 -1
- dodal/devices/p45.py +31 -20
- dodal/devices/s4_slit_gaps.py +8 -4
- dodal/devices/util/lookup_tables.py +14 -10
- dodal/devices/zebra/__init__.py +0 -0
- dodal/devices/{zebra.py → zebra/zebra.py} +3 -32
- dodal/devices/zebra/zebra_constants_mapping.py +96 -0
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.38.0.dist-info}/LICENSE +0 -0
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.38.0.dist-info}/WHEEL +0 -0
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.38.0.dist-info}/entry_points.txt +0 -0
- {dls_dodal-1.37.0.dist-info → dls_dodal-1.38.0.dist-info}/top_level.txt +0 -0
- /dodal/devices/{zebra_controlled_shutter.py → zebra/zebra_controlled_shutter.py} +0 -0
- /dodal/{devices/util → plans}/save_panda.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: dls-dodal
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.38.0
|
|
4
4
|
Summary: Ophyd devices and other utils that could be used across DLS beamlines
|
|
5
5
|
Author-email: Dominic Oram <dominic.oram@diamond.ac.uk>
|
|
6
6
|
License: Apache License
|
|
@@ -237,6 +237,7 @@ Requires-Dist: scanspec>=0.7.3
|
|
|
237
237
|
Provides-Extra: dev
|
|
238
238
|
Requires-Dist: black; extra == "dev"
|
|
239
239
|
Requires-Dist: diff-cover; extra == "dev"
|
|
240
|
+
Requires-Dist: import-linter; extra == "dev"
|
|
240
241
|
Requires-Dist: mypy; extra == "dev"
|
|
241
242
|
Requires-Dist: myst-parser; extra == "dev"
|
|
242
243
|
Requires-Dist: ophyd_async[sim]; extra == "dev"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
dodal/__init__.py,sha256=Ksms_WJF8LTkbm38gEpm1jBpGqcQ8NGvmb2ZJlOE1j8,198
|
|
2
2
|
dodal/__main__.py,sha256=kP2S2RPitnOWpNGokjZ1Yq-1umOtp5sNOZk2B3tBPLM,111
|
|
3
|
-
dodal/_version.py,sha256=
|
|
3
|
+
dodal/_version.py,sha256=j09VNHKdlg-z35f-tcp_3JKPr5SFOeDelj6hrHQ_smI,413
|
|
4
4
|
dodal/cli.py,sha256=NieWNUgLUxyck1rHoFAPJjX1xXLzHNdQ-s4wvxYFfps,3757
|
|
5
5
|
dodal/log.py,sha256=ry8WMq1S4WMIAPqtqGeKuegMRN7Jy3qdVTJlkpKXkL8,9503
|
|
6
6
|
dodal/utils.py,sha256=h2sNmTlsaznfxusV1Xj_mXtNjzsWjWAgmps6I0YNA3U,18097
|
|
@@ -11,18 +11,18 @@ dodal/beamlines/__init__.py,sha256=FsS1hMz9nqwTP12UtCJsfVn712mFElcBq2kKKpscp9k,3
|
|
|
11
11
|
dodal/beamlines/adsim.py,sha256=DUAFS1ueoZ6DK2cmZkiEm3NElnaro1mUvyodv14pSmU,1839
|
|
12
12
|
dodal/beamlines/b01_1.py,sha256=0gLjg0O9ttMjHzszSyJ_GT3fnoAB6u4aJ4MdAfjJbHA,1788
|
|
13
13
|
dodal/beamlines/i02_1.py,sha256=d2IyqFMgeaSEyZYm7GMSjTKr7_02SakyC_oARx-XwnY,1204
|
|
14
|
-
dodal/beamlines/i03.py,sha256=
|
|
15
|
-
dodal/beamlines/i04.py,sha256=
|
|
14
|
+
dodal/beamlines/i03.py,sha256=kAyStqsODSzg0kr27X63jm_nikWMCserMjJEOzRH2F4,19002
|
|
15
|
+
dodal/beamlines/i04.py,sha256=3_cMBAnRuLkzC9ELf0-a-Rq2c76YPNTIJomHqIjys5U,14926
|
|
16
16
|
dodal/beamlines/i10.py,sha256=lkn_xg0pt-vFuWkUGyl62A0xT-Rzs71JztJ1EeQkMi0,11487
|
|
17
|
-
dodal/beamlines/i13_1.py,sha256=
|
|
17
|
+
dodal/beamlines/i13_1.py,sha256=MYl2TLomSXvAdEAEMWbNfEIcX46elaugbKtkehLvB8Q,2371
|
|
18
18
|
dodal/beamlines/i20_1.py,sha256=MaPgONHqpoZuBtkiKEzYtViJnKBM2_ekeP4OdbmuXHE,1158
|
|
19
19
|
dodal/beamlines/i22.py,sha256=ED6TtjwZzGn0Hot1WSgUhdOQ4amLDjkse5hBqEBD6Zg,7619
|
|
20
20
|
dodal/beamlines/i23.py,sha256=2j5qLoqE_hg9ETHqNkOVu7LLkVB8qalgXeORnVYKN_I,1075
|
|
21
|
-
dodal/beamlines/i24.py,sha256=
|
|
21
|
+
dodal/beamlines/i24.py,sha256=tao1YIZS0amhS8EHYOQ7-22twmPujC8fAvcGncDsm0A,8851
|
|
22
22
|
dodal/beamlines/p38.py,sha256=JJbclLYoRdIxcpzpW4oTj77YJ001CdEAM0bKRk7seYI,8735
|
|
23
23
|
dodal/beamlines/p45.py,sha256=N4SDTIFok3uMqb37higZHMr3xRjxItsT4ib_KacKKAE,2935
|
|
24
24
|
dodal/beamlines/p99.py,sha256=k24QhYpoOHBd0188Fu3wvmpT6dsu8okiIVqVVckdBkw,1063
|
|
25
|
-
dodal/beamlines/training_rig.py,sha256=
|
|
25
|
+
dodal/beamlines/training_rig.py,sha256=74lrNa_qNksA1eOsSZnhhcwAXcMJdw4fBc0a-w4IV5M,1897
|
|
26
26
|
dodal/common/__init__.py,sha256=ZC4ICKUDB0BDxRaVy8nmqclVmDBne-dPtk6UJsoFq6I,258
|
|
27
27
|
dodal/common/coordination.py,sha256=OxIjDiO1-9A9KESRPFtzwkvvQlavbgA5RHemlbubBPg,1168
|
|
28
28
|
dodal/common/crystal_metadata.py,sha256=XGr-X81G9SZvPx5b4nBCH4FOnywyX_zYVy6zwDxIMVM,1926
|
|
@@ -50,19 +50,19 @@ dodal/devices/eiger.py,sha256=VGGgkSz8AzSOP3rpehs2GwPHnOGz0OKsRP6U_FYbBA4,15337
|
|
|
50
50
|
dodal/devices/eiger_odin.py,sha256=ytUH_18YuM1nJDhplS6OTdtADloYvHpO6ppENjVd4jU,7411
|
|
51
51
|
dodal/devices/fast_grid_scan.py,sha256=SNwbLuSJ6YnZ-Qx6t6veLZtStcrPNslRGrw8nouFx9g,11259
|
|
52
52
|
dodal/devices/fluorescence_detector_motion.py,sha256=-1qCSvW0PdT0m6BcoLxrtc0OJ5UDIBsEe11EOLr-gFw,501
|
|
53
|
-
dodal/devices/flux.py,sha256=
|
|
53
|
+
dodal/devices/flux.py,sha256=1CDsq9yU2-ho8MfYBl50Tl9ABZwpUBHnV486PQXKNoQ,462
|
|
54
54
|
dodal/devices/focusing_mirror.py,sha256=vdUPkwyCAZBSR3LQ-EojDOoxVy1ZmOaD_nevETbj7BA,6592
|
|
55
55
|
dodal/devices/hutch_shutter.py,sha256=WXY9JwqAa5prbf72IP7_MTKndPDtAltCpPJlNbq-F_0,3313
|
|
56
56
|
dodal/devices/ipin.py,sha256=eq5jlKw7WGQi8VLrAWpaAIsZmfiVf-5Q0td_B22H6A4,473
|
|
57
57
|
dodal/devices/linkam3.py,sha256=2sf-_heIsDg4qmqae-w9C2Py8pG8bPB3mT0TFPQIzd0,3869
|
|
58
58
|
dodal/devices/logging_ophyd_device.py,sha256=dUVE-XhWA56WUXez0mrc4sf322CXY3MVLreTycO5j_A,668
|
|
59
59
|
dodal/devices/motors.py,sha256=mduFm9vTZfu9rhwL93AMZpDzGd2TASdqalWzRaMoqec,1114
|
|
60
|
-
dodal/devices/p45.py,sha256=
|
|
60
|
+
dodal/devices/p45.py,sha256=hNCfWb8xubuHO8uJ5MpHPurp-r1ss7JMgbZQwHVJg-w,1743
|
|
61
61
|
dodal/devices/pgm.py,sha256=am-AST9iTqma1PkGOKLozqAokZWbJUbM3TNcqXzB-6A,1132
|
|
62
62
|
dodal/devices/pressure_jump_cell.py,sha256=ONvSHpnS-kA8hjOgyIks-J2n02pP6LhLm2SY1zC-i_8,9437
|
|
63
63
|
dodal/devices/qbpm.py,sha256=FfrWWAHHtYv3fGRT1qljyPpAwoHJYfbooT9CfKg-oXI,465
|
|
64
64
|
dodal/devices/robot.py,sha256=Pw6k8rFGr2-hkM2TVkQw2Y_dYIdXdXN7QtqjSglkp3g,5289
|
|
65
|
-
dodal/devices/s4_slit_gaps.py,sha256=
|
|
65
|
+
dodal/devices/s4_slit_gaps.py,sha256=4KdarIQoRqX4ry3LUS1Km7fkjUFahA0VuTd2DvYEqQ8,446
|
|
66
66
|
dodal/devices/scatterguard.py,sha256=jx03in9QgaThWxD4t1S8_Llent2kWrn_hThJ9KkUWTk,330
|
|
67
67
|
dodal/devices/scintillator.py,sha256=PlD6cnJ39PTB_e7QrRspPliLYE4kL_K7ziJURzuxgdA,365
|
|
68
68
|
dodal/devices/slits.py,sha256=b_7ku2sHlzhMHTvWrwiRwee6ufrbxNX9JB_Z0lvk15o,1105
|
|
@@ -77,8 +77,6 @@ dodal/devices/undulator_dcm.py,sha256=zulVn1wvu4-WEpf0BgLiDet58IsaKV7KW6qruAdRR_
|
|
|
77
77
|
dodal/devices/watsonmarlow323_pump.py,sha256=rwU94YE6esgGLYdh-pe8nBo_3tvgp6brrrbPDrqp5_M,1406
|
|
78
78
|
dodal/devices/webcam.py,sha256=mef075ynDbzZ4pNAjfxR_9tdTTqF_rM7hAOVEEOV-Do,2408
|
|
79
79
|
dodal/devices/xbpm_feedback.py,sha256=j8MHhhE0feoe6R54zPKqS5EbQ0bEDR-nOpLHzHhnHHQ,1156
|
|
80
|
-
dodal/devices/zebra.py,sha256=sPMAKaZOrBHQy5V9ue4-TKE9r29OG8nTZCzQQC7OMFQ,9637
|
|
81
|
-
dodal/devices/zebra_controlled_shutter.py,sha256=5-SH5HoXp_6P-xAtfDFJKQq6mBDwreubuCULSz78fgw,1852
|
|
82
80
|
dodal/devices/areadetector/plugins/CAM.py,sha256=sZzJm5Ez3eWfXZi_EB67wluhZmMQm1UyOc2bJFfzd1U,964
|
|
83
81
|
dodal/devices/areadetector/plugins/MJPG.py,sha256=QTsxCoWbofNpLMGPoOR2hWoM33KyntuLepbF0YmX0KE,3031
|
|
84
82
|
dodal/devices/attenuator/attenuator.py,sha256=eHJpM-E4XQfzy1mxGRk754y3n9q6i3youkCqQg_6SUM,3986
|
|
@@ -106,13 +104,17 @@ dodal/devices/i10/slits.py,sha256=4X50bGiJhTIHxhsOrv-8DATBkQPwQgEaFMNa2OsPrFY,12
|
|
|
106
104
|
dodal/devices/i10/rasor/rasor_current_amp.py,sha256=hImaPI3veKiS5YVfYwv-qrQ1AYNBjFVxG_MwTQqtkcc,2368
|
|
107
105
|
dodal/devices/i10/rasor/rasor_motors.py,sha256=0w31rKDuzRL-9tGbLDj0JZljaDjfXvKHQyzMs6fc3sw,1653
|
|
108
106
|
dodal/devices/i10/rasor/rasor_scaler_cards.py,sha256=wchXaIAWKLg_K14Zez4ZUmYLLk5pqL_QXegYLQO_6AY,463
|
|
107
|
+
dodal/devices/i13_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
108
|
+
dodal/devices/i13_1/merlin.py,sha256=Pi-nEqk6OOv3oOBYVb5lemQJiM03KsFbbR7pBAFg5Wg,982
|
|
109
|
+
dodal/devices/i13_1/merlin_controller.py,sha256=8uf9r-2RwpFy7DPT_rmv6AjfHPF_QyfHhIS0dqX73UM,1673
|
|
110
|
+
dodal/devices/i13_1/merlin_io.py,sha256=0To4dzeg1GNRTlsdKL7RbF2aXFyLlACGh9ZhEvIOhUc,531
|
|
109
111
|
dodal/devices/i20_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
110
112
|
dodal/devices/i22/dcm.py,sha256=SQDh-Sj1OvplHZ9yTWblJwv8PJrUqxseDPupZOWmcLo,4701
|
|
111
113
|
dodal/devices/i22/fswitch.py,sha256=LSMoo9aDkH0SLcojbUh2NxTWIpUXHZxauTqThc3XtSk,3073
|
|
112
114
|
dodal/devices/i22/nxsas.py,sha256=a8oJXl5uhkh9zcb9rSZmVooU-SplzzO3EsAaHJZRfrQ,6086
|
|
113
115
|
dodal/devices/i24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
114
116
|
dodal/devices/i24/aperture.py,sha256=XlnOyQsvdTom1dJHVUg8CUSthq3jlBlZFOUaa9b1eZ4,837
|
|
115
|
-
dodal/devices/i24/beam_center.py,sha256=
|
|
117
|
+
dodal/devices/i24/beam_center.py,sha256=m6LWsG9e_lhtPfZ8pc_hoLNyTYQQGGdRNav8J_2scTo,483
|
|
116
118
|
dodal/devices/i24/beamstop.py,sha256=89ncXUisia1rn1Faf5iWg3k0QW6Rm99j1vq9A8l9Xv8,1221
|
|
117
119
|
dodal/devices/i24/dcm.py,sha256=Q3qqlgsiLJga2cgI8L4jczjyUgQixJh6QWg7shrFpTQ,1988
|
|
118
120
|
dodal/devices/i24/dual_backlight.py,sha256=CbQ9mYUNhhozVdNXqR5ac73tEIAWT2RnEpRwXB3EFog,2049
|
|
@@ -141,12 +143,15 @@ dodal/devices/training_rig/sample_stage.py,sha256=jktTp837ij8wor5LidE3AajCk95L7D
|
|
|
141
143
|
dodal/devices/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
142
144
|
dodal/devices/util/adjuster_plans.py,sha256=XpJ1YJKoOCFzj2sonkZYJAdewi3jRaok_2gOmNsfeS0,956
|
|
143
145
|
dodal/devices/util/epics_util.py,sha256=A8iNL79PnxntuxPTKA9oLGaDRKhnXaaeAVJwS6FNAWA,4687
|
|
144
|
-
dodal/devices/util/lookup_tables.py,sha256=
|
|
146
|
+
dodal/devices/util/lookup_tables.py,sha256=3gU9cOBhHBu1S6XqXHWNjCNkV7F4Z-eDlDfesvKbMg4,2185
|
|
145
147
|
dodal/devices/util/motor_utils.py,sha256=pNY-aUk9LxaIWeDr5rpMS6udiB9j19wcCXkNDLp1uA0,257
|
|
146
|
-
dodal/devices/util/save_panda.py,sha256=PHFlkerBhkkU0-o5dNEdi2P95_jD9Lk8yYgaqn9R97o,2538
|
|
147
148
|
dodal/devices/util/test_utils.py,sha256=x0QVKVeST4T-wpsVSSm-169MyNRXlmybVWnPTefv1as,565
|
|
148
149
|
dodal/devices/xspress3/xspress3.py,sha256=75RdPuHpES4Xi-Lcywz0XUhaN2G3vZSoc-dzgcxfNvs,4636
|
|
149
150
|
dodal/devices/xspress3/xspress3_channel.py,sha256=w8tAx2lz5kJ_LeJ_eb_4o--Dtt8MRijsYNgDG6oEIVg,1626
|
|
151
|
+
dodal/devices/zebra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
152
|
+
dodal/devices/zebra/zebra.py,sha256=_OA34T9CcgwXxyajVKai2jz4nHVDaEvMkb5eG5eAYKw,9192
|
|
153
|
+
dodal/devices/zebra/zebra_constants_mapping.py,sha256=DCWMvBFvmN90rBpZ4aOVF_hbKm4K6QWubsG811R-MK8,4170
|
|
154
|
+
dodal/devices/zebra/zebra_controlled_shutter.py,sha256=5-SH5HoXp_6P-xAtfDFJKQq6mBDwreubuCULSz78fgw,1852
|
|
150
155
|
dodal/devices/zocalo/__init__.py,sha256=dRAZ9o7B9TACqyE7aanT3yzvqWtt019YgV5ZJY7Ylso,517
|
|
151
156
|
dodal/devices/zocalo/zocalo_constants.py,sha256=vu7Xjz7UNEpBUWEEBxDvP4bVFkZIN6NLGfQDpWbCjH8,98
|
|
152
157
|
dodal/devices/zocalo/zocalo_interaction.py,sha256=GFukU9xqagQtVSDg5BrL23jxl1w8wjs4b4NLLqdFfpk,3584
|
|
@@ -158,11 +163,12 @@ dodal/plan_stubs/data_session.py,sha256=33wPwbs0mtMnle0H76mH_RNTc5omld7gNSJ9BvRd
|
|
|
158
163
|
dodal/plan_stubs/motor_utils.py,sha256=4c93U_WgjfmX12uNiztVW2oKxGVWa_SKQdJYCUNmsGU,4653
|
|
159
164
|
dodal/plan_stubs/wrapped.py,sha256=nriHKX4BF010CmrhdoUhY3-txClW5W8TPLz64kE_AXU,4533
|
|
160
165
|
dodal/plans/__init__.py,sha256=nH1jNxw3DzDMg9O8Uda0kqKIalRVEWBrq07OLY6Ey38,93
|
|
166
|
+
dodal/plans/save_panda.py,sha256=PHFlkerBhkkU0-o5dNEdi2P95_jD9Lk8yYgaqn9R97o,2538
|
|
161
167
|
dodal/plans/scanspec.py,sha256=Q0AcvTKRT401iGMRDSqK-D523UX5_ofiVMZ_rNXKOx8,2074
|
|
162
168
|
dodal/plans/wrapped.py,sha256=BPMw__RcWvk9v5XnhMsi9_k4KsDEbmXogzD2n1ecbUg,2098
|
|
163
|
-
dls_dodal-1.
|
|
164
|
-
dls_dodal-1.
|
|
165
|
-
dls_dodal-1.
|
|
166
|
-
dls_dodal-1.
|
|
167
|
-
dls_dodal-1.
|
|
168
|
-
dls_dodal-1.
|
|
169
|
+
dls_dodal-1.38.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
170
|
+
dls_dodal-1.38.0.dist-info/METADATA,sha256=H2_nchEL12FW1s-A-pmX4-m05TcWsK3F6dkJjsnueqA,16696
|
|
171
|
+
dls_dodal-1.38.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
172
|
+
dls_dodal-1.38.0.dist-info/entry_points.txt,sha256=bycw_EKUzup_rxfCetOwcauXV4kLln_OPpPT8jEnr-I,94
|
|
173
|
+
dls_dodal-1.38.0.dist-info/top_level.txt,sha256=xIozdmZk_wmMV4wugpq9-6eZs0vgADNUKz3j2UAwlhc,6
|
|
174
|
+
dls_dodal-1.38.0.dist-info/RECORD,,
|
dodal/_version.py
CHANGED
dodal/beamlines/i03.py
CHANGED
|
@@ -40,8 +40,13 @@ from dodal.devices.undulator_dcm import UndulatorDCM
|
|
|
40
40
|
from dodal.devices.webcam import Webcam
|
|
41
41
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
42
42
|
from dodal.devices.xspress3.xspress3 import Xspress3
|
|
43
|
-
from dodal.devices.zebra import Zebra
|
|
44
|
-
from dodal.devices.
|
|
43
|
+
from dodal.devices.zebra.zebra import Zebra
|
|
44
|
+
from dodal.devices.zebra.zebra_constants_mapping import (
|
|
45
|
+
ZebraMapping,
|
|
46
|
+
ZebraSources,
|
|
47
|
+
ZebraTTLOutputs,
|
|
48
|
+
)
|
|
49
|
+
from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
|
|
45
50
|
from dodal.devices.zocalo import ZocaloResults
|
|
46
51
|
from dodal.log import set_beamline as set_log_beamline
|
|
47
52
|
from dodal.utils import BeamlinePrefix, get_beamline_name, skip_device
|
|
@@ -58,6 +63,12 @@ set_utils_beamline(BL)
|
|
|
58
63
|
|
|
59
64
|
set_path_provider(PandASubpathProvider())
|
|
60
65
|
|
|
66
|
+
I03_ZEBRA_MAPPING = ZebraMapping(
|
|
67
|
+
outputs=ZebraTTLOutputs(TTL_DETECTOR=1, TTL_SHUTTER=2, TTL_XSPRESS3=3, TTL_PANDA=4),
|
|
68
|
+
sources=ZebraSources(),
|
|
69
|
+
AND_GATE_FOR_AUTO_SHUTTER=2,
|
|
70
|
+
)
|
|
71
|
+
|
|
61
72
|
|
|
62
73
|
def aperture_scatterguard(
|
|
63
74
|
wait_for_connection: bool = True,
|
|
@@ -368,6 +379,7 @@ def zebra(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -
|
|
|
368
379
|
"-EA-ZEBRA-01:",
|
|
369
380
|
wait_for_connection,
|
|
370
381
|
fake_with_ophyd_sim,
|
|
382
|
+
mapping=I03_ZEBRA_MAPPING,
|
|
371
383
|
)
|
|
372
384
|
|
|
373
385
|
|
dodal/beamlines/i04.py
CHANGED
|
@@ -28,8 +28,13 @@ from dodal.devices.synchrotron import Synchrotron
|
|
|
28
28
|
from dodal.devices.thawer import Thawer
|
|
29
29
|
from dodal.devices.undulator import Undulator
|
|
30
30
|
from dodal.devices.xbpm_feedback import XBPMFeedback
|
|
31
|
-
from dodal.devices.zebra import Zebra
|
|
32
|
-
from dodal.devices.
|
|
31
|
+
from dodal.devices.zebra.zebra import Zebra
|
|
32
|
+
from dodal.devices.zebra.zebra_constants_mapping import (
|
|
33
|
+
ZebraMapping,
|
|
34
|
+
ZebraSources,
|
|
35
|
+
ZebraTTLOutputs,
|
|
36
|
+
)
|
|
37
|
+
from dodal.devices.zebra.zebra_controlled_shutter import ZebraShutter
|
|
33
38
|
from dodal.log import set_beamline as set_log_beamline
|
|
34
39
|
from dodal.utils import BeamlinePrefix, get_beamline_name, skip_device
|
|
35
40
|
|
|
@@ -47,6 +52,11 @@ BL = get_beamline_name("s04")
|
|
|
47
52
|
set_log_beamline(BL)
|
|
48
53
|
set_utils_beamline(BL)
|
|
49
54
|
|
|
55
|
+
I04_ZEBRA_MAPPING = ZebraMapping(
|
|
56
|
+
outputs=(ZebraTTLOutputs(TTL_DETECTOR=1, TTL_FAST_SHUTTER=2, TTL_XSPRESS3=3)),
|
|
57
|
+
sources=ZebraSources(),
|
|
58
|
+
)
|
|
59
|
+
|
|
50
60
|
|
|
51
61
|
def smargon(
|
|
52
62
|
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
@@ -341,6 +351,7 @@ def zebra(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -
|
|
|
341
351
|
"-EA-ZEBRA-01:",
|
|
342
352
|
wait_for_connection,
|
|
343
353
|
fake_with_ophyd_sim,
|
|
354
|
+
mapping=I04_ZEBRA_MAPPING,
|
|
344
355
|
)
|
|
345
356
|
|
|
346
357
|
|
dodal/beamlines/i13_1.py
CHANGED
|
@@ -8,7 +8,8 @@ from dodal.common.beamlines.beamline_utils import (
|
|
|
8
8
|
set_path_provider,
|
|
9
9
|
)
|
|
10
10
|
from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
|
|
11
|
-
from dodal.common.visit import StaticVisitPathProvider
|
|
11
|
+
from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitPathProvider
|
|
12
|
+
from dodal.devices.i13_1.merlin import Merlin
|
|
12
13
|
from dodal.devices.motors import XYZPositioner
|
|
13
14
|
from dodal.log import set_beamline as set_log_beamline
|
|
14
15
|
from dodal.utils import get_beamline_name
|
|
@@ -19,7 +20,8 @@ set_utils_beamline(BL)
|
|
|
19
20
|
set_path_provider(
|
|
20
21
|
StaticVisitPathProvider(
|
|
21
22
|
BL,
|
|
22
|
-
Path("/data/2024/cm37257-
|
|
23
|
+
Path("/dls/i13-1/data/2024/cm37257-5/tmp/"), # latest commissioning visit
|
|
24
|
+
client=LocalDirectoryServiceClient(),
|
|
23
25
|
)
|
|
24
26
|
)
|
|
25
27
|
|
|
@@ -64,3 +66,19 @@ def side_camera(
|
|
|
64
66
|
wait=wait_for_connection,
|
|
65
67
|
fake=fake_with_ophyd_sim,
|
|
66
68
|
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def merlin(
|
|
72
|
+
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
73
|
+
) -> Merlin:
|
|
74
|
+
return device_instantiation(
|
|
75
|
+
Merlin,
|
|
76
|
+
prefix="BL13J-EA-DET-04:",
|
|
77
|
+
name="merlin",
|
|
78
|
+
bl_prefix=False,
|
|
79
|
+
drv_suffix="CAM:",
|
|
80
|
+
hdf_suffix="HDF5:",
|
|
81
|
+
path_provider=get_path_provider(),
|
|
82
|
+
wait=wait_for_connection,
|
|
83
|
+
fake=fake_with_ophyd_sim,
|
|
84
|
+
)
|
dodal/beamlines/i24.py
CHANGED
|
@@ -16,7 +16,12 @@ from dodal.devices.i24.pmac import PMAC
|
|
|
16
16
|
from dodal.devices.i24.vgonio import VerticalGoniometer
|
|
17
17
|
from dodal.devices.oav.oav_detector import OAV
|
|
18
18
|
from dodal.devices.oav.oav_parameters import OAVConfig
|
|
19
|
-
from dodal.devices.zebra import Zebra
|
|
19
|
+
from dodal.devices.zebra.zebra import Zebra
|
|
20
|
+
from dodal.devices.zebra.zebra_constants_mapping import (
|
|
21
|
+
ZebraMapping,
|
|
22
|
+
ZebraSources,
|
|
23
|
+
ZebraTTLOutputs,
|
|
24
|
+
)
|
|
20
25
|
from dodal.log import set_beamline as set_log_beamline
|
|
21
26
|
from dodal.utils import get_beamline_name, skip_device
|
|
22
27
|
|
|
@@ -25,10 +30,16 @@ ZOOM_PARAMS_FILE = (
|
|
|
25
30
|
)
|
|
26
31
|
DISPLAY_CONFIG = "/dls_sw/i24/software/gda_versions/var/display.configuration"
|
|
27
32
|
|
|
33
|
+
|
|
28
34
|
BL = get_beamline_name("s24")
|
|
29
35
|
set_log_beamline(BL)
|
|
30
36
|
set_utils_beamline(BL)
|
|
31
37
|
|
|
38
|
+
I24_ZEBRA_MAPPING = ZebraMapping(
|
|
39
|
+
outputs=ZebraTTLOutputs(TTL_EIGER=1, TTL_PILATUS=2, TTL_FAST_SHUTTER=4),
|
|
40
|
+
sources=ZebraSources(),
|
|
41
|
+
)
|
|
42
|
+
|
|
32
43
|
|
|
33
44
|
def attenuator(
|
|
34
45
|
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
|
|
@@ -191,6 +202,7 @@ def zebra(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -
|
|
|
191
202
|
"-EA-ZEBRA-01:",
|
|
192
203
|
wait_for_connection,
|
|
193
204
|
fake_with_ophyd_sim,
|
|
205
|
+
mapping=I24_ZEBRA_MAPPING,
|
|
194
206
|
)
|
|
195
207
|
|
|
196
208
|
|
dodal/beamlines/training_rig.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
3
|
from ophyd_async.epics.adaravis import AravisDetector
|
|
4
|
+
from ophyd_async.fastcs.panda import HDFPanda
|
|
4
5
|
|
|
5
6
|
from dodal.common.beamlines.beamline_utils import (
|
|
6
7
|
device_factory,
|
|
@@ -33,7 +34,7 @@ set_utils_beamline(BL)
|
|
|
33
34
|
set_path_provider(
|
|
34
35
|
StaticVisitPathProvider(
|
|
35
36
|
BL,
|
|
36
|
-
Path("/
|
|
37
|
+
Path("/data"),
|
|
37
38
|
client=LocalDirectoryServiceClient(),
|
|
38
39
|
)
|
|
39
40
|
)
|
|
@@ -52,3 +53,11 @@ def det() -> AravisDetector:
|
|
|
52
53
|
drv_suffix="DET:",
|
|
53
54
|
hdf_suffix=HDF5_PREFIX,
|
|
54
55
|
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@device_factory()
|
|
59
|
+
def panda() -> HDFPanda:
|
|
60
|
+
return HDFPanda(
|
|
61
|
+
prefix=f"{PREFIX.beamline_prefix}-MO-PANDA-01:",
|
|
62
|
+
path_provider=get_path_provider(),
|
|
63
|
+
)
|
dodal/devices/flux.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ophyd_async.core import (
|
|
2
|
+
StandardReadable,
|
|
3
|
+
StandardReadableFormat,
|
|
4
|
+
)
|
|
5
|
+
from ophyd_async.epics.core import epics_signal_r
|
|
2
6
|
|
|
3
7
|
|
|
4
|
-
class Flux(
|
|
8
|
+
class Flux(StandardReadable):
|
|
5
9
|
"""Simple device to get the flux reading"""
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
12
|
+
with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
|
|
13
|
+
self.flux_reading = epics_signal_r(float, prefix + "SAMP")
|
|
14
|
+
super().__init__(name=name)
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from ophyd_async.core import PathProvider, StandardDetector
|
|
2
|
+
from ophyd_async.epics import adcore
|
|
3
|
+
|
|
4
|
+
from dodal.devices.i13_1.merlin_controller import MerlinController
|
|
5
|
+
from dodal.devices.i13_1.merlin_io import MerlinDriverIO
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Merlin(StandardDetector):
|
|
9
|
+
_controller: MerlinController
|
|
10
|
+
_writer: adcore.ADHDFWriter
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
prefix: str,
|
|
15
|
+
path_provider: PathProvider,
|
|
16
|
+
drv_suffix="CAM:",
|
|
17
|
+
hdf_suffix="HDF:",
|
|
18
|
+
name: str = "",
|
|
19
|
+
):
|
|
20
|
+
self.drv = MerlinDriverIO(prefix + drv_suffix)
|
|
21
|
+
self.hdf = adcore.NDFileHDFIO(prefix + hdf_suffix)
|
|
22
|
+
|
|
23
|
+
super().__init__(
|
|
24
|
+
MerlinController(self.drv),
|
|
25
|
+
adcore.ADHDFWriter(
|
|
26
|
+
self.hdf,
|
|
27
|
+
path_provider,
|
|
28
|
+
lambda: self.name,
|
|
29
|
+
adcore.ADBaseDatasetDescriber(self.drv),
|
|
30
|
+
),
|
|
31
|
+
config_sigs=(self.drv.acquire_period, self.drv.acquire_time),
|
|
32
|
+
name=name,
|
|
33
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from ophyd_async.core import (
|
|
5
|
+
DEFAULT_TIMEOUT,
|
|
6
|
+
AsyncStatus,
|
|
7
|
+
DetectorController,
|
|
8
|
+
TriggerInfo,
|
|
9
|
+
)
|
|
10
|
+
from ophyd_async.epics import adcore
|
|
11
|
+
|
|
12
|
+
from dodal.devices.i13_1.merlin_io import MerlinDriverIO, MerlinImageMode
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MerlinController(DetectorController):
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
driver: MerlinDriverIO,
|
|
19
|
+
good_states: frozenset[adcore.DetectorState] = adcore.DEFAULT_GOOD_STATES,
|
|
20
|
+
) -> None:
|
|
21
|
+
self.driver = driver
|
|
22
|
+
self.good_states = good_states
|
|
23
|
+
self.frame_timeout: float = 0
|
|
24
|
+
self._arm_status: AsyncStatus | None = None
|
|
25
|
+
for drv_child in self.driver.children():
|
|
26
|
+
logging.debug(drv_child)
|
|
27
|
+
|
|
28
|
+
def get_deadtime(self, exposure: float | None) -> float:
|
|
29
|
+
return 0.002
|
|
30
|
+
|
|
31
|
+
async def prepare(self, trigger_info: TriggerInfo):
|
|
32
|
+
self.frame_timeout = (
|
|
33
|
+
DEFAULT_TIMEOUT + await self.driver.acquire_time.get_value()
|
|
34
|
+
)
|
|
35
|
+
await asyncio.gather(
|
|
36
|
+
self.driver.num_images.set(trigger_info.total_number_of_triggers),
|
|
37
|
+
self.driver.image_mode.set(MerlinImageMode.MULTIPLE),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
async def arm(self):
|
|
41
|
+
self._arm_status = await adcore.start_acquiring_driver_and_ensure_status(
|
|
42
|
+
self.driver, good_states=self.good_states, timeout=self.frame_timeout
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
async def wait_for_idle(self):
|
|
46
|
+
if self._arm_status:
|
|
47
|
+
await self._arm_status
|
|
48
|
+
|
|
49
|
+
async def disarm(self):
|
|
50
|
+
# We can't use caput callback as we already used it in arm() and we can't have
|
|
51
|
+
# 2 or they will deadlock
|
|
52
|
+
await adcore.stop_busy_record(self.driver.acquire, False, timeout=1)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from ophyd_async.core import StrictEnum
|
|
2
|
+
from ophyd_async.epics import adcore
|
|
3
|
+
from ophyd_async.epics.core import epics_signal_rw_rbv
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MerlinImageMode(StrictEnum):
|
|
7
|
+
SINGLE = "Single"
|
|
8
|
+
MULTIPLE = "Multiple"
|
|
9
|
+
CONTINUOUS = "Continuous"
|
|
10
|
+
THRESHOLD = "Threshold"
|
|
11
|
+
BACKGROUND = "Background"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MerlinDriverIO(adcore.ADBaseIO):
|
|
15
|
+
def __init__(self, prefix: str, name: str = "") -> None:
|
|
16
|
+
super().__init__(prefix, name)
|
|
17
|
+
self.image_mode = epics_signal_rw_rbv(MerlinImageMode, prefix + "ImageMode")
|
dodal/devices/i24/beam_center.py
CHANGED
|
@@ -7,6 +7,6 @@ from ophyd_async.epics.core import epics_signal_rw
|
|
|
7
7
|
|
|
8
8
|
class DetectorBeamCenter(StandardReadable):
|
|
9
9
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
10
|
-
self.beam_x = epics_signal_rw(float, prefix + "BeamX")
|
|
10
|
+
self.beam_x = epics_signal_rw(float, prefix + "BeamX") # in pixels
|
|
11
11
|
self.beam_y = epics_signal_rw(float, prefix + "BeamY")
|
|
12
12
|
super().__init__(name)
|
dodal/devices/p45.py
CHANGED
|
@@ -1,44 +1,55 @@
|
|
|
1
|
-
from
|
|
2
|
-
from
|
|
3
|
-
from ophyd.areadetector.base import ADComponent as Cpt
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.motor import Motor
|
|
4
3
|
|
|
5
4
|
|
|
6
|
-
class SampleY(
|
|
5
|
+
class SampleY(StandardReadable):
|
|
7
6
|
"""
|
|
8
7
|
Motors for controlling the sample's y position and stretch in the y axis.
|
|
9
8
|
"""
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
11
|
+
with self.add_children_as_readables():
|
|
12
|
+
self.base = Motor(prefix + "CS:Y")
|
|
13
|
+
self.stretch = Motor(prefix + "CS:Y:STRETCH")
|
|
14
|
+
self.top = Motor(prefix + "Y:TOP")
|
|
15
|
+
self.bottom = Motor(prefix + "Y:BOT")
|
|
16
|
+
super().__init__(name=name)
|
|
15
17
|
|
|
16
18
|
|
|
17
|
-
class SampleTheta(
|
|
19
|
+
class SampleTheta(StandardReadable):
|
|
18
20
|
"""
|
|
19
21
|
Motors for controlling the sample's theta position and skew
|
|
20
22
|
"""
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
25
|
+
with self.add_children_as_readables():
|
|
26
|
+
self.base = Motor(prefix + "THETA:POS")
|
|
27
|
+
self.skew = Motor(prefix + "THETA:SKEW")
|
|
28
|
+
self.top = Motor(prefix + "THETA:TOP")
|
|
29
|
+
self.bottom = Motor(prefix + "THETA:BOT")
|
|
30
|
+
super().__init__(name=name)
|
|
26
31
|
|
|
27
32
|
|
|
28
|
-
class TomoStageWithStretchAndSkew(
|
|
33
|
+
class TomoStageWithStretchAndSkew(StandardReadable):
|
|
29
34
|
"""
|
|
30
35
|
Grouping of motors for the P45 tomography stage
|
|
31
36
|
"""
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
39
|
+
with self.add_children_as_readables():
|
|
40
|
+
self.x = Motor(prefix + "X")
|
|
41
|
+
self.y = SampleY(prefix)
|
|
42
|
+
self.theta = SampleTheta(prefix)
|
|
43
|
+
super().__init__(name=name)
|
|
36
44
|
|
|
37
45
|
|
|
38
|
-
class Choppers(
|
|
46
|
+
class Choppers(StandardReadable):
|
|
39
47
|
"""
|
|
40
48
|
Grouping for the P45 chopper motors
|
|
41
49
|
"""
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
52
|
+
with self.add_children_as_readables():
|
|
53
|
+
self.x = Motor(prefix + "ENDAT")
|
|
54
|
+
self.y = Motor(prefix + "BISS")
|
|
55
|
+
super().__init__(name=name)
|
dodal/devices/s4_slit_gaps.py
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ophyd_async.core import StandardReadable
|
|
2
|
+
from ophyd_async.epics.motor import Motor
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
class S4SlitGaps(
|
|
5
|
+
class S4SlitGaps(StandardReadable):
|
|
5
6
|
"""Note that the S4 slits have a different PV fromat to other beamline slits"""
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
def __init__(self, prefix: str, name="") -> None:
|
|
9
|
+
with self.add_children_as_readables():
|
|
10
|
+
self.xgap = Motor(prefix + "XGAP")
|
|
11
|
+
self.ygap = Motor(prefix + "YGAP")
|
|
12
|
+
super().__init__(name=name)
|
|
@@ -32,28 +32,32 @@ async def energy_distance_table(lookup_table_path: str) -> np.ndarray:
|
|
|
32
32
|
return loadtxt(StringIO(raw_table), comments=["#", "Units"])
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def
|
|
35
|
+
def parse_lookup_table(filename: str) -> list[Sequence]:
|
|
36
|
+
"""Parse a generic lookup table with a number of columns >= 2 and return a list \
|
|
37
|
+
in column major order of the values in it."""
|
|
38
|
+
LOGGER.info(f"Parsing lookup table file {filename}")
|
|
39
|
+
|
|
40
|
+
lut_vals = zip(*loadtxt(filename, comments=["#", "Units"]), strict=False)
|
|
41
|
+
return list(lut_vals)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def linear_interpolation_lut(
|
|
45
|
+
s_values: Sequence, t_values: Sequence
|
|
46
|
+
) -> Callable[[float], float]:
|
|
36
47
|
"""Returns a callable that converts values by linear interpolation of lookup table
|
|
37
48
|
values.
|
|
38
49
|
|
|
39
50
|
If the value falls outside the lookup table then the closest value will be used."""
|
|
40
|
-
LOGGER.info(f"Using lookup table {filename}")
|
|
41
|
-
s_and_t_vals = zip(*loadtxt(filename, comments=["#", "Units"]), strict=False)
|
|
42
|
-
|
|
43
|
-
s_values: Sequence
|
|
44
|
-
t_values: Sequence
|
|
45
|
-
s_values, t_values = s_and_t_vals
|
|
46
|
-
|
|
47
51
|
# numpy interp expects x-values to be increasing
|
|
48
52
|
if not np.all(np.diff(s_values) > 0):
|
|
49
53
|
LOGGER.info(
|
|
50
|
-
|
|
54
|
+
"Configuration values in the lookup table are not ascending, trying reverse order..."
|
|
51
55
|
)
|
|
52
56
|
s_values = list(reversed(s_values))
|
|
53
57
|
t_values = list(reversed(t_values))
|
|
54
58
|
if not np.all(np.diff(s_values) > 0):
|
|
55
59
|
raise AssertionError(
|
|
56
|
-
|
|
60
|
+
"Configuration lookup table does not monotonically increase or decrease."
|
|
57
61
|
)
|
|
58
62
|
|
|
59
63
|
def s_to_t2(s: float) -> float:
|
|
File without changes
|
|
@@ -14,37 +14,7 @@ from ophyd_async.core import (
|
|
|
14
14
|
)
|
|
15
15
|
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
# Sources
|
|
19
|
-
DISCONNECT = 0
|
|
20
|
-
IN1_TTL = 1
|
|
21
|
-
IN2_TTL = 4
|
|
22
|
-
IN3_TTL = 7
|
|
23
|
-
IN4_TTL = 10
|
|
24
|
-
PC_ARM = 29
|
|
25
|
-
PC_GATE = 30
|
|
26
|
-
PC_PULSE = 31
|
|
27
|
-
AND3 = 34
|
|
28
|
-
AND4 = 35
|
|
29
|
-
OR1 = 36
|
|
30
|
-
PULSE1 = 52
|
|
31
|
-
PULSE2 = 53
|
|
32
|
-
SOFT_IN1 = 60
|
|
33
|
-
SOFT_IN2 = 61
|
|
34
|
-
SOFT_IN3 = 62
|
|
35
|
-
|
|
36
|
-
# Instrument specific
|
|
37
|
-
TTL_DETECTOR = 1
|
|
38
|
-
TTL_SHUTTER = 2
|
|
39
|
-
TTL_XSPRESS3 = 3
|
|
40
|
-
TTL_PANDA = 4
|
|
41
|
-
|
|
42
|
-
# The AND gate that controls the automatic shutter
|
|
43
|
-
AUTO_SHUTTER_GATE = 2
|
|
44
|
-
|
|
45
|
-
# The first two inputs of the auto shutter gate.
|
|
46
|
-
AUTO_SHUTTER_INPUT_1 = 1
|
|
47
|
-
AUTO_SHUTTER_INPUT_2 = 2
|
|
17
|
+
from dodal.devices.zebra.zebra_constants_mapping import ZebraMapping
|
|
48
18
|
|
|
49
19
|
|
|
50
20
|
class ArmSource(StrictEnum):
|
|
@@ -303,7 +273,8 @@ class SoftInputs(StandardReadable):
|
|
|
303
273
|
class Zebra(StandardReadable):
|
|
304
274
|
"""The Zebra device."""
|
|
305
275
|
|
|
306
|
-
def __init__(self, name: str, prefix: str) -> None:
|
|
276
|
+
def __init__(self, mapping: ZebraMapping, name: str, prefix: str) -> None:
|
|
277
|
+
self.mapping = mapping
|
|
307
278
|
self.pc = PositionCompare(prefix, name)
|
|
308
279
|
self.output = ZebraOutputPanel(prefix, name)
|
|
309
280
|
self.inputs = SoftInputs(prefix, name)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from collections import Counter
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field, model_validator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ZebraMappingValidations(BaseModel):
|
|
7
|
+
"""Raises an exception if field set to -1 is accessed, and validate against
|
|
8
|
+
multiple fields mapping to the same integer"""
|
|
9
|
+
|
|
10
|
+
def __getattribute__(self, name: str):
|
|
11
|
+
"""To protect against mismatch between the Zebra configuration that a plan expects and the Zebra which has
|
|
12
|
+
been instantiated, raise exception if a field which has been set to -1 is accessed."""
|
|
13
|
+
value = object.__getattribute__(self, name)
|
|
14
|
+
if not name.startswith("__"):
|
|
15
|
+
if value == -1:
|
|
16
|
+
raise UnmappedZebraException(
|
|
17
|
+
f"'{type(self).__name__}.{name}' was accessed but is set to -1. Please check the zebra mappings against the zebra's physical configuration"
|
|
18
|
+
)
|
|
19
|
+
return value
|
|
20
|
+
|
|
21
|
+
@model_validator(mode="after")
|
|
22
|
+
def ensure_no_duplicate_connections(self):
|
|
23
|
+
"""Check that TTL outputs and sources are mapped to unique integers"""
|
|
24
|
+
|
|
25
|
+
integer_fields = {
|
|
26
|
+
key: value
|
|
27
|
+
for key, value in self.model_dump().items()
|
|
28
|
+
if isinstance(value, int) and value != -1
|
|
29
|
+
}
|
|
30
|
+
counted_vals = Counter(integer_fields.values())
|
|
31
|
+
integer_fields_with_duplicates = {
|
|
32
|
+
k: v for k, v in integer_fields.items() if counted_vals[v] > 1
|
|
33
|
+
}
|
|
34
|
+
if len(integer_fields_with_duplicates):
|
|
35
|
+
raise ValueError(
|
|
36
|
+
f"Each field in {type(self)} must be mapped to a unique integer. Duplicate fields: {integer_fields_with_duplicates}"
|
|
37
|
+
)
|
|
38
|
+
return self
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ZebraTTLOutputs(ZebraMappingValidations):
|
|
42
|
+
"""Maps hardware to the Zebra TTL output (1-4) that they're physically wired to, or
|
|
43
|
+
None if that hardware is not connected. A value of -1 means this hardware is not connected."""
|
|
44
|
+
|
|
45
|
+
TTL_EIGER: int = Field(default=-1, ge=-1, le=4)
|
|
46
|
+
TTL_PILATUS: int = Field(default=-1, ge=-1, le=4)
|
|
47
|
+
TTL_FAST_SHUTTER: int = Field(default=-1, ge=-1, le=4)
|
|
48
|
+
TTL_DETECTOR: int = Field(default=-1, ge=-1, le=4)
|
|
49
|
+
TTL_SHUTTER: int = Field(default=-1, ge=-1, le=4)
|
|
50
|
+
TTL_XSPRESS3: int = Field(default=-1, ge=-1, le=4)
|
|
51
|
+
TTL_PANDA: int = Field(default=-1, ge=-1, le=4)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ZebraSources(ZebraMappingValidations):
|
|
55
|
+
"""Maps internal Zebra signal source to their integer PV value"""
|
|
56
|
+
|
|
57
|
+
DISCONNECT: int = Field(default=0, ge=0, le=63)
|
|
58
|
+
IN1_TTL: int = Field(default=1, ge=0, le=63)
|
|
59
|
+
IN2_TTL: int = Field(default=63, ge=0, le=63)
|
|
60
|
+
IN3_TTL: int = Field(default=7, ge=0, le=63)
|
|
61
|
+
IN4_TTL: int = Field(default=10, ge=0, le=63)
|
|
62
|
+
PC_ARM: int = Field(default=29, ge=0, le=63)
|
|
63
|
+
PC_GATE: int = Field(default=30, ge=0, le=63)
|
|
64
|
+
PC_PULSE: int = Field(default=31, ge=0, le=63)
|
|
65
|
+
AND3: int = Field(default=34, ge=0, le=63)
|
|
66
|
+
AND4: int = Field(default=35, ge=0, le=63)
|
|
67
|
+
OR1: int = Field(default=36, ge=0, le=63)
|
|
68
|
+
PULSE1: int = Field(default=52, ge=0, le=63)
|
|
69
|
+
PULSE2: int = Field(default=53, ge=0, le=63)
|
|
70
|
+
SOFT_IN1: int = Field(default=60, ge=0, le=63)
|
|
71
|
+
SOFT_IN2: int = Field(default=61, ge=0, le=63)
|
|
72
|
+
SOFT_IN3: int = Field(default=62, ge=0, le=63)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ZebraMapping(ZebraMappingValidations):
|
|
76
|
+
"""Mappings to locate a Zebra device's Ophyd signals based on a specific
|
|
77
|
+
Zebra's hardware configuration and wiring.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
# Zebra ophyd signal for connection can be accessed
|
|
81
|
+
# with, eg, zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR]
|
|
82
|
+
outputs: ZebraTTLOutputs = ZebraTTLOutputs()
|
|
83
|
+
|
|
84
|
+
# Zebra ophyd signal sources can be mapped to a zebra output by doing, eg,
|
|
85
|
+
# bps.abs_set(zebra.output.out_pvs[zebra.mapping.outputs.TTL_DETECTOR],
|
|
86
|
+
# zebra.mapping.sources.AND3)
|
|
87
|
+
sources: ZebraSources = ZebraSources()
|
|
88
|
+
|
|
89
|
+
# Which of the Zebra's four AND gates is used to control the automatic shutter, if it's being used.
|
|
90
|
+
# After defining, the correct GateControl device can be accessed with, eg,
|
|
91
|
+
# zebra.logic_gates.and_gates[zebra.mapping.AND_GATE_FOR_AUTO_SHUTTER]. Set to -1 if not being used.
|
|
92
|
+
AND_GATE_FOR_AUTO_SHUTTER: int = Field(default=-1, ge=-1, le=4)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class UnmappedZebraException(Exception):
|
|
96
|
+
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|