<p>srs_andre would like Nils to <strong>review</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/21217">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Modems: Introduce Android UEs<br><br>To expand the test capacities we would like to introduce<br>Android UEs as a new modem. Currently the following tests<br>are supported:<br>- Ping<br>- iPerf3 DL/UL<br>- RRC Mobile MT Ping<br><br>Change-Id: Iab37a0de59d6643d21bced34ddca06ff40fa62df<br>---<br>M src/osmo_gsm_tester/core/process.py<br>M src/osmo_gsm_tester/core/remote.py<br>M src/osmo_gsm_tester/core/schema.py<br>M src/osmo_gsm_tester/obj/enb_srs.py<br>M src/osmo_gsm_tester/obj/iperf3.py<br>M src/osmo_gsm_tester/obj/ms.py<br>A src/osmo_gsm_tester/obj/ms_android.py<br>M src/osmo_gsm_tester/obj/run_node.py<br>M sysmocom/default-suites.conf<br>A sysmocom/scenarios/androidue@.conf<br>M sysmocom/suites/4g/iperf3_dl.py<br>M sysmocom/suites/4g/iperf3_ul.py<br>A utils/bin/osmo-gsm-tester_androidue_conn_chk.sh<br>A utils/bin/osmo-gsm-tester_androidue_diag_parser.sh<br>14 files changed, 607 insertions(+), 12 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-gsm-tester refs/changes/17/21217/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/osmo_gsm_tester/core/process.py b/src/osmo_gsm_tester/core/process.py</span><br><span>index eaf8de7..5840881 100644</span><br><span>--- a/src/osmo_gsm_tester/core/process.py</span><br><span>+++ b/src/osmo_gsm_tester/core/process.py</span><br><span>@@ -381,12 +381,24 @@</span><br><span> </span><br><span> class RemoteProcess(Process):</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def __init__(self, name, run_dir, remote_user, remote_host, remote_cwd, popen_args, remote_env={}, **popen_kwargs):</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, name, run_dir, remote_user, remote_host, remote_cwd, popen_args,</span><br><span style="color: hsl(120, 100%, 40%);">+                 remote_env={}, remote_port=None, **popen_kwargs):</span><br><span>         super().__init__(name, run_dir, popen_args, **popen_kwargs)</span><br><span>         self.remote_user = remote_user</span><br><span>         self.remote_host = remote_host</span><br><span>         self.remote_cwd = remote_cwd</span><br><span>         self.remote_env = remote_env</span><br><span style="color: hsl(120, 100%, 40%);">+        self.remote_port = remote_port</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # check if the command should be executed on an Android UE</span><br><span style="color: hsl(120, 100%, 40%);">+        is_ue_cmd = False</span><br><span style="color: hsl(120, 100%, 40%);">+        android_cmds = ['iperf3-cli', 'ping', 'set-airplane-mode', 'set-apn', 'get-ip',</span><br><span style="color: hsl(120, 100%, 40%);">+                        'rx-monitor', 'tx-monitor', 'diag-monitor', 'kill-diag-monitor', 'clear-diag_logs']</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.remote_port:</span><br><span style="color: hsl(120, 100%, 40%);">+            for cmd in android_cmds:</span><br><span style="color: hsl(120, 100%, 40%);">+                if cmd in name:</span><br><span style="color: hsl(120, 100%, 40%);">+                    self.remote_user = 'root'</span><br><span style="color: hsl(120, 100%, 40%);">+                    is_ue_cmd = True</span><br><span> </span><br><span>         # hacky: instead of just prepending ssh, i.e. piping stdout and stderr</span><br><span>         # over the ssh link, we should probably run on the remote side,</span><br><span>@@ -402,6 +414,12 @@</span><br><span>                            '%s %s %s' % (cd,</span><br><span>                                          ' '.join(['%s=%r'%(k,v) for k,v in self.remote_env.items()]),</span><br><span>                                          ' '.join(self.popen_args))]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # add arguments to directly connect to the Android UE</span><br><span style="color: hsl(120, 100%, 40%);">+        if is_ue_cmd:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.popen_args.insert(1, '-p')  # add ssh parameters</span><br><span style="color: hsl(120, 100%, 40%);">+            self.popen_args.insert(2, str(self.remote_port))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         self.dbg(self.popen_args, dir=self.run_dir, conf=self.popen_kwargs, remote_env=self.remote_env)</span><br><span> </span><br><span>     def RunError(self, msg_prefix):</span><br><span>@@ -443,14 +461,21 @@</span><br><span>         super().__init__(name, run_dir, remote_user, remote_host, remote_cwd, args, **popen_kwargs)</span><br><span> </span><br><span> def run_local_sync(run_dir, name, popen_args):</span><br><span style="color: hsl(0, 100%, 40%);">-    run_dir =run_dir.new_dir(name)</span><br><span style="color: hsl(120, 100%, 40%);">+    run_dir = run_dir.new_dir(name)</span><br><span>     proc = Process(name, run_dir, popen_args)</span><br><span>     proc.launch_sync()</span><br><span>     return proc</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+def run_local(run_dir, name, popen_args):</span><br><span style="color: hsl(120, 100%, 40%);">+    run_dir = run_dir.new_dir(name)</span><br><span style="color: hsl(120, 100%, 40%);">+    proc = Process(name, run_dir, popen_args)</span><br><span style="color: hsl(120, 100%, 40%);">+    proc.launch()</span><br><span style="color: hsl(120, 100%, 40%);">+    return proc</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> def run_local_netns_sync(run_dir, name, netns, popen_args):</span><br><span style="color: hsl(0, 100%, 40%);">-    run_dir =run_dir.new_dir(name)</span><br><span style="color: hsl(120, 100%, 40%);">+    run_dir = run_dir.new_dir(name)</span><br><span>     proc = NetNSProcess(name, run_dir, netns, popen_args)</span><br><span>     proc.launch_sync()</span><br><span>     return proc</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # vim: expandtab tabstop=4 shiftwidth=4</span><br><span>diff --git a/src/osmo_gsm_tester/core/remote.py b/src/osmo_gsm_tester/core/remote.py</span><br><span>index 8deb25d..ef77c2cd 100644</span><br><span>--- a/src/osmo_gsm_tester/core/remote.py</span><br><span>+++ b/src/osmo_gsm_tester/core/remote.py</span><br><span>@@ -28,13 +28,14 @@</span><br><span> </span><br><span>     WRAPPER_SCRIPT = 'ssh_sigkiller.sh'</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def __init__(self, run_dir, remote_user = 'root', remote_host = 'localhost', remote_cwd=None):</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, run_dir, remote_user = 'root', remote_host = 'localhost', remote_cwd=None, remote_port=None):</span><br><span>         super().__init__(log.C_RUN, 'host-' + remote_user + '@' + remote_host)</span><br><span>         self.run_dir = util.Dir(run_dir.new_dir(self.name()))</span><br><span>         self.remote_user = remote_user</span><br><span>         self.remote_host = remote_host</span><br><span>         self.remote_cwd = remote_cwd</span><br><span>         self.remote_env = {}</span><br><span style="color: hsl(120, 100%, 40%);">+        self.remote_port = remote_port</span><br><span> </span><br><span>     def user(self):</span><br><span>         return self.remote_user</span><br><span>@@ -51,9 +52,13 @@</span><br><span>     def get_remote_env(self):</span><br><span>         return self.remote_env</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    def ssh_port(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        return self.remote_port</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def RemoteProcess(self, name, popen_args, remote_env={}, **popen_kwargs):</span><br><span>         run_dir = self.run_dir.new_dir(name)</span><br><span style="color: hsl(0, 100%, 40%);">-        return process.RemoteProcess(name, run_dir, self.user(), self.host(), self.cwd(), popen_args, remote_env=remote_env, **popen_kwargs)</span><br><span style="color: hsl(120, 100%, 40%);">+        return process.RemoteProcess(name, run_dir, self.user(), self.host(), self.cwd(), popen_args,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     remote_env=remote_env, remote_port=self.ssh_port(), **popen_kwargs)</span><br><span> </span><br><span>     def generate_wrapper_script(self, wait_time_sec):</span><br><span>         wrapper_script = self.run_dir.new_file(RemoteHost.WRAPPER_SCRIPT)</span><br><span>diff --git a/src/osmo_gsm_tester/core/schema.py b/src/osmo_gsm_tester/core/schema.py</span><br><span>index d56d6ec..6496e57 100644</span><br><span>--- a/src/osmo_gsm_tester/core/schema.py</span><br><span>+++ b/src/osmo_gsm_tester/core/schema.py</span><br><span>@@ -111,7 +111,7 @@</span><br><span>     raise ValueError('Unknown Cipher value: %r' % val)</span><br><span> </span><br><span> def modem_feature(val):</span><br><span style="color: hsl(0, 100%, 40%);">-    if val in ('sms', 'gprs', 'voice', 'ussd', 'sim', '2g', '3g', '4g', 'dl_qam256', 'ul_qam64'):</span><br><span style="color: hsl(120, 100%, 40%);">+    if val in ('sms', 'gprs', 'voice', 'ussd', 'sim', '2g', '3g', '4g', 'dl_qam256', 'ul_qam64', 'qc_diag'):</span><br><span>         return True</span><br><span>     raise ValueError('Unknown Modem Feature: %r' % val)</span><br><span> </span><br><span>diff --git a/src/osmo_gsm_tester/obj/enb_srs.py b/src/osmo_gsm_tester/obj/enb_srs.py</span><br><span>index 53beda8..307368f 100644</span><br><span>--- a/src/osmo_gsm_tester/obj/enb_srs.py</span><br><span>+++ b/src/osmo_gsm_tester/obj/enb_srs.py</span><br><span>@@ -114,6 +114,7 @@</span><br><span>             self.start_remotely()</span><br><span> </span><br><span>         # send t+Enter to enable console trace</span><br><span style="color: hsl(120, 100%, 40%);">+        MainLoop.sleep(3)</span><br><span>         self.dbg('Enabling console trace')</span><br><span>         self.process.stdin_write('t\n')</span><br><span> </span><br><span>diff --git a/src/osmo_gsm_tester/obj/iperf3.py b/src/osmo_gsm_tester/obj/iperf3.py</span><br><span>index 4785f78..f0309d2 100644</span><br><span>--- a/src/osmo_gsm_tester/obj/iperf3.py</span><br><span>+++ b/src/osmo_gsm_tester/obj/iperf3.py</span><br><span>@@ -232,7 +232,7 @@</span><br><span>         locally = not self._run_node or self._run_node.is_local()</span><br><span>         return locally</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def prepare_test_proc(self, dir=None, netns=None, time_sec=None, proto=None, bitrate=0, tos=None):</span><br><span style="color: hsl(120, 100%, 40%);">+    def prepare_test_proc(self, dir=None, netns=None, time_sec=None, proto=None, bitrate=0, tos=None, ue=None):</span><br><span>         values = config.get_defaults('iperf3cli')</span><br><span>         config.overlay(values, self.testenv.suite().config().get('iperf3cli', {}))</span><br><span> </span><br><span>@@ -264,6 +264,12 @@</span><br><span>         popen_args = ('iperf3', '-c',  self.server.addr(),</span><br><span>                       '-p', str(self.server.port()), '-J',</span><br><span>                       '-t', str(time_sec))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # In case the modem is an Android UE we have to extend the iPerf3 command for local execution</span><br><span style="color: hsl(120, 100%, 40%);">+        if self._run_node.is_local() and ue.ue_serial:</span><br><span style="color: hsl(120, 100%, 40%);">+            adb_cmd_pref = ['adb', '-s', ue.ue_serial, 'exec-out', 'su', '-c']</span><br><span style="color: hsl(120, 100%, 40%);">+            popen_args = adb_cmd_pref + list(popen_args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         if dir == IPerf3Client.DIR_DL:</span><br><span>             popen_args += ('-R',)</span><br><span>         elif dir == IPerf3Client.DIR_BI:</span><br><span>@@ -281,7 +287,8 @@</span><br><span>         return proc</span><br><span> </span><br><span>     def prepare_test_proc_remotely(self, netns, popen_args):</span><br><span style="color: hsl(0, 100%, 40%);">-        self.rem_host = remote.RemoteHost(self.run_dir, self._run_node.ssh_user(), self._run_node.ssh_addr())</span><br><span style="color: hsl(120, 100%, 40%);">+        self.rem_host = remote.RemoteHost(self.run_dir, self._run_node.ssh_user(), self._run_node.ssh_addr(),</span><br><span style="color: hsl(120, 100%, 40%);">+                                          None, self._run_node.ssh_port())</span><br><span> </span><br><span>         remote_prefix_dir = util.Dir(IPerf3Client.REMOTE_DIR)</span><br><span>         remote_run_dir = util.Dir(remote_prefix_dir.child('cli-' + str(self)))</span><br><span>diff --git a/src/osmo_gsm_tester/obj/ms.py b/src/osmo_gsm_tester/obj/ms.py</span><br><span>index 70ce558..bfd3f3b 100644</span><br><span>--- a/src/osmo_gsm_tester/obj/ms.py</span><br><span>+++ b/src/osmo_gsm_tester/obj/ms.py</span><br><span>@@ -72,6 +72,9 @@</span><br><span>         elif ms_type == 'srsue':</span><br><span>             from .ms_srs import srsUE</span><br><span>             ms_class = srsUE</span><br><span style="color: hsl(120, 100%, 40%);">+        elif ms_type == 'androidue':</span><br><span style="color: hsl(120, 100%, 40%);">+            from .ms_android import AndroidUE</span><br><span style="color: hsl(120, 100%, 40%);">+            ms_class = AndroidUE</span><br><span>         elif ms_type == 'amarisoftue':</span><br><span>             from .ms_amarisoft import AmarisoftUE</span><br><span>             ms_class = AmarisoftUE</span><br><span>diff --git a/src/osmo_gsm_tester/obj/ms_android.py b/src/osmo_gsm_tester/obj/ms_android.py</span><br><span>new file mode 100644</span><br><span>index 0000000..0d9ed16</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo_gsm_tester/obj/ms_android.py</span><br><span>@@ -0,0 +1,526 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# Author: Nils Fürste <nils.fuerste@softwareradiosystems.com></span><br><span style="color: hsl(120, 100%, 40%);">+# Author: Bedran Karakoc <bedran.karakoc@softwareradiosystems.com></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import pprint</span><br><span style="color: hsl(120, 100%, 40%);">+import time</span><br><span style="color: hsl(120, 100%, 40%);">+import re</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from ..core import log, util, config, remote, process</span><br><span style="color: hsl(120, 100%, 40%);">+from ..core import schema</span><br><span style="color: hsl(120, 100%, 40%);">+from .run_node import RunNode</span><br><span style="color: hsl(120, 100%, 40%);">+from .ms import MS</span><br><span style="color: hsl(120, 100%, 40%);">+from .srslte_common import srslte_common</span><br><span style="color: hsl(120, 100%, 40%);">+from .ms_srs import srsUEMetrics</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def on_register_schemas():</span><br><span style="color: hsl(120, 100%, 40%);">+    resource_schema = {</span><br><span style="color: hsl(120, 100%, 40%);">+        'additional_args[]': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'apn': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'apn_name': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'apn_mcc': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'apn_mnc': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'sel_apn': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'ue_serial': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'enable_pcap': schema.BOOL_STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+    for key, val in RunNode.schema().items():</span><br><span style="color: hsl(120, 100%, 40%);">+        resource_schema['run_node.%s' % key] = val</span><br><span style="color: hsl(120, 100%, 40%);">+    schema.register_resource_schema('modem', resource_schema)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    config_schema = {</span><br><span style="color: hsl(120, 100%, 40%);">+        'enable_pcap': schema.BOOL_STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'log_all_level': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+    schema.register_config_schema('modem', config_schema)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class AndroidUE(MS, srslte_common):</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    REMOTEDIR = '/osmo-gsm-tester-androidue'</span><br><span style="color: hsl(120, 100%, 40%);">+    METRICSFILE = 'android_ue_metrics.csv'</span><br><span style="color: hsl(120, 100%, 40%);">+    PCAPFILE = 'android_ue.pcap'</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, testenv, conf):</span><br><span style="color: hsl(120, 100%, 40%);">+        self._run_node = RunNode.from_conf(conf.get('run_node', {}))</span><br><span style="color: hsl(120, 100%, 40%);">+        super().__init__('androidue_%s' % self.addr(), testenv, conf)</span><br><span style="color: hsl(120, 100%, 40%);">+        srslte_common.__init__(self)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.run_dir = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.rem_host = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.testenv = testenv</span><br><span style="color: hsl(120, 100%, 40%);">+        self.emm_connected = False</span><br><span style="color: hsl(120, 100%, 40%);">+        self.rrc_connected = False</span><br><span style="color: hsl(120, 100%, 40%);">+        self.connect_timeout = 300  # sec</span><br><span style="color: hsl(120, 100%, 40%);">+        self.ue_serial = None  # stores the UE serial if available</span><br><span style="color: hsl(120, 100%, 40%);">+        self.remote_port = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.conn_reset_intvl = 20</span><br><span style="color: hsl(120, 100%, 40%);">+        self.remote_pcap_file = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.pcap_file = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.ue_data_intf = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.remote_metrics_file = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.metrics_file = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.remote_run_dir = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.have_metrics_file = False</span><br><span style="color: hsl(120, 100%, 40%);">+        self.rx_monitor_proc = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.tx_monitor_proc = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.diag_monitor_proc = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.diag_parser_proc = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.enable_pcap = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def cleanup(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.process is None:</span><br><span style="color: hsl(120, 100%, 40%);">+            return</span><br><span style="color: hsl(120, 100%, 40%);">+        if self._run_node.is_local():</span><br><span style="color: hsl(120, 100%, 40%);">+            return</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # stop monitoring</span><br><span style="color: hsl(120, 100%, 40%);">+        self.stop()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def scp_back_pcap(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.enable_pcap:</span><br><span style="color: hsl(120, 100%, 40%);">+            DIAG_PARSER = 'osmo-gsm-tester_androidue_diag_parser.sh'</span><br><span style="color: hsl(120, 100%, 40%);">+            if not self._run_node.is_local():</span><br><span style="color: hsl(120, 100%, 40%);">+                popen_args_diag_parser = [DIAG_PARSER, str(self.ue_serial), str(self.remote_run_dir), str(self.remote_pcap_file)]</span><br><span style="color: hsl(120, 100%, 40%);">+                diag_parser_proc = self.rem_host.RemoteProcess("diag-parser", popen_args_diag_parser, env={})</span><br><span style="color: hsl(120, 100%, 40%);">+                diag_parser_proc.launch()</span><br><span style="color: hsl(120, 100%, 40%);">+            else:</span><br><span style="color: hsl(120, 100%, 40%);">+                popen_args_diag_parser = [DIAG_PARSER, str(self.ue_serial), str(self.run_dir), str(self.pcap_file)]</span><br><span style="color: hsl(120, 100%, 40%);">+                diag_parser_proc = process.run_local(self.run_dir, "diag-parser", popen_args_diag_parser)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            timeout_ = 300  # timeout in s</span><br><span style="color: hsl(120, 100%, 40%);">+            while timeout_ > 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                diag_parser_stdout = diag_parser_proc.get_stdout()</span><br><span style="color: hsl(120, 100%, 40%);">+                if diag_parser_stdout.count('Pulling new .qmdl file...') > 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                    # If the parsers pulls the .qmdl file for the second time we know that</span><br><span style="color: hsl(120, 100%, 40%);">+                    # the parsing of the first one is done</span><br><span style="color: hsl(120, 100%, 40%);">+                    break</span><br><span style="color: hsl(120, 100%, 40%);">+                time.sleep(2)</span><br><span style="color: hsl(120, 100%, 40%);">+                timeout_ -= 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            if timeout_ <= 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                raise log.Error("Writing PCAP failed")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            if not self._run_node.is_local():</span><br><span style="color: hsl(120, 100%, 40%);">+                try:</span><br><span style="color: hsl(120, 100%, 40%);">+                    self.rem_host.scpfrom('scp-back-pcap', self.remote_pcap_file, self.pcap_file)</span><br><span style="color: hsl(120, 100%, 40%);">+                except Exception as e:</span><br><span style="color: hsl(120, 100%, 40%);">+                    self.log(repr(e))</span><br><span style="color: hsl(120, 100%, 40%);">+            else:</span><br><span style="color: hsl(120, 100%, 40%);">+                pass</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def stop(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        # terminate bitrate monitors and save metrics</span><br><span style="color: hsl(120, 100%, 40%);">+        brate_rx_raw = self.rx_monitor_proc.get_stdout().split('\n')</span><br><span style="color: hsl(120, 100%, 40%);">+        brate_tx_raw = self.tx_monitor_proc.get_stdout().split('\n')</span><br><span style="color: hsl(120, 100%, 40%);">+        brate_rx_raw.remove('')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.rx_monitor_proc.terminate()</span><br><span style="color: hsl(120, 100%, 40%);">+        brate_tx_raw.remove('')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.tx_monitor_proc.terminate()</span><br><span style="color: hsl(120, 100%, 40%);">+        self.save_metrics(brate_rx_raw[1:], brate_tx_raw[1:])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # kill diag monitor if started</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.diag_monitor_proc:</span><br><span style="color: hsl(120, 100%, 40%);">+            kill_diag_proc = self.rem_host.RemoteProcess("kill-diag-monitor", ['/vendor/bin/diag_mdlog', '-k'], env={})</span><br><span style="color: hsl(120, 100%, 40%);">+            kill_diag_proc.launch_sync()</span><br><span style="color: hsl(120, 100%, 40%);">+            time.sleep(3)</span><br><span style="color: hsl(120, 100%, 40%);">+            if self.diag_monitor_proc.is_running():</span><br><span style="color: hsl(120, 100%, 40%);">+                self.diag_monitor_proc.terminate()</span><br><span style="color: hsl(120, 100%, 40%);">+            self.diag_parser_proc.terminate()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # enable airplane mode</span><br><span style="color: hsl(120, 100%, 40%);">+        self.set_airplane_mode(True)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # scp back pcap file</span><br><span style="color: hsl(120, 100%, 40%);">+        self.scp_back_pcap()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def start(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        # check if device is available over ADB</span><br><span style="color: hsl(120, 100%, 40%);">+        if not self.check_device_availability():</span><br><span style="color: hsl(120, 100%, 40%);">+            self.log("Can't find requested device. Restarting ADB and check again")</span><br><span style="color: hsl(120, 100%, 40%);">+            self.restart_adb_inst(True)</span><br><span style="color: hsl(120, 100%, 40%);">+            if not self.check_device_availability():</span><br><span style="color: hsl(120, 100%, 40%);">+                raise log.Error("Device with serial %s is not available" % self.ue_serial)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # enable airplane mode</span><br><span style="color: hsl(120, 100%, 40%);">+        self.set_airplane_mode(True)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # clear working directories</span><br><span style="color: hsl(120, 100%, 40%);">+        self.clear_work_dirs()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def clear_work_dirs(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        # clear remote_run_dir</span><br><span style="color: hsl(120, 100%, 40%);">+        popen_args_clear_run_dir = ['sudo', 'rm', '-rf', '-v', str(self.remote_run_dir) + '/*', '||', 'true']</span><br><span style="color: hsl(120, 100%, 40%);">+        clear_run_dir_proc = self.run_netns_wait('clear-run_dir', popen_args_clear_run_dir)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg("Deleted the following files: %s" % clear_run_dir_proc.get_stdout())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # clear diag_logs</span><br><span style="color: hsl(120, 100%, 40%);">+        popen_args_clear_diag_logs = ['rm', '-r', '/data/local/tmp/diag_logs/*', '||', 'true']</span><br><span style="color: hsl(120, 100%, 40%);">+        clear_diag_logs_proc = self.run_netns_wait('clear-diag_logs', popen_args_clear_diag_logs)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg("Deleted the following files: %s" % clear_diag_logs_proc.get_stdout())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def check_device_availability(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        serials_cmd = ['adb', 'devices']</span><br><span style="color: hsl(120, 100%, 40%);">+        proc = self.run_netns_wait("devices", serials_cmd)</span><br><span style="color: hsl(120, 100%, 40%);">+        return self.ue_serial in proc.get_stdout()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def restart_adb_inst(self, as_root=False):</span><br><span style="color: hsl(120, 100%, 40%);">+        self.run_netns_wait("kill-adb",  ['sudo', 'adb', 'kill-server'])</span><br><span style="color: hsl(120, 100%, 40%);">+        if as_root:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.run_netns_wait("start-adb", ['adb', 'start-server'])</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.run_netns_wait("start-adb", ['sudo', 'adb', 'start-server'])</span><br><span style="color: hsl(120, 100%, 40%);">+        return</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def connect(self, enb):</span><br><span style="color: hsl(120, 100%, 40%);">+        self.log('Starting AndroidUE')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.configure()</span><br><span style="color: hsl(120, 100%, 40%);">+        CONN_CHK = 'osmo-gsm-tester_androidue_conn_chk.sh'</span><br><span style="color: hsl(120, 100%, 40%);">+        popen_args_emm_conn_chk = [CONN_CHK, self.ue_serial]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if not self._run_node.is_local():</span><br><span style="color: hsl(120, 100%, 40%);">+            emm_conn_chk_proc = self.rem_host.RemoteProcess('emm-conn-chk', popen_args_emm_conn_chk, env={})</span><br><span style="color: hsl(120, 100%, 40%);">+            emm_conn_chk_proc.launch()</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            emm_conn_chk_proc = process.run_local(self.run_dir, 'emm-conn-chk', popen_args_emm_conn_chk)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # check connection status</span><br><span style="color: hsl(120, 100%, 40%);">+        timer = self.connect_timeout</span><br><span style="color: hsl(120, 100%, 40%);">+        while timer > 0:</span><br><span style="color: hsl(120, 100%, 40%);">+            if 'LTE' in emm_conn_chk_proc.get_stdout():</span><br><span style="color: hsl(120, 100%, 40%);">+                if self.get_assigned_addr():</span><br><span style="color: hsl(120, 100%, 40%);">+                    self.emm_connected = True</span><br><span style="color: hsl(120, 100%, 40%);">+                    self.rrc_connected = True</span><br><span style="color: hsl(120, 100%, 40%);">+                    emm_conn_chk_proc.terminate()</span><br><span style="color: hsl(120, 100%, 40%);">+                    break</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # reset connection</span><br><span style="color: hsl(120, 100%, 40%);">+            if timer % self.conn_reset_intvl == 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                self.set_airplane_mode(True)</span><br><span style="color: hsl(120, 100%, 40%);">+                time.sleep(2)</span><br><span style="color: hsl(120, 100%, 40%);">+                timer -= 2</span><br><span style="color: hsl(120, 100%, 40%);">+                self.set_airplane_mode(False)</span><br><span style="color: hsl(120, 100%, 40%);">+            time.sleep(1)</span><br><span style="color: hsl(120, 100%, 40%);">+            timer -= 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if timer == 0:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error("Android UE %s connection timer expired" % self.ue_serial)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # start bit rate monitoring on Android UE</span><br><span style="color: hsl(120, 100%, 40%);">+        popen_args_rx = ['while', 'true;', 'do',</span><br><span style="color: hsl(120, 100%, 40%);">+                         'echo', '`cat', '/sys/class/net/' + self.ue_data_intf + '/statistics/rx_bytes`;',</span><br><span style="color: hsl(120, 100%, 40%);">+                         'sleep', '1;', 'done']</span><br><span style="color: hsl(120, 100%, 40%);">+        popen_args_tx = ['while', 'true;', 'do',</span><br><span style="color: hsl(120, 100%, 40%);">+                         'echo', '`cat', '/sys/class/net/' + self.ue_data_intf + '/statistics/tx_bytes`;',</span><br><span style="color: hsl(120, 100%, 40%);">+                         'sleep', '1;', 'done']</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if not self._run_node.is_local():</span><br><span style="color: hsl(120, 100%, 40%);">+            self.rx_monitor_proc = self.rem_host.RemoteProcess("rx-monitor", popen_args_rx, env={})</span><br><span style="color: hsl(120, 100%, 40%);">+            self.rx_monitor_proc.launch()</span><br><span style="color: hsl(120, 100%, 40%);">+            self.tx_monitor_proc = self.rem_host.RemoteProcess("tx-monitor", popen_args_tx, env={})</span><br><span style="color: hsl(120, 100%, 40%);">+            self.tx_monitor_proc.launch()</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.rx_monitor_proc = process.run_local(self.run_dir, "rx-monitor", popen_args_rx)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.tx_monitor_proc = process.run_local(self.run_dir, "tx-monitor", popen_args_tx)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # start diag_mdlog and parsing</span><br><span style="color: hsl(120, 100%, 40%);">+        if 'qc_diag' in self.features():</span><br><span style="color: hsl(120, 100%, 40%);">+            DIAG_PARSER = 'osmo-gsm-tester_androidue_diag_parser.sh'</span><br><span style="color: hsl(120, 100%, 40%);">+            self.pcap_file = self.run_dir.child(AndroidUE.PCAPFILE)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.remote_pcap_file = self.remote_run_dir.child(AndroidUE.PCAPFILE)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            popen_args_diag = ['/vendor/bin/diag_mdlog', '-s', '90000', '-f', '/data/local/tmp/ogt_diag.cfg',</span><br><span style="color: hsl(120, 100%, 40%);">+                               '-o', '/data/local/tmp/diag_logs']</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            if not self._run_node.is_local():</span><br><span style="color: hsl(120, 100%, 40%);">+                self.diag_monitor_proc = self.rem_host.RemoteProcess("diag-monitor", popen_args_diag, env={})</span><br><span style="color: hsl(120, 100%, 40%);">+                self.diag_monitor_proc.launch()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                popen_args_diag_parser = [DIAG_PARSER, str(self.ue_serial), str(self.remote_run_dir), str(self.remote_pcap_file)]</span><br><span style="color: hsl(120, 100%, 40%);">+                self.diag_parser_proc = self.rem_host.RemoteProcess("diag-parser", popen_args_diag_parser, env={})</span><br><span style="color: hsl(120, 100%, 40%);">+                self.diag_parser_proc.launch()</span><br><span style="color: hsl(120, 100%, 40%);">+            else:</span><br><span style="color: hsl(120, 100%, 40%);">+                self.diag_monitor_proc = process.run_local(self.run_dir, "diag-monitor", popen_args_diag)</span><br><span style="color: hsl(120, 100%, 40%);">+                self.diag_monitor_proc.launch()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                popen_args_diag_parser = [DIAG_PARSER, str(self.ue_serial), str(self.run_dir), str(self.pcap_file)]</span><br><span style="color: hsl(120, 100%, 40%);">+                self.diag_parser_proc = process.run_local(self.run_dir, "diag-parser", popen_args_diag_parser)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def configure(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        values = dict(ue=config.get_defaults('androidue'))</span><br><span style="color: hsl(120, 100%, 40%);">+        config.overlay(values, dict(ue=self.testenv.suite().config().get('modem', {})))</span><br><span style="color: hsl(120, 100%, 40%);">+        config.overlay(values, dict(ue=self._conf))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg('AndroidUE CONFIG:\n' + pprint.pformat(values))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        self.remote_port = values['ue']['run_node']['remote_port']</span><br><span style="color: hsl(120, 100%, 40%);">+        self.ue_serial = values['ue']['ue_serial']</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if 'qc_diag' in self.features():</span><br><span style="color: hsl(120, 100%, 40%);">+            self.enable_pcap = util.str2bool(values['ue'].get('enable_pcap', 'false'))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        self.run_dir = util.Dir(self.testenv.test().get_run_dir().new_dir(self.name()))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.metrics_file = self.run_dir.child(AndroidUE.METRICSFILE)</span><br><span style="color: hsl(120, 100%, 40%);">+        if not self._run_node.is_local():</span><br><span style="color: hsl(120, 100%, 40%);">+            self.rem_host = remote.RemoteHost(self.run_dir, self._run_node.ssh_user(),</span><br><span style="color: hsl(120, 100%, 40%);">+                                              self._run_node.ssh_addr(), None, remote_port=self.remote_port)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.remote_run_dir = util.Dir(AndroidUE.REMOTEDIR)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.remote_metrics_file = self.remote_run_dir.child(AndroidUE.METRICSFILE)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # set APN</span><br><span style="color: hsl(120, 100%, 40%);">+        apn_params = {</span><br><span style="color: hsl(120, 100%, 40%);">+            "carrier": str(values['ue']['apn_name'] or 'default'),</span><br><span style="color: hsl(120, 100%, 40%);">+            "apn": str(values['ue']['apn']),  # mandatory</span><br><span style="color: hsl(120, 100%, 40%);">+            "proxy": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "port": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "user": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "password": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "server": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "mmsc": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "mmsport": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "mmsproxy": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "mcc": str(values['ue']['apn_mcc']),  # mandatory</span><br><span style="color: hsl(120, 100%, 40%);">+            "mnc": str(values['ue']['apn_mnc']),  # mandatory</span><br><span style="color: hsl(120, 100%, 40%);">+            "auth": str('-1'),</span><br><span style="color: hsl(120, 100%, 40%);">+            "type": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "protocol": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "mvnotype": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "mvnoval": str(''),</span><br><span style="color: hsl(120, 100%, 40%);">+            "groupid": str('-1')</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # make sure UE is not in airplane mode</span><br><span style="color: hsl(120, 100%, 40%);">+        self.set_airplane_mode(False)</span><br><span style="color: hsl(120, 100%, 40%);">+        time.sleep(1)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg("Set APN parameters: " + str(apn_params))</span><br><span style="color: hsl(120, 100%, 40%);">+        # self.set_apn(apn_params, True)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # move back in airplane mode</span><br><span style="color: hsl(120, 100%, 40%);">+        time.sleep(1)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.set_airplane_mode(False)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # clear working directories</span><br><span style="color: hsl(120, 100%, 40%);">+        self.clear_work_dirs()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def is_rrc_connected(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        if not ('qc_diag' in self.features()):</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error("Checking RRC state not supported (missing qc_diag feature?)")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if not self.diag_monitor_proc:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error("Diag monitor crashed or not started")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        diag_mon_stdout_l = self.diag_monitor_proc.get_stdout().split("\n")</span><br><span style="color: hsl(120, 100%, 40%);">+        rrc_connected = self.rrc_connected</span><br><span style="color: hsl(120, 100%, 40%);">+        for line in diag_mon_stdout_l:</span><br><span style="color: hsl(120, 100%, 40%);">+            if "rrc_state=RRC_IDLE_CAMPED" in line:</span><br><span style="color: hsl(120, 100%, 40%);">+                rrc_connected = False</span><br><span style="color: hsl(120, 100%, 40%);">+            # elif "LTE_RRC_STATE_CHANGE: RRC_IDLE_NOT_CAMPED" in line:  # UE lost connection, throw exception</span><br><span style="color: hsl(120, 100%, 40%);">+            #    raise log.Error("Android UE lost connection to the eNB")</span><br><span style="color: hsl(120, 100%, 40%);">+            elif "rrc_state=" in line:</span><br><span style="color: hsl(120, 100%, 40%);">+                rrc_connected = True</span><br><span style="color: hsl(120, 100%, 40%);">+        return rrc_connected</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def is_registered(self, mcc_mnc=None):</span><br><span style="color: hsl(120, 100%, 40%);">+        return self.emm_connected</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def get_counter(self, counter_name):</span><br><span style="color: hsl(120, 100%, 40%);">+        self.stop()</span><br><span style="color: hsl(120, 100%, 40%);">+        if counter_name == 'prach_sent':</span><br><span style="color: hsl(120, 100%, 40%);">+            # not implemented so far, return 2 to pass tests</span><br><span style="color: hsl(120, 100%, 40%);">+            return 2</span><br><span style="color: hsl(120, 100%, 40%);">+        elif counter_name == 'paging_received':</span><br><span style="color: hsl(120, 100%, 40%);">+            diag_parser_stdout_l = self.diag_parser_proc.get_stdout().split("\n")</span><br><span style="color: hsl(120, 100%, 40%);">+            return diag_parser_stdout_l.count('Paging received')</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error("Counter %s not implemented" % counter_name)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def get_assigned_addr(self, ipv6=False):</span><br><span style="color: hsl(120, 100%, 40%);">+        ip_prefix = "172.16.0"</span><br><span style="color: hsl(120, 100%, 40%);">+        proc = self.run_netns_wait("get-ip", ['ip', 'addr', 'show'])</span><br><span style="color: hsl(120, 100%, 40%);">+        out_l = proc.get_stdout().split('\n')</span><br><span style="color: hsl(120, 100%, 40%);">+        ip = None</span><br><span style="color: hsl(120, 100%, 40%);">+        for line in out_l:</span><br><span style="color: hsl(120, 100%, 40%);">+            if ip_prefix in line:</span><br><span style="color: hsl(120, 100%, 40%);">+                ip = line.split(' ')[5][:-3]  # UE's IP</span><br><span style="color: hsl(120, 100%, 40%);">+                self.ue_data_intf = line.split(' ')[-1]  # UE's data interface</span><br><span style="color: hsl(120, 100%, 40%);">+        return ip</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def running(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        # check if device is available over ADB</span><br><span style="color: hsl(120, 100%, 40%);">+        if not (self.ue_serial is None):</span><br><span style="color: hsl(120, 100%, 40%);">+            serials_cmd = ['adb', 'devices']</span><br><span style="color: hsl(120, 100%, 40%);">+            proc = self.run_netns_wait("devices", serials_cmd)</span><br><span style="color: hsl(120, 100%, 40%);">+            if self.ue_serial in proc.get_stdout():</span><br><span style="color: hsl(120, 100%, 40%);">+                return True</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg("Device with serial %s is currently not available" % self.ue_serial)</span><br><span style="color: hsl(120, 100%, 40%);">+        return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def addr(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        return self._run_node.run_addr()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def run_node(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        return self._run_node</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def features(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        return self._conf.get('features', [])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def run_netns_wait(self, name, popen_args):</span><br><span style="color: hsl(120, 100%, 40%);">+        if self._run_node.is_local():</span><br><span style="color: hsl(120, 100%, 40%);">+            # use adb locally instead of ssh</span><br><span style="color: hsl(120, 100%, 40%);">+            adb_cmd_pref = ['adb', '-s', self.ue_serial, 'exec-out', 'su', '-c']</span><br><span style="color: hsl(120, 100%, 40%);">+            popen_args = adb_cmd_pref + list(popen_args)</span><br><span style="color: hsl(120, 100%, 40%);">+            proc = process.run_local_sync(self.run_dir, name, popen_args)</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            proc = self.rem_host.RemoteProcess(name, popen_args, env={})</span><br><span style="color: hsl(120, 100%, 40%);">+        proc.launch_sync()</span><br><span style="color: hsl(120, 100%, 40%);">+        return proc</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def verify_metric(self, value, operation='avg', metric='dl_brate', criterion='gt', window=1):</span><br><span style="color: hsl(120, 100%, 40%);">+        self.stop()</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.have_metrics_file:</span><br><span style="color: hsl(120, 100%, 40%);">+            metrics = srsUEMetrics(self.metrics_file)</span><br><span style="color: hsl(120, 100%, 40%);">+            return metrics.verify(value, operation, metric, criterion, window)</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error("Metrics file not available")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def netns(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        return None  # no netns needed</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def set_airplane_mode(self, apm_state):</span><br><span style="color: hsl(120, 100%, 40%);">+        self.log("Setting airplane mode: " + str(apm_state))</span><br><span style="color: hsl(120, 100%, 40%);">+        popen_args = ['settings', 'put', 'global', 'airplane_mode_on', str(int(apm_state)),</span><br><span style="color: hsl(120, 100%, 40%);">+                      '&&', 'su', '-c', '\"', 'am', 'broadcast', '-a', 'android.intent.action.AIRPLANE_MODE', '\"']</span><br><span style="color: hsl(120, 100%, 40%);">+        self.run_netns_wait("set-airplane-mode", popen_args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def get_carrier_id(self, carrier_name):</span><br><span style="color: hsl(120, 100%, 40%);">+        qry_carrier_cmd = "content query --uri \"content://telephony/carriers\" "</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        proc = self.run_netns_wait("set-apn", [qry_carrier_cmd])</span><br><span style="color: hsl(120, 100%, 40%);">+        available_carriers = proc.get_stdout().split("\n")</span><br><span style="color: hsl(120, 100%, 40%);">+        carr_id = -1</span><br><span style="color: hsl(120, 100%, 40%);">+        for carr in available_carriers:</span><br><span style="color: hsl(120, 100%, 40%);">+            if 'name=' + carrier_name in carr:  # found carrier</span><br><span style="color: hsl(120, 100%, 40%);">+                carr_id = re.findall(r'_id=(\S+),', carr)[0]</span><br><span style="color: hsl(120, 100%, 40%);">+                break</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return carr_id</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def set_new_carrier(self, apn_parameter, carr_id):</span><br><span style="color: hsl(120, 100%, 40%);">+        # check if carrier was found, delete it if exists</span><br><span style="color: hsl(120, 100%, 40%);">+        if carr_id != -1:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.delete_apn(apn_parameter["carrier"])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # build command to add/update carrier</span><br><span style="color: hsl(120, 100%, 40%);">+        set_carrier_cmd = "content insert --uri content://telephony/carriers" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind name:s:\"" + apn_parameter["carrier"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind numeric:s:\"" + apn_parameter["mcc"] + apn_parameter["mnc"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind mcc:s:\"" + apn_parameter["mcc"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind mnc:s:\"" + apn_parameter["mnc"] + "\""\</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind apn:s:\"" + apn_parameter["apn"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind user:s:\"" + apn_parameter["user"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind password:s:\"" + apn_parameter["password"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind mmsc:s:\"" + apn_parameter["mmsc"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind mmsport:s:\"" + apn_parameter["mmsport"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind mmsproxy:s:\"" + apn_parameter["mmsproxy"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind authtype:s:\"" + apn_parameter["auth"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind type:s:\"" + apn_parameter["type"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind protocol:s:\"" + apn_parameter["protocol"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind mvno_type:s:\"" + apn_parameter["mvnotype"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind mvno_match_data:s:\"" + apn_parameter["mvnoval"] + "\"" \</span><br><span style="color: hsl(120, 100%, 40%);">+                          + " --bind sub_id:s:\"" + apn_parameter["groupid"] + "\""</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        self.run_netns_wait("set-apn", [set_carrier_cmd])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # return carrier ID</span><br><span style="color: hsl(120, 100%, 40%);">+        return self.get_carrier_id(apn_parameter["carrier"])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def set_preferred_apn(self, carr_id):</span><br><span style="color: hsl(120, 100%, 40%);">+        if carr_id != -1:</span><br><span style="color: hsl(120, 100%, 40%);">+            set_apn_cmd = "content insert --uri content://telephony/carriers/preferapn --bind apn_id:s:\"" + str(carr_id) + "\""</span><br><span style="color: hsl(120, 100%, 40%);">+            self.run_netns_wait("set-apn", [set_apn_cmd])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def set_apn(self, apn_param, sel_apn):</span><br><span style="color: hsl(120, 100%, 40%);">+        # search for carrier in APN database</span><br><span style="color: hsl(120, 100%, 40%);">+        carrier_id = self.get_carrier_id(apn_param["carrier"])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # add/update carrier</span><br><span style="color: hsl(120, 100%, 40%);">+        carrier_id = self.set_new_carrier(apn_param, carrier_id)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # select as preferred APN</span><br><span style="color: hsl(120, 100%, 40%);">+        if sel_apn:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.set_preferred_apn(carrier_id)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def select_apn(self, carr_name):</span><br><span style="color: hsl(120, 100%, 40%);">+        # search for carrier_id</span><br><span style="color: hsl(120, 100%, 40%);">+        carr_id = self.get_carrier_id(carr_name)</span><br><span style="color: hsl(120, 100%, 40%);">+        if carr_id == 0:</span><br><span style="color: hsl(120, 100%, 40%);">+            return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # select carrier by id</span><br><span style="color: hsl(120, 100%, 40%);">+        sel_apn_cmd = "content update --uri content://telephony/carriers/preferapn --bind apn_id:s:\"" + str(carr_id) + "\""</span><br><span style="color: hsl(120, 100%, 40%);">+        self.run_netns_wait("set-apn", [sel_apn_cmd])</span><br><span style="color: hsl(120, 100%, 40%);">+        return True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def delete_apn(self, carr_name):</span><br><span style="color: hsl(120, 100%, 40%);">+        set_apn_cmd = "content delete --uri content://telephony/carriers --where \'name=\"" + str(carr_name) + "\" \'"</span><br><span style="color: hsl(120, 100%, 40%);">+        self.run_netns_wait("set-apn", [set_apn_cmd])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def is_emm_connected(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        time.sleep(2)</span><br><span style="color: hsl(120, 100%, 40%);">+        proc = self.run_netns_wait("emm-conn-chk", ['getprop', '\"gsm.network.type\"'])</span><br><span style="color: hsl(120, 100%, 40%);">+        return 'LTE' in proc.get_stdout()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def save_metrics(self, brate_rx_l, brate_tx_l):</span><br><span style="color: hsl(120, 100%, 40%);">+        if len(brate_rx_l) < 2 or len(brate_tx_l) < 2:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error("Insufficient data available to write metrics file")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # cut of elements if lists don't have the same length</span><br><span style="color: hsl(120, 100%, 40%);">+        if len(brate_rx_l) > len(brate_tx_l):</span><br><span style="color: hsl(120, 100%, 40%);">+            brate_rx_l = brate_rx_l[:len(brate_tx_l) - len(brate_rx_l)]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if len(brate_rx_l) < len(brate_tx_l):</span><br><span style="color: hsl(120, 100%, 40%);">+            brate_tx_l = brate_tx_l[:len(brate_rx_l) - len(brate_tx_l)]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # get start value</span><br><span style="color: hsl(120, 100%, 40%);">+        brate_rx_last = int(brate_rx_l[0])</span><br><span style="color: hsl(120, 100%, 40%);">+        brate_tx_last = int(brate_tx_l[0])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        with open(self.metrics_file, "w") as ue_metrics_fh:</span><br><span style="color: hsl(120, 100%, 40%);">+            ue_metrics_fh.write("time;cc;earfcn;pci;rsrp;pl;cfo;pci_neigh;rsrp_neigh;cfo_neigh;"</span><br><span style="color: hsl(120, 100%, 40%);">+                                + "dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;"</span><br><span style="color: hsl(120, 100%, 40%);">+                                + "ul_ta;ul_mcs;ul_buff;ul_brate;ul_bler;rf_o;rf_u;rf_l;"</span><br><span style="color: hsl(120, 100%, 40%);">+                                + "is_attached\n")</span><br><span style="color: hsl(120, 100%, 40%);">+            for i in range(1, len(brate_rx_l)):</span><br><span style="color: hsl(120, 100%, 40%);">+                time = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                cc = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                earfcn = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                pci = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                rsrp = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                pl = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                cfo = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                pci_neigh = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                rsrp_neigh = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                cfo_neigh = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                dl_mcs = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                dl_snr = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                dl_turbo = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                dl_brate = str((int(brate_rx_l[i]) - brate_rx_last) * 8)</span><br><span style="color: hsl(120, 100%, 40%);">+                brate_rx_last = int(brate_rx_l[i])</span><br><span style="color: hsl(120, 100%, 40%);">+                dl_bler = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                ul_ta = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                ul_mcs = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                ul_buff = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                ul_brate = str((int(brate_tx_l[i]) - brate_tx_last) * 8)</span><br><span style="color: hsl(120, 100%, 40%);">+                brate_tx_last = int(brate_tx_l[i])</span><br><span style="color: hsl(120, 100%, 40%);">+                ul_bler = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                rf_o = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                rf_u = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                rf_l = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+                is_attached = "0"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                line = time + ";" + cc + ";" + earfcn + ";" + pci + ";" + rsrp + ";" + pl + ";" + cfo + ";" \</span><br><span style="color: hsl(120, 100%, 40%);">+                       + pci_neigh + ";" + rsrp_neigh + ";" + cfo_neigh + ";" + dl_mcs + ";" + dl_snr + ";" \</span><br><span style="color: hsl(120, 100%, 40%);">+                       + dl_turbo + ";" + dl_brate + ";" + dl_bler + ";" + ul_ta + ";" + ul_mcs + ";" + ul_buff + ";" \</span><br><span style="color: hsl(120, 100%, 40%);">+                       + ul_brate + ";" + ul_bler + ";" + rf_o + ";" + rf_u + ";" + rf_l + ";" + is_attached</span><br><span style="color: hsl(120, 100%, 40%);">+                ue_metrics_fh.write(line + "\n")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        self.have_metrics_file = True</span><br><span>diff --git a/src/osmo_gsm_tester/obj/run_node.py b/src/osmo_gsm_tester/obj/run_node.py</span><br><span>index 6a030ac..c907944 100644</span><br><span>--- a/src/osmo_gsm_tester/obj/run_node.py</span><br><span>+++ b/src/osmo_gsm_tester/obj/run_node.py</span><br><span>@@ -30,13 +30,14 @@</span><br><span>     T_LOCAL = 'local'</span><br><span>     T_REM_SSH = 'ssh'</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def __init__(self, type=None, run_addr=None, ssh_user=None, ssh_addr=None, run_label=None):</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, type=None, run_addr=None, ssh_user=None, ssh_addr=None, run_label=None, remote_port=None):</span><br><span>         super().__init__(log.C_RUN, 'runnode')</span><br><span>         self._type = type</span><br><span>         self._run_addr = run_addr</span><br><span>         self._ssh_user = ssh_user</span><br><span>         self._ssh_addr = ssh_addr</span><br><span>         self._run_label = run_label</span><br><span style="color: hsl(120, 100%, 40%);">+        self._remote_port = remote_port</span><br><span>         if not self._type:</span><br><span>             raise log.Error('run_type not set')</span><br><span>         if not self._run_addr:</span><br><span>@@ -55,7 +56,7 @@</span><br><span>     def from_conf(cls, conf):</span><br><span>         return cls(conf.get('run_type', None), conf.get('run_addr', None),</span><br><span>                    conf.get('ssh_user', None), conf.get('ssh_addr', None),</span><br><span style="color: hsl(0, 100%, 40%);">-                   conf.get('run_label', None))</span><br><span style="color: hsl(120, 100%, 40%);">+                   conf.get('run_label', None), conf.get('remote_port', None))</span><br><span> </span><br><span>     @classmethod</span><br><span>     def schema(cls):</span><br><span>@@ -65,6 +66,7 @@</span><br><span>             'ssh_user': schema.STR,</span><br><span>             'ssh_addr': schema.IPV4,</span><br><span>             'run_label': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+            'remote_port': schema.STR,</span><br><span>             }</span><br><span>         return resource_schema</span><br><span> </span><br><span>@@ -89,4 +91,7 @@</span><br><span>     def run_label(self):</span><br><span>         return self._run_label</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    def ssh_port(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        return self._remote_port</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # vim: expandtab tabstop=4 shiftwidth=4</span><br><span>diff --git a/sysmocom/default-suites.conf b/sysmocom/default-suites.conf</span><br><span>index b32d7b1..4c196b4 100644</span><br><span>--- a/sysmocom/default-suites.conf</span><br><span>+++ b/sysmocom/default-suites.conf</span><br><span>@@ -172,3 +172,4 @@</span><br><span> - encryption</span><br><span> </span><br><span> - 4g:srsenb-rftype@zmq+srsue-rftype@zmq</span><br><span style="color: hsl(120, 100%, 40%);">+- 4g:androidue@mi5g+srsenb-rftype@uhd+mod-enb-nprb@25+mod-enb-txmode@1</span><br><span>diff --git a/sysmocom/scenarios/androidue@.conf b/sysmocom/scenarios/androidue@.conf</span><br><span>new file mode 100644</span><br><span>index 0000000..a129c0e</span><br><span>--- /dev/null</span><br><span>+++ b/sysmocom/scenarios/androidue@.conf</span><br><span>@@ -0,0 +1,3 @@</span><br><span style="color: hsl(120, 100%, 40%);">+resources:</span><br><span style="color: hsl(120, 100%, 40%);">+  modem:</span><br><span style="color: hsl(120, 100%, 40%);">+  - label: ${param1}</span><br><span>diff --git a/sysmocom/suites/4g/iperf3_dl.py b/sysmocom/suites/4g/iperf3_dl.py</span><br><span>index bf5b1f0..ed137bd 100755</span><br><span>--- a/sysmocom/suites/4g/iperf3_dl.py</span><br><span>+++ b/sysmocom/suites/4g/iperf3_dl.py</span><br><span>@@ -23,7 +23,7 @@</span><br><span> max_rate = enb.ue_max_rate(downlink=True, num_carriers=ue.num_carriers)</span><br><span> </span><br><span> iperf3srv.start()</span><br><span style="color: hsl(0, 100%, 40%);">-proc = iperf3cli.prepare_test_proc(iperf3cli.DIR_DL, ue.netns(), bitrate=max_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+proc = iperf3cli.prepare_test_proc(iperf3cli.DIR_DL, ue.netns(), bitrate=max_rate, ue=ue)</span><br><span> </span><br><span> print('waiting for UE to attach...')</span><br><span> wait(ue.is_registered)</span><br><span>diff --git a/sysmocom/suites/4g/iperf3_ul.py b/sysmocom/suites/4g/iperf3_ul.py</span><br><span>index 6c0d25d..6cc9f21 100755</span><br><span>--- a/sysmocom/suites/4g/iperf3_ul.py</span><br><span>+++ b/sysmocom/suites/4g/iperf3_ul.py</span><br><span>@@ -23,7 +23,7 @@</span><br><span> max_rate = enb.ue_max_rate(downlink=False, num_carriers=ue.num_carriers)</span><br><span> </span><br><span> iperf3srv.start()</span><br><span style="color: hsl(0, 100%, 40%);">-proc = iperf3cli.prepare_test_proc(iperf3cli.DIR_UL, ue.netns(), bitrate=max_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+proc = iperf3cli.prepare_test_proc(iperf3cli.DIR_UL, ue.netns(), bitrate=max_rate, ue=ue)</span><br><span> </span><br><span> print('waiting for UE to attach...')</span><br><span> wait(ue.is_registered)</span><br><span>diff --git a/utils/bin/osmo-gsm-tester_androidue_conn_chk.sh b/utils/bin/osmo-gsm-tester_androidue_conn_chk.sh</span><br><span>new file mode 100644</span><br><span>index 0000000..8e126cd</span><br><span>--- /dev/null</span><br><span>+++ b/utils/bin/osmo-gsm-tester_androidue_conn_chk.sh</span><br><span>@@ -0,0 +1,9 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# osmo-gsm-tester_androidue_conn_chk.sh $serial</span><br><span style="color: hsl(120, 100%, 40%);">+while true; do</span><br><span style="color: hsl(120, 100%, 40%);">+    sudo adb -s "$1" shell getprop "gsm.network.type";</span><br><span style="color: hsl(120, 100%, 40%);">+    sleep 1;</span><br><span style="color: hsl(120, 100%, 40%);">+done</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/utils/bin/osmo-gsm-tester_androidue_diag_parser.sh b/utils/bin/osmo-gsm-tester_androidue_diag_parser.sh</span><br><span>new file mode 100644</span><br><span>index 0000000..00a2f81</span><br><span>--- /dev/null</span><br><span>+++ b/utils/bin/osmo-gsm-tester_androidue_diag_parser.sh</span><br><span>@@ -0,0 +1,10 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# format ./osmo-gsm-tester_androidue_diag_parser.sh $serial $run_dir $pcap_path</span><br><span style="color: hsl(120, 100%, 40%);">+while true; do</span><br><span style="color: hsl(120, 100%, 40%);">+    echo "Pulling new qmdl file...";</span><br><span style="color: hsl(120, 100%, 40%);">+    sudo adb -s "$1" pull /data/local/tmp/diag_logs "$2" > /dev/null;</span><br><span style="color: hsl(120, 100%, 40%);">+    wait $!;</span><br><span style="color: hsl(120, 100%, 40%);">+    QMDL_FN=$(find "$2" -maxdepth 2 -type f -name "*.qmdl");</span><br><span style="color: hsl(120, 100%, 40%);">+    wait $!;</span><br><span style="color: hsl(120, 100%, 40%);">+    sudo scat -t qc --event -d "$QMDL_FN" -F "$3";</span><br><span style="color: hsl(120, 100%, 40%);">+    wait $!;</span><br><span style="color: hsl(120, 100%, 40%);">+done</span><br><span>\ No newline at end of file</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/21217">change 21217</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/21217"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-gsm-tester </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Iab37a0de59d6643d21bced34ddca06ff40fa62df </div>
<div style="display:none"> Gerrit-Change-Number: 21217 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: srs_andre <andre@softwareradiosystems.com> </div>
<div style="display:none"> Gerrit-Reviewer: Nils <nils.fuerste@softwareradiosystems.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>