cgse 2023.38.0__py3-none-any.whl → 2024.1.4__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 (653) hide show
  1. README.md +27 -0
  2. bump.py +85 -0
  3. cgse-2024.1.4.dist-info/METADATA +38 -0
  4. cgse-2024.1.4.dist-info/RECORD +5 -0
  5. {cgse-2023.38.0.dist-info → cgse-2024.1.4.dist-info}/WHEEL +1 -2
  6. cgse-2023.38.0.dist-info/COPYING +0 -674
  7. cgse-2023.38.0.dist-info/COPYING.LESSER +0 -165
  8. cgse-2023.38.0.dist-info/METADATA +0 -144
  9. cgse-2023.38.0.dist-info/RECORD +0 -649
  10. cgse-2023.38.0.dist-info/entry_points.txt +0 -75
  11. cgse-2023.38.0.dist-info/top_level.txt +0 -2
  12. egse/__init__.py +0 -12
  13. egse/__main__.py +0 -32
  14. egse/aeu/aeu.py +0 -5235
  15. egse/aeu/aeu_awg.yaml +0 -265
  16. egse/aeu/aeu_crio.yaml +0 -273
  17. egse/aeu/aeu_cs.py +0 -626
  18. egse/aeu/aeu_devif.py +0 -321
  19. egse/aeu/aeu_main_ui.py +0 -912
  20. egse/aeu/aeu_metrics.py +0 -131
  21. egse/aeu/aeu_protocol.py +0 -463
  22. egse/aeu/aeu_psu.yaml +0 -204
  23. egse/aeu/aeu_ui.py +0 -873
  24. egse/aeu/arbdata/FccdRead.arb +0 -2
  25. egse/aeu/arbdata/FccdRead_min_points.arb +0 -2
  26. egse/aeu/arbdata/HeaterSync_FccdRead.arb +0 -2
  27. egse/aeu/arbdata/HeaterSync_ccdRead25.arb +0 -2
  28. egse/aeu/arbdata/HeaterSync_ccdRead31_25.arb +0 -2
  29. egse/aeu/arbdata/HeaterSync_ccdRead37_50.arb +0 -2
  30. egse/aeu/arbdata/HeaterSync_ccdRead43_75.arb +0 -2
  31. egse/aeu/arbdata/HeaterSync_ccdRead50.arb +0 -2
  32. egse/aeu/arbdata/Heater_FccdRead_min_points.arb +0 -2
  33. egse/aeu/arbdata/ccdRead25.arb +0 -2
  34. egse/aeu/arbdata/ccdRead25_150ms.arb +0 -2
  35. egse/aeu/arbdata/ccdRead31_25.arb +0 -2
  36. egse/aeu/arbdata/ccdRead31_25_150ms.arb +0 -2
  37. egse/aeu/arbdata/ccdRead37_50.arb +0 -2
  38. egse/aeu/arbdata/ccdRead37_50_150ms.arb +0 -2
  39. egse/aeu/arbdata/ccdRead43_75.arb +0 -2
  40. egse/aeu/arbdata/ccdRead43_75_150ms.arb +0 -2
  41. egse/aeu/arbdata/ccdRead50.arb +0 -2
  42. egse/aeu/arbdata/ccdRead50_150ms.arb +0 -2
  43. egse/alert/__init__.py +0 -1049
  44. egse/alert/alertman.yaml +0 -37
  45. egse/alert/alertman_cs.py +0 -234
  46. egse/alert/alertman_ui.py +0 -603
  47. egse/alert/gsm/beaglebone.py +0 -138
  48. egse/alert/gsm/beaglebone.yaml +0 -51
  49. egse/alert/gsm/beaglebone_cs.py +0 -108
  50. egse/alert/gsm/beaglebone_devif.py +0 -130
  51. egse/alert/gsm/beaglebone_protocol.py +0 -48
  52. egse/bits.py +0 -318
  53. egse/camera.py +0 -44
  54. egse/collimator/__init__.py +0 -0
  55. egse/collimator/fcul/__init__.py +0 -0
  56. egse/collimator/fcul/ogse.py +0 -1077
  57. egse/collimator/fcul/ogse.yaml +0 -14
  58. egse/collimator/fcul/ogse_cs.py +0 -154
  59. egse/collimator/fcul/ogse_devif.py +0 -358
  60. egse/collimator/fcul/ogse_protocol.py +0 -129
  61. egse/collimator/fcul/ogse_sim.py +0 -431
  62. egse/collimator/fcul/ogse_ui.py +0 -1108
  63. egse/command.py +0 -699
  64. egse/config.py +0 -410
  65. egse/confman/__init__.py +0 -1015
  66. egse/confman/confman.yaml +0 -67
  67. egse/confman/confman_cs.py +0 -239
  68. egse/confman/confman_ui.py +0 -381
  69. egse/confman/setup_ui.py +0 -565
  70. egse/control.py +0 -442
  71. egse/coordinates/__init__.py +0 -531
  72. egse/coordinates/avoidance.py +0 -103
  73. egse/coordinates/cslmodel.py +0 -127
  74. egse/coordinates/laser_tracker_to_dict.py +0 -120
  75. egse/coordinates/point.py +0 -707
  76. egse/coordinates/pyplot.py +0 -195
  77. egse/coordinates/referenceFrame.py +0 -1279
  78. egse/coordinates/refmodel.py +0 -737
  79. egse/coordinates/rotationMatrix.py +0 -85
  80. egse/coordinates/transform3d_addon.py +0 -419
  81. egse/csl/__init__.py +0 -50
  82. egse/csl/commanding.py +0 -78
  83. egse/csl/icons/hexapod-connected-selected.svg +0 -30
  84. egse/csl/icons/hexapod-connected.svg +0 -30
  85. egse/csl/icons/hexapod-homing-selected.svg +0 -68
  86. egse/csl/icons/hexapod-homing.svg +0 -68
  87. egse/csl/icons/hexapod-retract-selected.svg +0 -56
  88. egse/csl/icons/hexapod-retract.svg +0 -51
  89. egse/csl/icons/hexapod-zero-selected.svg +0 -56
  90. egse/csl/icons/hexapod-zero.svg +0 -56
  91. egse/csl/icons/logo-puna.svg +0 -92
  92. egse/csl/icons/stop.svg +0 -1
  93. egse/csl/initialisation.py +0 -102
  94. egse/csl/mech_pos_settings.yaml +0 -18
  95. egse/das.py +0 -1247
  96. egse/das.yaml +0 -7
  97. egse/data/conf/SETUP_CSL_00000_170620_150000.yaml +0 -5
  98. egse/data/conf/SETUP_CSL_00001_170620_151010.yaml +0 -69
  99. egse/data/conf/SETUP_CSL_00002_170620_151020.yaml +0 -69
  100. egse/data/conf/SETUP_CSL_00003_170620_151030.yaml +0 -69
  101. egse/data/conf/SETUP_CSL_00004_170620_151040.yaml +0 -69
  102. egse/data/conf/SETUP_CSL_00005_170620_151050.yaml +0 -69
  103. egse/data/conf/SETUP_CSL_00006_170620_151060.yaml +0 -69
  104. egse/data/conf/SETUP_CSL_00007_170620_151070.yaml +0 -69
  105. egse/data/conf/SETUP_CSL_00008_170620_151080.yaml +0 -75
  106. egse/data/conf/SETUP_CSL_00010_210308_083016.yaml +0 -138
  107. egse/data/conf/SETUP_INTA_00000_170620_150000.yaml +0 -4
  108. egse/data/conf/SETUP_SRON_00000_170620_150000.yaml +0 -4
  109. egse/decorators.py +0 -415
  110. egse/device.py +0 -269
  111. egse/dpu/__init__.py +0 -2681
  112. egse/dpu/ccd_ui.py +0 -508
  113. egse/dpu/dpu.py +0 -786
  114. egse/dpu/dpu.yaml +0 -153
  115. egse/dpu/dpu_cs.py +0 -272
  116. egse/dpu/dpu_ui.py +0 -668
  117. egse/dpu/fitsgen.py +0 -2077
  118. egse/dpu/fitsgen_test.py +0 -752
  119. egse/dpu/fitsgen_ui.py +0 -399
  120. egse/dpu/hdf5_model.py +0 -332
  121. egse/dpu/hdf5_ui.py +0 -277
  122. egse/dpu/hdf5_viewer.py +0 -506
  123. egse/dpu/hk_ui.py +0 -468
  124. egse/dpu_commands.py +0 -81
  125. egse/dsi/constants.py +0 -220
  126. egse/dsi/esl.py +0 -870
  127. egse/dsi/rmap.py +0 -1042
  128. egse/dsi/rmapci.py +0 -37
  129. egse/dsi/spw.py +0 -154
  130. egse/dsi/spw_state.py +0 -29
  131. egse/dummy.py +0 -258
  132. egse/dyndummy.py +0 -179
  133. egse/env.py +0 -278
  134. egse/exceptions.py +0 -88
  135. egse/fdir/__init__.py +0 -28
  136. egse/fdir/fdir_manager.py +0 -85
  137. egse/fdir/fdir_manager.yaml +0 -51
  138. egse/fdir/fdir_manager_controller.py +0 -228
  139. egse/fdir/fdir_manager_cs.py +0 -164
  140. egse/fdir/fdir_manager_interface.py +0 -25
  141. egse/fdir/fdir_remote.py +0 -73
  142. egse/fdir/fdir_remote.yaml +0 -37
  143. egse/fdir/fdir_remote_controller.py +0 -50
  144. egse/fdir/fdir_remote_cs.py +0 -97
  145. egse/fdir/fdir_remote_interface.py +0 -14
  146. egse/fdir/fdir_remote_popup.py +0 -31
  147. egse/fee/__init__.py +0 -114
  148. egse/fee/f_fee_register.yaml +0 -43
  149. egse/fee/fee.py +0 -631
  150. egse/fee/feesim.py +0 -750
  151. egse/fee/n_fee_hk.py +0 -761
  152. egse/fee/nfee.py +0 -187
  153. egse/filterwheel/__init__.py +0 -4
  154. egse/filterwheel/eksma/__init__.py +0 -24
  155. egse/filterwheel/eksma/fw8smc4.py +0 -661
  156. egse/filterwheel/eksma/fw8smc4.yaml +0 -121
  157. egse/filterwheel/eksma/fw8smc4_cs.py +0 -144
  158. egse/filterwheel/eksma/fw8smc4_devif.py +0 -473
  159. egse/filterwheel/eksma/fw8smc4_protocol.py +0 -81
  160. egse/filterwheel/eksma/fw8smc4_ui.py +0 -940
  161. egse/filterwheel/eksma/fw8smc5.py +0 -111
  162. egse/filterwheel/eksma/fw8smc5.yaml +0 -105
  163. egse/filterwheel/eksma/fw8smc5_controller.py +0 -307
  164. egse/filterwheel/eksma/fw8smc5_cs.py +0 -141
  165. egse/filterwheel/eksma/fw8smc5_interface.py +0 -65
  166. egse/filterwheel/eksma/fw8smc5_simulator.py +0 -29
  167. egse/filterwheel/eksma/fw8smc5_ui.py +0 -1068
  168. egse/filterwheel/eksma/testpythonfw.py +0 -215
  169. egse/fov/__init__.py +0 -65
  170. egse/fov/fov_hk.py +0 -712
  171. egse/fov/fov_ui.py +0 -861
  172. egse/fov/fov_ui_controller.py +0 -140
  173. egse/fov/fov_ui_model.py +0 -200
  174. egse/fov/fov_ui_view.py +0 -345
  175. egse/gimbal/__init__.py +0 -32
  176. egse/gimbal/symetrie/__init__.py +0 -26
  177. egse/gimbal/symetrie/alpha.py +0 -586
  178. egse/gimbal/symetrie/generic_gimbal_ui.py +0 -1521
  179. egse/gimbal/symetrie/gimbal.py +0 -877
  180. egse/gimbal/symetrie/gimbal.yaml +0 -168
  181. egse/gimbal/symetrie/gimbal_cs.py +0 -183
  182. egse/gimbal/symetrie/gimbal_protocol.py +0 -135
  183. egse/gimbal/symetrie/gimbal_ui.py +0 -361
  184. egse/gimbal/symetrie/pmac.py +0 -1006
  185. egse/gimbal/symetrie/pmac_regex.py +0 -83
  186. egse/graph.py +0 -132
  187. egse/gui/__init__.py +0 -47
  188. egse/gui/buttons.py +0 -378
  189. egse/gui/focalplane.py +0 -1281
  190. egse/gui/formatter.py +0 -10
  191. egse/gui/led.py +0 -162
  192. egse/gui/limitswitch.py +0 -143
  193. egse/gui/mechanisms.py +0 -588
  194. egse/gui/states.py +0 -148
  195. egse/gui/stripchart.py +0 -729
  196. egse/gui/switch.py +0 -112
  197. egse/h5.py +0 -274
  198. egse/help/__init__.py +0 -0
  199. egse/help/help_ui.py +0 -126
  200. egse/hexapod/__init__.py +0 -32
  201. egse/hexapod/symetrie/__init__.py +0 -138
  202. egse/hexapod/symetrie/alpha.py +0 -874
  203. egse/hexapod/symetrie/dynalpha.py +0 -1387
  204. egse/hexapod/symetrie/hexapod_ui.py +0 -1516
  205. egse/hexapod/symetrie/pmac.py +0 -1010
  206. egse/hexapod/symetrie/pmac_regex.py +0 -83
  207. egse/hexapod/symetrie/puna.py +0 -1167
  208. egse/hexapod/symetrie/puna.yaml +0 -193
  209. egse/hexapod/symetrie/puna_cs.py +0 -196
  210. egse/hexapod/symetrie/puna_protocol.py +0 -131
  211. egse/hexapod/symetrie/puna_ui.py +0 -434
  212. egse/hexapod/symetrie/punaplus.py +0 -107
  213. egse/hexapod/symetrie/zonda.py +0 -872
  214. egse/hexapod/symetrie/zonda.yaml +0 -337
  215. egse/hexapod/symetrie/zonda_cs.py +0 -172
  216. egse/hexapod/symetrie/zonda_devif.py +0 -415
  217. egse/hexapod/symetrie/zonda_protocol.py +0 -119
  218. egse/hexapod/symetrie/zonda_ui.py +0 -449
  219. egse/hk.py +0 -765
  220. egse/icons/aeu-cs-start.svg +0 -117
  221. egse/icons/aeu-cs-stop.svg +0 -118
  222. egse/icons/aeu-cs.svg +0 -107
  223. egse/icons/aeu_cs-started.svg +0 -112
  224. egse/icons/aeu_cs-stopped.svg +0 -112
  225. egse/icons/aeu_cs.svg +0 -55
  226. egse/icons/alert.svg +0 -1
  227. egse/icons/arrow-double-left.png +0 -0
  228. egse/icons/arrow-double-right.png +0 -0
  229. egse/icons/arrow-up.svg +0 -11
  230. egse/icons/backward.svg +0 -1
  231. egse/icons/busy.svg +0 -1
  232. egse/icons/cleaning.svg +0 -115
  233. egse/icons/color-scheme.svg +0 -1
  234. egse/icons/cs-connected-alert.svg +0 -91
  235. egse/icons/cs-connected-disabled.svg +0 -43
  236. egse/icons/cs-connected.svg +0 -89
  237. egse/icons/cs-not-connected.svg +0 -44
  238. egse/icons/double-left-arrow.svg +0 -1
  239. egse/icons/double-right-arrow.svg +0 -1
  240. egse/icons/erase-disabled.svg +0 -19
  241. egse/icons/erase.svg +0 -59
  242. egse/icons/fitsgen-start.svg +0 -47
  243. egse/icons/fitsgen-stop.svg +0 -48
  244. egse/icons/fitsgen.svg +0 -1
  245. egse/icons/forward.svg +0 -1
  246. egse/icons/fov-hk-start.svg +0 -33
  247. egse/icons/fov-hk-stop.svg +0 -37
  248. egse/icons/fov-hk.svg +0 -1
  249. egse/icons/front-desk.svg +0 -1
  250. egse/icons/home-actioned.svg +0 -15
  251. egse/icons/home-disabled.svg +0 -15
  252. egse/icons/home.svg +0 -13
  253. egse/icons/info.svg +0 -1
  254. egse/icons/invalid.png +0 -0
  255. egse/icons/led-green.svg +0 -20
  256. egse/icons/led-grey.svg +0 -20
  257. egse/icons/led-orange.svg +0 -20
  258. egse/icons/led-red.svg +0 -20
  259. egse/icons/led-square-green.svg +0 -134
  260. egse/icons/led-square-grey.svg +0 -134
  261. egse/icons/led-square-orange.svg +0 -134
  262. egse/icons/led-square-red.svg +0 -134
  263. egse/icons/limit-switch-all-green.svg +0 -115
  264. egse/icons/limit-switch-all-red.svg +0 -117
  265. egse/icons/limit-switch-el+.svg +0 -116
  266. egse/icons/limit-switch-el-.svg +0 -117
  267. egse/icons/location-marker.svg +0 -1
  268. egse/icons/logo-dpu.svg +0 -48
  269. egse/icons/logo-gimbal.svg +0 -112
  270. egse/icons/logo-huber.svg +0 -23
  271. egse/icons/logo-ogse.svg +0 -31
  272. egse/icons/logo-puna.svg +0 -92
  273. egse/icons/logo-tcs.svg +0 -29
  274. egse/icons/logo-zonda.svg +0 -66
  275. egse/icons/maximize.svg +0 -1
  276. egse/icons/meter.svg +0 -1
  277. egse/icons/more.svg +0 -45
  278. egse/icons/n-fee-hk-start.svg +0 -24
  279. egse/icons/n-fee-hk-stop.svg +0 -25
  280. egse/icons/n-fee-hk.svg +0 -83
  281. egse/icons/observing-off.svg +0 -46
  282. egse/icons/observing-on.svg +0 -46
  283. egse/icons/open-document-hdf5.png +0 -0
  284. egse/icons/open-document-hdf5.svg +0 -21
  285. egse/icons/ops-mode.svg +0 -1
  286. egse/icons/play-green.svg +0 -17
  287. egse/icons/plugged-disabled.svg +0 -27
  288. egse/icons/plugged.svg +0 -21
  289. egse/icons/pm_ui.svg +0 -1
  290. egse/icons/power-button-green.svg +0 -27
  291. egse/icons/power-button-red.svg +0 -27
  292. egse/icons/power-button.svg +0 -27
  293. egse/icons/radar.svg +0 -1
  294. egse/icons/radioactive.svg +0 -2
  295. egse/icons/reload.svg +0 -1
  296. egse/icons/remote-control-off.svg +0 -28
  297. egse/icons/remote-control-on.svg +0 -28
  298. egse/icons/repeat-blue.svg +0 -15
  299. egse/icons/repeat.svg +0 -1
  300. egse/icons/settings.svg +0 -1
  301. egse/icons/shrink.svg +0 -1
  302. egse/icons/shutter.svg +0 -1
  303. egse/icons/sign-off.svg +0 -1
  304. egse/icons/sign-on.svg +0 -1
  305. egse/icons/sim-mode.svg +0 -1
  306. egse/icons/small-buttons-go.svg +0 -20
  307. egse/icons/small-buttons-minus.svg +0 -51
  308. egse/icons/small-buttons-plus.svg +0 -51
  309. egse/icons/sponge.svg +0 -220
  310. egse/icons/start-button-disabled.svg +0 -84
  311. egse/icons/start-button.svg +0 -50
  312. egse/icons/stop-button-disabled.svg +0 -84
  313. egse/icons/stop-button.svg +0 -50
  314. egse/icons/stop-red.svg +0 -17
  315. egse/icons/stop.svg +0 -1
  316. egse/icons/switch-disabled-square.svg +0 -87
  317. egse/icons/switch-disabled.svg +0 -15
  318. egse/icons/switch-off-square.svg +0 -87
  319. egse/icons/switch-off.svg +0 -72
  320. egse/icons/switch-on-square.svg +0 -87
  321. egse/icons/switch-on.svg +0 -61
  322. egse/icons/temperature-control.svg +0 -44
  323. egse/icons/th_ui_logo.svg +0 -1
  324. egse/icons/unplugged.svg +0 -23
  325. egse/icons/unvalid.png +0 -0
  326. egse/icons/user-interface.svg +0 -1
  327. egse/icons/vacuum.svg +0 -1
  328. egse/icons/valid.png +0 -0
  329. egse/icons/zoom-to-pixel-dark.svg +0 -64
  330. egse/icons/zoom-to-pixel-white.svg +0 -36
  331. egse/images/big-rotation-stage.png +0 -0
  332. egse/images/connected-100.png +0 -0
  333. egse/images/cross.svg +0 -6
  334. egse/images/disconnected-100.png +0 -0
  335. egse/images/gui-icon.png +0 -0
  336. egse/images/home.svg +0 -6
  337. egse/images/info-icon.png +0 -0
  338. egse/images/led-black.svg +0 -89
  339. egse/images/led-green.svg +0 -85
  340. egse/images/led-orange.svg +0 -85
  341. egse/images/led-red.svg +0 -85
  342. egse/images/load-icon.png +0 -0
  343. egse/images/load-setup.png +0 -0
  344. egse/images/load.png +0 -0
  345. egse/images/pause.png +0 -0
  346. egse/images/play-button.svg +0 -8
  347. egse/images/play.png +0 -0
  348. egse/images/process-status.png +0 -0
  349. egse/images/restart.png +0 -0
  350. egse/images/search.png +0 -0
  351. egse/images/sma.png +0 -0
  352. egse/images/start.png +0 -0
  353. egse/images/stop-button.svg +0 -8
  354. egse/images/stop.png +0 -0
  355. egse/images/switch-off.svg +0 -48
  356. egse/images/switch-on.svg +0 -48
  357. egse/images/undo.png +0 -0
  358. egse/images/update-button.svg +0 -11
  359. egse/imageviewer/exposureselection.py +0 -475
  360. egse/imageviewer/imageviewer.py +0 -198
  361. egse/imageviewer/matchfocalplane.py +0 -179
  362. egse/imageviewer/subfieldposition.py +0 -133
  363. egse/lampcontrol/__init__.py +0 -4
  364. egse/lampcontrol/beaglebone/beaglebone.py +0 -178
  365. egse/lampcontrol/beaglebone/beaglebone.yaml +0 -62
  366. egse/lampcontrol/beaglebone/beaglebone_cs.py +0 -106
  367. egse/lampcontrol/beaglebone/beaglebone_devif.py +0 -150
  368. egse/lampcontrol/beaglebone/beaglebone_protocol.py +0 -73
  369. egse/lampcontrol/energetiq/__init__.py +0 -22
  370. egse/lampcontrol/energetiq/eq99.yaml +0 -98
  371. egse/lampcontrol/energetiq/lampEQ99.py +0 -283
  372. egse/lampcontrol/energetiq/lampEQ99_cs.py +0 -128
  373. egse/lampcontrol/energetiq/lampEQ99_devif.py +0 -158
  374. egse/lampcontrol/energetiq/lampEQ99_encode_decode_errors.py +0 -73
  375. egse/lampcontrol/energetiq/lampEQ99_protocol.py +0 -69
  376. egse/lampcontrol/energetiq/lampEQ99_ui.py +0 -465
  377. egse/lib/CentOS-7/EtherSpaceLink_v34_86.dylib +0 -0
  378. egse/lib/CentOS-8/ESL-RMAP_v34_86.dylib +0 -0
  379. egse/lib/CentOS-8/EtherSpaceLink_v34_86.dylib +0 -0
  380. egse/lib/Debian/ESL-RMAP_v34_86.dylib +0 -0
  381. egse/lib/Debian/EtherSpaceLink_v34_86.dylib +0 -0
  382. egse/lib/Debian/libetherspacelink_v35_21.dylib +0 -0
  383. egse/lib/Linux/ESL-RMAP_v34_86.dylib +0 -0
  384. egse/lib/Linux/EtherSpaceLink_v34_86.dylib +0 -0
  385. egse/lib/Ubuntu-20/ESL-RMAP_v34_86.dylib +0 -0
  386. egse/lib/Ubuntu-20/EtherSpaceLink_v34_86.dylib +0 -0
  387. egse/lib/gssw/python3-gssw_2.2.3+31f63c9f-1_all.deb +0 -0
  388. egse/lib/macOS/ESL-RMAP_v34_86.dylib +0 -0
  389. egse/lib/macOS/EtherSpaceLink_v34_86.dylib +0 -0
  390. egse/lib/ximc/__pycache__/pyximc.cpython-38 2.pyc +0 -0
  391. egse/lib/ximc/__pycache__/pyximc.cpython-38.pyc +0 -0
  392. egse/lib/ximc/libximc.framework/Frameworks/libbindy.dylib +0 -0
  393. egse/lib/ximc/libximc.framework/Frameworks/libxiwrapper.dylib +0 -0
  394. egse/lib/ximc/libximc.framework/Headers/ximc.h +0 -5510
  395. egse/lib/ximc/libximc.framework/Resources/Info.plist +0 -42
  396. egse/lib/ximc/libximc.framework/Resources/keyfile.sqlite +0 -0
  397. egse/lib/ximc/libximc.framework/libbindy.so +0 -0
  398. egse/lib/ximc/libximc.framework/libximc +0 -0
  399. egse/lib/ximc/libximc.framework/libximc.so +0 -0
  400. egse/lib/ximc/libximc.framework/libximc.so.7.0.0 +0 -0
  401. egse/lib/ximc/libximc.framework/libxiwrapper.so +0 -0
  402. egse/lib/ximc/pyximc.py +0 -922
  403. egse/listener.py +0 -73
  404. egse/logger/__init__.py +0 -243
  405. egse/logger/log_cs.py +0 -321
  406. egse/metrics.py +0 -98
  407. egse/mixin.py +0 -464
  408. egse/monitoring.py +0 -95
  409. egse/ni/alarms/__init__.py +0 -26
  410. egse/ni/alarms/cdaq9375.py +0 -300
  411. egse/ni/alarms/cdaq9375.yaml +0 -89
  412. egse/ni/alarms/cdaq9375_cs.py +0 -130
  413. egse/ni/alarms/cdaq9375_devif.py +0 -183
  414. egse/ni/alarms/cdaq9375_protocol.py +0 -48
  415. egse/obs_inspection.py +0 -163
  416. egse/observer.py +0 -41
  417. egse/obsid.py +0 -163
  418. egse/powermeter/__init__.py +0 -0
  419. egse/powermeter/ni/__init__.py +0 -38
  420. egse/powermeter/ni/cdaq9184.py +0 -224
  421. egse/powermeter/ni/cdaq9184.yaml +0 -73
  422. egse/powermeter/ni/cdaq9184_cs.py +0 -130
  423. egse/powermeter/ni/cdaq9184_devif.py +0 -201
  424. egse/powermeter/ni/cdaq9184_protocol.py +0 -48
  425. egse/powermeter/ni/cdaq9184_ui.py +0 -544
  426. egse/powermeter/thorlabs/__init__.py +0 -25
  427. egse/powermeter/thorlabs/pm100a.py +0 -380
  428. egse/powermeter/thorlabs/pm100a.yaml +0 -132
  429. egse/powermeter/thorlabs/pm100a_cs.py +0 -136
  430. egse/powermeter/thorlabs/pm100a_devif.py +0 -127
  431. egse/powermeter/thorlabs/pm100a_protocol.py +0 -80
  432. egse/powermeter/thorlabs/pm100a_ui.py +0 -725
  433. egse/process.py +0 -451
  434. egse/procman/__init__.py +0 -811
  435. egse/procman/cannot_start_process_popup.py +0 -43
  436. egse/procman/procman.yaml +0 -49
  437. egse/procman/procman_cs.py +0 -201
  438. egse/procman/procman_ui.py +0 -2081
  439. egse/protocol.py +0 -603
  440. egse/proxy.py +0 -522
  441. egse/randomwalk.py +0 -140
  442. egse/reg.py +0 -585
  443. egse/reload.py +0 -122
  444. egse/reprocess.py +0 -675
  445. egse/resource.py +0 -333
  446. egse/rst.py +0 -135
  447. egse/search.py +0 -182
  448. egse/serialdevice.py +0 -190
  449. egse/services.py +0 -212
  450. egse/services.yaml +0 -51
  451. egse/settings.py +0 -379
  452. egse/settings.yaml +0 -980
  453. egse/setup.py +0 -1180
  454. egse/shutter/__init__.py +0 -0
  455. egse/shutter/thorlabs/__init__.py +0 -19
  456. egse/shutter/thorlabs/ksc101.py +0 -205
  457. egse/shutter/thorlabs/ksc101.yaml +0 -105
  458. egse/shutter/thorlabs/ksc101_cs.py +0 -136
  459. egse/shutter/thorlabs/ksc101_devif.py +0 -201
  460. egse/shutter/thorlabs/ksc101_protocol.py +0 -69
  461. egse/shutter/thorlabs/ksc101_ui.py +0 -548
  462. egse/shutter/thorlabs/sc10.py +0 -82
  463. egse/shutter/thorlabs/sc10.yaml +0 -52
  464. egse/shutter/thorlabs/sc10_controller.py +0 -81
  465. egse/shutter/thorlabs/sc10_cs.py +0 -108
  466. egse/shutter/thorlabs/sc10_interface.py +0 -25
  467. egse/shutter/thorlabs/sc10_simulator.py +0 -30
  468. egse/simulator.py +0 -41
  469. egse/slack.py +0 -61
  470. egse/socketdevice.py +0 -218
  471. egse/sockets.py +0 -218
  472. egse/spw.py +0 -1479
  473. egse/stages/__init__.py +0 -12
  474. egse/stages/aerotech/ensemble.py +0 -247
  475. egse/stages/aerotech/ensemble.yaml +0 -205
  476. egse/stages/aerotech/ensemble_controller.py +0 -275
  477. egse/stages/aerotech/ensemble_cs.py +0 -110
  478. egse/stages/aerotech/ensemble_interface.py +0 -132
  479. egse/stages/aerotech/ensemble_parameters.py +0 -433
  480. egse/stages/aerotech/ensemble_simulator.py +0 -27
  481. egse/stages/aerotech/mgse_sim.py +0 -193
  482. egse/stages/arun/smd3.py +0 -111
  483. egse/stages/arun/smd3.yaml +0 -68
  484. egse/stages/arun/smd3_controller.py +0 -472
  485. egse/stages/arun/smd3_cs.py +0 -112
  486. egse/stages/arun/smd3_interface.py +0 -53
  487. egse/stages/arun/smd3_simulator.py +0 -27
  488. egse/stages/arun/smd3_stop.py +0 -16
  489. egse/stages/huber/__init__.py +0 -49
  490. egse/stages/huber/smc9300.py +0 -904
  491. egse/stages/huber/smc9300.yaml +0 -63
  492. egse/stages/huber/smc9300_cs.py +0 -178
  493. egse/stages/huber/smc9300_devif.py +0 -345
  494. egse/stages/huber/smc9300_protocol.py +0 -111
  495. egse/stages/huber/smc9300_sim.py +0 -547
  496. egse/stages/huber/smc9300_ui.py +0 -973
  497. egse/state.py +0 -173
  498. egse/statemachine.py +0 -274
  499. egse/storage/__init__.py +0 -1004
  500. egse/storage/persistence.py +0 -2295
  501. egse/storage/storage.yaml +0 -72
  502. egse/storage/storage_cs.py +0 -214
  503. egse/styles/dark.qss +0 -343
  504. egse/styles/default.qss +0 -48
  505. egse/synoptics/__init__.py +0 -412
  506. egse/synoptics/syn.yaml +0 -9
  507. egse/synoptics/syn_cs.py +0 -195
  508. egse/system.py +0 -1408
  509. egse/tcs/__init__.py +0 -14
  510. egse/tcs/tcs.py +0 -874
  511. egse/tcs/tcs.yaml +0 -14
  512. egse/tcs/tcs_cs.py +0 -202
  513. egse/tcs/tcs_devif.py +0 -292
  514. egse/tcs/tcs_protocol.py +0 -177
  515. egse/tcs/tcs_sim.py +0 -177
  516. egse/tcs/tcs_ui.py +0 -543
  517. egse/tdms.py +0 -171
  518. egse/tempcontrol/__init__.py +0 -23
  519. egse/tempcontrol/agilent/agilent34970.py +0 -109
  520. egse/tempcontrol/agilent/agilent34970.yaml +0 -44
  521. egse/tempcontrol/agilent/agilent34970_cs.py +0 -116
  522. egse/tempcontrol/agilent/agilent34970_devif.py +0 -182
  523. egse/tempcontrol/agilent/agilent34970_protocol.py +0 -99
  524. egse/tempcontrol/agilent/agilent34972.py +0 -111
  525. egse/tempcontrol/agilent/agilent34972.yaml +0 -44
  526. egse/tempcontrol/agilent/agilent34972_cs.py +0 -117
  527. egse/tempcontrol/agilent/agilent34972_devif.py +0 -189
  528. egse/tempcontrol/agilent/agilent34972_protocol.py +0 -101
  529. egse/tempcontrol/beaglebone/beaglebone.py +0 -342
  530. egse/tempcontrol/beaglebone/beaglebone.yaml +0 -110
  531. egse/tempcontrol/beaglebone/beaglebone_cs.py +0 -117
  532. egse/tempcontrol/beaglebone/beaglebone_protocol.py +0 -135
  533. egse/tempcontrol/beaglebone/beaglebone_ui.py +0 -681
  534. egse/tempcontrol/digalox/digalox.py +0 -107
  535. egse/tempcontrol/digalox/digalox.yaml +0 -36
  536. egse/tempcontrol/digalox/digalox_cs.py +0 -112
  537. egse/tempcontrol/digalox/digalox_protocol.py +0 -55
  538. egse/tempcontrol/keithley/__init__.py +0 -33
  539. egse/tempcontrol/keithley/daq6510.py +0 -662
  540. egse/tempcontrol/keithley/daq6510.yaml +0 -105
  541. egse/tempcontrol/keithley/daq6510_cs.py +0 -163
  542. egse/tempcontrol/keithley/daq6510_devif.py +0 -343
  543. egse/tempcontrol/keithley/daq6510_protocol.py +0 -78
  544. egse/tempcontrol/keithley/daq6510_sim.py +0 -186
  545. egse/tempcontrol/lakeshore/__init__.py +0 -33
  546. egse/tempcontrol/lakeshore/lsci.py +0 -361
  547. egse/tempcontrol/lakeshore/lsci.yaml +0 -162
  548. egse/tempcontrol/lakeshore/lsci_cs.py +0 -174
  549. egse/tempcontrol/lakeshore/lsci_devif.py +0 -292
  550. egse/tempcontrol/lakeshore/lsci_protocol.py +0 -73
  551. egse/tempcontrol/lakeshore/lsci_ui.py +0 -389
  552. egse/tempcontrol/ni/__init__.py +0 -0
  553. egse/tempcontrol/spid/spid.py +0 -109
  554. egse/tempcontrol/spid/spid.yaml +0 -81
  555. egse/tempcontrol/spid/spid_controller.py +0 -279
  556. egse/tempcontrol/spid/spid_cs.py +0 -136
  557. egse/tempcontrol/spid/spid_protocol.py +0 -107
  558. egse/tempcontrol/spid/spid_ui.py +0 -727
  559. egse/tempcontrol/srs/__init__.py +0 -22
  560. egse/tempcontrol/srs/ptc10.py +0 -875
  561. egse/tempcontrol/srs/ptc10.yaml +0 -227
  562. egse/tempcontrol/srs/ptc10_cs.py +0 -128
  563. egse/tempcontrol/srs/ptc10_devif.py +0 -118
  564. egse/tempcontrol/srs/ptc10_protocol.py +0 -42
  565. egse/tempcontrol/srs/ptc10_ui.py +0 -906
  566. egse/ups/apc/apc.py +0 -236
  567. egse/ups/apc/apc.yaml +0 -45
  568. egse/ups/apc/apc_cs.py +0 -101
  569. egse/ups/apc/apc_protocol.py +0 -125
  570. egse/user.yaml +0 -7
  571. egse/vacuum/beaglebone/beaglebone.py +0 -149
  572. egse/vacuum/beaglebone/beaglebone.yaml +0 -44
  573. egse/vacuum/beaglebone/beaglebone_cs.py +0 -108
  574. egse/vacuum/beaglebone/beaglebone_devif.py +0 -164
  575. egse/vacuum/beaglebone/beaglebone_protocol.py +0 -193
  576. egse/vacuum/beaglebone/beaglebone_ui.py +0 -638
  577. egse/vacuum/instrutech/igm402.py +0 -92
  578. egse/vacuum/instrutech/igm402.yaml +0 -90
  579. egse/vacuum/instrutech/igm402_controller.py +0 -128
  580. egse/vacuum/instrutech/igm402_cs.py +0 -108
  581. egse/vacuum/instrutech/igm402_interface.py +0 -49
  582. egse/vacuum/instrutech/igm402_simulator.py +0 -36
  583. egse/vacuum/keller/kellerBus.py +0 -256
  584. egse/vacuum/keller/leo3.py +0 -102
  585. egse/vacuum/keller/leo3.yaml +0 -38
  586. egse/vacuum/keller/leo3_controller.py +0 -83
  587. egse/vacuum/keller/leo3_cs.py +0 -101
  588. egse/vacuum/keller/leo3_interface.py +0 -33
  589. egse/vacuum/mks/evision.py +0 -86
  590. egse/vacuum/mks/evision.yaml +0 -75
  591. egse/vacuum/mks/evision_cs.py +0 -101
  592. egse/vacuum/mks/evision_devif.py +0 -316
  593. egse/vacuum/mks/evision_interface.py +0 -60
  594. egse/vacuum/mks/evision_simulator.py +0 -24
  595. egse/vacuum/mks/evision_ui.py +0 -704
  596. egse/vacuum/pfeiffer/acp40.py +0 -87
  597. egse/vacuum/pfeiffer/acp40.yaml +0 -60
  598. egse/vacuum/pfeiffer/acp40_controller.py +0 -117
  599. egse/vacuum/pfeiffer/acp40_cs.py +0 -109
  600. egse/vacuum/pfeiffer/acp40_interface.py +0 -40
  601. egse/vacuum/pfeiffer/acp40_simulator.py +0 -39
  602. egse/vacuum/pfeiffer/tc400.py +0 -113
  603. egse/vacuum/pfeiffer/tc400.yaml +0 -83
  604. egse/vacuum/pfeiffer/tc400_controller.py +0 -140
  605. egse/vacuum/pfeiffer/tc400_cs.py +0 -109
  606. egse/vacuum/pfeiffer/tc400_interface.py +0 -70
  607. egse/vacuum/pfeiffer/tc400_simulator.py +0 -24
  608. egse/vacuum/pfeiffer/tpg261.py +0 -81
  609. egse/vacuum/pfeiffer/tpg261.yaml +0 -66
  610. egse/vacuum/pfeiffer/tpg261_controller.py +0 -150
  611. egse/vacuum/pfeiffer/tpg261_cs.py +0 -109
  612. egse/vacuum/pfeiffer/tpg261_interface.py +0 -60
  613. egse/vacuum/pfeiffer/tpg261_simulator.py +0 -24
  614. egse/version.py +0 -174
  615. egse/visitedpositions.py +0 -398
  616. egse/windowing.py +0 -213
  617. egse/zmq/__init__.py +0 -28
  618. egse/zmq/spw.py +0 -160
  619. egse/zmq_ser.py +0 -41
  620. scripts/alerts/cold.yaml +0 -278
  621. scripts/alerts/example_alerts.yaml +0 -54
  622. scripts/alerts/transition.yaml +0 -14
  623. scripts/alerts/warm.yaml +0 -49
  624. scripts/analyse_n_fee_hk_data.py +0 -44
  625. scripts/check_hdf5_files.py +0 -192
  626. scripts/check_register_sync.py +0 -47
  627. scripts/create_hdf5_report.py +0 -295
  628. scripts/csl_model.py +0 -436
  629. scripts/csl_restore_setup.py +0 -230
  630. scripts/export-grafana-dashboards.py +0 -50
  631. scripts/fdir/cs_recovery/fdir_cs_recovery.py +0 -59
  632. scripts/fdir/fdir_table.yaml +0 -70
  633. scripts/fdir/fdir_test_recovery.py +0 -11
  634. scripts/fdir/hw_recovery/fdir_agilent_hw_recovery.py +0 -73
  635. scripts/fdir/limit_recovery/fdir_agilent_limit.py +0 -64
  636. scripts/fdir/limit_recovery/fdir_bb_heater_limit.py +0 -61
  637. scripts/fdir/limit_recovery/fdir_ensemble_limit.py +0 -33
  638. scripts/fdir/limit_recovery/fdir_pressure_limit_recovery.py +0 -71
  639. scripts/fix_csv.py +0 -80
  640. scripts/n_fee_supply_voltage_calculation.py +0 -92
  641. scripts/playground.py +0 -30
  642. scripts/print_hdf5_hk_data.py +0 -68
  643. scripts/print_register_map.py +0 -43
  644. scripts/sron/commanding/control_heaters.py +0 -44
  645. scripts/sron/commanding/pumpdown.py +0 -46
  646. scripts/sron/commanding/set_pid_setpoint.py +0 -19
  647. scripts/sron/commanding/shutdown_bbb_heaters.py +0 -10
  648. scripts/sron/commanding/shutdown_pumps.py +0 -33
  649. scripts/sron/tm_gen/tm_gen_agilent.py +0 -38
  650. scripts/sron/tm_gen/tm_gen_heaters.py +0 -4
  651. scripts/sron/tm_gen/tm_gen_spid.py +0 -13
  652. scripts/update_operational_cgse.py +0 -268
  653. scripts/update_operational_cgse_old.py +0 -273
