diff options
-rwxr-xr-x | tools/gr-usrptest/examples/lv_control_example.py | 81 | ||||
-rw-r--r-- | tools/gr-usrptest/python/functions.py | 30 | ||||
-rw-r--r-- | tools/gr-usrptest/python/labview_control/CMakeLists.txt | 28 | ||||
-rw-r--r-- | tools/gr-usrptest/python/labview_control/__init__.py | 14 | ||||
-rw-r--r-- | tools/gr-usrptest/python/labview_control/lv_control.py | 87 | ||||
-rw-r--r-- | tools/gr-usrptest/python/rts_tests/CMakeLists.txt | 6 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/gr-usrptest/python/rts_tests/test_phasealignment.py | 93 | ||||
-rw-r--r-- | tools/gr-usrptest/python/setup.py | 13 |
8 files changed, 329 insertions, 23 deletions
diff --git a/tools/gr-usrptest/examples/lv_control_example.py b/tools/gr-usrptest/examples/lv_control_example.py new file mode 100755 index 000000000..dc2a7be2f --- /dev/null +++ b/tools/gr-usrptest/examples/lv_control_example.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +from usrptest.labview_control import lv_control +import time +import numpy as np +import argparse +import sys + +def test00(freq, frange, steps): + freqrange = np.arange(freq,freq+frange,steps) + source = 'VST-Out' + sink = 'X3x0-4-B-RX2' + host = 'pollux' + base_path = 'C:\Users\sdrtest\git\labview-test\labview\RTS_Control\Host\\' + print('connecting to switch') + switch = lv_control.executive_switch(host,base_path,'RTSwitch') + print('connecting to siggen') + siggen = lv_control.vst_siggen(host,base_path,'RIO0') + # Configure RF-Switching + switch.connect_ports(source, sink) + + # Sweep over freqrange + for freq in freqrange: + siggen.set_freq(float(freq)) + time.sleep(1) + # Shutdown Siggen + siggen.disconnect() + switch.disconnect_all() + +def test01(freq, frange, steps): + freqrange = np.arange(freq,freq+frange,steps) + source = 'VST-Out' + sink0 = 'X3x0-4-B-RX2' + sink1 = 'X3x0-2-B-RX2' + host = 'pollux' + base_path = 'C:\Users\sdrtest\git\labview-test\labview\RTS_Control\Host\\' + print('connecting to switch') + switch = lv_control.executive_switch(host,base_path,'RTSwitch') + print('connecting to siggen') + siggen = lv_control.vst_siggen(host,base_path,'RIO0') + for freq in freqrange: + siggen.set_freq(float(freq)) + print('retuning siggen to {freq} MHz'.format(freq=freq/1e6)) + switch.connect_ports(source,sink0) + time.sleep(0.5) + switch.connect_ports(source,sink1) + time.sleep(0.5) + switch.disconnect_all() + time.sleep(0.2) + siggen.disconnect() + switch.disconnect_all() + + +if __name__ == '__main__': + thismodule = sys.modules[__name__] + parser = argparse.ArgumentParser() + parser.add_argument( + '-t', + '--test', + help='which testcase?' + ) + parser.add_argument( + '-f', + '--freq', + type=float, + help='which center freq?' + ) + parser.add_argument( + '-r', + '--range', + type=float, + help='which freq range?' + ) + parser.add_argument( + '--steps', + type=float, + default=1e6, + help='which frequency step size?' + ) + args = parser.parse_args() + getattr(thismodule,args.test)(args.freq,args.range,args.steps) diff --git a/tools/gr-usrptest/python/functions.py b/tools/gr-usrptest/python/functions.py index e3f7958b1..2ce2ee451 100644 --- a/tools/gr-usrptest/python/functions.py +++ b/tools/gr-usrptest/python/functions.py @@ -54,18 +54,42 @@ def setup_tx_phase_alignment_parser(parser): def setup_rts_phase_alignment_parser(parser): - rts_group = parser.add_argument_group('RTS Phase alignment specific arguments') + rts_group = parser.add_argument_group( + 'RTS Phase alignment specific arguments') rts_group.add_argument( - '-pd', '--phasedev', + '-pd', + '--phasedev', type=float, default=1.0, - help='maximum phase standard deviation of dphi in a run which is considered settled (in deg)') + help='maximum phase standard deviation of dphi in a run which is considered settled (in deg)' + ) rts_group.add_argument( '-dp', '--dphi', type=float, default=2.0, help='maximum allowed d_phase deviation between runs (in deg)') + rts_group.add_argument( + '--freqlist', + type=str, + help='comma-separated list of frequencies to test') + rts_group.add_argument( + '--lv-host', + type=str, + help='specify this argument if running tests with vst/switch') + rts_group.add_argument('--lv-vst-name', type=str, help='vst device name') + rts_group.add_argument( + '--lv-switch-name', type=str, help='executive switch name') + rts_group.add_argument( + '--lv-basepath', + type=str, + help='basepath for LabVIEW VIs on Windows') + rts_group.add_argument( + '--tx-offset', + type=float, + help='transmitter frequency offset in VST') + rts_group.add_argument( + '--lv-switch-ports', type=str, help='comma-separated switch-port pair') return parser def setup_manual_phase_alignment_parser(parser): diff --git a/tools/gr-usrptest/python/labview_control/CMakeLists.txt b/tools/gr-usrptest/python/labview_control/CMakeLists.txt new file mode 100644 index 000000000..924df5479 --- /dev/null +++ b/tools/gr-usrptest/python/labview_control/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +######################################################################## +# Install python sources +######################################################################## +GR_PYTHON_INSTALL( + FILES + __init__.py + lv_control.py DESTINATION ${GR_PYTHON_DIR}/usrptest/labview_control +) + diff --git a/tools/gr-usrptest/python/labview_control/__init__.py b/tools/gr-usrptest/python/labview_control/__init__.py new file mode 100644 index 000000000..28d2fe03b --- /dev/null +++ b/tools/gr-usrptest/python/labview_control/__init__.py @@ -0,0 +1,14 @@ +""" +usrptest.labview_control +====================================== + +Contents +-------- + +Subpackages +----------- +:: + +The existance of the file turns the folder into a Python module. + +""" diff --git a/tools/gr-usrptest/python/labview_control/lv_control.py b/tools/gr-usrptest/python/labview_control/lv_control.py new file mode 100644 index 000000000..27407a07c --- /dev/null +++ b/tools/gr-usrptest/python/labview_control/lv_control.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +from labview_automation.client import LabVIEWClient + +class vst_siggen: + def __init__(self,host,vi_base_path,rio_device): + self._host = host + self._path = vi_base_path + self._rio = rio_device + self._caller = lv_caller(host,2552,vi_base_path) + + def __del__(self): + self.disconnect() + + def set_freq(self, freq): + self._caller.vst_set_freq(self._rio,freq) + + def disconnect(self): + try: + self._caller.vst_disconnect(self._rio) + except: + pass + + +class executive_switch: + def __init__(self,host,vi_base_path,device_name): + self._host = host + self._path = vi_base_path + self._device = device_name + self._caller = lv_caller(host,2552,vi_base_path) + + def __del__(self): + self.disconnect_all() + + def connect_ports(self, port0, port1): + self._caller.switch_connect_ports(self._device,port0,port1) + + def disconnect_all(self): + try: + self._caller.switch_disconnect_all(self._device) + except: + pass + + + +class lv_caller: + def __init__(self, host, port, vi_base_path): + self._host = host + self._port = port + self._client = LabVIEWClient(host, port) + self._path = vi_base_path + + def vst_disconnect(self, rio_device): + with self._client as c: + control_values = { + "rio_device": rio_device, + } + result = c.run_vi_synchronous("".join([self._path,"vst_disconnect.vi"]),control_values) + return result + + def vst_set_freq(self, rio_device, freq): + with self._client as c: + control_values = { + "rio_device": rio_device, + "cw_freq": freq, + "power": 0, + } + result = c.run_vi_synchronous("".join([self._path,"vst_set_freq.vi"]),control_values) + return result + + def switch_connect_ports(self, switch_device, port0, port1): + with self._client as c: + control_values = { + "virtual_switch": switch_device, + "chan0": port0, + "chan1": port1, + } + result = c.run_vi_synchronous("".join([self._path,"switch_connect_ports.vi"]),control_values) + return result + + + def switch_disconnect_all(self, switch_device): + with self._client as c: + control_values = { + "virtual_switch": switch_device, + } + result = c.run_vi_synchronous("".join([self._path,"switch_disconnect.vi"]),control_values) + return result diff --git a/tools/gr-usrptest/python/rts_tests/CMakeLists.txt b/tools/gr-usrptest/python/rts_tests/CMakeLists.txt index fbe49995a..03111a9bb 100644 --- a/tools/gr-usrptest/python/rts_tests/CMakeLists.txt +++ b/tools/gr-usrptest/python/rts_tests/CMakeLists.txt @@ -25,3 +25,9 @@ GR_PYTHON_INSTALL( __init__.py test_phasealignment.py DESTINATION ${GR_PYTHON_DIR}/usrptest/rts_tests ) + +GR_PYTHON_INSTALL( + PROGRAMS + test_phasealignment.py + DESTINATION bin +) diff --git a/tools/gr-usrptest/python/rts_tests/test_phasealignment.py b/tools/gr-usrptest/python/rts_tests/test_phasealignment.py index 10642f298..12856bbdb 100644..100755 --- a/tools/gr-usrptest/python/rts_tests/test_phasealignment.py +++ b/tools/gr-usrptest/python/rts_tests/test_phasealignment.py @@ -21,66 +21,106 @@ import unittest from tinydb import TinyDB, Query from usrptest.flowgraphs import phasealignment_fg -from usrptest.functions import setup_phase_alignment_parser, run_test +from usrptest.functions import setup_phase_alignment_parser, setup_tx_phase_alignment_parser, setup_rts_phase_alignment_parser, run_test, log_level +from usrptest.labview_control import lv_control from gnuradio.uhd.uhd_app import UHDApp +import logging +import sys import numpy as np import argparse import time +import copy + class gr_usrp_test(unittest.TestCase): def __init__(self, methodName='runTest', args=None): - super(gr_usrp_test,self).__init__(methodName) + super(gr_usrp_test, self).__init__(methodName) self.args = args + class qa_phasealignment(gr_usrp_test): def setUp(self): + time.sleep(15) #Wait for devices to settle, just in case + if self.args.lv_host is not None: + self.siggen = lv_control.vst_siggen(self.args.lv_host, + self.args.lv_basepath, + self.args.lv_vst_name) + self.switch = lv_control.executive_switch(self.args.lv_host, + self.args.lv_basepath, + self.args.lv_switch_name) + self.siggen.set_freq(self.args.freq + self.args.tx_offset) + self.switch.connect_ports( + *self.args.lv_switch_ports.strip().split(',')) + self.uhd_app = UHDApp(args=self.args) + self.log = logging.getLogger("test_phasealignment") self.tb = phasealignment_fg.phasealignment_fg(self.uhd_app) self.db = TinyDB('phase_db.json') def tearDown(self): self.uhd_app = None self.tb = None + if args.lv_host is not None: + self.siggen.disconnect() + self.switch.disconnect_all() def test_001(self): self.tb.start() time.sleep(2) - results = run_test(self.tb,self.args.runs) # dict key:dev, value: dict{dphase:[],stddev:[]} + results = run_test( + self.tb, + self.args.runs) # dict key:dev, value: dict{dphase:[],stddev:[]} time.sleep(1) - self.first_device = self.tb.measurement_channels_names[:-1] - self.second_device = self.tb.measurement_channels_names[1:] #self.tb.stop() #self.tb.wait() self.time_stamp = time.strftime('%Y%m%d%H%M') self.passed = True - for fdev, sdev in zip(self.first_device,self.second_device): - print('Comparing values for phase difference between {} and {}'.format(fdev, sdev)) - dphase_list = results[fdev]['avg'] - dev_list = results[fdev]['stddev'] + for result in results: + fdev = result['first'] + sdev = result['second'] + self.log.info('Comparing values for phase difference between {} and {}'. + format(fdev, sdev)) + dphase_list = result['avg'] + dev_list = result['stddev'] dphase = np.average(dphase_list) dev = np.average(dev_list) ref_meas = get_reference_meas(self.db, fdev, sdev, self.args.freq) for dphase_i in dphase_list: passed = True if abs(dphase_i - dphase) > self.args.dphi and passed: - print('\t dPhase of a measurement_run differs from average dhpase. dphase_run: {}, dphase_avg: {}'.format(dphase_i, dphase)) + self.log.info( + '\t dPhase of a measurement_run differs from average dhpase. dphase_run: {}, dphase_avg: {}'. + format(dphase_i, dphase)) passed = False if dev > self.args.phasedev: - print('\t dPhase deviates during measurement. stddev: {}'.format(dev)) + self.log.info('\t dPhase deviates during measurement. stddev: {}'. + format(dev)) passed = False if ref_meas: if abs(ref_meas['dphase'] - dphase) > self.args.dphi: - print('\t dPhase differs from reference measurement. Now: {}, reference: {}'.format(dphase, ref_meas['dphase'])) + self.log.info( + '\t dPhase differs from reference measurement. Now: {}, reference: {}'. + format(dphase, ref_meas['dphase'])) if not passed: self.passed = False else: - self.db.insert({'dev1':fdev, 'dev2':sdev, 'timestamp':self.time_stamp, 'dphase':dphase, 'dphase_dev': dev, 'freq': self.args.freq}) + self.db.insert({ + 'dev1': fdev, + 'dev2': sdev, + 'timestamp': self.time_stamp, + 'dphase': dphase, + 'dphase_dev': dev, + 'freq': self.args.freq + }) self.tb.stop() + self.tb.wait() self.assertTrue(self.passed) + def get_previous_meas(db, dev1, dev2, freq): meas = Query() - results = db.search((meas.dev1 == dev1) & (meas.dev2 == dev2) & (meas.freq == freq)) + results = db.search((meas.dev1 == dev1) & (meas.dev2 == dev2) & (meas.freq + == freq)) prev_result = dict() if results: prev_result = results[0] @@ -89,9 +129,11 @@ def get_previous_meas(db, dev1, dev2, freq): prev_result = result return prev_result + def get_reference_meas(db, dev1, dev2, freq): meas = Query() - results = db.search((meas.dev1 == dev1) & (meas.dev2 == dev2) & (meas.freq == freq)) + results = db.search((meas.dev1 == dev1) & (meas.dev2 == dev2) & (meas.freq + == freq)) ref_result = dict() if results: ref_result = results[0] @@ -101,21 +143,32 @@ def get_reference_meas(db, dev1, dev2, freq): return ref_result - if __name__ == '__main__': + # parse all arguments parser = argparse.ArgumentParser(conflict_handler='resolve') parser = setup_phase_alignment_parser(parser) + parser = setup_tx_phase_alignment_parser(parser) + parser = setup_rts_phase_alignment_parser(parser) + logging.basicConfig(stream=sys.stdout) UHDApp.setup_argparser(parser=parser) args = parser.parse_args() - def make_suite(testcase_class): + logging.getLogger("test_phasealignment").setLevel(log_level(args.log_level)) + + freqlist = args.freqlist.strip().split(',') + + def make_suite(testcase_class, freqlist): testloader = unittest.TestLoader() testnames = testloader.getTestCaseNames(testcase_class) suite = unittest.TestSuite() for name in testnames: - suite.addTest(testcase_class(name, args=args)) + for freq in freqlist: + test_args = copy.deepcopy(args) + test_args.freq = float(freq) + suite.addTest(testcase_class(name, args=test_args)) return suite # Add tests. alltests = unittest.TestSuite() - alltests.addTest(make_suite(qa_phasealignment)) - result = unittest.TextTestRunner(verbosity=2).run(alltests) # Run tests. + alltests.addTest(make_suite(qa_phasealignment, freqlist)) + result = unittest.TextTestRunner(verbosity=2).run(alltests) # Run tests. + sys.exit(not result.wasSuccessful()) diff --git a/tools/gr-usrptest/python/setup.py b/tools/gr-usrptest/python/setup.py new file mode 100644 index 000000000..6969f413d --- /dev/null +++ b/tools/gr-usrptest/python/setup.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +try: + from setuptools import setup +except ImportError: + from distutils.core import setup + + +setup(name='urptest_automation', + version='0.0.1', + description='usrptest integration into RTS and Labview', + packages=['usrptest_automation'], + install_requires=['labview-automation>=15.0.0.dev1','hoplite>=15.0.0.dev1'] + ) |