From dccaed0112e41a6f4c5d3996c90d5ef2730ce919 Mon Sep 17 00:00:00 2001 From: Arno Schoenmakers <schoenmakers@astron.nl> Date: Tue, 27 Jan 2009 15:09:26 +0000 Subject: [PATCH] Bug 1319: Moved MAC/Test/Station to StationTest --- .gitattributes | 45 + StationTest/Makefile.am | 23 + StationTest/README.txt | 303 +++++++ StationTest/bootstrap | 3 + StationTest/configure.in | 12 + StationTest/gold/Makefile.am | 9 + StationTest/gold/prbs_dir_test.gold | 68 ++ StationTest/gold/rsp_version.gold | 4 + StationTest/gold/tbb_version.gold | 11 + StationTest/gold/xst.m | 29 + StationTest/gold/xst_160.gold | Bin 0 -> 16384 bytes StationTest/gold/xst_200_even.gold | Bin 0 -> 16384 bytes StationTest/gold/xst_200_odd.gold | Bin 0 -> 16384 bytes StationTest/i2c_spu.py | 64 ++ StationTest/i2c_td.py | 54 ++ StationTest/modules/Makefile.am | 9 + StationTest/modules/cli.py | 14 + StationTest/modules/mep.py | 366 ++++++++ StationTest/modules/rsp.py | 1280 +++++++++++++++++++++++++++ StationTest/modules/smbus.py | 281 ++++++ StationTest/modules/testcase.py | 72 ++ StationTest/modules/testlog.py | 69 ++ StationTest/prbs_dir_test.py | 114 +++ StationTest/prbs_test.py | 103 +++ StationTest/rmfiles.sh | 7 + StationTest/rsp_version.sh | 16 + StationTest/rsp_xc_160.sh | 11 + StationTest/rsp_xc_200.sh | 11 + StationTest/station_production.py | 191 ++++ StationTest/subrack_production.py | 170 ++++ StationTest/subracktest.sh | 29 + StationTest/tbb_prbs_tester.sh | 48 + StationTest/tbb_version.sh | 16 + StationTest/tc/Makefile.am | 15 + StationTest/tc/bist.py | 146 +++ StationTest/tc/empty.py | 2 + StationTest/tc/hba_client.py | 167 ++++ StationTest/tc/hba_server.py | 337 +++++++ StationTest/tc/prsg.py | 150 ++++ StationTest/tc/rad_lanemode.py | 35 + StationTest/tc/rad_latency.py | 21 + StationTest/tc/serdes.py | 187 ++++ StationTest/tc/spustat.py | 102 +++ StationTest/tc/status.py | 57 ++ StationTest/tc/sync_delay.py | 37 + StationTest/tc/tdstat.py | 95 ++ StationTest/verify.py | 188 ++++ StationTest/xc_160_setup.sh | 24 + StationTest/xc_160_verify.sh | 25 + StationTest/xc_200_setup.sh | 24 + StationTest/xc_200_verify.sh | 31 + 51 files changed, 5075 insertions(+) create mode 100644 StationTest/Makefile.am create mode 100644 StationTest/README.txt create mode 100755 StationTest/bootstrap create mode 100644 StationTest/configure.in create mode 100644 StationTest/gold/Makefile.am create mode 100644 StationTest/gold/prbs_dir_test.gold create mode 100644 StationTest/gold/rsp_version.gold create mode 100644 StationTest/gold/tbb_version.gold create mode 100644 StationTest/gold/xst.m create mode 100644 StationTest/gold/xst_160.gold create mode 100644 StationTest/gold/xst_200_even.gold create mode 100644 StationTest/gold/xst_200_odd.gold create mode 100644 StationTest/i2c_spu.py create mode 100644 StationTest/i2c_td.py create mode 100644 StationTest/modules/Makefile.am create mode 100644 StationTest/modules/cli.py create mode 100644 StationTest/modules/mep.py create mode 100644 StationTest/modules/rsp.py create mode 100644 StationTest/modules/smbus.py create mode 100644 StationTest/modules/testcase.py create mode 100644 StationTest/modules/testlog.py create mode 100644 StationTest/prbs_dir_test.py create mode 100644 StationTest/prbs_test.py create mode 100644 StationTest/rmfiles.sh create mode 100644 StationTest/rsp_version.sh create mode 100644 StationTest/rsp_xc_160.sh create mode 100644 StationTest/rsp_xc_200.sh create mode 100644 StationTest/station_production.py create mode 100644 StationTest/subrack_production.py create mode 100644 StationTest/subracktest.sh create mode 100644 StationTest/tbb_prbs_tester.sh create mode 100644 StationTest/tbb_version.sh create mode 100644 StationTest/tc/Makefile.am create mode 100644 StationTest/tc/bist.py create mode 100644 StationTest/tc/empty.py create mode 100644 StationTest/tc/hba_client.py create mode 100644 StationTest/tc/hba_server.py create mode 100644 StationTest/tc/prsg.py create mode 100644 StationTest/tc/rad_lanemode.py create mode 100644 StationTest/tc/rad_latency.py create mode 100644 StationTest/tc/serdes.py create mode 100644 StationTest/tc/spustat.py create mode 100644 StationTest/tc/status.py create mode 100644 StationTest/tc/sync_delay.py create mode 100644 StationTest/tc/tdstat.py create mode 100644 StationTest/verify.py create mode 100644 StationTest/xc_160_setup.sh create mode 100644 StationTest/xc_160_verify.sh create mode 100644 StationTest/xc_200_setup.sh create mode 100644 StationTest/xc_200_verify.sh diff --git a/.gitattributes b/.gitattributes index f4f68e0047e..90e8ece855f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1149,6 +1149,51 @@ SHM/Components/WebInterface/testing/djstart/playpen/urls.py -text SHM/apache_config/httpd.conf -text SHM/apache_config/sites-enabled/001-shmprod -text SHM/apache_config/sites-enabled/002-shmdev -text +StationTest/README.txt -text +StationTest/bootstrap -text +StationTest/gold/prbs_dir_test.gold -text +StationTest/gold/rsp_version.gold -text +StationTest/gold/tbb_version.gold -text +StationTest/gold/xst.m -text +StationTest/gold/xst_160.gold -text +StationTest/gold/xst_200_even.gold -text +StationTest/gold/xst_200_odd.gold -text +StationTest/i2c_spu.py -text +StationTest/i2c_td.py -text +StationTest/modules/cli.py -text +StationTest/modules/mep.py -text +StationTest/modules/rsp.py -text +StationTest/modules/smbus.py -text +StationTest/modules/testcase.py -text +StationTest/modules/testlog.py -text +StationTest/prbs_dir_test.py -text +StationTest/prbs_test.py -text +StationTest/rmfiles.sh -text +StationTest/rsp_version.sh -text +StationTest/rsp_xc_160.sh -text +StationTest/rsp_xc_200.sh -text +StationTest/station_production.py -text +StationTest/subrack_production.py -text +StationTest/subracktest.sh -text +StationTest/tbb_prbs_tester.sh -text +StationTest/tbb_version.sh -text +StationTest/tc/bist.py -text +StationTest/tc/empty.py -text +StationTest/tc/hba_client.py -text +StationTest/tc/hba_server.py -text +StationTest/tc/prsg.py -text +StationTest/tc/rad_lanemode.py -text +StationTest/tc/rad_latency.py -text +StationTest/tc/serdes.py -text +StationTest/tc/spustat.py -text +StationTest/tc/status.py -text +StationTest/tc/sync_delay.py -text +StationTest/tc/tdstat.py -text +StationTest/verify.py -text +StationTest/xc_160_setup.sh -text +StationTest/xc_160_verify.sh -text +StationTest/xc_200_setup.sh -text +StationTest/xc_200_verify.sh -text SubSystems/CEPCU_MAC/lofarconf.in -text SubSystems/LCU_MAC/lofarconf.in -text SubSystems/MCU_MAC/lofarconf.in -text diff --git a/StationTest/Makefile.am b/StationTest/Makefile.am new file mode 100644 index 00000000000..4c094293917 --- /dev/null +++ b/StationTest/Makefile.am @@ -0,0 +1,23 @@ +SUBDIRS = modules gold tc + +testdir = $(prefix)/stationtest +test_SCRIPTS = README.txt \ + i2c_spu.py \ + i2c_td.py \ + prbs_dir_test.py \ + prbs_test.py \ + rmfiles.sh \ + rsp_version.sh \ + rsp_xc_160.sh \ + rsp_xc_200.sh \ + subrack_production.py \ + subracktest.sh \ + tbb_prbs_tester.sh \ + tbb_version.sh \ + verify.py \ + xc_160_setup.sh \ + xc_160_verify.sh \ + xc_200_setup.sh \ + xc_200_verify.sh + +include $(top_srcdir)/Makefile.common diff --git a/StationTest/README.txt b/StationTest/README.txt new file mode 100644 index 00000000000..fd5eb2f8951 --- /dev/null +++ b/StationTest/README.txt @@ -0,0 +1,303 @@ +# +# Test scripts for LOFAR station regression, production and operation tests. +# +# 2 sep 2008 Eric Kooistra First working test environment. +# 31 oct 2008 Eric kooistra More readme info. +# Added subrack_production.py, smbus.py, spustat.py, +# tdstat.py, hba_client.py, hba_server.py +# + +################################################################################ +1) Introduction + +a) Purpose +This test suite uses scripts that call rsptcl and tbbctl to control a LOFAR +station. Most scripts are written in Python. The test suite offers modules +written in Python that allow easy access to rspctl and tbbctl, and that offer +pass/fail handling and logging. The test scripts allow focussing on a typical +function or interface of the station, therefore they can be used for: + +- regression tests (e.g. functional coverage tests) +- production tests (e.g. chip interface, board interface tests) +- stress tests (e.g. many HBA write, read accesses) +- operation sanity tests + +b) Why Python? +For tool interfacing TCL is the common script language, that is why the VHDL +developent using Modelsim uses TCL scripts. The problem with the remote station +TCL scripts is that they run under Windows using WinPCap to interface with the +Ethernet card. TCL is platform independent, but there is no easy equivalent for +WinPCAP under Linux. Hence it is not straigthforward to run the TCL testcases +environment also under Linux on the LCU. +Instead of using something like WinPCap the low level register access functions +--readblock and --writeblock were added to rspctl . This allows controlling the +RSP board via scripts. +Python was choosen as test script language, because it is a popular script +language and adopted at various levels within the LOFAR software development, +including operations. Based on my experience in translating TCL scripts into +Python equivalents I think that Python is a more natural and nicer language than +TCL. + + +################################################################################ +2) Test setup + +a) Directory structure + ./ : README.txt, Python scripts, bash scripts. Run from this directory. + modules/ : Python modules + gold/ : Golden result files for corresponding scripts, 'diff *.log *.gold' + should yield no difference for the test to pass + tc/ : Testcase scripts to be used with verify.py + +b) This test suite uses different types of test scripting: + + - Testcase Python scripts in tc/ called via verify.py + . e.g.: tc/status.py, tc/bist.py, tc/prsg.py + . verify.py offers argument parsing, test result logging + . Resembles TCL testcase structure used for gateware development tests + . Most scripts in tc/ are direct (manual) translations of the TCL test + scripts that were used for the gateware (VHDL) development, see + LOFAR-ASTRON-MEM-186. The Python / rspctl test scripts run rather slow, + about a factor 2 slower than a comparable TCL / C test script. + - Stand alone Python scripts + . e.g.: python i2c_spy.py + . suitable for simple tests without argument passing + - BASH shell scripts + . e.g.: ./rsp_version.sh + + All these individual test scripts can be combined: + . e.g. for production test, regression test + . e.g. subracktest.sh + +c) Environment setting + + The scripts run from ./ The search path needs to be set: + export PYTHONPATH=./modules + or absolute path + export PYTHONPATH=/home/lofartest/ptest/modules + or to add the path + export PYTHONPATH=$PYTHONPATH:./modules + or on older systems + PYTHONPATH=$PYTHONPATH:./modules + export PYTHONPATH + + If rspctl is called then there must be a directory ../log/ for rspctl.log. + This ../log/ can be a symbolic link. + + +d) RSPDriver.conf + +To allow the 'rspctl --readblock' and 'rspctl --writeblock' low level access +commands the RSP driver in /opt/lofar/etc/ must have: + + RSPDriver.READ_RAW_DATA = 1 + RSPDriver.WRITE_RAW_DATA = 1 + +For tests that access the SPU or TDS, the RSP driver regular accesses via TDSH +must be stopped via: + + RSPDriver.READWRITE_TDSSTATUS=0 + + +################################################################################ +3) Test modules: + +cli.py - Command line interface access +verify.py - Run one or more test scripts after parsing the arguments from the + command line +testcase.py - Testcase pass/fail control, timing and logging for testcases that + run with verify.py +testlog.py - Similar to testcase.py, provides pass/fail control, timing and + logging for standalone test scripts like subrack_production.py +mep.py - MEP interface for RSP board access via 'rspctl --readblock/ + rspctl --writeblock' +rsp.py - RSP board register access functions +smbus.py - SMBus (I2C) access functions + + +Remarks: + +a) To see all script options (both general and test case specific) do: + + python verify.py --help + + Remarks: + - via --brd a test can be ran for one RSP or multiple + - via --fpga a test can be ran on the BP, AP0, AP1, AP2, and/or AP3 in any + combination + - via --pol a test can be ran on RCU x and/or RCU y of the AP. + - There are 2 RCU per AP and 4 AP per RSP. In a station the RCUs are + numbered starting from 0. Hence e.g. RCU[64] = (rsp8, blp0, x) and + RCU[65] = (rsp8, blp0, y). + +b) Classes: + - mep.py defines class MepMessage + - testcase.py defines class Testcase + - testlog.py defines class Testlog + The other modules cli.py, rsp.py and smbus.py define plain functions. Classes + are a nice way of grouping constants and functions to an object, for mep.py + the object it the message string that can be manipulated and access through + the class functions. Similar smbus.py could have been written as a class to + with the protocol_list and protocol_result as objects. I do not know what is + the best approach and why. With smbus.py as a plain set of functions it is + also clear that the functions belong together, because they are called using + the module name as prefix. + +c) The 'rspctl --readblock' and 'rspctl --writeblock' are quite slow, due to: + - the double buffering in the RSP driver + - maybe rspctl excepts only one access per pps interval + - the hex translations in mep.py to adhere to the format ot rspctl + For scripts that only use these low level peek and poke rsptcl commands it + would be a great improvement to have a dedicated driver program that takes + care of these low level commands. This may be a driver program or some C + functions that can be used directly in Python. The scripts can then remain as + they are, only a different mep.py module needs to be added. + +d) Some scripts also use higher level rspctl commands, e.g. to set the RCU in + PSRG mode. + +e) Typically all RSP access goes via functions in rsp.py and smbus.py. Hence in + a test script it should never be necessary to call the low level rspctl + commands directly. + +f) I tried to follow the Python documentation rules. For example to read the + documentation in the module rsp.py do: + + python + >>> import rsp + >>> dir(rsp) + >>> print rsp.__doc__ + >>> print rsp.write_mem.__doc__ + +g) When command line options are needed I use the Python option parser. For the + test scripts all command line options need to be defined in testcase.py. + There are some general test script options (e.g. --brd) but there are also + test script specific options (e.g. --pid). The general testcase options are + passed on via the Testcase class, the specific options are passed on as + directly and all get prefix 'arg_' in verify.py to easily recognize them. + +h) For logging I followed the logging approach that was used for the RSP test + environment written in TCL. Python also has modules for logging thay may be + useful in future. + + +################################################################################ +4) Test scripts in tc/ + +a) The testcases in tc/ are ran using verify.py. The test results are reported + to the screen and also stored in tc/ in a *.log file with the same name. The + ammount of logging depends on the verbosity level set by option -v. + + To run a testcase with verify.py in ./ do: + + python verify.py --brd rsp0 --fp blp0 --te tc/prsg.py -v 21 + + To run a testcase for one subrack with 4 RSP do: + + python verify.py --brd rsp0,rsp1,rsp2,rsp3 --rep 1 -v 21 --te tc/serdes.py + + To run a testcase for a station with three subracks, so 12 RSP do: + + python verify.py --brd rsp0,rsp1,rsp2,rsp3,rsp4,rsp5,rsp6,rsp7,rsp8,rsp9, + rsp10,rsp11 --te tc/serdes.py + + Remarks: + - The default option parameter values are defined in verify.py + - For options with multiple parameters the parameters must form one continuous + string seperated by commas's. + +b) The following test scripts are available in tc/, they are more or less plain, + manual translations from TCL test cases: + + - empty.py = empty, can be used to try verify.py + - prsg.py = TC 5.10, capture RCU PSRG data + - serdes.py = TC 3.8, serdes ring test + - status.py = TC 11.1, read RSP status register + - spustat.py = TC 9.6, read SPU sensor status <=> 'rspctl --spustat' + - tdstat.py = TC 9.1, read TD sensor status <=> 'rspctl --tdstat' + - hba_client = TC 5.42, read or write to a HBA client register at the RCU + - hba_server = TC 5.43, read or write to a HBA server register at the tile + +c) 'rspctl --readblock' and 'rspctl --writeblock' + + If available high level rspctl options are used to set up things, e.g. like + the PRSG on an RCU. For other low level board control use the direct access + '--readblock' and '--writeblock' options of rspctl. The modules mep.py and + rsp.py provide easy interfacing with theses options. + +d) For help on the testcase usage and options do: + + python verify.py --help + +e) To delete temporary files do: + + ./rmfiles.sh + +f) Verbosity level (-v) + The testcases all adhere to the following verbosity level convention: + + -v 0 : show PASSED or FAILED + -v 1 : show testcase title + -v 2 : show testcase time + -v 11 : show '... went wrong' for each step or section in a testcase, plus + some more info like expected result and read result + -v 21 : show '... went OK' for each step or section in a testcase + -v 22 : show rspctl commands + -v 23 : show rspctl command return results + +g) Pass/fail + Default a testcase run using verify.py/testcase.py (or using testlog.py) gets + pass/fail status 'RUNONLY'. This is useful for test scripts that are + utilities. If the testcase checks for expected results then it one of the it + should first initialized the tc result to 'PASSED'. Subsequently each step in + the testcase that fails should also set the tc result to 'FAILED'. Once the + tc status is 'FAILED' it can not change anymore. + +h) Test scripts and the RSP driver + The test scripts use rspctl. Some test scripts do not affect the functional + behaviour of the RSP driver, however many scripts do. Due to the slow and + asynchronlous behaviour of teh test scripts it is often handy to disable the + external sync (pps). The scripts also enable the external sync again, but + if that does not recover normal rspctl behaviour then it may be necessary to + do a 'rspctl --rspclear' or restart the RSP driver via swlevel 1, swlevel 2. + + +################################################################################ +5) More examples + +a) HBA client access + To read the speed register of HBA client on RCU[65] do: + + python verify.py --brd rsp8 --fp blp0 --rep 1 -v 21 --te tc/hba_client.py + --client_access r --client_reg speed --data 1 + + The test will only signal pass if the --data value equals the read speed + value, hence for read the --data option is used as expected result. + +b) HBA server access + To read the delay settings for polarization X and Y of HBA server 2 on the + HBA tile of RCU[64]=X (power via X) and RCU[65]=Y (control via Y) do: + + python verify.py --brd rsp8 --fp blp0 --rep 1 -v 21 --te tc/hba_server.py + --server 2 --server_access uc --server_function gw + --server_reg delay_x --data 50,51 + + +################################################################################ +6) Standalone test scripts + +a) Subrack production tests + +The Python script subrack_production.py runs the subrack production test, it +requires a batch nr and a serial nr that will be used to name the log file. + + python subrack_production.py --help + python subrack_production.py -b 3 -s 2 + +This subrack_production.py replaces subracktest.sh. + +b) Various + + i2c_spu.py = uses 'rspctl --spustat' to verify SPU sensor status + i2c_td.py = uses 'rspctl --spustat' to verify TDS sensor status + diff --git a/StationTest/bootstrap b/StationTest/bootstrap new file mode 100755 index 00000000000..06f18cde1db --- /dev/null +++ b/StationTest/bootstrap @@ -0,0 +1,3 @@ +#!/bin/sh + +../../../autoconf_share/bootstrap ../../../autoconf_share diff --git a/StationTest/configure.in b/StationTest/configure.in new file mode 100644 index 00000000000..4fcf2bda263 --- /dev/null +++ b/StationTest/configure.in @@ -0,0 +1,12 @@ +AC_INIT(README.txt) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(Station, 1.0, no-define) + +AC_PROG_LIBTOOL + +AC_OUTPUT( + Makefile + gold/Makefile + modules/Makefile + tc/Makefile +) diff --git a/StationTest/gold/Makefile.am b/StationTest/gold/Makefile.am new file mode 100644 index 00000000000..46aa24695c7 --- /dev/null +++ b/StationTest/gold/Makefile.am @@ -0,0 +1,9 @@ +testdir = $(prefix)/stationtest/gold +test_SCRIPTS = prbs_dir_test.gold \ + rsp_version.gold \ + tbb_version.gold \ + xst_160.gold \ + xst_200_even.gold \ + xst_200_odd.gold + +include $(top_srcdir)/Makefile.common diff --git a/StationTest/gold/prbs_dir_test.gold b/StationTest/gold/prbs_dir_test.gold new file mode 100644 index 00000000000..99aaecba653 --- /dev/null +++ b/StationTest/gold/prbs_dir_test.gold @@ -0,0 +1,68 @@ + + + PRSB test + +Frame nr 0 Station 1 RSP 0 RCU 0 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 0 RCU 1 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 0 RCU 2 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 0 RCU 3 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 0 RCU 4 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 0 RCU 5 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 0 RCU 6 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 0 RCU 7 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 1 RCU 8 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 1 RCU 9 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 1 RCU 10 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 1 RCU 11 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 1 RCU 12 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 1 RCU 13 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 1 RCU 14 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 1 RCU 15 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 2 RCU 16 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 2 RCU 17 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 2 RCU 18 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 2 RCU 19 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 2 RCU 20 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 2 RCU 21 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 2 RCU 22 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 2 RCU 23 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 3 RCU 24 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 3 RCU 25 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 3 RCU 26 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 3 RCU 27 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 3 RCU 28 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 3 RCU 29 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 3 RCU 30 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 +Frame nr 0 Station 1 RSP 3 RCU 31 Sample rate 200 MHz +Samples checked : 10239 PRBS errors: 0 diff --git a/StationTest/gold/rsp_version.gold b/StationTest/gold/rsp_version.gold new file mode 100644 index 00000000000..71915568991 --- /dev/null +++ b/StationTest/gold/rsp_version.gold @@ -0,0 +1,4 @@ +RSP[ 0] RSP version = 4, BP version = 4.13, AP version = 4.13 +RSP[ 1] RSP version = 4, BP version = 4.13, AP version = 4.13 +RSP[ 2] RSP version = 4, BP version = 4.13, AP version = 4.13 +RSP[ 3] RSP version = 4, BP version = 4.13, AP version = 4.13 diff --git a/StationTest/gold/tbb_version.gold b/StationTest/gold/tbb_version.gold new file mode 100644 index 00000000000..6d3133946f0 --- /dev/null +++ b/StationTest/gold/tbb_version.gold @@ -0,0 +1,11 @@ + +== TBB ====================================== ID and version information ==== + +TBBDriver software version 2.00 + +TBB ID Software Board TP0 MP0 MP1 MP2 MP3 +--- -- -------- ------- ------- ------- ------- ------- ------- + 0 0 V 2.0 V 0.2 V 1.6 V 1.6 V 1.6 V 1.6 V 1.6 + 1 2 V 2.0 V 0.2 V 1.6 V 1.6 V 1.6 V 1.6 V 1.6 + +== normal termination of tbbctl ============================================== diff --git a/StationTest/gold/xst.m b/StationTest/gold/xst.m new file mode 100644 index 00000000000..c6eee9a6097 --- /dev/null +++ b/StationTest/gold/xst.m @@ -0,0 +1,29 @@ +% +% Utility to examine XST data +% + +%cd C:\svnroot\LOFAR\trunk\MAC\Test\Station\gold +close all +% golden XST data +fid = fopen('xst_160.gold','r') +data_gold = fread(fid,'double') +fclose(fid) +corr_gold = reshape(data_gold(1:2:end) + i * data_gold(2:2:end), [32,32]) +figure(1) +imagesc(abs(corr_gold)) +colorbar +figure(2) +imagesc(angle(corr_gold)) +colorbar + +% new XST data +fid = fopen('xst.dat','r') +data = fread(fid,'double') +fclose(fid) +corr = reshape(data(1:2:end) + i * data(2:2:end), [32,32]) +figure(3) +imagesc(abs(corr)) +colorbar +figure(4) +imagesc(angle(corr)) +colorbar diff --git a/StationTest/gold/xst_160.gold b/StationTest/gold/xst_160.gold new file mode 100644 index 0000000000000000000000000000000000000000..028a0359218d24ffea62e82480cd199f9fa46172 GIT binary patch literal 16384 zcmeI3`(KsC_Q#)!jI`A1q<G1;CWc4ypplq)+3w1a!%<XJ^ozDt6jHM79S!Y45C~Ba zZ)j?GCqu<cie|Rmsj2Ca%&(%E?bJGCR=d1JYI>N@=Nb31SAW9c2iEKT%;lM9)|xdl zYi1k9|Nj2h1App)DNP-BJ?Ybi99heQ=RMk!$213<FLnZ(o1Z0L>CE&Ox{zODy3w>7 z*oci_`l@Jh!&YE>zg}eXi#_T+=IK7<S#2nn_Jy<`bU?bD{UFVm|AO@X%5-nvSg_HK z(!P5D*x8WvyVnk8dXw&u<^6_`8@~Wqv}Y)}?)k2&9j?j4z-B@hhhlqQvaMwd*cHqC z&XPE=v%eGhoui##^VmSJ5s|?3acq~jV<Olc`x4T<_lyJ^b-%@XjrpU<pLU~sA{o-T ztS{w0rn?<Oz%i>|gDl-L0<t`Z(!PNCoIQu)c~S8jknY<9Ak{bB^{4gyQZ1&R?0Q!| zcfBZbey~TCv%SuKFjlhv%wfHmekl^^?qg*8<J70KMK7e=ny_EoS6N?CCi~5NmG)!b z%zidPet|vMB1f>kgD*nb0+Jx@JK3M*E6Mp0Ry_te>>pOS--oljZxm$d>(pCFmW$7? zu{~w)j0Kw|w9odBjt3jrzd<htJ|a7>^1I!0$@ZSqLw@2o<hO-WpA{X)fD4nyI8=Y- z_j?^&UULH2+dcv8I+Ox7+R%=T_&3RA0g!<=QXz}lQvca2r-FSENsuvzm|oFnEI4le z6iDy>Ns#tzO6Mu&J5XmFo~t(9^{2<Tt2xr|=sPc%^_}l?S2=H^f#m#fkE+L3Jeb^< z<I7ylabRoD@oG;c=ciFm#+E_I?`mr4>7M>z-&*R)9&FiL4D^)IdiQ?np$GNkKG_5B zHRiM5izc$(s@vq4Bd;Od97T>?O?}ulQ-(B~h;-Xl>c!S{3OHsb?Zq}^D%f7uAJV(z zEl9&gyBt5z1iSZeJYD%a*|(7THzrR*`hl0nJ5>Kf9(@z+>qq@mbmRMz7nw*ex{vl4 zAD#}j)ueyA*=`2dh<X;~y(yVsZve-&>l<=h0`(sjLk@Y5cH}yof&7=+O@}=EPfFD$ z`KSH4vH4l#)8pG*@dDpx>D$Z;2m21w?sXl$J;U+bNb2fQ&%9-{Pj6l<xcoo#Q$`ZM zE2bUU*^YX0b{T>4_I2zB<385!n!|DCz0n)#t_M<3pMG!37V6E&?T6>CA*qnQ<B8-i zEM7pnsX9nKghWh6x|S7FsbAN96YxANV>;_`kA_V8C<D^Spq(X0XOgXkT=J29ZH7A3 zqmpH0=Pv5Sw{`~d#|)!hLceGIA>U6&{=#2rFNdGX0*ADii2U}CbHFjfM}l|tp9R+6 zf1zz2*cZY6EL=wp%A1Vm9lf(5ovmqCaXWJFDzED?t@+#R!1+%5bN3IC$gjt@JGMJm z>)V~!6>Jt;^OjX%(I6L|+v`Vp)T6Si^n>nmgTN_M*)Ptu^w-7jGu>Rn@oAnKjq=5H zCLw>(0M47<=crHZf6QJScScbq{KKk1_N)2mV3a%jXgXy6mv2BObS2x0X-7fRm_KDb z>v?Ds<zYAVZ97GKiSD0`^5rkk9+SJy1pAH*hYWdo7Nk*Hg?TI7NA_-DyW>A6C!L?@ zQ2kM{i{-sjssF$N)*o$VBR%{vzCZ3J_3fNO`{-?(gLGdS?XvA7bHRp>erd&%^T0vD z?En1H<oIOznegwd{HhV+&$QNSZd*5$*YmgS@jhVf&yDu|z<PYU^J2kT-$wl?u<_J* zO6wg#0h3rRxwl6>syxVf&pAE;Y&=GLHOpM!$W6>2xt975OJRMb%h?a5CutvBbErR? zjsD_hUyd`w`8(_(enJ-NGv6Kt>0HNt4xB(e?m9$vFXH$w-N^jK-B?fbtCXpua!@{X zTN-5Zs@ag<J@g~<I?n;;?;HiW^R)s<!*zr9aEn}8YotScf5k#_*v4t#)Yn-)>DerB z=yBHXbk7DCH|G1zlmhUD0DgD$y7^#lUCwjUk1hlo<L~#V_pE8U2wd2J{TH7~R%v(r zS?hE6%4p=*>oudvK(L;_%`_)i`*UC75U?KKMdvuLYkj+ud$T^huCZR)zJ%ZHek{(T z9tCu!eLCGE!DlQkUP^x)naKQ+vDAN6qbaDj@^y}9XYM#~WD@n~E9HC?dW8LEWZ!~4 zMEB%4H2;=__t@97pW`B_$AD6@t~dXm%pVubdIF;;|NVSE%KMJcJ}NF!pCLuGqt-R& zBi&U+du}{_0pEA|MaT{JEQGYxp&#@VFg<rB{lV^LEMFFs>rnku89W#HAGH;LeQ9jx z-YpBjL5J9mn@=tVd;h_4(_;G)u+g}lN7a-2$}+M7`RCt{AziG`ncu%&1B>|^Ec`iG zjBl{eH~7ryG)Ucqo9j70c@tjssApFeWFWoxan1*BC%K|0{js}}{j|4|;~=gP?I)x@ z$FuXY<v&j6qCQ)lk*F^ynR?Ujb$!WkXKr{M`CQhxw3pD%4$Y=sZ)Vc2<}G3Vj`Q=7 zzr7_7Orn0yJVg8Gu$KBX_OX430v92F#jJ^t-UEvvbvvfSy#tQhKEa`$>GWM~Gr_gT zv;4qD`QY#%)?Y2bRae=ro9C(jCClITsCu$5Qr|Iw?6<eB6(PS$yX()t|3<plkAdC( z^*LCq*T7=_1`B@<7ULVN_3ci06<jon->KVVFW@}r%%k6KKk;qkvj@{3#NTFm?nchn zp$}Pp^FHb+K8N-c*NWpe>2NB_j~~i@au0t4yleyXw&$hIhv26d^x(J)nKs6w+Oqp8 z_H$_%^%#De=^1A^e|PrIL%z<1w3FNwlokJBxv<q7r>O&}@4z?MzGX9(qFhie$LYYn z?}82Qb+n`5HL`ao=f&_svb~qpFVC@j!?)%-R68rS(ms5p^zQ{fuwBuPcaffSl>HEL zWjR=tx$Dm#Z(+KB{|y%VF{b<1=U}m31B>|^Ec`iGkME+#$AGoIWAcW9vyab&)NPCj zoDB}UmFQ8=Y^TZD8T8x94ag5!>!!e^EMJ*JJzaX9_EC2T^&eV~{%6HP_EXiwv8cbI z9sRNqb1!(sBUZo89*_54{F&_PNq>9c6Y}W@`jyPSg~(TX1?}W|F=crx>c3<P?Zb9{ z8S)v{I6YQ(Ik>7j$Em%+3Z}b$hCL)@k-hV24?Sy;uat9rc<Nvg@)wSzKR7;z_7O5; zsYCTwSPiyo?=OF?e-U3pez!l~qFC;~kuLUQV6i?2i}e~<%->+`&&zwh3D)DgeeeXZ z*0=3eBKX9qd`R^z>TmY_1z_*wWRK#6L~_*t`t66#&Ov(gK9090uduw+PCb>z&^|^E zq5j)fr6YfGZT6FWFWWJ_);p-*NU4GJpMu!0m7j9lx*JfB+3B2jV)rmTd_DE-d~gZM zk8rTw8uMu{|DMBgJyQApz8k3j@;5k6Cuglhxw4nvg6yzy6{L4SFUSvTuZFy|g7e<s zY^DcY;dg%CjO9z-T;x#wlX;x>F=PK<`+pHnMSc-q1B-YISk<Zis`uYuu^$7A^*LCq z*T8!I)>8ZP?2Y^$J-*G1$;hwuT|PM(Jg>$)NVdW-YImOxuBvo-)U(;k$XmbWdVTy! z=69Z>KZyUH_EIg8zxj+jl#gG=@n2k*{-WD{>fg7I`<0-^^uzkSF+13=z9^2{jp5Ye zyoR}`_x3fWPtT#Af9XVa529V{w&a<CEO+TSzJE*|>T}5w+UwDK)}TJ$XX%iwN34a^ z?YR0e`KA?52n!*{wwmiudG4P{dzrUy30RlYQpC@ZF5;<R5np3@f4qh4-+zO}ehe(u z=U}~FYhIu8nV!Ex?qk1ee;)W)2J-9i?He!+to7}ybb-5NEQHkGv+k=xaN$SeJnC6? z5XZr;6B*!3^_hOQ5&PG(i}rGTKmB#hCutv%^{D?#(K)DZpojW*c1{H^+fTje_(PL> zIqpj9bKHKDPR_o}ah)}qoZFKA!2JmQc+@S{n|hma@f_ysZR5PLBaZsNb(HJO-_I7~ zJ3>9_kiJgqAPpP$y>(WS!`jY3J74|zJ)|e4@;h}uX(`T2kYB{l!6Kdt7V$N(h_`^n z{+s#z`!TRypTBfE7p&K7v8_0t>G}IY4*j(D=aKuekYA7Q(y!CNTHpB}jRPC8?@(GF zc&?0gUusP9s7K*nl0&X!fv?SC{u-0$4-zV9AM;L7PvvvyKVpy3Z=0vt&Kk9;zwB#o z;eAy>9Jhw?2j=bQaU6Hf?bGm{woR;Yd~FUmbQRN^KS4Wtq8rOcT&7*c{6P6(F7wrl z<@>*JP@k#i=vVG@zmNJZ{XPToYPa=}M)~!w>U&48Czq~c|EXv4Pn?fA)N{B0yaX)b z=U|^do(dN6HL!@cfW`hBtoLK}k~v@L_4(MLoVWFQt@aSIp1%j%nP2<!_;a)mJ-*9M z&|heM7aNoCKKJl<*$(TYmn9dG>rU~gM|O+nMR0yN*N^!#t@ZtZhP0R6b?LW9bf>@h zIFb5^`jYKx6G{DDxRr+bTjx^W?jwD`XCLOcEuYD8``!xj#cLeb&$J}33ZtH*max2I z!b-IBrxe!TX(02Bj^cds#=Rv-@7!S_<gI-hAafUFL!OB!g*0rnD6M|bLY#*>)H88D zM)seVkp1y<u!yIEMSKk`;w@nP-s=4~SnS8ZVto!4>ou^Lzrn(vgT?p;3w?tF&Mb%2 z?WkF}0-UmOsz*Ib$Rq3cP>ZF^zdMWl+j#-)!@hw2dfUT`Q9db!dRn}X^T(C7)L;JW zOr#e+$Z@ORyXzqRbYL0B?Z5#X$77#efOhEguNzU%XUDVr#UR%Ey(LdwU_H6lXpdPx zQ2(P>aJ^aUH|jt1LE5)|zn0?s8-7cihoar$d<-nkOTZ$24i@oLu!ygLMZ86^+<zlo z?8m@jeGV4uHL#e!!NQ+|#rOtmeY-YJ1-ELt3R3sSwu|JXbkn1r4L(5L`3(K`m>nyT ze_L<P&&%GSeWc~H|KqRHUvycy8s(=1b6?i^TaMef7ikZloTt8xz}l#<-eUUcfZsST zg|(#~E3eTWHlJd8#7NFN-xjj`%$Hbivna}#Eauz4m-hJGRqDTADE*iIPA$cK2een5 zf5RTcc_`W`&d0#wyaX)b=U@>}1&jC^Sj1bvV*kzj{{0wOtk1z>y#^NZH(2;{rd#8? z<NDcPt?z_%llkYZfz<tz^nYu?7uHPosAs-5<R&lDZ`b>7HPVm0vJ~m--=uwPw$^{^ zmvFvmwrDNVOYY(PaqtB7=S}1~_$N2@ZMf^IeCFH#qTUX7gguyBH(GkUOuGx{Kz4NG zyf7w$<?Ak|Ke&Gp<)vqsFSwBQsJ}}~alZxa6Zaj!;`|%y32`3kP<4p&F|ar<0gL!K zSj1DoBEAOp`Qt5MvHxbee?JBm>vOPJuYtw<4c7jAR~Gf4$9LH?oR74=y=$f;f0rlU zgVg<X<2pH}G{d8wWtWg|b(#;J*}53{V_O!1Ti2#Njk!)eEm=)};TlE#6!+%-#FI<? zReY9%@;kqx-ikWLD>g5Gxe4_}|C$SVGITTKx*@PTGhsW^gCFMn@Nyc<AHJ9VV0Hkd z{thk0eJ0c=?ze!&eFyNL&%ecas6*8$&d0#wyaX)b=U@>}1&jC^Sj1bvy4}_LZ?M>p zfyMe9EY@paJ%4Md{rT43oX7R}Zv5h0<k$L+F3kXc@zeW|x*g|sm4GiD%Jisbr~8s) zQ@CE(Yh(V@r#U~2E~WpdmdOA7Q2L9NH@S}U?#6z^{J>59#btASS?Q#{t@oN4Ia^RZ za$%m5=CuDOx4Rd1XMWs|-24H|3+9$TXdhPjJ3`!FLw({t6Ik4D0gL+%U~&Ep{~*po z9qJ|Gd<-nkOTZ$24i@oLu!ygLMZ5(p_TS9!-;aUC`W&p+Yl$iBcRhcb`5c$ppO?SF z_^BS>H#^Nod9CltLz&=lJ2yb;4&63$Blt?Iw>|3FjwJGi4%|;hg|A2YqdA<PZ=9z8 z2tUj9U1lTBCr_-}i1J$u*txl~F7@v{pQp;3?>F3vbfe}YN}4s=eE_}~G6!;G7P;3D z*q!<LRV%-0l=u_(6;V#yUjvK#Oki=p1uX76fW`SY>_MD|I@D{$`50K7mw-k594z9g zU=d#fi+BrI?7zWcKL*z8^UG`Lm-TwB^Gf!+p1(Jx(>}C6@6(e0Mvw2_DV#sFzJ0CU zR`r`5PLx{hU?+RyH-U=-vOOyO(?6KrFof%|jwfj!ryZQ18@8bTxD`TwaOMm8i)Sk7 z54w(GI|`3+d@t!S2lWs5l=`kdK~?>3{(OC#dY^GRy#ViR5xpI(p2<I_|9&dc#eGGv zxW5J#_nE-rehWC<f8PNt&c7Y%z2ZC+EY8Qk;=BYb;^$xyPX&wk8d$_zz+(Rm*88!A z4|3e;^?9dnIdALrTGK`BcRhc*u5%xt{rQ_u(_iTEUDAPZBdzaM0oi!pr>@PAR-c=H z>?iNOnD0@~o{J$Tbm4j-t_JPph5O;Rjo%m1zdZ6T*9W}}w9_1Po&Ml-DgA>{O8s|y zEg$cjx|#ZpIXVpQ`Q%g?q}7f)Lfl72y11VT7WWmw;{F=b{r8#3{`)Opao+)~&$o30 z#CfPgJrn0+U~ygo7V&eih^K;m{`eYL#9P4nz190`u-K1*#rhm9)@xufe}jcTS1iXj zSm+!1>($>1soU|{baF*^+JjC{T0?snTYn4k=Q2KIrWMeCOfM+)s5-KL;dhK`wH3VV zdHSv4VbuS+Zu3w+YU~cA>-XM~{`==l_uoebi~FfyabFQE?yrHxeI~HD-vSo*9l+xJ z8}o%Y4|S+Eit{nBI4=Q<_&Hd_Q^6v>1{U!au-Jct#eNJd*5_ccUIUBy8!Y@eSd4G5 z*7u3-7^mjLdq2Q)t&e?ew}H(MIFGOQG5yGoT-Uw)3hm`=llMKUOu<R|i;Odyz-=Gk z`r@Y@^aqpH!Ec!xFaP!UH~hahKzYM|{~RptBZI~LRIs?O2p0F(z~Vj=Sdahe`z>H` z-vKPnzhMvJJk+7SSDcT5#d!%>#LvMZo(dN6HL!@cfW`hBEcRnyu|5Zj^%_{r-(ca- z!FqfruHihc^*!x_IV#<Z$k~p3>RZ*{gAK~SH8#*cWV)DsBMIwAGvPSxqbQX7yWQ>S zFE)g8eehHVtS`*GIQj$D>i;i(U*b_u#qSNk;{G{U+(!nB`>9}YUlA<suYtvVCa}2Q z0v7ijz~cPdq1q?TL&4&F3@pw|z#@JQ7V%WDh_8V~yag=w-(ayH1B>-JSghB;V*Une ze?GINwcfDC_u(ID4_e;=8|WYUCG9{t_3hPv=E-g3lBNqiiu?aW``Fc#`~F^kgMFBp zT{%CbHG#h{gPYMGpce5@{GLeFXNcdIfW_|(z`AJl{d4B`-$w?E`>9s?Y{=^Sijd;| z8rbQ-&jc3tTfpMJ1NhJ9-{L&fq1q<S$H3ye1T5m`U=dFR_w&csz#`rPw!UBOzrkWZ z1{Ujcuvo7t*7Nrrsr~s^O&BN8<NJCN=J7lFUe|OX>g(M9LrAL~MzEW_q5=E&Xl?S% z;jjm@W+?2%{QFVbgD$6~`2CniJrlnt0*l|5fW_|(z~cTnSlmYji~FfyabFQE?yrHx zeI~HD-vSo*9l+xJdyi_rI1hCw7UyGNab5xz@pG_<r-DU%4J_g<V6p!Oi~Sf_tk1#L zdd(c!3gc4G-)8z5%;R_b`MaT*$M1~q51Vqos`XveV1cU7925Bw>Q&#W{{GlO-d_m+ zU_AHhE~J0=>sk+U-2GqtUJ&Wx_hVr3dm^y-eF@qBdjqhze-0M+k-_4ADp=fC1dID? zU~!)bEbg~}#eD~`IRAz{i1Sc~`f_nT1{UWfU=cqDi+Czn#Mi(g-U1f;Z?M>pfvxqq znGnW#+*+@hKknc>Zq483`f&Oe%by$7{v74?_`Wfm_Mr8>w~+o}>Y$IUc2Li^J|lOG zUgWu3^Ca>6P^63B3xY5Ce?P`_|L=*w;`b$B@p}WXxPJ~7_mRQkekxepR|JduYhZDo z2`uinfW>_WusHvAs4o`hp<r=71{UWfU=cqDi+Czn#Mi(g-U1f;Z?Lr=GrN!FJZ`Pe zjq3F|(yjHHQN3ORTl2S3J%20K{@kec=SbJ%``cd`uh9DL5WNWLo%gsQ)wll_9LMA& literal 0 HcmV?d00001 diff --git a/StationTest/gold/xst_200_even.gold b/StationTest/gold/xst_200_even.gold new file mode 100644 index 0000000000000000000000000000000000000000..0b0b7fe23fded1d1acea55d98510d328fd959f7e GIT binary patch literal 16384 zcmeI3`FoAm7RO&2ZM3N;G&Nj9Q^k#;dTP2cRF7kd2u)&0TB<=11c?}8enm(S1PMVZ zClSQhw1Ob&IJ9-uB~{ea%F|1Ws;0QEwuXE5_j`8E(x-pI%@3B(yY}Aie)rmY?X`zv z82|tKe+&Gn1<p6NJ@urZE!n5KQ$06_b|x=r3bqE@$T@*vM`Ty9Be^Ttt+#IJ4K|y; z1-<!07`fa6F55N$Y($+utls1QRV2B*Eu__J5TrSyC!haDwoVNP+b6hr?7K|Ym9ng6 z6w?o7`K1BF!PXJ)Fx~bMl)qY;ZsI7)vLCysdXz@QkaPH5W;1eB>;5*SH*buDKI)qx zVC%SOre72dPCvr;JGzagKArXQ^%)0tjP8Z>0bSz2M$}Eb*Z-|}>JvjC{a28UX9s~J z2a)4ejsS-~$NcuFSa96yl-J$mSpPi|&tv|X09pEW6r}owr~b6PpRW$RBc#Vu>HPbK zlJ7Nhs(ewYYzL!97qIzoAoPwV?)FWI0Gk&hpf8&+09+c*cClYzd7%YtH^(3BPmc9$ zXCv-E><<^mBEL}*1nFO8Jf!0~+q3WlIj%d)NjJ#G0p_zLQpQb*Xa1_Rb9uoeu=S$5 zKDMbW_b2vGN6l$qBjyq868JOO(Td+uSWNcaKs&^BNksbeDB8n2Z8Es{i^(?CUbP2K z1e<-PgME9B275o64YtmD4?MHZT(EJqD&*CANz~7I57M%LT;6>=IPNjiAIqBpzIVWc z%qpG*88n9S@^j2r{Pk2kS9Owq72`XtDfAWgzS|63b~*B?d~sp!epJ-nsmk$fIvjfI zR@%SxB*%gO=NzA*>&Rufv{Tu#VMt%Ph4%4x4hBC6qMfV}>>m$?!%k7V$DM#3;=Z4P z_m%bN2N^h>?QYFrx#dsDq5g5uNA@6RRbxJT1Iog!GoVjTr(FvBn=Chg^(h>j1diJD zKBTvE9;6Y&e(4jR4EC?XcG%vQ{9rxppZx;UTOy{}RQse3os0DSr<h>#Jl}uxP%_yI z-)Y2EN(I|P=%0#{7g1j?(5cGttCa@!UBGdDYz;Z)5$)gR>SE}Nda+-mK3NF1A6)=h z@*SlrOa5tpZmthRIz7G}-MfIbz0F<i!4@muugi#QH5SheXLqN1=Kmx6r(@T<;4%x_ z#c=Yw%H~Z#`to@bptqc2{?apShr+HLSI2fwgWj>9{=`~!HdwzmppbSm-WZJMWhHE9 z%kgnwf3GCSf=(RYfkUV-Po9J4TH1HgUP0Za<9T4?6v*_z1jv$G3n7h-(U8ek7L(l- z@!ydKj{21C(!U2eZY;;!)#^;|+kkeNw1MTvZAh`HBC;a*{*qg?XW>WeAIW>up%0zI z{(O4i3b6kE6LVIA%jdH_vyYR{-<gBwjY7!xe&c)2-Ch1veqD~9zs=;X&})BgHhBlE z$G5SStnKYM+#UMRUYwV7dB)^PET?a%Q$6!fVE-)KF${dZ9^1w875#O3P3rx9IX<uV zOhEqBuV*5?uZ8pG_FURe_s7d4IPQ$n+wc!37A-*f^e_3IncuLTEjMV#;_9i;2b^X< z%C1j+>3NnD@-5|qa@xCa6yH~G+*0Io1hYSuc`paYbr}meDR2d(QT7<~R)am{^tG(_ zxjeEpd!|jbhu1*nkE~C-B=2GQgY8S9e^`s}FFHtjC;G5|42#KxKCn8!XXe?}U?b)} z-n-!MYrv5$+5VPA<hT_2nUX76Os^^-{v0}<+tM3)(>;GjU5o&0e{OuvI7E+c`>uCc zp4;A0?l_^i`Lw6r<Nq1I+uu9Fsa_lPkn^6od^ET?g8en?2af-&4`(62@A6sD2d-jy z-i_G~$9k}TM7{2|Z_Eg!Pu#W$>5bwi=nvb&mw-#h#z5XX!*&i@K|4l2BKtX5Zq_=c z56NOVwf9oCn3s<HwHvX2`3+hL4yZ%_(`IQVIIBPBuSQ<0!A7G>kR=DnK|SdQkH1Bp z`T9JYYL9crn7@;;1iY#n%kL1l5_~<3@6WDDd)HpTdR+8d2fgpvsZLeSkRu<0jne1A zK4Wso{%pV4OKw()#h;GPqkafOdL6Gh!lS@?{w~dprrzz(%MY{N_4u~$;JmKwZFsZ) z6zjOg{Z4yxez(2$5T|-%_F@0D7RQ0p`;vXD%mAkvOkZ%1{yZ_vL_G%g;&@J+kO=N? zqx~%PIiCbN*lvd3Gtj4naU9y~j7PcMTCkmC)^a|0{5m<xU2eN~n7)4m%dw58>>QMV z{4re?LoV7#d-@$^KPn1Yi|48BCPUV%o(*Y~2SL_!lCQ6rVpHEA`wwz#%M|dKvCJR0 zY&m%FFD$=C!76a8>a1sBR5m!f6YKFuKRdYekC{$Y?&LeUU?aaSxad|MSt-Sz=~<6K zFXD5sh}X!T`5P?!IarKuu&_5cJ!}D_uEL}>jC+in;ZF6euw)_h-h<eFw-U)$tJ5Ff z%40i~=cOQhi-znkx9V{`2bR-+jPa)Z5_@sn{Vj!d)9(!mUxoa>OC~}FxyNOGbJ{Vn z72CZihW%>KGfZzg$o99o<(>gq$nPD*{!uxM_Utr;^}8RO!}8yxT^1g+gLOT6)yf42 zG@fBo&$K@J&|>iOUon5nh8f^a>(?Q@OM)jQuwK(o(*8yj)?<122Iwu<Or)>dW+Pa? zw?cZ>-_VQo7+A#TU=go@#rzEx{v0gEH(1-deEo2+*PCgOx;`iNECpK<=(mr4y$qZ_ zp7ELGZF20TWT(nwImP_tM;LdN$Fe`w=t%pQJYn2b?La2dXXPZIJlk5@&2W@r{%n`W zaaZsy``y;<Z0GYO^tX>^ldFy8{2g4I>4Q77pET=Dc|4c)@9=l_lf{X&_t9YXqd5tA zs7LJyoZtFqZU7r649I`|MovF42lcFfh@3Wp?ecCH=D$273wp2WEPrJ++J9mb)+=@) z?Vp{?c4!&D3F&n^S4hu(3-zA$H(0F4z#={ei+Bwz=5Mg@=gjXO-^QTHU~O;zgc$JY zX!<=}Kg(x~g9;ywbE;?IK`W8Yer*o8>=gCK+;LMw8}pxRM>|D(b6ySINBb8KnveVo z4z5A|LcgitRId-g#`R~xUIRJq?4K}RC~wPl4%)!DAog$M6W!@oz8|w5`O}_fKWXz4 z<p+b9u74f&kMcgW=Xx)W(`N>3M83dk^lxc7n^=#6yXcp1HQfx3{Db}ByA<j(^7!2$ z5A&J73g?4YXRv>?O`yLoevb8ebNpZ1U+k~h(B_`~7R7S?4ZT>8fkk`{7V#Qb%->+` z&&#TFT<Y<iI(|Cz+TQj@<G?|_nUJWP>z~^TR)GUf#5>iq4wY7e+dN1DrwyP!YY)fU z_mT9QlR{~y*c$8~j%l>N^*;SY<r-|K(6%#BUdtb8H>0)>c*PrR*Rp*aw=b8Hqw_iM ze3eC>8A&@|m`}g{dpOIr{m%YWzb@@RcpcyWLmk?)Yy`(?ztIKwj*P|gAiXYafs85~ z068*zD`ftc$u{-<@mr~{_a@tE?oaG5=@)aL&#%h<)$l<+Smlv_Vm}pnvA+fu`z=r9 zcdfs{Vm$^H@i|z;YhXQpYpMNt%q4!09^YBl*x$9i{ZGUre>?9rkop@!)~y9wUYqPx z&ssja4xAma0NnRQ>ZgyRKPcS5{^F9*x7kI1a(h0<f9V;{CpQMselh=@jq=jsX*d1e z+#fmaO5Nl3o4IV~taQGoqz$>j4%&H4AEwXT&vG-|a@ogBH|!a{zt>B&=ch;5Uppsl zLp^VOnhII;_6|s0kDosxC+4T1p8vSB9r`Bs`JK+6*<Yspkqf=fr=``ie-6FaPX&wp zHRkv1w~#&SZ?MI)9s`T`9IWHD>-9LF>G}KC5w^Sb=SOQTM0!2GEf12w+TH=LO$LXL z_z+TmkMGOu_YbxwI@PmHL&z~c^xNOpUyt;s8?t?GH)nq-3S5Wu$2ZY`-29p2zeZd- z(oeoX`#;z;7i<gUxYhd)xlWF|W8*n)&qZ?_w<_kiZX8U$*_!^K#VY2%`IzNyeM0$g zGSgZ5^Zno7ru~0E!g%GAnjfK_MW3W9Y3>?X2sUD{?lphdNG_he2=!dkmOT3s$ANAq zEyZ~W(u@6bu-H!pi~TjQ*l%He&-$C`J?k;Bj?ZJfIe+PR&9@_2&)+B7(NAlCp0Q^M z^6T-P6|n%U?Onb-5j@N9>3+WGF1ggf`1`SU9@1HU<@~TWkb0*d{lWBV>@Tf+=&!AN z=x^e?(mqQISkL6;w4d+q^H5%^S2%7B|H@9)wslK6?y_33KkVN~I~Gh@1%0a*$*u3u z&h`lAuN22}UmZz#?H86a?;huujFq&1&AN>9o<w|%@}d(LLk<l21k!LAHdi&wp=spE zOtzo4yO!d7Or<x(c?nqTpM%AIDp>5VfyI6cSggOndOcP<h4ZqG&wUPLLa*bszWc~} z{+<}h^xB^%j${AO<2%}i{axGpm}4f&%goupdbmH>nUYTqHl6BGA2*j&UJedk#q{~^ z`2IjT`^Th3^xOOE(%)=9yb<YZ*I+%{zeoFJ&1S!B`v(26^>8HK7gl{I(mTdu+!}qq zB-`(CTu*9E9{wHe9NCrmmxj|HG+xc}zldYHXWz$sVkXV~808-G=KOJ><1TPO$x<cF zQ{9We#yww3cROfddd@>_>X|qn1B>$#>OK4CV6mSH7W->pvEKsL?{%%e!D2lI7V$Y) z#A{$Ne}jcT2aE9y7WM{L>bD6}*Q09Z&ESG1Nlx{weQUDbABy#2`hwAH->V1NKdv35 zKUfxINB-FZX{X0iIPcyHqx~$c(x89Po8wl$_oYwim%W;B+@7sPI|e&A4{80GhKw70 zPcy%N4*kX}l&04ymeYI^{l%O8X#b=t^ee~P?8bNPzm^WE-(Mj;=igXw*gfZ=sJA#D z1B>$#u-HEbi~Urv*k1#S{T8rTe}lz(3@qYvu!z^dV*UmTe-0Mo8?5b}za$A9-*gM4 zZjTQdZv}VCPj;$j@xN2wXj&%tpPLJy|0sd&JGV0X$NGEp2LtQmL0{E}b~>|@@kMF_ z+ONf##n4BLr@f7%H58k{CjE5DJ<dymu8^~fvYkrrQ$RlKwHciDHuG;8K!31lFy*pI zOm}xT`{Ur&wEwPk^k3?m<e#|jpvpDG`8WE5I1g3zG{pHBSe%!D#r`>1?5Bdo{u)^9 zw}8d^8!XmiU=g2#MZ5+U^EX)dbFd!Ywib;0wY>xLlcBHKVLPPyR`vH*s~zC1&=jZQ zQIDxFdx?H~^#|LaFAK?oKJz{HkG1aj@9dF$=ts`k0ll9y8{Bau?RRD_;$U-mAjhpy z?x)h3*Q4mSAHKl;u>KPHrSs@_=G-9iJH0V4m>a&Q-8bjMADH$W`i1EBOxN@=;|TQ) z@=x4vLH)#i2e3H*?xOOE^H6+;I3ELx^AfPwKL?BbRIu1z1B?9@uvmYC#d-`Z;&ZTw z*T7=_25W!5X*B0?J-!=G%Y<IrJ0mm&{QRhoAa$Ev>{JMjy1dZodS;$}ft<L6@mSLi zJE7m$ntprta`um^?b-fMs=;5Fug#-<LN+7bH1F4<{YM^3SNYAxFLT_MZ5)d7eh%NG z-e<(tS^-(LnEc%P=yzuO#^f>S@H^&;T-e<#d6oU*TtiA#hWr!vnNY5{-vSo*9l(D+ z{}$(=HdU@T9|Mc?60q1m2aEkwu-IP%i~Sa`uDfgf4HoM$u!zsWB3=XQ`CCiv&vzzp z9@pdhyO*+%UfX-{<%QrblRt*k^?3e1**+`H>3U{v+)a)ih<L%AdXN1hGM@88ayI>m zORDt7kq-11|E^E_1V`km^35ydu%8jTH3RQ!@Eh%`^0@xYSH~42f9j_zAuk>$J1Vo^ zjcq}`?#+3j{;a3+vlQ3A;{F=S5%-zE;(iNQ+;;$r^KbYEaUN<@FA?WsU~ygo7W?O5 zv7ZVS`)gpa-vSovZ?IU8fkk`{*74e`foyj@e}8yyBlOyzUkSlHUNOF>EaCcD+dF#} z<GT56b|Ig;LCwB<$+xB~bGn|Hak=FFy|C^#w^=_y`jxSmpUsN_>>uAXqdyov4DpA# z^mF=yZw>Tw^H>J$7jv8QR`{#?RQZMx@-k%dy#0{=37L@A8|1uw=yzt9)@0-n|A_mF z$S3ZvfyI3$u(;m>7WW;%;{4mDUL(#!!Qy-jEY3^7V*ea0_EW)Pe+?}5Tfk!d&Ger2 z7+A;WKZS7~*YTRS5B;>Bzt=>we`tT6-<o#N<9paZ%pVo@zCLA{D&PF<h25+N+t~Cg zBA=+T)Tth|dy8Cc4dbz-AJ{*Zti=3a{%bY;NA{YJk^bZ{`ir&=cY~`fU_IJ@!SQX) z%T(_(o3%dxy<z;O#-X`sUkUg`qt!~9&0jg_*1JgjSv~htp%?cR!Q%cJSlnj<i~B8L zao+(f&cAKywc<P!EY8Qk;=BYb_Rqm$KNT$Y*T7=G1uWLzV7(suZ*R`)IzCTnK-Tfv zh&gO`J%4+*=eX4VJR%<cqGEi9_gb&Yudw&ADogRc|M={M)J?uGkvyg`#;Mu)>K^Dj zyaT^&-t5W#G5=ZkZ8Ojx{lgsf8vVgg1M!7fUcA?-%6#!#&Vvu@(*CLQFkhIpa%gYg zBQYwS+0yqA((8I?DefafFYc#;#eGGvxW5J#_nE-rehXOKcL3}2ZT)_69%@t1#Q7Ll zoR@&b{yA9er-H@)8d&VNfc1M_>ua!BkAX#e4i@nmSj^vwr9X#WjBl{8H`0GoZy%n! z>tRmYKn@<9;Z)^m{o_;Y55eEEzua{14>j0ZgmPR`r8n-J!*`fn+HpRp<PE=NPJ77l z9~!v^@B8NDU)x{YKSz1uJ~G(!+)o9I`-)(3e+?||Gl9kZ7O=SQ02b%pHuXK?JQOU> z$H3ye1T6N?!D2rZEcVyHV!s6}*56>U9s`T`94z8B#d7|JUifq9#rOtmdj}0>T<6pF z0P?ACcm0|1hsc*3u5zjeXJW~nnsOem@h<yI&|Sm}=EOeqAG!SyADA;6F}@fPK!4zS zb_>d1W%+CSJ3PNP!287gbFjFN3>NoO!Q#FmSlnL&i~CGqJ^o$yTfpMJ16Z7YBc2rJ zp*GbX;(QD&&P%{z{~Rp#Q^8_?4J`Isz+(Lk7V9zQ_r&L55w9th^EX)dbFd!Yk4|wO z*Y>{Ha2529*n>(|{PlR{Q*hD+`iHy_>f3fj{Af(;h5lidb;SC?yzy)?$~jw!@j<_2 z#uqzV9&}a|D*xm8eF^kd&+iSursw`SSlmYji~FfyabFQE?yrHxeI~HD-vSo*9l+xJ z+oq~5&O^cCd<-nkOTc3P94z)z!D4?6EcRQ#V*L#k>oKs1&%q*IQ!M9iu=eLST4Nrs z7~dV6a{Zz0ZC;>%809>Ka<$32)o_4o+{|{WXV;rj-(>4H#b(rn66mjmaek=Z1pdO@ zI_9tAfAM=FlqY^)0v5kF0PA|V?w^CjePpn>p9&WD6~W^E8d%(C0*m`CU~%68{O9v; zaUN<@bra`fU~ygo7W?O5v7ZVS`)gpa-vV}jzgmBT#d-`Z;&ZTw*TC-i+tBm4+n<{~ z?{Xg3<GW2)u0OQBeQ#zXe{#*kknVa|{UXU;_H|CzGe_qe>>pE~pg$PiQ_(-nUn_I{ z;LcYe#P7#cenb482rPbI0v5kF0E_$QU~wNAEbga*#eGGvxW5J#_nE-rehXOKcTg<P zzYnYWi}O&M(u?ykusAPKY>54Hu-H!pi~TjQ*lz)g^*30o$G{>!2fO1n!xgV7*7LV% z@5g!E?avLDKSz2!z8i1F`n1B{mF?@G@7Bi&slG-1b<7~&nf;+t@sL{NwZCw`Nj;N) z;`f3`FMdA;7QZI~i{F=k#qSNk;{G{U+()L~b3YX<?kj@D{WY+-&jc3tTNKOt4$zD9 zZ?HHIwW;qG=VM@TUIG^T=U}m)3KsioV6oo<7VB@YSdW3-@wwrO&lT%<&5RD<Jno*q z4cGh)z1yFgSHlqZSB&o|Pq<&9?Oi?_`w@;YYmeYP>RVlZ=8P-k9yvKqK6?6J@%vEd z#qR~d;`d`<@p~e$_<af3@ciC@?74pq7Wa|C;(jVv+*bsP`)govp9w7Pw<wnP9l+xJ z+orx;oQHzN`50K7mnfF|=g^D&RIu1z1B?9@uvmYC-Rm*)+)2*c?)coyw2<BLnz^GT p<2?8LZMf!d<ahgX!{yJxdVH_>1^X2h_U@LG1O1|3k3y<%{~s&0(_jDq literal 0 HcmV?d00001 diff --git a/StationTest/gold/xst_200_odd.gold b/StationTest/gold/xst_200_odd.gold new file mode 100644 index 0000000000000000000000000000000000000000..5c689fb51c1a8c0819e177233ae009a03c0304ab GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/StationTest/i2c_spu.py b/StationTest/i2c_spu.py new file mode 100644 index 00000000000..78293b5328c --- /dev/null +++ b/StationTest/i2c_spu.py @@ -0,0 +1,64 @@ +"""Testcase for RSP - SPU I2C interface, read SPU sensor information +""" + +################################################################################ +# User imports +import cli + +print '' +print 'Read SPU sensor information to verify the RSP - SPU I2C interface' +print '' + +################################################################################ +# Command line + +appLev = False +cli.command('rm -f spustat.log',appLev) +cli.command('rspctl --spustat > spustat.log',appLev) + +################################################################################ +# Verify result + +f=open('spustat.log','r') +f.readline() # skip title line +data_str = f.readline() # keep measured data line +f.close() + +data_str = data_str.replace(' ','') # remove spaces +data_str = data_str.strip() # remove \n +data = data_str.split('|') # make a list of strings + +volt_5v = float(data[1]) +volt_8v = float(data[2]) +volt_48v = float(data[3]) +volt_3v3 = float(data[4]) +temp_pcb = int(data[5]) + +print '5 V = %5.2f V' % volt_5v +print '8 V = %5.2f V' % volt_8v +print '48 V = %5.2f V' % volt_48v +print '3.3 V = %5.2f V' % volt_3v3 +print 'Temp = %d degrees C' % temp_pcb +print '' + +tc_result = 1 +if volt_5v < 4.5 or volt_5v > 5.5: + print 'Value %f for 5 V is wrong' % volt_5v + tc_result = 0 +if volt_8v < 7.0 or volt_8v > 8.5: + print 'Value %f for 8 V is wrong' % volt_8v + tc_result = 0 +if volt_48v < 44 or volt_48v > 49: + print 'Value %f for 48 V is wrong' % volt_48v + tc_result = 0 +if volt_3v3 < 3.0 or volt_3v3 > 4.0: + print 'Value %f for 3.3 V is wrong' % volt_3v3 + tc_result = 0 +if temp_pcb < 10 or temp_pcb > 40: + print 'Value %f for PCB temperature is wrong' % temp_pcb + tc_result = 0 + +if tc_result == 0: + print 'RSP --> SPU I2C interface test went wrong' +else: + print 'RSP --> SPU I2C interface test went OK' diff --git a/StationTest/i2c_td.py b/StationTest/i2c_td.py new file mode 100644 index 00000000000..01b5d631baf --- /dev/null +++ b/StationTest/i2c_td.py @@ -0,0 +1,54 @@ +"""Testcase for RSP - TD I2C interface, read TD sensor information +""" + +################################################################################ +# User imports +import cli + +print '' +print 'Read TD sensor information to verify the RSP - TD I2C interface' +print '' + +################################################################################ +# Command line + +appLev = False +cli.command('rm -f tdstat.log',appLev) +cli.command('rspctl --tdstat > tdstat.log',appLev) + +################################################################################ +# Verify result + +f=open('tdstat.log','r') +f.readline() # skip title line +data_str = f.readline() # keep measured data line +f.close() + +data_str = data_str.replace(' ','') # remove spaces +data_str = data_str.strip() # remove \n +data = data_str.split('|') # make a list of strings + +volt_3v3 = float(data[6]) +volt_5v = float(data[7]) +temp_pcb = int(data[8]) + +print '3.3 V = %5.2f V' % volt_3v3 +print '5 V = %5.2f V' % volt_5v +print 'Temp = %d degrees C' % temp_pcb +print '' + +tc_result = 1 +if volt_3v3 < 3.0 and volt_5v > 4.0: + print 'Value %f for 3.3 V is wrong' % volt_3v3 + tc_result = 0 +if volt_5v < 4.5 and volt_5v > 5.5: + print 'Value %f for 5 V is wrong' % volt_5v + tc_result = 0 +if temp_pcb < 10 and temp_pcb > 40: + print 'Value %f for PCB temperature is wrong' % temp_pcb + tc_result = 0 + +if tc_result == 0: + print 'RSP --> TD I2C interface test went wrong' +else: + print 'RSP --> TD I2C interface test went OK' diff --git a/StationTest/modules/Makefile.am b/StationTest/modules/Makefile.am new file mode 100644 index 00000000000..0d289bbe166 --- /dev/null +++ b/StationTest/modules/Makefile.am @@ -0,0 +1,9 @@ +testdir = $(prefix)/stationtest/modules +test_SCRIPTS = cli.py \ + mep.py \ + rsp.py \ + smbus.py \ + testcase.py \ + testlog.py + +include $(top_srcdir)/Makefile.common diff --git a/StationTest/modules/cli.py b/StationTest/modules/cli.py new file mode 100644 index 00000000000..9cb9861031b --- /dev/null +++ b/StationTest/modules/cli.py @@ -0,0 +1,14 @@ +"""Command line interface access +""" + +################################################################################ +# System imports +import commands + +################################################################################ +# Functions + +def command(arg, p=False): + if p: + print arg + return commands.getoutput(arg) diff --git a/StationTest/modules/mep.py b/StationTest/modules/mep.py new file mode 100644 index 00000000000..92a3fb5ca8a --- /dev/null +++ b/StationTest/modules/mep.py @@ -0,0 +1,366 @@ +"""MEP interface for RSP board access via rspctl --readblock/--writeblock + + See also MepMessage.tcl. + + class MepMessage: + def swap2(self, h) + def swap3(self, h) + def swap4(self, h) + def packAddr(self, blpId, pid, regId) + def clearPayload(self) + def appendPayload(self, hexString) + def lenPayload(self) + def getPayload(self, offset, nof) + def packPayload(self, data, width) + def extractPayload(self, readData) + def unpackPayload(self, width, sign='+') + def setOffset(self, offset=0) + def incrOffset(self, offset=1) + def readUnsigned(self, width): + def readSigned(self, width): +""" + +class MepMessage: + c_blpid = {'blp0' : 1, + 'blp1' : 2, + 'blp2' : 4, + 'blp3' : 8} + + c_pid = {'rsr' :1, + 'rsu' :2, + 'diag' :3, + 'ss' :4, + 'bf' :5, + 'bst' :6, + 'sst' :7, + 'rcuh' :8, + 'cr' :9, + 'xst' :10, + 'cdo' :11, + 'bs' :12, + 'serdes':13, + 'tdsh' :14, + 'tbbi' :15, + 'cep' :16, + 'lcu' :17, + 'rad' :18} + + c_regid = {('rsr','status') : 0, + ('rsr','version') : 1, + ('rsr','timestamp') : 2, + ('rsu','flash') : 1, + ('rsu','erase') : 2, + ('rsu','reconfig') : 3, + ('rsu','sysctrl') : 4, + ('rsu','unprotect') : 5, + ('tdsh','protocol') : 0, + ('tdsh','result') : 1, + ('diag','setx') : 0, + ('diag','sety') : 1, + ('diag','wavex') : 2, + ('diag','wavey') : 3, + ('diag','bypass') : 4, + ('diag','result') : 5, + ('diag','selftest') : 6, + ('bs','psync') : 0, + ('ss','settings') : 0, + ('bf','coefxr') : 0, + ('bf','coefxi') : 1, + ('bf','coefyr') : 2, + ('bf','coefyi') : 3, + ('sst','power') : 0, + ('bst','power0') : 0, + ('bst','power1') : 1, + ('bst','power2') : 2, + ('bst','power3') : 3, + ('xst','r0') : 0, + ('xst','r1') : 1, + ('xst','r2') : 2, + ('xst','r3') : 3, + ('xst','r4') : 4, + ('xst','r5') : 5, + ('xst','r6') : 6, + ('xst','r7') : 7, + ('xst','r8') : 8, + ('xst','r9') : 9, + ('xst','r10') : 10, + ('xst','r11') : 11, + ('xst','r12') : 12, + ('xst','r13') : 13, + ('xst','r14') : 14, + ('xst','r15') : 15, + ('xst','r16') : 16, + ('xst','r17') : 17, + ('xst','r18') : 18, + ('xst','r19') : 19, + ('xst','r20') : 20, + ('xst','r21') : 21, + ('xst','r22') : 22, + ('xst','r23') : 23, + ('xst','r24') : 24, + ('xst','r25') : 25, + ('xst','r26') : 26, + ('xst','r27') : 27, + ('xst','r28') : 28, + ('xst','r29') : 29, + ('xst','r30') : 30, + ('xst','r31') : 31, + ('rcuh','settings') : 0, + ('rcuh','protocolx') : 1, + ('rcuh','resultx') : 2, + ('rcuh','protocoly') : 3, + ('rcuh','resulty') : 4, + ('cr','softrst') : 0, + ('cr','softsync') : 1, + ('cr','syncoff') : 2, + ('cr','syncdelay') : 3, + ('cdo','settings') : 0, + ('cdo','iphdr') : 1, + ('serdes','hdr') : 0, + ('serdes','data') : 1, + ('cep','hdr') : 0, + ('cep','data') : 1, + ('lcu','hdr') : 0, + ('lcu','data') : 1, + ('rad','settings') : 0, + ('rad','latency') : 1, + ('tbbi','settingsx') : 0, + ('tbbi','settingsy') : 1, + ('tbbi','selmemx') : 2, + ('tbbi','selmemy') : 3} + + c_hw = 2 # 2 hex digits per byte + + hexAddr = '' # rspctl --readblock/writeblock ADDR field as string of hex digits + hexPayload = '' # payload string of hex digits + offset = 0 # offset for read hexPayload in nof bytes + + def swap2(self, h): + """Byte swap hex string of two bytes + """ + return h[2:4] + h[0:2] + + def swap3(self, h): + """Byte swap hex string of three bytes + """ + return h[4:6] + h[2:4] + h[0:2] + + def swap4(self, h): + """Byte swap hex string of four bytes + """ + return h[6:8] + h[4:6] + h[2:4] + h[0:2] + + def packAddr(self, blpId, pid, regId): + """Construct string of hex digits for rspctl --readblock/writeblock ADDR field + + Input: + - blpId = list of 'rsp' for BP and/or one or more 'blp#' for AP# to address + - pid = process ID + - regId = register ID of the process + Output: + - self.hexAddr + Return: void + Example: + p=mep.MepMessage() + p.packAddr(['rsp', 'blp0', 'blp1'], 'diag', 'bypass') + """ + ap = 0 + bp = 0 + for i in blpId: + if i=='rsp': + bp = 1 + else: + ap += self.c_blpid[i] + self.hexAddr = '%02x%02x%02x%02x' % (ap, bp, self.c_pid[pid], self.c_regid[(pid,regId)]) + + def clearPayload(self): + """Clear hex payload string + """ + self.hexPayload = '' + + def appendPayload(self, hexString): + """Append hex string to the hex payload string + """ + self.hexPayload += hexString + + def lenPayload(self): + """Return length of the hex payload string in nof bytes + """ + return len(self.hexPayload)/self.c_hw + + def getPayload(self, offset, nof): + """Return hex payload string + + Input: + - offset = Offset in nof bytes + - nof = Nof bytes to get + Return: + - hex string + """ + return self.hexPayload[offset * self.c_hw : (offset + nof) * self.c_hw] + + def packPayload(self, data, width, append=False): + """Pack data list into hex payload string + + Input: + - data = list of numbers + - width = nof bytes per number + - append = when false clear hexPayload first, when true append the data + Output: + - self.hexPayload + Return: void + Example: + p=mep.MepMessage() + p.packPayload([3,-400,50],2) + """ + if append == False: + self.clearPayload() + if width==1: + for i in data: + self.appendPayload(('%02x' % i)[-2:]) # pad 0 for single hex digit, strip sign extension of negative long + elif width==2: + for i in data: + self.appendPayload(self.swap2(('%04x' % i)[-4:])) + else: # width==4: + for i in data: + self.appendPayload(self.swap4(('%08x' % i))) + + def extractPayload(self, readData, append=False): + """Extract hex payload string from rspctl read data + Input: + - readData = echo from rspctl command + - append = when false clear hexPayload first, when true append the read data + Output: + - self.hexPayload + Return: void + """ + if append == False: + self.clearPayload() + j = 1 + for i in range(len(readData)): + if readData[i] == '\n': + j = 0 # found new line + elif readData[i] != ':' and j == 5: + j = -1 # check data start of ':' at pos 5 + elif j > 5 and j < 55: + if readData[i] != ' ': # read the data + self.appendPayload(readData[i]) + if j >= 0: + j += 1 + + def unpackPayload(self, width, sign='+'): + """Unpack data list from hex payload string + + Input: + - self.hexPayload + - width = nof bytes per number + - sign = '+' for unsigned word list, '-' for signed word list + Return: + - list of numbers + Example: + p=mep.MepMessage() + p.packPayload([3,-400,50],2) + p.unpackPayload(2, '-'): + """ + umax = [0, 256, 65536, 0, 4294967296L] # sign convert constant + data = [] + if sign=='+': # unsigned + for i in range(0, self.lenPayload(), width): + d = self.getPayload(i, width) + if width==2: + d = self.swap2(d) + elif width==4: + d = self.swap4(d) + d = int(d,16) + data.append(d) + else: # signed + for i in range(0, self.lenPayload(), width): + d = self.getPayload(i, width) + if width==2: + d = self.swap2(d) + elif width==4: + d = self.swap4(d) + if int(d[0],16)<8: + d = int(d,16) + else: + d = int(d,16)-umax[width] + data.append(d) + return data + + def setOffset(self, offset=0): + """Set offset for read access in payload octets + + Input: + - offset = offset as nof bytes + Output: + - self.offset = offset as nof bytes + Return: void + """ + self.offset = offset + + def incrOffset(self, offset=1): + """Increment offset for read access in payload octets + + Input: + - offset = offset increment in nof bytes + Output: + - self.offset = offset incremented by offset nof bytes + Return: void + """ + self.offset += offset + + def readUnsigned(self, width): + """Read unsigned word from the hex payload string and increment offset + + Input: + - self.hexPayload + - width = nof bytes per number + - self.offset + Return: + - unsigned + Example: + p=mep.MepMessage() + p.packPayload([3,-400,50],2) + p.setOffset(2) + p.readUnsigned(payload, 2) + """ + d = self.getPayload(self.offset, width) + self.incrOffset(width) + if width==2: + d = self.swap2(d) + elif width==3: + d = self.swap3(d) + elif width==4: + d = self.swap4(d) + return int(d,16) + + def readSigned(self, width): + """Read signed from the hex payload string and increment offset + + Input: + - self.hexPayload + - width = nof bytes per number + - self.offset + Return: + - signed + Example: + p=mep.MepMessage() + p.packPayload([3,-400,50],2) + p.setOffset(1) + p.readSigned(payload, 2) + """ + umax = [0, 256, 65536, 0, 4294967296L] # sign convert constant + d = self.getPayload(self.offset, width) + self.incrOffset(width) + if width==2: + d = self.swap2(d) + elif width==3: + d = self.swap3(d) + elif width==4: + d = self.swap4(d) + if int(d[0],16)<8: + d = int(d,16) + else: + d = int(d,16)-umax[width] + return d + diff --git a/StationTest/modules/rsp.py b/StationTest/modules/rsp.py new file mode 100644 index 00000000000..a17f8cd8201 --- /dev/null +++ b/StationTest/modules/rsp.py @@ -0,0 +1,1280 @@ +"""RSP board register access functions + + def rspctl(tc, arg) + + def i2bb(s) + def i2bbbb(s) + def calculate_next_sequence_value(in_word, seq='PRSG', width=12) + def reorder(data, index) + + def write_mem(tc, msg, pid, regid, data, blpId=['blp0'], rspId=['rsp0'], width=2, offset=0, bc=0) + def read_mem(tc, msg, pid, regid, nof, blpId=['blp0'], rspId=['rsp0'], sign='+', width=2, offset=0) + + def write_cr_syncoff(tc, msg, blpId=['blp0'], rspId=['rsp0']) + def write_cr_syncon(tc, msg, blpId=['blp0'], rspId=['rsp0']) + def write_cr_sync_delay(tc, msg, syncdelay=0, syncedge=0, blpId=['blp0'], rspId=['rsp0']) + def read_cr_sync_delay(tc, msg, blpId=['blp0'], rspId=['rsp0'], applev=21) + + def write_diag_bypass(tc, msg, bypass, blpId=['blp0'], rspId=['rsp0'], applev=21) + def read_diag_bypass(tc, msg, blpId=['blp0'], rspId=['rsp0'], applev=21) + def write_diag_selftest(tc, msg, selftest, blpId=['blp0'], rspId=['rsp0'], applev=21) + def read_diag_result_buffer(tc, msg, nof, width, blpId=['blp0'], rspId=['rsp0']) + + def write_rd_smbh_protocol_list(tc, msg, smbh, protocol_list, polId=['x', 'y'], blpId=['blp0'], rspId=['rsp0']) + def overwrite_rd_smbh_protocol_results(tc, msg, smbh, polId=['x', 'y'], blpId=['blp0'], rspId=['rsp0']) + + def write_rsu_altsync(tc, msg, rspId=['rsp0']) + + def overwrite_rsr(tc, msg, procid='all', value=255, rspId=['rsp0']) + def read_rsr(tc, msg, procid='all', rspId=['rsp0'], applev=21) + + def write_rad_settings(tc, msg, settings, rspId=['rsp0'], applev=21) + def read_rad_settings(tc, msg, rspId=['rsp0'], applev=21) + def read_rad_latency(tc, msg, rspId=['rsp0'], applev=21) + + def write_ss(tc, msg, ss_map, blpId=['blp0'], rspId=['rsp0']) + def read_ss(tc, msg, nof, blpId=['blp0'], rspId=['rsp0']) +""" + +################################################################################ +# System imports +import math + +# User imports +import cli +import mep +import smbus + + +################################################################################ +# Constansts (from constants.tcl) + +# From common(pkg).vhd +c_complex = 2 # factor 2 accounting for Re part and Im part of complex number +c_cpx = c_complex +c_phs = c_complex +c_pol = 2 # factor 2 accounting for X and Y polarization +c_pol_phs = c_pol * c_phs + +c_long = 4 + +c_rcu_version = 1 # ctrlreg[23:20] = "0001" in RCU i2cslave(rtl).vhd + +c_ext_clk_freq = 200000000 +c_rcu_clk_freq = c_ext_clk_freq + +c_nof_bp = 1 +c_nof_ap = 4 +c_nof_blp_per_ap = 1 +c_nof_blp = c_nof_ap * c_nof_blp_per_ap + +c_nof_subbands = 512 +c_slice_size = c_cpx * c_nof_subbands + +c_nof_lanes = 4 +c_nof_beamlets = 248 +c_nof_beamlets_per_lane = c_nof_beamlets / c_nof_lanes +c_nof_antennas = 96 +c_nof_crosslets_per_antenna = 1 +c_nof_crosslets = c_nof_antennas * c_nof_crosslets_per_antenna +c_nof_crosslets_per_lane = c_nof_crosslets / c_nof_lanes +c_nof_reflets = c_nof_crosslets_per_antenna +c_nof_reflets_ap = c_nof_crosslets_per_antenna * c_nof_ap +c_nof_beamlets_ap = c_nof_reflets_ap + c_nof_beamlets +c_nof_let_types = 2 + +c_rcu_dat_w = 12 +c_rcu_dat_mask = 2**c_rcu_dat_w - 1 +c_blp_out_dat_w = 18 +c_ring_data_dat_w = c_blp_out_dat_w+2 # = 20 + +c_diag_reg_wave_dat_w = 18 +c_diag_reg_wave_size_small_w = 11 +c_diag_reg_res_word_w = 4 +c_diag_reg_res_size = c_nof_beamlets_ap*c_pol_phs + +c_bf_reg_coef_w = 16 +c_beam_data_dat_w = 24 + +c_ring_dat_w = 14 + +c_tdsh_protocol_adr_w = 11 +c_tdsh_result_adr_w = 10 +c_rcuh_protocol_adr_w = 9 +c_rcuh_result_adr_w = 9 + +c_rad_nof_rx = 1+c_nof_let_types*c_nof_lanes # = 9 + +c_ei_status_rsp_tvolt_offset = 0 +c_ei_status_rsp_tvolt_size = 9 +c_ei_status_rsp_clk_offset = c_ei_status_rsp_tvolt_offset + c_ei_status_rsp_tvolt_size +c_ei_status_rsp_clk_size = 1 +c_ei_status_rsp_offset = 0 # = c_ei_status_rsp_tvolt_offset +c_ei_status_rsp_size = 12 # = c_ei_status_rsp_tvolt_size + c_ei_status_rsp_clk_size rounded to factor of 4 +c_ei_status_eth_offset = c_ei_status_rsp_offset + c_ei_status_rsp_size +c_ei_status_eth_size = 12 +c_ei_status_mep_offset = c_ei_status_eth_offset + c_ei_status_eth_size +c_ei_status_mep_size = 4 +c_ei_status_diag_offset = c_ei_status_mep_offset + c_ei_status_mep_size +c_ei_status_diag_size = 24 +c_ei_status_bs_offset = c_ei_status_diag_offset + c_ei_status_diag_size +c_ei_status_bs_size = 16 # For each AP +c_ei_status_rcuh_offset = c_ei_status_bs_offset + c_nof_blp * c_ei_status_bs_size +c_ei_status_rcuh_size = 12 # For each AP +c_ei_status_rsu_offset = c_ei_status_rcuh_offset + c_nof_blp * c_ei_status_rcuh_size +c_ei_status_rsu_size = 4 +c_ei_status_ado_offset = c_ei_status_rsu_offset + c_ei_status_rsu_size +c_ei_status_ado_size = 8 +c_ei_status_rad_offset = c_ei_status_ado_offset + c_nof_blp * c_ei_status_ado_size +c_ei_status_rad_size = 4 +c_ei_status_rsr_offset = 0 # = c_ei_status_rsp_tvolt_offset +c_ei_status_rsr_size = c_ei_status_rad_offset + c_rad_nof_rx * c_ei_status_rad_size + +c_ei_eth_err_noerr = 0 +c_ei_eth_err_preamblevalue = 1 +c_ei_eth_err_framedelimiter = 2 +c_ei_eth_err_preamblelength = 3 +c_ei_eth_err_headerlength = 4 +c_ei_eth_err_crc = 5 +c_ei_eth_err_oddnibblelength = 6 +c_ei_eth_err_framelength = 7 + +c_ei_mep_err_noerr = 0 +c_ei_mep_err_type = 1 +c_ei_mep_err_addr_blp = 2 +c_ei_mep_err_pid = 3 +c_ei_mep_err_regid = 4 +c_ei_mep_err_offset = 5 +c_ei_mep_err_size = 6 +c_ei_mep_err_ringcrc = 7 +c_ei_mep_err_timeout = 8 + +################################################################################ +# Derived constants (from constants.tcl) + +# - Calculate ADO scale factor based on word widths in ado(rtl).vhd and nof samples per sync interval for 200 MHz +dat_in_w = c_rcu_dat_w +nof_acc_w = math.ceil(math.log(c_rcu_clk_freq)/math.log(2)) +result_w = 32 +acc_w = dat_in_w + nof_acc_w +c_ado_scale = int(round(pow(2, acc_w - result_w))) + +# RSR status +c_rsr_ok = 0 +c_rsr_error = 1 +c_rsr_undefined = 2 + +c_cp_bp = 1 +c_cp_statusRdy = 0 +c_cp_statusVersion0 = 1 +c_cp_statusFpgaType = 2 +c_cp_statusImageType = 3 +c_cp_statusTrigLo = 4 +c_cp_statusTrigHi = 6 +c_cp_statusVersion1 = 7 +c_cp_version_w = 2 +c_cp_trig_w = c_cp_statusTrigHi-c_cp_statusTrigLo+1 +c_cp_trig_mask = (1 << c_cp_trig_w) - 1 +c_cp_trig_ButtonRst = 0 +c_cp_trig_TempRst = 1 +c_cp_trig_UserRst = 2 +c_cp_trig_WdRst = 4 + +# From diag(pkg).vhd +c_diag_dev_ri = 0 +c_diag_dev_rcux = 1 +c_diag_dev_rcuy = 2 +c_diag_dev_lcu = 3 +c_diag_dev_cep = 4 +c_diag_dev_serdes = 5 + +c_diag_mode_no_tst = 0 +c_diag_mode_loop_local = 1 +c_diag_mode_loop_line = 2 +c_diag_mode_loop_remote = 3 +c_diag_mode_tx = 4 +c_diag_mode_rx = 5 +c_diag_mode_tx_rx = 6 +# RI specific modes +c_diag_mode_bus = c_diag_mode_tx_rx +c_diag_mode_lane_all = 7 +c_diag_mode_lane_single = 8 +# Serdes specific loopback mode variants +c_diag_mode_loop_sys_diag = 9 +c_diag_mode_loop_par_diag = c_diag_mode_loop_local +c_diag_mode_loop_serial = 10 +c_diag_mode_loop_metal_line = c_diag_mode_loop_line +c_diag_mode_loop_par_line = 11 + +c_diag_duration_debug = 0 +c_diag_duration_quick = 1 +c_diag_duration_normal = 2 +c_diag_duration_extra = 3 + +c_diag_res_ok = 0 +c_diag_res_none = 1 +c_diag_res_sync_timeout = 2 +c_diag_res_data_timeout = 3 +c_diag_res_word_err = 4 +c_diag_res_illegal = 5 + +# RCU I2C bus +c_rcuh_i2c_addr_rcu = 1 +c_rcuh_i2c_addr_hba = 2 + +# I2C handler time resolution +c_msec = int(round(200e6 * 1e-3)) + +# HBA control +# +# In the client the registers are stored in order: SPEED, TBM, LED, DUMMY, VREF, STAT. +# - TBM = measured bit time +# - STAT = bit 0 contains the comparator state: 0 is high line input level, 1 for low line input level +# Reading 2 bytes from the SPEED register yields SPEED and TBM. Similar reading 2 bytes from VREF yields +# VREF and STAT. In fact note that reading 6 bytes from SPEED yields them all. +# +# In the server the measured bit time is also stored after YDELAY, so via get word from c_hba_sreg_ydelay +# one gets ydelay and the measured bit time. +c_hba_nof_servers = 16 # HBA nof servers + +c_hba_cmd_request = 0 # HBA client REQUEST register +c_hba_cmd_response = 1 # HBA client RESPONSE register +c_hba_cmd_led = 2 # HBA client LED register +c_hba_cmd_vref = 124 # HBA client VREF register (v10) +c_hba_cmd_speed = 127 # HBA client SPEED register (old) +#c_hba_cmd_speed = 125 # HBA client SPEED register (v10) +c_hba_cmd_version = 126 # HBA client VERSION register +c_hba_reg_request_sz = 38 # register size in octets +c_hba_reg_response_sz = 4 +c_hba_reg_led_sz = 1 +c_hba_reg_vref_sz = 1 +c_hba_reg_speed_sz = 1 +c_hba_reg_version_sz = 1 + +c_hba_f_set_byte = 2 # HBA server function codes +c_hba_f_get_byte = 3 +c_hba_f_set_word = 4 +c_hba_f_get_word = 5 +c_hba_bc_server = 0 # HBA server broadcast address +c_hba_sreg_xdelay = 0 # HBA server xdelay register address +c_hba_sreg_ydelay = 1 # HBA server ydelay register address +c_hba_sreg_version = 254 # HBA server version register address +c_hba_sreg_address = 255 # HBA server address register address + +# - Modem time (modem speed = 40 = 10 kbps, modem prescaler = 1): +# . Broadcast request: 38 msec seems minimum for set_word broadcast 16 servers +# . Unicast request : 11 msec seems minimum for set_word or get word +# - For modem prescaler = 2 the uc_wait = 20 just works at modem speed = 40 = 5.5 kbps, +# hence to be safe double the wait times. +# - Use hba_gap_wait as minimal wait after every I2C access to the client, before issueing a new I2C access +hba_prescaler = 1 +hba_prescaler = 2 +hba_bc_wait = 40*hba_prescaler # used with PROTOCOL_C_WAIT and WG_WAIT +hba_uc_wait = 16*hba_prescaler # used with PROTOCOL_C_WAIT and WG_WAIT +hba_gap_wait = 2 # used with PROTOCOL_C_WAIT and WG_WAIT +hba_bc_i2c = 40 # used with WG_WAIT, I2C signalling time +30 is enough at 200 M +hba_uc_i2c = 25 # used with WG_WAIT, I2C signalling time +20 is enough at 200 M +hba_reg_i2c = 5 # used with WG_WAIT, I2C signalling time +4 is enough at 50 kbps and 327 us comma per byte, + # so addr, cmd, 4 bytes = 6 bytes * 9 = 54 bits @ 50 kbps = 1.1 ms, 6 bytes * 327 us = 1.9 ms + +c_hba_vref_default = 0xEC # Reference default mid level setting +c_hba_speed_default = 40 + +# TDS timing distribution clock board +c_tds_clksel_10MHz_sma = 1 +c_tds_clksel_10MHz_infini = 1 * (not c_tds_clksel_10MHz_sma) +c_tds_clksel_160MHz = 0 +c_tds_clksel_200MHz = 1 * (not c_tds_clksel_160MHz) +c_tds_clksel_pps_sma = 0 +c_tds_clksel_pps_infini = 1 * (not c_tds_clksel_pps_sma) + +################################################################################ +# Other constants (not from constants.tcl) +c_eth_block = 1400 + +c_sens2v5 = 2.5/192 +c_sens3v3 = 3.3/192 +c_sens5v = 5.0/192 +c_sens12v = 12.0/192 + +################################################################################ +# Functions + +def rspctl(tc, arg, applev=22): + cmd = 'rspctl %s' % arg + if tc != None: + tc.appendLog(applev,cmd) # 22: show command line + res = cli.command(cmd) + tc.appendLog(applev+1,res) # 23: show command return + return res + else: + return cli.command(cmd) + + +def i2bb(s): + """ Convert list of integers into list of byte-bytes + Input: + - s = list of integers + Return: + - ret = list of two bytes, LSByte first per pair + """ + ret = [] + for i in s: + ret.extend([i%256, (i/256)%256]) + return ret + + +def i2bbbb(s): + """ Convert list of integers into list of byte-byte-byte-bytes + Input: + - s = list of integers + Return: + - ret = list of four bytes, LSByte first per four + """ + ret = [] + for i in s: + ret.extend([i%256, (i/256)%256, (i/(256*256))%256, (i/(256*256*256))%256]) + return ret + + +def calculate_next_sequence_value(in_word, seq='PRSG', width=12): + """ Calculate next sequence value for PRSG or COUNTER + + Input: + - in_word = seed + - seq = PRSG : use PRSG sequence as in RCU (width=12) + others : use COUNTER sequence + Return: + - out_word = next sequence value after in_word + """ + if seq=='PRSG': + # Polynome + w = 2**width-1 + taps = [0, 3, 5, 11] + + # Feedback shift register + p = 0 + for t in taps: + b = 2**t + b = 1 * (not (not (in_word & b))) + p = p ^ b + out_word = ((in_word << 1) & w) + 1 * (not p) + else: + w = 2**width - 1 + out_word = (in_word + 1) & w + return out_word + + +def reorder(data, index): + """Reorder the data list according to the indices in the index list + + Input: + - data = Input data list + - index = List with reorder indices + Return: + Reordered data list + """ + nof = len(data) + redata = nof * [0] + for i in range(nof): + redata[index[i]] = data[i] + return redata + + +def write_mem(tc, msg, pid, regid, data, blpId=['blp0'], rspId=['rsp0'], width=2, offset=0, bc=1): + """Write data to memory register + + Input: + - tc = Testcase + - msg = MepMessage + - pid = Process ID string + - regid = Register ID string + - data = List of words to write + - blpId = List of ['blp#'] + - rspId = List of ['rsp#'] + - width = Nof bytes per data word + - offset = Offset in nof bytes + - bc = When !=0 use MEP broadcast + Return: void + """ + msg.packAddr(blpId, pid, regid) + msg.packPayload(data,width) + nof = width * len(data) # nof octets + for ri in rspId: + i = 0 + n = c_eth_block + while i < nof: + if nof - i < n: + n = nof - i + hexData = msg.getPayload(i, n) + if bc == 0: + # Individual accesses to BLPs on an RSP board + for bi in blpId: + msg.packAddr([bi], pid, regid) + rspctl(tc, '--writeblock=%s,%s,%d,%s' % (ri[3:], msg.hexAddr, offset+i, hexData)) + else: + # Make use of MEP broadcast to BLPs on an RSP board + rspctl(tc, '--writeblock=%s,%s,%d,%s' % (ri[3:], msg.hexAddr, offset+i, hexData)) + i = i + n + + +def read_mem(tc, msg, pid, regid, nof, blpId=['blp0'], rspId=['rsp0'], sign='+', width=2, offset=0): + """Read data from memory register + + Input: + - tc = Testcase + - msg = MepMessage + - pid = Process ID string + - regid = Register ID string + - nof = Nof bytes to read from the memory + - blpId = List of one ['blp#'] + - rspId = List of one ['rsp#'] + - width = Nof bytes per data word + - sign = 'h' for hex string, '+' for unsigned word list, '-' for signed word list + - offset = Offset in nof bytes + Return: + - list of read words + """ + msg.packAddr(blpId, pid, regid) + msg.clearPayload() + i = 0 + n = c_eth_block + while i < nof: + if nof - i < n: + n = nof - i + msg.extractPayload(rspctl(tc, '--readblock=%s,%s,%d,%d' % (rspId[0][3:], msg.hexAddr, offset+i, n)), True) + i = i + n + if sign == 'h': + return None # use access via msg.hexPayload + else: + return msg.unpackPayload(width, sign) + + +def write_cr_syncoff(tc, msg, blpId=['blp0'], rspId=['rsp0']): + """CR disable external sync + + Input: + - tc = Testcase + - msg = MepMessage + - blpId = List of 'rsp, blp#' + - rspId = List of 'rsp#' + Return: void + """ + for ri in rspId: + msg.packAddr(blpId, 'cr', 'syncoff') + msg.packPayload([1],1) + rspctl(tc, '--writeblock=%s,%s,0,%s' % (ri[3:], msg.hexAddr, msg.hexPayload)) + + +def write_cr_syncon(tc, msg, blpId=['blp0'], rspId=['rsp0']): + """CR enable external sync + + Input: + - tc = Testcase + - msg = MepMessage + - blpId = List of 'rsp, blp#' + - rspId = List of 'rsp#' + Return: void + """ + for ri in rspId: + msg.packAddr(blpId, 'cr', 'syncoff') + msg.packPayload([0],1) + rspctl(tc, '--writeblock=%s,%s,0,%s' % (ri[3:], msg.hexAddr, msg.hexPayload)) + + +def write_cr_sync_delay(tc, msg, syncdelay=0, syncedge=0, blpId=['blp0'], rspId=['rsp0']): + """CR write external sync input delay + + Input: + - tc = Testcase + - msg = MepMessage + - syncdelay = 0 is reset input delay to hardware default, > 0 increment input delay one time + - syncedge = 0 is capture ext_sync on rising edge, != 0 is on falling edge + - blpId = List of 'rsp, blp#' + - rspId = List of 'rsp#' + Return: void + """ + bit0 = syncdelay > 0 + bit1 = syncedge > 0 + syncdata = (bit1 << 1) + bit0 + for ri in rspId: + msg.packAddr(blpId, 'cr', 'syncdelay') + msg.packPayload([syncdata],1) + rspctl(tc, '--writeblock=%s,%s,0,%s' % (ri[3:], msg.hexAddr, msg.hexPayload)) + + +def read_cr_sync_delay(tc, msg, blpId=['blp0'], rspId=['rsp0'], applev=21): + """CR read sync delay bit + + Input: + - tc = Testcase + - msg = MepMessage + - blpId = List of one 'rsp, blp#' + - rspId = List of one 'rsp#' + - applev = Append logging level + Return: + - syncdata = External sync data + . bit 0 : '0' is default input delay, '1' is incremented delay + . bit 1 : '0' capture external sync on rising edge, '1' on falling edge + + tc appendlog messages are reported. + """ + syncdata = -1 + msg.packAddr(blpId, 'cr', 'syncdelay') + readData = rspctl(tc, '--readblock=%s,%s,0,1' % (rspId[0][3:], msg.hexAddr)) + msg.extractPayload(readData) + syncdata = msg.unpackPayload(1, '+') + syncdata = syncdata[0] + bit0 = syncdata & 1 + bit1 = (syncdata & 2) >> 1 + if bit0==0 and bit1==0: + tc.appendLog(applev, '>>> RSP-%s, BLP-%-8s, read CR sync: default input delay, default capture on rising edge' % (rspId, blpId)) + elif bit0==0 and bit1!=0: + tc.appendLog(applev, '>>> RSP-%s, BLP-%-8s, read CR sync: default input delay, capture on falling edge' % (rspId, blpId)) + elif bit0!=0 and bit1==0: + tc.appendLog(applev, '>>> RSP-%s, BLP-%-8s, read CR sync: incremented input delay, default capture on rising edge' % (rspId, blpId)) + else: + tc.appendLog(applev, '>>> RSP-%s, BLP-%-8s, read CR sync: incremented input delay, capture on falling edge' % (rspId, blpId)) + return syncdata + + +def write_diag_bypass(tc, msg, bypass, blpId=['blp0'], rspId=['rsp0'], applev=21): + """Write DIAG bypass register + + Input: + - tc = Testcase + - msg = MepMessage + - bypass = Bypass enable word + - blpId = List of ['blp#'] + - rspId = List of ['rsp#'] + - applev = Append logging level + Return: void + """ + tc.appendLog(applev, '>>> RSP-%s, BLP-%s, write DIAG bypass:' % (rspId, blpId)) + tc.appendLog(applev, ' bit(0) : Bypass DC = %d' % ((bypass & 1 ) > 0)) + tc.appendLog(applev, ' bit(1) : Bypass PFS = %d' % ((bypass & (1<<1)) > 0)) + tc.appendLog(applev, ' bit(2) : Bypass PFT = %d' % ((bypass & (1<<2)) > 0)) + tc.appendLog(applev, ' bit(3) : Bypass BF = %d' % ((bypass & (1<<3)) > 0)) + tc.appendLog(applev, ' bit(4) : SI enable X = %d' % ((bypass & (1<<4)) > 0)) + tc.appendLog(applev, ' bit(5) : SI enable Y = %d' % ((bypass & (1<<5)) > 0)) + tc.appendLog(applev, ' bit(6) : DIAG result buffer use sync = %d' % ((bypass & (1<<6)) > 0)) + tc.appendLog(applev, ' bit(7) : DIAG result buffer use resync = %d' % ((bypass & (1<<7)) > 0)) + tc.appendLog(applev, ' bit(8) : PFT switching disable = %d' % ((bypass & (1<<8)) > 0)) + + for ri in rspId: + msg.packAddr(blpId, 'diag', 'bypass') + msg.packPayload([bypass],2) + rspctl(tc, '--writeblock=%s,%s,0,%s' % (ri[3:], msg.hexAddr, msg.hexPayload)) + + +def read_diag_bypass(tc, msg, blpId=['blp0'], rspId=['rsp0'], applev=21): + """Read DIAG bypass register + + Input: + - tc = Testcase + - msg = MepMessage + - blpId = List of one 'blp#' + - rspId = List of one 'rsp#' + - applev = Append logging level + Return: + - bypass = Bypass bits + """ + msg.packAddr(blpId, 'diag', 'bypass') + readData = rspctl(tc, '--readblock=%s,%s,0,2' % (rspId[0][3:], msg.hexAddr)) + msg.extractPayload(readData) + bypass = msg.unpackPayload(2, '+') + bypass = bypass[0] + + tc.appendLog(applev, '>>> RSP-%s, BLP-%s, read DIAG bypass:' % (rspId, blpId)) + tc.appendLog(applev, ' bit(0) : Bypass DC = %d' % ((bypass & 1 ) > 0)) + tc.appendLog(applev, ' bit(1) : Bypass PFS = %d' % ((bypass & (1<<1)) > 0)) + tc.appendLog(applev, ' bit(2) : Bypass PFT = %d' % ((bypass & (1<<2)) > 0)) + tc.appendLog(applev, ' bit(3) : Bypass BF = %d' % ((bypass & (1<<3)) > 0)) + tc.appendLog(applev, ' bit(4) : SI enable X = %d' % ((bypass & (1<<4)) > 0)) + tc.appendLog(applev, ' bit(5) : SI enable Y = %d' % ((bypass & (1<<5)) > 0)) + tc.appendLog(applev, ' bit(6) : DIAG result buffer use sync = %d' % ((bypass & (1<<6)) > 0)) + tc.appendLog(applev, ' bit(7) : DIAG result buffer use resync = %d' % ((bypass & (1<<7)) > 0)) + tc.appendLog(applev, ' bit(8) : PFT switching disable = %d' % ((bypass & (1<<8)) > 0)) + return bypass + + +def write_diag_selftest(tc, msg, selftest, blpId=['rsp'], rspId=['rsp0'], applev=21): + """Write DIAG selftest register + + Input: + - tc = Testcase + - msg = MepMessage + - selftest = Selftest list: [interface, mode, duration, line] + - blpId = List of ['rsp', 'blp#'] + - rspId = List of ['rsp#'] + - applev = Append logging level + Return: void + """ + tc.appendLog(applev, '>>> RSP-%s write DIAG selftest:' % rspId) + tc.appendLog(applev, ' interface = %d' % selftest[0]) + tc.appendLog(applev, ' mode = %d' % selftest[1]) + tc.appendLog(applev, ' duration = %d' % selftest[2]) + tc.appendLog(applev, ' line = %d' % selftest[3]) + + for ri in rspId: + msg.packAddr(blpId, 'diag', 'selftest') + msg.packPayload(selftest,1) + rspctl(tc, '--writeblock=%s,%s,0,%s' % (ri[3:], msg.hexAddr, msg.hexPayload)) + + +def read_diag_result_buffer(tc, msg, nof, width, blpId=['blp0'], rspId=['rsp0']): + """Read DIAG result buffer + + Input: + - tc = Testcase + - msg = MepMessage + - nof = Nof words to read from the result buffer + - width = Word width of the result buffer samples, 1, 2, or 4 + - blpId = List of one 'blp#' + - rspId = List of one 'rsp#' + Return: + - Read result buffer words + """ + return read_mem(tc, msg, 'diag', 'result', width*nof, blpId, rspId, '-', width) + + +def write_rsu_altsync(tc, msg, rspId=['rsp0']): + """RSU apply altsync + + Input: + - tc = Testcase + - msg = MepMessage + - rspId = List of 'rsp#' + Return: void + """ + for ri in rspId: + msg.packAddr(['rsp'], 'rsu', 'sysctrl') + msg.packPayload([1],1) + rspctl(tc, '--writeblock=%s,%s,0,%s' % (ri[3:], msg.hexAddr, msg.hexPayload)) + + +def write_rd_smbh_protocol_list(tc, msg, smbh, protocol_list, polId=['x', 'y'], blpId=['blp0'], rspId=['rsp0']): + """Write and readback protocol list to SMBus handler in RSP. The list will take effect at next sync. + + Input: + - tc = Testcase + - msg = MepMessage + - smbh = SMBus handler: 'tdsh' or 'rcuh' + - protocol_list = Protocol list + - polId = Polarization ID: x, y or 'x y' for RCUH, ignored for TDSH + - blpId = BLP ID: 'blp#' for RCUH, destination defaults to 'rsp' for TDSH + - rspId = RSP ID: 'rsp#' + Report: + tc.appendlog messages are reported. + tc.setResult is set + Return: void + """ + # - Write the protocol list to the SMBH + smbus.write_protocol_list(tc, msg, smbh, protocol_list, polId, blpId, rspId) + + # - Read back the protocol list to verify that this is possible + for ri in rspId: + if smbh == 'tdsh': + rb_protocol_list = smbus.readback_protocol_list(tc, msg, smbh, len(protocol_list), None, None, [ri]) + if protocol_list == rb_protocol_list: + tc.appendLog(21, '>>> RSP-%s, TDSH : The protocol list READBACK went OK' % ri) + else: + tc.appendLog(11, '>>> RSP-%s, TDSH : The protocol list READBACK went wrong:' % ri) + tc.appendLog(11, 'Expected protocol list: %s' % protocol_list) + tc.appendLog(11, 'Readback protocol list: %s' % rb_protocol_list) + tc.setResult('FAILED') + elif smbh == 'rcuh': + for bi in blpId: + for pi in polId: + rb_protocol_list = smbus.readback_protocol_list(tc, msg, smbh, len(protocol_list), pi, [bi], [ri]) + if protocol_list == rb_protocol_list: + tc.appendLog(21, '>>> RSP-%s, BLP-%s, RCUH-%s: The protocol list READBACK went OK' % (ri, bi, pi)) + else: + tc.appendLog(11, '>>> RSP-%s, BLP-%s, RCUH-%s: The protocol list READBACK went wrong:' % (ri, bi, pi)) + tc.appendLog(11, 'Expected protocol list: %s' % protocol_list) + tc.appendLog(11, 'Readback protocol list: %s' % rb_protocol_list) + tc.setResult('FAILED') + + +def overwrite_rd_smbh_protocol_results(tc, msg, smbh, polId=['x', 'y'], blpId=['blp0'], rspId=['rsp0']): + """Overwrite and read protocol result of SMBus handler in RSP. + + Input: + - tc = Testcase + - msg = MepMessage + - smbh = SMBus handler: 'tdsh' or 'rcuh' + - polId = Polarization ID: x, y or 'x y' for RCUH, ignored for TDSH + - blpId = BLP ID: 'blp#' for RCUH, destination defaults to 'rsp' for TDSH + - rspId = RSP ID: 'rsp#' + Report: + tc appendlog messages are reported. + tc setResult is set + Return: void + """ + if smbh == 'rcuh': + nof_result_bytes = 2**c_rcuh_result_adr_w + if smbh == 'tdsh': + nof_result_bytes = 2**c_tdsh_result_adr_w + + # - Overwrite first entries of protocol result register to be sure that the results will be fresh + wr_result = [] + for i in range(nof_result_bytes): + wr_result.append(17) # Just some number not equal to 0, 1, 255 and < 256 + + # - Overwrite + smbus.overwrite_results(tc, msg, smbh, wr_result, polId, blpId, rspId) + + # - Readback to verify overwrite + for ri in rspId: + if smbh == 'tdsh': + rd_result = smbus.read_results(tc, msg, smbh, nof_result_bytes, None, None, [ri]) + if wr_result == rd_result: + tc.appendLog(21, '>>> RSP-%s, TDSH : The protocol results OVERWRITE and read went OK' % ri) + else: + tc.appendLog(11, '>>> RSP-%s, TDSH : The protocol results OVERWRITE and read went wrong:' % ri) + tc.appendLog(11, 'Expected protocol result: %s' % wr_result) + tc.appendLog(11, 'Readback protocol result: %s' % rd_result) + tc.setResult('FAILED') + elif smbh == 'rcuh': + for bi in blpId: + for pi in polId: + rd_result = smbus.read_results(tc, msg, smbh, nof_result_bytes, pi, [bi], [ri]) + if wr_result == rd_result: + tc.appendLog(21, '>>> RSP-%s, BLP-%s, RCUH-%s: The protocol results OVERWRITE and read went OK' % (ri, bi, pi)) + else: + tc.appendLog(11, '>>> RSP-%s, BLP-%s, RCUH-%s: The protocol results OVERWRITE and read went wrong:' % (ri, bi, pi)) + tc.appendLog(11, 'Expected protocol result: %s' % wr_result) + tc.appendLog(11, 'Readback protocol result: %s' % rd_result) + tc.setResult('FAILED') + + +def overwrite_rsr(tc, msg, procid='all', value=255, rspId=['rsp0']): + """Overwrite the selected process fields of the RSP status register + + Input: + - tc = Testcase + - msg = MepMessage + - procid = Process ID : 'rsp', 'eth', 'mep', 'diag', 'bs', 'rcuh', 'rsu', 'ado', 'rad' or 'all' + - value = Byte value to use for overwrite + - rspId = List of 'rsp#' + Return: void + """ + if procid == 'rsp' : offset = c_ei_status_rsp_offset; size = c_ei_status_rsp_size + elif procid == 'eth' : offset = c_ei_status_eth_offset; size = c_ei_status_eth_size + elif procid == 'mep' : offset = c_ei_status_mep_offset; size = c_ei_status_mep_size + elif procid == 'diag': offset = c_ei_status_diag_offset; size = c_ei_status_diag_size + elif procid == 'bs' : offset = c_ei_status_bs_offset; size = c_nof_blp *c_ei_status_bs_size + elif procid == 'rcuh': offset = c_ei_status_rcuh_offset; size = c_nof_blp *c_ei_status_rcuh_size + elif procid == 'rsu' : offset = c_ei_status_rsu_offset; size = c_ei_status_rsu_size + elif procid == 'ado' : offset = c_ei_status_ado_offset; size = c_nof_blp *c_ei_status_ado_size + elif procid == 'rad' : offset = c_ei_status_rad_offset; size = c_rad_nof_rx *c_ei_status_rad_size + else: offset = c_ei_status_rsr_offset; size = c_ei_status_rsr_size + + status = [] + for i in range(size): + status.append(value) + + for ri in rspId: + write_mem(tc, msg, 'rsr', 'status', status, ['rsp'], [ri], 1, offset) + + +def read_rsr(tc, msg, procid='all', rspId=['rsp0'], applev=21): + """Read the selected process fields from the RSP status register + + Input: + - tc = Testcase + - msg = MepMessage + - procid = Process ID : 'rsp', 'eth', 'mep', 'diag', 'bs', 'rcuh', 'rsu', 'ado', 'rad' or 'all' + - rspId = List of 'rsp#' + - applev = Append log level + Return: + - ret = List of read process status fields, list structure: [[first RSP], ..., [last RSP]], + where the data structure per RSP depends on the procid. + - retb = Boolean telling wither the status is OK or ERROR + """ + ret_rsp = [] # Declare return result + + # Read all RSR fields + for ri in rspId: + ret = [] + retb = [] + + read_mem(tc, msg, 'rsr', 'status', c_ei_status_rsr_size, ['rsp'], [ri], 'h', 1, c_ei_status_rsr_offset) + + msg.setOffset(c_ei_status_rsr_offset) + # RSP status + rsp_volt_1v2 = msg.readUnsigned(1) + rsp_volt_2v5 = msg.readUnsigned(1) + rsp_volt_3v3 = msg.readUnsigned(1) + rsp_pcb_temp = msg.readSigned(1) + rsp_bp_temp = msg.readSigned(1) + rsp_ap0_temp = msg.readSigned(1) + rsp_ap1_temp = msg.readSigned(1) + rsp_ap2_temp = msg.readSigned(1) + rsp_ap3_temp = msg.readSigned(1) + rsp_clk = msg.readUnsigned(1) + rsp_rsvd = msg.readUnsigned(2) + # ETH status + eth_nof_frames = msg.readUnsigned(4) + eth_nof_errors = msg.readUnsigned(4) + eth_last_error = msg.readUnsigned(1) + eth_rsvd = msg.readUnsigned(3) + # MEP status + mep_seq_nr = msg.readUnsigned(2) + mep_prev_error = msg.readUnsigned(1) + mep_rsvd = msg.readUnsigned(1) + # DIAG status + diag_interface = msg.readUnsigned(1) + diag_mode = msg.readUnsigned(1) + diag_ri_errors = {} + diag_ri_errors['rsp'] = msg.readUnsigned(2) + diag_rcux_errors = msg.readUnsigned(2) + diag_rcuy_errors = msg.readUnsigned(2) + diag_eth_errors = {} + diag_eth_errors['LCU'] = msg.readUnsigned(2) + diag_eth_errors['CEP'] = msg.readUnsigned(2) + diag_serdes_errors = msg.readUnsigned(2) + diag_ri_errors['0'] = msg.readUnsigned(2) + diag_ri_errors['1'] = msg.readUnsigned(2) + diag_ri_errors['2'] = msg.readUnsigned(2) + diag_ri_errors['3'] = msg.readUnsigned(2) + diag_rsvd = msg.readUnsigned(2) + # BS status + bs_ext_cnt = {} + bs_sync_cnt = {} + bs_sample_cnt = {} + bs_slice_cnt = {} + for bi in range(c_nof_blp): + bs_ext_cnt[bi] = msg.readUnsigned(4) + bs_sync_cnt[bi] = msg.readUnsigned(4) + bs_sample_cnt[bi] = msg.readUnsigned(4) + bs_slice_cnt[bi] = msg.readUnsigned(4) + # RCU status + rcu_status = {} + rcu_nof_ovr_x = {} + rcu_nof_ovr_y = {} + for bi in range(c_nof_blp): + rcu_status[bi] = msg.readUnsigned(4) + rcu_nof_ovr_x[bi] = msg.readUnsigned(4) + rcu_nof_ovr_y[bi] = msg.readUnsigned(4) + # RSU status + rsu_cp_status = msg.readUnsigned(4) + # ADO status + ado_x = {} + ado_y = {} + for bi in range(c_nof_blp): + ado_x[bi] = msg.readSigned(4) + ado_y[bi] = msg.readSigned(4) + # RAD BP status + rad_ri = msg.readUnsigned(4) + rad_lane = {} + for la in range(c_nof_lanes): + rad_lane[la,'crosslets'] = msg.readUnsigned(4) + rad_lane[la,'beamlets'] = msg.readUnsigned(4) + + # Report RSR fields indicated by procid + tc.appendLog(applev, '') + tc.appendLog(applev, '>>> RSR read outs for RSP-%s.' % ri) + tc.appendLog(applev, '') + + if procid == 'rsp' or procid == 'all': + tc.appendLog(applev, 'RSP board status:') + tc.appendLog(applev, '') + tc.appendLog(applev, ' supply 1.2V = %6.3f V (= %3d * %5.3f)' % (rsp_volt_1v2 * c_sens2v5, rsp_volt_1v2, c_sens2v5)) + tc.appendLog(applev, ' supply 2.5V = %6.3f V (= %3d * %5.3f)' % (rsp_volt_2v5 * c_sens3v3, rsp_volt_2v5, c_sens3v3)) + tc.appendLog(applev, ' supply 3.3V = %6.3f V (= %3d * %5.3f)' % (rsp_volt_3v3 * c_sens5v, rsp_volt_3v3, c_sens5v)) + tc.appendLog(applev, '') + tc.appendLog(applev, ' temp PCB = %4d degrees C' % rsp_pcb_temp) + tc.appendLog(applev, '') + tc.appendLog(applev, ' temp BP = %4d degrees C' % rsp_bp_temp) + tc.appendLog(applev, ' temp AP0 = %4d degrees C' % rsp_ap0_temp) + tc.appendLog(applev, ' temp AP1 = %4d degrees C' % rsp_ap1_temp) + tc.appendLog(applev, ' temp AP2 = %4d degrees C' % rsp_ap2_temp) + tc.appendLog(applev, ' temp AP3 = %4d degrees C' % rsp_ap3_temp) + tc.appendLog(applev, '') + tc.appendLog(applev, ' clk rate = %4d MHz' % rsp_clk) + tc.appendLog(applev, '') + ret.append([rsp_volt_1v2, rsp_volt_2v5, rsp_volt_3v3, rsp_pcb_temp, rsp_bp_temp, rsp_ap0_temp, rsp_ap1_temp, rsp_ap2_temp, rsp_ap3_temp, rsp_clk]) + + if procid == 'eth' or procid == 'all': + tc.appendLog(applev, 'Ethernet status:') + tc.appendLog(applev, '') + tc.appendLog(applev, ' Number of frames = %d' % eth_nof_frames) + tc.appendLog(applev, ' Number of errors = %d' % eth_nof_errors) + if eth_last_error == c_ei_eth_err_noerr : tc.appendLog(applev, ' Last error = OK') + elif eth_last_error == c_ei_eth_err_preamblevalue : tc.appendLog(applev, ' Last error = Preamble value error') + elif eth_last_error == c_ei_eth_err_framedelimiter : tc.appendLog(applev, ' Last error = Frame delimiter error') + elif eth_last_error == c_ei_eth_err_preamblelength : tc.appendLog(applev, ' Last error = Preamble length error') + elif eth_last_error == c_ei_eth_err_headerlength : tc.appendLog(applev, ' Last error = Frame header lenght error') + elif eth_last_error == c_ei_eth_err_crc : tc.appendLog(applev, ' Last error = CRC error') + elif eth_last_error == c_ei_eth_err_oddnibblelength: tc.appendLog(applev, ' Last error = Odd nof nibbles error') + elif eth_last_error == c_ei_eth_err_framelength : tc.appendLog(applev, ' Last error = Frame size error') + else: tc.appendLog(applev, ' Last error = Illegal error code: %d' % eth_last_error) + tc.appendLog(applev, '') + ret.append([eth_nof_frames, eth_nof_errors, eth_last_error]) + if procid == 'mep' or procid == 'all': + tc.appendLog(applev, 'MEP status:') + tc.appendLog(applev, '') + tc.appendLog(applev, ' Sequence number = %d' % mep_seq_nr) + if mep_prev_error == c_ei_mep_err_noerr : tc.appendLog(applev, ' Error status previous msg = OK') + elif mep_prev_error == c_ei_mep_err_type : tc.appendLog(applev, ' Error status previous msg = Unknown message type') + elif mep_prev_error == c_ei_mep_err_addr_blp: tc.appendLog(applev, ' Error status previous msg = Illegal BLP address') + elif mep_prev_error == c_ei_mep_err_pid : tc.appendLog(applev, ' Error status previous msg = Invalid PID') + elif mep_prev_error == c_ei_mep_err_regid : tc.appendLog(applev, ' Error status previous msg = Register does not exist') + elif mep_prev_error == c_ei_mep_err_offset : tc.appendLog(applev, ' Error status previous msg = Offset too large') + elif mep_prev_error == c_ei_mep_err_size : tc.appendLog(applev, ' Error status previous msg = Message too large') + elif mep_prev_error == c_ei_mep_err_ringcrc : tc.appendLog(applev, ' Error status previous msg = Ring CRC error') + elif mep_prev_error == c_ei_mep_err_timeout : tc.appendLog(applev, ' Error status previous msg = Timeout') + else: tc.appendLog(applev, ' Error status previous msg = Illegal error code: %d' % mep_prev_error) + tc.appendLog(applev, '') + ret.append([mep_seq_nr, mep_prev_error]) + if procid == 'diag' or procid == 'all': + tc.appendLog(applev, 'DIAG status:') + tc.appendLog(applev, '') + tc.appendLog(applev, ' Interface = %d' % diag_interface) + tc.appendLog(applev, ' Mode = %d' % diag_mode) + # - BP RI + if diag_ri_errors['rsp'] == c_diag_res_ok: + tc.appendLog(applev, ' Test result RI-BP = OK') + elif diag_ri_errors['rsp'] == c_diag_res_none: + tc.appendLog(applev, ' Test result RI-BP = Nothing happened') + elif diag_ri_errors['rsp'] == c_diag_res_sync_timeout: + tc.appendLog(applev, ' Test result RI-BP = Sync timeout') + elif diag_ri_errors['rsp'] == c_diag_res_data_timeout: + tc.appendLog(applev, ' Test result RI-BP = Data timeout') + elif diag_ri_errors['rsp'] == c_diag_res_word_err: + tc.appendLog(applev, ' Test result RI-BP = Data errors occured') + else: + tc.appendLog(applev, ' Test result RI-BP = Unknown status %d' % diag_ri_errors['rsp']) + tc.appendLog(applev, ' Test result RCU-X = %d' % diag_rcux_errors) + tc.appendLog(applev, ' Test result RCU-Y = %d' % diag_rcuy_errors) + # - ETH + eth_interfaces = ['LCU', 'CEP'] + for ei in eth_interfaces: + if diag_eth_errors[ei] == c_diag_res_ok: + tc.appendLog(applev, ' Test result %s = OK' % ei) + elif diag_eth_errors[ei] == c_diag_res_none: + tc.appendLog(applev, ' Test result %s = Nothing happened' % ei) + elif diag_eth_errors[ei] == c_diag_res_data_timeout: + tc.appendLog(applev, ' Test result %s = Data timeout (= frame lost)' % ei) + elif diag_eth_errors[ei] == c_diag_res_word_err: + tc.appendLog(applev, ' Test result %s = Word errors occured' % ei) + else: + tc.appendLog(applev, ' Test result %s = Unknown status %d' % (ei, diag_eth_errors[ei])) + # - SERDES lanes + lane_mask = 2**c_nof_lanes-1 + lane_ref = 2**c_nof_lanes + for i in range(c_nof_lanes): + lane_errors = (diag_serdes_errors >> (i*c_nof_lanes)) & lane_mask + if lane_errors == c_diag_res_ok: + tc.appendLog(applev, ' Test result SERDES lane %d = OK' % i) + elif lane_errors == c_diag_res_none: + tc.appendLog(applev, ' Test result SERDES lane %d = nothing happened' % i) + elif lane_errors == c_diag_res_sync_timeout: + tc.appendLog(applev, ' Test result SERDES lane %d = sync timeout' % i) + elif lane_errors == c_diag_res_data_timeout: + tc.appendLog(applev, ' Test result SERDES lane %d = data timeout' % i) + elif lane_errors == c_diag_res_word_err: + tc.appendLog(applev, ' Test result SERDES lane %d = word errors occured' % i) + elif lane_errors == c_diag_res_illegal: + tc.appendLog(applev, ' Test result SERDES lane %d = illegal status %d' % (i, lane_errors)) + else: + tc.appendLog(applev, ' Test result SERDES lane %d = unknown status %d' % (i, lane_errors)) + # - APs RI + for ai in ['0','1','2','3']: + if diag_ri_errors[ai] == c_diag_res_ok: + tc.appendLog(applev, ' Test result RI-AP%s = OK' % ai) + elif diag_ri_errors[ai] == c_diag_res_none: + tc.appendLog(applev, ' Test result RI-AP%s = Nothing happened.' % ai) + elif diag_ri_errors[ai] == c_diag_res_sync_timeout: + tc.appendLog(applev, ' Test result RI-AP%s = Sync timeout.' % ai) + elif diag_ri_errors[ai] == c_diag_res_data_timeout: + tc.appendLog(applev, ' Test result RI-AP%s = Data timeout.' % ai) + elif diag_ri_errors[ai] == c_diag_res_word_err: + tc.appendLog(applev, ' Test result RI-AP%s = Data errors occured.' % ai) + else: + tc.appendLog(applev, ' Test result RI-AP%s = Unknown status %d.' % (ai, diag_ri_errors[ai])) + tc.appendLog(applev, '') + ret.append([diag_interface, diag_mode, diag_ri_errors['rsp'], diag_rcux_errors, diag_rcuy_errors, diag_eth_errors['LCU'], diag_eth_errors['CEP'], diag_serdes_errors, diag_ri_errors['0'], diag_ri_errors['1'], diag_ri_errors['2'], diag_ri_errors['3']]) + if procid == 'bs' or procid == 'all': + tc.appendLog(applev, 'BS status:') + tc.appendLog(applev, '') + for bi in range(c_nof_blp): + st = 'BLP-%s: ' % bi + st += 'Ext_cnt = %u, ' % bs_ext_cnt[bi] + st += 'Sync_cnt = %u, ' % bs_sync_cnt[bi] + st += 'Sample_cnt = %u, ' % bs_sample_cnt[bi] + st += 'Slice_cnt = %u.' % bs_slice_cnt[bi] + tc.appendLog(applev, ' %s' % st) + ret.append([bs_ext_cnt[bi], bs_sync_cnt[bi], bs_sample_cnt[bi], bs_slice_cnt[bi]]) + tc.appendLog(applev, '') + if procid == 'rcuh' or procid == 'all': + tc.appendLog(applev, 'RCU status:') + tc.appendLog(applev, '') + for bi in range(c_nof_blp): + st = 'BLP-%s: ' % bi + st += 'status = %u, ' % rcu_status[bi] + st += 'nof_ovr_x = %u, ' % rcu_nof_ovr_x[bi] + st += 'nof_ovr_y = %u.' % rcu_nof_ovr_y[bi] + tc.appendLog(applev, ' %s' % st) + ret.append([rcu_status[bi], rcu_nof_ovr_x[bi], rcu_nof_ovr_y[bi]]) + tc.appendLog(applev, '') + if procid == 'rsu' or procid == 'all': + tc.appendLog(applev, 'RSU status:') + tc.appendLog(applev, '') + tc.appendLog(applev, ' CP status = %d' % rsu_cp_status) + tc.appendLog(applev, '') + if ((rsu_cp_status >> c_cp_statusRdy) & 0x1) == 1: + tc.appendLog(applev, ' [%d] statusRdy = 1 : CP is done' % c_cp_statusRdy) + else: + tc.appendLog(applev, ' [%d] statusRdy = 0 : CP is in some intermediate state' % c_cp_statusRdy) + if ((rsu_cp_status >> c_cp_statusFpgaType) & 0x1) == c_cp_bp: + tc.appendLog(applev, ' [%d] statusFpgaType = %d : Image was loaded via JTAG' % (c_cp_statusFpgaType, c_cp_bp)) + else: + tc.appendLog(applev, ' [%d] statusFpgaType = %d : Image was loaded from flash' % (c_cp_statusFpgaType, 1 * (not c_cp_bp))) + if ((rsu_cp_status >> c_cp_statusImageType) & 0x1) == 0: + tc.appendLog(applev, ' [%d] statusImageType = 0 : Factory image is running' % c_cp_statusImageType) + else: + tc.appendLog(applev, ' [%d] statusImageType = 1 : User image is running' % c_cp_statusImageType) + if ((rsu_cp_status >> c_cp_statusTrigLo) & c_cp_trig_mask) == c_cp_trig_ButtonRst: + tc.appendLog(applev, ' [%d:%d] statusTrig = %d : Reconfiguration due to button reset' % (c_cp_statusTrigHi, c_cp_statusTrigLo, c_cp_trig_ButtonRst)) + elif ((rsu_cp_status >> c_cp_statusTrigLo) & c_cp_trig_mask) == c_cp_trig_TempRst: + tc.appendLog(applev, ' [%d:%d] statusTrig = %d : Reconfiguration due to over temperature' % (c_cp_statusTrigHi, c_cp_statusTrigLo, c_cp_trig_TempRst)) + elif ((rsu_cp_status >> c_cp_statusTrigLo) & c_cp_trig_mask) == c_cp_trig_UserRst: + tc.appendLog(applev, ' [%d:%d] statusTrig = %d : Reconfiguration due to user reset' % (c_cp_statusTrigHi, c_cp_statusTrigLo, c_cp_trig_UserRst)) + elif ((rsu_cp_status >> c_cp_statusTrigLo) & c_cp_trig_mask) == c_cp_trig_WdRst: + tc.appendLog(applev, ' [%d:%d] statusTrig = %d : Reconfiguration due to watchdog reset' % (c_cp_statusTrigHi, c_cp_statusTrigLo, c_cp_trig_WdRst)) + else: + tc.appendLog(applev, ' [%d:%d] statusTrig = %d : Unknown reconfiguration trigger' % (c_cp_statusTrigHi, c_cp_statusTrigLo, (rsu_cp_status >> c_cp_statusTrigLo) & c_cp_trig_mask)) + cp_version = (((rsu_cp_status >> c_cp_statusVersion1) & 0x1) << 1) + ((rsu_cp_status >> c_cp_statusVersion0) & 0x1) + tc.appendLog(applev, ' [%d,%d] statusVersion = %d : CP version number' % (c_cp_statusVersion1, c_cp_statusVersion0, cp_version)) + tc.appendLog(applev, '') + ret.append([rsu_cp_status]) + elif procid == 'ado' or procid == 'all': + tc.appendLog(applev, 'ADC offset:') + tc.appendLog(applev, '') + for bi in range(c_nof_blp): + nof_samples_psync = bs_slice_cnt[bi] * c_slice_size + st = 'BLP-%s, RCU-X ADC offset = ' % bi + if nof_samples_psync != 0: + st += '%11.7f lsb ' % (1.0 * ado_x[bi] * c_ado_scale / nof_samples_psync) + else: + st += '-----------' + st += '(%10d * %u / %11.0f)' % (ado_x[bi], c_ado_scale, nof_samples_psync) + tc.appendLog(applev, ' %s' % st) + + st = 'BLP-%s, RCU-Y ADC offset = ' % bi + if nof_samples_psync != 0: + st += '%11.7f lsb ' % (1.0 * ado_y[bi] * c_ado_scale / nof_samples_psync) + else: + st += '-----------' + st += '(%10d * %u / %11.0f)' % (ado_y[bi], c_ado_scale, nof_samples_psync) + tc.appendLog(applev, ' %s' % st) + + ret.append([ado_x[bi], ado_y[bi]]) + tc.appendLog(applev, '') + if procid == 'rad' or procid == 'all': + tc.appendLog(applev, 'RAD BP frame rx status:') + tc.appendLog(applev, '') + tc.appendLog(applev, ' Align Sync CRC Frame cnt') + retb = c_rsr_undefined # default undefined + st = 'RI : ' + cnt = rad_ri & ((1<<18)-1) + if cnt==0: + st += '- - - ' + else: + # when rad is busy there is always input from RI, from lane only in case of multiple RSP + retb = c_rsr_ok + st += '- ' # not applicable for RI + if (rad_ri & (1<<19))!=0: st += 'OK ' + else: st += 'Error '; retb = c_rsr_error # sync error(s) + if (rad_ri & (1<<18))==0: st += 'OK ' + else: st += 'Error '; retb = c_rsr_error # CRC error(s) + st += '%u' % cnt + tc.appendLog(applev, ' %s' % st) + ret.append(rad_ri) + for la in range(c_nof_lanes): + for let in ['crosslets', 'beamlets']: + st = 'Lane-%d, %-9s: ' % (la, let) + cnt = rad_lane[la, let] & ((1<<18)-1) + if cnt==0: + st += '- - - ' + else: + # input from lane can keep retb as set by input from RI, or cause retb to indicate error + if (rad_lane[la, let] & (1<<20))==0: st += 'OK ' + else: st += 'Error '; retb = c_rsr_error # frame(s) discarded + if (rad_lane[la, let] & (1<<19))!=0: st += 'OK ' + else: st += 'Error '; retb = c_rsr_error # sync error(s) + if (rad_lane[la, let] & (1<<18))==0: st += 'OK ' + else: st += 'Error '; retb = c_rsr_error # CRC error(s) + st += '%u' % cnt + tc.appendLog(applev, ' %s' % st) + ret.append(rad_lane[la, let]) + tc.appendLog(applev, '') + ret = [retb, ret] + ret_rsp.append(ret) + return ret_rsp + + +def write_rad_settings(tc, msg, settings, rspId=['rsp0'], applev=21): + """RAD_BP write settings + + Input: + - tc = Testcase + - msg = MepMessage + - settings = Lane settings for beamlets and crosslets + - rspId = List of 'rsp#' + - applev = Append log level + Report: + tc appendlog messages are reported (see read_rad_settings for lane mode definition). + Return: void + """ + tc.appendLog(applev, '>>> RSP-%s write RAD settings (= 0x%X):' % (rspId, settings)) + # beamlet lane modes + for i in range(c_nof_lanes): + lane_mode = (settings >> (8*i)) & 0x3 + if lane_mode==0: tc.appendLog(applev, ' lane(%d): beamlet mode local' % i) + elif lane_mode==1: tc.appendLog(applev, ' lane(%d): beamlet mode disable' % i) + elif lane_mode==2: tc.appendLog(applev, ' lane(%d): beamlet mode combine' % i) + else: tc.appendLog(applev, ' lane(%d): beamlet mode remote' % i) + # crosslet lane modes + for i in range(c_nof_lanes): + lane_mode = (settings >> (8*i + 2)) & 0x3 + if lane_mode==0: tc.appendLog(applev, ' lane(%d): crosslet mode local' % i) + elif lane_mode==1: tc.appendLog(applev, ' lane(%d): crosslet mode disable' % i) + elif lane_mode==2: tc.appendLog(applev, ' lane(%d): crosslet mode combine' % i) + else: tc.appendLog(applev, ' lane(%d): crosslet mode remote' % i) + for ri in rspId: + msg.packAddr(['rsp'], 'rad', 'settings') + msg.packPayload([settings],4) + rspctl(tc, '--writeblock=%s,%s,0,%s' % (ri[3:], msg.hexAddr, msg.hexPayload)) + + +def read_rad_settings(tc, msg, rspId=['rsp0'], applev=21): + """RAD_BP read settings + Input: + - tc = Testcase + - msg = MepMessage + - rspId = List of one 'rsp#' + - applev = Append log level + Report: + tc appendlog messages are reported. + Return: + - settings = Lane settings for beamlets and crosslets + lane mode: one byte for each lane + format: XXXXAABB + where XX = don't care + AA = xlet mode + BB = blet mode + mode 00 = ignore remote data (only local) DEFAULT + mode 01 = disable + mode 10 = combine local and remote data + mode 11 = ignore local data (only remote) + """ + msg.packAddr(['rsp'], 'rad', 'settings') + readData = rspctl(tc, '--readblock=%s,%s,0,4' % (rspId[0][3:], msg.hexAddr)) + msg.extractPayload(readData) + settings = msg.unpackPayload(4, '+') + settings = settings[0] + tc.appendLog(applev, '>>> RSP-%s read RAD settings (= 0x%X):' % (rspId, settings)) + # beamlet lane modes + for i in range(c_nof_lanes): + lane_mode = (settings >> (8*i)) & 0x3 + if lane_mode==0: tc.appendLog(applev, ' lane(%d): beamlet mode local' % i) + elif lane_mode==1: tc.appendLog(applev, ' lane(%d): beamlet mode disable' % i) + elif lane_mode==2: tc.appendLog(applev, ' lane(%d): beamlet mode combine' % i) + else: tc.appendLog(applev, ' lane(%d): beamlet mode remote' % i) + # crosslet lane modes + for i in range(c_nof_lanes): + lane_mode = (settings >> (8*i + 2)) & 0x3 + if lane_mode==0: tc.appendLog(applev, ' lane(%d): crosslet mode local' % i) + elif lane_mode==1: tc.appendLog(applev, ' lane(%d): crosslet mode disable' % i) + elif lane_mode==2: tc.appendLog(applev, ' lane(%d): crosslet mode combine' % i) + else: tc.appendLog(applev, ' lane(%d): crosslet mode remote' % i) + return settings + + +def read_rad_latency(tc, msg, rspId=['rsp0'], applev=21): + """RAD_BP read latency + + Input: + - tc = Testcase + - msg = MepMessage + - rspId = List of 'rsp#' + - applev = Append log level + Report: + tc appendlog messages are reported. + Return: + - latency = RI and lane latencies crosslets and beamlets + """ + latency = [] + nof_rd = 2*c_rad_nof_rx + + title_str = '>>> ' + title_str += 'Ri' + for i in range(c_nof_lanes-1,-1,-1): + title_str += ' X%d' % i + for i in range(c_nof_lanes-1,-1,-1): + title_str += ' B%d' % i + tc.appendLog(applev, title_str) + + for ri in rspId: + lat = [] + read_mem(tc, msg, 'rad', 'latency', nof_rd, ['rsp'], [ri], 'h', 1, 0) + + msg.setOffset(0) + lane = {} + for i in range(c_nof_lanes): + lane[i,'b'] = msg.readUnsigned(2) + lane[i,'x'] = msg.readUnsigned(2) + ring = msg.readUnsigned(2) + + lat_str = 'RSP-%s' % ri + lat_str += '%6d' % ring + lat.append(ring) + for i in range(c_nof_lanes-1,-1,-1): + lat_str += '%6d' % lane[i,'x'] + lat.append(lane[i,'x']) + for i in range(c_nof_lanes-1,-1,-1): + lat_str += '%6d' % lane[i,'b'] + lat.append(lane[i,'b']) + tc.appendLog(applev, lat_str) + latency.append(lat) + return latency + + +def write_ss(tc, msg, ss_map, blpId=['blp0'], rspId=['rsp0']): + """Write subband to beamlet mapping to SS register + + Input: + - tc = Testcase + - msg = MepMessage + - ss_map = List of words for subband to beamlet mapping + - blpId = List of 'blp#' + - rspId = List of 'rsp#' + Return: void + """ + write_mem(tc, msg, 'ss', 'settings', ss_map, blpId, rspId, 2) + + +def read_ss(tc, msg, nof, blpId=['blp0'], rspId=['rsp0']): + """Read subband to beamlet mapping from SS register + + Input: + - tc = Testcase + - msg = MepMessage + - nof = Nof words to read from the SS register + - blpId = List of one 'blp#' + - rspId = List of one 'rsp#' + Return: + - Read SS register words + """ + width = 2 + return read_mem(tc, msg, 'ss', 'settings', width*nof, blpId, rspId, '+', width) + + +################################################################################ +# Try some functions on the python command line +if __name__ == "__main__": + import sys + sys.argv[1:] # list of input arguments diff --git a/StationTest/modules/smbus.py b/StationTest/modules/smbus.py new file mode 100644 index 00000000000..d73e8825f3f --- /dev/null +++ b/StationTest/modules/smbus.py @@ -0,0 +1,281 @@ +"""SMBus (I2C) access constants and functions (translated from RSP smbus.tcl) + + Constants for I2C peripherals + + - c_max6652 voltage temperature sensor + - c_pca9555 I/O expander + + Procedures for accessing the SMBus (I2C) interface + + - set_protocol + - write_protocol_list + - readback_protocol_list + - read_results + - overwrite_results +""" + +################################################################################ +# System imports + +# User imports +import rsp + +############################################################################### +# - MAX6652 voltage temperature sensor constants + +c_max6652_addr_gnd = 0x14 # I2C slave address +c_max6652_addr_vcc = 0x15 +c_max6652_addr_sda = 0x16 +c_max6652_addr_scl = 0x17 + +c_max6652_cmd_read_2v5 = 0x20 # Commands +c_max6652_cmd_read_12v = 0x21 +c_max6652_cmd_read_3v3 = 0x22 +c_max6652_cmd_read_vcc = 0x23 +c_max6652_cmd_read_temp = 0x27 +c_max6652_cmd_config = 0x40 + +c_max6652_config_start = 0x01 # Configuration bits +c_max6652_config_int_en = 0x02 +c_max6652_config_int_clr = 0x08 +c_max6652_config_line_freq_sel = 0x10 +c_max6652_config_short_cycle = 0x20 +c_max6652_config_reset = 0x80 + +c_max6652_unit_12v = 12.0/192 # Unit in V +c_max6652_unit_vcc = 5.0/192 +c_max6652_unit_3v3 = 3.3/192 +c_max6652_unit_2v5 = 2.5/192 +c_max6652_unit_temp = 1.0 # Unit in degree C + + +############################################################################### +# - PCA9555 I/O expander constants + +c_pca9555_base_addr = 0x20 +c_pca9555_addr_000 = c_pca9555_base_addr + 0 # A2 A1 A0 +c_pca9555_addr_001 = c_pca9555_base_addr + 1 +c_pca9555_addr_010 = c_pca9555_base_addr + 2 +c_pca9555_addr_011 = c_pca9555_base_addr + 3 +c_pca9555_addr_100 = c_pca9555_base_addr + 4 +c_pca9555_addr_101 = c_pca9555_base_addr + 5 +c_pca9555_addr_110 = c_pca9555_base_addr + 6 +c_pca9555_addr_111 = c_pca9555_base_addr + 7 + +c_pca9555_cmd_input_0 = 0 +c_pca9555_cmd_input_1 = 1 +c_pca9555_cmd_output_0 = 2 +c_pca9555_cmd_output_1 = 3 +c_pca9555_cmd_invert_0 = 4 +c_pca9555_cmd_invert_1 = 5 +c_pca9555_cmd_config_0 = 6 +c_pca9555_cmd_config_1 = 7 + + +############################################################################### +# - SMBus functions + +def set_protocol(tc, protocol_id, cnt=1, addr=1, data='', cmd='', cmd2='', appLev=1): + """Returns filled in protocol message + + See i2c_smbus(pkg).vhd for more detailed comments on the SMBus protocol definitions. + + Input: + - tc = Testcase + - protocol_id = Protocol ID: STRING + - cnt = Number of data bytes, or timeout value: INTEGER + - addr = I2C slave address: BYTE + - data = I2C write data: list of BYTE + - cmd = I2C slave command (register) + - cmd2 = I2C slave command (register) 2 + + Return: + - msg = Protocol request message + """ + + def error_len(data, le): + ret = 0 + if len(data)!=le: + print 'Wrong SMBus protocol data length, must be %d bytes.' % le + ret = 1 + return ret + + # SMBUS protocol identifiers conform i2c_smbus(pkg).vhd + PROTOCOL_ARRAY = {'PROTOCOL_WRITE_QUICK' :2, + 'PROTOCOL_READ_QUICK' :3, + 'PROTOCOL_SEND_BYTE' :4, + 'PROTOCOL_RECEIVE_BYTE' :5, + 'PROTOCOL_WRITE_BYTE' :6, + 'PROTOCOL_READ_BYTE' :7, + 'PROTOCOL_WRITE_WORD' :8, + 'PROTOCOL_READ_WORD' :9, + 'PROTOCOL_WRITE_BLOCK' :10, + 'PROTOCOL_READ_BLOCK' :11, + 'PROTOCOL_PROCESS_CALL' :12, + 'PROTOCOL_C_WRITE_BLOCK_NO_CNT' :13, + 'PROTOCOL_C_READ_BLOCK_NO_CNT' :14, + 'PROTOCOL_C_SEND_BLOCK' :15, + 'PROTOCOL_C_RECEIVE_BLOCK' :16, + 'PROTOCOL_C_NOP' :17, + 'PROTOCOL_C_WAIT' :18, + 'PROTOCOL_C_END' :19, + 'PROTOCOL_C_UNKNOWN' :20} # To test unknown protocol + + # First message field + msg = [] + msg.append(PROTOCOL_ARRAY[protocol_id]) + + # Additional message fields: + if protocol_id == 'PROTOCOL_WRITE_QUICK': msg.append(addr) + elif protocol_id == 'PROTOCOL_READ_QUICK': msg.append(addr) + elif protocol_id == 'PROTOCOL_SEND_BYTE': + msg.append(addr) + msg.extend(data) + if error_len(data,1)!=0: msg = -1 + elif protocol_id == 'PROTOCOL_RECEIVE_BYTE': msg.append(addr) + elif protocol_id == 'PROTOCOL_WRITE_BYTE': + msg.append(addr) + msg.append(cmd) + msg.extend(data) + if error_len(data,1)!=0: msg = -1 + elif protocol_id == 'PROTOCOL_READ_BYTE': msg.append(addr); msg.append(cmd) + elif protocol_id == 'PROTOCOL_WRITE_WORD': + msg.append(addr) + msg.append(cmd) + msg.extend(data) + if error_len(data,2)!=0: msg = -1 + elif protocol_id == 'PROTOCOL_READ_WORD': msg.append(addr); msg.append(cmd) + elif protocol_id == 'PROTOCOL_WRITE_BLOCK': msg.append(addr); msg.append(cmd); msg.append(cnt); msg.extend(data) + elif protocol_id == 'PROTOCOL_READ_BLOCK': msg.append(addr); msg.append(cmd); msg.append(cnt) + elif protocol_id == 'PROTOCOL_PROCESS_CALL': + msg.append(addr) + msg.append(cmd) + msg.extend(data) + if error_len(data,2)!=0: msg = -1 + msg.append(addr); msg.append(cmd2) + elif protocol_id == 'PROTOCOL_C_WRITE_BLOCK_NO_CNT': msg.append(addr); msg.append(cmd); msg.append(cnt); msg.extend(data) + elif protocol_id == 'PROTOCOL_C_READ_BLOCK_NO_CNT': msg.append(addr); msg.append(cmd); msg.append(cnt) + elif protocol_id == 'PROTOCOL_C_SEND_BLOCK': msg.append(addr); msg.append(cnt); msg.extend(data) + elif protocol_id == 'PROTOCOL_C_RECEIVE_BLOCK': msg.append(addr); msg.append(cnt) + elif protocol_id == 'PROTOCOL_C_NOP': None + elif protocol_id == 'PROTOCOL_C_WAIT': msg.extend(rsp.i2bbbb([cnt])) + elif protocol_id == 'PROTOCOL_C_END': None + else: tc.appendLog(appLev, 'Unknown SMBus protocol.') + + return msg + + +def test_protocols(tc): + """Procedure used to verify set_protocol in a Python shell + """ + print set_protocol(tc, 'PROTOCOL_WRITE_QUICK', None, 1, None, None, None) + print set_protocol(tc, 'PROTOCOL_READ_QUICK', None, 1, None, None, None) + print set_protocol(tc, 'PROTOCOL_SEND_BYTE', None, 1, [5], None, None) + print set_protocol(tc, 'PROTOCOL_RECEIVE_BYTE', None, 1, None, None, None) + print set_protocol(tc, 'PROTOCOL_WRITE_BYTE', None, 1, [5], 17, None) + print set_protocol(tc, 'PROTOCOL_READ_BYTE', None, 1, None, 17, None) + print set_protocol(tc, 'PROTOCOL_WRITE_WORD', None, 1, [5, 6], 17, None) + print set_protocol(tc, 'PROTOCOL_READ_WORD', None, 1, None, 17, None) + print set_protocol(tc, 'PROTOCOL_WRITE_BLOCK', 3, 1, [9, 9, 9], 17, None) + print set_protocol(tc, 'PROTOCOL_READ_BLOCK', 3, 1, None, 17, None) + print set_protocol(tc, 'PROTOCOL_PROCESS_CALL', None, 1, [5, 6], 17, 18) + print set_protocol(tc, 'PROTOCOL_C_WRITE_BLOCK_NO_CNT', 3, 1, [9, 9, 9], 17, None) + print set_protocol(tc, 'PROTOCOL_C_READ_BLOCK_NO_CNT', 3, 1, None, 17, None) + print set_protocol(tc, 'PROTOCOL_C_SEND_BLOCK', 3, 1, [9, 9, 9], None, None) + print set_protocol(tc, 'PROTOCOL_C_RECEIVE_BLOCK', 3, 1, None, None, None) + print set_protocol(tc, 'PROTOCOL_C_NOP', None, 1, None, None, None) + print set_protocol(tc, 'PROTOCOL_C_WAIT', 1333, 1, None, None, None) + print set_protocol(tc, 'PROTOCOL_C_END', None, 1, None, None, None) + set_protocol( tc, 'PROTOCOL_C_UNKNOWN', None, 1, None, None, None) + + +def write_protocol_list(tc, msg, smbh, protocol_list, polId=['x', 'y'], blpId=['blp0'], rspId=['rsp0']): + """Write SMBus protocol list to SMBus handler + + Input: + - tc = Testcase + - msg = MepMessage + - smbh = I2C device handler: 'rcuh' or 'tdsh' + - protocol_list = Protocol list: bytes + - polId = Polarization: 'x' or 'y' for RCUH, ignored for TDSH + - blpId = BLP ID: 'blp#' for RCUH, destination defaults to 'rsp' for TDSH + - rspId = RSP ID: 'rsp#' + + Return: void + """ + width = 1 # protocol_list is in bytes + offset = 0 # access from address 0 + bc = 1 # allow BLP broadcast + if smbh == 'tdsh': + rsp.write_mem(tc, msg, smbh, 'protocol', protocol_list, ['rsp'], rspId, width, offset, bc) + if smbh == 'rcuh': + for pi in polId: + rsp.write_mem(tc, msg, smbh, 'protocol'+pi, protocol_list, blpId, rspId, width, offset, bc) + + +def readback_protocol_list(tc, msg, smbh, le, polId='x', blpId=['blp0'], rspId=['rsp0']): + """Read back SMBus protocol list from SMBus handler + + Input: + - tc = Testcase + - msg = MepMessage + - smbh = I2C device handler: 'rcuh' or 'tdsh' + - le = Number of bytes to read from the protocol list buffer, INTEGER + - polId = Polarization ID: 'x' or 'y' for RCUH, ignored for TDSH - only one + - blpId = BLP ID: 'blp#' for RCUH, destination defaults to 'rsp' for TDSH - only one + - rspId = RSP ID: 'rsp#' - only one + + Return: Read protocol list bytes + """ + width = 1 # protocol_list is in bytes + offset = 0 # access from address 0 + if smbh == 'tdsh': + return rsp.read_mem(tc, msg, smbh, 'protocol', width * le, ['rsp'], rspId, '+', width, offset) + if smbh == 'rcuh': + return rsp.read_mem(tc, msg, smbh, 'protocol'+polId, width * le, blpId, rspId, '+', width, offset) + + +def read_results (tc, msg, smbh, le, polId='x', blpId=['blp0'], rspId=['rsp0']): + """Read the results of the SMBus protocol list from the SMBus handler + + Input: + - tc = Testcase + - msg = MepMessage + - smbh = I2C device handler: 'rcuh' or 'tdsh' + - le = Number of bytes to read from the protocol result buffer, INTEGER + - polId = Polarization ID: 'x' or 'y' for RCUH, ignored for TDSH - only one + - blpId = BLP ID: 'blp#' for RCUH, destination defaults to 'rsp' for TDSH - only one + - rspId = RSP ID: 'rsp#' - only one + + Return: = Read result data + """ + width = 1 # protocol_list is in bytes + offset = 0 # access from address 0 + if smbh == 'tdsh': + return rsp.read_mem(tc, msg, smbh, 'result', width * le, ['rsp'], rspId, '+', width, offset) + if smbh == 'rcuh': + return rsp.read_mem(tc, msg, smbh, 'result'+polId, width * le, blpId, rspId, '+', width, offset) + + +def overwrite_results (tc, msg, smbh, wr_result, polId=['x', 'y'], blpId=['blp0'], rspId=['rsp0']): + """Write SMBus results to SMBus handler + + Input: + - tc = Testcase + - msg = MepMessage + - smbh = I2C device handler: 'rcuh' or 'tdsh' + - wr_result = Overwrite results: bytes + - polId = Polarization: 'x' or 'y' for RCUH, ignored for TDSH + - blpId = BLP ID: 'blp#' for RCUH, destination defaults to 'rsp' for TDSH + - rspId = RSP ID: 'rsp#' + + Return: void + """ + width = 1 # result is in bytes + offset = 0 # access from address 0 + bc = 1 # allow BLP broadcast + if smbh == 'tdsh': + rsp.write_mem(tc, msg, smbh, 'result', wr_result, ['rsp'], rspId, width, offset, bc) + if smbh == 'rcuh': + for pi in polId: + rsp.write_mem(tc, msg, smbh, 'result'+pi, wr_result, blpId, rspId, width, offset, bc) diff --git a/StationTest/modules/testcase.py b/StationTest/modules/testcase.py new file mode 100644 index 00000000000..1463e231162 --- /dev/null +++ b/StationTest/modules/testcase.py @@ -0,0 +1,72 @@ +"""Testcase utilities +""" + +################################################################################ +# System imports +import time + +################################################################################ +# Functions + +class Testcase: + + def __init__(self, verbosity=11, testName='empty.py', repeat=1, + rspId=['rsp0'], bpId='rsp', blpId='blp0', + tbbId=None, tpId=None, mpId=None, + polId=['x','y']): + self.startTime = time.time() + self.verbosity = verbosity + self.testName = testName + self.repeat = repeat + self.rspId = rspId + self.bpId = bpId + self.blpId = blpId + self.tbbId = tbbId + self.tpId = tpId + self.mpId = mpId + self.polId = polId + if testName != None: + self.logName = testName[0:-3] + '.log' + self.logFile = open(self.logName,'w') + self.result = 'RUNONLY' + + def setResult(self, res): # Use this method rather than direct access to result + if res in ['RUNONLY', 'PASSED', 'FAILED']: # Ignore illegal res + if self.result != 'FAILED': # Once FAILED the result can not be changed + self.result=res + + def getResult(self): # Method alterative to than direct access to result + return self.result + + def appendLog(self, level, string, nolevel=0, notime=0): + txt = 'Tc %s - ' % self.testName[0:-3] + if notime == 0: + t = time.localtime() + txt = txt + '[%d:%02d:%02d %02d:%02d:%02d]' % (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec) + if nolevel == 0: + txt = txt + ' - (%02d) ' % level + txt = txt + string + + if level <= self.verbosity: + print txt + self.logFile.write(txt + '\n') + + def appendFile(self, level, fileName): + try: + appFile = open(fileName,'r') + self.appendLog(level,appFile.read(),1,1,1) + appFile.close() + except IOError: + self.appendLog(level,'ERROR : Can not open file %s' % fileName) + + def sleep(self, ms): + time.sleep(ms/1000.0) + + def setStartTime(self): + self.startTime = time.time() + + def getRunTime(self): + return int(time.time() - self.startTime) + + def closeLog(self): + self.logFile.close() diff --git a/StationTest/modules/testlog.py b/StationTest/modules/testlog.py new file mode 100644 index 00000000000..d31e7b62940 --- /dev/null +++ b/StationTest/modules/testlog.py @@ -0,0 +1,69 @@ +"""Test logging utilities +""" + +################################################################################ +# System imports +import time + +################################################################################ +# Functions + +class Testlog: + + def __init__(self, verbosity=11, testId=None, logName='empty.dat'): + self.startTime = time.time() + self.verbosity = verbosity + self.testId = testId + self.logName = logName + if logName != None: + try: + self.logFile = open(self.logName,'w') + except IOError: + print 'ERROR : Can not open log file %s' % logName + self.result = 'RUNONLY' + + def setId(self, txt): # Use this method rather than direct access to testId + self.testId=txt + + def setResult(self, res): # Use this method rather than direct access to result + if res in ['RUNONLY', 'PASSED', 'FAILED']: # Ignore illegal res + if self.result != 'FAILED': # Once FAILED the result can not be changed + self.result=res + + def getResult(self): # Method alternative for direct access to result + return self.result + + def appendLog(self, level, string, notime=0, nolevel=0, noId=0): + txt = '' + if notime == 0: + t = time.localtime() + txt = txt + '[%d:%02d:%02d %02d:%02d:%02d]' % (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec) + if nolevel == 0: + txt = txt + ' - (%02d) ' % level + if noId == 0: + txt = txt + self.testId + txt = txt + string + + if level <= self.verbosity: + print txt + self.logFile.write(txt + '\n') + + def appendFile(self, level, fileName): + try: + appFile = open(fileName,'r') + self.appendLog(level,appFile.read(),1,1,1) + appFile.close() + except IOError: + self.appendLog(level,'ERROR : Can not open file %s' % fileName) + + def sleep(self, ms): + time.sleep(ms/1000.0) + + def setStartTime(self): + self.startTime = time.time() + + def getRunTime(self): + return int(time.time() - self.startTime) + + def closeLog(self): + self.logFile.close() diff --git a/StationTest/prbs_dir_test.py b/StationTest/prbs_dir_test.py new file mode 100644 index 00000000000..83709022e53 --- /dev/null +++ b/StationTest/prbs_dir_test.py @@ -0,0 +1,114 @@ + +""" script for testing PRBS data in dir. +Gijs, 16 dec 07 +""" +# INIT + +import array +import operator +import os +import time +import commands + +# Open file for processing +def open_dir() : + files = os.listdir('./prbs/.') + files.sort() +# print files + return files + +def open_file(files, file_nr) : + file_name = './prbs/' + files[file_nr][:] + if files[file_nr][-3:] == 'dat': + fileinfo = os.stat(file_name) + size = int(fileinfo.st_size) + f=open(file_name,'rb') + max_frames = size/(88 + 1024*2 + 4) + frames_to_proces=max_frames + else : + frames_to_proces=0 + f=open(file_name,'rb') + return f, frames_to_proces + + +# Read single frame from file +def read_frame(f, info_plot, frame_nr,f_log): + station_info = array.array('B') + station_info.fromfile(f,4) # Bytes 0..3 + time_info = array.array('L') + time_info.fromfile(f,3) # Bytes 4..15 + if (info_plot) : + time_string = time.ctime(time_info[1]) +# string_info = 'Frame nr %(FR)d Station %(ST)d RSP %(RSP)d RCU %(RCU)d Sample rate %(S)d MHz time of data %(ti_D)s and %(SN)00.6f seconds'%\ +# {"FR": frame_nr, "ST": station_info[0] ,"RSP": station_info[1], "RCU": station_info[2], "S": station_info[3], "ti_D": time_string,"SN": float(time_info[2])/float(200000000)} + string_info = 'Frame nr %(FR)d Station %(ST)d RSP %(RSP)d RCU %(RCU)d Sample rate %(S)d MHz'%\ + {"FR": frame_nr, "ST": station_info[0] ,"RSP": station_info[1], "RCU": station_info[2], "S": station_info[3]} +# print string_info + f_log.write(string_info + '\n') + div_info = array.array('H') + div_info.fromfile(f,36) # Bytes 16..87 + + # READ DATA SAMPLES + data_in = array.array('H') + samples = int(div_info[0]) + data_in.fromfile(f,samples) + data_list = data_in.tolist() + + data_crc = array.array('l') + data_crc.fromfile(f,1) + return data_list, time_info[1], time_info[2] + + +# Function for testing PRBS data +def PRBS_CHECK(data_list, prev): + samples_chk=0 + prbs_err=0 + for i in range(0,len(data_list)) : + if prev == 0x0FFF : + prev = data_list[i] & 0x07FF + elif data_list[i] == 0xFFFF : + prbs_err = prbs_err + 1 + else : + cur = data_list[i] & 0x0FFE + samples_chk = samples_chk + 1 + if cur != 2*prev : + prbs_err = prbs_err + 1 +# print(str(i) + ' ' + hex(2*prev) + ' ' + hex(cur)) + prev = data_list[i] & 0x07FF + return samples_chk, prbs_err, prev + + +# Main loop +def main() : + files = open_dir() + f_log = file('prbs_dir_test.log', 'w') + f_log.write('\n \n PRSB test \n \n') + for file_cnt in range(len(files)) : + prev = 0x0FFF; + samples_chk=0 + prbs_err=0 + o_ta=0 + o_tb=0 + (f, frames_to_proces) = open_file(files, file_cnt) + if frames_to_proces >0 : + for frame_cnt in range(frames_to_proces): + data_list, ta, tb = read_frame(f, (frame_cnt==0), frame_cnt, f_log) + if (((ta==o_ta) and tb==(o_tb+1024)) or (ta == (o_ta+1))) : +# if (tb==(o_tb+1)) : + prev = prev + else: + prev=0x0FFF + r_samples_chk, r_prbs_err, prev = PRBS_CHECK(data_list, prev) + samples_chk = samples_chk + r_samples_chk + prbs_err = prbs_err + r_prbs_err + o_ta = ta + o_tb = tb + # plot results +# print 'Samples checked : ' + str(samples_chk) + ' PRBS errors: ' + str(prbs_err) + f_log.write('Samples checked : ' + str(samples_chk) + ' PRBS errors: ' + str(prbs_err) + '\n') + + f.close + f_log.close + +if __name__ == "__main__": + main() diff --git a/StationTest/prbs_test.py b/StationTest/prbs_test.py new file mode 100644 index 00000000000..5dea30abe24 --- /dev/null +++ b/StationTest/prbs_test.py @@ -0,0 +1,103 @@ + +""" script for testing PRBS data in dir. +Gijs, 16 dec 07 +""" +# INIT + +import array +import operator +import os +import time + +# Open file for processing +def open_dir() : +# os.chdir('c:/test') + files = os.listdir('.') + return files + +def open_file(files, file_nr) : + if files[file_nr][-3:] == 'dat': + fileinfo = os.stat(files[file_nr]) + size = int(fileinfo.st_size) + f=open(files[file_nr],'rb') + max_frames = size/(88 + 1024*2 + 4) + frames_to_proces=max_frames + else : + frames_to_proces=0 + f=open(files[file_nr],'rb') + return f, frames_to_proces + + + + +# Read single frame from file +def read_frame(f, info_plot, frame_nr,f_log): + station_info = array.array('B') + station_info.fromfile(f,4) # Bytes 0..3 + time_info = array.array('L') + time_info.fromfile(f,3) # Bytes 4..15 + if (info_plot) : + time_string = time.ctime(time_info[1]) + string_info = 'Frame nr %(FR)d Station %(ST)d RSP %(RSP)d RCU %(RCU)d Sample rate %(S)d MHz time of data %(ti_D)s and %(SN)00.6f seconds'%\ + {"FR": frame_nr, "ST": station_info[0] ,"RSP": station_info[1], "RCU": station_info[2], "S": station_info[3], "ti_D": time_string,"SN": float(time_info[2])/float(200000000)} + print string_info + f_log.write(string_info + '\n') + div_info = array.array('H') + div_info.fromfile(f,36) # Bytes 16..87 + + # READ DATA SAMPLES + data_in = array.array('H') + samples = int(div_info[0]) + data_in.fromfile(f,samples) + data_list = data_in.tolist() + + data_crc = array.array('l') + data_crc.fromfile(f,1) + return data_list + + +# Function for testing PRBS data +def PRBS_CHECK(data_list, prev): + samples_chk=0 + prbs_err=0 + for i in range(0,len(data_list)) : + if prev == 0x0FFF : + prev = data_list[i] & 0x07FF + elif data_list[i] == 0xFFFF : + prbs_err = prbs_err + 1 + else : + cur = data_list[i] & 0x0FFE + samples_chk = samples_chk + 1 + if cur != 2*prev : + prbs_err = prbs_err + 1 +# print(str(i) + ' ' + hex(2*prev) + ' ' + hex(cur)) + prev = data_list[i] & 0x07FF + return samples_chk, prbs_err, prev + + +# Main loop +def main() : + files = open_dir() + f_log = file('prbs_test.log', 'a') + f_log.write('\n \n PRSB test \n \n') + for file_cnt in range(len(files)) : + prev = 0x0FFF; + samples_chk=0 + prbs_err=0 + f, frames_to_proces = open_file(files, file_cnt) + if frames_to_proces >1 : + for frame_cnt in range(frames_to_proces): + data_list = read_frame(f, (frame_cnt==0), frame_cnt, f_log) + # Test data + r_samples_chk, r_prbs_err, prev = PRBS_CHECK(data_list, prev) + samples_chk = samples_chk + r_samples_chk + prbs_err = prbs_err + r_prbs_err + + # plot results + print 'Samples checked : ' + str(samples_chk) + ' PRBS errors: ' + str(prbs_err) + f_log.write('Samples checked : ' + str(samples_chk) + ' PRBS errors: ' + str(prbs_err) + '\n') + + f.close + f_log.close + +main() diff --git a/StationTest/rmfiles.sh b/StationTest/rmfiles.sh new file mode 100644 index 00000000000..c80deb914e2 --- /dev/null +++ b/StationTest/rmfiles.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +rm -f tc/*.log +rm -f *.log +rm -f *.diff +rm -f *.nfo +rm -f *.dat diff --git a/StationTest/rsp_version.sh b/StationTest/rsp_version.sh new file mode 100644 index 00000000000..64d46a8b4cf --- /dev/null +++ b/StationTest/rsp_version.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# +# Get version info from the RSP boards and compare this with the expected golden result. +# + +rm -f *.log +rm -f *.diff +rspctl --version > rsp_version.log +diff rsp_version.log gold/rsp_version.gold > rsp_version.diff +if [ -e rsp_version.log ] && [ -e gold/rsp_version.gold ] && [ -e rsp_version.diff ] && ! [ -s rsp_version.diff ]; then + # The files exists AND the diff has size 0 + echo "RSP version test went OK" +else + echo "RSP version test went wrong" +fi diff --git a/StationTest/rsp_xc_160.sh b/StationTest/rsp_xc_160.sh new file mode 100644 index 00000000000..b6c6af8e664 --- /dev/null +++ b/StationTest/rsp_xc_160.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# +# Test the SERDES ring between the RSP by verifing the crosslet statistics. +# + +./xc_160_setup.sh + +sleep 2 + +./xc_160_verify.sh diff --git a/StationTest/rsp_xc_200.sh b/StationTest/rsp_xc_200.sh new file mode 100644 index 00000000000..b5afc5a52a6 --- /dev/null +++ b/StationTest/rsp_xc_200.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# +# Test the SERDES ring between the RSP by verifing the crosslet statistics. +# + +./xc_200_setup.sh + +sleep 2 + +./xc_200_verify.sh diff --git a/StationTest/station_production.py b/StationTest/station_production.py new file mode 100644 index 00000000000..69507897f3b --- /dev/null +++ b/StationTest/station_production.py @@ -0,0 +1,191 @@ +# +# Run the production tests for a LOFAR station +# + +import sys +from optparse import OptionParser + +import cli +import testlog + +################################################################################ +# Parse command line for subrack ID +# +# -v 0 : only PASSED or FAILED +# -v 1 : overall title +# -v 11 : result per test +# -v 21 : title per test + +op = OptionParser(usage='usage: python %prog [options]', version='%prog 0.1') + +op.add_option('-v', type='int', dest='verbosity', + help='Verbosity level',default=11) +op.add_option('-r', type='int', dest='rsp_nr', + help='Provide number of rsp boards that will be used in this test',default=None) +op.add_option('-t', type='int', dest='tbb_nr', + help='Provide number of tbb boards that will be used in this test',default=None) + +opts, args = op.parse_args() + +# - Option checks and/or reformatting +if opts.rsp_nr==None: + op.error('Option -r must specify the number of rsp boards') +if opts.tbb_nr==None: + op.error('Option -t must specify the number of tbb boards') + + +################################################################################ +# Define subrack testlog class for pass/fail and logging +vlev = opts.verbosity +testId = '' +appLev = False +logName = '/home/lofartest/subracktest/data/SUBR-%05d-%05d.dat' % (opts.rsp_nr, opts.tbb_nr) +cli.command('rm -f /home/lofartest/subracktest/data/SUBR-%05d-%05d.dat', appLev) +sr = testlog.Testlog(vlev, testId, logName) + +sr.setResult('PASSED') + +sr.setId('Station - ') +sr.appendLog(11,'') +sr.appendLog(1,'Station production test %s' % logName) +sr.appendLog(11,'') + + +################################################################################ +sr.setId('RSP version - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify LCU - RSP ethernet link by getting the RSP version info') +sr.appendLog(21,'') +res = cli.command('./rsp_version.sh') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> RSP version test went OK') +else: + sr.appendLog(11,'>>> RSP version test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'Result:') + sr.appendFile(11,'rsp_version.log') + sr.appendLog(11,'Expected:') + sr.appendFile(11,'gold/rsp_version.gold') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('TBB version - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify LCU - TBB ethernet link by getting the TBB version info') +sr.appendLog(21,'') +res = cli.command('./tbb_version.sh') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> TBB version test went OK') +else: + sr.appendLog(11,'>>> TBB version test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'Result:') + sr.appendFile(11,'tbb_version.log') + sr.appendLog(11,'Expected:') + sr.appendFile(11,'gold/tbb_version.gold') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('SPU status - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the RSP - SPU I2C interface by reading the SPU sensor data') +sr.appendLog(21,'') + +res = cli.command('python i2c_spu.py') +res = cli.command('python i2c_spu.py') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> RSP - SPU I2c interface test went OK') +else: + sr.appendLog(11,'>>> RSP - SPU I2c interface test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'Result:') + sr.appendFile(11,'spustat.log') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('TD status - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the RSP - TD I2C interface by reading the TD sensor data') +sr.appendLog(21,'') + +res = cli.command('python i2c_td.py') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> RSP - TD I2c interface test went OK') +else: + sr.appendLog(11,'>>> RSP - TD I2c interface test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'Result:') + sr.appendFile(11,'tdstat.log') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('RCU-RSP - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the RCU -> RSP LVDS interfaces by capturing pseudo random data on RSP') +sr.appendLog(21,'') + + +res = cli.command('python verify.py --brd rsp0,rsp1,rsp2,rsp3 --fpga blp0,blp1,blp2,blp3 --pol x,y --rep 1 -v 11 --te tc/prsg.py') + +if res.find('FAILED')==-1: + sr.appendLog(11,'>>> RCU-RSP interface test went OK') + sr.appendFile(21,'tc/prsg.log') +else: + sr.appendLog(11,'>>> RCU-RSP interface test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendFile(11,'tc/prsg.log') + sr.setResult('FAILED') + +################################################################################ +sr.setId('Serdes ring -') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the Serdes ring connection between the RSP boards') +sr.appendLog(21,'') + +res = cli.command('python verify.py --brd rsp0,rsp1,rsp2,rsp3,rsp4,rsp5,rsp6,rsp7,rsp8,rsp9,rsp10,rsp11 --rep 1 -v 21 --te tc/serdes.py') + +if res.find('FAILED')==-1: + sr.appendLog(11,'>>> Serdes ring test went OK') + sr.appendLog(21,'tc/serdes.log') +else: + sr.appendLog(11,'>>> Serdes ring test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'tc/serdes.log') + sr.appendLog('FAILED') + + + +################################################################################ +sr.setId('RCU-RSP-TBB - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the RCU - RSP - TBB LVDS interfaces by capturing pseudo random data on TBB') +sr.appendLog(21,'') + +res = cli.command('./tbb_prbs_tester.sh') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> RCU - RSP - TBB LVDS interfaces test went OK') +else: + sr.appendLog(11,'>>> RCU - RSP - TBB LVDS interfaces went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.setResult('FAILED') + + +################################################################################ +# End of the subrack test + +sr.setId('Subrack - ') +dt = sr.getRunTime() +sr.appendLog(2,'Duration: %02dm:%02ds' % (dt/60 % 60, dt % 60)) +sr.appendLog(0,sr.getResult()) +sr.closeLog() diff --git a/StationTest/subrack_production.py b/StationTest/subrack_production.py new file mode 100644 index 00000000000..a70b196447c --- /dev/null +++ b/StationTest/subrack_production.py @@ -0,0 +1,170 @@ +# +# Run the production tests for a LOFAR station subrack +# + +import sys +from optparse import OptionParser + +import cli +import testlog + +################################################################################ +# Parse command line for subrack ID +# +# -v 0 : only PASSED or FAILED +# -v 1 : overall title +# -v 11 : result per test +# -v 21 : title per test + +op = OptionParser(usage='usage: python %prog [options]', version='%prog 0.1') + +op.add_option('-v', type='int', dest='verbosity', + help='Verbosity level',default=11) +op.add_option('-b', type='int', dest='batch_nr', + help='Provide subrack batch number that will be used for the log file name',default=None) +op.add_option('-s', type='int', dest='serial_nr', + help='Provide subrack serial number that will be used for the log file name',default=None) + +opts, args = op.parse_args() + +# - Option checks and/or reformatting +if opts.batch_nr==None: + op.error('Option -b must specify a subrack batch number') +if opts.serial_nr==None: + op.error('Option -s must specify a subrack serial number') + + +################################################################################ +# Define subrack testlog class for pass/fail and logging +vlev = opts.verbosity +testId = '' +appLev = False +logName = '/home/lofartest/subracktest/data/SUBR-%05d-%05d.dat' % (opts.batch_nr, opts.serial_nr) +cli.command('rm -f /home/lofartest/subracktest/data/SUBR-%05d-%05d.dat', appLev) +sr = testlog.Testlog(vlev, testId, logName) + +sr.setResult('PASSED') + +sr.setId('Subrack - ') +sr.appendLog(11,'') +sr.appendLog(1,'Subrack production test %s' % logName) +sr.appendLog(11,'') + + +################################################################################ +sr.setId('RSP version - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify LCU - RSP ethernet link by getting the RSP version info') +sr.appendLog(21,'') +res = cli.command('./rsp_version.sh') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> RSP version test went OK') +else: + sr.appendLog(11,'>>> RSP version test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'Result:') + sr.appendFile(11,'rsp_version.log') + sr.appendLog(11,'Expected:') + sr.appendFile(11,'gold/rsp_version.gold') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('TBB version - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify LCU - TBB ethernet link by getting the TBB version info') +sr.appendLog(21,'') +res = cli.command('./tbb_version.sh') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> TBB version test went OK') +else: + sr.appendLog(11,'>>> TBB version test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'Result:') + sr.appendFile(11,'tbb_version.log') + sr.appendLog(11,'Expected:') + sr.appendFile(11,'gold/tbb_version.gold') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('SPU status - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the RSP - SPU I2C interface by reading the SPU sensor data') +sr.appendLog(21,'') + +res = cli.command('python i2c_spu.py') +res = cli.command('python i2c_spu.py') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> RSP - SPU I2c interface test went OK') +else: + sr.appendLog(11,'>>> RSP - SPU I2c interface test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'Result:') + sr.appendFile(11,'spustat.log') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('TD status - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the RSP - TD I2C interface by reading the TD sensor data') +sr.appendLog(21,'') + +res = cli.command('python i2c_td.py') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> RSP - TD I2c interface test went OK') +else: + sr.appendLog(11,'>>> RSP - TD I2c interface test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendLog(11,'Result:') + sr.appendFile(11,'tdstat.log') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('RCU-RSP - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the RCU -> RSP LVDS interfaces by capturing pseudo random data on RSP') +sr.appendLog(21,'') + +res = cli.command('python verify.py --brd rsp0,rsp1,rsp2,rsp3 --fpga blp0,blp1,blp2,blp3 --pol x,y --rep 1 -v 11 --te tc/prsg.py') +if res.find('FAILED')==-1: + sr.appendLog(11,'>>> RCU-RSP interface test went OK') + sr.appendFile(21,'tc/prsg.log') +else: + sr.appendLog(11,'>>> RCU-RSP interface test went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.appendFile(11,'tc/prsg.log') + sr.setResult('FAILED') + + +################################################################################ +sr.setId('RCU-RSP-TBB - ') +sr.appendLog(21,'') +sr.appendLog(21,'### Verify the RCU - RSP - TBB LVDS interfaces by capturing pseudo random data on TBB') +sr.appendLog(21,'') + +res = cli.command('./tbb_prbs_tester.sh') +if res.find('wrong')==-1: + sr.appendLog(11,'>>> RCU - RSP - TBB LVDS interfaces test went OK') +else: + sr.appendLog(11,'>>> RCU - RSP - TBB LVDS interfaces went wrong') + sr.appendLog(11,'CLI:') + sr.appendLog(11,res,1,1,1) + sr.setResult('FAILED') + + +################################################################################ +# End of the subrack test + +sr.setId('Subrack - ') +dt = sr.getRunTime() +sr.appendLog(2,'Duration: %02dm:%02ds' % (dt/60 % 60, dt % 60)) +sr.appendLog(0,sr.getResult()) +sr.closeLog() diff --git a/StationTest/subracktest.sh b/StationTest/subracktest.sh new file mode 100644 index 00000000000..4ac35bcf8ff --- /dev/null +++ b/StationTest/subracktest.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# +# Run the tests for a LOFAR station subrack +# + +# Verify LCU - RSP, LCU - TBB ethernet links by getting the version info +./rsp_version.sh +./tbb_version.sh + +# Verify the RSP internal interfaces (Ethernet LCU, Ethernet CEP, 10 Gb Serdes, LVDS ring) by running the BIST +python verify.py --brd rsp0,rsp1,rsp2,rsp3 --rep 1 -v 11 --te tc/bist.py + +# Verify the RSP - SPU, TD I2C interface by reading the sensor data +python i2c_spu.py +python i2c_td.py + +# Verify the RSP - RSP SERDES links using pseudo random data +python verify.py --brd rsp0,rsp1,rsp2,rsp3 --rep 1 -v 11 --te tc/serdes.py --mode tx_rx + +# Verify the RSP - RSP SERDES links by capturing cross correlation statistics +./rsp_xc_200.sh + +# Verify the RCU -> RSP LVDS interfaces by capturing pseudo random data on RSP +python verify.py --brd rsp0,rsp1,rsp2,rsp3 --fpga blp0,blp1,blp2,blp3 --pol x,y --rep 1 -v 11 --te tc/prsg.py + +# Verify the RCU -> RSP -> TBB LVDS interfaces by capturing pseudo random data on TBB +./tbb_prbs_tester.sh + diff --git a/StationTest/tbb_prbs_tester.sh b/StationTest/tbb_prbs_tester.sh new file mode 100644 index 00000000000..4390bb7c21e --- /dev/null +++ b/StationTest/tbb_prbs_tester.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# +# Test the LVDS interfaces between RCU -> RSP -> TBB using the Pseudo Random generator in the RCUs. +# + +nof_rcu=32 + +rm -f *.log +rm -f *.diff +rm -f ./prbs/*.* +rm -f ./prbs/.* + + +# Set up RCU and RSP, make sure waveform generator is off +rspctl --rcuprsg=1 +sleep 1 +rspctl --tbbmode=transient + +sleep 5 +# set up TBB +nof_slices=10 # one slice contains 1024 transient (raw data) samples + +tbbctl --free +tbbctl --alloc +tbbctl --rec + +sleep 0.1 + +# Freeze and get the captured data from TBB +cd ./prbs +tbbctl --stop +for ((i = 0; i < $nof_rcu; i++)) do + tbbctl --readpage=$i,0,$nof_slices +done +cd .. +# Verify the PRBS +python prbs_dir_test.py + + +echo "" +diff prbs_dir_test.log ./gold/prbs_dir_test.gold > prbs_dir_test.diff +if [ -e prbs_dir_test.log ] && [ -e ./gold/prbs_dir_test.gold ] && [ -e prbs_dir_test.diff ] && ! [ -s prbs_dir_test.diff ]; then + # The files exists AND has the diff size 0 + echo "RCU -> RSP -> TBB interfaces test went OK" +else + echo "RCU -> RSP -> TBB interfaces test went wrong" +fi diff --git a/StationTest/tbb_version.sh b/StationTest/tbb_version.sh new file mode 100644 index 00000000000..c9b8155367c --- /dev/null +++ b/StationTest/tbb_version.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# +# Get version info from the TBB boards and compare this with the expected golden result. +# + +rm -f *.log +rm -f *.diff +tbbctl --version --select=0,1 > tbb_version.log +diff tbb_version.log gold/tbb_version.gold > tbb_version.diff +if [ -e tbb_version.log ] && [ -e gold/tbb_version.gold ] && [ -e tbb_version.diff ] && ! [ -s tbb_version.diff ]; then + # The files exists AND has the diff size 0 + echo "TBB version test went OK" +else + echo "TBB version test went wrong" +fi diff --git a/StationTest/tc/Makefile.am b/StationTest/tc/Makefile.am new file mode 100644 index 00000000000..8bee11394e1 --- /dev/null +++ b/StationTest/tc/Makefile.am @@ -0,0 +1,15 @@ +testdir = $(prefix)/stationtest/tc +test_SCRIPTS = bist.py \ + empty.py \ + hba_client.py \ + hba_server.py \ + prsg.py \ + rad_lanemode.py \ + rad_latency.py \ + serdes.py \ + spustat.py \ + status.py \ + sync_delay.py \ + tdstat.py + +include $(top_srcdir)/Makefile.common diff --git a/StationTest/tc/bist.py b/StationTest/tc/bist.py new file mode 100644 index 00000000000..4f44e401d83 --- /dev/null +++ b/StationTest/tc/bist.py @@ -0,0 +1,146 @@ +"""Run the BIST messages manually, based on TCL testcase 11.5. +""" + +# See bist/src/data/bist_msgrom.txt + +################################################################################ +# - Verify options +rspId = tc.rspId +bpId = ['rsp'] +fpgaId = ['rsp', 'blp0', 'blp1', 'blp2', 'blp3'] + +tc.appendLog(11, '') +tc.appendLog(11, '>>> Run the BIST messages manually on RSP-%s' % rspId) +tc.appendLog(11, '') + +################################################################################ +# - Test selections +tst_duration = rsp.c_diag_duration_quick # 1 = quick +tst_duration = rsp.c_diag_duration_normal # 2 = normal +tst_lane = 0 + +# Ensure CR ext sync is enabled +#rsp.write_cr_syncon(tc, msg, fpgaId, rspId) + +# - Overwrite 20 (= 0x10+0x04) RSR selftest result fields with FE starting at offset 30 (= 0x1E). +# +# ty st frlen blp rsp pi rg offset payld seqnr rsvd Data ... +# 02 00 20 00 00 01 01 00 1E 00 10 00 01 00 00 00 FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE +# 02 00 14 00 00 01 01 00 2E 00 04 00 02 00 00 00 FE FE FE FE 00 00 00 00 00 00 00 00 00 00 00 00 +# +value = 0xFE +rsp.overwrite_rsr(tc, msg, 'mep', value, rspId) +rsp.overwrite_rsr(tc, msg, 'diag', value, rspId) + +# Check overwriten RSR DIAG +for ri in rspId: + rsp.read_rsr(tc, msg, 'diag', [ri], 31) + +# - Write DIAG selftest for LCU +# +# ty st frlen blp rsp pi rg offset payld seqnr rsvd Data ... +# 02 00 14 00 00 01 03 06 00 00 04 00 03 00 00 00 03 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 +# +tst_interface = rsp.c_diag_dev_lcu # 3 = LCU +tst_mode = rsp.c_diag_mode_loop_local # 1 = loop local +selftest = [tst_interface, tst_mode, tst_duration, tst_lane] +for ri in rspId: + rsp.write_diag_selftest(tc, msg, selftest, bpId, [ri], 99) +tc.sleep(7000) + +# - Write DIAG selftest for CEP +# +# ty st frlen blp rsp pi rg offset payld seqnr rsvd Data ... +# 02 00 14 00 00 01 03 06 00 00 04 00 04 00 00 00 04 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 +# +tst_interface = rsp.c_diag_dev_cep # 4 = CEP +tst_mode = rsp.c_diag_mode_loop_local # 1 = loop local +selftest = [tst_interface, tst_mode, tst_duration, tst_lane] +for ri in rspId: + rsp.write_diag_selftest(tc, msg, selftest, bpId, [ri], 99) +tc.sleep(5000) + +# - Write DIAG selftest for SERDES +# +# ty st frlen blp rsp pi rg offset payld seqnr rsvd Data ... +# 02 00 14 00 00 01 03 06 00 00 04 00 05 00 00 00 05 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 +# +tst_interface = rsp.c_diag_dev_serdes # 5 = SERDES +tst_mode = rsp.c_diag_mode_loop_local # 1 = loop local +selftest = [tst_interface, tst_mode, tst_duration, tst_lane] +for ri in rspId: + rsp.write_diag_selftest(tc, msg, selftest, bpId, [ri], 99) +tc.sleep(1000) + +# - Write DIAG selftest for RI +# +# ty st frlen blp rsp pi rg offset payld seqnr rsvd Data ... +# 02 00 14 00 0F 01 03 06 00 00 04 00 06 00 00 00 00 06 02 00 00 00 00 00 00 00 00 00 00 00 00 00 +# +tst_interface = rsp.c_diag_dev_ri # 0 = RI +tst_mode = rsp.c_diag_mode_bus # 6 = mode bus is mode tx,rx +selftest = [tst_interface, tst_mode, tst_duration, tst_lane] +for ri in rspId: + rsp.write_diag_selftest(tc, msg, selftest, fpgaId, [ri], 99) +tc.sleep(1000) + +# - Read RSR to get BIST result, starting with MEP status error field (offset 0x1A) and length 0x18 bytes +# +# ty st frlen blp rsp pi rg offset payld seqnr rsvd Data ... +# 01 00 10 00 00 01 01 00 1A 00 18 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# +for ri in rspId: + rsp.read_mem(tc, msg, 'rsr', 'status', rsp.c_ei_status_rsr_size, bpId, [ri], 'h', 1, rsp.c_ei_status_rsr_offset) + + msg.setOffset(rsp.c_ei_status_mep_offset) + dummy = msg.readUnsigned(2) + mep_prev_msg = msg.readUnsigned(1) + dummy = msg.readUnsigned(1) + + msg.setOffset(rsp.c_ei_status_diag_offset) + # DIAG status + diag_interface = msg.readUnsigned(1) + diag_mode = msg.readUnsigned(1) + diag_ri_bp = msg.readUnsigned(2) + diag_rcux = msg.readUnsigned(2) + diag_rcuy = msg.readUnsigned(2) + diag_eth_LCU = msg.readUnsigned(2) + diag_eth_CEP = msg.readUnsigned(2) + diag_serdes = msg.readUnsigned(2) + diag_ri_ap0 = msg.readUnsigned(2) + diag_ri_ap1 = msg.readUnsigned(2) + diag_ri_ap2 = msg.readUnsigned(2) + diag_ri_ap3 = msg.readUnsigned(2) + + # Verify + if mep_prev_msg == 0 and \ + diag_ri_bp == rsp.c_diag_res_ok and \ + diag_rcux != rsp.c_diag_res_ok and \ + diag_rcuy != rsp.c_diag_res_ok and \ + diag_eth_LCU == rsp.c_diag_res_ok and \ + diag_eth_CEP == rsp.c_diag_res_ok and \ + diag_serdes == rsp.c_diag_res_ok and \ + diag_ri_ap0 == rsp.c_diag_res_ok and \ + diag_ri_ap1 == rsp.c_diag_res_ok and \ + diag_ri_ap2 == rsp.c_diag_res_ok and \ + diag_ri_ap3 == rsp.c_diag_res_ok: + tc.appendLog(11, 'RSP-%s : BIST sequence went OK' % ri) + tc.setResult('PASSED') + else: + tc.appendLog(11, 'RSP-%s : BIST sequence went wrong:' % ri) + tc.appendLog(11, ' mep msg = %d' % mep_prev_msg) + tc.appendLog(11, ' ri-bp = %d' % diag_ri_bp) + tc.appendLog(11, ' rcux = %d' % diag_rcux) + tc.appendLog(11, ' rcuy = %d' % diag_rcuy) + tc.appendLog(11, ' eth-LCU = %d' % diag_eth_LCU) + tc.appendLog(11, ' eth-CEP = %d' % diag_eth_CEP) + tc.appendLog(11, ' serdes = %d' % diag_serdes) + tc.appendLog(11, ' ri-ap0 = %d' % diag_ri_ap0) + tc.appendLog(11, ' ri-ap1 = %d' % diag_ri_ap1) + tc.appendLog(11, ' ri-ap2 = %d' % diag_ri_ap2) + tc.appendLog(11, ' ri-ap3 = %d' % diag_ri_ap3) + tc.setResult('FAILED') + +# Read RSR DIAG again to also display result in text instead of numbers +for ri in rspId: + rsp.read_rsr(tc, msg, 'diag', [ri], 21) diff --git a/StationTest/tc/empty.py b/StationTest/tc/empty.py new file mode 100644 index 00000000000..0f6116eefa8 --- /dev/null +++ b/StationTest/tc/empty.py @@ -0,0 +1,2 @@ +"""Empty testcase""" + diff --git a/StationTest/tc/hba_client.py b/StationTest/tc/hba_client.py new file mode 100644 index 00000000000..6d74e533d8f --- /dev/null +++ b/StationTest/tc/hba_client.py @@ -0,0 +1,167 @@ +"""Write and readback HBA client registers, based on TCL testcase 5.42 + + - Specific arguments + . client_rcu : RCU to use for the HBA client I2C access, x or y + . client_access : r = read only, w = write only, wr = first write then readback + . client_reg : client register to access: request, response, led, vref, version, speed + . data : data byte(s) to write or verify read +""" + +################################################################################ +# - Verify options +rspId = tc.rspId +blpId = tc.blpId +repeat = tc.repeat # When > 1 then the register access will be repeated + +# - Rename testcase specific options +arg_rcu = arg_hba_client_rcu +arg_access = arg_hba_client_access +arg_reg = arg_hba_client_reg + +# Get rcuId +rcuId = [arg_rcu] + +# Adapt access format +if arg_access == 'w': + str_access = 'Write' +elif arg_access == 'r': + str_access = 'Read' +else: + str_access = 'Write and read' + arg_access = 'wr' + +tc.setResult('PASSED') + +tc.appendLog(11, '') +tc.appendLog(11, '>>> %s access of RSP-%s, BLP-%s, HBA client register %s via I2C access of RCU-%s' % (str_access, rspId, blpId, arg_reg, arg_rcu)) +tc.appendLog(11, '') + +################################################################################ +# - Testcase initializations + +# - Disable external sync +rsp.write_cr_syncoff(tc, msg, blpId, rspId) + +# - Prepare the protocol list for RCU control register +addr = rsp.c_rcuh_i2c_addr_hba # HBA client I2C address (7 bit) + +cmd_request = rsp.c_hba_cmd_request +cmd_response = rsp.c_hba_cmd_response +cmd_led = rsp.c_hba_cmd_led +cmd_vref = rsp.c_hba_cmd_vref +cmd_speed = rsp.c_hba_cmd_speed +cmd_version = rsp.c_hba_cmd_version + +f_set_byte = rsp.c_hba_f_set_byte +f_get_byte = rsp.c_hba_f_get_byte +f_set_word = rsp.c_hba_f_set_word +f_get_word = rsp.c_hba_f_get_word + +bc_server = rsp.c_hba_bc_server +first_server = 1 +last_server = 16 + +reg_xdelay = rsp.c_hba_sreg_xdelay + +# Select register +if arg_reg == 'request': + cmd = cmd_request + data_len = 2*(last_server - first_server + 1) + data = [] # primary data values + data.append(bc_server) + data.append(5 + data_len) + data.append(f_set_word) + data.append(reg_xdelay) + data.append(first_server) + data.append(last_server) + data2 = data # alternate data values + for i in range(data_len): + data.append(i) # count up data + data2.append(data_len - i) # count down data +elif arg_reg == 'response': + cmd = cmd_response + data = [17, 37, 59, 214] + data2 = [97, 231, 1, 14] +elif arg_reg == 'led': + cmd = cmd_led + data = arg_data # HBA client LED on > 0 + data2 = 0 # HBA client LED off = 0 +elif arg_reg == 'vref': + cmd = cmd_vref + data = arg_data # HBA client VREF setting, see pic16f87 manual + data2 = 236 # HBA client default VREF "11101100", [5]=1 for 24 steps, [3:0]=12 for mid level +elif arg_reg == 'speed': + cmd = cmd_speed + data = arg_data # HBA modem default speed setting is 40 + data2 = 41 +elif arg_reg == 'version': + cmd = cmd_version + data = arg_data # HBA client version write access should be ignored + data2 = 29 +else: + tc.appendLog(11, 'Register -%s- is unknown or not supported!' % arg_reg) + sys.exit() + +# - HBA modem timing +msec = rsp.c_msec +bc_wait = rsp.hba_bc_wait +gap_wait = rsp.hba_gap_wait +bc_i2c = rsp.hba_bc_i2c +reg_i2c = rsp.hba_reg_i2c + +for rep in range(1,1+repeat): + reg_dat = data + if repeat > 1: + tc.appendLog(11, '>>> %s' % rep) + if (rep % 2)==0 and arg_access != 'r': + reg_dat = data2 # alternate between write data and write data2 + + protocol_list = [] + exp_result = [] + if arg_access == 'wr' or arg_access == 'w': + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_WRITE_BLOCK_NO_CNT', len(reg_dat), addr, reg_dat, cmd)) + exp_result.append(0) + if arg_access == 'wr' and arg_reg == 'request': + # Broadcast request takes modem time, 38 msec seems minimum for broadcast 16 servers and modem speed = 40, + # other I2C only register accesses do not need wait. + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_WAIT', bc_wait * msec)) + exp_result.append(0) + else: + # Default I2C client register access wait time + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_WAIT', gap_wait * msec)) + exp_result.append(0) + if arg_access == 'wr' or arg_access == 'r': + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_READ_BLOCK_NO_CNT', len(reg_dat), addr, None, cmd)) + exp_result.extend(reg_dat) + exp_result.append(0) + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_END')) + exp_result.append(0) + + # - Overwrite and read the protocol results from the RCUH + rsp.overwrite_rd_smbh_protocol_results(tc, msg, 'rcuh', rcuId, blpId, rspId) + + # - Write (and readback) the protocol list to the RCUH + rsp.write_rd_smbh_protocol_list(tc, msg, 'rcuh', protocol_list, rcuId, blpId, rspId) + + # - Apply altsync to start the RCUH SMBus protocols + rsp.write_rsu_altsync(tc, msg, rspId) + tc.sleep(bc_i2c + bc_wait + reg_i2c) + + # Read the protocol results from the RCUH + for ri in rspId: + for bi in blpId: + for pi in rcuId: + rd_result = smbus.read_results(tc, msg, 'rcuh', len(exp_result), pi, [bi], [ri]) + # Equal? + if rd_result == exp_result: + tc.appendLog(21, '>>> RSP-%s, BLP-%s, RCU-%s, HBA client I2C access result buffer contents is OK' % (ri, bi, pi)) + else: + tc.appendLog(11, '>>> RSP-%s, BLP-%s, RCU-%s, HBA client I2C access result buffer contents is wrong:' % (ri, bi, pi)) + tc.appendLog(11, 'Expected protocol result: %s' % exp_result) + tc.appendLog(11, 'Read protocol result: %s' % rd_result) + tc.setResult('FAILED') + + #tc.sleep(1000) + +# - Enable external sync +rsp.write_cr_syncon(tc, msg, blpId, rspId) diff --git a/StationTest/tc/hba_server.py b/StationTest/tc/hba_server.py new file mode 100644 index 00000000000..7aa8be90387 --- /dev/null +++ b/StationTest/tc/hba_server.py @@ -0,0 +1,337 @@ +"""HBA server access via modem, based on TCL testcase 5.43 + + - Specific arguments: + . client_rcu : RCU to use for the HBA client I2C access, x or y + . server : first server number and last server number: first,last + . server_access : bc = broadcast to all servers, uc = unicast to first server + . server_func : server function: gb, gw, sb, sw + . server_reg : server register: delay_x, delay_y, version, address + . data : data byte(s) to write or verify for each server + . count : use counter data for each write request (instead of data) + . rand : use random data for each write request (instead of data) +""" + +################################################################################ +# - Verify options +rspId = tc.rspId +blpId = tc.blpId +repeat = tc.repeat # When > 1 then the register access will be repeated + +# - Rename testcase specific options +arg_rcu = arg_hba_client_rcu +arg_server = arg_hba_server +arg_access = arg_hba_server_access +arg_func = arg_hba_server_function +arg_reg = arg_hba_server_reg + +# Get rcuId +rcuId = [arg_rcu] + +# Adapt access format +if arg_access == 'bc': + str_access = 'broadcast' +else: + str_access = 'unicast' + arg_access = 'uc' + +# Get server addresses +bc_server = rsp.c_hba_bc_server +if arg_access == 'bc': + first_server = arg_server[0] + last_server = arg_server[1] +else: + first_server = arg_server[0] + last_server = first_server +if first_server > last_server: + tc.appendLog(11, 'First server %d must be <= last server %d!' % (first_server, last_server)) + sys.exit() +elif last_server - first_server + 1 > 16: + tc.appendLog(11, 'Maximum first server %d to %d range is 16!' % (first_server, last_server)) + sys.exit() +elif first_server < 1 or first_server > 127: + tc.appendLog(11, 'First server %d must be in range 1 to 127!' % first_server) + sys.exit() +elif last_server < 1 or last_server > 127: + tc.appendLog(11, 'Last server %d must be in range 1 to 127!' % last_server) + sys.exit() + +# Get function +f_set_byte = rsp.c_hba_f_set_byte +f_get_byte = rsp.c_hba_f_get_byte +f_set_word = rsp.c_hba_f_set_word +f_get_word = rsp.c_hba_f_get_word +if arg_func == 'sb': + funcId = f_set_byte + funcSet = 1 + funcWidth = 1 +elif arg_func == 'gb': + funcId = f_get_byte + funcSet = 0 + funcWidth = 1 +elif arg_func == 'sw': + funcId = f_set_word + funcSet = 1 + funcWidth = 2 +elif arg_func == 'gw': + funcId = f_get_word + funcSet = 0 + funcWidth = 2 +else: + tc.appendLog(11, 'Function -%s- is unknown or not supported!' % arg_func) + sys.exit() + +# Get server register +if arg_reg == 'delay_x': + sreg = rsp.c_hba_sreg_xdelay # HBA server frontend X delay register +elif arg_reg == 'delay_y': + sreg = rsp.c_hba_sreg_ydelay # HBA server frontend Y delay register + if funcWidth != 1 and funcSet == 1: + tc.appendLog(11, 'Combination -%s- and -%s- is not supported!' % (arg_func, arg_reg)) + sys.exit() +elif arg_reg == 'version': + sreg = rsp.c_hba_sreg_version # HBA server version register + if funcWidth != 1 and funcSet == 1: + tc.appendLog(11, 'Combination -%s- and -%s- is not supported!' % (arg_func, arg_reg)) + sys.exit() +elif arg_reg == 'address': + sreg = rsp.c_hba_sreg_address # HBA server address register + if funcWidth != 1 and funcSet == 1: + tc.appendLog(11, 'Combination -%s- and -%s- is not supported!' % (arg_func, arg_reg)) + sys.exit() +else: + tc.appendLog(11, 'Server register -%s- is unknown or not supported!' % arg_reg) + sys.exit() + +# Define the server data: count values for bc and arg_data for uc +data = range(2) +data[0] = arg_data[0] +data[1] = 0 +if len(arg_data) == 2: + data[1] = arg_data[1] + +server_data = range(256) +for i in range(256): + server_data[i] = range(2) + server_data[i][0] = 0 + server_data[i][1] = 0 + +if arg_access == 'bc': + for si in range(first_server, last_server+1): + offset = 1 + for di in range(funcWidth): + server_data[si][di] = funcWidth*(si-first_server)+offset + offset += 1 +else: + for di in range(funcWidth): + server_data[first_server][di] = data[di] + +# Init random seed to allow reproduceble results for arg_rand +random.seed(0) + +tc.setResult('PASSED') + +tc.appendLog(11, '') +tc.appendLog(11, '>>> HBA server access of RSP-%s, BLP-%s via I2C access and control modem of RCU-%s' % (rspId, blpId, rcuId)) +tc.appendLog(11, ' Server access : str_access') +if arg_access == 'bc': + tc.appendLog(11, ' First server : %d' % first_server) + tc.appendLog(11, ' Last server : %d' % last_server) +else: + tc.appendLog(11, ' Server address : %d' % first_server) +tc.appendLog(11, ' Function : %s' % arg_func) +tc.appendLog(11, ' Register : %s' % arg_reg) +if funcSet == 1: + if arg_count==1: + tc.appendLog(11, ' Server data : Counter') + elif arg_rand==1: + tc.appendLog(11, ' Server data : Random') + else: + tc.appendLog(11, ' Server data :') + for si in range(first_server, last_server+1): + if funcWidth == 1: + tc.appendLog(11, ' %-3d: d(0) = %3d' % (si, server_data[si][0])) + else: + tc.appendLog(11, ' %-3d: d(0) = %3d, d(1) = %3d' % (si, server_data[si][0], server_data[si][1])) +tc.appendLog(11, '') + + +################################################################################ +# - Determine data request message + +reg_response_size = rsp.c_hba_reg_response_sz # HBA client RESPONSE register size in bytes + +data_request_hdr = [] +if arg_access == 'bc': + # Broadcast request + data_request_hdr.append(bc_server) + if funcSet == 1: + # Set byte or word + data_request_hdr.append(5 + funcWidth*(last_server - first_server + 1)) + data_request_hdr.append(funcId) + data_request_hdr.append(sreg) + data_request_hdr.append(first_server) + data_request_hdr.append(last_server) + else: + # Get byte or word + tc.appendLog(11, '') + tc.appendLog(11, '>>> Broadcast get function is allowed but void, because the HBA servers will not respond!') + tc.appendLog(11, '') + data_request_hdr.append(5) + data_request_hdr.append(funcId) + data_request_hdr.append(sreg) + data_request_hdr.append(first_server) + data_request_hdr.append(last_server) +else: + # Unicast request + data_request_hdr.append(first_server) + if funcSet == 1: + # Set byte or word + data_request_hdr.append(3 + funcWidth) + data_request_hdr.append(funcId) + data_request_hdr.append(sreg) + else: + # Get byte or word + data_request_hdr.append(3) + data_request_hdr.append(funcId) + data_request_hdr.append(sreg) + +################################################################################ +# - Testcase initializations + +# - Disable external sync +rsp.write_cr_syncoff(tc, msg, blpId, rspId) + +# - HBA modem timing +msec = rsp.c_msec +bc_wait = rsp.hba_bc_wait +uc_wait = rsp.hba_uc_wait +gap_wait = rsp.hba_gap_wait +bc_i2c = rsp.hba_bc_i2c +uc_i2c = rsp.hba_uc_i2c +reg_i2c = rsp.hba_reg_i2c + + +############################################################################### +# - HBA client I2C access + +i2c_addr = rsp.c_rcuh_i2c_addr_hba # HBA client I2C address (7 bit) + +cmd_request = rsp.c_hba_cmd_request # HBA client REQUEST register +cmd_response = rsp.c_hba_cmd_response # HBA client RESPONSE register + +for rep in range(1,1+repeat): + + if arg_count==1: + # - Use counter write data for each new data request + count = rep-1 + for si in range(first_server, last_server+1): + server_data[si][0] = (count >> 8) & 0xFF # byte data repeats after 2^8 count + if funcWidth==2: + server_data[si][1] = count & 0xFF # word data repeats after 2^16 count + # use same count for all servers + elif arg_rand==1: + # - Use random write data for each new data request + for si in range(first_server, last_server+1): + for di in range(funcWidth): + server_data[si][di] = int(256*random.random()) + # else: use default data + + # - Append the write data to the fixed data request header + data_request = data_request_hdr + if arg_access == 'bc': + # Broadcast request + if funcSet == 1: + # Set byte or word + for si in range(first_server, last_server+1): + for di in range(funcWidth): + data_request.append(server_data[si][di]) + # else: Get byte or word + else: + # Unicast request + if funcSet == 1: + # Set byte or word + for di in range(funcWidth): + data_request.append(server_data[first_server][di]) + # else: Get byte or word + + # - Define random data for response overwrite + repsonse_overwrite = [] + for i in range(reg_response_size): + repsonse_overwrite.append(int(256*random.random())) + + if arg_access == 'bc': + # Broadcast request + # Define arbitrary response register data that will written first and should not be affected by the broadcast request + data_response = repsonse_overwrite + else: + # Unicast request + # Determine expected response register data + data_response = [first_server + 128] + if funcSet == 1: + data_response.append(1) + else: + data_response.append(funcWidth + 1) + for di in range(funcWidth): + data_response.append(server_data[first_server][di]) + + # Log for debugging + #tc.appendLog(11, 'Expected REQUEST register: %s' % data_request) + #tc.appendLog(11, 'Expected RESPONSE register: %s' % data_response) + + if repeat > 1: + tc.appendLog(11, '>>> rep') + + protocol_list = [] + exp_result = [] + tc.appendLog(21, 'Overwrite RESPONSE register: %s' % repsonse_overwrite) + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_WRITE_BLOCK_NO_CNT', len(repsonse_overwrite), i2c_addr, repsonse_overwrite, cmd_response)) + exp_result.append(0) + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_WAIT', gap_wait * msec)) + exp_result.append(0) + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_WRITE_BLOCK_NO_CNT', len(data_request), i2c_addr, data_request, cmd_request)) + exp_result.append(0) + if arg_access == 'bc': + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_WAIT', bc_wait * msec)) + else: + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_WAIT', uc_wait * msec)) + exp_result.append(0) + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_READ_BLOCK_NO_CNT', len(data_response), i2c_addr, None, cmd_response)) + exp_result.extend(data_response) + exp_result.append(0) + protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_END')) + exp_result.append(0) + + # - Overwrite and read the protocol results from the RCUH + rsp.overwrite_rd_smbh_protocol_results(tc, msg, 'rcuh', rcuId, blpId, rspId) + + # - Write (and readback) the protocol list to the RCUH + rsp.write_rd_smbh_protocol_list(tc, msg, 'rcuh', protocol_list, rcuId, blpId, rspId) + + # - Apply altsync to start the RCUH SMBus protocols + rsp.write_rsu_altsync(tc, msg, rspId) + if arg_access == 'bc': + tc.sleep(reg_i2c + gap_wait + bc_i2c + bc_wait) + else: + tc.sleep(reg_i2c + gap_wait + uc_i2c + uc_wait) + + # Read the protocol results from the RCUH + for ri in rspId: + for bi in blpId: + for pi in rcuId: + rd_result = smbus.read_results(tc, msg, 'rcuh', len(exp_result), pi, [bi], [ri]) + # Equal? + if rd_result == exp_result: + tc.appendLog(21, '>>> RSP-%s, BLP-%s, RCU-%s, HBA client I2C access result buffer contents is OK' % (ri, bi, pi)) + #tc.appendLog(11, 'Expected protocol result: %s' % exp_result) # useful for debugging + else: + tc.appendLog(11, '>>> RSP-%s, BLP-%s, RCU-%s, HBA client I2C access result buffer contents is wrong:' % (ri, bi, pi)) + tc.appendLog(11, 'Expected protocol result: %s' % exp_result) + tc.appendLog(11, 'Read protocol result: %s' % rd_result) + tc.setResult('FAILED') + + if tc.getResult()=='FAILED': + None + #break + +# - Enable external sync +rsp.write_cr_syncon(tc, msg, blpId, rspId) diff --git a/StationTest/tc/prsg.py b/StationTest/tc/prsg.py new file mode 100644 index 00000000000..73188b0e01f --- /dev/null +++ b/StationTest/tc/prsg.py @@ -0,0 +1,150 @@ +"""Testcase for RCU - RSP data interface using PRSG, based on TCL testcase 5.10 + + Note: No specific arguments +""" + +################################################################################ +# Constants + +nof_reflets_ap = rsp.c_nof_reflets_ap +nof_beamlets = rsp.c_nof_beamlets_ap # maximum capable by RSP gateware +nof_beamlets = 216 # sufficient nof beamlets for 32 MHz BW +nof_beamlets_ap = rsp.c_nof_beamlets_ap # including reflets +nof_beamlets_ap = nof_reflets_ap + nof_beamlets # including reflets + +# - SS output size +c_ss_reflets_size = rsp.c_pol * nof_reflets_ap +c_ss_size = rsp.c_pol * nof_beamlets_ap + +c_ss_gap = rsp.c_slice_size - rsp.c_cpx * rsp.c_pol * nof_beamlets_ap + +# - Datapath result buffer +c_res_word_width = 4 +c_res_nof_words = rsp.c_cpx * rsp.c_pol * nof_beamlets_ap # include read reflets +c_res_nof_words_per_pol = rsp.c_cpx * nof_beamlets # skipped reflets + +################################################################################ +# - Verify options +rspId = tc.rspId +blpId = tc.blpId +polId = tc.polId +repeat = tc.repeat +tc.setResult('PASSED') # self checking test, so start assuming it will run PASSED + +tc.appendLog(11,'') +tc.appendLog(11,'>>> Capture PRSG data for RSP-%s, BLP-%s, RCU-%s' % (rspId, blpId, polId)) +tc.appendLog(11,'') + +################################################################################ +# - Testcase initializations +bypass = 0x8F # Bypass data path to have direct access to RCU data via SS, use resync + # version of pps to preserve X and Y order in captured data + +# - Write incrementing SS mapping, repeat (r > 1) write to 'ensure' both pages are written +#ss_map = [] +#for i in range(0, rsp.c_pol * nof_beamlets_ap): +# ss_map.append(i) +#r = 1 +#for i in range(0,r): +# rsp.write_ss(tc, msg, ss_map, blpId, rspId) +# tc.sleep(1000) +# rsp.write_ss(tc, msg, ss_map, blpId, rspId) +# tc.sleep(1000) + +# Apparently rspctl updates the SS every pps, so overwriting it does not work. +# Disabling SS update in RSPDriver.conf may be an option. However instead adapt +# this test case to the actual SS by reordering the captured data accordingly. +# Therefore read the actual SS into ss_map. + +# - Read actual SS mapping, to use it to reorder the read DIAG result +# . assume all BLP use same mapping +# . strip the reflets +# . assume that the beamlets mapping uses all subbands +bi = [blpId[0]] +ri = [rspId[0]] +ss_map = rsp.read_ss(tc, msg, c_ss_size, bi, ri) +ss_map = ss_map[c_ss_reflets_size:] + +rsp.write_cr_syncoff(tc, msg, blpId, rspId) +rsp.write_diag_bypass(tc, msg, bypass, blpId, rspId) + +################################################################################ +# Set RCU in PRSG mode +rsp.rspctl(tc, '--rcuprsg') + +################################################################################ +# Run the test +for k in range(0, repeat): + rsp.write_rsu_altsync(tc, msg, rspId) # Apply altsync to capture a new result buffer + tc.sleep(100) + + for ri in rspId: + for bi in blpId: + res_buffer = rsp.read_diag_result_buffer(tc, msg, c_res_nof_words, c_res_word_width, [bi], [ri]) + + res ={'x':[], 'y':[]} + for x in range(0, len(res_buffer), 2): + res['x'].append(res_buffer[x] & rsp.c_rcu_dat_mask) + for y in range(1, len(res_buffer), 2): + res['y'].append(res_buffer[y] & rsp.c_rcu_dat_mask) + res['x'] = res['x'][c_ss_reflets_size:] # strip the reflets + res['y'] = res['y'][c_ss_reflets_size:] + res['x'] = rsp.reorder(res['x'], ss_map) # reorder according to SS map + res['y'] = rsp.reorder(res['y'], ss_map) + + for pi in polId: + first = 1 # First result sample is used as starting seed for the expected samples + ok = 0 # 0 = OK + if len(res[pi]) == c_res_nof_words_per_pol: + for rs in res[pi]: + if first == 0: + if ok == 0: + if rs != rsp.calculate_next_sequence_value(rs_prev): + # Mismatch, so bridge the potential SS gap in the sample stream to verify whether this is the cause + rs_gap = rs_prev + for i in range(0, c_ss_gap): + rs_gap = rsp.calculate_next_sequence_value(rs_gap) + if rs != rsp.calculate_next_sequence_value(rs_prev): + # Mismatch again, so assume the potential SS gap was not the cause of the initial mismatch + nxt_rs_prev = rsp.calculate_next_sequence_value(rs_prev) + exp.append(nxt_rs_prev) + ok = 1 # 1 = sample mismatch + else: + # OK, so bridge the SS gap in the expected results + nxt_rs_prev = rsp.calculate_next_sequence_value(rs_gap) + exp.append(nxt_rs_prev) + else: + # OK, no SS gap to bridge + nxt_rs_prev = rsp.calculate_next_sequence_value(rs_prev) + exp.append(nxt_rs_prev) + else: + # A mismatch has aleready occured, no need to check for more mismatches + nxt_rs_prev = rsp.calculate_next_sequence_value(rs_prev) + exp.append(nxt_rs_prev) + else: + first = 0 + nxt_rs_prev = res[pi][0] + exp = [nxt_rs_prev] + rs_prev = nxt_rs_prev + else: + ok = 2 # 2 = length error + + # Report results + if ok == 0: + tc.appendLog(11,'>>> %d : RSP-%s, BLP-%s, RCU-%s PRSG data is OK.' % (k, ri, bi, pi)) + elif ok == 1: + tc.appendLog(11,'>>> %d : RSP-%s, BLP-%s, RCU-%s PRSG data mismatch.' % (k, ri, bi, pi)) + tc.appendLog(11,'- Expected data:') + tc.appendLog(11,'%s' % exp) + tc.appendLog(11,'- Captured data:') + tc.appendLog(11,'%s' % res[pi]) + tc.setResult('FAILED') + else: + tc.appendLog(11,'>>> %d : RSP-%s, BLP-%s, RCU-%s PRSG data length mismatch.' % (k, ri, bi, pi)) + tc.appendLog(11,'Captured length %d != expected length %d' % (len(res[pi]), c_res_nof_words_per_pol)) + tc.setResult('FAILED') + +# Restore defaults +bypass = 1 +rsp.write_diag_bypass(tc, msg, bypass, blpId, rspId, 99) +rsp.write_cr_syncon(tc, msg, blpId, rspId) diff --git a/StationTest/tc/rad_lanemode.py b/StationTest/tc/rad_lanemode.py new file mode 100644 index 00000000000..102806726d7 --- /dev/null +++ b/StationTest/tc/rad_lanemode.py @@ -0,0 +1,35 @@ +"""Write or read the RAD lane mode, based on TCL testcase 5.24""" + +################################################################################ +# - Verify options +rspId = tc.rspId +repeat = tc.repeat + +# - Construct settings word from arg_rad_lane_mode +# +# settings: one byte for each lane, byte [3:0] for lane [3:0] +# format: XXXXAABB +# where XX = don't care +# AA = xlet mode +# BB = blet mode +# +# mode 00 = ignore remote data (only local) DEFAULT +# mode 01 = disable +# mode 10 = combine local and remote data +# mode 11 = ignore local data (only remote) +# +# arg_rad_lane_mode = [X3,X2,X1,X0,B3,B2,B1,B0] + +settings = 0 +for i in range(rsp.c_nof_lanes): + settings += ((arg_rad_lane_mode[i] << 2) + arg_rad_lane_mode[i+rsp.c_nof_lanes]) << (8*i) # X,B[3:0] + + +############################################################################# +# Read RAD latency for each RSP board + +if arg_read: + for ri in rspId: + rsp.read_rad_settings(tc, msg, [ri], 11) +else: + rsp.write_rad_settings(tc, msg, settings, rspId, 11) diff --git a/StationTest/tc/rad_latency.py b/StationTest/tc/rad_latency.py new file mode 100644 index 00000000000..b4bf54d46cf --- /dev/null +++ b/StationTest/tc/rad_latency.py @@ -0,0 +1,21 @@ +"""Read the RAD latency, based on TCL testcase 5.49""" + +################################################################################ +# - Verify options +rspId = tc.rspId +repeat = tc.repeat + +tc.appendLog(11, '') +tc.appendLog(11, '>>> Read RAD_BP latency for RSP-%s.' % rspId) +tc.appendLog(11, '') + + +############################################################################# +# Read RAD latency for each RSP board + +if repeat==1: + latency = rsp.read_rad_latency(tc, msg, rspId, 11) +else: + for rep in range(1,1+repeat): + tc.appendLog(11, '>>> Rep %d' % rep) + latency = rsp.read_rad_latency(tc, msg, rspId, 11) diff --git a/StationTest/tc/serdes.py b/StationTest/tc/serdes.py new file mode 100644 index 00000000000..06f92b21fd0 --- /dev/null +++ b/StationTest/tc/serdes.py @@ -0,0 +1,187 @@ +"""Test the SERDES ring between RSP boards, based on TCL testcase 3.8 + + - Specific arguments: + . diag_mode: + off = rsp.c_diag_mode_no_tst --> enable sync to stop continuous tx test + tx = rsp.c_diag_mode_loop_tx --> keep ext sync disabled to continue tx + rx = rsp.c_diag_mode_loop_rx + tx_rx = rsp.c_diag_mode_loop_tx_rx + local = rsp.c_diag_mode_loop_local --> use local loopback (idem as testcase 3.6) + . diag_sync: When 0 use external sync, else use altsync with sync interval time + given by 'sync' sec. + . diag_data: + cntr = use incremental data + lfsr = use LFSR data + + - Note: + . All four lanes are verified in parallel +""" +################################################################################ + +# NOTE: +# When using arg_sync = 0 to select the external sync the --brd order of RSP +# boards should match the fysical SERDES tx order. Due to the slow script +# (few MEP messages/sec) the test migth otherwise fail when too many boards +# are in the test. + +################################################################################ +# - Verify options +rspId = tc.rspId +repeat = tc.repeat + +# - Rename testcase specific options +arg_mode = arg_diag_mode +arg_sync = arg_diag_sync +arg_data = arg_diag_data + +################################################################################ +# - Test selections +tst_interface = rsp.c_diag_dev_serdes +tst_lane = 0xFF # not used + +if arg_mode == 'off': tst_mode = rsp.c_diag_mode_no_tst +elif arg_mode == 'tx': tst_mode = rsp.c_diag_mode_tx +elif arg_mode == 'rx': tst_mode = rsp.c_diag_mode_rx +elif arg_mode == 'tx_rx': tst_mode = rsp.c_diag_mode_tx_rx +elif arg_mode == 'local': tst_mode = rsp.c_diag_mode_loop_local +else: + tst_mode = rsp.c_diag_mode_loop_local + arg_mode = 'local' + tc.appendLog(11, 'ILLEGAL test mode, default to test mode %s.' % arg_mode) + +if arg_mode == 'tx': + # Use mode 'tx' as continuous tx, so no repeat necessary. Mode 'off' will stop the tx. + repeat = 1 + +# Incremental data is generated for test duration debug, else LFSR data +if arg_data == 'cntr': tst_duration = rsp.c_diag_duration_debug +elif arg_data == 'lfsr': tst_duration = rsp.c_diag_duration_quick +else: + tst_duration = rsp.c_diag_duration_quick + arg_data = 'lfsr' + +selftest = [tst_interface, tst_mode, tst_duration, tst_lane] + +############################################################################# +# Constants + +if arg_mode == 'off': + tc.appendLog(11, '') + tc.appendLog(11, '>>> RSP-%s, stop any previous SERDES tx selftest using mode %s.' % (rspId, arg_mode)) + tc.appendLog(11, '') + # - Stop any previous tx selftest + rsp.write_rsu_altsync(tc, msg, rspId) # start of tst sync interval + rsp.write_rsu_altsync(tc, msg, rspId) # end of tst sync interval + rsp.write_rsu_altsync(tc, msg, rspId) # end tx + rsp.write_cr_syncon(tc, msg, ['rsp'], rspId) # restore CR ext sync enabled default +else: + # - Run selftest + + tc.appendLog(11, '') + if arg_sync == 0: + tc.appendLog(11, '>>> RSP-%s, run SERDES test: mode %s, data %s, using external sync from TD clock board.' % (rspId, arg_mode, arg_data)) + else: + tc.appendLog(11, '>>> RSP-%s, run SERDES test: mode %s, data %s, using RSP on board alternative sync.' % (rspId, arg_mode, arg_data)) + tc.appendLog(11, '') + + for rep in range(1,1+repeat): + # Temporarily disable external sync + rsp.write_cr_syncoff(tc, msg, ['rsp'], rspId) + + value = 0xAB + tc.appendLog(31, '') + tc.appendLog(31, '>>> Overwrite RSR diag bytes with %#x to ensure fresh status.' % value) + tc.appendLog(31, '') + rsp.overwrite_rsr(tc, msg, 'diag', value, rspId) + for ri in rspId: + rsp.read_rsr(tc, msg, 'diag', [ri], 31) + + # Configure DIAG tst + for ri in rspId: + rsp.write_diag_selftest(tc, msg, selftest, ['rsp'], [ri], 99) + + tc.sleep(100) # wait DIAG ack_period_done + + # Sync control + if arg_mode != 'tx': + if arg_sync == 0: + # Enable external sync, first ext sync will start test, next ext sync will end test + rsp.write_cr_syncon(tc, msg, ['rsp'], rspId) + + # Wait for serdes_diag_lane tx, rx test to finish (1 until start sync, 1 measurement sync interval, 1 sync interval + # for tx to finish, so worst case 3 sec) + tc.sleep(3000) + else: + # Run serdes_diag_lane tx, rx test for 1 sync interval (arbitrary long, typically 1 sec) + rsp.write_rsu_altsync(tc, msg, rspId) # start of sync interval + tc.sleep(arg_sync*1000) + rsp.write_rsu_altsync(tc, msg, rspId) # end of sync interval + rsp.write_rsu_altsync(tc, msg, rspId) # end tx + tc.sleep(1000) # allow time for DIAG tst result event to reach RSR + rsp.write_cr_syncon(tc, msg, ['rsp'], rspId) # restore CR ext sync enabled default + # else: For mode 'tx' keep ext sync off to run tx forever, i.e. until tc is rerun with mode 'off'. + + for ri in rspId: + tc.appendLog(31, '') + tc.appendLog(31, '>>> %d: RSP-%s, read RSR diag status:' % (rep, ri)) + tc.appendLog(31, '') + + status = rsp.read_rsr(tc, msg, 'diag', [ri], 31) + status = status[0][0][:] + diag_interface = status[0] + diag_mode = status[1] + diag_ri_errors = status[2] + diag_rcux_errors = status[3] + diag_rcuy_errors = status[4] + diag_lcu_errors = status[5] + diag_cep_errors = status[6] + diag_serdes_errors = status[7] + diag_ap0_ri_errors = status[8] + diag_ap1_ri_errors = status[9] + diag_ap2_ri_errors = status[10] + diag_ap3_ri_errors = status[11] + + if arg_mode == 'tx': + if diag_interface == value: + tc.appendLog(11, '>>> RSP-%s, SERDES tx only is active, use mode off to stop it.' % ri) + tc.appendLog(11, '') + else: + tc.appendLog(11, '>>> RSP-%s, SERDES tx only went wrong.' % ri) + tc.appendLog(11, ' Unexpected test interface %d.' % diag_interface) + tc.setResult('FAILED') + elif diag_interface == tst_interface and \ + diag_mode == tst_mode and \ + diag_serdes_errors == 0: + tc.appendLog(11, '>>> %d: RSP-%s, SERDES test went OK.' % (rep, ri)) + tc.setResult('PASSED') + else: + tc.appendLog(11, '>>> %d: RSP-%s, SERDES test went wrong.' % (rep, ri)) + if diag_interface != tst_interface: + tc.appendLog(11, ' Unexpected test interface %d.' % diag_interface) + elif diag_mode != tst_mode: + tc.appendLog(11, ' Unexpected test mode %d.' % diag_mode) + else: + lane_mask = 2**rsp.c_nof_lanes - 1 + lane_ref = 2**rsp.c_nof_lanes + for i in range(rsp.c_nof_lanes): + lane_errors = (diag_serdes_errors >> (i*rsp.c_nof_lanes)) & lane_mask + if lane_errors == rsp.c_diag_res_ok: + tc.appendLog(11, ' Lane %d went OK.' % i) + elif lane_errors == rsp.c_diag_res_none: + tc.appendLog(11, ' Lane %d went wrong, nothing happened.' % i) + elif lane_errors == rsp.c_diag_res_sync_timeout: + tc.appendLog(11, ' Lane %d went wrong, sync timeout.' % i) + elif lane_errors == rsp.c_diag_res_data_timeout: + tc.appendLog(11, ' Lane %d went wrong, data timeout.' % i) + elif lane_errors == rsp.c_diag_res_word_err: + tc.appendLog(11, ' Lane %d went wrong, word errors occured.' % i) + elif lane_errors == rsp.c_diag_res_illegal: + tc.appendLog(11, ' Lane %d illegal status %d.' % (i, lane_errors)) + else: + tc.appendLog(11, ' Lane %d unknown status %d.' % (i, lane_errors)) + tc.setResult('FAILED') + # Break repeat loop in case test FAILED + if tc.getResult() == 'FAILED': + break + # Restore external sync enabled + rsp.write_cr_syncon(tc, msg, ['rsp'], rspId) diff --git a/StationTest/tc/spustat.py b/StationTest/tc/spustat.py new file mode 100644 index 00000000000..3c571e43513 --- /dev/null +++ b/StationTest/tc/spustat.py @@ -0,0 +1,102 @@ +"""SPU monitor voltages and temperature via I2C, based on TCL testcase 9.6""" + +################################################################################ +# - Verify options +rspId = tc.rspId # allow multiple rsp, e.g. rsp0,rsp4 to access SPU in two subracks +repeat = tc.repeat # use >1 for continuous T,V monitoring or I2C stress test + +tc.setResult('PASSED') + + +tc.appendLog(11,'') +tc.appendLog(11,'>>> Monitor T and V of the SPU board using an I2C access via RSP-%s.' % rspId) +tc.appendLog(11,'') + +# Handle older versions of the SPU (Subrack Power Unit). +spu_version = 2 +#spu_version = 3 +if spu_version == 2: + v48 = 8 +if spu_version == 3: + v48 = 48 + +################################################################################ +# - Testcase initializations + +# - Disable external sync to avoid asynchronous trigger of TDSH protocol list +rsp.write_cr_syncoff(tc, msg, ['rsp'], rspId) + + +################################################################################ +# Read SPU sensor status via I2C + +addr = smbus.c_max6652_addr_vcc +config = smbus.c_max6652_config_start + smbus.c_max6652_config_line_freq_sel +protocol_list = [] +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_WRITE_BYTE', None, addr, [config], smbus.c_max6652_cmd_config)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_read_2v5)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_read_3v3)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_read_12v)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_read_vcc)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_read_temp)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_END')) +exp_result = '0 ? 0 ? 0 ? 0 ? 0 ? 0 0' +len_result = len(exp_result.split()) + + +for rep in range(1,1+repeat): + for ri in rspId: + # - Overwrite and read the protocol results from the TDSH + rsp.overwrite_rd_smbh_protocol_results(tc, msg, 'tdsh', None, None, [ri]) + + # - Write (and readback) the protocol list to the TDSH + rsp.write_rd_smbh_protocol_list(tc, msg, 'tdsh', protocol_list, None, None, [ri]) + + # Apply altsync to start the TDSH SMBus protocols + rsp.write_rsu_altsync(tc, msg, [ri]) + tc.sleep(100) + + # Read the protocol results from the TDSH + rd_result = smbus.read_results(tc, msg, 'tdsh', len_result, None, None, [ri]) + + # Sensor values + spu_volt_2v5 = rd_result[1] + spu_volt_3v3 = rd_result[3] + spu_volt_12v = rd_result[5] + spu_volt_vcc = rd_result[7] + spu_temp = rd_result[9] + + # SPU voltages + v_rcu = spu_volt_2v5 * smbus.c_max6652_unit_2v5 * (10+10)/10 + v_lba_rcu = spu_volt_3v3 * smbus.c_max6652_unit_3v3 * (10+20)/10 + v_hba = spu_volt_12v * smbus.c_max6652_unit_12v * (10+30.1)/10 + v_monitor = spu_volt_vcc * smbus.c_max6652_unit_vcc + + tc.appendLog(11, '') + tc.appendLog(11, 'SPU voltage and temperature measurements:') + tc.appendLog(11, '') + tc.appendLog(11, ' V_RCU = %6.3f V (= %4d * %7.1f mV)' % (v_rcu, spu_volt_2v5, 1000 * smbus.c_max6652_unit_2v5 * (10+10)/10)) + tc.appendLog(11, ' V_LBA_RCU = %6.3f V (= %4d * %7.1f mV)' % (v_lba_rcu, spu_volt_3v3, 1000 * smbus.c_max6652_unit_3v3 * (10+20)/10)) + tc.appendLog(11, ' V_HBA = %6.3f V (= %4d * %7.1f mV)' % (v_hba, spu_volt_12v, 1000 * smbus.c_max6652_unit_12v * (10+30.1)/10)) + tc.appendLog(11, '') + tc.appendLog(11, ' V_monitor = %6.3f V (= %4d * %7.1f mV) (This is the supply voltage of the sensor itself)' \ + % (v_monitor, spu_volt_vcc, 1000 * smbus.c_max6652_unit_vcc)) + tc.appendLog(11, '') + tc.appendLog(11, ' Temp = %4d degrees C' % spu_temp) + tc.appendLog(11, '') + + if rd_result[ 0] == 0 and v_rcu > 4.0 and v_rcu < 5.5 and \ + rd_result[ 2] == 0 and v_lba_rcu > 7 and v_lba_rcu < 9 and \ + rd_result[ 4] == 0 and v_hba > v48-5 and v_hba < v48+5 and \ + rd_result[ 6] == 0 and v_monitor > 3 and v_monitor < 4 and \ + rd_result[ 8] == 0 and spu_temp > 0 and spu_temp < 70 and \ + rd_result[10] == 0: + tc.appendLog(11, '>>> Rep-%d, RSP-%s, I2C access to the MAX6652 T,V sensor on the SPU board went OK' % (rep, ri)) + else: + tc.appendLog(11, '>>> Rep-%d, RSP-%s, I2C access to the MAX6652 T,V sensor on the SPU board went wrong:' % (rep, ri)) + tc.appendLog(11, 'Expected protocol result: %s' % exp_result) + tc.appendLog(11, 'Read protocol result: %s (slave address 0x%x)' % (rd_result, addr)) + tc.setResult('FAILED') + +# - Enable external sync +rsp.write_cr_syncon(tc, msg, ['rsp'], rspId) diff --git a/StationTest/tc/status.py b/StationTest/tc/status.py new file mode 100644 index 00000000000..c0dae7045ea --- /dev/null +++ b/StationTest/tc/status.py @@ -0,0 +1,57 @@ +""" Read the RSP status for one or all pid, based on TCL testcase 11.1""" + +################################################################################ +# - Verify options +rspId = tc.rspId +repeat = tc.repeat + +# Testcase specific options + +if not (arg_procid in ['rsp', + 'eth', + 'mep', + 'diag', + 'bs', + 'rcuh', + 'rsu', + 'ado', + 'rad', + 'all']): + arg_procid = 'all' + tc.appendLog(11, 'Forced unknown procid to \'all\'.') + +tc.appendLog(11, '') +tc.appendLog(11, '>>> Selected RSR read %s for RSP-%s.' % (arg_procid, rspId)) +tc.appendLog(11, '') + + +############################################################################# +# Read RSR for each RSP board + +if repeat==1: + status = rsp.read_rsr(tc, msg, arg_procid, rspId, 11) +else: + for rep in range(1,1+repeat): + tc.appendLog(11, '>>> %d' % rep) + if arg_procid == 'rad': + for ri in rspId: + status = rsp.read_rsr(tc, msg, arg_procid, [ri], 99) + rad_status = status[0][0] # based on bit 20 (= align, 0 is ok), + # bit 19 (= sync, 1 is ok), + # bit 18 (= brc, 0 is ok) + rad_raw = status[0][1] # rad_status info with count (bits 17:0) + rad_cnt = status[0][1][0] & 0x3FFFF # use RI count bits 17:0 + + rsr_str = '%d' % rad_status + for rd in rad_raw: + rsr_str += '%8d' % rd + if rad_status == rsp.c_rsr_undefined: + tc.appendLog(11, '%s, %d: RAD status is OFF (%s)' % (ri, rep, rsr_str)) + elif rad_status == rsp.c_rsr_ok: + tc.appendLog(21, '%s, %d: RAD status is OK (%s), RI count = %d' % (ri, rep, rsr_str, rad_cnt)) + else: + tc.appendLog(11, '%s, %d: RAD status is wrong : %s' % (ri, rep, rsr_str)) + else: + for ri in rspId: + status = rsp.read_rsr(tc, msg, arg_procid, [ri], 11) + tc.sleep(100) # less than 1 sec so we do not miss an interval status diff --git a/StationTest/tc/sync_delay.py b/StationTest/tc/sync_delay.py new file mode 100644 index 00000000000..378e45e658c --- /dev/null +++ b/StationTest/tc/sync_delay.py @@ -0,0 +1,37 @@ +""" Read the RSP status for one or all pid, based on TCL testcase 11.1""" + +################################################################################ +# - Verify options +rspId = tc.rspId +blpId = tc.bpId +blpId.extend(tc.blpId) + +# Testcase specific options +arg_edge = arg_pps_edge +arg_delay = arg_pps_delay + +tc.appendLog(11, '') +if arg_read: + tc.appendLog(11, '>>> Read PPS input delay status for RSP-%s, BLP-%s.' % (rspId, blpId)) + tc.appendLog(11, '') + for ri in rspId: + for bi in blpId: + rsp.read_cr_sync_delay(tc, msg, [bi], [ri]) +else: + if arg_delay==0: + if arg_edge=='r': + tc.appendLog(11, '>>> RSP-%s, BLP-%s: Reset PPS input delay to default and capture on rising edge.' % (rspId, blpId)) + rsp.write_cr_sync_delay(tc, msg, 0, 0, blpId, rspId) + else: + tc.appendLog(11, '>>> RSP-%s, BLP-%s: Reset PPS input delay to default and capture on falling edge.' % (rspId, blpId)) + rsp.write_cr_sync_delay(tc, msg, 0, 1, blpId, rspId) + else: + if arg_edge=='r': + tc.appendLog(11, '>>> RSP-%s, BLP-%s: Increment PPS input delay %d times and capture on rising edge.' % (rspId, blpId, arg_delay)) + for ri in range(arg_delay): + rsp.write_cr_sync_delay(tc, msg, 1, 0, blpId, rspId) + else: + tc.appendLog(11, '>>> RSP-%s, BLP-%s: Increment PPS input delay %d times and capture on falling edge.' % (rspId, blpId, arg_delay)) + for ri in range(arg_delay): + rsp.write_cr_sync_delay(tc, msg, 1, 1, blpId, rspId) +tc.appendLog(11, '') diff --git a/StationTest/tc/tdstat.py b/StationTest/tc/tdstat.py new file mode 100644 index 00000000000..33839489073 --- /dev/null +++ b/StationTest/tc/tdstat.py @@ -0,0 +1,95 @@ +"""TDS monitor voltages and temperature via I2C, based on TCL testcase 9.1""" + +################################################################################ +# - Verify options +rspId = tc.rspId # allow multiple rsp, e.g. rsp0,rsp4 to access TDS in two subracks +repeat = tc.repeat # use >1 for continuous T,V monitoring or I2C stress test + +tc.setResult('PASSED') + +tc.appendLog(11,'') +tc.appendLog(11,'>>> Monitor T and V of the TDS board using an I2C access via RSP-%s.' % rspId) +tc.appendLog(11,'') + +# Handle older versions of the TDS (Timing Distribution Subrack) clock board. +td_version = 2 +#td_version = 3 +if td_version == 2: + v5 = 0 +if td_version == 3: + v5 = 5 + +################################################################################ +# - Testcase initializations + +# - Disable external sync to avoid asynchronous trigger of TDSH protocol list +rsp.write_cr_syncoff(tc, msg, ['rsp'], rspId) + + +################################################################################ +# Read TD sensor status via I2C + +addr = smbus.c_max6652_addr_gnd +config = smbus.c_max6652_config_start + smbus.c_max6652_config_line_freq_sel +protocol_list = [] +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_WRITE_BYTE', None, addr, [config], smbus.c_max6652_cmd_config)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_config)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_read_2v5)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_read_vcc)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_READ_BYTE', None, addr, None, smbus.c_max6652_cmd_read_temp)) +protocol_list.extend(smbus.set_protocol(tc, 'PROTOCOL_C_END')) +exp_result = '0 %d 0 ? 0 ? 0 ? 0 0' % config +len_result = len(exp_result.split()) + + +for rep in range(1,1+repeat): + for ri in rspId: + # - Overwrite and read the protocol results from the TDSH + rsp.overwrite_rd_smbh_protocol_results(tc, msg, 'tdsh', None, None, [ri]) + + # - Write (and readback) the protocol list to the TDSH + rsp.write_rd_smbh_protocol_list(tc, msg, 'tdsh', protocol_list, None, None, [ri]) + + # Apply altsync to start the TDSH SMBus protocols + rsp.write_rsu_altsync(tc, msg, [ri]) + tc.sleep(100) + + # Read the protocol results from the TDSH + rd_result = smbus.read_results(tc, msg, 'tdsh', len_result, None, None, [ri]) + + # Sensor values + volt_2v5 = rd_result[3] + volt_vcc = rd_result[5] + temp = rd_result[7] + + # TDS voltages + tds_5v = volt_2v5 * smbus.c_max6652_unit_2v5 * (10+10)/10 + tds_3v3 = volt_vcc * smbus.c_max6652_unit_vcc # note vcc unit is based on 5v, independent of true VCC + + tc.appendLog(11, '') + tc.appendLog(11, '>>> TDS voltage and temperature measurements:') + tc.appendLog(11, '') + tc.appendLog(11, ' 5V via 2v5 input = %6.3f V (= %4d * %7.4f mV)' % (tds_5v, volt_2v5, 1000*smbus.c_max6652_unit_2v5 * (10+10)/10)) + tc.appendLog(11, ' 3.3V via vcc input = %6.3f V (= %4d * %7.4f mV)' % (tds_3v3, volt_vcc, 1000*smbus.c_max6652_unit_vcc)) + tc.appendLog(11, ' Temp = %4d degrees C' % temp) + tc.appendLog(11, '') + + if rd_result[0] == 0 and \ + rd_result[1] == config and \ + rd_result[2] == 0 and \ + tds_5v > v5-1.0 and tds_5v < v5+0.5 and \ + rd_result[4] == 0 and \ + tds_3v3 > 3.0 and tds_3v3 < 4.0 and \ + rd_result[6] == 0 and \ + temp > 0 and temp < 70 and \ + rd_result[8] == 0 and \ + rd_result[9] == 0: + tc.appendLog(11, '>>> Rep-%d, RSP-%s, I2C access to the MAX6652 T,V sensor on the TDS board went OK' % (rep, ri)) + else: + tc.appendLog(11, '>>> Rep-%d, RSP-%s, I2C access to the MAX6652 T,V sensor on the TDS board went wrong:' % (rep, ri)) + tc.appendLog(11, 'Expected protocol result: %s' % exp_result) + tc.appendLog(11, 'Read protocol result: %s (slave address 0x%x)' % (rd_result, addr)) + tc.setResult('FAILED') + +# - Enable external sync +rsp.write_cr_syncon(tc, msg, ['rsp'], rspId) diff --git a/StationTest/verify.py b/StationTest/verify.py new file mode 100644 index 00000000000..b61f451fc71 --- /dev/null +++ b/StationTest/verify.py @@ -0,0 +1,188 @@ +"""Master script to execute a LOFAR station testcase script + + Features: + - Imports several modules + - Provides argument parsing using optparse + - Instantiates a Testcase class for logging + - Instantiates a MepMessage class for using rspctl --writeblock, --readblock + - Executes one or more testcase scripts (all use the same arguments) + + Notes: + - The structure resembles the TCL/C testcase suite used for the station + gateware (VHDL) development. + - Most TCL testcase will work directly if they are translated to Python. The + python scripts ougth to use high level rspctl commands wherever possible. + - The TCL suite only works under Windows, because it uses WinPCap for ethernet + access. This Python suite only works under Linux, because it uses rspctl. +""" + +################################################################################ +# Parse command line for testcase and options + +import sys +from optparse import OptionParser + +# Define empty class to be used as record, to keep local verify variables less +# easily known in the testcase scripts. +class v: + pass + +verify = OptionParser(usage='usage: python %prog [options]', version='%prog 0.1') + +# - Common options +verify.add_option('-v', type='int', dest='verbosity', + help='Verbosity level for the log file', default=11) +verify.add_option('--te', type='string', dest='testname', + help='File names of one or more testcases') + # Multiple testcases can be run using comma seperator, each with the same options though +verify.add_option('--rep', type='int', dest='repeat', + help='Repeat the test', default=1) +verify.add_option('--brd', type='string', dest='brdId', + help='Board id: rsp0,rsp1 for RSP 0 and 1, tbb0 for TBB 0', default='rsp0') + # Note multiple values for an option are possible by providing them with comma seperator and no spaces +verify.add_option('--fpga', type='string', dest='fpId', + help='FPGA id: rsp for BP, blp0 for AP0, tbb for TP, mp0 for MP0', default='rsp') + # On RSP and BLP is equivalent to an AP, but generaly an AP could implement multiple BLP +verify.add_option('--pol', type='string', dest='polId', + help='Polarization id: x, y or x,y', default='x,y') + +# - Testcase specific options +# Define the testcase specific options here, rather than passing an --args +# string to the testcase. The advantage is that they all show up with --help. +# The disadvantage is that for every new options also this verify.py needs to +# be updated. +verify.add_option('--pid', type='string', dest='pid', + help='Process ID: rsp, eth, mep, diag, bs, rcuh, rsu, ado, rad, all', default='all') +verify.add_option('--data', type='string', dest='data', + help='Data values(s) to write or verify read', default='40') +verify.add_option('--count', action='store_true', dest='count', + help='Use counter data values') +verify.add_option('--rand', action='store_true', dest='rand', + help='Use random data values') +verify.add_option('--read', action='store_true', dest='read', + help='Run the testcase read only') +verify.add_option('--pps_edge', type='string', dest='pps_edge', + help='Capture PPS on rising or falling clock edge: r, f', default='r') +verify.add_option('--pps_delay', type='int', dest='pps_delay', + help='Increment PPS input delay in steps of about 75 ps, use 0 for reset', default=1) +verify.add_option('--diag_mode', type='string', dest='diag_mode', + help='Diag mode: off, tx, rx, tx_rx, local', default='tx_rx') +verify.add_option('--diag_sync', type='int', dest='diag_sync', + help='Diag sync: 0 for pps, > 0 for alt sync interval in s', default=1) +verify.add_option('--diag_data', type='string', dest='diag_data', + help='Diag data: lfsr, cntr', default='lfsr') +verify.add_option('--rad_lane_mode', type='string', dest='rad_lane_mode', + help='RAD lane mode: X lane 3:0, B lane 3:0, where 0=local, 1=disable, 2=combine, 3=remote', default='0,0,0,0,0,0,0,0') +verify.add_option('--client_rcu', type='string', dest='client_rcu', + help='HBA control via this RCU, power via the other RCU: x or y', default='y') +verify.add_option('--client_access', type='string', dest='client_access', + help='HBA client access: r = read only, w = write only, wr = first write then readback', default='r') +verify.add_option('--client_reg', type='string', dest='client_reg', + help='HBA client register: request, response, led, vref, version, speed', default='led') +verify.add_option('--server', type='string', dest='server', + help='HBA server range, first server and last server', default='1,16') +verify.add_option('--server_access', type='string', dest='server_access', + help='HBA server access: bc = broadcast to all servers, uc = unicast to first server', default='uc') +verify.add_option('--server_function', type='string', dest='server_function', + help='HBA server function: gb, gw, sb, sw', default='gb') +verify.add_option('--server_reg', type='string', dest='server_reg', + help='HBA server register: delay_x, delay_y, version, address', default='delay_x') + +v.opts, v.args = verify.parse_args() + +# - Option checks and/or reformatting +if v.opts.testname==None: + verify.error('Option --te must specify a testcase file name') +else: + v.testname = v.opts.testname.split(',') + +v.strId = v.opts.brdId.split(',') +v.rspId = [] +v.tbbId = [] +for brd in v.strId: + if brd[:3] == 'rsp': + v.rspId.append(brd) + elif brd[:3] == 'tbb': + v.tbbId.append(brd) + else: + verify.error('Option --brd has invalid board id %s' % brd) + +v.strId = v.opts.fpId.split(',') +v.bpId = [] # RSP +v.blpId = [] +v.tpId = [] # TBB +v.mpId = [] +for fp in v.strId: + if fp == 'rsp': + v.bpId.append(fp) + elif fp[:3] == 'blp': + v.blpId.append(fp) + elif fp == 'tbb': + v.tpId.append(fp) + elif fp[:2] == 'mp': + v.mpId.append(fp) + else: + verify.error('Option --fp has invalid FPGA id %s' % fp) + +v.polId = v.opts.polId.split(',') + +# Pass the testcase specific options on directly, to avoid having to edit +# testcase.py for every new option. Rename with prefix arg_ so it is easier +# to search for the specific arguments, e.g. with grep or an editor. + +arg_procid = v.opts.pid +data_str = v.opts.data.split(',') +arg_data = [] +for di in data_str: + arg_data.append(int(di)) +arg_count = v.opts.count +arg_rand = v.opts.rand +arg_read = v.opts.read +arg_pps_edge = v.opts.pps_edge +arg_pps_delay = v.opts.pps_delay +arg_diag_mode = v.opts.diag_mode +arg_diag_sync = v.opts.diag_sync +arg_diag_data = v.opts.diag_data +rad_lane_mode_str = v.opts.rad_lane_mode.split(',') +arg_rad_lane_mode = [] +for lm in rad_lane_mode_str: + arg_rad_lane_mode.append(int(lm)) +arg_hba_client_rcu = v.opts.client_rcu +arg_hba_client_access = v.opts.client_access +arg_hba_client_reg = v.opts.client_reg +server_str = v.opts.server.split(',') +arg_hba_server = [] +for si in server_str: + arg_hba_server.append(int(si)) +arg_hba_server_access = v.opts.server_access +arg_hba_server_function = v.opts.server_function +arg_hba_server_reg = v.opts.server_reg + + +################################################################################ +# Run the testcase + +# Import here so no need in Testcase +import random +import mep +import testcase +import rsp +import smbus + +msg = mep.MepMessage() + +for te in v.testname: + # Pass the common options on via the testcase class instance. + tc = testcase.Testcase(v.opts.verbosity, + te, + v.opts.repeat, + v.rspId, v.bpId, v.blpId, + v.tbbId, v.tpId, v.mpId, + v.polId) + tc.appendLog(2,'--------------------------------------------------------------------------------') + tc.setResult('RUNONLY') + execfile(tc.testName) + dt = tc.getRunTime() + tc.appendLog(2,'Duration: %d %02d:%02d:%02d' % (dt/60/60/24, dt/60/60 % 24, dt/60 % 60, dt % 60)) + tc.appendLog(0,tc.getResult()) + tc.closeLog() diff --git a/StationTest/xc_160_setup.sh b/StationTest/xc_160_setup.sh new file mode 100644 index 00000000000..919a24161ea --- /dev/null +++ b/StationTest/xc_160_setup.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# +# Setup part - Test the SERDES ring between the RSP by verifing the crosslet statistics. +# + +pi=$(echo "4*a(1)" | bc -l) + +nof_subbands=512 + +# Start waveform generators for crosscorrelation measurement + +nof_rcu=32 # nof RCU in a subrack +sample_freq=160000000 +rf_freq=40000000 +xc_subband=$(echo "$nof_subbands * $rf_freq / ($sample_freq/2)" | bc -l) + +for ((i = 0; i < $nof_rcu; i++)) do + phs=$(echo "($i * 2 * $pi) / $nof_rcu" | bc -l) + amp=$(echo "0.498 * $i / $nof_rcu" | bc -l) # use 0.498 for deterministic result, see bug 767 + rspctl --wg=$rf_freq --select=$i --ampli=$amp --phase=$phs +done + +rspctl --xcsubband=$xc_subband diff --git a/StationTest/xc_160_verify.sh b/StationTest/xc_160_verify.sh new file mode 100644 index 00000000000..6c3dbfa0d00 --- /dev/null +++ b/StationTest/xc_160_verify.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# +# Verify part - Test the SERDES ring between the RSP by verifing the crosslet statistics. +# + +rm -f *.dat +rm -f *.diff + +# Capture crosscorrelation data for 1 sec + +rspctl --xcstat --duration=1 + + +# Verify the captured data + +xc_dat=$(ls *.dat) +diff $xc_dat gold/xst_160.gold > xst.diff +if [ -e $xc_dat ] && [ -e gold/xst_160.gold ] && [ -e xst.diff ] && ! [ -s xst.diff ]; then + # The files exists AND the diff has size 0 + echo "RSP serdes crosscorrelation test at 160 MHz went OK" +else + echo "RSP serdes crosscorrelation test at 160 MHz went wrong" +fi + diff --git a/StationTest/xc_200_setup.sh b/StationTest/xc_200_setup.sh new file mode 100644 index 00000000000..42d7b17d6f4 --- /dev/null +++ b/StationTest/xc_200_setup.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# +# Setup part - Test the SERDES ring between the RSP by verifing the crosslet statistics. +# + +pi=$(echo "4*a(1)" | bc -l) + +nof_subbands=512 + +# Start waveform generators for crosscorrelation measurement + +nof_rcu=32 # nof RCU in a subrack +sample_freq=200000000 +rf_freq=50000000 +xc_subband=$(echo "$nof_subbands * $rf_freq / ($sample_freq/2)" | bc -l) + +for ((i = 0; i < $nof_rcu; i++)) do + phs=$(echo "($i * 2 * $pi) / $nof_rcu" | bc -l) + amp=$(echo "0.498 * $i / $nof_rcu" | bc -l) # use 0.498 for deterministic result, see bug 767 + rspctl --wg=$rf_freq --select=$i --ampli=$amp --phase=$phs +done + +rspctl --xcsubband=$xc_subband diff --git a/StationTest/xc_200_verify.sh b/StationTest/xc_200_verify.sh new file mode 100644 index 00000000000..1fbfe22a32b --- /dev/null +++ b/StationTest/xc_200_verify.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# +# Verify part - Test the SERDES ring between the RSP by verifing the crosslet statistics. +# + +rm -f *.dat +rm -f *.diff + +# Capture crosscorrelation data for 1 sec + +rspctl --xcstat --duration=1 + + +# Verify the captured data, at 200 MHz it is necessary to distinghuis between even or odd sec + +xc_dat=$(ls *.dat) +diff $xc_dat gold/xst_200_even.gold > xst.diff +if [ -e $xc_dat ] && [ -e gold/xst_200_even.gold ] && [ -e xst.diff ] && ! [ -s xst.diff ]; then + # The files exists AND the diff has size 0 + echo "RSP serdes crosscorrelation test even second went OK" +else + diff $xc_dat gold/xst_200_odd.gold > xst.diff + if [ -e $xc_dat ] && [ -e gold/xst_200_odd.gold ] && [ -e xst.diff ] && ! [ -s xst.diff ]; then + # The files exists AND the diff has size 0 + echo "RSP serdes crosscorrelation test odd second went OK" + else + echo "RSP serdes crosscorrelation test went wrong" + fi +fi + -- GitLab