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
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
from prometheus_client import Gauge
|
|
4
|
-
|
|
5
|
-
from egse.control import ControlServer
|
|
6
|
-
from egse.protocol import CommandProtocol
|
|
7
|
-
from egse.command import ClientServerCommand
|
|
8
|
-
from egse.proxy import Proxy
|
|
9
|
-
from egse.settings import Settings
|
|
10
|
-
from egse.setup import load_setup
|
|
11
|
-
from egse.synoptics import SynopticsManagerProxy
|
|
12
|
-
from egse.zmq_ser import bind_address
|
|
13
|
-
from egse.system import format_datetime
|
|
14
|
-
from egse.filterwheel.eksma.fw8smc5_interface import Fw8Smc5Interface
|
|
15
|
-
from egse.filterwheel.eksma.fw8smc5_simulator import Fw8Smc5Simulator
|
|
16
|
-
from egse.zmq_ser import connect_address
|
|
17
|
-
|
|
18
|
-
logger = logging.getLogger(__name__)
|
|
19
|
-
|
|
20
|
-
FDIR_PREFIX = 400
|
|
21
|
-
|
|
22
|
-
DEVICE_SETTINGS = Settings.load(filename="fw8smc5.yaml")
|
|
23
|
-
CTRL_SETTINGS = Settings.load("Standa 8SMC5 Control Server")
|
|
24
|
-
|
|
25
|
-
gauge_position_0 = Gauge('GSRON_FW8SMC5_POS_0', 'wheel 0 position in encoder steps')
|
|
26
|
-
gauge_position_1 = Gauge('GSRON_FW8SMC5_POS_1', 'wheel 1 position in encoder steps')
|
|
27
|
-
gauge_relative_intensity = Gauge('GSRON_FW8SMC5_RI', 'filter attenuation as relative index')
|
|
28
|
-
gauge_fwc_fraction = Gauge('GSRON_FW8SMC5_FWC_FRACTION', 'FWC fraction')
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class Fw8Smc5Command(ClientServerCommand):
|
|
32
|
-
pass
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class Fw8Smc5Protocol(CommandProtocol):
|
|
36
|
-
|
|
37
|
-
def __init__(self, control_server: ControlServer):
|
|
38
|
-
|
|
39
|
-
from egse.filterwheel.eksma.fw8smc5_controller import Fw8Smc5Controller
|
|
40
|
-
|
|
41
|
-
super().__init__()
|
|
42
|
-
|
|
43
|
-
setup = load_setup()
|
|
44
|
-
|
|
45
|
-
self.control_server = control_server
|
|
46
|
-
|
|
47
|
-
self.fwc_calibration = setup.gse.ogse.calibration.fwc_calibration
|
|
48
|
-
|
|
49
|
-
if Settings.simulation_mode():
|
|
50
|
-
self.dev = Fw8Smc5Simulator()
|
|
51
|
-
else:
|
|
52
|
-
self.dev = Fw8Smc5Controller()
|
|
53
|
-
|
|
54
|
-
self.load_commands(DEVICE_SETTINGS.Commands, Fw8Smc5Command, Fw8Smc5Interface)
|
|
55
|
-
self.build_device_method_lookup_table(self.dev)
|
|
56
|
-
|
|
57
|
-
self.synoptics = SynopticsManagerProxy()
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# move to parent class?
|
|
61
|
-
def get_bind_address(self):
|
|
62
|
-
return bind_address(
|
|
63
|
-
self.control_server.get_communication_protocol(),
|
|
64
|
-
self.control_server.get_commanding_port(),
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def get_status(self):
|
|
69
|
-
status_dict = super().get_status()
|
|
70
|
-
status = {
|
|
71
|
-
'RelativeIntensity': self.dev.get_relative_intensity(),
|
|
72
|
-
'FullWellCapacity': self.dev.get_relative_intensity() / self.fwc_calibration,
|
|
73
|
-
'FW1Position' : self.dev.get_position_steps(0),
|
|
74
|
-
'FW2Position' : self.dev.get_position_steps(1)
|
|
75
|
-
}
|
|
76
|
-
status_dict['fw8smc5_status'] = status
|
|
77
|
-
# need to get the channel from somewhere
|
|
78
|
-
# status_dict['device_status'] = self.dev.get_status(channel)
|
|
79
|
-
|
|
80
|
-
return status_dict
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def get_housekeeping(self) -> dict:
|
|
84
|
-
result = dict()
|
|
85
|
-
result["timestamp"] = format_datetime()
|
|
86
|
-
|
|
87
|
-
try:
|
|
88
|
-
result["GSRON_FW8SMC5_RI"] = self.dev.get_relative_intensity()
|
|
89
|
-
result["GSRON_FW8SMC5_FWC_FRACTION"] = result["GSRON_FW8SMC5_RI"] / self.fwc_calibration
|
|
90
|
-
# TODO Include FWC fraction in result
|
|
91
|
-
|
|
92
|
-
# Send the HK acquired so far to the Synoptics Manager
|
|
93
|
-
self.synoptics.store_th_synoptics(result)
|
|
94
|
-
|
|
95
|
-
result["GSRON_FW8SMC5_POS_0"] = self.dev.get_position_steps(0)
|
|
96
|
-
result["GSRON_FW8SMC5_POS_1"] = self.dev.get_position_steps(1)
|
|
97
|
-
|
|
98
|
-
except Exception as exc:
|
|
99
|
-
logger.warning(f'failed to get HK ({exc})')
|
|
100
|
-
return result
|
|
101
|
-
|
|
102
|
-
gauge_position_0.set(result[f"GSRON_FW8SMC5_POS_0"])
|
|
103
|
-
gauge_position_1.set(result[f"GSRON_FW8SMC5_POS_1"])
|
|
104
|
-
gauge_relative_intensity.set(result[f"GSRON_FW8SMC5_RI"])
|
|
105
|
-
gauge_fwc_fraction.set(result["GSRON_FW8SMC5_FWC_FRACTION"])
|
|
106
|
-
|
|
107
|
-
return result
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
class Fw8Smc5Proxy(Proxy, Fw8Smc5Interface):
|
|
111
|
-
|
|
112
|
-
def __init__(self):
|
|
113
|
-
super().__init__(
|
|
114
|
-
connect_address(
|
|
115
|
-
CTRL_SETTINGS.PROTOCOL, CTRL_SETTINGS.HOSTNAME, CTRL_SETTINGS.COMMANDING_PORT))
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
BaseClass:
|
|
2
|
-
egse.filterwheel.eksma.fw8smc5_interface.Fw8Smc5Interface
|
|
3
|
-
|
|
4
|
-
ProxyClass:
|
|
5
|
-
egse.filterwheel.eksma.fw8smc5.Fw8Smc5Proxy
|
|
6
|
-
|
|
7
|
-
ControlServer:
|
|
8
|
-
egse.filterwheel.eksma.fw8smc5_cs
|
|
9
|
-
|
|
10
|
-
UserInterface:
|
|
11
|
-
egse.filterwheel.eksma.fw8smc5_ui
|
|
12
|
-
|
|
13
|
-
Commands:
|
|
14
|
-
|
|
15
|
-
connect:
|
|
16
|
-
description: Connect the Filter Wheel hardware controller.
|
|
17
|
-
|
|
18
|
-
reconnect:
|
|
19
|
-
description: Reconnect the Lamp hardware controller.
|
|
20
|
-
|
|
21
|
-
This command will force a disconnect and then try to re-connect to the controller.
|
|
22
|
-
|
|
23
|
-
disconnect:
|
|
24
|
-
description: Disconnect from the Lamp controller. This command will be send to the
|
|
25
|
-
Thorlabs Control Server which will then disconnect from the hardware controller.
|
|
26
|
-
This command doesn't affect the ZeroMQ connection of this Proxy to the
|
|
27
|
-
control server. Use the service command `disconnect_cs()` to disconnect
|
|
28
|
-
from the control server.
|
|
29
|
-
|
|
30
|
-
is_connected:
|
|
31
|
-
description: Check if the Thorlabs Hardware Controller is connected.
|
|
32
|
-
|
|
33
|
-
is_simulator:
|
|
34
|
-
description: Ask if the control server is a simulator instead of the real controller class.
|
|
35
|
-
returns: bool | True if the far end is a simulator instead of the real hardware
|
|
36
|
-
|
|
37
|
-
get_idn:
|
|
38
|
-
description: Get the device ID string.
|
|
39
|
-
returns: str | ID string
|
|
40
|
-
|
|
41
|
-
get_error_flags:
|
|
42
|
-
description: Read the error status word for both controllers.
|
|
43
|
-
returs: (int, int)
|
|
44
|
-
|
|
45
|
-
is_moving:
|
|
46
|
-
description: Check whether either of the two wheels is currently moving.
|
|
47
|
-
returns: (bool, bool)
|
|
48
|
-
|
|
49
|
-
get_position_steps:
|
|
50
|
-
description: Read the current position of one wheel in encoder steps.
|
|
51
|
-
args:
|
|
52
|
-
id: int | wheel ID [0, 1]
|
|
53
|
-
returns: int | position in encoder steps
|
|
54
|
-
cmd: "{id}" # Not a real command.
|
|
55
|
-
|
|
56
|
-
set_position_steps:
|
|
57
|
-
description: Move one wheel to a encoder step position (blocking).
|
|
58
|
-
args:
|
|
59
|
-
id: int | wheel ID [0, 1]
|
|
60
|
-
position: int | position in encoder steps
|
|
61
|
-
cmd: "{id}{position}" # Not a real command.
|
|
62
|
-
|
|
63
|
-
get_position_wheels:
|
|
64
|
-
description: Return the filter position of both wheels.
|
|
65
|
-
returns: (int, int) | index [0 - 7]
|
|
66
|
-
|
|
67
|
-
set_position_wheels:
|
|
68
|
-
description: Set the wheels to specific filter positions.
|
|
69
|
-
args:
|
|
70
|
-
position_a: int | position index of wheel 0
|
|
71
|
-
position_b: int | position index of wheel 1
|
|
72
|
-
cmd: "{position_a}{position_b}" # Not a real command.
|
|
73
|
-
|
|
74
|
-
get_position_index:
|
|
75
|
-
description: Get the position of both wheels as a single index (sorted by attenuation).
|
|
76
|
-
returns: int | index [0 - 63]
|
|
77
|
-
|
|
78
|
-
set_position_index:
|
|
79
|
-
description: Move the wheels to a single filter index position (blocking).
|
|
80
|
-
args:
|
|
81
|
-
index: int | index [0 - 63]
|
|
82
|
-
cmd: "{index}" # Not a real command.
|
|
83
|
-
|
|
84
|
-
get_relative_intensity:
|
|
85
|
-
description: Read the relative intensity value of the current filter.
|
|
86
|
-
returns: float | relative intensity [0 - 1] = [opaque - transparent]
|
|
87
|
-
|
|
88
|
-
set_relative_intensity:
|
|
89
|
-
description: Set filter combination that matches the relative intensity the closest.
|
|
90
|
-
args:
|
|
91
|
-
rel_intensity: float | relative intensity [0 - 1] = [opaque - transparent]
|
|
92
|
-
cmd: "{rel_intensity}" # Not a real command.
|
|
93
|
-
|
|
94
|
-
intensity_level_up:
|
|
95
|
-
description: Increase the relative intensity by one level
|
|
96
|
-
|
|
97
|
-
intensity_level_down:
|
|
98
|
-
description: Decrease the relative intensity by one level
|
|
99
|
-
|
|
100
|
-
home:
|
|
101
|
-
description: Move both wheels to the home position (blocking).
|
|
102
|
-
|
|
103
|
-
set_position_wheel:
|
|
104
|
-
description:
|
|
105
|
-
cmd: "{id}{position}"
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import logging
|
|
3
|
-
from collections import OrderedDict
|
|
4
|
-
from ctypes import cast, byref, c_int, POINTER
|
|
5
|
-
|
|
6
|
-
import numpy as np
|
|
7
|
-
import time
|
|
8
|
-
|
|
9
|
-
from egse.device import DeviceConnectionError
|
|
10
|
-
from egse.filterwheel.eksma.fw8smc5 import Fw8Smc5Interface
|
|
11
|
-
from egse.lib.ximc.pyximc import device_information_t, get_position_t, status_t, MoveState
|
|
12
|
-
from egse.lib.ximc.pyximc import lib as ximc
|
|
13
|
-
from egse.settings import Settings
|
|
14
|
-
from egse.setup import load_setup
|
|
15
|
-
|
|
16
|
-
logger = logging.getLogger(__name__)
|
|
17
|
-
|
|
18
|
-
CTRL_SETTINGS = Settings.load("Standa 8SMC5 Controller")
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class Fw8Smc5Exception(Exception):
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class Fw8Smc5Controller(Fw8Smc5Interface):
|
|
26
|
-
""" This class controls a 8smc5 dual filterwheel controller through two serial devices
|
|
27
|
-
connected via USB. It uses a wrapped c library (ximc) to communicate with the device.
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
DEVICE_NAME = "Standa 8SMC5"
|
|
31
|
-
WHEEL_POSITIONS = 8
|
|
32
|
-
TOTAL_POSITIONS = WHEEL_POSITIONS * WHEEL_POSITIONS
|
|
33
|
-
ROTATION_STEPS = 600 # number of encoder steps in a full rotation
|
|
34
|
-
POSITION_STEPS = ROTATION_STEPS // WHEEL_POSITIONS # number of encoder steps between filter positions
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def __init__(self, port0=None, port1=None):
|
|
38
|
-
self._port0 = CTRL_SETTINGS.PORT_0 if port0 is None else port0
|
|
39
|
-
self._port1 = CTRL_SETTINGS.PORT_1 if port1 is None else port1
|
|
40
|
-
self._devIds = [None, None]
|
|
41
|
-
self._is_connected = False
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# Get device calibration from the setup
|
|
45
|
-
self.setup = load_setup()
|
|
46
|
-
self.relative_intensities = self.setup.gse.ogse.calibration.relative_intensity_by_index
|
|
47
|
-
self.home_offsets = self.setup.gse.filterwheel.home_offset
|
|
48
|
-
self.ri_wheel_positions = self.setup.gse.ogse.calibration.relative_intensity_by_wheel
|
|
49
|
-
|
|
50
|
-
self.ri_wheel_positions = {eval(k): v for k, v in self.ri_wheel_positions.items()} # convert wheel indices from strings to tuples
|
|
51
|
-
self.ri_wheel_positions = OrderedDict( # Convert to ordereddict sorted by values to match self.relative_intensities
|
|
52
|
-
sorted(self.ri_wheel_positions.items(), key=lambda x: x[1]))
|
|
53
|
-
|
|
54
|
-
# self.disconnect()
|
|
55
|
-
try:
|
|
56
|
-
self.connect()
|
|
57
|
-
except Exception as exc:
|
|
58
|
-
logger.error(f"Could not connect to device ({exc})")
|
|
59
|
-
|
|
60
|
-
self.home() # avoid being in an invalid position
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# The device sometimes becomes unresponsive when the connection is not closed
|
|
64
|
-
def __del__(self):
|
|
65
|
-
self.disconnect()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def connect(self):
|
|
69
|
-
|
|
70
|
-
if self._is_connected:
|
|
71
|
-
logger.warning("Trying to connect to an already connected device")
|
|
72
|
-
else:
|
|
73
|
-
try:
|
|
74
|
-
self._devIds[0] = ximc.open_device(f"xi-com:{self._port0}".encode())
|
|
75
|
-
self._devIds[1] = ximc.open_device(f"xi-com:{self._port1}".encode())
|
|
76
|
-
except OSError as exc:
|
|
77
|
-
raise DeviceConnectionError(self.DEVICE_NAME, f"Could not connect ({exc}).") from exc
|
|
78
|
-
else:
|
|
79
|
-
self._is_connected = True
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def disconnect(self):
|
|
83
|
-
|
|
84
|
-
if not self._is_connected:
|
|
85
|
-
logger.warning("Trying to disconnect to an already disconnected device")
|
|
86
|
-
else:
|
|
87
|
-
try:
|
|
88
|
-
ximc.close_device(byref(cast(self._devIds[0], POINTER(c_int))))
|
|
89
|
-
ximc.close_device(byref(cast(self._devIds[1], POINTER(c_int))))
|
|
90
|
-
except OSError as exc:
|
|
91
|
-
raise DeviceConnectionError(self.DEVICE_NAME, f"Could not disconnect ({exc}).") from exc
|
|
92
|
-
else:
|
|
93
|
-
self._is_connected = False
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def reconnect(self):
|
|
97
|
-
|
|
98
|
-
if self._is_connected:
|
|
99
|
-
self.disconnect()
|
|
100
|
-
self.connect()
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def is_connected(self):
|
|
104
|
-
|
|
105
|
-
return self._is_connected
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def is_simulator(self):
|
|
109
|
-
|
|
110
|
-
return False
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def get_idn(self):
|
|
114
|
-
|
|
115
|
-
device_information = device_information_t()
|
|
116
|
-
result = ximc.get_device_information(self._devIds[0], byref(device_information))
|
|
117
|
-
|
|
118
|
-
return device_information.ProductDescription.decode()
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def get_error_flags(self):
|
|
122
|
-
|
|
123
|
-
status0, status1 = self._get_status()
|
|
124
|
-
|
|
125
|
-
return (status0.Flags, status1.Flags)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def is_moving(self):
|
|
129
|
-
|
|
130
|
-
status0, status1 = self._get_status()
|
|
131
|
-
|
|
132
|
-
return (bool(status0.MoveSts & MoveState.MOVE_STATE_MOVING),
|
|
133
|
-
bool(status1.MoveSts & MoveState.MOVE_STATE_MOVING))
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def get_position_steps(self, id):
|
|
137
|
-
|
|
138
|
-
get_position = get_position_t()
|
|
139
|
-
ximc.get_position(self._devIds[id], byref(get_position))
|
|
140
|
-
|
|
141
|
-
return get_position.Position
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def set_position_steps(self, id, position):
|
|
145
|
-
|
|
146
|
-
assert id in [0, 1], 'Device id must be in [0, 1]'
|
|
147
|
-
|
|
148
|
-
position = position % self.ROTATION_STEPS
|
|
149
|
-
|
|
150
|
-
ximc.command_move(self._devIds[id], position, 0)
|
|
151
|
-
|
|
152
|
-
# TODO: add some error checking and maybe a timout to this loop
|
|
153
|
-
while self.get_position_steps(id) != position:
|
|
154
|
-
time.sleep(0.1)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def get_position_wheels(self):
|
|
158
|
-
|
|
159
|
-
return self._get_position_wheel(0), self._get_position_wheel(1)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def set_position_wheels(self, position_a, position_b):
|
|
163
|
-
|
|
164
|
-
self.set_position_wheel(0, position_a)
|
|
165
|
-
self.set_position_wheel(1, position_b)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def get_position_index(self):
|
|
169
|
-
|
|
170
|
-
# Get the current wheel positions
|
|
171
|
-
p0, p1 = self.get_position_wheels()
|
|
172
|
-
|
|
173
|
-
if p0 is None or p1 is None:
|
|
174
|
-
raise Fw8Smc5Exception('Wheel(s) in intermediate position')
|
|
175
|
-
|
|
176
|
-
try:
|
|
177
|
-
return list(self.ri_wheel_positions.keys()).index((p0, p1))
|
|
178
|
-
except ValueError:
|
|
179
|
-
return None
|
|
180
|
-
# Do we really need to crash the CS/Leave a log message if the comination is non indexed?
|
|
181
|
-
# I think we are better off just returning an impossible value
|
|
182
|
-
# logger.warning("Filterwheel is in a non-indexed combination of wheel positions")
|
|
183
|
-
# raise Fw8Smc5Exception("Filterwheel is in a non-indexed combination of wheel positions")
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def set_position_index(self, index):
|
|
187
|
-
|
|
188
|
-
index0, index1 = list(self.ri_wheel_positions.keys())[index]
|
|
189
|
-
self.set_position_wheels(index0, index1)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def get_relative_intensity(self):
|
|
193
|
-
index = self.get_position_index()
|
|
194
|
-
if index in self.relative_intensities:
|
|
195
|
-
return self.relative_intensities[index]
|
|
196
|
-
else:
|
|
197
|
-
return 9.99999e9
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
def set_relative_intensity(self, relative_intensity):
|
|
201
|
-
|
|
202
|
-
# Find the index that matches the desired relative_intensity the closest.
|
|
203
|
-
index = int(np.abs(
|
|
204
|
-
np.array(list(self.relative_intensities.values())) - relative_intensity).argmin())
|
|
205
|
-
|
|
206
|
-
# Look up corresponding wheel positions
|
|
207
|
-
p0, p1 = list(self.ri_wheel_positions.keys())[index]
|
|
208
|
-
|
|
209
|
-
self.set_position_wheels(p0, p1)
|
|
210
|
-
|
|
211
|
-
logger.info(f'set relative intensity to {relative_intensity}')
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def intensity_level_up(self):
|
|
215
|
-
|
|
216
|
-
index = self.get_position_index() # get current index
|
|
217
|
-
index = min(index + 1, self.TOTAL_POSITIONS - 1) # increment
|
|
218
|
-
self.set_position_index(index)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def intensity_level_down(self):
|
|
222
|
-
|
|
223
|
-
index = self.get_position_index() # get current index
|
|
224
|
-
index = max(index - 1, 0) # decrement
|
|
225
|
-
self.set_position_index(index)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
# NOTE: this is blocking but the position might still be outdated when read directly after homing
|
|
229
|
-
def home(self):
|
|
230
|
-
|
|
231
|
-
logger.info('Homing started...')
|
|
232
|
-
|
|
233
|
-
ximc.command_homezero(self._devIds[0])
|
|
234
|
-
ximc.command_homezero(self._devIds[1])
|
|
235
|
-
|
|
236
|
-
self.set_position_steps(0, self.home_offsets[0])
|
|
237
|
-
self.set_position_steps(1, self.home_offsets[1])
|
|
238
|
-
|
|
239
|
-
logger.info('Homing complete')
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
def _get_status(self):
|
|
243
|
-
|
|
244
|
-
status0 = status_t()
|
|
245
|
-
status1 = status_t()
|
|
246
|
-
|
|
247
|
-
ximc.get_status(self._devIds[0], byref(status0))
|
|
248
|
-
ximc.get_status(self._devIds[1], byref(status1))
|
|
249
|
-
|
|
250
|
-
return (status0, status1)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def _get_position_wheel(self, id):
|
|
254
|
-
""" Get the position of one of the wheels.
|
|
255
|
-
Returns None for inbetween positions.
|
|
256
|
-
"""
|
|
257
|
-
|
|
258
|
-
position = self.get_position_steps(id) - self.home_offsets[id]
|
|
259
|
-
offset = position % self.POSITION_STEPS
|
|
260
|
-
|
|
261
|
-
if offset != 0:
|
|
262
|
-
return None
|
|
263
|
-
else:
|
|
264
|
-
return position // self.POSITION_STEPS % self.WHEEL_POSITIONS
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
def set_position_wheel(self, id, position):
|
|
268
|
-
""" Set the position of one of the wheels. """
|
|
269
|
-
|
|
270
|
-
assert 0 <= position < self.WHEEL_POSITIONS, f"Filterwheel index out of range ({position})"
|
|
271
|
-
|
|
272
|
-
position_steps = (position * self.POSITION_STEPS + self.home_offsets[id]) % self.ROTATION_STEPS
|
|
273
|
-
self.set_position_steps(id, position_steps)
|
|
274
|
-
|
|
275
|
-
logger.debug(f'set wheel {id} to step position {position_steps}')
|
|
276
|
-
|
|
277
|
-
while(self.get_position_steps(id) != position_steps):
|
|
278
|
-
logger.info(f'position = {self.get_position_steps(id)}')
|
|
279
|
-
time.sleep(1)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
def main():
|
|
283
|
-
dev = Fw8Smc5Controller()
|
|
284
|
-
|
|
285
|
-
print('id :', dev.get_idn())
|
|
286
|
-
print('status :', dev.get_error_flags())
|
|
287
|
-
print('position:', (dev.get_position_steps(0), dev.get_position_steps(0)))
|
|
288
|
-
|
|
289
|
-
print(list(dev.ri_wheel_positions.keys()).index(('(0, 0)')))
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
# dev.home()
|
|
293
|
-
# print(dev.get_position_index())
|
|
294
|
-
# print(dev.get_position_wheels())
|
|
295
|
-
#
|
|
296
|
-
# dev.set_position_index(24)
|
|
297
|
-
# print(dev.get_position_index())
|
|
298
|
-
# print(dev.get_position_wheels())
|
|
299
|
-
#
|
|
300
|
-
# dev.set_relative_intensity(1E-4)
|
|
301
|
-
# print(dev.get_position_index())
|
|
302
|
-
# print(dev.get_position_wheels())
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if __name__ == '__main__':
|
|
307
|
-
main()
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
import click
|
|
4
|
-
import rich
|
|
5
|
-
import sys
|
|
6
|
-
import zmq
|
|
7
|
-
from prometheus_client import start_http_server
|
|
8
|
-
|
|
9
|
-
from egse.control import ControlServer, is_control_server_active
|
|
10
|
-
from egse.filterwheel.eksma.fw8smc5 import Fw8Smc5Protocol, Fw8Smc5Proxy
|
|
11
|
-
from egse.settings import Settings
|
|
12
|
-
from egse.zmq_ser import connect_address
|
|
13
|
-
|
|
14
|
-
logging.basicConfig(level=logging.DEBUG, format=Settings.LOG_FORMAT_FULL)
|
|
15
|
-
|
|
16
|
-
logger = logging.getLogger(__name__)
|
|
17
|
-
|
|
18
|
-
CTRL_SETTINGS = Settings.load("Standa 8SMC5 Control Server")
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class Fw8Smc5ControlServer(ControlServer):
|
|
22
|
-
"""
|
|
23
|
-
Fw8Smc5ControlServer - Command and monitor the 8SMC5 turbo pump.
|
|
24
|
-
This class works as a command and monitoring server to control the device remotely.
|
|
25
|
-
The sever binds to the following ZeroMQ sockets:
|
|
26
|
-
* a REP socket that can be used as a command server. Any client can connect and
|
|
27
|
-
send a command to the Lamp controller.
|
|
28
|
-
* a PUB socket that serves as a monitoring server. It will send out Lamp status
|
|
29
|
-
information to all the connected clients every DELAY seconds.
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
def __init__(self):
|
|
33
|
-
super().__init__()
|
|
34
|
-
|
|
35
|
-
self.device_protocol = Fw8Smc5Protocol(self)
|
|
36
|
-
|
|
37
|
-
self.logger.debug(f"Binding ZeroMQ socket to {self.device_protocol.get_bind_address()}")
|
|
38
|
-
|
|
39
|
-
self.device_protocol.bind(self.dev_ctrl_cmd_sock)
|
|
40
|
-
|
|
41
|
-
self.poller.register(self.dev_ctrl_cmd_sock, zmq.POLLIN)
|
|
42
|
-
|
|
43
|
-
def get_communication_protocol(self):
|
|
44
|
-
return CTRL_SETTINGS.PROTOCOL
|
|
45
|
-
|
|
46
|
-
def get_commanding_port(self):
|
|
47
|
-
return CTRL_SETTINGS.COMMANDING_PORT
|
|
48
|
-
|
|
49
|
-
def get_service_port(self):
|
|
50
|
-
return CTRL_SETTINGS.SERVICE_PORT
|
|
51
|
-
|
|
52
|
-
def get_monitoring_port(self):
|
|
53
|
-
return CTRL_SETTINGS.MONITORING_PORT
|
|
54
|
-
|
|
55
|
-
def get_storage_mnemonic(self):
|
|
56
|
-
try:
|
|
57
|
-
return CTRL_SETTINGS.STORAGE_MNEMONIC
|
|
58
|
-
except AttributeError:
|
|
59
|
-
return "8SMC5"
|
|
60
|
-
|
|
61
|
-
def before_serve(self):
|
|
62
|
-
start_http_server(CTRL_SETTINGS.METRICS_PORT)
|
|
63
|
-
|
|
64
|
-
def after_serve(self):
|
|
65
|
-
self.device_protocol.synoptics.disconnect_cs()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
@click.group()
|
|
69
|
-
def cli():
|
|
70
|
-
pass
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@cli.command()
|
|
74
|
-
@click.option("--simulator", "--sim", is_flag=True, help="Start the 8SMC5 Simulator as the backend.")
|
|
75
|
-
def start(simulator):
|
|
76
|
-
"""Start the 8SMC5 Control Server."""
|
|
77
|
-
|
|
78
|
-
if simulator:
|
|
79
|
-
Settings.set_simulation_mode(True)
|
|
80
|
-
try:
|
|
81
|
-
controller = Fw8Smc5ControlServer()
|
|
82
|
-
controller.serve()
|
|
83
|
-
|
|
84
|
-
except KeyboardInterrupt:
|
|
85
|
-
print("Shutdown requested...exiting")
|
|
86
|
-
|
|
87
|
-
except SystemExit as exit_code:
|
|
88
|
-
print("System Exit with code {}.".format(exit_code))
|
|
89
|
-
sys.exit(exit_code)
|
|
90
|
-
|
|
91
|
-
except Exception:
|
|
92
|
-
|
|
93
|
-
logger.exception("Cannot start the 8SMC5 Control Server")
|
|
94
|
-
# The above line does exactly the same as the traceback, but on the logger
|
|
95
|
-
# import traceback
|
|
96
|
-
# traceback.print_exc(file=sys.stdout)
|
|
97
|
-
|
|
98
|
-
return 0
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
@cli.command()
|
|
102
|
-
def stop():
|
|
103
|
-
"""Send a 'quit_server' command to the Control Server."""
|
|
104
|
-
|
|
105
|
-
with Fw8Smc5Proxy() as proxy:
|
|
106
|
-
|
|
107
|
-
sp = proxy.get_service_proxy()
|
|
108
|
-
sp.quit_server()
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
@cli.command()
|
|
112
|
-
def status():
|
|
113
|
-
"""Send a 'quit_server' command to the FW8 SMC5 filterwheel."""
|
|
114
|
-
|
|
115
|
-
rich.print("FW8SMC5 filterwheel:")
|
|
116
|
-
|
|
117
|
-
protocol = CTRL_SETTINGS.PROTOCOL
|
|
118
|
-
hostname = CTRL_SETTINGS.HOSTNAME
|
|
119
|
-
port = CTRL_SETTINGS.COMMANDING_PORT
|
|
120
|
-
|
|
121
|
-
endpoint = connect_address(protocol, hostname, port)
|
|
122
|
-
|
|
123
|
-
if is_control_server_active(endpoint):
|
|
124
|
-
rich.print(f" Status: [green]active")
|
|
125
|
-
|
|
126
|
-
with Fw8Smc5Proxy() as filterwheel:
|
|
127
|
-
rich.print(f" Hostname: {filterwheel.get_ip_address()}")
|
|
128
|
-
rich.print(f" Monitoring port: {filterwheel.get_monitoring_port()}")
|
|
129
|
-
rich.print(f" Commanding port: {filterwheel.get_commanding_port()}")
|
|
130
|
-
rich.print(f" Service port: {filterwheel.get_service_port()}")
|
|
131
|
-
sim = filterwheel.is_simulator()
|
|
132
|
-
connected = filterwheel.is_connected()
|
|
133
|
-
rich.print(f"mode: {'simulator' if sim else 'device'}{' not' if not connected else ''} connected")
|
|
134
|
-
|
|
135
|
-
else:
|
|
136
|
-
rich.print(f" Status: [red]inactive")
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if __name__ == "__main__":
|
|
140
|
-
|
|
141
|
-
sys.exit(cli())
|