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
@@ -1,2081 +0,0 @@
1
- import importlib
2
- import logging
3
- import multiprocessing
4
- import pickle
5
- import threading
6
- from enum import Enum
7
- from pathlib import Path
8
-
9
- import sys
10
- import time
11
- import zmq
12
- from PyQt5.QtCore import QObject, QLockFile
13
- from PyQt5.QtCore import QThread
14
- from PyQt5.QtCore import Qt
15
- from PyQt5.QtCore import pyqtSignal
16
- from PyQt5.QtCore import pyqtSlot
17
- from PyQt5.QtGui import QCloseEvent, QIcon
18
- from PyQt5.QtWidgets import QApplication, QScrollArea, QAction, QWidget, QSizePolicy, QMessageBox
19
- from PyQt5.QtWidgets import QFrame
20
- from PyQt5.QtWidgets import QGridLayout
21
- from PyQt5.QtWidgets import QGroupBox
22
- from PyQt5.QtWidgets import QHBoxLayout
23
- from PyQt5.QtWidgets import QLabel
24
- from PyQt5.QtWidgets import QMainWindow
25
- from PyQt5.QtWidgets import QVBoxLayout
26
- from prometheus_client import start_http_server
27
-
28
- from egse.confman import ConfigurationManagerProxy
29
- from egse.confman import is_configuration_manager_active
30
- from egse.control import is_control_server_active, Response, Failure
31
- from egse.device import DeviceInterface
32
- from egse.gui import show_info_message
33
- from egse.gui.buttons import ToggleButton, TouchButton
34
- from egse.gui.led import Indic
35
- from egse.gui.led import LED
36
- from egse.obsid import ObservationIdentifier
37
- from egse.process import ProcessStatus
38
- from egse.process import SubProcess
39
- from egse.procman import ProcessManagerProxy
40
- from egse.resource import get_resource
41
- from egse.settings import Settings
42
- from egse.setup import Setup
43
- from egse.system import do_every
44
- from egse.system import find_class
45
- from egse.zmq_ser import connect_address
46
- from egse.zmq_ser import set_address_port
47
-
48
- logging.basicConfig(level=logging.INFO, format=Settings.LOG_FORMAT_FULL)
49
-
50
- GUI_SETTINGS = Settings.load("PM GUI")
51
- LOGGER = logging.getLogger(__name__)
52
- SITE = Settings.load("SITE")
53
-
54
- class FILE_GENERATION_PROCESS_NAMES(str, Enum):
55
-
56
- FITSGEN = "FITS generation"
57
- FOV_HK = "FOV HK"
58
- N_FEE_HK = "N-FEE HK"
59
-
60
-
61
- class ConfigurationMonitoringWorker(QObject):
62
-
63
- # The thread will send a signal with the monitoring information:
64
- # - The obsid;
65
- # - The setup that has been loaded by the configuration manager.
66
-
67
- setup_changed_signal = pyqtSignal(dict)
68
- obsid_changed_signal = pyqtSignal(object) # This allows ObservationIdentifier or None to be returned
69
-
70
- def __init__(self):
71
-
72
- """ Initialisation of a monitoring thread.
73
-
74
- This monitoring thread will listen on the monitoring port of the
75
- Control Server. At this point the socket (that will connect to the
76
- monitoring port) is not created yet.
77
- """
78
-
79
- super(ConfigurationMonitoringWorker, self).__init__()
80
-
81
- self.setup = None # Previous setup
82
- self.obsid = None # Previous obsid
83
- self.active = False
84
-
85
- self.connect_socket()
86
-
87
- def connect_socket(self):
88
- """ Create a socket and connect to the monitoring port.
89
-
90
- Args:
91
- - proxy_type: Proxy type (needed to read the connection details).
92
- """
93
-
94
- # Start listening to the monitoring port
95
-
96
- self.socket = zmq.Context().socket(zmq.SUB)
97
-
98
- cm = ConfigurationManagerProxy()
99
- endpoint = cm.get_endpoint()
100
- monitoring_port = cm.get_monitoring_port()
101
- address = set_address_port(endpoint, monitoring_port)
102
-
103
- self.socket.connect(address)
104
- self.socket.setsockopt_string(zmq.SUBSCRIBE, "")
105
-
106
- def start_process(self):
107
- """ Start listening on the monitoring port.
108
- """
109
-
110
- self.run()
111
-
112
- @pyqtSlot()
113
- def run(self):
114
- """ Keep on listening on the monitoring port.
115
-
116
- If monitoring information is received before the timeout, it is
117
- checked whether the obsid and/or current setup have changed. If so, a
118
- signal with the monitoring information is emitted.
119
- """
120
-
121
- self.active = True
122
-
123
- while self.active:
124
-
125
- pickle_string = self.socket.recv()
126
- monitoring_info = pickle.loads(pickle_string)
127
-
128
- new_setup = monitoring_info["setup"] # New setup
129
-
130
- # The setup has changed
131
-
132
- if new_setup != self.setup:
133
-
134
- self.setup = new_setup
135
-
136
- # Emit the setup ID
137
-
138
- self.setup_changed_signal.emit(self.setup)
139
-
140
- new_obsid = monitoring_info["obsid"] # New obsid
141
-
142
- if new_obsid != self.obsid:
143
-
144
- self.obsid = new_obsid
145
-
146
- # Emit the obsid
147
-
148
- self.obsid_changed_signal.emit(self.obsid)
149
-
150
- def has_setup(self):
151
- """ Check whether a setup has been loaded.
152
-
153
- Returns: True if a setup has been loaded; False otherwise.
154
- """
155
-
156
- return self.setup is not None
157
-
158
-
159
- class MonitoringWorker(QObject):
160
- """ Worker for monitoring the status of an EGSE process."""
161
-
162
- # The worker will send a signal with the following information:
163
- # - process name
164
- # - colour of the led (in the process widget)
165
- # - in case of a running device process: whether or not it is running in simulator mode
166
-
167
- process_status_signal = pyqtSignal(dict)
168
-
169
- def __init__(self, process_name, process_info):
170
- """ Initialisation of a monitoring worker.
171
-
172
- This monitoring worker will listen on the monitoring port of the Control Server.
173
-
174
- Args:
175
- - process_name: Name of the process.
176
- - proxy_type: Proxy type (needed to read the connection details).
177
- """
178
-
179
- super(MonitoringWorker, self).__init__()
180
-
181
- self.active = False
182
- self.start_stop_cs_button_clicked = False
183
-
184
- self.process_name = process_name
185
- self.proxy_type = process_info[0]
186
- self.proxy_type_as_type = find_class(self.proxy_type[7:])
187
- self.device_args = process_info[1]
188
-
189
- self.monitoring_socket = None
190
- self.monitoring_timeout = 0.5 # [s]
191
- self.is_socket_connected = False
192
-
193
- self.commanding_address = None
194
- self.connect_socket()
195
-
196
- self.previous_state = -1
197
-
198
- def connect_socket(self):
199
- """ Create a socket and connect to the monitoring port."""
200
-
201
- try:
202
-
203
- module_name = self.proxy_type[7:].rsplit(".", 1)[0]
204
- module = importlib.import_module(module_name)
205
-
206
- # Ctrl settings:
207
- # - transport protocol
208
- # - hostname
209
- # - commanding port (to check whether the CS is active)
210
- # - monitoring port (to ask for process information)
211
-
212
- ctrl_settings = module.CTRL_SETTINGS
213
-
214
- transport = ctrl_settings.PROTOCOL
215
- hostname = ctrl_settings.HOSTNAME
216
-
217
- if module_name == "egse.aeu.aeu" or "egse.tempcontrol.agilent.agilent3497" in module_name:
218
-
219
- name = self.process_name.split(" ")[1].upper()
220
-
221
- commanding_port = ctrl_settings[name]["COMMANDING_PORT"]
222
- monitoring_port = ctrl_settings[name]["MONITORING_PORT"]
223
-
224
- elif module_name == "egse.powermeter.ni.cdaq9184":
225
- commanding_port = ctrl_settings.CDAQ9184["COMMANDING_PORT"]
226
- monitoring_port = ctrl_settings.CDAQ9184["MONITORING_PORT"]
227
-
228
- elif module_name == "egse.tempcontrol.lakeshore.lsci":
229
- name = "LS_" + self.process_name.split(" ")[2].upper()
230
- commanding_port = ctrl_settings[name]["COMMANDING_PORT"]
231
- monitoring_port = ctrl_settings[name]["MONITORING_PORT"]
232
-
233
- else:
234
- commanding_port = ctrl_settings.COMMANDING_PORT
235
- monitoring_port = ctrl_settings.MONITORING_PORT
236
-
237
- # Create a socket and connect to the monitoring port
238
-
239
- monitoring_address = connect_address(transport, hostname, monitoring_port)
240
- self.monitoring_socket = zmq.Context().socket(zmq.SUB)
241
- self.monitoring_socket.connect(monitoring_address)
242
- self.monitoring_socket.setsockopt_string(zmq.SUBSCRIBE, "")
243
-
244
- # Address of the commanding port
245
- # This is needed when checking whether or not the CS is active
246
-
247
- self.commanding_address = connect_address(transport, hostname, commanding_port)
248
-
249
- self.is_socket_connected = True
250
-
251
- except AttributeError:
252
-
253
- self.is_socket_connected = False
254
-
255
- def stop(self):
256
-
257
- """ Stop the monitoring worker.
258
-
259
- The monitoring socket is disconnected from the monitoring port and is then closed immediately.
260
- """
261
-
262
- self.is_socket_connected = False
263
- self.monitoring_socket.close()
264
-
265
- # self.monitoring_socket.disconnect(self.monitoring_address)
266
- # self.monitoring_socket.close(linger=0)
267
-
268
- def start_process(self):
269
- """ Start listening on the monitoring port.
270
-
271
- If the Control Server is not active when the thread starts listening on the monitoring port, a signal is emitted
272
- to notify the GUI.
273
- """
274
-
275
- if not is_control_server_active(self.commanding_address, 0.5):
276
-
277
- # Emit a signal, indicating the CS is not running
278
-
279
- process_status = {"Name": self.process_name, "Color": Indic.RED}
280
- self.previous_state = Indic.RED
281
-
282
- self.process_status_signal.emit(process_status)
283
-
284
- self.run()
285
-
286
- @pyqtSlot()
287
- def run(self):
288
- """ Keep on listening on the monitoring port.
289
-
290
- If monitoring information is received before the timeout, a signal with the monitoring information is emitted.
291
- Otherwise, it is checked whether or not the Control Server is active. If not, a signal is emitted with the
292
- process name. Otherwise, the timeout for monitoring was too strict (and it will therefore be increased by
293
- 0.5s).
294
- """
295
-
296
- self.active = True
297
-
298
- while self.is_socket_connected and self.active:
299
-
300
- process_status = {"Name": self.process_name}
301
-
302
- try:
303
-
304
- socket_list, _, _ = zmq.select([self.monitoring_socket], [], [], timeout=self.monitoring_timeout)
305
-
306
- # Monitoring information was received (before timeout)
307
-
308
- if self.monitoring_socket in socket_list:
309
-
310
- pickle_string = self.monitoring_socket.recv()
311
- monitoring_info = pickle.loads(pickle_string)
312
-
313
- # Update the timeout, to be more in line with the monitoring
314
- # frequency of the CS (i.e. the delay). Take 0.5s extra to be
315
- # on the safe side.
316
-
317
- self.monitoring_timeout = monitoring_info["delay"] / 1000.0 + 0.5 # [s]
318
-
319
- # Running core CS
320
-
321
- if self.process_name in ["Logger", "Storage", "Configuration Manager", "Process Manager",
322
- "Synoptics Manager"]:
323
- process_status["Color"] = Indic.GREEN
324
-
325
- # Running device CS
326
-
327
- else:
328
- process_status["Color"], process_status["Simulator"] = self.get_device_process_status()
329
-
330
- if not issubclass(self.proxy_type_as_type, DeviceInterface):
331
- process_status.pop("Simulator")
332
-
333
- if self.previous_state != process_status["Color"]:
334
-
335
- self.process_status_signal.emit(process_status)
336
- self.previous_state = process_status["Color"]
337
-
338
- except zmq.ZMQError:
339
- pass
340
-
341
- # Timeout occurred
342
-
343
- else:
344
-
345
- # The CS is not active
346
-
347
- if not is_control_server_active(endpoint=self.commanding_address, timeout=10):
348
-
349
- process_status["Color"] = Indic.RED
350
-
351
- if self.previous_state != process_status["Color"]:
352
-
353
- self.process_status_signal.emit(process_status)
354
- self.previous_state = process_status["Color"]
355
-
356
- elif self.start_stop_cs_button_clicked:
357
-
358
- self.process_status_signal.emit(process_status)
359
- self.previous_state = process_status["Color"]
360
- self.start_stop_cs_button_clicked = False
361
-
362
- # The CS is active, but the timeout was too strict
363
-
364
- else:
365
- self.monitoring_timeout += 0.5
366
-
367
- def get_device_process_status(self):
368
- """ Determine the status of the device Control Server.
369
-
370
- Returns:
371
- - color: Colour of the led light (to use in the process widget).
372
- - is_simulator: Whether or not the Control Server is running in simulator mode.
373
- """
374
-
375
- color = Indic.BLACK
376
- is_simulator = False
377
-
378
- # Core process -> green
379
-
380
- try:
381
-
382
- with find_class(self.proxy_type)(*self.device_args) as process_proxy:
383
-
384
- # CS that are supposed to connect to a H/W unit (controller)
385
-
386
- if isinstance(process_proxy, DeviceInterface):
387
-
388
- try:
389
-
390
- # CS connected to Controller -> green
391
-
392
- if process_proxy.is_connected():
393
- color = Indic.GREEN
394
-
395
- # CS not connected to Controller -> orange
396
-
397
- else:
398
- color = Indic.ORANGE
399
-
400
- except AttributeError:
401
- color = Indic.GREEN
402
-
403
- is_simulator = process_proxy.is_simulator()
404
-
405
- # CS that do not control any device (e.g. FDIR, alert manager, etc.)
406
-
407
- else:
408
- color = Indic.GREEN
409
- is_simulator = False
410
-
411
- except ConnectionError:
412
- pass
413
-
414
- return color, is_simulator
415
-
416
-
417
- class ProcessMonitoringWorker(QObject):
418
- """ Worker for monitoring the status of a process."""
419
-
420
- is_running_signal = pyqtSignal(bool)
421
-
422
- def __init__(self, module):
423
- """ Worker for monitoring the status of a process.
424
-
425
- Args:
426
- - module
427
- """
428
-
429
- super(ProcessMonitoringWorker, self).__init__()
430
-
431
- self.active = False
432
- self.start_stop_cs_button_clicked = False
433
-
434
- self.was_running_before = None
435
-
436
- self.module = importlib.import_module(module)
437
-
438
- def start_process(self):
439
- """ Start listening on the monitoring port.
440
-
441
- If the Control Server is not active when the thread starts listening on the monitoring port, a signal is emitted
442
- to notify the GUI.
443
- """
444
-
445
- self.run()
446
-
447
- @pyqtSlot()
448
- def run(self):
449
- """ Keep on asking for the status of the status of the process.
450
-
451
- Every 5s, ask for the status of the process. If this changes w.r.t. of they way it was before, a signal is
452
- emitted with the current status.
453
- """
454
-
455
- self.active = True
456
- last_time = time.time()
457
-
458
- while self.active:
459
-
460
- if time.time() - last_time >= 5:
461
-
462
- is_running = self.module.send_request("status").get("status") == "ACK"
463
-
464
- if is_running != self.was_running_before:
465
- self.was_running_before = is_running
466
- self.is_running_signal.emit(is_running)
467
-
468
- elif self.start_stop_cs_button_clicked:
469
-
470
- for index in range(15):
471
-
472
- # Check (max 15x) to see whether pressing the button had an effect
473
-
474
- is_running = self.module.send_request("status").get("status") == "ACK"
475
- if self.was_running_before != is_running:
476
- break
477
- time.sleep(2)
478
-
479
- self.was_running_before = is_running
480
- self.start_stop_cs_button_clicked = False
481
- self.is_running_signal.emit(is_running)
482
-
483
- last_time = time.time()
484
-
485
- else:
486
- time.sleep(0.1)
487
-
488
-
489
- class ProcessWidget(QGroupBox):
490
-
491
- def __init__(self, process_name, process_info, parent, include_start_stop_button=True):
492
- """ Initialisation of a process widget.
493
-
494
- For a Control Server with the given process name and Proxy type, a process widget is created. This widget will
495
- comprise the following components:
496
-
497
- - status LED;
498
- - process name;
499
- - button to start the GUI for the Control Server (if this has been
500
- configured in the YAML file with the "UserInterface" entry);
501
- - button to start / shut down the Control Server (for devices only).
502
-
503
- Args:
504
- - process_name: Name of the process (to display on the widget).
505
- - proxy_type: Type of Proxy (to check the status of the process).
506
- """
507
-
508
- super().__init__()
509
-
510
- self.process_name = process_name
511
- self.proxy_type = process_info[0]
512
- self.proxy_type_as_type = find_class(self.proxy_type[7:])
513
- self.device_args = process_info[1]
514
- self.is_simulator_mode = False
515
- self.is_device = True
516
-
517
- self.parent = parent
518
-
519
- layout = QGridLayout()
520
-
521
- index = 0
522
-
523
- # Status LED
524
-
525
- self.status_led = LED(parent=self)
526
- layout.addWidget(self.status_led, 0, index)
527
- index += 1
528
-
529
- # Process name
530
-
531
- self.process_name_label = QLabel(process_name)
532
- layout.addWidget(self.process_name_label, 0, index)
533
- layout.setColumnStretch(index, 1) # Push LED and name to the left and buttons to the right
534
- index += 1
535
-
536
- # Fire up (default) GUI
537
-
538
- self.show_gui_button = TouchButton(name=f"Open the GUI for the {self.process_name}.",
539
- status_tip=f"Open the GUI for the {self.process_name}.",
540
- selected=get_resource(":/icons/user-interface.svg")
541
- )
542
- self.show_gui_button.setFixedSize(30, 30)
543
- self.show_gui_button.clicked.connect(self.start_gui)
544
-
545
- module_name = self.proxy_type[7:].rsplit(".", 1)[0]
546
- module = importlib.import_module(module_name)
547
-
548
- if not process_name.startswith("AEU") or process_name == "AEU cRIO":
549
-
550
- if hasattr(module, "DEVICE_SETTINGS") and hasattr(module.DEVICE_SETTINGS, "UserInterface"):
551
- layout.addWidget(self.show_gui_button, 0, index)
552
- elif hasattr(module, "COMMAND_SETTINGS") and hasattr(module.COMMAND_SETTINGS, "UserInterface"):
553
- layout.addWidget(self.show_gui_button, 0, index)
554
-
555
- index += 1
556
-
557
- # Shut down / re-start
558
-
559
- if include_start_stop_button:
560
-
561
- self.start_stop_button = ToggleButton(name=f"Start / shut down the {self.process_name} control server.",
562
- status_tip=f"Start / shut down the {self.process_name} control server.",
563
- selected=get_resource(":/images/play-button.svg"),
564
- not_selected=get_resource(":/images/stop-button.svg"),
565
- disabled=[get_resource(":/icons/busy.svg"),
566
- get_resource(":/icons/busy.svg")]
567
- )
568
- self.start_stop_button.clicked.connect(self.start_stop_cs)
569
-
570
- layout.addWidget(self.start_stop_button, 0, index)
571
- index += 1
572
-
573
- if issubclass(self.proxy_type_as_type, DeviceInterface):
574
- self.sim_option_button = ToggleButton(name=f"Operational vs. simulator mode",
575
- status_tip=f"Indicate whether you want to start the "
576
- f"{self.process_name} Control Server in operational or in "
577
- f"simulator mode.",
578
- selected=get_resource(":/icons/sim-mode.svg"),
579
- not_selected=get_resource(":/icons/ops-mode.svg"),
580
- disabled=[get_resource(":/icons/sim-mode.svg"),
581
- get_resource(":/icons/ops-mode.svg")]
582
- )
583
- self.sim_option_button.set_selected(False) # Default: operational mode
584
- else:
585
- self.sim_option_button = ToggleButton(name=f"Operational vs. simulator mode",
586
- status_tip=f"The {self.process_name} Control Server can only be "
587
- f"started in operational mode.",
588
- selected=get_resource(":/icons/ops-mode.svg"),
589
- not_selected=get_resource(":/icons/ops-mode.svg"),
590
- disabled=[get_resource(":/icons/ops-mode.svg"),
591
- get_resource(":/icons/ops-mode.svg")]
592
- )
593
- self.is_device = False
594
- self.sim_option_button.clicked.connect(self.set_cs_start_mode)
595
-
596
- if self.process_name == "DAQ":
597
-
598
- self.start_stop_button.setToolTip(f"Start / shut down the {self.process_name} control server and its "
599
- f"data acquisition.")
600
- self.sim_option_button.setEnabled(False) # Only in operational mode
601
- self.sim_option_button.setStatusTip(f"The {self.process_name} and its data acquisition can only be"
602
- f"started in operational mode.")
603
-
604
- layout.addWidget(self.sim_option_button, 0, index)
605
- index += 1
606
-
607
- self.setLayout(layout)
608
-
609
- def start_gui(self):
610
- """ Starting the default GUI for the process."""
611
-
612
- LOGGER.debug(f"Starting GUI for {self.process_name}")
613
-
614
- module_name = self.proxy_type[7:].rsplit(".", 1)[0]
615
- module = importlib.import_module(module_name)
616
-
617
- if hasattr(module, "DEVICE_SETTINGS") and hasattr(module.DEVICE_SETTINGS, "UserInterface"):
618
- gui_type = module.DEVICE_SETTINGS.UserInterface # Device CS
619
- elif hasattr(module, "COMMAND_SETTINGS") and hasattr(module.COMMAND_SETTINGS, "UserInterface"):
620
- gui_type = module.COMMAND_SETTINGS.UserInterface # Core CS
621
- else: # No GUI defined in the YAML file of the CS
622
- LOGGER.debug(f"No GUI available for {self.process_name}")
623
- return
624
- if module_name == "egse.tempcontrol.lakeshore.lsci":
625
- index = self.process_name.split(" ")[2]
626
- gui_process = SubProcess("MyApp", [sys.executable, "-m", gui_type, "--index", index])
627
- gui_process.execute(detach_from_parent=True)
628
- else:
629
- gui_process = SubProcess("MyApp", [sys.executable, "-m", gui_type])
630
- gui_process.execute(detach_from_parent=True)
631
-
632
- def set_cs_start_mode(self):
633
- """ Change the start mode for the Control Server.
634
-
635
- Change the start mode for the Control Server from simulator mode to operational mode, or vice versa.
636
- """
637
- self.is_simulator_mode = not self.is_simulator_mode
638
-
639
- def start_stop_cs(self):
640
- """ Start or shut down the Control Server.
641
-
642
- Depending on the current state of the Control Server, it will either be started or shut down.
643
- """
644
-
645
- self.sim_option_button.setEnabled(False)
646
- self.start_stop_button.setDisabled(True)
647
-
648
- if self.start_stop_button.is_selected():
649
-
650
- LOGGER.info(f"Shut down the {self.process_name} Control Server")
651
- thread = threading.Thread(target=self.stop_cs)
652
-
653
- else:
654
-
655
- LOGGER.info(f"Start the {self.process_name} Control Server")
656
- thread = threading.Thread(target=self.start_cs)
657
-
658
- thread.daemon = True
659
- thread.start()
660
-
661
- # Let the main UI window know that the start/stop button has been clicked
662
- self.parent.on_start_stop_cs_button_clicked(self.process_name)
663
-
664
- def start_cs(self):
665
-
666
- try:
667
-
668
- with ProcessManagerProxy() as pm:
669
-
670
- response: Response = pm.start_cs(self.process_name, self.is_simulator_mode)
671
- if response.successful:
672
- self.sim_option_button.setDisabled(True)
673
- else:
674
- self.sim_option_button.setEnabled(True)
675
-
676
- gui_process = SubProcess("MyApp", [sys.executable, "-m", "egse.procman.cannot_start_process_popup",
677
- "--process_name", f"{self.process_name} Control Server",
678
- "--message", response.message])
679
- gui_process.execute(detach_from_parent=True)
680
-
681
- return response
682
-
683
- #
684
- # try:
685
- # pm.start_cs(self.process_name, self.is_simulator_mode)
686
- # self.sim_option_button.setDisabled(True)
687
- #
688
- # except ConnectionError:
689
- # LOGGER.info(f"Could not start Control Server for {self.process_name}")
690
- # self.sim_option_button.setEnabled(True)
691
- #
692
- except ConnectionError as exc:
693
-
694
- message = f"Lost connection to Process Manager"
695
- LOGGER.critical(message, exc_info=True)
696
-
697
- self.sim_option_button.setEnabled(True)
698
- self.start_stop_button.setEnabled(True)
699
- self.start_stop_button.set_selected(True)
700
-
701
- return Failure(message, cause=exc)
702
-
703
- def stop_cs(self):
704
-
705
- try:
706
- with ProcessManagerProxy() as pm:
707
- LOGGER.info(f"PM: shut down {self.process_name}")
708
- pm.shut_down_cs(self.process_name)
709
- self.sim_option_button.setDisabled(False)
710
-
711
- except ConnectionError:
712
-
713
- LOGGER.critical(f"Lost connection to Process Manager")
714
- self.sim_option_button.setEnabled(True)
715
-
716
- def set_led_color(self, color: int):
717
- """ Set the colour of the LED, representing the status of the process.
718
-
719
- The meaning of the colours is the following:
720
-
721
- - green:
722
- - core process with running Control Server;
723
- - device process in simulator mode with running Control Server;
724
- - device process in operational mode with running Control Server and connection to the Controller;
725
- - orange: device process in operational mode with Control Server running but without connection to the
726
- Controller;
727
- - red: no Control Server running.
728
-
729
- Args:
730
- - color: Integer representing the colour to indicate the process status. Should only be Indic.GREEN,
731
- Indic.ORANGE, or Indic.RED.
732
- """
733
-
734
- self.status_led.set_color(color)
735
-
736
- try:
737
- self.start_stop_button.setDisabled(False)
738
- except AttributeError:
739
- # Core processes don't have this button
740
- pass
741
-
742
- if color != Indic.RED:
743
- try:
744
- self.sim_option_button.setEnabled(False)
745
- self.start_stop_button.set_selected(False)
746
- except AttributeError:
747
- # Core processes don't have this button
748
- pass
749
-
750
- else:
751
- try:
752
- self.sim_option_button.setEnabled(True)
753
- self.start_stop_button.set_selected(True)
754
- except AttributeError:
755
- # Core processes don't have this button
756
- pass
757
-
758
- def is_simulator_mode(self):
759
- """ Check whether the simulator mode checkbox was checked.
760
-
761
- Returns: True of the simulator mode checkbox was checked; False otherwise.
762
- """
763
-
764
- return self.sim_option_button.is_selected()
765
-
766
-
767
- class NonCSProcessWidget(QGroupBox):
768
-
769
- def __init__(self, process_name, parent, include_gui_button=True, include_start_stop_button=True):
770
- """ Initialisation of a process widget.
771
-
772
- For a Control Server with the given process name and Proxy type, a process widget is created. This widget will
773
- comprise the following components:
774
-
775
- - status LED;
776
- - process name;
777
- - button to start the GUI for the process;
778
- - button to start / shut down the process.
779
-
780
- Args:
781
- - process_name: Name of the process (to display on the widget).
782
- """
783
-
784
- super().__init__()
785
-
786
- self.process_name = process_name
787
- self.parent = parent
788
-
789
- layout = QGridLayout()
790
-
791
- index = 0
792
-
793
- # Status LED
794
-
795
- self.status_led = LED(parent=self)
796
- layout.addWidget(self.status_led, 0, index)
797
- index += 1
798
-
799
- # Process name
800
-
801
- self.process_name_label = QLabel(process_name)
802
- layout.addWidget(self.process_name_label, 0, index)
803
- layout.setColumnStretch(index, 1) # Push LED and name to the left and buttons to the right
804
- index += 1
805
-
806
- # Fire up (default) GUI
807
-
808
- if include_gui_button:
809
-
810
- self.show_gui_button = TouchButton(name=f"Open the GUI for the {self.process_name}.",
811
- status_tip=f"Open the GUI for the {self.process_name}.",
812
- selected=get_resource(":/icons/user-interface.svg")
813
- )
814
- self.show_gui_button.setFixedSize(30, 30)
815
- layout.addWidget(self.show_gui_button, 0, index)
816
- self.show_gui_button.clicked.connect(self.start_gui)
817
-
818
- index += 1
819
-
820
- # Shut down / re-start
821
-
822
- if include_start_stop_button:
823
-
824
- self.start_stop_button = ToggleButton(name=f"Start / shut down the {self.process_name}.",
825
- status_tip=f"Start / shut down the {self.process_name}.",
826
- selected=get_resource(":/images/play-button.svg"),
827
- not_selected=get_resource(":/images/stop-button.svg"),
828
- disabled=[get_resource(":/icons/busy.svg"),
829
- get_resource(":/icons/busy.svg")]
830
- )
831
- self.start_stop_button.clicked.connect(self.start_stop_service)
832
- layout.addWidget(self.start_stop_button, 0, index)
833
- index += 1
834
-
835
- self.setLayout(layout)
836
-
837
- def start_stop_service(self):
838
-
839
- self.start_stop_button.setDisabled(True)
840
-
841
- if self.start_stop_button.is_selected():
842
-
843
- print(f"Stopping {self.process_name}")
844
- LOGGER.info(f"Shut down the {self.process_name}")
845
- thread = threading.Thread(target=self.stop_service)
846
-
847
- else:
848
-
849
- print(f"Starting {self.process_name}")
850
- LOGGER.info(f"Start the {self.process_name}")
851
- thread = threading.Thread(target=self.start_service)
852
-
853
- thread.daemon = True
854
- thread.start()
855
-
856
- self.parent.on_start_stop_non_cs_process_button_clicked(self.process_name)
857
-
858
- # def start_gui(self):
859
- # """ Starting the default GUI for the process."""
860
- #
861
- # LOGGER.debug(f"Starting GUI for {self.process_name}")
862
- # print("Starting GUI")
863
-
864
- def set_led_color(self, color: int):
865
- """ Set the colour of the LED, representing the status of the process.
866
-
867
- The meaning of the colours is the following:
868
-
869
- - green: process running;
870
- - red: process not running.
871
-
872
- Args:
873
- - color: Integer representing the colour to indicate the process status. Should only be Indic.GREEN,
874
- or Indic.RED.
875
- """
876
-
877
- self.status_led.set_color(color)
878
-
879
- try:
880
- self.start_stop_button.setDisabled(False)
881
- self.start_stop_button.set_selected(color == Indic.RED)
882
- except AttributeError:
883
- # The logger doesn't have a start/stop button
884
- pass
885
-
886
-
887
- class LogWidget(NonCSProcessWidget):
888
-
889
- def __init__(self, parent):
890
-
891
- super().__init__("Logger", parent, include_gui_button=True, include_start_stop_button=False)
892
-
893
- def start_gui(self):
894
-
895
- gui_process = SubProcess("MyApp", [sys.executable, "-m", "cutelog"])
896
- gui_process.execute(detach_from_parent=True)
897
-
898
-
899
- class FitsgenWidget(NonCSProcessWidget):
900
-
901
- def __init__(self, parent):
902
-
903
- super(FitsgenWidget, self).__init__(FILE_GENERATION_PROCESS_NAMES.FITSGEN, parent, include_gui_button=True,
904
- include_start_stop_button=True)
905
-
906
- def start_gui(self):
907
-
908
- gui_process = SubProcess("MyApp", [sys.executable, "-m", "egse.dpu.fitsgen_ui"])
909
- gui_process.execute(detach_from_parent=True)
910
-
911
- def start_service(self):
912
-
913
- response: Response = start_fitsgen()
914
-
915
- if not response.successful:
916
- gui_process = SubProcess("MyApp", [sys.executable, "-m", "egse.procman.cannot_start_process_popup",
917
- "--process_name", "FITS generation", "--message", response.message])
918
- gui_process.execute(detach_from_parent=True)
919
-
920
- def stop_service(self):
921
-
922
- stop_fitsgen()
923
-
924
-
925
- class FovHkWidget(NonCSProcessWidget):
926
-
927
- def __init__(self, parent):
928
-
929
- super(FovHkWidget, self).__init__(FILE_GENERATION_PROCESS_NAMES.FOV_HK, parent, include_gui_button=False,
930
- include_start_stop_button=True)
931
-
932
- def start_service(self):
933
-
934
- response: Response = start_fov_hk()
935
-
936
- if not response.successful:
937
- gui_process = SubProcess("MyApp", [sys.executable, "-m", "egse.procman.cannot_start_process_popup",
938
- "--process_name", "FOV HK generation", "--message", response.message])
939
- gui_process.execute(detach_from_parent=True)
940
-
941
- def stop_service(self):
942
-
943
- stop_fov_hk()
944
-
945
-
946
- class NFeeHkWidget(NonCSProcessWidget):
947
-
948
- def __init__(self, parent):
949
-
950
- super(NFeeHkWidget, self).__init__(FILE_GENERATION_PROCESS_NAMES.N_FEE_HK, parent, include_gui_button=False,
951
- include_start_stop_button=True)
952
-
953
- def start_service(self):
954
-
955
- response: Response = start_n_fee_hk()
956
-
957
- if not response.successful:
958
- gui_process = SubProcess("MyApp", [sys.executable, "-m", "egse.procman.cannot_start_process_popup",
959
- "--process_name", "N-FEE HK generation", "--message", response.message])
960
- gui_process.execute(detach_from_parent=True)
961
-
962
- def stop_service(self):
963
-
964
- stop_n_fee_hk()
965
-
966
-
967
- def start_fitsgen():
968
- """ Start the FITS generation."""
969
-
970
- with ProcessManagerProxy() as pm:
971
- return pm.start_fitsgen()
972
-
973
-
974
- def stop_fitsgen():
975
- """ Stop the FITS generation."""
976
-
977
- with ProcessManagerProxy() as pm:
978
- pm.stop_fitsgen()
979
-
980
-
981
- def start_fov_hk():
982
- """ Start the generation of FOV HK."""
983
-
984
- with ProcessManagerProxy() as pm:
985
- return pm.start_fov_hk()
986
-
987
-
988
- def stop_fov_hk():
989
- """ Stop the generation of FOV HK"""
990
-
991
- with ProcessManagerProxy() as pm:
992
- pm.stop_fov_hk()
993
-
994
-
995
- def start_n_fee_hk():
996
- """ Start the generation of N-FEE HK."""
997
-
998
- with ProcessManagerProxy() as pm:
999
- return pm.start_n_fee_hk()
1000
-
1001
-
1002
- def stop_n_fee_hk():
1003
- """ Stop the generation of N-FEE HK."""
1004
-
1005
- with ProcessManagerProxy() as pm:
1006
- pm.stop_n_fee_hk()
1007
-
1008
-
1009
- def start_egse():
1010
- """ Start all device Control Servers in one go."""
1011
-
1012
- with ProcessManagerProxy() as pm:
1013
- pm.start_egse()
1014
-
1015
-
1016
- def stop_egse():
1017
- """ Stop all device Control Servers in one go."""
1018
-
1019
- with ProcessManagerProxy() as pm:
1020
- pm.shut_down_egse()
1021
-
1022
- def open_th_ui():
1023
- """ Open the TH Operator UI."""
1024
-
1025
- sitehash = {
1026
- "CSL": get_csl_ui_process,
1027
- "CSL1": get_csl_ui_process,
1028
- "CSL2": get_csl_ui_process,
1029
- "IAS": get_ias_ui_process,
1030
- "INTA": get_inta_ui_process,
1031
- "SRON": get_sron_ui_process,
1032
- }
1033
-
1034
- gui_process = sitehash[SITE.ID]()
1035
- gui_process.execute(detach_from_parent=True)
1036
-
1037
-
1038
- def get_csl_ui_process():
1039
- return SubProcess("MyApp", ["csl_ui"])
1040
-
1041
-
1042
- def get_sron_ui_process():
1043
- return SubProcess("MyApp", ["sron_ui"])
1044
-
1045
-
1046
- def get_ias_ui_process():
1047
- return SubProcess("MyApp", ["ias_ui"])
1048
-
1049
-
1050
- def get_inta_ui_process():
1051
- return SubProcess("MyApp", ["inta_ui"])
1052
-
1053
-
1054
- def open_fov_ui():
1055
- """ Open the FOV UI."""
1056
-
1057
- gui_process = SubProcess("MyApp", ["fov_ui"])
1058
- gui_process.execute(detach_from_parent=True)
1059
-
1060
-
1061
- def open_visited_positions_ui():
1062
- """ Open the visited-positions UI."""
1063
-
1064
- gui_process = SubProcess("MyApp", ["visited_positions_ui"])
1065
- gui_process.execute(detach_from_parent=True)
1066
-
1067
-
1068
- class ProcessManagerUIView(QMainWindow):
1069
-
1070
- def __init__(self):
1071
- """ Initialisation of the Process Manager GUI.
1072
-
1073
- The components are placed in the window and threads are created for all processes, to be able to check for
1074
- updates in the process status (in the background) and display these in the GUI.
1075
- """
1076
-
1077
- super().__init__()
1078
-
1079
- self.setGeometry(300, 300, 1000, 1000)
1080
- self.setWindowTitle("Process Manager")
1081
-
1082
- self.processes = {}
1083
- self.devices = {}
1084
-
1085
- try:
1086
-
1087
- with ProcessManagerProxy() as process_manager_proxy:
1088
-
1089
- self.core = process_manager_proxy.get_core() # Core
1090
-
1091
- except ConnectionError:
1092
-
1093
- self.core = {}
1094
-
1095
- self.monitoring_threads = {}
1096
- self.monitoring_workers = {}
1097
-
1098
- self.process_widgets = {}
1099
-
1100
- self.process_widgets_core = {}
1101
-
1102
- self.setup_monitoring_thread = QThread(self)
1103
- self.setup_monitoring_worker = ConfigurationMonitoringWorker()
1104
- self.setup_monitoring_worker.moveToThread(self.setup_monitoring_thread)
1105
-
1106
- # What to do when information has been received on the monitoring
1107
- # port before timeout?
1108
-
1109
- self.setup_monitoring_worker.setup_changed_signal.connect(self.on_setup_changed_signal)
1110
- self.setup_monitoring_worker.obsid_changed_signal.connect(self.on_obsid_changed_signal)
1111
- self.setup_monitoring_thread.started.connect(self.setup_monitoring_worker.start_process)
1112
- self.setup_monitoring_thread.start()
1113
-
1114
- # Build up the GUI
1115
-
1116
- self.init_ui()
1117
-
1118
- # Keep an eye on the logger
1119
-
1120
- self.logger_monitoring_thread = QThread(self)
1121
- self.logger_monitoring_worker = ProcessMonitoringWorker("egse.logger.log_cs")
1122
- self.logger_monitoring_worker.moveToThread(self.logger_monitoring_thread)
1123
- self.logger_monitoring_worker.is_running_signal.connect(self.on_logger_is_running_signal)
1124
- self.logger_monitoring_thread.started.connect(self.logger_monitoring_worker.start_process)
1125
- self.logger_monitoring_thread.start()
1126
-
1127
- # Keep an eye on the FITS generation
1128
-
1129
- self.fitsgen_monitoring_thread = QThread(self)
1130
- self.fitsgen_monitoring_worker = ProcessMonitoringWorker("egse.dpu.fitsgen")
1131
- self.fitsgen_monitoring_worker.moveToThread(self.fitsgen_monitoring_thread)
1132
- self.fitsgen_monitoring_worker.is_running_signal.connect(self.on_fitsgen_is_running_signal)
1133
- self.fitsgen_monitoring_thread.started.connect(self.fitsgen_monitoring_worker.start_process)
1134
- self.fitsgen_monitoring_thread.start()
1135
-
1136
- # Keep an eye on the generation of FOV HK
1137
-
1138
- self.fov_hk_monitoring_thread = QThread(self)
1139
- self.fov_hk_monitoring_worker = ProcessMonitoringWorker("egse.fov.fov_hk")
1140
- self.fov_hk_monitoring_worker.moveToThread(self.fov_hk_monitoring_thread)
1141
- self.fov_hk_monitoring_worker.is_running_signal.connect(self.on_fov_hk_is_running_signal)
1142
- self.fov_hk_monitoring_thread.started.connect(self.fov_hk_monitoring_worker.start_process)
1143
- self.fov_hk_monitoring_thread.start()
1144
-
1145
- # Keep an eye on the generation of N-FEE HK
1146
-
1147
- self.n_fee_hk_monitoring_thread = QThread(self)
1148
- self.n_fee_hk_monitoring_worker = ProcessMonitoringWorker("egse.fee.n_fee_hk")
1149
- self.n_fee_hk_monitoring_worker.moveToThread(self.n_fee_hk_monitoring_thread)
1150
- self.n_fee_hk_monitoring_worker.is_running_signal.connect(self.on_n_fee_hk_is_running_signal)
1151
- self.n_fee_hk_monitoring_thread.started.connect(self.n_fee_hk_monitoring_worker.start_process)
1152
- self.n_fee_hk_monitoring_thread.start()
1153
-
1154
- self.file_generation_monitoring_workers = {
1155
- FILE_GENERATION_PROCESS_NAMES.FITSGEN: self.fitsgen_monitoring_worker,
1156
- FILE_GENERATION_PROCESS_NAMES.FOV_HK: self.fov_hk_monitoring_worker,
1157
- FILE_GENERATION_PROCESS_NAMES.N_FEE_HK: self.n_fee_hk_monitoring_worker
1158
- }
1159
-
1160
- def init_ui(self):
1161
- """ Put the components in the GUI window.
1162
-
1163
- The GUI comprises the following components:
1164
-
1165
- - the toolbar;
1166
- - on the left-hand side: one process widget per process;
1167
- - on the right-hand side: one tab per process.
1168
- """
1169
-
1170
- # Creating the content
1171
-
1172
- app_frame = QFrame()
1173
- app_frame.setObjectName("AppFrame")
1174
-
1175
- self.create_toolbar()
1176
- self.create_statusbar()
1177
-
1178
- scroll = QScrollArea()
1179
- # widget_frame = QFrame()
1180
-
1181
- hbox = QHBoxLayout()
1182
- vbox_left = QVBoxLayout()
1183
- vbox_right = QVBoxLayout()
1184
- hbox.addLayout(vbox_left)
1185
- hbox.addLayout(vbox_right)
1186
-
1187
- vbox_right.addStretch()
1188
-
1189
- app_frame.setLayout(hbox)
1190
-
1191
- # Obsid
1192
-
1193
- info_gridbox = QGridLayout()
1194
-
1195
- self.obsid = QLabel("No observation is running")
1196
- self.setStyleSheet('QMainWindow{border: 3px solid green;}')
1197
- info_gridbox.addWidget(QLabel("Obsid:"), 0, 0)
1198
- info_gridbox.addWidget(self.obsid, 0, 1)
1199
-
1200
-
1201
- self.setup_id = QLabel("No setup loaded")
1202
- info_gridbox.addWidget(QLabel("Setup ID:"), 1, 0)
1203
- info_gridbox.addWidget(self.setup_id, 1, 1)
1204
-
1205
- self.camera_id = QLabel("Camera ID unknown")
1206
- info_gridbox.addWidget(QLabel("Camera ID:"), 2, 0)
1207
- info_gridbox.addWidget(self.camera_id, 2, 1)
1208
-
1209
- self.csl_hexapod_id = QLabel("Hexapod ID unknown")
1210
- if "CSL" in SITE.ID:
1211
- info_gridbox.addWidget(QLabel("Hexapod ID:"), 3, 0)
1212
- info_gridbox.addWidget(self.csl_hexapod_id, 3, 1)
1213
-
1214
- vbox_left.addLayout(info_gridbox)
1215
- vbox_left.addWidget(QLabel())
1216
-
1217
- self.overview_widget_device_cs_layout = QVBoxLayout()
1218
- self.overview_widget_device_cs_layout.addStretch()
1219
- self.overview_widget_device_cs = QGroupBox("Device Control Servers", self)
1220
- self.overview_widget_device_cs.setLayout(self.overview_widget_device_cs_layout)
1221
- self.overview_widget_device_cs.setToolTip(
1222
- "EGSE device control servers:\n" +
1223
- "can be started in this GUI or on the command line.")
1224
-
1225
- self.overview_widget_non_device_cs_layout = QVBoxLayout()
1226
- self.overview_widget_non_device_cs_layout.addStretch()
1227
- self.overview_widget_non_device_cs = QGroupBox("Non-Device Control Servers", self)
1228
- self.overview_widget_non_device_cs.setLayout(self.overview_widget_non_device_cs_layout)
1229
- self.overview_widget_non_device_cs.setToolTip(
1230
- "EGSE non-device control servers:\n" +
1231
- "can be started in this GUI or on the command line (operational mode only).")
1232
-
1233
- self.create_overview_widget_core()
1234
- vbox_left.addWidget(self.overview_widget_core)
1235
-
1236
- self.create_overview_widget_file_services()
1237
- vbox_left.addWidget(self.overview_widget_file_services)
1238
-
1239
- vbox_right.addWidget(self.overview_widget_device_cs)
1240
- vbox_left.addWidget(self.overview_widget_non_device_cs)
1241
-
1242
- scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
1243
- scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
1244
- scroll.setWidgetResizable(True)
1245
-
1246
- scroll.setWidget(app_frame)
1247
- self.setCentralWidget(scroll)
1248
-
1249
- def start_monitoring(self) -> object:
1250
- """ Start listening on the monitoring port.
1251
-
1252
- Create and start a thread that listens on the monitoring port in the background. If information is received
1253
- before timeout, the Control Server is running: the light in the process tab should be set to green or orange,
1254
- and the process information should be updated in the process tab.
1255
- """
1256
-
1257
- for process_name, process_info in self.processes.items():
1258
-
1259
- self.monitoring_threads[process_name] = QThread()
1260
-
1261
- self.monitoring_workers[process_name] = MonitoringWorker(process_name, process_info)
1262
- self.monitoring_workers[process_name].moveToThread(self.monitoring_threads[process_name])
1263
-
1264
- # What to do when information has been sent back from the process thread?
1265
-
1266
- self.monitoring_workers[process_name].process_status_signal.connect(self.on_process_status_signal)
1267
-
1268
- self.monitoring_threads[process_name].started.connect(
1269
- self.monitoring_workers[process_name].start_process)
1270
-
1271
- self.monitoring_threads[process_name].start()
1272
-
1273
- def on_setup_changed_signal(self, setup: Setup):
1274
- """ Re-build the GUI after a change in setup.
1275
-
1276
- Args:
1277
- - setup: New setup.
1278
- """
1279
-
1280
- # self.all_aeu_cs_button.disable()
1281
- # self.start_aeu_button.setDisabled(True)
1282
- # self.stop_aeu_button.setDisabled(True)
1283
-
1284
- # Stop all workers and threads
1285
-
1286
- for process_name in self.processes.keys():
1287
-
1288
- self.monitoring_workers[process_name].process_status_signal.disconnect()
1289
-
1290
- self.monitoring_workers[process_name].stop()
1291
- self.monitoring_threads[process_name].quit()
1292
-
1293
- for process_name in self.processes.keys():
1294
- self.monitoring_threads[process_name].wait()
1295
-
1296
- self.monitoring_workers.clear()
1297
- self.monitoring_threads.clear()
1298
-
1299
- # Make process list
1300
-
1301
- self.processes.clear()
1302
- self.core.clear()
1303
- self.devices.clear()
1304
-
1305
- self.start_aeu_button.setVisible(False)
1306
- self.stop_aeu_button.setVisible(False)
1307
-
1308
- # Remove the widgets from the layouts
1309
-
1310
- while self.overview_widget_device_cs_layout.count():
1311
-
1312
- widget = self.overview_widget_device_cs_layout.takeAt(0).widget()
1313
-
1314
- if widget is not None:
1315
- widget.deleteLater()
1316
-
1317
- while self.overview_widget_non_device_cs_layout.count():
1318
-
1319
- widget = self.overview_widget_non_device_cs_layout.takeAt(0).widget()
1320
-
1321
- if widget is not None:
1322
- widget.deleteLater()
1323
-
1324
- self.process_widgets.clear()
1325
-
1326
- # Re-build the process list
1327
-
1328
- try:
1329
-
1330
- with ProcessManagerProxy() as process_manager_proxy:
1331
-
1332
- self.core = process_manager_proxy.get_core()
1333
- self.devices = process_manager_proxy.get_devices()
1334
-
1335
- self.processes.update(self.core)
1336
- self.processes.update(self.devices)
1337
-
1338
- except ConnectionError:
1339
-
1340
- self.core = {}
1341
- self.devices = {}
1342
-
1343
- # Make new process widgets
1344
-
1345
- for process_name in self.devices.keys():
1346
-
1347
- process_widget = ProcessWidget(process_name, self.devices[process_name], self)
1348
-
1349
- self.process_widgets[process_name] = process_widget
1350
-
1351
- if process_widget.is_device:
1352
- self.overview_widget_device_cs_layout.addWidget(process_widget)
1353
- else:
1354
- self.overview_widget_non_device_cs_layout.addWidget(process_widget)
1355
-
1356
- self.process_widgets.update(self.process_widgets_core)
1357
-
1358
- # Make sure the boxes stay nicely together when vertically resizing
1359
-
1360
- self.overview_widget_device_cs_layout.addStretch()
1361
- self.overview_widget_non_device_cs_layout.addStretch()
1362
-
1363
- # Start monitoring the process status
1364
-
1365
- self.start_monitoring()
1366
-
1367
- if "AEU cRIO" in self.devices.keys():
1368
-
1369
- # self.all_aeu_cs_button.set_selected(False)
1370
- # self.all_aeu_cs_button.enable()
1371
- self.start_aeu_button.setEnabled(True)
1372
- self.stop_aeu_button.setEnabled(True)
1373
-
1374
- else:
1375
-
1376
- # self.all_aeu_cs_button.set_selected(False)
1377
- # self.all_aeu_cs_button.disable()
1378
- self.start_aeu_button.setEnabled(False)
1379
- self.stop_aeu_button.setEnabled(False)
1380
-
1381
- self.setup_id.setText(f"{setup.get_id()}")
1382
-
1383
- try:
1384
- cam_id = setup.camera.ID
1385
- if cam_id != "EM":
1386
- self.camera_id.setToolTip("Ah, beer! The cause of and the solution to all of life's problems!")
1387
- self.camera_id.setText(cam_id)
1388
- except AttributeError:
1389
- self.camera_id.setText("Camera ID unknown")
1390
-
1391
- try:
1392
- self.csl_hexapod_id.setText(str(setup.gse.hexapod.ID))
1393
- except AttributeError:
1394
- self.csl_hexapod_id.setText("Hexapod ID unknown")
1395
-
1396
- def on_obsid_changed_signal(self, obsid: ObservationIdentifier):
1397
- """ Update the GUI for the new obsid.
1398
-
1399
- Args:
1400
- - obsid: The new obsid.
1401
- """
1402
-
1403
- if obsid is None:
1404
-
1405
- self.obsid.setText("No observation is running")
1406
- self.setStyleSheet('QMainWindow{border: 3px solid green;}')
1407
-
1408
- else:
1409
-
1410
- self.obsid.setText(str(obsid))
1411
- self.setStyleSheet('QMainWindow{border: 3px solid red;}')
1412
-
1413
- def on_process_status_signal(self, process_info):
1414
- """ Update the GUI for the process with the given name.
1415
-
1416
- This method is called to update the GUI for the process with the given name in case the Control Server is
1417
- running:
1418
-
1419
- - the colour of the light in the process widget is set to green or orange;
1420
- - the process information is updated in the tab.
1421
-
1422
- The meaning of the colours is the following:
1423
-
1424
- - green:
1425
- - core process with running Control Server;
1426
- - device process in simulator mode with running Control Server;
1427
- - device process in operational mode with running Control Server and connection to the Controller;
1428
- - orange: device process in operational mode with Control Server running but without connection to the
1429
- Controller.
1430
-
1431
-
1432
- Args:
1433
- process_info: Information for one process, to be updated in the
1434
- Process Manager GUI.
1435
- """
1436
-
1437
- process_name = process_info["Name"]
1438
- color = process_info["Color"]
1439
-
1440
- widget = self.process_widgets[process_name]
1441
-
1442
- # Update the process widget
1443
-
1444
- if "Simulator" in process_info:
1445
-
1446
- if process_name != "DPU":
1447
-
1448
- try:
1449
- widget.sim_option_button.set_selected(process_info["Simulator"])
1450
- except TypeError:
1451
- # See #1419
1452
- widget.sim_option_button.set_selected(False)
1453
- LOGGER.debug(f"Unchecking the simulator checkbox in PM UI for {process_name}")
1454
-
1455
- widget.sim_option_button.button_disabled = widget.sim_option_button.button_selected \
1456
- if widget.sim_option_button.is_selected() \
1457
- else widget.sim_option_button.button_disabled
1458
- widget.sim_option_button.setDisabled(True)
1459
-
1460
- widget.set_led_color(color)
1461
-
1462
- if process_name == "Configuration Manager" and color == Indic.RED:
1463
-
1464
- self.obsid.setText("Obsid unknown")
1465
- self.setStyleSheet('QMainWindow{border: 3px solid orange;}')
1466
-
1467
- def on_start_stop_cs_button_clicked(self, process_name):
1468
-
1469
- self.monitoring_workers[process_name].start_stop_cs_button_clicked = True
1470
-
1471
- def on_start_stop_non_cs_process_button_clicked(self, process_name):
1472
-
1473
- self.file_generation_monitoring_workers[process_name].start_stop_cs_button_clicked = True
1474
-
1475
- def on_logger_is_running_signal(self, logger_is_running: bool):
1476
-
1477
- if logger_is_running:
1478
- self.logger_widget.set_led_color(Indic.GREEN)
1479
- else:
1480
- self.logger_widget.set_led_color(Indic.RED)
1481
-
1482
- def on_fitsgen_is_running_signal(self, fitsgen_is_running: bool):
1483
- """ Update the icon of the toolbar button for FITS generation.
1484
-
1485
- Args:
1486
- - fitsgen_is_running: Indicates whether or not the FITS generation is running.
1487
- """
1488
-
1489
- if fitsgen_is_running:
1490
- self.fitsgen_widget.set_led_color(Indic.GREEN)
1491
- else:
1492
- self.fitsgen_widget.set_led_color(Indic.RED)
1493
-
1494
- self.fitsgen_widget.start_stop_button.set_selected(not fitsgen_is_running)
1495
-
1496
- def on_fov_hk_is_running_signal(self, fov_hk_is_running: bool):
1497
- """ Update the icon of the toolbar button for the generation of FOV HK.
1498
-
1499
- Args:
1500
- - fov_hk_is_running: Indicates whether or not the generation of FOV HK is running.
1501
- """
1502
-
1503
- if fov_hk_is_running:
1504
- self.fov_hk_widget.set_led_color(Indic.GREEN)
1505
- else:
1506
- self.fov_hk_widget.set_led_color(Indic.RED)
1507
-
1508
- self.fov_hk_widget.start_stop_button.set_selected(not fov_hk_is_running)
1509
-
1510
- def on_n_fee_hk_is_running_signal(self, n_fee_hk_is_running: bool):
1511
- """ Update the icon of the toolbar button for the generation of N-FEE HK.
1512
-
1513
- Args:
1514
- - n_fee_hk_is_running: Indicates whether or not the generation of N-FEE HK is running.
1515
- """
1516
-
1517
- if n_fee_hk_is_running:
1518
- self.n_fee_hk_widget.set_led_color(Indic.GREEN)
1519
- else:
1520
- self.n_fee_hk_widget.set_led_color(Indic.RED)
1521
-
1522
- self.n_fee_hk_widget.start_stop_button.set_selected(not n_fee_hk_is_running)
1523
-
1524
- def set_process_list(self):
1525
- """ Make dictionary with all processes (core + devices).
1526
-
1527
- The Configuration Manager is asked which processes (core + devices) are included in the setup.
1528
- """
1529
-
1530
- self.processes = {}
1531
-
1532
- # Ask the CM which CS are included in the setup
1533
-
1534
- try:
1535
-
1536
- with ProcessManagerProxy() as process_manager_proxy:
1537
-
1538
- self.core = process_manager_proxy.get_core() # Core
1539
- self.devices = process_manager_proxy.get_devices() # Devices
1540
-
1541
- self.processes.update(self.core)
1542
- self.processes.update(self.devices)
1543
-
1544
- except ConnectionError:
1545
-
1546
- self.devices = {}
1547
- self.core = {}
1548
-
1549
- def create_toolbar(self):
1550
- """ Create the toolbar.
1551
-
1552
- Buttons with the following functionality are foreseen:
1553
- - Start/stop all EGSE device Control Servers in one go;
1554
- - Start/stop all AEU Control Servers in one go:
1555
- - Start/stop the FITS generation;
1556
- - Start/stop the generation of FOV HK;
1557
- - Start/stop the generation of N-FEE HK.
1558
- """
1559
-
1560
- self.start_egse_button = ToggleButton(name="Start all device control servers in one go.",
1561
- status_tip="Start all device control servers in one go.",
1562
- selected=get_resource(":/icons/play-green.svg"),
1563
- not_selected=get_resource(":/icons/play-green.svg")
1564
- )
1565
- self.start_egse_button.clicked.connect(self.start_egse)
1566
- self.stop_egse_button = ToggleButton(name="Start all device control servers in one go.",
1567
- status_tip="Stop all device control servers in one go.",
1568
- selected=get_resource(":/icons/stop-red.svg"),
1569
- not_selected=get_resource(":/icons/stop-red.svg")
1570
- )
1571
- self.stop_egse_button.clicked.connect(self.stop_egse)
1572
-
1573
- self.start_aeu_button = ToggleButton(name="Start all AEU control servers in one go.",
1574
- status_tip="Start all AEU control servers in one go.",
1575
- selected=get_resource(":/icons/aeu-cs-start.svg"),
1576
- not_selected=get_resource(":/icons/aeu-cs-start.svg"),
1577
- disabled=[get_resource(":/icons/aeu-cs.svg"),
1578
- get_resource(":/icons/aeu-cs.svg")]
1579
- )
1580
- self.start_aeu_button.clicked.connect(self.start_all_aeu_cs)
1581
-
1582
- self.stop_aeu_button = ToggleButton(name="Stop all AEU control servers in one go.",
1583
- status_tip="Stop all AEU control servers in one go.",
1584
- selected=get_resource(":/icons/aeu-cs-stop.svg"),
1585
- not_selected=get_resource(":/icons/aeu-cs-stop.svg"),
1586
- disabled=get_resource(":/icons/aeu-cs.svg")
1587
- )
1588
- self.stop_aeu_button.clicked.connect(self.stop_all_aeu_cs)
1589
-
1590
- th_ui_icon = QIcon(str(get_resource(":/icons/th_ui_logo.svg")))
1591
- th_ui_action = QAction(th_ui_icon, f"Open the {SITE.ID} Operator UI", self)
1592
- th_ui_action.setToolTip(f"Open the {SITE.ID} Operator UI")
1593
- th_ui_action.setCheckable(False)
1594
- th_ui_action.triggered.connect(open_th_ui)
1595
-
1596
- fov_ui_icon = QIcon(str(get_resource(":/icons/location-marker.svg"))) # TODO
1597
- fov_ui_action = QAction(fov_ui_icon, "Open the FOV UI", self)
1598
- fov_ui_action.setToolTip("Open the FOV UI")
1599
- fov_ui_action.setCheckable(False)
1600
- fov_ui_action.triggered.connect(open_fov_ui)
1601
-
1602
- visited_positions_ui_icon = QIcon(str(get_resource(":/icons/radar.svg"))) #TODO
1603
- visited_positions_ui_action = QAction(visited_positions_ui_icon, "Open the visited-positions UI", self)
1604
- visited_positions_ui_action.setToolTip("Open the visited-positions UI")
1605
- visited_positions_ui_action.setCheckable(False)
1606
- visited_positions_ui_action.triggered.connect(open_visited_positions_ui)
1607
-
1608
- self.toolbar = self.addToolBar("MainToolbar")
1609
- self.toolbar.addWidget(self.start_egse_button)
1610
- self.toolbar.addWidget(self.stop_egse_button)
1611
- self.toolbar.addSeparator()
1612
- self.toolbar.addWidget(self.start_aeu_button)
1613
- self.toolbar.addWidget(self.stop_aeu_button)
1614
-
1615
- spacer = QWidget()
1616
- spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
1617
- self.toolbar.addWidget(spacer)
1618
-
1619
- if "CSL" in SITE.ID:
1620
- self.toolbar.addAction(fov_ui_action)
1621
-
1622
- self.toolbar.addAction(th_ui_action)
1623
- self.toolbar.addSeparator()
1624
-
1625
- self.toolbar.addAction(visited_positions_ui_action)
1626
-
1627
- return self.toolbar
1628
-
1629
- def create_statusbar(self):
1630
- """ Create the status bar."""
1631
-
1632
- self.statusBar().setStyleSheet("border: 0; background-color: #FFF8DC;")
1633
- self.statusBar().setStyleSheet("QStatusBar::item {border: none;}")
1634
- # self.statusBar().addPermanentWidget(VLine())
1635
-
1636
- def start_egse(self):
1637
- """ Start all EGSE device Control Servers in one go.
1638
-
1639
- We only try to start the control servers that are currently down. For those, the following steps are taken:
1640
- - The start/stop button of each of these control servers should show the stop icon;
1641
- - The simulator option button is disabled;
1642
- - The control server is started, in the mode indicated by the simulator option button.
1643
-
1644
- For the control servers that could be started, the start/stop button keeps showing the stop icon and the
1645
- simulator mode button stays disabled. For control servers that could not be started, the start/stop button
1646
- show the start icon again and the simulator mode button is enabled again.
1647
- """
1648
-
1649
- LOGGER.info(f"Starting all device Control Servers")
1650
- thread = threading.Thread(target=self._start_egse)
1651
-
1652
- thread.daemon = True
1653
- thread.start()
1654
-
1655
- def _start_egse(self):
1656
-
1657
- # First make sure that the start/stop buttons in the process widgets show the hourglass icon (denoting is going
1658
- # on with that CD) and that the simulator option button is disabled (so you cannot switch between simulator and
1659
- # operational mode while starting the CS)
1660
-
1661
- for process_name in self.devices.keys():
1662
-
1663
- process_widget: ProcessWidget = self.process_widgets[process_name]
1664
-
1665
- if process_widget.status_led.color == Indic.RED:
1666
-
1667
- process_widget.start_stop_button.setDisabled(True)
1668
- process_widget.sim_option_button.setEnabled(False)
1669
-
1670
- # In order not to overload the Process Manager, we loop through the list of devices again and start the CS
1671
- # one-by-one
1672
-
1673
- with ProcessManagerProxy() as pm:
1674
-
1675
- for process_name in self.devices.keys():
1676
-
1677
- if process_widget.status_led.color == Indic.RED:
1678
-
1679
- self.monitoring_workers[process_name].start_stop_cs_button_clicked = True
1680
-
1681
- sim_mode = self.process_widgets[process_name].is_simulator_mode
1682
- response: Response = pm.start_cs(process_name, sim_mode)
1683
-
1684
- if not response.successful:
1685
- gui_process = SubProcess("MyApp", [sys.executable, "-m",
1686
- "egse.procman.cannot_start_process_popup", "--process_name",
1687
- process_name, "--message", response.message])
1688
- gui_process.execute(detach_from_parent=True)
1689
-
1690
- def stop_egse(self):
1691
- """ Shut down all EGSE device Control Servers in one go.
1692
-
1693
- We only try to start the control servers that are currently running. For those, the following steps are taken:
1694
- - The start/stop button of each of these control servers should show the start icon;
1695
- - The simulator option button is disabled;
1696
- - The control server is stopped.
1697
-
1698
- For the control servers that could be stopped, the start/stop button keeps showing the start icon and the
1699
- simulator mode button is enabled. For control servers that could not be stopped, the start/stop button
1700
- show the stop icon again and the simulator mode button is disabled again.
1701
- """
1702
-
1703
- LOGGER.info(f"Shutting down all device Control Servers")
1704
- thread = threading.Thread(target=self._stop_egse)
1705
-
1706
- thread.daemon = True
1707
- thread.start()
1708
-
1709
- def _stop_egse(self):
1710
-
1711
- # First make sure that the start/stop buttons in the process widgets show the hourglass icon (denoting is going
1712
- # on with that CD) and that the simulator option button is disabled (so you cannot switch between simulator and
1713
- # operational mode while starting the CS)
1714
-
1715
- for process_name in self.devices.keys():
1716
-
1717
- process_widget: ProcessWidget = self.process_widgets[process_name]
1718
-
1719
- if process_widget.status_led.color != Indic.RED:
1720
-
1721
- process_widget.start_stop_button.setDisabled(True)
1722
-
1723
- # In order not to overload the Process Manager, we loop through the list of devices again and start the CS
1724
- # one-by-one
1725
-
1726
- with ProcessManagerProxy() as pm:
1727
-
1728
- for process_name in reversed(self.devices.keys()):
1729
-
1730
- if process_widget.status_led.color != Indic.RED:
1731
-
1732
- self.monitoring_workers[process_name].start_stop_cs_button_clicked = True
1733
- pm.shut_down_cs(process_name)
1734
-
1735
- def start_all_aeu_cs(self):
1736
- """ Start the AEU Control Servers in one go."""
1737
-
1738
- thread = threading.Thread(target=self._start_all_aeu_cs)
1739
-
1740
- thread.daemon = True
1741
- thread.start()
1742
-
1743
- def _start_all_aeu_cs(self):
1744
-
1745
- # First make sure that the start/stop buttons in the process widgets show the hourglass icon (denoting is going
1746
- # on with that CD) and that the simulator option button is disabled (so you cannot switch between simulator and
1747
- # operational mode while starting the CS)
1748
-
1749
- for process_name in self.devices.keys():
1750
-
1751
- if str.startswith(process_name, "AEU"):
1752
-
1753
- process_widget: ProcessWidget = self.process_widgets[process_name]
1754
-
1755
- if process_widget.status_led.color == Indic.RED:
1756
-
1757
- process_widget.start_stop_button.setDisabled(True)
1758
- process_widget.sim_option_button.setEnabled(False)
1759
-
1760
- # In order not to overload the Process Manager, we loop through the list of devices again and start the CS
1761
- # one-by-one
1762
-
1763
- with ProcessManagerProxy() as pm:
1764
-
1765
- for process_name in self.devices.keys():
1766
-
1767
- if str.startswith(process_name, "AEU"):
1768
-
1769
- process_widget: ProcessWidget = self.process_widgets[process_name]
1770
-
1771
- if process_widget.status_led.color == Indic.RED:
1772
-
1773
- self.monitoring_workers[process_name].start_stop_cs_button_clicked = True
1774
-
1775
- sim_mode = self.process_widgets[process_name].is_simulator_mode
1776
- response: Response = pm.start_cs(process_name, sim_mode)
1777
-
1778
- if not response.successful:
1779
- gui_process = SubProcess("MyApp", [sys.executable, "-m",
1780
- "egse.procman.cannot_start_process_popup",
1781
- "--process_name", process_name,
1782
- "--message", response.message])
1783
- gui_process.execute(detach_from_parent=True)
1784
-
1785
- def stop_all_aeu_cs(self):
1786
- """ Shut down the AEU Control Servers in one go."""
1787
-
1788
- thread = threading.Thread(target=self._stop_all_aeu_cs)
1789
-
1790
- thread.daemon = True
1791
- thread.start()
1792
-
1793
- def _stop_all_aeu_cs(self):
1794
-
1795
- # First make sure that the start/stop buttons in the process widgets show the hourglass icon (denoting is going
1796
- # on with that CD) and that the simulator option button is disabled (so you cannot switch between simulator and
1797
- # operational mode while starting the CS)
1798
-
1799
- for process_name in self.devices.keys():
1800
-
1801
- if str.startswith(process_name, "AEU"):
1802
-
1803
- process_widget: ProcessWidget = self.process_widgets[process_name]
1804
-
1805
- if process_widget.status_led.color != Indic.RED:
1806
- process_widget.start_stop_button.setDisabled(True)
1807
-
1808
- # In order not to overload the Process Manager, we loop through the list of devices again and start the CS
1809
- # one-by-one
1810
-
1811
- with ProcessManagerProxy() as pm:
1812
-
1813
- for process_name in reversed(self.devices.keys()):
1814
-
1815
- if str.startswith(process_name, "AEU"):
1816
-
1817
- process_widget: ProcessWidget = self.process_widgets[process_name]
1818
-
1819
- if process_widget.status_led.color != Indic.RED:
1820
-
1821
- self.monitoring_workers[process_name].start_stop_cs_button_clicked = True
1822
- pm.shut_down_cs(process_name)
1823
-
1824
-
1825
- # def start_stop_fitsgen(self):
1826
- # """ Start/stop the FITS generation.
1827
- #
1828
- # Depending on the selection state of the FITS generation button, the FITS generation will be started or stopped
1829
- # (this is done in a separate thread).
1830
- # """
1831
- #
1832
- # if self.fitsgen_button.is_selected():
1833
- # thread = threading.Thread(target=stop_fitsgen)
1834
- # else:
1835
- # thread = threading.Thread(target=start_fitsgen)
1836
- #
1837
- # thread.daemon = True
1838
- # thread.start()
1839
- #
1840
- # def start_stop_fov_hk(self):
1841
- # """ Start/stop the generation of FOV HK.
1842
- #
1843
- # Depending on the selection state of the FOV HK generation button, the FOV HK generation will be started or
1844
- # stopped (this is done in a separate thread).
1845
- # """
1846
- #
1847
- # if self.fov_hk_button.is_selected():
1848
- # thread = threading.Thread(target=stop_fov_hk)
1849
- # else:
1850
- # thread = threading.Thread(target=start_fov_hk)
1851
- #
1852
- # thread.daemon = True
1853
- # thread.start()
1854
- #
1855
- # def start_stop_n_fee_hk(self):
1856
- # """ Start/stop the generation of N-FEE HK.
1857
- #
1858
- # Depending on the selection state of the N-FEE HK generation button, the N-FEE HK generation will be started or
1859
- # stopped (this is done in a separate thread).
1860
- # """
1861
- #
1862
- # if self.n_fee_hk_button.is_selected():
1863
- # thread = threading.Thread(target=stop_n_fee_hk)
1864
- # else:
1865
- # thread = threading.Thread(target=start_n_fee_hk)
1866
- #
1867
- # thread.daemon = True
1868
- # thread.start()
1869
-
1870
- def create_overview_widget_core(self):
1871
- """ Create a frame with one process widget per core process."""
1872
-
1873
- # Core processes
1874
-
1875
- self.overview_widget_core_layout = QVBoxLayout()
1876
-
1877
- for process_name in self.core.keys():
1878
-
1879
- process_widget = ProcessWidget(
1880
- process_name, self.core[process_name], self,
1881
- include_start_stop_button=False)
1882
- self.process_widgets[process_name] = process_widget
1883
- self.process_widgets_core[process_name] = process_widget
1884
-
1885
- self.overview_widget_core_layout.addWidget(process_widget)
1886
-
1887
- self.logger_widget = LogWidget(self)
1888
- self.overview_widget_core_layout.addWidget(self.logger_widget)
1889
-
1890
- self.overview_widget_core = QGroupBox("Services/Core", self)
1891
- self.overview_widget_core.setLayout(self.overview_widget_core_layout)
1892
- self.overview_widget_core.setToolTip(
1893
- "EGSE core processes: must be running at all times.")
1894
-
1895
- def create_overview_widget_file_services(self):
1896
-
1897
- # File generation processes
1898
-
1899
- self.overview_widget_file_services_layout = QVBoxLayout()
1900
-
1901
- self.fitsgen_widget = FitsgenWidget(self)
1902
- self.overview_widget_file_services_layout.addWidget(self.fitsgen_widget)
1903
-
1904
- self.fov_hk_widget = FovHkWidget(self)
1905
- self.overview_widget_file_services_layout.addWidget(self.fov_hk_widget)
1906
-
1907
- self.n_fee_hk_widget = NFeeHkWidget(self)
1908
- self.overview_widget_file_services_layout.addWidget(self.n_fee_hk_widget)
1909
-
1910
- self.overview_widget_file_services = QGroupBox("File Generation Processes", self)
1911
- self.overview_widget_file_services.setLayout(self.overview_widget_file_services_layout)
1912
- # self.overview_widget_file_services.setToolTip(
1913
- # "EGSE core processes: must be running at all times.")
1914
-
1915
- def closeEvent(self, close_event: QCloseEvent) -> None:
1916
- """ Make sure that all threads are stopped when the GUI is closed.
1917
-
1918
- Args:
1919
- - close_event: Close event received when the GUI is closed.
1920
- """
1921
- for monitoring_worker in self.monitoring_workers.values():
1922
- monitoring_worker.active = False
1923
-
1924
- for monitoring_thread in self.monitoring_threads.values():
1925
- monitoring_thread.quit()
1926
-
1927
- self.setup_monitoring_worker.active = False
1928
- self.setup_monitoring_thread.quit()
1929
-
1930
- self.logger_monitoring_worker.active = False
1931
- self.logger_monitoring_thread.quit()
1932
-
1933
- self.fitsgen_monitoring_worker.active = False
1934
- self.fitsgen_monitoring_thread.quit()
1935
-
1936
- self.fov_hk_monitoring_worker.active = False
1937
- self.fov_hk_monitoring_thread.quit()
1938
-
1939
- self.n_fee_hk_monitoring_worker.active = False
1940
- self.n_fee_hk_monitoring_thread.quit()
1941
-
1942
- # Group the waiting
1943
- for monitoring_thread in self.monitoring_threads.values():
1944
- monitoring_thread.wait()
1945
-
1946
- self.setup_monitoring_thread.wait()
1947
- self.logger_monitoring_thread.wait()
1948
- self.fitsgen_monitoring_thread.wait()
1949
- self.fov_hk_monitoring_thread.wait()
1950
- self.n_fee_hk_monitoring_thread.wait()
1951
-
1952
- class ProcessManagerUIModel:
1953
-
1954
- def __init__(self):
1955
- """ Initialisation of the Process Manager UI model."""
1956
-
1957
- try:
1958
-
1959
- self.process_manager = ProcessManagerProxy()
1960
-
1961
- except ConnectionError:
1962
-
1963
- self.process_manager = None
1964
-
1965
- def is_connected(self):
1966
- """ Checks whether the Process Manager Control Server is active.
1967
-
1968
- Checks whether a connection to the Process Manager Control Server has been established.
1969
-
1970
- Returns:
1971
- - True if a connection to the Process Manager Control Server has been established; False otherwise.
1972
- """
1973
-
1974
- return self.process_manager.ping() and self.process_manager.is_cs_connected()
1975
-
1976
-
1977
- class ProcessManagerUIController:
1978
-
1979
- def __init__(self, model: ProcessManagerUIModel, view: ProcessManagerUIView):
1980
- """ Initialisation of the Controller for the Process Manager GUI.
1981
-
1982
- Args:
1983
- - model: Process Manager UI model.
1984
- - view: Process Manager UI view.
1985
- """
1986
-
1987
- self.model = model
1988
- self.view = view
1989
-
1990
-
1991
- def main():
1992
- """ Main method to launch the Process Manager GUI."""
1993
- lock_file = QLockFile(str(Path("~/pm_ui.app.lock").expanduser()))
1994
-
1995
- multiprocessing.current_process().name = "pm_ui"
1996
- app = QApplication(sys.argv)
1997
- app.setWindowIcon(QIcon(str(get_resource(":/icons/pm_ui.svg"))))
1998
-
1999
- if lock_file.tryLock(100):
2000
- process_status = ProcessStatus()
2001
-
2002
- timer_thread = threading.Thread(target=do_every, args=(10, process_status.update))
2003
- timer_thread.daemon = True
2004
- timer_thread.start()
2005
-
2006
- start_http_server(GUI_SETTINGS.METRICS_PORT)
2007
-
2008
-
2009
- # Check whether the Process Manager CS is running
2010
- # (show a warning in a pop-up window if it's not)
2011
-
2012
- try:
2013
-
2014
- with ProcessManagerProxy():
2015
-
2016
- if not is_configuration_manager_active():
2017
-
2018
- description = "Could not connect to Configuration Manager"
2019
- into_text = (
2020
- "The GUI will start, but without listed processes. "
2021
- "Please, check if the Configuration Manager is running and start the server if needed."
2022
- # "Otherwise, check if the correct HOSTNAME for the Configuration Manager is set in the "
2023
- # "Settings.yaml "
2024
- # "configuration file."
2025
- "The Process Manager GUI will have to be re-started after that."
2026
- )
2027
-
2028
- show_info_message(description, into_text)
2029
-
2030
- except ConnectionError:
2031
-
2032
- description = "Could not connect to Process Manager Control Server"
2033
-
2034
- into_text = (
2035
- "The GUI will start, but the connection button will show a disconnected state. "
2036
- "Please, check if the Control Server is running and start the server if needed. "
2037
- "Otherwise, check if the correct HOSTNAME for the control server is set in the "
2038
- "Settings.yaml "
2039
- "configuration file."
2040
- )
2041
-
2042
- show_info_message(description, into_text)
2043
-
2044
- # proxy = ProcessManagerProxy()
2045
-
2046
- # if not proxy.ping():
2047
- # description = "Could not connect to Process Manager Control Server"
2048
- # into_text = (
2049
- # "The GUI will start, but the connection button will show a disconnected state. "
2050
- # "Please check if the Control Server is running and start the server if needed. "
2051
- # "Otherwise, check if the correct HOSTNAME for the control server is set in the "
2052
- # "Settings.yaml "
2053
- # "configuration file."
2054
- # )
2055
-
2056
- # show_info_message(description, into_text)
2057
-
2058
- # proxy.disconnect_cs()
2059
-
2060
- # Create the Process Manager GUI, following the MVC-model
2061
-
2062
- view = ProcessManagerUIView()
2063
- model = ProcessManagerUIModel()
2064
- ProcessManagerUIController(model, view)
2065
-
2066
- view.show()
2067
-
2068
- return app.exec_()
2069
- else:
2070
- error_message = QMessageBox()
2071
- error_message.setIcon(QMessageBox.Warning)
2072
- error_message.setWindowTitle("Error")
2073
- error_message.setText("The Process Manager (PM) GUI application is already running!")
2074
- error_message.setStandardButtons(QMessageBox.Ok)
2075
-
2076
- return error_message.exec()
2077
-
2078
-
2079
- if __name__ == '__main__':
2080
-
2081
- sys.exit(main())