cgse 2024.7.0__py3-none-any.whl → 2025.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- README.md +27 -0
- bump.py +85 -0
- cgse-2025.0.2.dist-info/METADATA +38 -0
- cgse-2025.0.2.dist-info/RECORD +5 -0
- {cgse-2024.7.0.dist-info → cgse-2025.0.2.dist-info}/WHEEL +1 -2
- cgse-2024.7.0.dist-info/COPYING +0 -674
- cgse-2024.7.0.dist-info/COPYING.LESSER +0 -165
- cgse-2024.7.0.dist-info/METADATA +0 -144
- cgse-2024.7.0.dist-info/RECORD +0 -660
- cgse-2024.7.0.dist-info/entry_points.txt +0 -75
- cgse-2024.7.0.dist-info/top_level.txt +0 -2
- egse/__init__.py +0 -12
- egse/__main__.py +0 -32
- egse/aeu/aeu.py +0 -5238
- egse/aeu/aeu_awg.yaml +0 -265
- egse/aeu/aeu_crio.yaml +0 -273
- egse/aeu/aeu_cs.py +0 -627
- egse/aeu/aeu_devif.py +0 -321
- egse/aeu/aeu_main_ui.py +0 -903
- egse/aeu/aeu_metrics.py +0 -131
- egse/aeu/aeu_protocol.py +0 -463
- egse/aeu/aeu_psu.yaml +0 -204
- egse/aeu/aeu_ui.py +0 -873
- egse/aeu/arbdata/FccdRead.arb +0 -2
- egse/aeu/arbdata/FccdRead_min_points.arb +0 -2
- egse/aeu/arbdata/HeaterSync_FccdRead.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead25.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead31_25.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead37_50.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead43_75.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead50.arb +0 -2
- egse/aeu/arbdata/Heater_FccdRead_min_points.arb +0 -2
- egse/aeu/arbdata/ccdRead25.arb +0 -2
- egse/aeu/arbdata/ccdRead25_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead31_25.arb +0 -2
- egse/aeu/arbdata/ccdRead31_25_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead37_50.arb +0 -2
- egse/aeu/arbdata/ccdRead37_50_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead43_75.arb +0 -2
- egse/aeu/arbdata/ccdRead43_75_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead50.arb +0 -2
- egse/aeu/arbdata/ccdRead50_150ms.arb +0 -2
- egse/alert/__init__.py +0 -1049
- egse/alert/alertman.yaml +0 -37
- egse/alert/alertman_cs.py +0 -233
- egse/alert/alertman_ui.py +0 -600
- egse/alert/gsm/beaglebone.py +0 -138
- egse/alert/gsm/beaglebone.yaml +0 -51
- egse/alert/gsm/beaglebone_cs.py +0 -108
- egse/alert/gsm/beaglebone_devif.py +0 -122
- egse/alert/gsm/beaglebone_protocol.py +0 -46
- egse/bits.py +0 -318
- egse/camera.py +0 -44
- egse/collimator/__init__.py +0 -0
- egse/collimator/fcul/__init__.py +0 -0
- egse/collimator/fcul/ogse.py +0 -1077
- egse/collimator/fcul/ogse.yaml +0 -14
- egse/collimator/fcul/ogse_cs.py +0 -154
- egse/collimator/fcul/ogse_devif.py +0 -358
- egse/collimator/fcul/ogse_protocol.py +0 -132
- egse/collimator/fcul/ogse_sim.py +0 -431
- egse/collimator/fcul/ogse_ui.py +0 -1108
- egse/command.py +0 -699
- egse/config.py +0 -410
- egse/confman/__init__.py +0 -1058
- egse/confman/confman.yaml +0 -70
- egse/confman/confman_cs.py +0 -240
- egse/confman/confman_ui.py +0 -381
- egse/confman/setup_ui.py +0 -565
- egse/control.py +0 -632
- egse/coordinates/__init__.py +0 -534
- egse/coordinates/avoidance.py +0 -100
- egse/coordinates/cslmodel.py +0 -127
- egse/coordinates/laser_tracker_to_dict.py +0 -122
- egse/coordinates/point.py +0 -707
- egse/coordinates/pyplot.py +0 -194
- egse/coordinates/referenceFrame.py +0 -1279
- egse/coordinates/refmodel.py +0 -737
- egse/coordinates/rotationMatrix.py +0 -85
- egse/coordinates/transform3d_addon.py +0 -419
- egse/csl/__init__.py +0 -50
- egse/csl/commanding.py +0 -78
- egse/csl/icons/hexapod-connected-selected.svg +0 -30
- egse/csl/icons/hexapod-connected.svg +0 -30
- egse/csl/icons/hexapod-homing-selected.svg +0 -68
- egse/csl/icons/hexapod-homing.svg +0 -68
- egse/csl/icons/hexapod-retract-selected.svg +0 -56
- egse/csl/icons/hexapod-retract.svg +0 -51
- egse/csl/icons/hexapod-zero-selected.svg +0 -56
- egse/csl/icons/hexapod-zero.svg +0 -56
- egse/csl/icons/logo-puna.svg +0 -92
- egse/csl/icons/stop.svg +0 -1
- egse/csl/initialisation.py +0 -102
- egse/csl/mech_pos_settings.yaml +0 -18
- egse/das.py +0 -1240
- egse/das.yaml +0 -7
- egse/data/conf/SETUP_CSL_00000_170620_150000.yaml +0 -5
- egse/data/conf/SETUP_CSL_00001_170620_151010.yaml +0 -69
- egse/data/conf/SETUP_CSL_00002_170620_151020.yaml +0 -69
- egse/data/conf/SETUP_CSL_00003_170620_151030.yaml +0 -69
- egse/data/conf/SETUP_CSL_00004_170620_151040.yaml +0 -69
- egse/data/conf/SETUP_CSL_00005_170620_151050.yaml +0 -69
- egse/data/conf/SETUP_CSL_00006_170620_151060.yaml +0 -69
- egse/data/conf/SETUP_CSL_00007_170620_151070.yaml +0 -69
- egse/data/conf/SETUP_CSL_00008_170620_151080.yaml +0 -75
- egse/data/conf/SETUP_CSL_00010_210308_083016.yaml +0 -138
- egse/data/conf/SETUP_INTA_00000_170620_150000.yaml +0 -4
- egse/data/conf/SETUP_SRON_00000_170620_150000.yaml +0 -4
- egse/decorators.py +0 -514
- egse/device.py +0 -269
- egse/dpu/__init__.py +0 -2698
- egse/dpu/ccd_ui.py +0 -514
- egse/dpu/dpu.py +0 -783
- egse/dpu/dpu.yaml +0 -153
- egse/dpu/dpu_cs.py +0 -272
- egse/dpu/dpu_ui.py +0 -671
- egse/dpu/fitsgen.py +0 -2096
- egse/dpu/fitsgen_ui.py +0 -399
- egse/dpu/hdf5_model.py +0 -332
- egse/dpu/hdf5_ui.py +0 -277
- egse/dpu/hdf5_viewer.py +0 -506
- egse/dpu/hk_ui.py +0 -468
- egse/dpu_commands.py +0 -81
- egse/dsi/__init__.py +0 -33
- egse/dsi/_libesl.py +0 -232
- egse/dsi/constants.py +0 -296
- egse/dsi/esl.py +0 -630
- egse/dsi/rmap.py +0 -444
- egse/dsi/rmapci.py +0 -39
- egse/dsi/spw.py +0 -335
- egse/dsi/spw_state.py +0 -29
- egse/dummy.py +0 -318
- egse/dyndummy.py +0 -179
- egse/env.py +0 -278
- egse/exceptions.py +0 -88
- egse/fdir/__init__.py +0 -26
- egse/fdir/fdir_manager.py +0 -85
- egse/fdir/fdir_manager.yaml +0 -37
- egse/fdir/fdir_manager_controller.py +0 -136
- egse/fdir/fdir_manager_cs.py +0 -164
- egse/fdir/fdir_manager_interface.py +0 -15
- egse/fdir/fdir_remote.py +0 -73
- egse/fdir/fdir_remote.yaml +0 -30
- egse/fdir/fdir_remote_controller.py +0 -30
- egse/fdir/fdir_remote_cs.py +0 -94
- egse/fdir/fdir_remote_interface.py +0 -9
- egse/fdir/fdir_remote_popup.py +0 -26
- egse/fee/__init__.py +0 -106
- egse/fee/f_fee_register.yaml +0 -43
- egse/fee/feesim.py +0 -914
- egse/fee/n_fee_hk.py +0 -768
- egse/fee/nfee.py +0 -188
- egse/filterwheel/__init__.py +0 -4
- egse/filterwheel/eksma/__init__.py +0 -49
- egse/filterwheel/eksma/fw8smc4.py +0 -657
- egse/filterwheel/eksma/fw8smc4.yaml +0 -121
- egse/filterwheel/eksma/fw8smc4_cs.py +0 -144
- egse/filterwheel/eksma/fw8smc4_devif.py +0 -473
- egse/filterwheel/eksma/fw8smc4_protocol.py +0 -82
- egse/filterwheel/eksma/fw8smc4_ui.py +0 -940
- egse/filterwheel/eksma/fw8smc5.py +0 -115
- egse/filterwheel/eksma/fw8smc5.yaml +0 -105
- egse/filterwheel/eksma/fw8smc5_controller.py +0 -307
- egse/filterwheel/eksma/fw8smc5_cs.py +0 -141
- egse/filterwheel/eksma/fw8smc5_interface.py +0 -65
- egse/filterwheel/eksma/fw8smc5_simulator.py +0 -29
- egse/filterwheel/eksma/fw8smc5_ui.py +0 -1065
- egse/filterwheel/eksma/testpythonfw.py +0 -215
- egse/fov/__init__.py +0 -65
- egse/fov/fov_hk.py +0 -710
- egse/fov/fov_ui.py +0 -859
- egse/fov/fov_ui_controller.py +0 -140
- egse/fov/fov_ui_model.py +0 -200
- egse/fov/fov_ui_view.py +0 -345
- egse/gimbal/__init__.py +0 -32
- egse/gimbal/symetrie/__init__.py +0 -26
- egse/gimbal/symetrie/alpha.py +0 -586
- egse/gimbal/symetrie/generic_gimbal_ui.py +0 -1521
- egse/gimbal/symetrie/gimbal.py +0 -877
- egse/gimbal/symetrie/gimbal.yaml +0 -168
- egse/gimbal/symetrie/gimbal_cs.py +0 -183
- egse/gimbal/symetrie/gimbal_protocol.py +0 -138
- egse/gimbal/symetrie/gimbal_ui.py +0 -361
- egse/gimbal/symetrie/pmac.py +0 -1006
- egse/gimbal/symetrie/pmac_regex.py +0 -83
- egse/graph.py +0 -132
- egse/gui/__init__.py +0 -47
- egse/gui/buttons.py +0 -378
- egse/gui/focalplane.py +0 -1285
- egse/gui/formatter.py +0 -10
- egse/gui/led.py +0 -162
- egse/gui/limitswitch.py +0 -143
- egse/gui/mechanisms.py +0 -587
- egse/gui/states.py +0 -148
- egse/gui/stripchart.py +0 -729
- egse/gui/styles.qss +0 -48
- egse/gui/switch.py +0 -112
- egse/h5.py +0 -274
- egse/help/__init__.py +0 -0
- egse/help/help_ui.py +0 -126
- egse/hexapod/__init__.py +0 -32
- egse/hexapod/symetrie/__init__.py +0 -137
- egse/hexapod/symetrie/alpha.py +0 -874
- egse/hexapod/symetrie/dynalpha.py +0 -1387
- egse/hexapod/symetrie/hexapod_ui.py +0 -1516
- egse/hexapod/symetrie/pmac.py +0 -1010
- egse/hexapod/symetrie/pmac_regex.py +0 -83
- egse/hexapod/symetrie/puna.py +0 -1167
- egse/hexapod/symetrie/puna.yaml +0 -193
- egse/hexapod/symetrie/puna_cs.py +0 -195
- egse/hexapod/symetrie/puna_protocol.py +0 -134
- egse/hexapod/symetrie/puna_ui.py +0 -433
- egse/hexapod/symetrie/punaplus.py +0 -107
- egse/hexapod/symetrie/zonda.py +0 -872
- egse/hexapod/symetrie/zonda.yaml +0 -337
- egse/hexapod/symetrie/zonda_cs.py +0 -172
- egse/hexapod/symetrie/zonda_devif.py +0 -414
- egse/hexapod/symetrie/zonda_protocol.py +0 -123
- egse/hexapod/symetrie/zonda_ui.py +0 -449
- egse/hk.py +0 -791
- egse/icons/aeu-cs-start.svg +0 -117
- egse/icons/aeu-cs-stop.svg +0 -118
- egse/icons/aeu-cs.svg +0 -107
- egse/icons/aeu_cs-started.svg +0 -112
- egse/icons/aeu_cs-stopped.svg +0 -112
- egse/icons/aeu_cs.svg +0 -55
- egse/icons/alert.svg +0 -1
- egse/icons/arrow-double-left.png +0 -0
- egse/icons/arrow-double-right.png +0 -0
- egse/icons/arrow-up.svg +0 -11
- egse/icons/backward.svg +0 -1
- egse/icons/busy.svg +0 -1
- egse/icons/cleaning.svg +0 -115
- egse/icons/color-scheme.svg +0 -1
- egse/icons/cs-connected-alert.svg +0 -91
- egse/icons/cs-connected-disabled.svg +0 -43
- egse/icons/cs-connected.svg +0 -89
- egse/icons/cs-not-connected.svg +0 -44
- egse/icons/double-left-arrow.svg +0 -1
- egse/icons/double-right-arrow.svg +0 -1
- egse/icons/erase-disabled.svg +0 -19
- egse/icons/erase.svg +0 -59
- egse/icons/fitsgen-start.svg +0 -47
- egse/icons/fitsgen-stop.svg +0 -48
- egse/icons/fitsgen.svg +0 -1
- egse/icons/forward.svg +0 -1
- egse/icons/fov-hk-start.svg +0 -33
- egse/icons/fov-hk-stop.svg +0 -37
- egse/icons/fov-hk.svg +0 -1
- egse/icons/front-desk.svg +0 -1
- egse/icons/home-actioned.svg +0 -15
- egse/icons/home-disabled.svg +0 -15
- egse/icons/home.svg +0 -13
- egse/icons/info.svg +0 -1
- egse/icons/invalid.png +0 -0
- egse/icons/led-green.svg +0 -20
- egse/icons/led-grey.svg +0 -20
- egse/icons/led-orange.svg +0 -20
- egse/icons/led-red.svg +0 -20
- egse/icons/led-square-green.svg +0 -134
- egse/icons/led-square-grey.svg +0 -134
- egse/icons/led-square-orange.svg +0 -134
- egse/icons/led-square-red.svg +0 -134
- egse/icons/limit-switch-all-green.svg +0 -115
- egse/icons/limit-switch-all-red.svg +0 -117
- egse/icons/limit-switch-el+.svg +0 -116
- egse/icons/limit-switch-el-.svg +0 -117
- egse/icons/location-marker.svg +0 -1
- egse/icons/logo-dpu.svg +0 -48
- egse/icons/logo-gimbal.svg +0 -112
- egse/icons/logo-huber.svg +0 -23
- egse/icons/logo-ogse.svg +0 -31
- egse/icons/logo-puna.svg +0 -92
- egse/icons/logo-tcs.svg +0 -29
- egse/icons/logo-zonda.svg +0 -66
- egse/icons/maximize.svg +0 -1
- egse/icons/meter.svg +0 -1
- egse/icons/more.svg +0 -45
- egse/icons/n-fee-hk-start.svg +0 -24
- egse/icons/n-fee-hk-stop.svg +0 -25
- egse/icons/n-fee-hk.svg +0 -83
- egse/icons/observing-off.svg +0 -46
- egse/icons/observing-on.svg +0 -46
- egse/icons/open-document-hdf5.png +0 -0
- egse/icons/open-document-hdf5.svg +0 -21
- egse/icons/ops-mode.svg +0 -1
- egse/icons/play-green.svg +0 -17
- egse/icons/plugged-disabled.svg +0 -27
- egse/icons/plugged.svg +0 -21
- egse/icons/pm_ui.svg +0 -1
- egse/icons/power-button-green.svg +0 -27
- egse/icons/power-button-red.svg +0 -27
- egse/icons/power-button.svg +0 -27
- egse/icons/radar.svg +0 -1
- egse/icons/radioactive.svg +0 -2
- egse/icons/reload.svg +0 -1
- egse/icons/remote-control-off.svg +0 -28
- egse/icons/remote-control-on.svg +0 -28
- egse/icons/repeat-blue.svg +0 -15
- egse/icons/repeat.svg +0 -1
- egse/icons/settings.svg +0 -1
- egse/icons/shrink.svg +0 -1
- egse/icons/shutter.svg +0 -1
- egse/icons/sign-off.svg +0 -1
- egse/icons/sign-on.svg +0 -1
- egse/icons/sim-mode.svg +0 -1
- egse/icons/small-buttons-go.svg +0 -20
- egse/icons/small-buttons-minus.svg +0 -51
- egse/icons/small-buttons-plus.svg +0 -51
- egse/icons/sponge.svg +0 -220
- egse/icons/start-button-disabled.svg +0 -84
- egse/icons/start-button.svg +0 -50
- egse/icons/stop-button-disabled.svg +0 -84
- egse/icons/stop-button.svg +0 -50
- egse/icons/stop-red.svg +0 -17
- egse/icons/stop.svg +0 -1
- egse/icons/switch-disabled-square.svg +0 -87
- egse/icons/switch-disabled.svg +0 -15
- egse/icons/switch-off-square.svg +0 -87
- egse/icons/switch-off.svg +0 -72
- egse/icons/switch-on-square.svg +0 -87
- egse/icons/switch-on.svg +0 -61
- egse/icons/temperature-control.svg +0 -44
- egse/icons/th_ui_logo.svg +0 -1
- egse/icons/unplugged.svg +0 -23
- egse/icons/unvalid.png +0 -0
- egse/icons/user-interface.svg +0 -1
- egse/icons/vacuum.svg +0 -1
- egse/icons/valid.png +0 -0
- egse/icons/zoom-to-pixel-dark.svg +0 -64
- egse/icons/zoom-to-pixel-white.svg +0 -36
- egse/images/big-rotation-stage.png +0 -0
- egse/images/connected-100.png +0 -0
- egse/images/cross.svg +0 -6
- egse/images/disconnected-100.png +0 -0
- egse/images/gui-icon.png +0 -0
- egse/images/home.svg +0 -6
- egse/images/info-icon.png +0 -0
- egse/images/led-black.svg +0 -89
- egse/images/led-green.svg +0 -85
- egse/images/led-orange.svg +0 -85
- egse/images/led-red.svg +0 -85
- egse/images/load-icon.png +0 -0
- egse/images/load-setup.png +0 -0
- egse/images/load.png +0 -0
- egse/images/pause.png +0 -0
- egse/images/play-button.svg +0 -8
- egse/images/play.png +0 -0
- egse/images/process-status.png +0 -0
- egse/images/restart.png +0 -0
- egse/images/search.png +0 -0
- egse/images/sma.png +0 -0
- egse/images/start.png +0 -0
- egse/images/stop-button.svg +0 -8
- egse/images/stop.png +0 -0
- egse/images/switch-off.svg +0 -48
- egse/images/switch-on.svg +0 -48
- egse/images/undo.png +0 -0
- egse/images/update-button.svg +0 -11
- egse/imageviewer/exposureselection.py +0 -475
- egse/imageviewer/imageviewer.py +0 -198
- egse/imageviewer/matchfocalplane.py +0 -179
- egse/imageviewer/subfieldposition.py +0 -133
- egse/lampcontrol/__init__.py +0 -4
- egse/lampcontrol/beaglebone/beaglebone.py +0 -178
- egse/lampcontrol/beaglebone/beaglebone.yaml +0 -62
- egse/lampcontrol/beaglebone/beaglebone_cs.py +0 -106
- egse/lampcontrol/beaglebone/beaglebone_devif.py +0 -150
- egse/lampcontrol/beaglebone/beaglebone_protocol.py +0 -73
- egse/lampcontrol/energetiq/__init__.py +0 -22
- egse/lampcontrol/energetiq/eq99.yaml +0 -98
- egse/lampcontrol/energetiq/lampEQ99.py +0 -283
- egse/lampcontrol/energetiq/lampEQ99_cs.py +0 -128
- egse/lampcontrol/energetiq/lampEQ99_devif.py +0 -158
- egse/lampcontrol/energetiq/lampEQ99_encode_decode_errors.py +0 -73
- egse/lampcontrol/energetiq/lampEQ99_protocol.py +0 -71
- egse/lampcontrol/energetiq/lampEQ99_ui.py +0 -465
- egse/lib/CentOS-7/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/CentOS-8/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/CentOS-8/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Debian/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Debian/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Debian/libetherspacelink_v35_21.dylib +0 -0
- egse/lib/Linux/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Linux/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Ubuntu-20/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Ubuntu-20/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/gssw/python3-gssw_2.2.3+31f63c9f-1_all.deb +0 -0
- egse/lib/ximc/__pycache__/pyximc.cpython-38 2.pyc +0 -0
- egse/lib/ximc/__pycache__/pyximc.cpython-38.pyc +0 -0
- egse/lib/ximc/libximc.framework/Frameworks/libbindy.dylib +0 -0
- egse/lib/ximc/libximc.framework/Frameworks/libxiwrapper.dylib +0 -0
- egse/lib/ximc/libximc.framework/Headers/ximc.h +0 -5510
- egse/lib/ximc/libximc.framework/Resources/Info.plist +0 -42
- egse/lib/ximc/libximc.framework/Resources/keyfile.sqlite +0 -0
- egse/lib/ximc/libximc.framework/libbindy.so +0 -0
- egse/lib/ximc/libximc.framework/libximc +0 -0
- egse/lib/ximc/libximc.framework/libximc.so +0 -0
- egse/lib/ximc/libximc.framework/libximc.so.7.0.0 +0 -0
- egse/lib/ximc/libximc.framework/libxiwrapper.so +0 -0
- egse/lib/ximc/pyximc.py +0 -922
- egse/listener.py +0 -179
- egse/logger/__init__.py +0 -243
- egse/logger/log_cs.py +0 -321
- egse/metrics.py +0 -102
- egse/mixin.py +0 -464
- egse/monitoring.py +0 -95
- egse/ni/alarms/__init__.py +0 -26
- egse/ni/alarms/cdaq9375.py +0 -300
- egse/ni/alarms/cdaq9375.yaml +0 -89
- egse/ni/alarms/cdaq9375_cs.py +0 -130
- egse/ni/alarms/cdaq9375_devif.py +0 -183
- egse/ni/alarms/cdaq9375_protocol.py +0 -48
- egse/obs_inspection.py +0 -165
- egse/observer.py +0 -41
- egse/obsid.py +0 -163
- egse/powermeter/__init__.py +0 -0
- egse/powermeter/ni/__init__.py +0 -38
- egse/powermeter/ni/cdaq9184.py +0 -224
- egse/powermeter/ni/cdaq9184.yaml +0 -73
- egse/powermeter/ni/cdaq9184_cs.py +0 -130
- egse/powermeter/ni/cdaq9184_devif.py +0 -201
- egse/powermeter/ni/cdaq9184_protocol.py +0 -48
- egse/powermeter/ni/cdaq9184_ui.py +0 -544
- egse/powermeter/thorlabs/__init__.py +0 -25
- egse/powermeter/thorlabs/pm100a.py +0 -380
- egse/powermeter/thorlabs/pm100a.yaml +0 -132
- egse/powermeter/thorlabs/pm100a_cs.py +0 -136
- egse/powermeter/thorlabs/pm100a_devif.py +0 -127
- egse/powermeter/thorlabs/pm100a_protocol.py +0 -80
- egse/powermeter/thorlabs/pm100a_ui.py +0 -725
- egse/process.py +0 -451
- egse/procman/__init__.py +0 -834
- egse/procman/cannot_start_process_popup.py +0 -43
- egse/procman/procman.yaml +0 -49
- egse/procman/procman_cs.py +0 -201
- egse/procman/procman_ui.py +0 -2081
- egse/protocol.py +0 -605
- egse/proxy.py +0 -531
- egse/randomwalk.py +0 -140
- egse/reg.py +0 -585
- egse/reload.py +0 -122
- egse/reprocess.py +0 -693
- egse/resource.py +0 -333
- egse/rmap.py +0 -406
- egse/rst.py +0 -135
- egse/search.py +0 -182
- egse/serialdevice.py +0 -190
- egse/services.py +0 -247
- egse/services.yaml +0 -68
- egse/settings.py +0 -379
- egse/settings.yaml +0 -980
- egse/setup.py +0 -1181
- egse/shutter/__init__.py +0 -0
- egse/shutter/thorlabs/__init__.py +0 -19
- egse/shutter/thorlabs/ksc101.py +0 -205
- egse/shutter/thorlabs/ksc101.yaml +0 -105
- egse/shutter/thorlabs/ksc101_cs.py +0 -136
- egse/shutter/thorlabs/ksc101_devif.py +0 -201
- egse/shutter/thorlabs/ksc101_protocol.py +0 -71
- egse/shutter/thorlabs/ksc101_ui.py +0 -548
- egse/shutter/thorlabs/sc10.py +0 -82
- egse/shutter/thorlabs/sc10.yaml +0 -52
- egse/shutter/thorlabs/sc10_controller.py +0 -81
- egse/shutter/thorlabs/sc10_cs.py +0 -108
- egse/shutter/thorlabs/sc10_interface.py +0 -25
- egse/shutter/thorlabs/sc10_simulator.py +0 -30
- egse/simulator.py +0 -41
- egse/slack.py +0 -61
- egse/socketdevice.py +0 -218
- egse/sockets.py +0 -218
- egse/spw.py +0 -1401
- egse/stages/__init__.py +0 -12
- egse/stages/aerotech/ensemble.py +0 -245
- egse/stages/aerotech/ensemble.yaml +0 -205
- egse/stages/aerotech/ensemble_controller.py +0 -275
- egse/stages/aerotech/ensemble_cs.py +0 -110
- egse/stages/aerotech/ensemble_interface.py +0 -132
- egse/stages/aerotech/ensemble_parameters.py +0 -433
- egse/stages/aerotech/ensemble_simulator.py +0 -27
- egse/stages/aerotech/mgse_sim.py +0 -188
- egse/stages/arun/smd3.py +0 -110
- egse/stages/arun/smd3.yaml +0 -68
- egse/stages/arun/smd3_controller.py +0 -470
- egse/stages/arun/smd3_cs.py +0 -112
- egse/stages/arun/smd3_interface.py +0 -53
- egse/stages/arun/smd3_simulator.py +0 -27
- egse/stages/arun/smd3_stop.py +0 -16
- egse/stages/huber/__init__.py +0 -49
- egse/stages/huber/smc9300.py +0 -920
- egse/stages/huber/smc9300.yaml +0 -63
- egse/stages/huber/smc9300_cs.py +0 -178
- egse/stages/huber/smc9300_devif.py +0 -345
- egse/stages/huber/smc9300_protocol.py +0 -113
- egse/stages/huber/smc9300_sim.py +0 -547
- egse/stages/huber/smc9300_ui.py +0 -973
- egse/state.py +0 -173
- egse/statemachine.py +0 -274
- egse/storage/__init__.py +0 -1067
- egse/storage/persistence.py +0 -2295
- egse/storage/storage.yaml +0 -79
- egse/storage/storage_cs.py +0 -231
- egse/styles/dark.qss +0 -343
- egse/styles/default.qss +0 -48
- egse/synoptics/__init__.py +0 -417
- egse/synoptics/syn.yaml +0 -9
- egse/synoptics/syn_cs.py +0 -195
- egse/system.py +0 -1611
- egse/tcs/__init__.py +0 -14
- egse/tcs/tcs.py +0 -879
- egse/tcs/tcs.yaml +0 -14
- egse/tcs/tcs_cs.py +0 -202
- egse/tcs/tcs_devif.py +0 -292
- egse/tcs/tcs_protocol.py +0 -180
- egse/tcs/tcs_sim.py +0 -177
- egse/tcs/tcs_ui.py +0 -543
- egse/tdms.py +0 -171
- egse/tempcontrol/__init__.py +0 -23
- egse/tempcontrol/agilent/agilent34970.py +0 -109
- egse/tempcontrol/agilent/agilent34970.yaml +0 -44
- egse/tempcontrol/agilent/agilent34970_cs.py +0 -114
- egse/tempcontrol/agilent/agilent34970_devif.py +0 -182
- egse/tempcontrol/agilent/agilent34970_protocol.py +0 -96
- egse/tempcontrol/agilent/agilent34972.py +0 -111
- egse/tempcontrol/agilent/agilent34972.yaml +0 -44
- egse/tempcontrol/agilent/agilent34972_cs.py +0 -115
- egse/tempcontrol/agilent/agilent34972_devif.py +0 -189
- egse/tempcontrol/agilent/agilent34972_protocol.py +0 -98
- egse/tempcontrol/beaglebone/beaglebone.py +0 -341
- egse/tempcontrol/beaglebone/beaglebone.yaml +0 -110
- egse/tempcontrol/beaglebone/beaglebone_cs.py +0 -117
- egse/tempcontrol/beaglebone/beaglebone_protocol.py +0 -134
- egse/tempcontrol/beaglebone/beaglebone_ui.py +0 -674
- egse/tempcontrol/digalox/digalox.py +0 -115
- egse/tempcontrol/digalox/digalox.yaml +0 -36
- egse/tempcontrol/digalox/digalox_cs.py +0 -108
- egse/tempcontrol/digalox/digalox_protocol.py +0 -56
- egse/tempcontrol/keithley/__init__.py +0 -33
- egse/tempcontrol/keithley/daq6510.py +0 -662
- egse/tempcontrol/keithley/daq6510.yaml +0 -105
- egse/tempcontrol/keithley/daq6510_cs.py +0 -163
- egse/tempcontrol/keithley/daq6510_devif.py +0 -343
- egse/tempcontrol/keithley/daq6510_protocol.py +0 -79
- egse/tempcontrol/keithley/daq6510_sim.py +0 -186
- egse/tempcontrol/lakeshore/__init__.py +0 -33
- egse/tempcontrol/lakeshore/lsci.py +0 -361
- egse/tempcontrol/lakeshore/lsci.yaml +0 -162
- egse/tempcontrol/lakeshore/lsci_cs.py +0 -174
- egse/tempcontrol/lakeshore/lsci_devif.py +0 -292
- egse/tempcontrol/lakeshore/lsci_protocol.py +0 -76
- egse/tempcontrol/lakeshore/lsci_ui.py +0 -387
- egse/tempcontrol/ni/__init__.py +0 -0
- egse/tempcontrol/spid/spid.py +0 -109
- egse/tempcontrol/spid/spid.yaml +0 -81
- egse/tempcontrol/spid/spid_controller.py +0 -279
- egse/tempcontrol/spid/spid_cs.py +0 -136
- egse/tempcontrol/spid/spid_protocol.py +0 -107
- egse/tempcontrol/spid/spid_ui.py +0 -723
- egse/tempcontrol/srs/__init__.py +0 -22
- egse/tempcontrol/srs/ptc10.py +0 -867
- egse/tempcontrol/srs/ptc10.yaml +0 -227
- egse/tempcontrol/srs/ptc10_cs.py +0 -128
- egse/tempcontrol/srs/ptc10_devif.py +0 -116
- egse/tempcontrol/srs/ptc10_protocol.py +0 -39
- egse/tempcontrol/srs/ptc10_ui.py +0 -906
- egse/ups/apc/apc.py +0 -236
- egse/ups/apc/apc.yaml +0 -45
- egse/ups/apc/apc_cs.py +0 -101
- egse/ups/apc/apc_protocol.py +0 -125
- egse/user.yaml +0 -7
- egse/vacuum/beaglebone/beaglebone.py +0 -149
- egse/vacuum/beaglebone/beaglebone.yaml +0 -44
- egse/vacuum/beaglebone/beaglebone_cs.py +0 -108
- egse/vacuum/beaglebone/beaglebone_devif.py +0 -159
- egse/vacuum/beaglebone/beaglebone_protocol.py +0 -192
- egse/vacuum/beaglebone/beaglebone_ui.py +0 -638
- egse/vacuum/instrutech/igm402.py +0 -91
- egse/vacuum/instrutech/igm402.yaml +0 -90
- egse/vacuum/instrutech/igm402_controller.py +0 -124
- egse/vacuum/instrutech/igm402_cs.py +0 -108
- egse/vacuum/instrutech/igm402_interface.py +0 -49
- egse/vacuum/instrutech/igm402_simulator.py +0 -36
- egse/vacuum/keller/kellerBus.py +0 -256
- egse/vacuum/keller/leo3.py +0 -100
- egse/vacuum/keller/leo3.yaml +0 -38
- egse/vacuum/keller/leo3_controller.py +0 -81
- egse/vacuum/keller/leo3_cs.py +0 -101
- egse/vacuum/keller/leo3_interface.py +0 -33
- egse/vacuum/mks/evision.py +0 -86
- egse/vacuum/mks/evision.yaml +0 -75
- egse/vacuum/mks/evision_cs.py +0 -101
- egse/vacuum/mks/evision_devif.py +0 -313
- egse/vacuum/mks/evision_interface.py +0 -60
- egse/vacuum/mks/evision_simulator.py +0 -24
- egse/vacuum/mks/evision_ui.py +0 -701
- egse/vacuum/pfeiffer/acp40.py +0 -87
- egse/vacuum/pfeiffer/acp40.yaml +0 -60
- egse/vacuum/pfeiffer/acp40_controller.py +0 -117
- egse/vacuum/pfeiffer/acp40_cs.py +0 -109
- egse/vacuum/pfeiffer/acp40_interface.py +0 -40
- egse/vacuum/pfeiffer/acp40_simulator.py +0 -37
- egse/vacuum/pfeiffer/tc400.py +0 -87
- egse/vacuum/pfeiffer/tc400.yaml +0 -83
- egse/vacuum/pfeiffer/tc400_controller.py +0 -136
- egse/vacuum/pfeiffer/tc400_cs.py +0 -109
- egse/vacuum/pfeiffer/tc400_interface.py +0 -70
- egse/vacuum/pfeiffer/tc400_simulator.py +0 -35
- egse/vacuum/pfeiffer/tpg261.py +0 -80
- egse/vacuum/pfeiffer/tpg261.yaml +0 -66
- egse/vacuum/pfeiffer/tpg261_controller.py +0 -150
- egse/vacuum/pfeiffer/tpg261_cs.py +0 -109
- egse/vacuum/pfeiffer/tpg261_interface.py +0 -59
- egse/vacuum/pfeiffer/tpg261_simulator.py +0 -23
- egse/version.py +0 -174
- egse/visitedpositions.py +0 -398
- egse/windowing.py +0 -213
- egse/zmq/__init__.py +0 -28
- egse/zmq/spw.py +0 -160
- egse/zmq_ser.py +0 -41
- scripts/alerts/cold.yaml +0 -278
- scripts/alerts/example_alerts.yaml +0 -54
- scripts/alerts/transition.yaml +0 -14
- scripts/alerts/warm.yaml +0 -49
- scripts/analyse_n_fee_hk_data.py +0 -52
- scripts/check_hdf5_files.py +0 -192
- scripts/check_register_sync.py +0 -47
- scripts/check_tcs_calib_coef.py +0 -90
- scripts/correct_ccd_cold_temperature_cal.py +0 -157
- scripts/create_hdf5_report.py +0 -293
- scripts/csl_model.py +0 -420
- scripts/csl_restore_setup.py +0 -229
- scripts/export-grafana-dashboards.py +0 -49
- scripts/fdir/cs_recovery/fdir_cs_recovery.py +0 -54
- scripts/fdir/fdir_table.yaml +0 -70
- scripts/fdir/fdir_test_recovery.py +0 -10
- scripts/fdir/hw_recovery/fdir_agilent_hw_recovery.py +0 -73
- scripts/fdir/limit_recovery/fdir_agilent_limit.py +0 -61
- scripts/fdir/limit_recovery/fdir_bb_heater_limit.py +0 -59
- scripts/fdir/limit_recovery/fdir_ensemble_limit.py +0 -33
- scripts/fdir/limit_recovery/fdir_pressure_limit_recovery.py +0 -71
- scripts/fix_csv.py +0 -80
- scripts/ias/correct_ccd_temp_cal_elfique.py +0 -43
- scripts/ias/correct_ccd_temp_cal_floreffe.py +0 -43
- scripts/ias/correct_trp_swap_achel.py +0 -199
- scripts/inta/correct_ccd_temp_cal_duvel.py +0 -43
- scripts/inta/correct_ccd_temp_cal_gueuze.py +0 -43
- scripts/n_fee_supply_voltage_calculation.py +0 -92
- scripts/playground.py +0 -30
- scripts/print_hdf5_hk_data.py +0 -68
- scripts/print_register_map.py +0 -43
- scripts/remove_lines_between_matches.py +0 -188
- scripts/sron/commanding/control_heaters.py +0 -44
- scripts/sron/commanding/pumpdown.py +0 -46
- scripts/sron/commanding/set_pid_setpoint.py +0 -19
- scripts/sron/commanding/shutdown_bbb_heaters.py +0 -10
- scripts/sron/commanding/shutdown_pumps.py +0 -33
- scripts/sron/correct_mgse_coordinates_brigand_chimay.py +0 -272
- scripts/sron/correct_trp_swap_brigand.py +0 -204
- scripts/sron/gimbal_conversions.py +0 -75
- scripts/sron/tm_gen/tm_gen_agilent.py +0 -37
- scripts/sron/tm_gen/tm_gen_heaters.py +0 -4
- scripts/sron/tm_gen/tm_gen_spid.py +0 -13
- scripts/update_operational_cgse.py +0 -268
- scripts/update_operational_cgse_old.py +0 -273
egse/control.py
DELETED
|
@@ -1,632 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module defines the abstract class for any control server and some convenience functions.
|
|
3
|
-
"""
|
|
4
|
-
import abc
|
|
5
|
-
import datetime
|
|
6
|
-
import logging
|
|
7
|
-
import pickle
|
|
8
|
-
import threading
|
|
9
|
-
import time
|
|
10
|
-
from functools import partial
|
|
11
|
-
from typing import Any
|
|
12
|
-
from typing import Callable
|
|
13
|
-
from typing import Type
|
|
14
|
-
|
|
15
|
-
import zmq
|
|
16
|
-
|
|
17
|
-
from egse.decorators import retry
|
|
18
|
-
from egse.listener import Listeners
|
|
19
|
-
from egse.logger import close_all_zmq_handlers
|
|
20
|
-
from egse.process import ProcessStatus
|
|
21
|
-
from egse.settings import Settings
|
|
22
|
-
from egse.system import do_every
|
|
23
|
-
from egse.system import get_average_execution_time
|
|
24
|
-
from egse.system import get_average_execution_times
|
|
25
|
-
from egse.system import get_full_classname
|
|
26
|
-
from egse.system import get_host_ip
|
|
27
|
-
from egse.system import save_average_execution_time
|
|
28
|
-
|
|
29
|
-
MODULE_LOGGER = logging.getLogger(__name__)
|
|
30
|
-
PROCESS_SETTINGS = Settings.load("PROCESS")
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def time_in_ms():
|
|
34
|
-
"""Returns the current time in milliseconds since the Epoch."""
|
|
35
|
-
return int(round(time.time() * 1000))
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def time_in_s():
|
|
39
|
-
"""Returns the current time in seconds since the Epoch."""
|
|
40
|
-
return time.time()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def is_control_server_active(endpoint: str = None, timeout: float = 0.5) -> bool:
|
|
44
|
-
"""
|
|
45
|
-
Check if the control server is running. This function sends a *Ping* message to the
|
|
46
|
-
control server and expects a *Pong* answer back within the timeout period.
|
|
47
|
-
|
|
48
|
-
Args:
|
|
49
|
-
endpoint (str): the endpoint to connect to, i.e. <protocol>://<address>:<port>
|
|
50
|
-
timeout (float): timeout when waiting for a reply [seconds, default=0.5]
|
|
51
|
-
Returns:
|
|
52
|
-
True if the Control Server is running and replied with the expected answer.
|
|
53
|
-
"""
|
|
54
|
-
ctx = zmq.Context.instance()
|
|
55
|
-
|
|
56
|
-
return_code = False
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
socket = ctx.socket(zmq.REQ)
|
|
60
|
-
socket.connect(endpoint)
|
|
61
|
-
data = pickle.dumps("Ping")
|
|
62
|
-
socket.send(data)
|
|
63
|
-
rlist, _, _ = zmq.select([socket], [], [], timeout=timeout)
|
|
64
|
-
if socket in rlist:
|
|
65
|
-
data = socket.recv()
|
|
66
|
-
response = pickle.loads(data)
|
|
67
|
-
return_code = response == "Pong"
|
|
68
|
-
socket.close(linger=0)
|
|
69
|
-
except Exception as exc:
|
|
70
|
-
MODULE_LOGGER.warning(f"Caught an exception while pinging a control server at {endpoint}: {exc}.")
|
|
71
|
-
|
|
72
|
-
return return_code
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class Response:
|
|
76
|
-
"""Base class for any reply or response between client-server communication.
|
|
77
|
-
|
|
78
|
-
The idea is that the response is encapsulated in one of the subclasses depending
|
|
79
|
-
on the type of response.
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
def __init__(self, message: str):
|
|
83
|
-
self.message = message
|
|
84
|
-
|
|
85
|
-
def __str__(self):
|
|
86
|
-
return self.message
|
|
87
|
-
|
|
88
|
-
@property
|
|
89
|
-
def successful(self):
|
|
90
|
-
"""Returns True if the Response is not an Exception."""
|
|
91
|
-
return not isinstance(self, Exception)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class Failure(Response, Exception):
|
|
95
|
-
"""A failure response indicating something went wrong at the other side.
|
|
96
|
-
|
|
97
|
-
This class is used to encapsulate an Exception that was caught and needs to be
|
|
98
|
-
passed to the client. So, the intended use is like this:
|
|
99
|
-
```
|
|
100
|
-
try:
|
|
101
|
-
# perform some useful action that might raise an Exception
|
|
102
|
-
except SomeException as exc:
|
|
103
|
-
return Failure("Our action failed", exc)
|
|
104
|
-
```
|
|
105
|
-
The client can inspect the Exception that was originally raised, in this case `SomeException`
|
|
106
|
-
with the `cause` variable.
|
|
107
|
-
|
|
108
|
-
Since a Failure is also an Exception, the property `successful` will return False.
|
|
109
|
-
So, the calling method can test for this easily.
|
|
110
|
-
|
|
111
|
-
```
|
|
112
|
-
rc: Response = function_that_returns_a_response()
|
|
113
|
-
|
|
114
|
-
if not rc.successful:
|
|
115
|
-
# handle the failure
|
|
116
|
-
else:
|
|
117
|
-
# handle success
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
"""
|
|
121
|
-
|
|
122
|
-
def __init__(self, message: str, cause: Exception = None):
|
|
123
|
-
msg = f"{message}: {cause}" if cause is not None else message
|
|
124
|
-
super().__init__(msg)
|
|
125
|
-
self.cause = cause
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
class Success(Response):
|
|
129
|
-
"""A success response for the client.
|
|
130
|
-
|
|
131
|
-
The return code from any action or function that needs to be returned to the
|
|
132
|
-
client shall be added.
|
|
133
|
-
|
|
134
|
-
Since `Success` doesn't inherit from `Exception`, the property `successful` will return True.
|
|
135
|
-
"""
|
|
136
|
-
|
|
137
|
-
def __init__(self, message: str, return_code: Any = None):
|
|
138
|
-
msg = f"{message}: {return_code}" if return_code is not None else message
|
|
139
|
-
super().__init__(msg)
|
|
140
|
-
self.return_code = return_code
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
class Message(Response):
|
|
144
|
-
"""A message response from the client.
|
|
145
|
-
|
|
146
|
-
Send a Message when there is no Failure, but also no return code. This is the alternative of
|
|
147
|
-
returning a None.
|
|
148
|
-
|
|
149
|
-
Message returns True for the property successful since it doesn't inherit from Exception.
|
|
150
|
-
"""
|
|
151
|
-
|
|
152
|
-
pass
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
class ControlServer(metaclass=abc.ABCMeta):
|
|
156
|
-
"""
|
|
157
|
-
The base class for all device control servers and for the Storage Manager and Configuration
|
|
158
|
-
Manager. A Control Server reads commands from a ZeroMQ socket and executes these commands by
|
|
159
|
-
calling the `execute()` method of the commanding protocol class.
|
|
160
|
-
|
|
161
|
-
The sub-class shall define the following:
|
|
162
|
-
|
|
163
|
-
* Define the device protocol class -> `self.device_protocol`
|
|
164
|
-
* Bind the command socket to the device protocol -> `self.dev_ctrl_cmd_sock`
|
|
165
|
-
* Register the command socket in the poll set -> `self.poller`
|
|
166
|
-
|
|
167
|
-
"""
|
|
168
|
-
|
|
169
|
-
def __init__(self):
|
|
170
|
-
from egse.monitoring import MonitoringProtocol
|
|
171
|
-
from egse.services import ServiceProtocol
|
|
172
|
-
|
|
173
|
-
self._process_status = ProcessStatus()
|
|
174
|
-
|
|
175
|
-
self._timer_thread = threading.Thread(
|
|
176
|
-
target=do_every, args=(PROCESS_SETTINGS.METRICS_INTERVAL, self._process_status.update))
|
|
177
|
-
self._timer_thread.daemon = True
|
|
178
|
-
self._timer_thread.start()
|
|
179
|
-
|
|
180
|
-
# The logger will be overwritten by the sub-class, if not, then we use this logger
|
|
181
|
-
# with the name of the sub-class. That will help us to identify which sub-class did not
|
|
182
|
-
# overwrite the logger attribute.
|
|
183
|
-
|
|
184
|
-
self.logger = logging.getLogger(get_full_classname(self))
|
|
185
|
-
|
|
186
|
-
self.listeners = Listeners()
|
|
187
|
-
self.scheduled_tasks = []
|
|
188
|
-
|
|
189
|
-
self.interrupted = False
|
|
190
|
-
self.delay = 1000 # delay between publish status information [milliseconds]
|
|
191
|
-
self.hk_delay = 1000 # delay between saving housekeeping information [milliseconds]
|
|
192
|
-
|
|
193
|
-
self.zcontext = zmq.Context.instance()
|
|
194
|
-
self.poller = zmq.Poller()
|
|
195
|
-
|
|
196
|
-
self.device_protocol = None # This will be set in the sub-class
|
|
197
|
-
self.service_protocol = ServiceProtocol(self)
|
|
198
|
-
self.monitoring_protocol = MonitoringProtocol(self)
|
|
199
|
-
|
|
200
|
-
# Setup the control server waiting for service requests
|
|
201
|
-
|
|
202
|
-
self.dev_ctrl_service_sock = self.zcontext.socket(zmq.REP)
|
|
203
|
-
self.service_protocol.bind(self.dev_ctrl_service_sock)
|
|
204
|
-
|
|
205
|
-
# Setup the control server for sending monitoring info
|
|
206
|
-
|
|
207
|
-
self.dev_ctrl_mon_sock = self.zcontext.socket(zmq.PUB)
|
|
208
|
-
self.monitoring_protocol.bind(self.dev_ctrl_mon_sock)
|
|
209
|
-
|
|
210
|
-
# Setup the control server waiting for device commands.
|
|
211
|
-
# The device protocol shall bind the socket in the sub-class
|
|
212
|
-
|
|
213
|
-
self.dev_ctrl_cmd_sock = self.zcontext.socket(zmq.REP)
|
|
214
|
-
|
|
215
|
-
# Initialize the poll set
|
|
216
|
-
|
|
217
|
-
self.poller.register(self.dev_ctrl_service_sock, zmq.POLLIN)
|
|
218
|
-
self.poller.register(self.dev_ctrl_mon_sock, zmq.POLLIN)
|
|
219
|
-
|
|
220
|
-
@abc.abstractmethod
|
|
221
|
-
def get_communication_protocol(self):
|
|
222
|
-
pass
|
|
223
|
-
|
|
224
|
-
@abc.abstractmethod
|
|
225
|
-
def get_commanding_port(self):
|
|
226
|
-
pass
|
|
227
|
-
|
|
228
|
-
@abc.abstractmethod
|
|
229
|
-
def get_service_port(self):
|
|
230
|
-
pass
|
|
231
|
-
|
|
232
|
-
@abc.abstractmethod
|
|
233
|
-
def get_monitoring_port(self):
|
|
234
|
-
pass
|
|
235
|
-
|
|
236
|
-
def get_ip_address(self):
|
|
237
|
-
return get_host_ip()
|
|
238
|
-
|
|
239
|
-
def get_storage_mnemonic(self):
|
|
240
|
-
return self.__class__.__name__
|
|
241
|
-
|
|
242
|
-
def get_process_status(self):
|
|
243
|
-
return self._process_status.as_dict()
|
|
244
|
-
|
|
245
|
-
def get_average_execution_times(self):
|
|
246
|
-
return get_average_execution_times()
|
|
247
|
-
|
|
248
|
-
def set_delay(self, seconds: float) -> float:
|
|
249
|
-
"""
|
|
250
|
-
Sets the delay time for monitoring. The delay time is the time between two successive executions of the
|
|
251
|
-
`get_status()` function of the device protocol.
|
|
252
|
-
|
|
253
|
-
It might happen that the delay time that is set is longer than what you requested. That is the case when
|
|
254
|
-
the execution of the `get_status()` function takes longer than the requested delay time. That should
|
|
255
|
-
prevent the server from blocking when a too short delay time is requested.
|
|
256
|
-
|
|
257
|
-
Args:
|
|
258
|
-
seconds: the number of seconds between the monitoring calls.
|
|
259
|
-
Returns:
|
|
260
|
-
The delay that was set in milliseconds.
|
|
261
|
-
"""
|
|
262
|
-
execution_time = get_average_execution_time(self.device_protocol.get_status)
|
|
263
|
-
self.delay = max(seconds * 1000, (execution_time + 0.2) * 1000)
|
|
264
|
-
return self.delay
|
|
265
|
-
|
|
266
|
-
def set_hk_delay(self, seconds) -> float:
|
|
267
|
-
"""
|
|
268
|
-
Sets the delay time for housekeeping. The delay time is the time between two successive executions of the
|
|
269
|
-
`get_housekeeping()` function of the device protocol.
|
|
270
|
-
|
|
271
|
-
It might happen that the delay time that is set is longer than what you requested. That is the case when
|
|
272
|
-
the execution of the `get_housekeeping()` function takes longer than the requested delay time. That should
|
|
273
|
-
prevent the server from blocking when a too short delay time is requested.
|
|
274
|
-
|
|
275
|
-
Args:
|
|
276
|
-
seconds: the number of seconds between the housekeeping calls.
|
|
277
|
-
Returns:
|
|
278
|
-
The delay that was set in milliseconds.
|
|
279
|
-
"""
|
|
280
|
-
execution_time = get_average_execution_time(self.device_protocol.get_housekeeping)
|
|
281
|
-
self.hk_delay = max(seconds * 1000, (execution_time + 0.2) * 1000)
|
|
282
|
-
return self.hk_delay
|
|
283
|
-
|
|
284
|
-
def set_logging_level(self, level):
|
|
285
|
-
self.logger.setLevel(level=level)
|
|
286
|
-
|
|
287
|
-
def quit(self):
|
|
288
|
-
self.interrupted = True
|
|
289
|
-
|
|
290
|
-
def before_serve(self):
|
|
291
|
-
pass
|
|
292
|
-
|
|
293
|
-
def after_serve(self):
|
|
294
|
-
pass
|
|
295
|
-
|
|
296
|
-
def handle_scheduled_tasks(self):
|
|
297
|
-
"""
|
|
298
|
-
Executes or reschedules tasks in the `serve()` event loop.
|
|
299
|
-
"""
|
|
300
|
-
self.scheduled_tasks.reverse()
|
|
301
|
-
rescheduled_tasks = []
|
|
302
|
-
while self.scheduled_tasks:
|
|
303
|
-
task_info = self.scheduled_tasks.pop()
|
|
304
|
-
task = task_info["task"]
|
|
305
|
-
task_name = task_info.get("name")
|
|
306
|
-
|
|
307
|
-
at = task_info.get("after")
|
|
308
|
-
if at and at > datetime.datetime.now(tz=datetime.timezone.utc):
|
|
309
|
-
rescheduled_tasks.append(task_info)
|
|
310
|
-
continue
|
|
311
|
-
|
|
312
|
-
condition = task_info.get("condition")
|
|
313
|
-
if condition and not condition():
|
|
314
|
-
rescheduled_tasks.append(task_info)
|
|
315
|
-
continue
|
|
316
|
-
|
|
317
|
-
self.logger.debug(f"Running scheduled task: {task_name}")
|
|
318
|
-
try:
|
|
319
|
-
task()
|
|
320
|
-
except Exception as exc:
|
|
321
|
-
self.logger.exception(exc, exc_info=True, stack_info=True)
|
|
322
|
-
self.logger.warning(f"Task {task_name} has failed: {exc!r}")
|
|
323
|
-
else:
|
|
324
|
-
self.logger.debug(f"Scheduled task finished: {task_name}")
|
|
325
|
-
|
|
326
|
-
if self.scheduled_tasks:
|
|
327
|
-
self.logger.warning(f"There are still {len(self.scheduled_tasks)} scheduled tasks.")
|
|
328
|
-
|
|
329
|
-
if rescheduled_tasks:
|
|
330
|
-
self.scheduled_tasks.append(*rescheduled_tasks)
|
|
331
|
-
|
|
332
|
-
def schedule_task(self, callback: Callable, after: float = 0.0, when: Callable = None):
|
|
333
|
-
"""
|
|
334
|
-
Schedules a task to run in the control server event loop.
|
|
335
|
-
|
|
336
|
-
The `callback` function will be executed as soon as possible in the `serve()` event loop.
|
|
337
|
-
|
|
338
|
-
Some simple scheduling options are available:
|
|
339
|
-
|
|
340
|
-
* after: the task will only execute 'x' seconds after the time of scheduling. I.e.
|
|
341
|
-
the task will be rescheduled until time > scheduled time + 'x' seconds.
|
|
342
|
-
* when: the task will only execute when the condition is True.
|
|
343
|
-
|
|
344
|
-
The `after` and the `when` arguments can be combined.
|
|
345
|
-
|
|
346
|
-
Note:
|
|
347
|
-
* This function is intended to be used in order to prevent a deadlock.
|
|
348
|
-
* Since the `callback` function is executed in the `serve()` event loop, it shall not block!
|
|
349
|
-
|
|
350
|
-
"""
|
|
351
|
-
try:
|
|
352
|
-
name = callback.func.__name__ if isinstance(callback, partial) else callback.__name__
|
|
353
|
-
except AttributeError:
|
|
354
|
-
name = "unknown"
|
|
355
|
-
|
|
356
|
-
current_time = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
357
|
-
scheduled_time = current_time + datetime.timedelta(seconds=after)
|
|
358
|
-
|
|
359
|
-
self.logger.info(f"Task {name} scheduled")
|
|
360
|
-
|
|
361
|
-
self.scheduled_tasks.append({'task': callback, "name": name, "after": scheduled_time, "when": when})
|
|
362
|
-
|
|
363
|
-
def serve(self):
|
|
364
|
-
|
|
365
|
-
self.before_serve()
|
|
366
|
-
|
|
367
|
-
# check if Storage Manager is available
|
|
368
|
-
|
|
369
|
-
from egse.storage import is_storage_manager_active
|
|
370
|
-
|
|
371
|
-
storage_manager = is_storage_manager_active(timeout=0.1)
|
|
372
|
-
|
|
373
|
-
storage_manager and self.register_to_storage_manager()
|
|
374
|
-
|
|
375
|
-
# This approach is very simplistic and not time efficient
|
|
376
|
-
# We probably want to use a Timer that executes the monitoring and saving actions at
|
|
377
|
-
# dedicated times in the background.
|
|
378
|
-
|
|
379
|
-
last_time = time_in_ms()
|
|
380
|
-
last_time_hk = time_in_ms()
|
|
381
|
-
|
|
382
|
-
while True:
|
|
383
|
-
try:
|
|
384
|
-
socks = dict(self.poller.poll(50)) # timeout in milliseconds, do not block
|
|
385
|
-
except KeyboardInterrupt:
|
|
386
|
-
self.logger.warning("Keyboard interrupt caught!")
|
|
387
|
-
self.logger.warning(
|
|
388
|
-
"The ControlServer can not be interrupted with CTRL-C, "
|
|
389
|
-
"send a quit command to the server."
|
|
390
|
-
)
|
|
391
|
-
continue
|
|
392
|
-
|
|
393
|
-
if self.dev_ctrl_cmd_sock in socks:
|
|
394
|
-
self.device_protocol.execute()
|
|
395
|
-
|
|
396
|
-
if self.dev_ctrl_service_sock in socks:
|
|
397
|
-
self.service_protocol.execute()
|
|
398
|
-
|
|
399
|
-
# Now handle the periodic sending out of status information. A dictionary with the
|
|
400
|
-
# status or HK info is sent out periodically based on the DELAY time that is in the
|
|
401
|
-
# YAML config file.
|
|
402
|
-
|
|
403
|
-
if time_in_ms() - last_time >= self.delay:
|
|
404
|
-
last_time = time_in_ms()
|
|
405
|
-
# self.logger.debug("Sending status to monitoring processes.")
|
|
406
|
-
self.monitoring_protocol.send_status(
|
|
407
|
-
save_average_execution_time(self.device_protocol.get_status)
|
|
408
|
-
)
|
|
409
|
-
|
|
410
|
-
if time_in_ms() - last_time_hk >= self.hk_delay:
|
|
411
|
-
last_time_hk = time_in_ms()
|
|
412
|
-
if storage_manager:
|
|
413
|
-
# self.logger.debug("Sending housekeeping information to Storage.")
|
|
414
|
-
self.store_housekeeping_information(
|
|
415
|
-
save_average_execution_time(self.device_protocol.get_housekeeping)
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
# Handle scheduled tasks/callback functions
|
|
419
|
-
|
|
420
|
-
self.handle_scheduled_tasks()
|
|
421
|
-
|
|
422
|
-
if self.interrupted:
|
|
423
|
-
self.logger.info(
|
|
424
|
-
f"Quit command received, closing down the {self.__class__.__name__}."
|
|
425
|
-
)
|
|
426
|
-
break
|
|
427
|
-
|
|
428
|
-
# Some device protocol sub-classes might start a number of threads or processes to
|
|
429
|
-
# support the commanding. Check if these threads/processes are still alive and
|
|
430
|
-
# terminate gracefully if they are not.
|
|
431
|
-
|
|
432
|
-
if not self.device_protocol.is_alive():
|
|
433
|
-
self.logger.error(
|
|
434
|
-
"Some Thread or sub-process that was started by Protocol has "
|
|
435
|
-
"died, terminating..."
|
|
436
|
-
)
|
|
437
|
-
break
|
|
438
|
-
|
|
439
|
-
storage_manager and self.unregister_from_storage_manager()
|
|
440
|
-
|
|
441
|
-
self.after_serve()
|
|
442
|
-
|
|
443
|
-
self.device_protocol.quit()
|
|
444
|
-
|
|
445
|
-
self.dev_ctrl_mon_sock.close()
|
|
446
|
-
self.dev_ctrl_service_sock.close()
|
|
447
|
-
self.dev_ctrl_cmd_sock.close()
|
|
448
|
-
|
|
449
|
-
close_all_zmq_handlers()
|
|
450
|
-
|
|
451
|
-
self.zcontext.term()
|
|
452
|
-
|
|
453
|
-
def store_housekeeping_information(self, data):
|
|
454
|
-
"""Send housekeeping information to the Storage manager."""
|
|
455
|
-
|
|
456
|
-
from egse.storage.storage_cs import StorageControlServer
|
|
457
|
-
from egse.storage import StorageProxy
|
|
458
|
-
|
|
459
|
-
if isinstance(self, StorageControlServer):
|
|
460
|
-
self.logger.log(0, f"{self.__class__.__name__} doesn't store housekeeping information.")
|
|
461
|
-
return
|
|
462
|
-
|
|
463
|
-
self.logger.log(0, "Sending housekeeping to storage manager.")
|
|
464
|
-
|
|
465
|
-
try:
|
|
466
|
-
with StorageProxy() as proxy:
|
|
467
|
-
rc = proxy.save({"origin": self.get_storage_mnemonic(), "data": data})
|
|
468
|
-
if not rc.successful:
|
|
469
|
-
self.logger.warning(
|
|
470
|
-
f"Couldn't save data to the Storage manager: {data}, cause: {rc}"
|
|
471
|
-
)
|
|
472
|
-
except ConnectionError as exc:
|
|
473
|
-
self.logger.warning(
|
|
474
|
-
f"Couldn't connect to the Storage manager to store housekeeping: {exc}"
|
|
475
|
-
)
|
|
476
|
-
|
|
477
|
-
def register_to_storage_manager(self):
|
|
478
|
-
"""Register this ControlServer to the Storage manager."""
|
|
479
|
-
|
|
480
|
-
from egse.storage.storage_cs import StorageControlServer
|
|
481
|
-
from egse.storage import StorageProxy
|
|
482
|
-
from egse.storage.persistence import CSV
|
|
483
|
-
|
|
484
|
-
if isinstance(self, StorageControlServer):
|
|
485
|
-
return
|
|
486
|
-
|
|
487
|
-
try:
|
|
488
|
-
with StorageProxy() as proxy:
|
|
489
|
-
rc = proxy.register(
|
|
490
|
-
{
|
|
491
|
-
"origin": self.get_storage_mnemonic(),
|
|
492
|
-
"persistence_class": CSV,
|
|
493
|
-
"prep": {
|
|
494
|
-
"column_names": list(self.device_protocol.get_housekeeping().keys()),
|
|
495
|
-
"mode": "a",
|
|
496
|
-
},
|
|
497
|
-
}
|
|
498
|
-
)
|
|
499
|
-
if not rc.successful:
|
|
500
|
-
self.logger.warning(f"Couldn't register to the Storage manager: {rc}")
|
|
501
|
-
except ConnectionError as exc:
|
|
502
|
-
self.logger.warning(f"Couldn't connect to the Storage manager for registration: {exc}")
|
|
503
|
-
|
|
504
|
-
def unregister_from_storage_manager(self):
|
|
505
|
-
"""Unregister this ControlServer from the Storage manager."""
|
|
506
|
-
|
|
507
|
-
from egse.storage.storage_cs import StorageControlServer
|
|
508
|
-
from egse.storage import StorageProxy
|
|
509
|
-
|
|
510
|
-
if isinstance(self, StorageControlServer):
|
|
511
|
-
return
|
|
512
|
-
|
|
513
|
-
try:
|
|
514
|
-
with StorageProxy() as proxy:
|
|
515
|
-
rc = proxy.unregister({"origin": self.get_storage_mnemonic()})
|
|
516
|
-
if not rc.successful:
|
|
517
|
-
self.logger.warning(f"Couldn't unregister from the Storage manager: {rc}")
|
|
518
|
-
|
|
519
|
-
except ConnectionError as exc:
|
|
520
|
-
self.logger.warning(
|
|
521
|
-
f"Couldn't connect to the Storage manager for de-registration: {exc}"
|
|
522
|
-
)
|
|
523
|
-
|
|
524
|
-
def notify_listeners(self, event_id: int = 0, context: dict = None):
|
|
525
|
-
"""
|
|
526
|
-
Notifies registered listeners about an event.
|
|
527
|
-
|
|
528
|
-
This function creates an Event object with the provided `event_id` and `context`
|
|
529
|
-
and notifies all registered listeners with the created event.
|
|
530
|
-
|
|
531
|
-
Args:
|
|
532
|
-
event_id (int, optional): The identifier for the event. Defaults to 0.
|
|
533
|
-
context (dict, optional): Additional context information associated with the event.
|
|
534
|
-
Defaults to None.
|
|
535
|
-
|
|
536
|
-
Note:
|
|
537
|
-
The notification is performed by the `notify_listeners` method of the `listeners` object
|
|
538
|
-
associated with this instance.
|
|
539
|
-
The notification is executed in a daemon thread to avoid blocking the commanding
|
|
540
|
-
chain.
|
|
541
|
-
|
|
542
|
-
"""
|
|
543
|
-
from egse.listener import Event, EVENT_ID
|
|
544
|
-
|
|
545
|
-
self.logger.info(f"Notifying listeners for {EVENT_ID(event_id).name}")
|
|
546
|
-
|
|
547
|
-
retry_thread = threading.Thread(target=self.listeners.notify_listeners,
|
|
548
|
-
args=(Event(event_id=event_id, context=context),))
|
|
549
|
-
retry_thread.daemon = True
|
|
550
|
-
retry_thread.start()
|
|
551
|
-
|
|
552
|
-
def get_listener_names(self):
|
|
553
|
-
return self.listeners.get_listener_names()
|
|
554
|
-
|
|
555
|
-
def register_as_listener(self, proxy: Type, listener: dict):
|
|
556
|
-
"""
|
|
557
|
-
Registers a listener with the specified proxy.
|
|
558
|
-
|
|
559
|
-
This function attempts to add the provided listener to the specified proxy.
|
|
560
|
-
It employs a retry mechanism to handle potential ConnectionError exceptions,
|
|
561
|
-
making up to 5 attempts to add the listener.
|
|
562
|
-
|
|
563
|
-
Args:
|
|
564
|
-
proxy: A callable object representing the proxy to which the listener will be added.
|
|
565
|
-
listener (dict): The listener to be registered. Should be a dictionary containing
|
|
566
|
-
listener details.
|
|
567
|
-
|
|
568
|
-
Raises:
|
|
569
|
-
ConnectionError: If the connection to the proxy encounters issues even after
|
|
570
|
-
multiple retry attempts.
|
|
571
|
-
|
|
572
|
-
Note:
|
|
573
|
-
The function runs in a separate daemon thread to avoid blocking the main thread.
|
|
574
|
-
|
|
575
|
-
"""
|
|
576
|
-
@retry(times=5, exceptions=[ConnectionError])
|
|
577
|
-
def _add_listener(proxy, listener):
|
|
578
|
-
with proxy() as x, x.get_service_proxy() as srv:
|
|
579
|
-
rc = srv.add_listener(listener)
|
|
580
|
-
MODULE_LOGGER.debug(f"Response from service add_listener: {rc}")
|
|
581
|
-
|
|
582
|
-
MODULE_LOGGER.info(f"Registering {self.__class__.__name__} to {proxy}")
|
|
583
|
-
|
|
584
|
-
retry_thread = threading.Thread(target=_add_listener, args=(proxy, listener))
|
|
585
|
-
retry_thread.daemon = True
|
|
586
|
-
retry_thread.start()
|
|
587
|
-
|
|
588
|
-
def unregister_as_listener(self, proxy: Type, listener: dict):
|
|
589
|
-
"""
|
|
590
|
-
Removes a registered listener from the specified proxy.
|
|
591
|
-
|
|
592
|
-
This function attempts to remove the provided listener from the specified proxy.
|
|
593
|
-
It employs a retry mechanism to handle potential ConnectionError exceptions,
|
|
594
|
-
making up to 5 attempts to add the listener.
|
|
595
|
-
|
|
596
|
-
Args:
|
|
597
|
-
proxy: A callable object representing the proxy from which the listener will be removed.
|
|
598
|
-
listener (dict): The listener to be removed. Should be a dictionary containing
|
|
599
|
-
listener details.
|
|
600
|
-
|
|
601
|
-
Raises:
|
|
602
|
-
ConnectionError: If the connection to the proxy encounters issues even after
|
|
603
|
-
multiple retry attempts.
|
|
604
|
-
|
|
605
|
-
Note:
|
|
606
|
-
The function runs in a separate thread but will block until the de-registration is finished.
|
|
607
|
-
The reason being that this method is usually called in a `after_serve` block so it needs to
|
|
608
|
-
finish before the ZeroMQ context is destroyed.
|
|
609
|
-
|
|
610
|
-
"""
|
|
611
|
-
@retry(times=5, exceptions=[ConnectionError])
|
|
612
|
-
def _remove_listener(proxy, listener):
|
|
613
|
-
with proxy() as x, x.get_service_proxy() as srv:
|
|
614
|
-
rc = srv.remove_listener(listener)
|
|
615
|
-
|
|
616
|
-
endpoint = proxy().get_endpoint()
|
|
617
|
-
if not is_control_server_active(endpoint, timeout=0.5):
|
|
618
|
-
MODULE_LOGGER.warning(f"The {endpoint} endpoint is not responding, {listener['name']} not un-registered.")
|
|
619
|
-
return
|
|
620
|
-
|
|
621
|
-
MODULE_LOGGER.info(f"Removing {self.__class__.__name__} from {proxy}")
|
|
622
|
-
|
|
623
|
-
retry_thread = threading.Thread(target=_remove_listener, args=(proxy, listener))
|
|
624
|
-
retry_thread.daemon = False
|
|
625
|
-
retry_thread.start()
|
|
626
|
-
|
|
627
|
-
# Block until the listener has been removed. This is needed because this unregister function will usually
|
|
628
|
-
# be called in the `after_server()` method of the control server (which is the listener) and if we do not
|
|
629
|
-
# wait until the thread is finished the ZeroMQ Context will be destroyed before the reply can be sent.
|
|
630
|
-
# Note: we could probably do without the thread, and directly call the `_remove_listener()` function.
|
|
631
|
-
|
|
632
|
-
retry_thread.join()
|