srsLTE: Support configuring different RF backends

Before this patch, only virtual RF through ZeroMQ was supported.
This patch allows configuring srsUE and srsENB to use a real SDR with
UHD/SoapySDR backend connected through a physical RF network, while
still keeping compatibility to run on virtual RF ZeroMQ network, based
on the resources used (controlled by scenarios). For instance, one can
first run a suite through the phyisical RF (using 2 UHD-controlled SDRs)
and afterwards with ZeroMQ using the following default-suites.conf:

- 4g:srsenb-rftype-uhd+srsue-rftype-uhd
- 4g:srsenb-rftype-zmq+srsue-rftype-zmq

Change-Id: I7dbbe328f4c0225fe74e878bb2da13fe39ccf049
diff --git a/src/osmo_gsm_tester/resource.py b/src/osmo_gsm_tester/resource.py
index 0804591..e8ca859 100644
--- a/src/osmo_gsm_tester/resource.py
+++ b/src/osmo_gsm_tester/resource.py
@@ -89,7 +89,8 @@
         'enb[].type': schema.STR,
         'enb[].remote_user': schema.STR,
         'enb[].addr': schema.IPV4,
-        'enb[].band': schema.BAND,
+        'enb[].rf_dev_type': schema.STR,
+        'enb[].rf_dev_args': schema.STR,
         'arfcn[].arfcn': schema.INT,
         'arfcn[].band': schema.BAND,
         'modem[].type': schema.STR,
@@ -102,6 +103,8 @@
         'modem[].addr': schema.IPV4,
         'modem[].ciphers[]': schema.CIPHER,
         'modem[].features[]': schema.MODEM_FEATURE,
+        'modem[].rf_dev_type': schema.STR,
+        'modem[].rf_dev_args': schema.STR,
         'osmocon_phone[].serial_device': schema.STR,
     }
 
diff --git a/src/osmo_gsm_tester/srs_enb.py b/src/osmo_gsm_tester/srs_enb.py
index 2b65a5b..6fb186f 100644
--- a/src/osmo_gsm_tester/srs_enb.py
+++ b/src/osmo_gsm_tester/srs_enb.py
@@ -22,6 +22,9 @@
 
 from . import log, util, config, template, process, remote
 
+def rf_type_valid(rf_type_str):
+    return rf_type_str in ('zmq', 'UHD', 'soapy', 'bladeRF')
+
 class srsENB(log.Origin):
 
     REMOTE_DIR = '/osmo-gsm-tester-srsenb'
@@ -34,6 +37,7 @@
 
     def __init__(self, suite_run, conf):
         super().__init__(log.C_RUN, 'srsenb')
+        self._conf = conf
         self._addr = conf.get('addr', None)
         if self._addr is None:
             raise log.Error('addr not set')
@@ -59,6 +63,8 @@
         else:
           self.base_srate=23.04e6
         self.remote_user = conf.get('remote_user', None)
+        if not rf_type_valid(conf.get('rf_dev_type', None)):
+            raise log.Error('Invalid rf_dev_type=%s' % conf.get('rf_dev_type', None))
 
     def cleanup(self):
         if self.process is None:
@@ -117,8 +123,6 @@
                 '--enb_files.sib_config=' + self.remote_config_sib_file,
                 '--enb_files.rr_config=' + self.remote_config_rr_file,
                 '--enb_files.drb_config=' + self.remote_config_drb_file,
-                '--rf.device_name=zmq',
-                '--rf.device_args="fail_on_disconnect=true,tx_port=tcp://'+ self.addr() +':2000,rx_port=tcp://'+ self.ue.addr() +':2001,id=enb,base_srate='+ str(self.base_srate) + '"',
                 '--expert.nof_phy_threads=1',
                 '--expert.rrc_inactivity_timer=1500',
                 '--enb.n_prb=' + str(self.nof_prb),
@@ -145,8 +149,6 @@
                 '--enb_files.sib_config=' + os.path.abspath(self.config_sib_file),
                 '--enb_files.rr_config=' + os.path.abspath(self.config_rr_file),
                 '--enb_files.drb_config=' + os.path.abspath(self.config_drb_file),
-                '--rf.device_name=zmq',
-                '--rf.device_args="fail_on_disconnect=true,tx_port=tcp://'+ self.addr() +':2000,rx_port=tcp://'+ self.ue.addr() +':2001,id=enb,base_srate='+ str(self.base_srate) + '"',
                 '--expert.nof_phy_threads=1',
                 '--expert.rrc_inactivity_timer=1500',
                 '--enb.n_prb=' + str(self.nof_prb),
@@ -161,8 +163,12 @@
 
         values = dict(enb=config.get_defaults('srsenb'))
         config.overlay(values, self.suite_run.config())
-        config.overlay(values, dict(enb={ 'run_addr': self.addr(),
-                                          'mme_addr': self.epc.addr()}))
+        config.overlay(values, dict(enb=self._conf))
+        config.overlay(values, dict(enb={ 'mme_addr': self.epc.addr() }))
+
+        # We need to set some specific variables programatically here to match IP addresses:
+        if self._conf.get('rf_dev_type') == 'zmq':
+            config.overlay(values, dict(enb=dict(rf_dev_args='fail_on_disconnect=true,tx_port=tcp://'+ self.addr() +':2000,rx_port=tcp://'+ self.ue.addr() +':2001,id=enb,base_srate='+ str(self.base_srate))))
 
         self.dbg('srsENB ' + filename + ':\n' + pprint.pformat(values))
 
