diff options
| author | Andrej Rode <andrej.rode@ettus.com> | 2016-10-19 16:41:59 -0700 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2017-05-26 16:01:37 -0700 | 
| commit | 4b7b35570c13766ed575f69d79bf1ded954b6886 (patch) | |
| tree | a07e385db0e3e6adca71a2b3c817993e0b2c8422 /tools/gr-usrptest/python | |
| parent | 76e9e6393fe1d5a0ccc9e05deb431694921850ec (diff) | |
| download | uhd-4b7b35570c13766ed575f69d79bf1ded954b6886.tar.gz uhd-4b7b35570c13766ed575f69d79bf1ded954b6886.tar.bz2 uhd-4b7b35570c13766ed575f69d79bf1ded954b6886.zip  | |
gr-usrptest: add LabVIEW remote control capability
 - require modules labview_automation and hoplite for RTS python module
 - new python module: labview_control
Diffstat (limited to 'tools/gr-usrptest/python')
| -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 | 
7 files changed, 248 insertions, 23 deletions
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'] +        )  | 
