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/tcs/tcs.yaml
DELETED
egse/tcs/tcs_cs.py
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
The Control Server that connects to the PLATO TCS EGSE Hardware Controller.
|
|
3
|
-
|
|
4
|
-
Start the control server from the terminal as follows:
|
|
5
|
-
|
|
6
|
-
```bash
|
|
7
|
-
$ tcs_cs start
|
|
8
|
-
```
|
|
9
|
-
or when you don't have the device available, start the control server in simulator mode. That
|
|
10
|
-
will make the control server connect to a device software simulator:
|
|
11
|
-
```bash
|
|
12
|
-
$ tcs_cs start --sim
|
|
13
|
-
```
|
|
14
|
-
When you need to kill or stop the TCS control server, sue the stop command:
|
|
15
|
-
```bash
|
|
16
|
-
$ tcs_cs stop
|
|
17
|
-
```
|
|
18
|
-
Please note that software simulators are intended for simple test purposes and will not simulate
|
|
19
|
-
all device behavior correctly, e.g. timing, error conditions, etc.
|
|
20
|
-
|
|
21
|
-
"""
|
|
22
|
-
import logging
|
|
23
|
-
import multiprocessing
|
|
24
|
-
import sys
|
|
25
|
-
import time
|
|
26
|
-
|
|
27
|
-
from prometheus_client import start_http_server
|
|
28
|
-
|
|
29
|
-
multiprocessing.current_process().name = "tcs_cs"
|
|
30
|
-
|
|
31
|
-
import click
|
|
32
|
-
import invoke
|
|
33
|
-
import rich
|
|
34
|
-
import zmq
|
|
35
|
-
|
|
36
|
-
from egse.control import ControlServer
|
|
37
|
-
from egse.control import is_control_server_active
|
|
38
|
-
from egse.settings import Settings
|
|
39
|
-
from egse.tcs.tcs import TCSProxy
|
|
40
|
-
from egse.tcs.tcs import is_tcs_cs_active
|
|
41
|
-
from egse.tcs.tcs_protocol import TCSProtocol
|
|
42
|
-
from egse.zmq_ser import connect_address
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
logger = logging.getLogger(__name__)
|
|
46
|
-
|
|
47
|
-
CTRL_SETTINGS = Settings.load("TCS Control Server")
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def is_tcs_cs_active(timeout: float = 2.0):
|
|
51
|
-
"""
|
|
52
|
-
Checks whether the TCS EGSE Control Server is running.
|
|
53
|
-
|
|
54
|
-
Args:
|
|
55
|
-
timeout (float): Timeout when waiting for a reply [seconds, default=2.0]
|
|
56
|
-
|
|
57
|
-
Returns:
|
|
58
|
-
True if the TCS EGSE CS is running and replied with the expected answer.
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
endpoint = connect_address(
|
|
62
|
-
CTRL_SETTINGS.PROTOCOL, CTRL_SETTINGS.HOSTNAME, CTRL_SETTINGS.COMMANDING_PORT
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
return is_control_server_active(endpoint, timeout)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class TCSControlServer(ControlServer):
|
|
69
|
-
"""TCSControlServer - Command and monitor the TCS EGSE hardware.
|
|
70
|
-
|
|
71
|
-
This class works as a command and monitoring server to control the TCS EGSE.
|
|
72
|
-
This control server shall be used as the single point access for controlling the hardware
|
|
73
|
-
device. Monitoring access should be done preferably through this control server also.
|
|
74
|
-
|
|
75
|
-
The sever binds to the following ZeroMQ sockets:
|
|
76
|
-
|
|
77
|
-
* a REQ-REP socket that can be used as a command server. Any client can connect and
|
|
78
|
-
send a command to the TCS EGSE.
|
|
79
|
-
|
|
80
|
-
* a PUB-SUP socket that serves as a monitoring server. It will send out TCS EGSE status
|
|
81
|
-
information to all the connected clients every TBD seconds.
|
|
82
|
-
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
def __init__(self):
|
|
86
|
-
super().__init__()
|
|
87
|
-
|
|
88
|
-
self.device_protocol = TCSProtocol(self)
|
|
89
|
-
|
|
90
|
-
self.logger.info(f"Binding ZeroMQ socket to {self.device_protocol.get_bind_address()}")
|
|
91
|
-
|
|
92
|
-
self.device_protocol.bind(self.dev_ctrl_cmd_sock)
|
|
93
|
-
|
|
94
|
-
self.poller.register(self.dev_ctrl_cmd_sock, zmq.POLLIN)
|
|
95
|
-
|
|
96
|
-
self.set_delay(CTRL_SETTINGS.ST_DELAY)
|
|
97
|
-
self.set_hk_delay(CTRL_SETTINGS.HK_DELAY)
|
|
98
|
-
|
|
99
|
-
def get_communication_protocol(self):
|
|
100
|
-
return CTRL_SETTINGS.PROTOCOL
|
|
101
|
-
|
|
102
|
-
def get_commanding_port(self):
|
|
103
|
-
return CTRL_SETTINGS.COMMANDING_PORT
|
|
104
|
-
|
|
105
|
-
def get_service_port(self):
|
|
106
|
-
return CTRL_SETTINGS.SERVICE_PORT
|
|
107
|
-
|
|
108
|
-
def get_monitoring_port(self):
|
|
109
|
-
return CTRL_SETTINGS.MONITORING_PORT
|
|
110
|
-
|
|
111
|
-
def get_metrics_port(self):
|
|
112
|
-
return CTRL_SETTINGS.METRICS_PORT
|
|
113
|
-
|
|
114
|
-
def get_storage_mnemonic(self):
|
|
115
|
-
try:
|
|
116
|
-
return CTRL_SETTINGS.STORAGE_MNEMONIC
|
|
117
|
-
except AttributeError:
|
|
118
|
-
return "TCS"
|
|
119
|
-
|
|
120
|
-
def before_serve(self):
|
|
121
|
-
start_http_server(CTRL_SETTINGS.CS_METRICS_PORT)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
@click.group()
|
|
125
|
-
def cli():
|
|
126
|
-
pass
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
@cli.command()
|
|
130
|
-
@click.option(
|
|
131
|
-
"--simulator", "--sim", is_flag=True, help="Start the TCS EGSE Simulator as the backend."
|
|
132
|
-
)
|
|
133
|
-
def start(simulator):
|
|
134
|
-
"""Start the TCS EGSE Control Server."""
|
|
135
|
-
|
|
136
|
-
if simulator:
|
|
137
|
-
Settings.set_simulation_mode(True)
|
|
138
|
-
|
|
139
|
-
try:
|
|
140
|
-
controller = TCSControlServer()
|
|
141
|
-
controller.serve()
|
|
142
|
-
except KeyboardInterrupt:
|
|
143
|
-
print("Shutdown requested...exiting")
|
|
144
|
-
except SystemExit as exit_code:
|
|
145
|
-
print(f"System Exit with code {exit_code}.")
|
|
146
|
-
sys.exit(exit_code)
|
|
147
|
-
except Exception as exc:
|
|
148
|
-
logger.exception(f"Cannot start the TCS EGSE Control Server: {exc}")
|
|
149
|
-
|
|
150
|
-
time.sleep(3.0) # Give the process and sub-process (TCSTelemetry) time to start
|
|
151
|
-
|
|
152
|
-
return 0
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
@cli.command()
|
|
156
|
-
def start_bg():
|
|
157
|
-
"""Start the TCS EGSE Control Server in the background."""
|
|
158
|
-
invoke.run("tcs_cs start", disown=True)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
@cli.command()
|
|
162
|
-
def stop():
|
|
163
|
-
"""Send a 'quit_server' command to the TCS EGSE Control Server."""
|
|
164
|
-
|
|
165
|
-
if not is_tcs_cs_active():
|
|
166
|
-
rich.print("[red]I couldn't find the TCS Control Server, no action taken.")
|
|
167
|
-
return
|
|
168
|
-
|
|
169
|
-
with TCSProxy() as proxy:
|
|
170
|
-
|
|
171
|
-
sp = proxy.get_service_proxy()
|
|
172
|
-
sp.quit_server()
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
@cli.command()
|
|
176
|
-
def status():
|
|
177
|
-
"""Request status information from the Control Server."""
|
|
178
|
-
|
|
179
|
-
protocol = CTRL_SETTINGS.PROTOCOL
|
|
180
|
-
hostname = CTRL_SETTINGS.HOSTNAME
|
|
181
|
-
port = CTRL_SETTINGS.COMMANDING_PORT
|
|
182
|
-
|
|
183
|
-
endpoint = connect_address(protocol, hostname, port)
|
|
184
|
-
|
|
185
|
-
if is_control_server_active(endpoint):
|
|
186
|
-
rich.print("TCS CS: [green]active")
|
|
187
|
-
with TCSProxy() as tcs:
|
|
188
|
-
sim = tcs.is_simulator()
|
|
189
|
-
connected = tcs.is_connected()
|
|
190
|
-
ip = tcs.get_ip_address()
|
|
191
|
-
rich.print(f"mode: {'simulator' if sim else 'device'}"
|
|
192
|
-
f"{' not' if not connected else ''} connected")
|
|
193
|
-
rich.print(f"hostname: {ip}")
|
|
194
|
-
else:
|
|
195
|
-
rich.print('TCS CS: [red]not active')
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if __name__ == "__main__":
|
|
199
|
-
|
|
200
|
-
logging.basicConfig(level=logging.DEBUG, format=Settings.LOG_FORMAT_FULL)
|
|
201
|
-
|
|
202
|
-
sys.exit(cli())
|
egse/tcs/tcs_devif.py
DELETED
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import socket
|
|
3
|
-
import sys
|
|
4
|
-
|
|
5
|
-
from egse.device import DeviceConnectionError
|
|
6
|
-
from egse.device import DeviceConnectionInterface
|
|
7
|
-
from egse.device import DeviceTimeoutError
|
|
8
|
-
from egse.device import DeviceTransport
|
|
9
|
-
from egse.settings import Settings
|
|
10
|
-
from egse.system import Timer
|
|
11
|
-
from egse.system import format_datetime
|
|
12
|
-
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
IDENTIFICATION_QUERY = "*IDN?"
|
|
16
|
-
|
|
17
|
-
READ_TIMEOUT = 5.0 # seconds
|
|
18
|
-
WRITE_TIMEOUT = 1.0 # seconds
|
|
19
|
-
CONNECT_TIMEOUT = 3.0 # seconds
|
|
20
|
-
|
|
21
|
-
DEVICE_SETTINGS = Settings.load("TCS Controller")
|
|
22
|
-
DEVICE_NAME = "TCS EGSE"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class TCSEthernetInterface(DeviceConnectionInterface, DeviceTransport):
|
|
26
|
-
"""Defines the low-level interface to the Keithley DAQ6510 Controller."""
|
|
27
|
-
|
|
28
|
-
def __init__(self, hostname=None, port=None):
|
|
29
|
-
"""
|
|
30
|
-
Args:
|
|
31
|
-
hostname (str): the IP address or fully qualified hostname of the TCS EGSE hardware
|
|
32
|
-
controller. The default is defined in the 'settings.yaml' configuration file.
|
|
33
|
-
|
|
34
|
-
port (int): the IP port number to connect to. The default is defined in the
|
|
35
|
-
'settings.yaml' configuration file.
|
|
36
|
-
"""
|
|
37
|
-
super().__init__()
|
|
38
|
-
|
|
39
|
-
self.hostname = hostname or DEVICE_SETTINGS.HOSTNAME
|
|
40
|
-
self.port = port or DEVICE_SETTINGS.COMMANDING_PORT
|
|
41
|
-
self.sock = None
|
|
42
|
-
|
|
43
|
-
self.is_connection_open = False
|
|
44
|
-
|
|
45
|
-
def connect(self):
|
|
46
|
-
"""Connect the device.
|
|
47
|
-
|
|
48
|
-
Raises:
|
|
49
|
-
DeviceConnectionError: When the connection could not be established. Check the logging
|
|
50
|
-
messages for more detail.
|
|
51
|
-
|
|
52
|
-
DeviceTimeoutError: When the connection timed out.
|
|
53
|
-
|
|
54
|
-
ValueError: When hostname or port number are not provided.
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
# Sanity checks
|
|
58
|
-
|
|
59
|
-
if self.is_connection_open:
|
|
60
|
-
logger.warning(f"{DEVICE_NAME}: trying to connect to an already connected socket.")
|
|
61
|
-
return
|
|
62
|
-
|
|
63
|
-
if self.hostname in (None, ""):
|
|
64
|
-
raise ValueError(f"{DEVICE_NAME}: hostname is not initialized.")
|
|
65
|
-
|
|
66
|
-
if self.port in (None, 0):
|
|
67
|
-
raise ValueError(f"{DEVICE_NAME}: port number is not initialized.")
|
|
68
|
-
|
|
69
|
-
# Create a new socket instance
|
|
70
|
-
|
|
71
|
-
try:
|
|
72
|
-
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
73
|
-
except socket.error as e_socket:
|
|
74
|
-
raise DeviceConnectionError(DEVICE_NAME, "Failed to create socket.") from e_socket
|
|
75
|
-
|
|
76
|
-
# Attempt to establish a connection to the remote host
|
|
77
|
-
|
|
78
|
-
# FIXME: Socket shall be closed on exception?
|
|
79
|
-
|
|
80
|
-
# We set a timeout of CONNECT_TIMEOUT sec before connecting and reset to None
|
|
81
|
-
# (=blocking) after the connect. The reason for this is because when no
|
|
82
|
-
# device is available, e.g during testing, the timeout will take about
|
|
83
|
-
# two minutes which is way too long. It needs to be evaluated if this
|
|
84
|
-
# approach is acceptable and not causing problems during production.
|
|
85
|
-
|
|
86
|
-
try:
|
|
87
|
-
logger.debug(f'Connecting a socket to host "{self.hostname}" using port {self.port}')
|
|
88
|
-
self.sock.settimeout(CONNECT_TIMEOUT)
|
|
89
|
-
self.sock.connect((self.hostname, self.port))
|
|
90
|
-
self.sock.settimeout(None)
|
|
91
|
-
except ConnectionRefusedError as exc:
|
|
92
|
-
raise DeviceConnectionError(
|
|
93
|
-
DEVICE_NAME, f"Connection refused to {self.hostname}:{self.port}."
|
|
94
|
-
) from exc
|
|
95
|
-
except TimeoutError as exc:
|
|
96
|
-
raise DeviceTimeoutError(
|
|
97
|
-
DEVICE_NAME, f"Connection to {self.hostname}:{self.port} timed out."
|
|
98
|
-
) from exc
|
|
99
|
-
except socket.gaierror as exc:
|
|
100
|
-
raise DeviceConnectionError(
|
|
101
|
-
DEVICE_NAME, f"socket address info error for {self.hostname}"
|
|
102
|
-
) from exc
|
|
103
|
-
except socket.herror as exc:
|
|
104
|
-
raise DeviceConnectionError(
|
|
105
|
-
DEVICE_NAME, f"socket host address error for {self.hostname}"
|
|
106
|
-
) from exc
|
|
107
|
-
except socket.timeout as exc:
|
|
108
|
-
raise DeviceTimeoutError(
|
|
109
|
-
DEVICE_NAME, f"socket timeout error for {self.hostname}:{self.port}"
|
|
110
|
-
) from exc
|
|
111
|
-
except OSError as exc:
|
|
112
|
-
raise DeviceConnectionError(DEVICE_NAME, f"OSError caught ({exc}).") from exc
|
|
113
|
-
|
|
114
|
-
self.is_connection_open = True
|
|
115
|
-
|
|
116
|
-
def disconnect(self):
|
|
117
|
-
"""Disconnect from the Ethernet connection.
|
|
118
|
-
|
|
119
|
-
Raises:
|
|
120
|
-
DeviceConnectionError when the socket could not be closed.
|
|
121
|
-
"""
|
|
122
|
-
|
|
123
|
-
try:
|
|
124
|
-
if self.is_connection_open:
|
|
125
|
-
logger.debug(f"Disconnecting from {self.hostname}")
|
|
126
|
-
self.sock.close()
|
|
127
|
-
self.is_connection_open = False
|
|
128
|
-
except Exception as e_exc:
|
|
129
|
-
raise DeviceConnectionError(
|
|
130
|
-
DEVICE_NAME, f"Could not close socket to {self.hostname}") from e_exc
|
|
131
|
-
|
|
132
|
-
def reconnect(self):
|
|
133
|
-
"""
|
|
134
|
-
Reconnect to the device. If the connection is open, this function will first disconnect
|
|
135
|
-
and then connect again.
|
|
136
|
-
"""
|
|
137
|
-
|
|
138
|
-
if self.is_connection_open:
|
|
139
|
-
self.disconnect()
|
|
140
|
-
self.connect()
|
|
141
|
-
|
|
142
|
-
def is_connected(self) -> bool:
|
|
143
|
-
"""
|
|
144
|
-
Check if the device is connected.
|
|
145
|
-
|
|
146
|
-
Returns:
|
|
147
|
-
True is the device is connected, False otherwise.
|
|
148
|
-
"""
|
|
149
|
-
|
|
150
|
-
return bool(self.is_connection_open)
|
|
151
|
-
|
|
152
|
-
def read(self) -> bytes:
|
|
153
|
-
"""
|
|
154
|
-
Read a response from the device.
|
|
155
|
-
|
|
156
|
-
Returns:
|
|
157
|
-
A bytes object containing the response from the device. No processing is done
|
|
158
|
-
on the response.
|
|
159
|
-
Raises:
|
|
160
|
-
A DeviceTimeoutError when the read operation timed out.
|
|
161
|
-
"""
|
|
162
|
-
idx, n_total = 0, 0
|
|
163
|
-
buf_size = 1024 * 10
|
|
164
|
-
response = bytes()
|
|
165
|
-
|
|
166
|
-
# Set a timeout of READ_TIMEOUT to the socket.recv
|
|
167
|
-
|
|
168
|
-
saved_timeout = self.sock.gettimeout()
|
|
169
|
-
self.sock.settimeout(READ_TIMEOUT)
|
|
170
|
-
|
|
171
|
-
try:
|
|
172
|
-
for idx in range(100):
|
|
173
|
-
data = self.sock.recv(buf_size)
|
|
174
|
-
n = len(data)
|
|
175
|
-
n_total += n
|
|
176
|
-
response += data
|
|
177
|
-
if b'\x03' in response:
|
|
178
|
-
break
|
|
179
|
-
except socket.timeout as e_timeout:
|
|
180
|
-
logger.warning(f"Socket timeout error: {e_timeout}")
|
|
181
|
-
raise DeviceTimeoutError(DEVICE_NAME, "Socket timeout error") from e_timeout
|
|
182
|
-
finally:
|
|
183
|
-
self.sock.settimeout(saved_timeout)
|
|
184
|
-
|
|
185
|
-
# logger.info(f"Total number of bytes received is {n_total}, idx={idx}")
|
|
186
|
-
# logger.info(f"> {len(response)=}")
|
|
187
|
-
# logger.info(f"> {response[:80]=}")
|
|
188
|
-
|
|
189
|
-
return response
|
|
190
|
-
|
|
191
|
-
def write(self, command: str):
|
|
192
|
-
"""
|
|
193
|
-
Send a command to the device.
|
|
194
|
-
|
|
195
|
-
No processing is done on the command string, except for the encoding into a bytes object.
|
|
196
|
-
|
|
197
|
-
Args:
|
|
198
|
-
command: the command string including terminators.
|
|
199
|
-
|
|
200
|
-
Raises:
|
|
201
|
-
A DeviceTimeoutError when the send timed out, and a DeviceConnectionError if
|
|
202
|
-
there was a socket related error.
|
|
203
|
-
"""
|
|
204
|
-
|
|
205
|
-
try:
|
|
206
|
-
self.sock.sendall(command.encode())
|
|
207
|
-
except socket.timeout as e_timeout:
|
|
208
|
-
raise DeviceTimeoutError(DEVICE_NAME, "Socket timeout error") from e_timeout
|
|
209
|
-
except socket.error as e_socket:
|
|
210
|
-
# Interpret any socket-related error as an I/O error
|
|
211
|
-
raise DeviceConnectionError(DEVICE_NAME, "Socket communication error.") from e_socket
|
|
212
|
-
|
|
213
|
-
def trans(self, command: str):
|
|
214
|
-
"""
|
|
215
|
-
Send a command to the device and wait for the response.
|
|
216
|
-
|
|
217
|
-
No processing is done on the command string, except for the encoding into a bytes object.
|
|
218
|
-
|
|
219
|
-
Args:
|
|
220
|
-
command: the command string including terminators.
|
|
221
|
-
|
|
222
|
-
Returns:
|
|
223
|
-
A bytes object containing the response from the device. No processing is done
|
|
224
|
-
on the response.
|
|
225
|
-
|
|
226
|
-
Raises:
|
|
227
|
-
A DeviceTimeoutError when the send timed out, and a DeviceConnectionError if
|
|
228
|
-
there was a socket related error.
|
|
229
|
-
"""
|
|
230
|
-
|
|
231
|
-
try:
|
|
232
|
-
# Attempt to send the complete command
|
|
233
|
-
|
|
234
|
-
self.sock.sendall(command.encode())
|
|
235
|
-
|
|
236
|
-
# wait for, read and return the response (will be at most TBD chars)
|
|
237
|
-
|
|
238
|
-
return_string = self.read()
|
|
239
|
-
|
|
240
|
-
return return_string
|
|
241
|
-
|
|
242
|
-
except socket.timeout as e_timeout:
|
|
243
|
-
raise DeviceTimeoutError(DEVICE_NAME, "Socket timeout error") from e_timeout
|
|
244
|
-
except socket.error as e_socket:
|
|
245
|
-
# Interpret any socket-related error as an I/O error
|
|
246
|
-
raise DeviceConnectionError(DEVICE_NAME, "Socket communication error.") from e_socket
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if __name__ == "__main__":
|
|
250
|
-
|
|
251
|
-
from rich import print
|
|
252
|
-
|
|
253
|
-
def send_command(cmd):
|
|
254
|
-
cmd = cmd.rstrip()
|
|
255
|
-
with Timer("TCS EGSE Query"):
|
|
256
|
-
response = tcs.query(cmd + "\n")
|
|
257
|
-
logger.debug(f"{format_datetime()} Response for {cmd:>20s}: {response.rstrip()}")
|
|
258
|
-
return response.decode()
|
|
259
|
-
|
|
260
|
-
tcs = TCSEthernetInterface(hostname='localhost')
|
|
261
|
-
|
|
262
|
-
print("-" * 10, end="")
|
|
263
|
-
print("Connecting to the device.")
|
|
264
|
-
|
|
265
|
-
try:
|
|
266
|
-
tcs.connect()
|
|
267
|
-
except DeviceTimeoutError as exc:
|
|
268
|
-
print(f"[red]{exc}[/red]")
|
|
269
|
-
sys.exit(-1)
|
|
270
|
-
|
|
271
|
-
print("-"*10, end='')
|
|
272
|
-
print("Requesting remote operations.")
|
|
273
|
-
|
|
274
|
-
response = send_command("request_remote_operation")
|
|
275
|
-
print(f"{response=}")
|
|
276
|
-
|
|
277
|
-
if "not_active" in response:
|
|
278
|
-
print("[red]Remote operation was rejected from the TCS EGSE.[/red]")
|
|
279
|
-
|
|
280
|
-
print("Set operation mode .")
|
|
281
|
-
|
|
282
|
-
response = send_command("set_parameter operation_mode 6") # Extended operation mode
|
|
283
|
-
print(f"{response=}")
|
|
284
|
-
|
|
285
|
-
print("Stopping remote operations.")
|
|
286
|
-
|
|
287
|
-
response = send_command("quit_remote_operation") # !!!! no response expected !!!!
|
|
288
|
-
print(f"{response=}")
|
|
289
|
-
|
|
290
|
-
print("Disconnecting from the device.")
|
|
291
|
-
|
|
292
|
-
tcs.disconnect()
|
egse/tcs/tcs_protocol.py
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
import logging
|
|
3
|
-
import multiprocessing
|
|
4
|
-
from typing import List
|
|
5
|
-
|
|
6
|
-
from egse.command import ClientServerCommand
|
|
7
|
-
from egse.control import ControlServer
|
|
8
|
-
from egse.control import Failure
|
|
9
|
-
from egse.device import DeviceConnectionState
|
|
10
|
-
from egse.device import DeviceTimeoutError
|
|
11
|
-
from egse.metrics import define_metrics
|
|
12
|
-
from egse.protocol import DynamicCommandProtocol
|
|
13
|
-
from egse.settings import Settings
|
|
14
|
-
from egse.setup import load_setup, Setup
|
|
15
|
-
from egse.system import format_datetime
|
|
16
|
-
from egse.tcs.tcs import TCSController
|
|
17
|
-
from egse.tcs.tcs import TCSParameterNaming
|
|
18
|
-
from egse.tcs.tcs import TCSSimulator
|
|
19
|
-
from egse.tcs.tcs import TCSTelemetry
|
|
20
|
-
|
|
21
|
-
MODULE_LOGGER = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
|
-
CTRL_SETTINGS = Settings.load("TCS Control Server")
|
|
24
|
-
PUNA_SETTINGS = Settings.load(filename="tcs.yaml")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class TCSCommand(ClientServerCommand):
|
|
28
|
-
def get_cmd_string(self, *args, **kwargs) -> str:
|
|
29
|
-
out = super().get_cmd_string(*args, **kwargs)
|
|
30
|
-
return out + chr(3) # end the string with the ASCII character EOT
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class TCSMetrics:
|
|
34
|
-
"""Defines the metrics for the TCS EGSE that are maintained by the TCSProtocol class."""
|
|
35
|
-
def __init__(self, origin: str, dashboard: str, setup: Setup):
|
|
36
|
-
self.metrics = define_metrics(origin=origin, dashboard=dashboard, setup=setup)
|
|
37
|
-
|
|
38
|
-
def __contains__(self, item):
|
|
39
|
-
return self.metrics.__contains__(item)
|
|
40
|
-
|
|
41
|
-
def names(self):
|
|
42
|
-
return self.metrics.keys()
|
|
43
|
-
|
|
44
|
-
def update_metrics(self, name: str, value: str):
|
|
45
|
-
"""Update the TCS metric parameter with the given value."""
|
|
46
|
-
if name in self.metrics:
|
|
47
|
-
self.metrics[name].set(float(value))
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
class TCSProtocol(DynamicCommandProtocol):
|
|
51
|
-
def __init__(self, control_server: ControlServer):
|
|
52
|
-
super().__init__(control_server)
|
|
53
|
-
|
|
54
|
-
setup = load_setup()
|
|
55
|
-
|
|
56
|
-
# Read the configuration metrics from the tm-dictionary
|
|
57
|
-
|
|
58
|
-
self._metrics = TCSMetrics(origin=control_server.get_storage_mnemonic(),
|
|
59
|
-
dashboard="TCS_CONFIGURATION_MON", setup=setup)
|
|
60
|
-
|
|
61
|
-
# Device naming is different from CGSE naming, the conversion is handled in the
|
|
62
|
-
# TCSParameterNaming class.
|
|
63
|
-
|
|
64
|
-
self._hk_names = TCSParameterNaming(origin=control_server.get_storage_mnemonic(), setup=setup)
|
|
65
|
-
|
|
66
|
-
# Set up two queue's to communicate with the TCS Telemetry Process.
|
|
67
|
-
# The command queue is joinable because the Controller needs to wait for a response in
|
|
68
|
-
# the response queue.
|
|
69
|
-
|
|
70
|
-
self.command_queue = multiprocessing.Queue()
|
|
71
|
-
self.response_queue = multiprocessing.Queue()
|
|
72
|
-
|
|
73
|
-
# Start a separate Process to handle the TCS EGSE Telemetry
|
|
74
|
-
|
|
75
|
-
self.processor = TCSTelemetry(self.command_queue, self.response_queue)
|
|
76
|
-
self.processor.name = "tcs.telemetry"
|
|
77
|
-
self.processor.start()
|
|
78
|
-
|
|
79
|
-
self.device = TCSSimulator() if Settings.simulation_mode() else TCSController()
|
|
80
|
-
|
|
81
|
-
try:
|
|
82
|
-
self.device.connect()
|
|
83
|
-
except (ConnectionError, DeviceTimeoutError) as exc:
|
|
84
|
-
MODULE_LOGGER.warning(
|
|
85
|
-
f"Couldn't establish a connection to the TCS EGSE ({exc}).")
|
|
86
|
-
|
|
87
|
-
self._dt_of_last_error = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
88
|
-
|
|
89
|
-
def quit(self):
|
|
90
|
-
self.processor.terminate()
|
|
91
|
-
|
|
92
|
-
def get_device(self):
|
|
93
|
-
return self.device
|
|
94
|
-
|
|
95
|
-
def get_status(self):
|
|
96
|
-
|
|
97
|
-
status = super().get_status()
|
|
98
|
-
|
|
99
|
-
# TODO (rik): add status information for the monitoring service here
|
|
100
|
-
|
|
101
|
-
if self.state == DeviceConnectionState.DEVICE_CONNECTED or Settings.simulation_mode():
|
|
102
|
-
# Collect status information here
|
|
103
|
-
pass
|
|
104
|
-
|
|
105
|
-
return status
|
|
106
|
-
|
|
107
|
-
def get_housekeeping(self) -> dict:
|
|
108
|
-
|
|
109
|
-
self.log_new_errors()
|
|
110
|
-
|
|
111
|
-
result = {"timestamp": format_datetime()}
|
|
112
|
-
|
|
113
|
-
# Put in NaN as a default value, this will be updated with the actual real values
|
|
114
|
-
# when the TCS EGSE is in remote control mode and the configuration can be obtained.
|
|
115
|
-
# This 'initialisation' is also needed because the column names are determined when
|
|
116
|
-
# the TCS EGSE is not in remote control mode.
|
|
117
|
-
|
|
118
|
-
result.update(
|
|
119
|
-
{name: float('nan') for name in self._metrics.names()}
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
# if self.state == DeviceConnectionState.DEVICE_CONNECTED:
|
|
123
|
-
# # Collect housekeeping information here
|
|
124
|
-
# pass
|
|
125
|
-
|
|
126
|
-
configuration = self.device.get_configuration()
|
|
127
|
-
|
|
128
|
-
if isinstance(configuration, Failure):
|
|
129
|
-
[self._metrics.update_metrics(name, 'nan') for name in self._metrics.names()]
|
|
130
|
-
return result
|
|
131
|
-
|
|
132
|
-
# update the housekeeping table with the actual values for the Storage
|
|
133
|
-
|
|
134
|
-
result.update(
|
|
135
|
-
{
|
|
136
|
-
self._hk_names.get_cgse_name(name): value
|
|
137
|
-
for name, value in configuration.items()
|
|
138
|
-
if self._hk_names.get_cgse_name(name) in self._metrics
|
|
139
|
-
}
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
# update the recorded metrics for Prometheus/Grafana
|
|
143
|
-
|
|
144
|
-
for name, value in configuration.items():
|
|
145
|
-
self._metrics.update_metrics(self._hk_names.get_cgse_name(name), value)
|
|
146
|
-
|
|
147
|
-
return result
|
|
148
|
-
|
|
149
|
-
def log_new_errors(self):
|
|
150
|
-
|
|
151
|
-
errors = new_errors = None
|
|
152
|
-
try:
|
|
153
|
-
errors = self.device.get_error()
|
|
154
|
-
new_errors = self._extract_last_error(errors)
|
|
155
|
-
for error in new_errors:
|
|
156
|
-
MODULE_LOGGER.error(f"TCS EGSE: {error}")
|
|
157
|
-
except Exception as exc:
|
|
158
|
-
MODULE_LOGGER.error(f"Exception caught: {exc=}")
|
|
159
|
-
MODULE_LOGGER.debug(f"{errors=}")
|
|
160
|
-
MODULE_LOGGER.debug(f"{new_errors=}")
|
|
161
|
-
|
|
162
|
-
def _extract_last_error(self, errors: List):
|
|
163
|
-
|
|
164
|
-
new_errors = []
|
|
165
|
-
|
|
166
|
-
for error_msg in errors:
|
|
167
|
-
if 'remote_mode_not_active' in error_msg:
|
|
168
|
-
MODULE_LOGGER.warning("TCS EGSE: Remote mode is not active")
|
|
169
|
-
break
|
|
170
|
-
if 'no errors' in error_msg:
|
|
171
|
-
break
|
|
172
|
-
dt_error_str, *_, msg = error_msg.split('\t')
|
|
173
|
-
dt_error = datetime.datetime.strptime(dt_error_str, "%Y/%m/%d %H:%M:%S.%f UTC")
|
|
174
|
-
dt_error = dt_error.replace(tzinfo=datetime.timezone.utc)
|
|
175
|
-
if dt_error > self._dt_of_last_error:
|
|
176
|
-
new_errors.append((format_datetime(dt_error), msg))
|
|
177
|
-
|
|
178
|
-
self._dt_of_last_error = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
179
|
-
|
|
180
|
-
return new_errors
|