From 553e5de6e4c8a2325659dbf9b20b3a49ab49d15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20K=C3=BCnsem=C3=B6ller?= <jkuensem@physik.uni-bielefeld.de> Date: Fri, 6 Apr 2018 13:34:34 +0000 Subject: [PATCH] Task SW-111: Working implementation with tests. --- .gitattributes | 7 + LCU/checkhardware/CMakeLists.txt | 17 +- LCU/checkhardware/check_hardware.py | 113 +++++++- .../checkhardware_lib/CMakeLists.txt | 21 ++ .../spectrum_checks/CMakeLists.txt | 19 ++ .../config/FR606-check_hardware.conf | 2 + LCU/checkhardware/test/CMakeLists.txt | 5 + LCU/checkhardware/test/t_check_hardware.py | 226 ++++++++++++++++ LCU/checkhardware/test/t_check_hardware.run | 6 + LCU/checkhardware/test/t_check_hardware.sh | 2 + .../test/test-check_hardware.conf | 247 ++++++++++++++++++ 11 files changed, 661 insertions(+), 4 deletions(-) create mode 100644 LCU/checkhardware/checkhardware_lib/CMakeLists.txt create mode 100644 LCU/checkhardware/checkhardware_lib/spectrum_checks/CMakeLists.txt create mode 100644 LCU/checkhardware/test/CMakeLists.txt create mode 100644 LCU/checkhardware/test/t_check_hardware.py create mode 100755 LCU/checkhardware/test/t_check_hardware.run create mode 100755 LCU/checkhardware/test/t_check_hardware.sh create mode 100644 LCU/checkhardware/test/test-check_hardware.conf diff --git a/.gitattributes b/.gitattributes index 1059d9d2765..7bb79e5af45 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1963,6 +1963,7 @@ LCU/StationTest/xc_160_verify.sh eol=lf LCU/StationTest/xc_200_setup.sh eol=lf LCU/StationTest/xc_200_verify.sh eol=lf LCU/checkhardware/check_hardware.py -text +LCU/checkhardware/checkhardware_lib/CMakeLists.txt -text LCU/checkhardware/checkhardware_lib/__init__.py -text LCU/checkhardware/checkhardware_lib/data.py -text LCU/checkhardware/checkhardware_lib/db.py -text @@ -1974,6 +1975,7 @@ LCU/checkhardware/checkhardware_lib/lofar.py -text LCU/checkhardware/checkhardware_lib/reporting.py -text LCU/checkhardware/checkhardware_lib/rsp.py -text LCU/checkhardware/checkhardware_lib/settings.py -text +LCU/checkhardware/checkhardware_lib/spectrum_checks/CMakeLists.txt -text LCU/checkhardware/checkhardware_lib/spectrum_checks/__init__.py -text LCU/checkhardware/checkhardware_lib/spectrum_checks/cable_reflection.py -text LCU/checkhardware/checkhardware_lib/spectrum_checks/down.py -text @@ -2043,6 +2045,11 @@ LCU/checkhardware/do_station_test.sh -text svneol=unset#application/x-shellscrip LCU/checkhardware/rtsm.py -text LCU/checkhardware/show_bad_spectra.py -text LCU/checkhardware/show_test_result.py -text +LCU/checkhardware/test/CMakeLists.txt -text +LCU/checkhardware/test/t_check_hardware.py -text +LCU/checkhardware/test/t_check_hardware.run -text +LCU/checkhardware/test/t_check_hardware.sh -text +LCU/checkhardware/test/test-check_hardware.conf -text LCU/checkhardware/update_pvss.py -text LTA/LTAIngest/LTAIngestClient/bin/CMakeLists.txt -text LTA/LTAIngest/LTAIngestClient/bin/ingestaddjobstoqueue -text diff --git a/LCU/checkhardware/CMakeLists.txt b/LCU/checkhardware/CMakeLists.txt index a94754b9dcd..2bddc75a90d 100644 --- a/LCU/checkhardware/CMakeLists.txt +++ b/LCU/checkhardware/CMakeLists.txt @@ -1,6 +1,15 @@ # $Id$ -lofar_package(checkhardware 1.0) +lofar_package(checkhardware 1.0 DEPENDS PyCommon) +include(PythonInstall) + +# install for testing in cmake +set(_py_files + check_hardware.py +) + +python_install(${_py_files} DESTINATION lofar/lcu/checkhardware) + # Install files matching regex pattern in current directory and below install(DIRECTORY . @@ -14,3 +23,9 @@ install(DIRECTORY config/ USE_SOURCE_PERMISSIONS FILES_MATCHING REGEX "(\\.conf)$" PATTERN ".svn" EXCLUDE) + + +add_subdirectory(test) +add_subdirectory(checkhardware_lib) + + diff --git a/LCU/checkhardware/check_hardware.py b/LCU/checkhardware/check_hardware.py index 9dc57811d14..beb6da1ae5e 100755 --- a/LCU/checkhardware/check_hardware.py +++ b/LCU/checkhardware/check_hardware.py @@ -51,6 +51,13 @@ from time import sleep import datetime from socket import gethostname import logging +from signal import SIGABRT, SIGINT, SIGTERM, signal +import atexit +from subprocess import Popen, check_call, CalledProcessError, STDOUT +from functools import partial + +# FIXME: There is _way_ too much going on here outside a function, including things that might fail (like path checks) +# FIXME: emoving hard dependencies on station environment os.umask(001) @@ -283,6 +290,103 @@ def wait_for_start(start_datetime): return +def stop_test_signal(cmd): + logger.info("Stopping test signal.") + + # try to execute command to stop test signal + try: + check_call(cmd, shell=True) + except CalledProcessError as ex: + logger.error(("Could not stop the test signal! Non-zero return code from start_cmd (%s)." % cmd), ex) + raise + +def stop_test_signal_and_exit(cmd, *optargs): + """ + Signal handler that exits with the return code of a passed POSIX signal after executing the provided command. + + :param cmd: The command to stop the test signal + :param optargs: The intercepted POSIX signal + """ + stop_test_signal(cmd) + + # try to get correct return code + logger.info('Now exiting.') + try: + ret_code = int(optargs[0]) # use POSIX signal code + os._exit(ret_code) # sys.exit() won't work here, we don't want to trigger our handler again + # (hm, we could actually call sys.exit and just trigger the atexit handler, but this is more explicit and keeps + # things operational independently.) + except: + os._exit(1) + + +def register_exit_handler(cmd): + """ + execute stop_cmd when script exits normally or with Exception + :param cmd: the command to execute + """ + # execute stop_cmd when script exits normally + atexit.register(stop_test_signal, cmd) + + +def register_signal_handlers(cmd): + """ + execute stop_cmd when script is terminated externally + :param cmd: the command to execute + """ + # execute stop_cmd when script exits normally + atexit.register(stop_test_signal, cmd) + + # handle POSIX signals + for sig in (SIGABRT, SIGINT, SIGTERM): + signal(sig, partial(stop_test_signal_and_exit, cmd)) + + +def start_watchdog_daemon(pid, cmd): + """ + Start a daemon that sits and waits for this script to terminate and then execute the provided command. + We cannot handle SIGKILL / kill -9 from inside the script, so we have to handle that case this way. This may be + a bit --wait for it-- overkill (hah!) and I don't see why this would be needed under normal circumstances, but + nonetheless, since this was requested on the ticket, here we go. + :param cmd: command as shell-executable string + """ + daemon_cmd = 'while ps -p %s > /dev/null; do sleep 1; done; %s' % (pid, cmd) + Popen(daemon_cmd, stdout=open('/dev/null', 'w'), stderr=STDOUT, shell=True, preexec_fn=os.setpgrp) + + +def safely_start_test_signal(start_cmd, stop_cmd): + """ + This will start start_cmd and set things up in a way that stop_cmd is executed in case the check_hardware script + either exits regularly or gets killed for some reason by a POSIX signal. stop_cmd might be executed repeatedly + under circumstances. + :param start_cmd: the command to start as shell-executable string + :param stop_cmd: the command to stop on exit as shell-executable string + """ + + # start signal + try: + check_call(start_cmd, shell=True) + except CalledProcessError as ex: + logger.error(("Could not start the test signal! Non-zero return code from start_cmd (%s)." % start_cmd), ex) + raise + + # set things up sp signal is stopped when check_hardware terminates + register_signal_handlers(stop_cmd) + register_exit_handler(stop_cmd) + start_watchdog_daemon(os.getpid(), stop_cmd) # this alone would actually be sufficient + +def safely_start_test_signal_from_ParameterSet(settings): + ''' + :param settings: A settings.ParameterSet (e.g. obtained through TestSettings.group) + ''' + try: + start_cmd = settings.parset['testsignal']['start'] + stop_cmd = settings.parset['testsignal']['stop'] + logger.info('Test signal settings found. (%s // %s)' % (start_cmd, stop_cmd)) + safely_start_test_signal(start_cmd, stop_cmd) + except KeyError: + logger.info('No test signal settings found for this test.') + def main(): global station_name get_arguments() @@ -414,6 +518,7 @@ def main(): if rsp_check is True: if 'RV' in args: rsp = RSP(db) + logger.info('##### %s %s' % (rsp, rsp.check_versions)) rsp.check_versions(conf.group('rsp')) reset_rsp_settings() @@ -501,6 +606,7 @@ def main(): lbh.check_rf_power(mode=mode, parset=settings) for mode in (5, 6, 7): + # do all rcumode 5, 6, 7 tests hba = HBA(db) tile_settings = conf.group('rcumode.%d.tile' % mode) @@ -538,12 +644,12 @@ def main(): recordtime = 4 else: recordtime = int(args.get('E%d' % mode)) - + safely_start_test_signal_from_ParameterSet(elem_settings) hba.check_elements(mode=mode, record_time=recordtime, parset=elem_settings) # stop test if driver stopped db.rsp_driver_down = not check_active_rspdriver() - if db.rsp_driver_down and (restarts > 0): + if db.rsp_driver_down and (restarts > 0): # FIXME 'restarts' is undefined at this point?! restarts -= 1 reset_48_volt() time.sleep(30.0) @@ -634,6 +740,7 @@ def main(): return 0 - if __name__ == '__main__': sys.exit(main()) + + diff --git a/LCU/checkhardware/checkhardware_lib/CMakeLists.txt b/LCU/checkhardware/checkhardware_lib/CMakeLists.txt new file mode 100644 index 00000000000..e5ca32db72c --- /dev/null +++ b/LCU/checkhardware/checkhardware_lib/CMakeLists.txt @@ -0,0 +1,21 @@ +# $Id: CMakeLists.txt $ + +set(_py_files + __init__.py + data.py + db.py + general.py + hardware_tests.py + hba.py + lba.py + lofar.py + reporting.py + rsp.py + settings.py + spu.py + tbb.py +) + +python_install(${_py_files} DESTINATION lofar/lcu/checkhardware/checkhardware_lib) + +add_subdirectory(spectrum_checks) \ No newline at end of file diff --git a/LCU/checkhardware/checkhardware_lib/spectrum_checks/CMakeLists.txt b/LCU/checkhardware/checkhardware_lib/spectrum_checks/CMakeLists.txt new file mode 100644 index 00000000000..2aaae58c10f --- /dev/null +++ b/LCU/checkhardware/checkhardware_lib/spectrum_checks/CMakeLists.txt @@ -0,0 +1,19 @@ +# $Id: CMakeLists.txt $ + +set(_py_files + __init__.py + cable_reflections.py + down.py + down_old.py + flat.py + noise.py + oscillation.py + peakslib.py + rf_power.py + short.py + spurious.py + summator_noise.py + tools.py +) + +python_install(${_py_files} DESTINATION lofar/lcu/checkhardware/checkhardware_lib/spectrum_checks) diff --git a/LCU/checkhardware/config/FR606-check_hardware.conf b/LCU/checkhardware/config/FR606-check_hardware.conf index f72e209b682..ccc7a3ac885 100755 --- a/LCU/checkhardware/config/FR606-check_hardware.conf +++ b/LCU/checkhardware/config/FR606-check_hardware.conf @@ -161,6 +161,8 @@ oscillation.min-peak-pwr= 6.0 oscillation.passband= 1:511 spurious.min-peak-pwr= 3.0 spurious.passband= 1:511 +testsignal.start= echo set config 56.0 -10 | nc ncu 8093 +testsignal.stop= echo bye | nc ncu 8093 [rcumode.6.tile] short.mean-pwr.min= 55.0 diff --git a/LCU/checkhardware/test/CMakeLists.txt b/LCU/checkhardware/test/CMakeLists.txt new file mode 100644 index 00000000000..acc3d69163f --- /dev/null +++ b/LCU/checkhardware/test/CMakeLists.txt @@ -0,0 +1,5 @@ +# $Id: CMakeLists.txt 33404 2016-01-27 10:21:14Z jkuensem $ + +include(LofarCTest) + +lofar_add_test(t_check_hardware) diff --git a/LCU/checkhardware/test/t_check_hardware.py b/LCU/checkhardware/test/t_check_hardware.py new file mode 100644 index 00000000000..8c8a64c5724 --- /dev/null +++ b/LCU/checkhardware/test/t_check_hardware.py @@ -0,0 +1,226 @@ +import unittest +import os +from mock import MagicMock, patch, call +import sys +import logging +import subprocess +import signal +import atexit +import time + +logger = logging.getLogger(__name__) + +# mock out check for existing log directory on script import as module +os.access = MagicMock(return_value=True) + +# mock out modules with relative imports (that only work with the namespace when executed as a script) +# FIXME: make sure that absolute imports are ok and don't break things in production. +# FIXME: ...Then fix the implementation and remove this mock so we can test those modules. +with patch.dict('sys.modules', **{ + 'checkhardware_lib': MagicMock(), + 'checkhardware_lib.data': MagicMock(), + 'checkhardware_lib.rsp': MagicMock(), + 'cable_reflection': MagicMock(), + 'logging': MagicMock(), +}): + # import these here so we can before mock out checks on station environment + import lofar.lcu.checkhardware.check_hardware as check_hardware + from lofar.lcu.checkhardware.checkhardware_lib import TestSettings + check_hardware.logger = logger # override logger to handle logging output here + + +class TestCheckHardware(unittest.TestCase): + + def setUp(self): + logger.info(">>>---> %s <---<<<" % self._testMethodName) + # mock exit call to not actually exit the test + os._exit = MagicMock() + # we don't want to actually call anything + check_hardware.check_call = MagicMock() + + + def test_stop_test_signal(self): + """ Verify that the provided command is executed """ + + # test value + cmd = 'echo "Stop the signal! 1"' + + # trigger action + check_hardware.stop_test_signal(cmd) + + # assert correct behavior + os._exit.assert_not_called() + check_hardware.check_call.assert_called_with(cmd, shell=True) # command is executed + + def test_stop_test_signal_and_exit(self): + """ Verify that the provided command is executed and os._exit is called with correct return code """ + + # test value + cmd = 'echo "Stop the signal! 2"' + signal_code = 42 + + # trigger action + check_hardware.stop_test_signal_and_exit(cmd, signal_code, KeyboardInterrupt()) + + # assert correct behavior + os._exit.assert_called_with(signal_code) # exit code correct + check_hardware.check_call.assert_called_with(cmd, shell=True) # command is executed + + def test_register_signal_handlers_stops_test_signal_on_POSIX_signal(self): + """ Verify that the provided command is executed and os._exit is called with correct return code """ + + # test value + cmd = 'echo "Stop the signal! 3"' + + # register handlers we want to test + check_hardware.register_signal_handlers(cmd) + + # trigger action: + pid = os.getpid() + os.kill(pid, signal.SIGINT) # code 2 + os.kill(pid, signal.SIGABRT) # code 6 + os.kill(pid, signal.SIGTERM) # code 15 + + # assert correct behavior + os._exit.assert_has_calls([call(2), call(6), call(15)]) # all signal error codes correct + check_hardware.check_call.assert_called_with(cmd, shell=True) # command is executed + + def test_register_exit_handler_stops_test_signal_on_normal_exit(self): + """ Verify that the provided command is executed and os._exit is called with correct return code """ + + # This test turned out nastier than expected. + # The problem is that we cannot catch the SystemExit within the test, because the atexit hooks only fire after + # the test exits (even after tearDownClass), so we will get a stacktrace printed, but cmake won't count the + # assert failures as failure of the test. + # Note: As long as we use the watchdog, this is redundant anyway and we could also change the implementation + # to explicitely turn the test signal off before it exits and test for that instead. + # But who wants the easy way out, right? ;) + # FIXME: Find a way to make sure this test fails if the assertion fails or find a smarter way to test this. + + # test value + cmd = 'echo "Stop the signal! 4"' + + # assert correct behavior + def assert_on_exit(): + logger.info('>>>----> Asserting on exit!') + check_hardware.check_call.assert_called_with(cmd, shell=True) # command is executed + + # register a handler to trigger the assert. + atexit.register(assert_on_exit) + + # register handlers we want to test + check_hardware.register_exit_handler(cmd) + + # The test will now regularly exit with code 0, hopefully triggering all these hooks + + + def test_start_watchdog_daemon_stops_test_signal_when_provided_pid_is_killed(self): + """ Verify that the provided command is executed when watched process dies """ + + tmpfile = "/tmp/t_checkhardware.%s" % time.time() + + # test value + good_message = 'Stop the signal! 5' + cmd = 'echo "%s" > %s' % (good_message, tmpfile) + + # start dummy process + p = subprocess.Popen(['sleep', '60']) + + # start watchdog for dummy process + check_hardware.start_watchdog_daemon(p.pid, cmd) + + # kill dummy + os.kill(p.pid, signal.SIGKILL) + os.wait() + + # check temporary file to confirm the watchdog command has been executed + for i in range (30): + if os.path.isfile(tmpfile): + break + time.sleep(1) + self.assertTrue(os.path.isfile(tmpfile)) + with open(tmpfile) as f: + lines = f.read().split('\n') + self.assertTrue(good_message in lines) # cmd has been executed + + os.remove(tmpfile) + + # FIXME: Move this to t_settings once that exists + def test_settings_parset_raises_KeyError_when_accessing_missing_key(self): + + # read settings + f = os.environ.get('srcdir')+'/test-check_hardware.conf' + settings = TestSettings(filename=f) + elem_settings = settings.group('rcumode.5.tile') + + # assert KeyError if setting not there + with self.assertRaises(KeyError): + logger.info(elem_settings.parset['testsignal']['start']) + + + # FIXME: Move this to t_settings once that exists + def test_settings_contains_testsignal_commands_from_config_file(self): + + # test_values + expected_start_cmd = "echo set config 56.0 -10 | nc ncu 8093" + expected_stop_cmd = "echo bye | nc ncu 8093" + + # read settings + f = os.environ.get('srcdir')+'/test-check_hardware.conf' + settings = TestSettings(filename=f) + elem_settings = settings.group('rcumode.5.element') + + # assert correct values + start_cmd = elem_settings.parset['testsignal']['start'] + stop_cmd = elem_settings.parset['testsignal']['stop'] + + self.assertEqual(start_cmd, expected_start_cmd) + self.assertEqual(stop_cmd, expected_stop_cmd) + + #@unittest.skip('disabled due to fork bomb behavior') + def test_main_turns_signal_with_commands_from_settings(self): + + # test values + expected_start_cmd = "echo set config 56.0 -10 | nc ncu 8093" + expected_stop_cmd = "echo bye | nc ncu 8093" + + # setup tests + check_hardware.conf_file = r'test-check_hardware.conf' + check_hardware.confpath = os.environ.get('srcdir')+'/' + + # pretend to be a station + # FIXME: correct behavior of mocked-out parts should be covered by additional tests + # FIXME: why is all this actually necessary when I only run an element test? + check_hardware.read_station_config = MagicMock(return_value=(1, 1, 1, 1, 1, 1, 1)) + check_hardware.safely_start_test_signal = MagicMock() + check_hardware.swlevel = MagicMock(return_value=(6, None)) + check_hardware.rspctl = MagicMock() + check_hardware.RSP = MagicMock() + check_hardware.check_active_boards = MagicMock(return_value = (1, 1)) + check_hardware.check_active_tbbdriver = MagicMock(return_value=True) + check_hardware.check_active_rspdriver = MagicMock(return_value=True) + check_hardware.reset_rsp_settings = MagicMock() + check_hardware.HBA = MagicMock() + check_hardware.reset_48_volt = MagicMock() + check_hardware.tbbctl = MagicMock() + os.listdir = MagicMock() + os.remove = MagicMock() # I'm scared... + + # patch arguments: pretend script was started with these. + # -TST (test mode) + # -e5: (element test in mode 5) + # Names optimized for disk space + testargs = ["check_hardware.py", '-TST', '-e5'] + with patch.object(sys, 'argv', testargs): + # trigger action + check_hardware.main() # Warning: Something acts as a fork bomb when mocks are not setup properly! + + check_hardware.safely_start_test_signal.assert_called_with(expected_start_cmd, expected_stop_cmd) + + + +if __name__ == "__main__": + logger.level = logging.DEBUG + stream_handler = logging.StreamHandler(sys.stdout) + logger.addHandler(stream_handler) + unittest.main() diff --git a/LCU/checkhardware/test/t_check_hardware.run b/LCU/checkhardware/test/t_check_hardware.run new file mode 100755 index 00000000000..12b12ee0bd1 --- /dev/null +++ b/LCU/checkhardware/test/t_check_hardware.run @@ -0,0 +1,6 @@ +#!/bin/bash + +# Run the unit test +source python-coverage.sh +#python_coverage_test "checkhardware*" t_check_hardware.py +python t_check_hardware.py diff --git a/LCU/checkhardware/test/t_check_hardware.sh b/LCU/checkhardware/test/t_check_hardware.sh new file mode 100755 index 00000000000..43193a42534 --- /dev/null +++ b/LCU/checkhardware/test/t_check_hardware.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./runctest.sh t_check_hardware diff --git a/LCU/checkhardware/test/test-check_hardware.conf b/LCU/checkhardware/test/test-check_hardware.conf new file mode 100644 index 00000000000..41efd3a4696 --- /dev/null +++ b/LCU/checkhardware/test/test-check_hardware.conf @@ -0,0 +1,247 @@ +# +# configuration file for check_hardware.py +# + +[configuration] +version= 00.01 +station= FR606C + +# checks to do if '-l=x' argument is given, all checks behind list.x are executed +# always checks will be done always +# +# S(rcumode) : signal check for rcumode (also down and flat-check in rcumode 1..4). +# O(rcumode) : oscillation check for rcumode. +# SP(rcumode) : spurious check for rcumode. +# N(rcumode)[= 300]: noise check for rcumode, optional data time in seconds +# default data time= 120 sec. +# E(rcumode)[= 60] : do all RCU5 element tests, optional data time in seconds. +# default data time= 10 sec. +# M(rcumode) : do modem +# SN(rcumode) : do summator noise +# +# RCU(mode) : do all rcu checks for given mode, no element tests done. +# +# RBC : RSP voltage/temperature check +# TBC : TBB voltage/temperature check +# SPU : SPU voltage +# TM : TBB memmory +[check] +always= +list.0= +list.1= SPU,TM,RCU3,RCU5 +list.2= SPU,TM,RCU3,M5,SN5,O5,N5,SP5,S7,E7 +list.3= S3 + +[spu] +temperature.min= 10.0 +temperature.max= 35.0 +voltage.3_3.min= 3.1 +voltage.3_3.max= 3.4 +voltage.3_3.max-drop= 0.3 +voltage.5_0.min= 4.5 +voltage.5_0.max= 5.0 +voltage.5_0.max-drop= 0.3 +voltage.8_0.min= 7.4 +voltage.8_0.max= 8.0 +voltage.8_0.max-drop= 0.3 +voltage.48_0.min= 43.0 +voltage.48_0.max= 48.0 +voltage.48_0.max-drop= 2.0 + +[tbb] +version.tp= 2.4 +version.mp= 3.0 +temperature.min= 10.0 +temperature.max= 45.0 +temperature.tp.min= 10.0 +temperature.tp.max= 75.0 +temperature.tp.max_delta= 10.0 +temperature.mp.min= 10.0 +temperature.mp.max= 75.0 +temperature.mp.max_delta= 10.0 +voltage.1_2.min= 1.1 +voltage.1_2.max= 1.3 +voltage.2_5.min= 2.4 +voltage.2_5.max= 2.6 +voltage.3_3.min= 3.1 +voltage.3_3.max= 3.4 + +[rsp] +version.ap= 8.2 +version.bp= 8.2 +temperature.min= 10.0 +temperature.max= 50.0 +temperature.ap.min= 10.0 +temperature.ap.max= 80.0 +temperature.ap.max_delta= 10.0 +temperature.bp.min= 10.0 +temperature.bp.max= 80.0 +temperature.bp.max_delta= 10.0 +voltage.1_2.min= 1.1 +voltage.1_2.max= 1.3 +voltage.2_5.min= 2.4 +voltage.2_5.max= 2.6 +voltage.3_3.min= 3.1 +voltage.3_3.max= 3.4 + +[rcumode.1-3] +short.mean-pwr.min= 55.0 +short.mean-pwr.max= 61.0 +flat.mean-pwr.min= 61.0 +flat.mean-pwr.max= 64.5 +rf.subbands= 301 +rf.min-sb-pwr= 75.0 +rf.negative-deviation= -3.0 +rf.positive-deviation= 3.0 +noise.negative-deviation= -2.5 +noise.positive-deviation= 2.5 +noise.max-difference= 1.5 +noise.passband= 1:511 +oscillation.min-peak-pwr= 6.0 +oscillation.passband= 1:511 +cable-reflection.min-peak-pwr= 0.8 +cable-reflection.passband= 1:511 +spurious.min-peak-pwr= 3.0 +spurious.passband= 1:511 +down.passband= 231:371 + +[rcumode.2-4] +short.mean-pwr.min= 55.0 +short.mean-pwr.max= 61.0 +flat.mean-pwr.min= 61.0 +flat.mean-pwr.max= 64.5 +rf.subbands= 301 +rf.min-sb-pwr= 75.0 +rf.negative-deviation= -3.0 +rf.positive-deviation= 3.0 +noise.negative-deviation= -2.5 +noise.positive-deviation= 2.5 +noise.max-difference= 1.5 +noise.passband= 1:511 +oscillation.min-peak-pwr= 6.0 +oscillation.passband= 1:511 +cable-reflection.min-peak-pwr= 0.8 +cable-reflection.passband= 1:511 +spurious.min-peak-pwr= 3.0 +spurious.passband= 1:511 +down.passband= 231:371 + +[rcumode.5.tile] +short.mean-pwr.min= 55.0 +short.mean-pwr.max= 61.0 +flat.mean-pwr.min= 61.0 +flat.mean-pwr.max= 64.5 +rf.subbands= 105 +rf.min-sb-pwr= 65.0 +rf.negative-deviation= -24.0 +rf.positive-deviation= 12.0 +noise.negative-deviation= -3.0 +noise.positive-deviation= 1.5 +noise.max-difference= 1.5 +noise.passband= 1:511 +summator-noise.min-peak-pwr= 1.2 +summator-noise.passband= 45:135,200:270 +cable-reflection.min-peak-pwr= 0.8 +cable-reflection.passband= 1:511 +oscillation.min-peak-pwr= 6.0 +oscillation.passband= 1:511 +spurious.min-peak-pwr= 3.0 +spurious.passband= 1:511 + +[rcumode.5.element] +rf.subbands= 105 +rf.min-sb-pwr= 65.0 +rf.negative-deviation= -24.0 +rf.positive-deviation= 12.0 +noise.negative-deviation= -3.0 +noise.positive-deviation= 1.5 +noise.max-difference= 1.5 +noise.passband= 1:511 +oscillation.min-peak-pwr= 6.0 +oscillation.passband= 1:511 +spurious.min-peak-pwr= 3.0 +spurious.passband= 1:511 +testsignal.start= echo set config 56.0 -10 | nc ncu 8093 +testsignal.stop= echo bye | nc ncu 8093 + +[rcumode.6.tile] +short.mean-pwr.min= 55.0 +short.mean-pwr.max= 61.0 +flat.mean-pwr.min= 61.0 +flat.mean-pwr.max= 64.5 +rf.subbands= 105 +rf.min-sb-pwr= 65.0 +rf.negative-deviation= -24.0 +rf.positive-deviation= 12.0 +noise.negative-deviation= -3.0 +noise.positive-deviation= 1.5 +noise.max-difference= 1.5 +noise.passband= 1:511 +summator-noise.min-peak-pwr= 1.2 +summator-noise.passband= 45:135 +cable-reflection.min-peak-pwr= 0.8 +cable-reflection.passband= 1:511 +oscillation.min-peak-pwr= 6.0 +oscillation.passband= 1:511 +spurious.min-peak-pwr= 3.0 +spurious.passband= 1:511 + +[rcumode.6.element] +rf.subbands= 105 +rf.min-sb-pwr= 65.0 +rf.negative-deviation= -24.0 +rf.positive-deviation= 12.0 +noise.negative-deviation= -3.0 +noise.positive-deviation= 1.5 +noise.max-difference= 1.5 +noise.passband= 1:511 +oscillation.min-peak-pwr= 6.0 +oscillation.passband= 1:511 +spurious.min-peak-pwr= 3.0 +spurious.passband= 1:511 + +[rcumode.7.tile] +short.mean-pwr.min= 55.0 +short.mean-pwr.max= 61.0 +flat.mean-pwr.min= 61.0 +flat.mean-pwr.max= 64.5 +rf.subbands= 105 +rf.min-sb-pwr= 65.0 +rf.negative-deviation= -24.0 +rf.positive-deviation= 12.0 +noise.negative-deviation= -3.0 +noise.positive-deviation= 1.5 +noise.max-difference= 1.5 +noise.passband= 1:511 +summator-noise.min-peak-pwr= 1.2 +summator-noise.passband= 45:135 +cable-reflection.min-peak-pwr= 0.8 +cable-reflection.passband= 1:511 +oscillation.min-peak-pwr= 6.0 +oscillation.passband= 1:511 +spurious.min-peak-pwr= 3.0 +spurious.passband= 1:511 + +[rcumode.7.element] +rf.subbands= 105 +rf.min-sb-pwr= 65.0 +rf.negative-deviation= -24.0 +rf.positive-deviation= 12.0 +noise.negative-deviation= -3.0 +noise.positive-deviation= 3.0 +noise.max-difference= 1.5 +noise.passband= 1:511 +oscillation.min-peak-pwr= 6.0 +oscillation.passband= 1:511 +spurious.min-peak-pwr= 3.0 +spurious.passband= 1:511 + +# General settings +[paths] +global-data= /globalhome/log/stationtest +local-data= /opt/stationtest/data +local-report-dir= /localhome/stationtest/data +global-report-dir= /globalhome/log/stationtest + +[files] +bad-antenna-list= /localhome/stationtest/data/bad_antenna_list.txt -- GitLab