egse/spw.py DELETED
@@ -1,1479 +0,0 @@
1
- """
2
- This module defines classes and functions to work with SpaceWire packets.
3
- """
4
- import logging
5
- import os
6
- import struct
7
- from enum import IntEnum
8
- from typing import Tuple
9
- from typing import Union
10
-
11
- import numpy as np
12
-
13
- from egse.bits import clear_bit
14
- from egse.bits import crc_calc
15
- from egse.bits import set_bit
16
- from egse.exceptions import Error
17
- from egse.setup import SetupError
18
- from egse.state import GlobalState
19
-
20
- MODULE_LOGGER = logging.getLogger(__name__)
21
-
22
- try:
23
- _ = os.environ["PLATO_CAMERA_IS_EM"]
24
- TWOS_COMPLEMENT_OFFSET = 32768 if _.capitalize() in ("1", "True", "Yes") else 0
25
- except KeyError:
26
- TWOS_COMPLEMENT_OFFSET = 0
27
-
28
- # RMAP Error Codes and Constants -------------------------------------------------------------------
29
-
30
- RMAP_PROTOCOL_ID = 0x01
31
- RMAP_TARGET_LOGICAL_ADDRESS_DEFAULT = 0xFE
32
- RMAP_TARGET_KEY = 0xD1
33
-
34
- # Error and Status Codes
35
-
36
- RMAP_SUCCESS = 0
37
- RMAP_GENERAL_ERROR = 1
38
- RMAP_UNUSED_PACKET_TYPE_COMMAND_CODE = 2
39
- RMAP_INVALID_KEY = 3
40
- RMAP_INVALID_DATA_CRC = 4
41
- RMAP_EARLY_EOP = 5
42
- RMAP_TOO_MUCH_DATA = 6
43
- RMAP_EEP = 7
44
- RMAP_RESERVED = 8
45
- RMAP_VERIFY_BUFFER_OVERRUN = 9
46
- RMAP_NOT_IMPLEMENTED_AUTHORISED = 10
47
- RMAP_RMW_DATA_LENGTH_ERROR = 11
48
- RMAP_INVALID_TARGET_LOGICAL_ADDRESS = 12
49
-
50
- # Memory Map layout --------------------------------------------------------------------------------
51
-
52
- # NOTE: These memory areas are currently equal for N-FEE and F-FEE. Don't know if this will
53
- # change in the future.
54
-
55
- CRITICAL_AREA_START = 0x0000_0000
56
- CRITICAL_AREA_END = 0x0000_00FC
57
- GENERAL_AREA_START = 0x0000_0100
58
- GENERAL_AREA_END = 0x0000_06FC
59
- HK_AREA_START = 0x0000_0700
60
- HK_AREA_END = 0x0000_07FC
61
- WINDOWING_AREA_START = 0x0080_0000
62
- WINDOWING_AREA_END = 0x00FF_FFFC
63
-
64
- class RMAPError(Error):
65
- """An RMAP specific Error."""
66
- pass
67
-
68
-
69
- class CheckError(RMAPError):
70
- """
71
- Raised when a check fails and you want to pass a status values along with the message.
72
- """
73
-
74
- def __init__(self, message, status):
75
- self.message = message
76
- self.status = status
77
-
78
-
79
- def update_transaction_identifier(tid: int) -> int:
80
- """
81
- Updates the transaction identifier and returns the new value.
82
-
83
- FIXME: document more about this identifier, where is it used, when is it checked,
84
- when does it need to be incremented, who initializes the identifier and
85
- who updates it, ...
86
-
87
- Args:
88
- tid (int): The current transaction identifier
89
-
90
- Returns:
91
- the updated transaction identifier (int).
92
- """
93
- tid = (tid + 1) & 0xFFFF
94
- return tid
95
-
96
-
97
- def create_rmap_read_request_packet(address: int, length: int, tid: int, strict: bool = True) -> bytes:
98
- """
99
- Creates an RMAP Read Request SpaceWire packet.
100
-
101
- The read request is an RMAP command that read a number of bytes from the FEE register memory.
102
-
103
- The function returns a ``ctypes`` character array (which is basically a bytes array) that
104
- can be passed into the EtherSpaceLink library function ``esl_write_packet()``.
105
-
106
- Address shall be within the 0x0000_0000 and 0x00FF_FFFC. The memory map (register) is divided
107
- in the following areas:
108
-
109
- 0x0000_0000 - 0x0000_00FC Critical Configuration Area (verified write)
110
- 0x0000_0100 - 0x0000_06FC General Configuration Area (unverified write)
111
- 0x0000_0700 - 0x0000_07FC Housekeeping area
112
- 0x0000_0800 - 0x007F_FFFC Not Supported
113
- 0x0080_0000 - 0x00FF_FFFC Windowing Area (unverified write)
114
- 0x0010_0000 - 0xFFFF_FFFC Not Supported
115
-
116
- All read requests to the critical area shall have a fixed data length of 4 bytes.
117
- All read requests to a general area shall have a maximum data length of 256 bytes.
118
- All read requests to the housekeeping area shall have a maximum data length of 256 bytes.
119
- All read requests to the windowing area shall have a maximum data length of 4096 bytes.
120
-
121
- The transaction identifier shall be incremented for each read request. This shall be done by
122
- the calling function!
123
-
124
- Args:
125
- address (int): the FEE register memory address
126
- length (int): the data length
127
- tid (int): transaction identifier
128
- strict (bool): perform strict checking of address and length
129
-
130
- Returns:
131
- a bytes object containing the full RMAP Read Request packet.
132
- """
133
-
134
- check_address_and_data_length(address, length, strict=strict)
135
-
136
- buf = bytearray(16)
137
-
138
- # NOTE: The first bytes would each carry the target SpW address or a destination port,
139
- # but this is not used for point-to-point connections, so we're safe.
140
-
141
- buf[0] = 0x51 # Target N-FEE or F-FEE
142
- buf[1] = 0x01 # RMAP Protocol ID
143
- buf[2] = 0x4C # Instruction: 0b1001100, RMAP Request, Read, Incrementing address, reply address
144
- buf[3] = 0xD1 # Destination Key
145
- buf[4] = 0x50 # Initiator is always the DPU
146
- buf[5] = (tid >> 8) & 0xFF # MSB of the Transition ID
147
- buf[6] = tid & 0xFF # LSB of the Transition ID
148
- buf[7] = 0x00 # Extended address is not used
149
- buf[8] = (address >> 24) & 0xFF # address (MSB)
150
- buf[9] = (address >> 16) & 0xFF # address
151
- buf[10] = (address >> 8) & 0xFF # address
152
- buf[11] = address & 0xFF # address (LSB)
153
- buf[12] = (length >> 16) & 0xFF # data length (MSB)
154
- buf[13] = (length >> 8) & 0xFF # data length
155
- buf[14] = length & 0xFF # data length (LSB)
156
- buf[15] = rmap_crc_check(buf, 0, 15) & 0xFF
157
- return bytes(buf)
158
-
159
-
160
- def create_rmap_read_request_reply_packet(
161
- instruction_field: int, tid: int, status: int, buffer: bytes, buffer_length: int) -> bytes:
162
- """
163
- Creates an RMAP Reply to a RMAP Read Request packet.
164
-
165
- The function returns a ``ctypes`` character array (which is basically a bytes array) that
166
- can be passed into the EtherSpaceLink library function ``esl_write_packet()``.
167
-
168
- Args:
169
- instruction_field (int): the instruction field of the RMAP read request packet
170
- tid (int): the transaction identifier of the read request packet
171
- status (int): the status field, 0 on success
172
- buffer (bytes): the data that was read as indicated by the read request
173
- buffer_length (int): the data length
174
-
175
- Returns:
176
- packet: a bytes object containing the full RMAP Reply packet.
177
- """
178
-
179
- buf = bytearray(12 + buffer_length + 1)
180
-
181
- buf[0] = 0x50 # Initiator address N-DPU or F-DPU
182
- buf[1] = 0x01 # RMAP Protocol ID
183
- buf[2] = instruction_field & 0x3F # Clear the command bit as this is a reply
184
- buf[3] = status & 0xFF # Status field: 0 on success
185
- buf[4] = 0x51 # Target address is always the N-FEE or F-FEE
186
- buf[5] = (tid >> 8) & 0xFF # MSB of the Transition ID
187
- buf[6] = tid & 0xFF # LSB of the Transition ID
188
- buf[7] = 0x00 # Reserved
189
- buf[8] = (buffer_length >> 16) & 0xFF # data length (MSB)
190
- buf[9] = (buffer_length >> 8) & 0xFF # data length
191
- buf[10] = buffer_length & 0xFF # data length (LSB)
192
- buf[11] = rmap_crc_check(buf, 0, 11) & 0xFF # Header CRC
193
-
194
- # Note that we assume here that len(buffer) == buffer_length.
195
-
196
- if len(buffer) != buffer_length:
197
- MODULE_LOGGER.warning(
198
- f"While creating an RMAP read reply packet, the length of the buffer ({len(buffer)}) "
199
- f"not equals the buffer_length ({buffer_length})"
200
- )
201
-
202
- for idx, value in enumerate(buffer):
203
- buf[12 + idx] = value
204
-
205
- buf[12 + buffer_length] = rmap_crc_check(buffer, 0, buffer_length) & 0xFF # data CRC
206
-
207
- return bytes(buf)
208
-
209
-
210
- def create_rmap_verified_write_packet(address: int, data: bytes, tid: int) -> bytes:
211
- """
212
- Create an RMAP packet for a verified write request on the FEE. The length of the data is
213
- by convention always 4 bytes and therefore not passed as an argument.
214
-
215
- Args:
216
- address: the start memory address on the FEE register map
217
- data: the data to be written in the register map at address [4 bytes]
218
- tid (int): transaction identifier
219
-
220
- Returns:
221
- packet: a bytes object containing the SpaceWire packet.
222
- """
223
-
224
- if len(data) < 4:
225
- raise ValueError(
226
- f"The data argument should be at least 4 bytes, but it is only {len(data)} bytes: {data=}.")
227
-
228
- if address > CRITICAL_AREA_END:
229
- raise ValueError("The address range for critical configuration is [0x00 - 0xFC].")
230
-
231
- tid = update_transaction_identifier(tid)
232
-
233
- # Buffer length is fixed at 24 bytes since the data length is fixed
234
- # at 4 bytes (32 bit addressing)
235
-
236
- buf = bytearray(21)
237
-
238
- # The values below are taken from the PLATO N-FEE to N-DPU
239
- # Interface Requirements Document [PLATO-DLR-PL-ICD-0010]
240
-
241
- buf[0] = 0x51 # Logical Address
242
- buf[1] = 0x01 # Protocol ID
243
- buf[2] = 0x7C # Instruction
244
- buf[3] = 0xD1 # Key
245
- buf[4] = 0x50 # Initiator Address
246
- buf[5] = (tid >> 8) & 0xFF # MSB of the Transition ID
247
- buf[6] = tid & 0xFF # LSB of the Transition ID
248
- buf[7] = 0x00 # Extended address
249
- buf[8] = (address >> 24) & 0xFF # address (MSB)
250
- buf[9] = (address >> 16) & 0xFF # address
251
- buf[10] = (address >> 8) & 0xFF # address
252
- buf[11] = address & 0xFF # address (LSB)
253
- buf[12] = 0x00 # data length (MSB)
254
- buf[13] = 0x00 # data length
255
- buf[14] = 0x04 # data length (LSB)
256
- buf[15] = rmap_crc_check(buf, 0, 15) & 0xFF # header CRC
257
- buf[16] = data[0]
258
- buf[17] = data[1]
259
- buf[18] = data[2]
260
- buf[19] = data[3]
261
- buf[20] = rmap_crc_check(buf, 16, 4) & 0xFF # data CRC
262
-
263
- return bytes(buf)
264
-
265
-
266
- def create_rmap_unverified_write_packet(address: int, data: bytes, length: int, tid: int) -> bytes:
267
- """
268
- Create an RMAP packet for a unverified write request on the FEE.
269
-
270
- Args:
271
- address: the start memory address on the FEE register map
272
- data: the data to be written in the register map at address
273
- length: the length of the data
274
- tid (int): transaction identifier
275
-
276
- Returns:
277
- packet: a bytes object containing the SpaceWire packet.
278
- """
279
-
280
- # We can only handle data for which the length >= the given length argument.
281
-
282
- if len(data) < length:
283
- raise ValueError(
284
- f"The length of the data argument ({len(data)}) is smaller than "
285
- f"the given length argument ({length})."
286
- )
287
-
288
- if len(data) > length:
289
- MODULE_LOGGER.warning(
290
- f"The length of the data argument ({len(data)}) is larger than "
291
- f"the given length argument ({length}). The data will be truncated "
292
- f"when copied into the packet."
293
- )
294
-
295
- if address <= CRITICAL_AREA_END:
296
- raise ValueError(
297
- f"The given address (0x{address:08X}) is in the range for critical configuration is "
298
- f"[0x00 - 0xFC]. Use the verified write function for this."
299
- )
300
-
301
- tid = update_transaction_identifier(tid)
302
-
303
- # Buffer length is fixed at 24 bytes since the data length
304
- # is fixed at 4 bytes (32 bit addressing)
305
-
306
- buf = bytearray(16 + length + 1)
307
- offset = 0
308
-
309
- buf[offset + 0] = 0x51 # Logical Address
310
- buf[offset + 1] = 0x01 # Protocol ID
311
- buf[offset + 2] = 0x6C # Instruction
312
- buf[offset + 3] = 0xD1 # Key
313
- buf[offset + 4] = 0x50 # Initiator Address
314
- buf[offset + 5] = (tid >> 8) & 0xFF # MSB of the Transition ID
315
- buf[offset + 6] = tid & 0xFF # LSB of the Transition ID
316
- buf[offset + 7] = 0x00 # Extended address
317
- buf[offset + 8] = (address >> 24) & 0xFF # address (MSB)
318
- buf[offset + 9] = (address >> 16) & 0xFF # address
319
- buf[offset + 10] = (address >> 8) & 0xFF # address
320
- buf[offset + 11] = address & 0xFF # address (LSB)
321
- buf[offset + 12] = (length >> 16) & 0xFF # data length (MSB)
322
- buf[offset + 13] = (length >> 8) & 0xFF # data length
323
- buf[offset + 14] = length & 0xFF # data length (LSB)
324
- buf[offset + 15] = rmap_crc_check(buf, 0, 15) & 0xFF # header CRC
325
-
326
- offset += 16
327
-
328
- for idx, value in enumerate(data):
329
- buf[offset + idx] = value
330
-
331
- buf[offset + length] = rmap_crc_check(buf, offset, length) & 0xFF # data CRC
332
-
333
- return bytes(buf)
334
-
335
-
336
- def create_rmap_write_request_reply_packet(instruction_field: int, tid: int, status: int) -> bytes:
337
- buf = bytearray(8)
338
-
339
- buf[0] = 0x50 # Initiator address N-DPU or F-DPU
340
- buf[1] = 0x01 # RMAP Protocol ID
341
- buf[2] = instruction_field & 0x3F # Clear the command bit as this is a reply
342
- buf[3] = status & 0xFF # Status field: 0 on success
343
- buf[4] = 0x51 # Target address is always the N-FEE or F-FEE
344
- buf[5] = (tid >> 8) & 0xFF # MSB of the Transition ID
345
- buf[6] = tid & 0xFF # LSB of the Transition ID
346
- buf[7] = rmap_crc_check(buf, 0, 7) & 0xFF # Header CRC
347
-
348
- return bytes(buf)
349
-
350
-
351
- def check_address_and_data_length(address: int, length: int, strict: bool = True) -> None:
352
- """
353
- Checks the address and length in the range of memory areas used by the FEE.
354
-
355
- The ranges are taken from the PLATO-DLR-PL-ICD-0010 N-FEE to N-DPU IRD.
356
-
357
- Args:
358
- address (int): the memory address of the FEE Register
359
- length (int): the number of bytes requested
360
- strict (bool): strictly apply the rules
361
-
362
- Raises:
363
- RMAPError: when address + length fall outside any specified area.
364
- """
365
-
366
- if not strict:
367
- # All these restrictions have been relaxed on the N-FEE.
368
- # We are returning here immediately instead of removing or commenting out the code.
369
- # These reason is that we can then bring back restriction easier and gradually.
370
-
371
- MODULE_LOGGER.warning(
372
- "Address and data length checks have been disabled, because the N-FEE "
373
- "does not enforce restrictions in the critical memory area.")
374
- return
375
-
376
- if length % 4:
377
- raise RMAPError(
378
- "The requested data length shall be a multiple of 4 bytes.", address, length
379
- )
380
-
381
- if address % 4:
382
- raise RMAPError("The address shall be a multiple of 4 bytes.", address, length)
383
-
384
- # Note that when checking the given data length, at the defined area end,
385
- # we can still read 4 bytes.
386
-
387
- if CRITICAL_AREA_START <= address <= CRITICAL_AREA_END:
388
- if length != 4:
389
- raise RMAPError(
390
- "Read requests to the critical area have a fixed data length of 4 bytes.",
391
- address, length
392
- )
393
- elif GENERAL_AREA_START <= address <= GENERAL_AREA_END:
394
- if length > 256:
395
- raise RMAPError(
396
- "Read requests to the general area have a maximum data length of 256 bytes.",
397
- address, length
398
- )
399
- if address + length > GENERAL_AREA_END + 4:
400
- raise RMAPError(
401
- "The requested data length for the general area is too large. "
402
- "The address + length exceeds the general area boundaries.",
403
- address, length
404
- )
405
-
406
- elif HK_AREA_START <= address <= HK_AREA_END:
407
- if length > 256:
408
- raise RMAPError(
409
- "Read requests to the housekeeping area have a maximum data length of 256 bytes.",
410
- address, length
411
- )
412
- if address + length > HK_AREA_END + 4:
413
- raise RMAPError(
414
- "The requested data length for the housekeeping area is too large. "
415
- "The address + length exceeds the housekeeping area boundaries.",
416
- address, length
417
- )
418
-
419
- elif WINDOWING_AREA_START <= address <= WINDOWING_AREA_END:
420
- if length > 4096:
421
- raise RMAPError(
422
- "Read requests to the windowing area have a maximum data length of 4096 bytes.",
423
- address, length
424
- )
425
- if address + length > WINDOWING_AREA_END + 4:
426
- raise RMAPError(
427
- "The requested data length for the windowing area is too large. "
428
- "The address + length exceeds the windowing area boundaries.", address, length
429
- )
430
-
431
- else:
432
- raise RMAPError("Register address for RMAP read requests is invalid.", address, length)
433
-
434
-
435
- class PacketType(IntEnum):
436
- """Enumeration type that defines the SpaceWire packet type."""
437
-
438
- DATA_PACKET = 0
439
- OVERSCAN_DATA = 1
440
- HOUSEKEEPING_DATA = 2 # N-FEE
441
- DEB_HOUSEKEEPING_DATA = 2 # F-FEE
442
- AEB_HOUSEKEEPING_DATA = 3 # F-FEE
443
-
444
-
445
- class DataPacketType:
446
- """
447
- Defines the Data Packet Field: Type, which is a bit-field of 16 bits.
448
-
449
- Properties:
450
- * value: returns the data type as an integer
451
- * packet_type: the type of data packet, defined in PacketType enum.
452
- * mode: the FEE mode, defined in n_fee_mode and f_fee_mode enum
453
- * last_packet: flag which defines the last packet of a type in the current readout cycle
454
- * ccd_side: 0 for E-side (left), 1 for F-side (right), see egse.fee.fee_side
455
- * ccd_number: CCD number [0, 3]
456
- * frame_number: the frame number after sync
457
- """
458
-
459
- def __init__(self, data_type: int = 0):
460
- self._data_type: int = data_type
461
- # self.n_fee_side = GlobalState.setup.camera.fee.ccd_sides.enum
462
-
463
- @property
464
- def value(self) -> int:
465
- """Returns the data packet type as an int."""
466
- return self._data_type
467
-
468
- @property
469
- def packet_type(self):
470
- """Returns the packet type: 0 = data packet, 1 = overscan data, 2 = housekeeping packet."""
471
- return self._data_type & 0b0011
472
-
473
- @packet_type.setter
474
- def packet_type(self, value):
475
- if not 0 <= value < 3:
476
- raise ValueError(f"Packet Type can only have the value 0, 1, or 2, {value=} given.")
477
- x = self._data_type
478
- for idx, bit in enumerate([0, 1]):
479
- x = set_bit(x, bit) if value & (1 << idx) else clear_bit(x, bit)
480
- self._data_type = x
481
-
482
- @property
483
- def mode(self) -> int:
484
- return (self._data_type & 0b1111_0000_0000) >> 8
485
-
486
- @mode.setter
487
- def mode(self, value: int):
488
- x = self._data_type
489
- for idx, bit in enumerate([8, 9, 10, 11]):
490
- x = set_bit(x, bit) if value & (1 << idx) else clear_bit(x, bit)
491
- self._data_type = x
492
-
493
- @property
494
- def last_packet(self) -> bool:
495
- return bool(self._data_type & 0b1000_0000)
496
-
497
- @last_packet.setter
498
- def last_packet(self, flag: bool):
499
- self._data_type = set_bit(self._data_type, 7) if flag else clear_bit(self._data_type, 7)
500
-
501
- @property
502
- def ccd_side(self) -> int:
503
- return (self._data_type & 0b0100_0000) >> 6
504
-
505
- @ccd_side.setter
506
- def ccd_side(self, value: int):
507
- self._data_type = set_bit(self._data_type, 6) if value & 0b0001 else clear_bit(self._data_type, 6)
508
-
509
- @property
510
- def ccd_number(self) -> int:
511
- return (self._data_type & 0b0011_0000) >> 4
512
-
513
- @ccd_number.setter
514
- def ccd_number(self, value):
515
- x = self._data_type
516
- for idx, bit in enumerate([4, 5]):
517
- x = set_bit(x, bit) if value & (1 << idx) else clear_bit(x, bit)
518
- self._data_type = x
519
-
520
- @property
521
- def frame_number(self) -> int:
522
- return (self._data_type & 0b1100) >> 2
523
-
524
- @frame_number.setter
525
- def frame_number(self, value):
526
- x = self._data_type
527
- for idx, bit in enumerate([2, 3]):
528
- x = set_bit(x, bit) if value & (1 << idx) else clear_bit(x, bit)
529
- self._data_type = x
530
-
531
- def __str__(self) -> str:
532
- from egse.fee import n_fee_mode
533
- n_fee_side = GlobalState.setup.camera.fee.ccd_sides.enum
534
-
535
- return (
536
- f"mode:{n_fee_mode(self.mode).name}, last_packet:{self.last_packet}, "
537
- f"CCD side:{n_fee_side(self.ccd_side).name}, CCD number:{self.ccd_number}, "
538
- f"Frame number:{self.frame_number}, Packet Type:{PacketType(self.packet_type).name}"
539
- )
540
-
541
-
542
- def to_string(data: Union[DataPacketType]) -> str:
543
- """Returns a 'user-oriented' string representation of the SpW DataPacketType.
544
-
545
- The purpose of this function is to represent the N-FEE information in a user-oriented way.
546
- That means for certain values that they will be converted into the form the a user understands
547
- and that may be different or reverse from the original N-FEE definition. An example is the
548
- CCD number which is different from the user perspective with respect to the N-FEE.
549
-
550
- If any other object type is passed, the data.__str__() method will be returned without
551
- processing or conversion.
552
-
553
- Args:
554
- data: a DataPacketType
555
- """
556
- from egse.fee import n_fee_mode
557
- n_fee_side = GlobalState.setup.camera.fee.ccd_sides.enum
558
-
559
- if isinstance(data, DataPacketType):
560
- try:
561
- ccd_bin_to_id = GlobalState.setup.camera.fee.ccd_numbering.CCD_BIN_TO_ID
562
- except AttributeError:
563
- raise SetupError("No entry in the setup for camera.fee.ccd_numbering.CCD_BIN_TO_ID")
564
- return (
565
- f"mode:{n_fee_mode(data.mode).name}, last_packet:{data.last_packet}, "
566
- f"CCD side:{n_fee_side(data.ccd_side).name}, CCD number:"
567
- f"{ccd_bin_to_id[data.ccd_number]}, "
568
- f"Frame number:{data.frame_number}, Packet Type:{PacketType(data.packet_type).name}"
569
- )
570
- else:
571
- return data.__str__()
572
-
573
-
574
- class DataPacketHeader:
575
- """
576
- Defines the header of a data packet.
577
-
578
- The full header can be retrieved as a bytes object with the `data_as_bytes()` method.
579
-
580
- Properties:
581
- * logical_address: fixed value of 0x50
582
- * protocol_id: fixed value of 0xF0
583
- * length: length of the data part of the packet, i.e. the packet length - size of the header
584
- * type: data packet type as defined by DataPacketType
585
- * frame_counter:
586
- * sequence_counter: a packet sequence counter per CCD
587
- """
588
- def __init__(self, header_data: bytes = None):
589
- self.header_data = bytearray(
590
- header_data or bytes([0x50, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
591
-
592
- if len(self.header_data) != 10:
593
- raise ValueError(f"The length of the header for a data packet shall be 10 bytes, "
594
- f"got {len(self.header_data)}.")
595
-
596
- self.n_fee_side = GlobalState.setup.camera.fee.ccd_sides.enum
597
-
598
- def data_as_bytes(self) -> bytes:
599
- """Returns the full header as a bytes object."""
600
- return bytes(self.header_data)
601
-
602
- @property
603
- def logical_address(self) -> int:
604
- return self.header_data[0]
605
-
606
- @logical_address.setter
607
- def logical_address(self, value: int):
608
- self.header_data[0] = value
609
-
610
- @property
611
- def protocol_id(self) -> int:
612
- return self.header_data[1]
613
-
614
- @protocol_id.setter
615
- def protocol_id(self, value: int):
616
- self.header_data[1] = value
617
-
618
- @property
619
- def length(self) -> int:
620
- return int.from_bytes(self.header_data[2:4], byteorder='big')
621
-
622
- @length.setter
623
- def length(self, value: int):
624
- self.header_data[2:4] = value.to_bytes(2, 'big')
625
-
626
- @property
627
- def type(self):
628
- return int.from_bytes(self.header_data[4:6], byteorder='big')
629
-
630
- @type.setter
631
- def type(self, value: Union[int, bytes, DataPacketType]):
632
- if isinstance(value, bytes):
633
- self.header_data[4:6] = value
634
- elif isinstance(value, DataPacketType):
635
- self.header_data[4:6] = value.value.to_bytes(2, 'big')
636
- else:
637
- self.header_data[4:6] = value.to_bytes(2, 'big')
638
-
639
- @property
640
- def type_as_object(self):
641
- return DataPacketType(self.type)
642
-
643
- @property
644
- def packet_type(self):
645
- return self.type_as_object.packet_type
646
-
647
- @packet_type.setter
648
- def packet_type(self, value: int):
649
- type_obj = self.type_as_object
650
- type_obj.packet_type = value
651
- self.type = type_obj
652
-
653
- @property
654
- def last_packet(self):
655
- return self.type_as_object.last_packet
656
-
657
- @last_packet.setter
658
- def last_packet(self, flag: bool):
659
- type_obj = self.type_as_object
660
- type_obj.last_packet = flag
661
- self.type = type_obj
662
-
663
- @property
664
- def frame_counter(self):
665
- return int.from_bytes(self.header_data[6:8], byteorder='big')
666
-
667
- @frame_counter.setter
668
- def frame_counter(self, value):
669
- self.header_data[6:8] = value.to_bytes(2, 'big')
670
-
671
- @property
672
- def sequence_counter(self):
673
- return int.from_bytes(self.header_data[8:10], byteorder='big')
674
-
675
- @sequence_counter.setter
676
- def sequence_counter(self, value):
677
- self.header_data[8:10] = value.to_bytes(2, 'big')
678
-
679
- def as_dict(self):
680
- from egse.fee import n_fee_mode
681
-
682
- data_packet_type = DataPacketType(self.type)
683
- return dict(
684
- logical_address=f"0x{self.logical_address:02X}",
685
- protocol_id=f"0x{self.protocol_id:02X}",
686
- length=self.length,
687
- type=f"0x{self.type:04X}",
688
- frame_counter=self.frame_counter,
689
- sequence_counter=self.sequence_counter,
690
- packet_type=data_packet_type.packet_type,
691
- frame_number=data_packet_type.frame_number,
692
- ccd_number=data_packet_type.ccd_number,
693
- ccd_side=self.n_fee_side(data_packet_type.ccd_side).name,
694
- last_packet=data_packet_type.last_packet,
695
- mode=n_fee_mode(data_packet_type.mode).name,
696
- )
697
-
698
-
699
- class SpaceWirePacket:
700
- """Base class for any packet transmitted over a SpaceWire cable."""
701
-
702
- # these settings are used by this class and its sub-classes to configure the print options
703
- # for the numpy arrays.
704
-
705
- _threshold = 300 # sys.maxsize
706
- _edgeitems = 10
707
- _linewidth = 120
708
-
709
- def __init__(self, data: Union[bytes, np.ndarray]):
710
- """
711
- Args:
712
- data: a bytes object or a numpy array of type np.uint8 (not enforced)
713
- """
714
- self._bytes = bytes(data)
715
-
716
- def __repr__(self):
717
- options = np.get_printoptions()
718
- np.set_printoptions(
719
- formatter={"int": lambda x: f"0x{x:02x}"},
720
- threshold=self._threshold,
721
- edgeitems=self._edgeitems,
722
- linewidth=self._linewidth,
723
- )
724
- msg = f"{self.__class__.__name__}({self._bytes})"
725
- np.set_printoptions(**options)
726
- return msg
727
-
728
- @property
729
- def packet_as_bytes(self):
730
- return self._bytes
731
-
732
- @property
733
- def packet_as_ndarray(self):
734
- return np.frombuffer(self._bytes, dtype=np.uint8)
735
-
736
- @property
737
- def logical_address(self):
738
- # TODO: what about a timecode, that has no logical address?
739
- return self._bytes[0]
740
-
741
- @property
742
- def protocol_id(self):
743
- # TODO: what about a timecode, that has no protocol id?
744
- return self._bytes[1]
745
-
746
- def header_as_bytes(self) -> bytes:
747
- # TODO: what about timecode, this has no header, except maybe the first byte: 0x91
748
- raise NotImplementedError
749
-
750
- @staticmethod
751
- def create_packet(data: Union[bytes, np.ndarray]):
752
- """
753
- Factory method that returns a SpaceWire packet of the correct type based on the information
754
- in the header.
755
- """
756
- if TimecodePacket.is_timecode_packet(data):
757
- return TimecodePacket(data)
758
- if HousekeepingPacket.is_housekeeping_packet(data):
759
- return HousekeepingPacket(data)
760
- if DataDataPacket.is_data_data_packet(data):
761
- return DataDataPacket(data)
762
- if OverscanDataPacket.is_overscan_data_packet(data):
763
- return OverscanDataPacket(data)
764
- if WriteRequest.is_write_request(data):
765
- return WriteRequest(data)
766
- if WriteRequestReply.is_write_reply(data):
767
- return WriteRequestReply(data)
768
- if ReadRequest.is_read_request(data):
769
- return ReadRequest(data)
770
- if ReadRequestReply.is_read_reply(data):
771
- return ReadRequestReply(data)
772
- return SpaceWirePacket(data)
773
-
774
-
775
- class DataPacket(SpaceWirePacket):
776
- """
777
- Base class for proprietary SpaceWire data packets that are exchanged between FEE and DPU.
778
-
779
- .. note::
780
- This class should not be instantiated directly. Use the SpaceWirePacket.create_packet()
781
- factory method or the constructors of one of the sub-classes of this DataPacket class.
782
- """
783
-
784
- DATA_HEADER_LENGTH = 10
785
-
786
- def __init__(self, data: Union[bytes, np.ndarray]):
787
- """
788
- Args:
789
- data: a bytes object or a numpy array
790
- """
791
- if not self.is_data_packet(data):
792
- raise ValueError(
793
- f"Can not create a DataPacket from the given data {[f'0x{x:02x}' for x in data]}"
794
- )
795
-
796
- super().__init__(data)
797
-
798
- if (data[2] == 0x00 and data[3] == 0x00) or len(data) == self.DATA_HEADER_LENGTH:
799
- MODULE_LOGGER.warning(
800
- f"SpaceWire data packet without data found, packet={[f'0x{x:02x}' for x in data]}"
801
- )
802
-
803
- self._length = (data[2] << 8) + data[3]
804
-
805
- if len(data) != self._length + self.DATA_HEADER_LENGTH:
806
- MODULE_LOGGER.warning(
807
- f"The length of the data argument ({len(data)}) given to "
808
- f"the constructor of {self.__class__.__name__} (or sub-classes) is inconsistent "
809
- f"with the length data field ({self._length} + 10) in the packet header."
810
- )
811
- raise ValueError(
812
- f"{self.__class__.__name__} header: data-length field ({self._length}) not "
813
- f"consistent with packet length ({len(data)}). Difference should be "
814
- f"{self.DATA_HEADER_LENGTH}."
815
- )
816
-
817
- self._type = DataPacketType((data[4] << 8) + data[5])
818
- self._data = None # lazy loading of data from self._bytes
819
-
820
- @property
821
- def length(self) -> int:
822
- """Returns the data length in bytes.
823
-
824
- .. note:: length == len(data_nd_array) * 2
825
- This length property returns the length of the data area in bytes. This value is
826
- taken from the header of the data packet. If you want to compare this with the size
827
- of the data_as_ndarray property, multiply the length by 2 because the data is 16-bit
828
- integers, not bytes.
829
-
830
- Returns:
831
- the size of the data area of the packet in bytes.
832
- """
833
- return self._length
834
-
835
- @property
836
- def data_as_ndarray(self):
837
- """
838
- Returns the data from this data packet as a 16-bit integer Numpy array.
839
-
840
- .. note::
841
- The data has been converted from the 8-bit packet data into 16-bit integers. That
842
- means the length of this data array will be half the length of the data field the
843
- packet, i.e. ``len(data) == length // 2``.
844
- The reason for this is that pixel data has a size of 16-bit.
845
-
846
- .. todo::
847
- check if the data-length of HK packets should also be a multiple of 16.
848
-
849
- Returns:
850
- data: Numpy array with the data from this packet (type is np.uint16)
851
-
852
- """
853
-
854
- # We decided to lazy load/construct the data array. The reason is that the packet may be
855
- # created / transferred without the need to unpack the data field into a 16-bit numpy array.
856
-
857
- if self._data is None:
858
- # The data is in two's-complement. The most significant bit (msb) shall be inverted
859
- # according to Sampie Smit. That is done in the following line where the msb in each
860
- # byte on an even index is inverted.
861
-
862
- # data = [toggle_bit(b, 7) if not idx % 2 else b for idx, b in enumerate(self._bytes)]
863
- # data = bytearray(data)
864
- # data_1 = np.frombuffer(data, offset=10, dtype='>u2')
865
-
866
- # Needs further confirmation, but the following line should have the same effect as
867
- # the previous three lines.
868
- data_2 = np.frombuffer(self._bytes, offset=10, dtype='>i2') + TWOS_COMPLEMENT_OFFSET
869
-
870
- # Test if the results are identical, left the code in until we are fully confident
871
- # if diff := np.sum(np.cumsum(data_1 - data_2)):
872
- # MODULE_LOGGER.info(f"cumsum={diff}")
873
-
874
- self._data = data_2.astype('uint16')
875
- return self._data
876
-
877
- @property
878
- def data(self) -> bytes:
879
- return self._bytes[10: 10 + self._length]
880
-
881
- @property
882
- def type(self) -> DataPacketType:
883
- return self._type
884
-
885
- @property
886
- def frame_counter(self):
887
- return (self._bytes[6] << 8) + self._bytes[7]
888
-
889
- @property
890
- def sequence_counter(self):
891
- return (self._bytes[8] << 8) + self._bytes[9]
892
-
893
- @property
894
- def header(self) -> DataPacketHeader:
895
- return DataPacketHeader(self.header_as_bytes())
896
-
897
- def header_as_bytes(self):
898
- return self._bytes[:10]
899
-
900
- @classmethod
901
- def is_data_packet(cls, data: np.ndarray) -> bool:
902
- if len(data) < 10 or data[0] != 0x50 or data[1] != 0xF0:
903
- return False
904
- return True
905
-
906
- def __str__(self):
907
- options = np.get_printoptions()
908
- np.set_printoptions(
909
- formatter={"int": lambda x: f"0x{x:04x}"},
910
- threshold=super()._threshold,
911
- edgeitems=super()._edgeitems,
912
- linewidth=super()._linewidth,
913
- )
914
- msg = (
915
- f"{self.__class__.__name__}:\n"
916
- f" Logical Address = 0x{self.logical_address:02X}\n"
917
- f" Protocol ID = 0x{self.protocol_id:02X}\n"
918
- f" Length = {self.length}\n"
919
- f" Type = {self._type}\n"
920
- f" Frame Counter = {self.frame_counter}\n"
921
- f" Sequence Counter = {self.sequence_counter}\n"
922
- f" Data = \n{self.data}"
923
- )
924
- np.set_printoptions(**options)
925
- return msg
926
-
927
-
928
- class DataDataPacket(DataPacket):
929
- """Proprietary Data Packet for N-FEE and F-FEE CCD image data."""
930
-
931
- @classmethod
932
- def is_data_data_packet(cls, data: Union[bytes, np.ndarray]) -> bool:
933
- if len(data) <= 10:
934
- return False
935
- if data[0] != 0x50:
936
- return False
937
- if data[1] != 0xF0:
938
- return False
939
- type_ = DataPacketType((data[4] << 8) + data[5])
940
- if type_.packet_type == PacketType.DATA_PACKET:
941
- return True
942
- return False
943
-
944
-
945
- class OverscanDataPacket(DataPacket):
946
- """Proprietary Overscan Data Packet for N-FEE and F-FEE CCD image data."""
947
-
948
- @classmethod
949
- def is_overscan_data_packet(cls, data: Union[bytes, np.ndarray]) -> bool:
950
- if len(data) <= 10:
951
- return False
952
- if data[0] != 0x50:
953
- return False
954
- if data[1] != 0xF0:
955
- return False
956
- type_ = DataPacketType((data[4] << 8) + data[5])
957
- if type_.packet_type == PacketType.OVERSCAN_DATA:
958
- return True
959
- return False
960
-
961
-
962
- class HousekeepingPacket(DataPacket):
963
- """Proprietary Housekeeping data packet for the N-FEE and F-FEE."""
964
-
965
- def __init__(self, data: Union[bytes, np.ndarray]):
966
- """
967
- Args:
968
- data: a numpy array of type np.uint8 (not enforced)
969
- """
970
- if not self.is_housekeeping_packet(data):
971
- raise ValueError(f"Can not create a HousekeepingPacket from the given data {data}")
972
-
973
- # The __init__ method of DataPacket already checks e.g. data-length against packet length,
974
- # so there is no need for these tests here.
975
-
976
- super().__init__(data)
977
-
978
- @classmethod
979
- def is_housekeeping_packet(cls, data: Union[bytes, np.ndarray]) -> bool:
980
- if len(data) <= 10:
981
- return False
982
- if data[0] != 0x50:
983
- return False
984
- if data[1] != 0xF0:
985
- return False
986
- type_ = DataPacketType((data[4] << 8) + data[5])
987
- if type_.packet_type == PacketType.HOUSEKEEPING_DATA:
988
- return True
989
- return False
990
-
991
-
992
- class TimecodePacket(SpaceWirePacket):
993
- """A Timecode Packet.
994
-
995
- This packet really is an extended packet which is generated by the Diagnostic SpaceWire
996
- Interface (DSI) to forward a SpaceWire timecode over the Ethernet connection.
997
- """
998
-
999
- def __init__(self, data: Union[bytes, np.ndarray]):
1000
- super().__init__(data)
1001
-
1002
- @property
1003
- def timecode(self) -> int:
1004
- return self._bytes[1] & 0x3F
1005
-
1006
- def header_as_bytes(self) -> bytes:
1007
- return self._bytes[0:1]
1008
-
1009
- @classmethod
1010
- def is_timecode_packet(cls, data: Union[bytes, np.ndarray]) -> bool:
1011
- return data[0] == 0x91
1012
-
1013
- def __str__(self):
1014
- return f"Timecode Packet: timecode = 0x{self.timecode:x}"
1015
-
1016
-
1017
- class RMAPPacket(SpaceWirePacket):
1018
- """Base class for RMAP SpaceWire packets."""
1019
-
1020
- def __init__(self, data: Union[bytes, np.ndarray]):
1021
- if not self.is_rmap_packet(data):
1022
- raise ValueError(f"Can not create a RMAPPacket from the given data {data}")
1023
- super().__init__(data)
1024
-
1025
- def __str__(self):
1026
- return (
1027
- f"{self.__class__.__name__}:\n"
1028
- f" Logical Address = 0x{self.logical_address:02X}\n"
1029
- f" Data = {self.data}\n"
1030
- )
1031
-
1032
- @property
1033
- def instruction(self):
1034
- return get_instruction_field(self._bytes)
1035
-
1036
- @property
1037
- def transaction_id(self):
1038
- return get_transaction_identifier(self._bytes)
1039
-
1040
- @classmethod
1041
- def is_rmap_packet(cls, data: Union[bytes, np.ndarray]):
1042
- if data[1] == 0x01: # Protocol ID
1043
- return True
1044
- return False
1045
-
1046
-
1047
- class WriteRequest(RMAPPacket):
1048
- """A Write Request SpaceWire RMAP Packet."""
1049
-
1050
- def __init__(self, data: Union[bytes, np.ndarray]):
1051
- super().__init__(data)
1052
-
1053
- def is_verified(self):
1054
- return self._bytes[2] == 0x7C
1055
-
1056
- def is_unverified(self):
1057
- return self._bytes[2] == 0x6C
1058
-
1059
- @property
1060
- def address(self):
1061
- return get_address(self._bytes)
1062
-
1063
- @property
1064
- def data_length(self):
1065
- return get_data_length(self._bytes)
1066
-
1067
- @property
1068
- def data(self) -> bytes:
1069
- return get_data(self._bytes)
1070
-
1071
- @classmethod
1072
- def is_write_request(cls, data: Union[bytes, np.ndarray]):
1073
- if not RMAPPacket.is_rmap_packet(data):
1074
- return False
1075
- if data[0] != 0x51:
1076
- return False
1077
- if (data[2] == 0x7C or data[2] == 0x6C) and data[3] == 0xD1:
1078
- return True
1079
- return False
1080
-
1081
- def __str__(self):
1082
- prefix = "Verified" if self.is_verified() else "Unverified"
1083
- return f"{prefix} Write Request: {self.transaction_id=}, data=0x{self.data.hex()}"
1084
-
1085
-
1086
- class WriteRequestReply(RMAPPacket):
1087
- """An RMAP Reply packet to a Write Request."""
1088
-
1089
- def __init__(self, data: Union[bytes, np.ndarray]):
1090
- super().__init__(data)
1091
- self._status = data[3]
1092
-
1093
- @classmethod
1094
- def is_write_reply(cls, data: Union[bytes, np.ndarray]):
1095
- if not RMAPPacket.is_rmap_packet(data):
1096
- return False
1097
- if data[0] != 0x50:
1098
- return False
1099
- if (data[2] == 0x3C or data[2] == 0x2C) and data[4] == 0x51:
1100
- return True
1101
-
1102
- @property
1103
- def status(self):
1104
- return self._status
1105
-
1106
- def __str__(self):
1107
- return f"Write Request Reply: status={self.status}"
1108
-
1109
-
1110
- class ReadRequest(RMAPPacket):
1111
- """A Read Request SpaceWire RMAP Packet."""
1112
-
1113
- def __init__(self, data: Union[bytes, np.ndarray]):
1114
- super().__init__(data)
1115
-
1116
- @classmethod
1117
- def is_read_request(cls, data: Union[bytes, np.ndarray]):
1118
- if not RMAPPacket.is_rmap_packet(data):
1119
- return False
1120
- if data[0] != 0x51:
1121
- return False
1122
- if data[2] == 0x4C and data[3] == 0xD1:
1123
- return True
1124
- return False
1125
-
1126
- @property
1127
- def address(self):
1128
- return get_address(self._bytes)
1129
-
1130
- @property
1131
- def data_length(self):
1132
- return get_data_length(self._bytes)
1133
-
1134
- def __str__(self):
1135
- return (
1136
- f"Read Request: tid={self.transaction_id}, address=0x{self.address:04x}, "
1137
- f"data length={self.data_length}"
1138
- )
1139
-
1140
-
1141
- class ReadRequestReply(RMAPPacket):
1142
- """An RMAP Reply packet to a Read Request."""
1143
-
1144
- def __init__(self, data: Union[bytes, np.ndarray]):
1145
- super().__init__(data)
1146
-
1147
- @classmethod
1148
- def is_read_reply(cls, data: Union[bytes, np.ndarray]):
1149
- if not RMAPPacket.is_rmap_packet(data):
1150
- return False
1151
- if data[0] != 0x50:
1152
- return False
1153
- if data[2] == 0x0C and data[4] == 0x51:
1154
- return True
1155
-
1156
- @property
1157
- def data(self) -> bytes:
1158
- return get_data(self._bytes)
1159
-
1160
- @property
1161
- def data_length(self):
1162
- return get_data_length(self._bytes)
1163
-
1164
- def __str__(self):
1165
- data_length = self.data_length
1166
- return f"Read Request Reply: data length={data_length}, data={self.data[:20]} " \
1167
- f"{'(data is cut to max 20 bytes)' if data_length > 20 else ''}\n"
1168
-
1169
-
1170
- class SpaceWireInterface:
1171
- """
1172
- This interface defines methods that are used by the DPU to communicate with the FEE over
1173
- SpaceWire.
1174
- """
1175
-
1176
- def __enter__(self):
1177
- self.connect()
1178
-
1179
- def __exit__(self, exc_type, exc_val, exc_tb):
1180
- self.disconnect()
1181
-
1182
- def connect(self):
1183
- raise NotImplementedError
1184
-
1185
- def disconnect(self):
1186
- raise NotImplementedError
1187
-
1188
- def configure(self):
1189
- raise NotImplementedError
1190
-
1191
- def flush(self):
1192
- raise NotImplementedError
1193
-
1194
- def send_timecode(self, timecode: int):
1195
- raise NotImplementedError
1196
-
1197
- def read_packet(self, timeout: int = None) -> Tuple[int, bytes]:
1198
- """
1199
- Read a full packet from the SpaceWire transport layer.
1200
-
1201
- Args:
1202
- timeout (int): timeout in milliseconds [default=None]
1203
- Returns:
1204
- A tuple with the terminator value and a bytes object containing the packet.
1205
- """
1206
- raise NotImplementedError
1207
-
1208
- def write_packet(self, packet: bytes):
1209
- """
1210
- Write a full packet to the SpaceWire transport layer.
1211
-
1212
- Args:
1213
- packet (bytes): a bytes object containing the SpaceWire packet
1214
-
1215
- Returns:
1216
- None.
1217
- """
1218
- raise NotImplementedError
1219
-
1220
- def read_register(self, address: int, length: int = 4, strict: bool = True) -> bytes:
1221
- """
1222
- Reads the data for the given register from the FEE memory map.
1223
-
1224
- This function sends an RMAP read request for the register to the FEE.
1225
-
1226
- Args:
1227
- address: the start address (32-bit aligned) in the remote memory
1228
- length: the number of bytes to read from the remote memory [default = 4]
1229
- strict: perform strict checking of address and length
1230
-
1231
- Returns:
1232
- data: the 32-bit data that was read from the FEE.
1233
- """
1234
- raise NotImplementedError
1235
-
1236
- def write_register(self, address: int, data: bytes):
1237
- """
1238
- Writes the data from the given register to the N-FEE memory map.
1239
-
1240
- The function reads the data for the registry from the local register map
1241
- and then sends an RMAP write request for the register to the N-FEE.
1242
-
1243
- .. note:: it is assumed that the local register map is up-to-date.
1244
-
1245
- Args:
1246
- address: the start address (32-bit aligned) in the remote memory
1247
- data: the data that will be written into the remote memory
1248
-
1249
- Raises:
1250
- RMAPError: when data can not be written on the target, i.e. the N-FEE.
1251
- """
1252
-
1253
- raise NotImplementedError
1254
-
1255
- def read_memory_map(self, address: int, size: int):
1256
- """
1257
- Read (part of) the memory map from the N-FEE.
1258
-
1259
- Args:
1260
- address: start address
1261
- size: number of bytes to read
1262
-
1263
- Returns:
1264
- a bytes object containing the requested memory map.
1265
- """
1266
-
1267
- raise NotImplementedError
1268
-
1269
-
1270
- # General RMAP helper functions ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1271
-
1272
- def rmap_crc_check(data, start, length) -> int:
1273
- """Calculate the checksum for the given data."""
1274
- return crc_calc(data, start, length)
1275
-
1276
-
1277
- def get_protocol_id(data: bytes) -> int:
1278
- """
1279
- Returns the protocol identifier field. The protocol ID is 1 (0x01) for the RMAP protocol.
1280
- """
1281
- return data[1]
1282
-
1283
-
1284
- def get_reply_address_field_length(rx_buffer) -> int:
1285
- """Returns the size of reply address field.
1286
-
1287
- This function returns the actual size of the reply address field. It doesn't return
1288
- the content of the reply address length field. If you need that information, use the
1289
- reply_address_length() function that work on the instruction field.
1290
-
1291
- Returns:
1292
- length: the size of the reply address field.
1293
- """
1294
- instruction = get_instruction_field(rx_buffer)
1295
- return reply_address_length(instruction) * 4
1296
-
1297
-
1298
- def get_data(rxbuf) -> bytes:
1299
- """
1300
- Return the data from the RMAP packet.
1301
-
1302
- Raises:
1303
- ValueError: if there is no data section in the packet (TODO: not yet implemented)
1304
- """
1305
- instruction_field = get_instruction_field(rxbuf)
1306
- address_length = get_reply_address_field_length(rxbuf)
1307
- data_length = get_data_length(rxbuf)
1308
-
1309
- offset = 12 if is_read(instruction_field) else 16
1310
-
1311
- return rxbuf[offset + address_length:offset + address_length + data_length]
1312
-
1313
-
1314
- def check_data_crc(rxbuf):
1315
- instruction_field = get_instruction_field(rxbuf)
1316
- address_length = get_reply_address_field_length(rxbuf)
1317
- data_length = get_data_length(rxbuf)
1318
-
1319
- offset = 12 if is_read(instruction_field) else 16
1320
- idx = offset + address_length
1321
-
1322
- d_crc = rxbuf[idx + data_length]
1323
- c_crc = rmap_crc_check(rxbuf, idx, data_length) & 0xFF
1324
- if d_crc != c_crc:
1325
- raise CheckError(
1326
- f"Data CRC doesn't match calculated CRC, d_crc=0x{d_crc:02X} & c_crc=0x{c_crc:02X}",
1327
- RMAP_GENERAL_ERROR
1328
- )
1329
-
1330
-
1331
- def check_header_crc(rxbuf):
1332
- instruction_field = get_instruction_field(rxbuf)
1333
- if is_command(instruction_field):
1334
- offset = 15
1335
- elif is_write(instruction_field):
1336
- offset = 7
1337
- else:
1338
- offset = 11
1339
-
1340
- idx = offset + get_reply_address_field_length(rxbuf)
1341
- h_crc = rxbuf[idx]
1342
- c_crc = rmap_crc_check(rxbuf, 0, idx)
1343
- if h_crc != c_crc:
1344
- raise CheckError(
1345
- f"Header CRC doesn't match calculated CRC, h_crc=0x{h_crc:02X} & c_crc=0x{c_crc:02X}",
1346
- RMAP_GENERAL_ERROR
1347
- )
1348
-
1349
-
1350
- def get_data_length(rxbuf) -> int:
1351
- """
1352
- Returns the length of the data in bytes.
1353
-
1354
- Raises:
1355
- TypeError: when this method is used on a Write Request Reply packet (which has no
1356
- data length).
1357
- """
1358
- instruction_field = get_instruction_field(rxbuf)
1359
-
1360
- if not is_command(instruction_field) and is_write(instruction_field):
1361
- raise TypeError("There is no data length field for Write Request Reply packets, "
1362
- "asking for the data length is an invalid operation.")
1363
-
1364
- offset = 12 if is_command(instruction_field) else 8
1365
- idx = offset + get_reply_address_field_length(rxbuf)
1366
-
1367
- # We could use two alternative decoding methods here:
1368
- # int.from_bytes(rxbuf[idx:idx+3], byteorder='big') (timeit=1.166s)
1369
- # struct.unpack('>L', b'\x00' + rxbuf[idx:idx+3])[0] (timeit=0.670s)
1370
- data_length = struct.unpack('>L', b'\x00' + rxbuf[idx:idx + 3])[0]
1371
- return data_length
1372
-
1373
-
1374
- def get_address(rxbuf) -> int:
1375
- """
1376
- Returns the address field (including the extended address field if the address is 40-bits).
1377
-
1378
- Raises:
1379
- TypeError: when this method is used on a Reply packet (which has no address field).
1380
- """
1381
- instruction_field = get_instruction_field(rxbuf)
1382
-
1383
- if not is_command(instruction_field):
1384
- raise TypeError("There is no address field for Reply packets, asking for the address is "
1385
- "an invalid operation.")
1386
-
1387
- idx = 7 + get_reply_address_field_length(rxbuf)
1388
- extended_address = rxbuf[idx]
1389
- idx += 1
1390
- address = struct.unpack('>L', rxbuf[idx:idx + 4])[0]
1391
- if extended_address:
1392
- address = address + (extended_address << 32)
1393
- return address
1394
-
1395
-
1396
- def get_instruction_field(rxbuf):
1397
- idx = 2
1398
- return rxbuf[idx]
1399
-
1400
-
1401
- def get_transaction_identifier(rxbuf):
1402
- idx = 5 + get_reply_address_field_length(rxbuf)
1403
- tid = struct.unpack('>h', rxbuf[idx:idx + 2])[0]
1404
- return tid
1405
-
1406
-
1407
- # Functions to interpret the Instrument Field
1408
-
1409
- def is_reserved(instruction):
1410
- """The reserved bit of the 2-bit packet type field from the instruction field.
1411
-
1412
- For PLATO this bit shall be zero as the 0b10 and 0b11 packet field values are reserved.
1413
-
1414
- Returns:
1415
- bit value: 1 or 0.
1416
- """
1417
- return (instruction & 0b10000000) >> 7
1418
-
1419
-
1420
- def is_command(instruction):
1421
- """Returns True if the RMAP packet is a command packet."""
1422
- return (instruction & 0b01000000) >> 6
1423
-
1424
-
1425
- def is_reply(instruction):
1426
- """Returns True if the RMAP packet is a reply to a previous command packet."""
1427
- return not is_command(instruction)
1428
-
1429
-
1430
- def is_write(instruction):
1431
- """Returns True if the RMAP packet is a write request command packet."""
1432
- return (instruction & 0b00100000) >> 5
1433
-
1434
-
1435
- def is_read(instruction):
1436
- """Returns True if the RMAP packet is a read request command packet."""
1437
- return not is_write(instruction)
1438
-
1439
-
1440
- def is_verify(instruction):
1441
- """Returns True if the RMAP packet needs to do a verify before write."""
1442
- return (instruction & 0b00010000) >> 4
1443
-
1444
-
1445
- def is_reply_required(instruction):
1446
- """Returns True if the reply bit is set in the instruction field.
1447
-
1448
- Args:
1449
- instruction (int): the instruction field of an RMAP packet
1450
-
1451
- .. note:: the name of this function might be confusing.
1452
-
1453
- This function does **not** test if the packet is a reply packet, but it checks
1454
- if the command requests a reply from the target. If you need to test if the
1455
- packet is a command or a reply, use the is_command() or is_reply() function.
1456
-
1457
- """
1458
- return (instruction & 0b00001000) >> 3
1459
-
1460
-
1461
- def is_increment(instruction):
1462
- """Returns True if the data is written to sequential memory addresses."""
1463
- return (instruction & 0b00000100) >> 2
1464
-
1465
-
1466
- def reply_address_length(instruction):
1467
- """Returns the content of the reply address length field.
1468
-
1469
- The size of the reply address field is then decoded from the following table:
1470
-
1471
- Address Field Length | Size of Address Field
1472
- ----------------------+-----------------------
1473
- 0b00 | 0 bytes
1474
- 0b01 | 4 bytes
1475
- 0b10 | 8 bytes
1476
- 0b11 | 12 bytes
1477
-
1478
- """
1479
- return (instruction & 0b00000011) << 2