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