diff --git a/src/osmo_gsm_tester/srs_ue.py b/src/osmo_gsm_tester/srs_ue.py
index c68c726..4a99ad9 100644
--- a/src/osmo_gsm_tester/srs_ue.py
+++ b/src/osmo_gsm_tester/srs_ue.py
@@ -24,6 +24,9 @@
 from .run_node import RunNode
 from .ms import MS
 
+def rf_type_valid(rf_type_str):
+    return rf_type_str in ('zmq', 'UHD', 'soapy', 'bladeRF')
+
 class srsUE(MS):
 
     REMOTE_DIR = '/osmo-gsm-tester-srsue'
@@ -54,6 +57,8 @@
         else:
           self.base_srate=23.04e6
         self.remote_user = conf.get('remote_user', None)
+        if not rf_type_valid(conf.get('rf_dev_type', None)):
+            raise log.Error('Invalid rf_dev_type=%s' % conf.get('rf_dev_type', None))
 
     def cleanup(self):
         if self.process is None:
@@ -122,8 +127,6 @@
 
         #'strace', '-ff',
         args = (remote_binary, self.remote_config_file,
-                '--rf.device_name=zmq',
-                '--rf.device_args="tx_port=tcp://'+ self.addr() +':2001,rx_port=tcp://'+ self.enb.addr() +':2000,id=ue,base_srate='+ str(self.base_srate) + '"',
                 '--phy.nof_phy_threads=1',
                 '--gw.netns=' + self.netns(),
                 '--log.filename=' + 'stdout', #self.remote_log_file,
@@ -157,8 +160,6 @@
         util.setcap_netsys_admin(binary, self.run_dir.new_dir('setcap_netsys_admin'))
 
         args = (binary, os.path.abspath(self.config_file),
-                '--rf.device_name=zmq',
-                '--rf.device_args="tx_port=tcp://'+ self.addr() +':2001,rx_port=tcp://'+ self.enb.addr() +':2000,id=ue,base_srate='+ str(self.base_srate) + '"',
                 '--phy.nof_phy_threads=1',
                 '--gw.netns=' + self.netns(),
                 '--log.filename=' + self.log_file,
@@ -180,6 +181,10 @@
         config.overlay(values, self.suite_run.config())
         config.overlay(values, dict(ue=self._conf))
 
+        # We need to set some specific variables programatically here to match IP addresses:
+        if self._conf.get('rf_dev_type') == 'zmq':
+            config.overlay(values, dict(ue=dict(rf_dev_args='tx_port=tcp://'+ self.addr() +':2001,rx_port=tcp://'+ self.enb.addr() +':2000,id=ue,base_srate='+ str(self.base_srate))))
+
         self.dbg('SRSUE CONFIG:\n' + pprint.pformat(values))
 
         with open(self.config_file, 'w') as f:
diff --git a/src/osmo_gsm_tester/templates/srsenb.conf.tmpl b/src/osmo_gsm_tester/templates/srsenb.conf.tmpl
index 0eba35b..2006832 100644
--- a/src/osmo_gsm_tester/templates/srsenb.conf.tmpl
+++ b/src/osmo_gsm_tester/templates/srsenb.conf.tmpl
@@ -26,8 +26,8 @@
 mcc = ${enb.mcc}
 mnc = ${enb.mnc}
 mme_addr = ${enb.mme_addr}
-gtp_bind_addr = ${enb.run_addr}
-s1c_bind_addr = ${enb.run_addr}
+gtp_bind_addr = ${enb.addr}
+s1c_bind_addr = ${enb.addr}
 n_prb = 50
 #tm = 4
 #nof_ports = 2
@@ -70,7 +70,7 @@
 tx_gain = 80
 rx_gain = 40
 
-#device_name = auto
+device_name = ${enb.rf_dev_type}
 
 # For best performance in 2x2 MIMO and >= 15 MHz use the following device_args settings:
 #     USRP B210: num_recv_frames=64,num_send_frames=64
@@ -78,7 +78,7 @@
 # For best performance when BW<5 MHz (25 PRB), use the following device_args settings:
 #     USRP B210: send_frame_size=512,recv_frame_size=512
 
-#device_args = auto
+device_args = ${enb.rf_dev_args}
 #time_adv_nsamples = auto
 #burst_preamble_us = auto
 
diff --git a/src/osmo_gsm_tester/templates/srsue.conf.tmpl b/src/osmo_gsm_tester/templates/srsue.conf.tmpl
index 5e5676d..eef5a7e 100644
--- a/src/osmo_gsm_tester/templates/srsue.conf.tmpl
+++ b/src/osmo_gsm_tester/templates/srsue.conf.tmpl
@@ -39,13 +39,15 @@
 #nof_radios = 1
 #nof_rx_ant = 1
 
+device_name = ${ue.rf_dev_type}
+
 # For best performance in 2x2 MIMO and >= 15 MHz use the following device_args settings:
 #     USRP B210: num_recv_frames=64,num_send_frames=64
 
 # For best performance when BW<5 MHz (25 PRB), use the following device_args settings:
 #     USRP B210: send_frame_size=512,recv_frame_size=512
 
-#device_args = auto
+device_args = ${ue.rf_dev_args}
 #time_adv_nsamples = auto
 #burst_preamble_us = auto
 #continuous_tx     = auto