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