<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/17842">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">wip: websocket amarisoft<br><br>Change-Id: I4fd30a3e37789b76bfaddc2beba1815154daab7f<br>---<br>M check_dependencies.py<br>M src/osmo_gsm_tester/obj/enb_amarisoft.py<br>A src/osmo_gsm_tester/obj/rfemu.py<br>A src/osmo_gsm_tester/obj/rfemu_amarisoftctrl.py<br>A src/osmo_gsm_tester/obj/rfemu_minicircuits.py<br>M src/osmo_gsm_tester/resource.py<br>M src/osmo_gsm_tester/templates/amarisoft_enb.cfg.tmpl<br>M sysmocom/defaults.conf<br>A sysmocom/suites/4g/handover.py<br>9 files changed, 273 insertions(+), 24 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/42/17842/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/check_dependencies.py b/check_dependencies.py</span><br><span>index c3b1d64..c983065 100755</span><br><span>--- a/check_dependencies.py</span><br><span>+++ b/check_dependencies.py</span><br><span>@@ -6,6 +6,7 @@</span><br><span> from inspect import getframeinfo, stack</span><br><span> from mako.lookup import TemplateLookup</span><br><span> from mako.template import Template</span><br><span style="color: hsl(120, 100%, 40%);">+from websocket import create_connection</span><br><span> import argparse</span><br><span> import contextlib</span><br><span> import copy</span><br><span>diff --git a/src/osmo_gsm_tester/obj/enb_amarisoft.py b/src/osmo_gsm_tester/obj/enb_amarisoft.py</span><br><span>index 1772173..3d04357 100644</span><br><span>--- a/src/osmo_gsm_tester/obj/enb_amarisoft.py</span><br><span>+++ b/src/osmo_gsm_tester/obj/enb_amarisoft.py</span><br><span>@@ -22,6 +22,7 @@</span><br><span> </span><br><span> from ..core import log, util, config, template, process, remote</span><br><span> from . import enb</span><br><span style="color: hsl(120, 100%, 40%);">+from . import rfemu</span><br><span> </span><br><span> def rf_type_valid(rf_type_str):</span><br><span>     return rf_type_str in ('uhd', 'zmq')</span><br><span>@@ -62,6 +63,7 @@</span><br><span>         self.run_dir = None</span><br><span>         self.inst = None</span><br><span>         self._bin_prefix = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.gen_conf = None</span><br><span>         self.config_file = None</span><br><span>         self.config_sib1_file = None</span><br><span>         self.config_sib23_file = None</span><br><span>@@ -168,6 +170,22 @@</span><br><span>         self._num_cells = int(values['enb'].get('num_cells', None))</span><br><span>         assert self._num_cells</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        # adjust cell_list to num_cells length:</span><br><span style="color: hsl(120, 100%, 40%);">+        len_cell_list = len(values['enb']['cell_list'])</span><br><span style="color: hsl(120, 100%, 40%);">+        if len_cell_list >= self._num_cells:</span><br><span style="color: hsl(120, 100%, 40%);">+            values['enb']['cell_list'] = values['enb']['cell_list'][:self._num_cells]</span><br><span style="color: hsl(120, 100%, 40%);">+        else:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('enb.cell_list items (%d) < enb.num_cells (%d) attribute!' % (len_cell_list, self._num_cells))</span><br><span style="color: hsl(120, 100%, 40%);">+        # adjust scell list (to only contain values available in cell_list):</span><br><span style="color: hsl(120, 100%, 40%);">+        cell_id_list = [c['cell_id'] for c in values['enb']['cell_list']]</span><br><span style="color: hsl(120, 100%, 40%);">+        for i in range(len(values['enb']['cell_list'])):</span><br><span style="color: hsl(120, 100%, 40%);">+            scell_list_old = values['enb']['cell_list'][i]['scell_list']</span><br><span style="color: hsl(120, 100%, 40%);">+            scell_list_new = []</span><br><span style="color: hsl(120, 100%, 40%);">+            for scell_id in scell_list_old:</span><br><span style="color: hsl(120, 100%, 40%);">+                if scell_id in cell_id_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                    scell_list_new.append(scell_id)</span><br><span style="color: hsl(120, 100%, 40%);">+            values['enb']['cell_list'][i]['scell_list'] = scell_list_new</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         # Convert parsed boolean string to Python boolean:</span><br><span>         self.enable_measurements = util.str2bool(values['enb'].get('enable_measurements', 'false'))</span><br><span>         config.overlay(values, dict(enb={'enable_measurements': self.enable_measurements}))</span><br><span>@@ -211,6 +229,8 @@</span><br><span>         config.overlay(values, dict(trx=dict(rf_dev_type=values['enb'].get('rf_dev_type', None),</span><br><span>                                              rf_dev_args=values['enb'].get('rf_dev_args', None))))</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        self.gen_conf = values</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         self.gen_conf_file(self.config_file, AmarisoftENB.CFGFILE, values)</span><br><span>         self.gen_conf_file(self.config_sib1_file, AmarisoftENB.CFGFILE_SIB1, values)</span><br><span>         self.gen_conf_file(self.config_sib23_file, AmarisoftENB.CFGFILE_SIB23, values)</span><br><span>@@ -235,4 +255,19 @@</span><br><span>     def running(self):</span><br><span>         return not self.process.terminated()</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    def get_rfemu(self, cell=0, dl=True):</span><br><span style="color: hsl(120, 100%, 40%);">+        cell_list = self.gen_conf['enb'].get('cell_list', None)</span><br><span style="color: hsl(120, 100%, 40%);">+        if cell_list is None or len(cell_list) < cell + 1:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('cell_list attribute or subitem not found!')</span><br><span style="color: hsl(120, 100%, 40%);">+        rfemu_cfg = cell_list[cell].get('dl_rfemu', None)</span><br><span style="color: hsl(120, 100%, 40%);">+        if rfemu_cfg is None: # craft amarisfot by default:</span><br><span style="color: hsl(120, 100%, 40%);">+            rfemu_cfg = {'type': 'amarisoftctl',</span><br><span style="color: hsl(120, 100%, 40%);">+                         'addr': self.addr(),</span><br><span style="color: hsl(120, 100%, 40%);">+                         'port': 9001</span><br><span style="color: hsl(120, 100%, 40%);">+                         }</span><br><span style="color: hsl(120, 100%, 40%);">+        if rfemu_cfg['type'] == 'amarisoftctl': # this one requires extra config:</span><br><span style="color: hsl(120, 100%, 40%);">+            config.overlay(rfemu_cfg, dict(cell_id=cell_list[cell]['cell_id']))</span><br><span style="color: hsl(120, 100%, 40%);">+        rfemu_obj = rfemu.get_instance_by_type(rfemu_cfg['type'], rfemu_cfg)</span><br><span style="color: hsl(120, 100%, 40%);">+        return rfemu_obj</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/obj/rfemu.py b/src/osmo_gsm_tester/obj/rfemu.py</span><br><span>new file mode 100644</span><br><span>index 0000000..80869bb</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo_gsm_tester/obj/rfemu.py</span><br><span>@@ -0,0 +1,59 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# osmo_gsm_tester: class defining a RF emulation object</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Copyright (C) 2020 by sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+# it under the terms of the GNU General Public License as</span><br><span style="color: hsl(120, 100%, 40%);">+# published by the Free Software Foundation, either version 3 of the</span><br><span style="color: hsl(120, 100%, 40%);">+# License, or (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+# but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+# GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+# along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from abc import ABCMeta, abstractmethod</span><br><span style="color: hsl(120, 100%, 40%);">+from ..core import log</span><br><span style="color: hsl(120, 100%, 40%);">+from ..core.event_loop import MainLoop</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class RFemulation(log.Origin, metaclass=ABCMeta):</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%);">+# PROTECTED</span><br><span style="color: hsl(120, 100%, 40%);">+##############</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, conf, name):</span><br><span style="color: hsl(120, 100%, 40%);">+        """Base constructor. Must be called by subclass."""</span><br><span style="color: hsl(120, 100%, 40%);">+        super().__init__(log.C_RUN, name)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.conf = conf</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%);">+# PUBLIC (test API included)</span><br><span style="color: hsl(120, 100%, 40%);">+#############################</span><br><span style="color: hsl(120, 100%, 40%);">+    @abstractmethod</span><br><span style="color: hsl(120, 100%, 40%);">+    def set_attenuation(self, db):</span><br><span style="color: hsl(120, 100%, 40%);">+        """Set attenuation in dB on the configured channel"""</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from . import rfemu_amarisoftctrl, rfemu_minicircuits</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+KNOWN_RFEMU_TYPES = {</span><br><span style="color: hsl(120, 100%, 40%);">+        'amarisoftctl' : rfemu_amarisoftctrl.RFemulationAmarisoftCtrl,</span><br><span style="color: hsl(120, 100%, 40%);">+        'minicircuits' : rfemu_minicircuits.RFemulationMinicircuitsHTTP,</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 get_instance_by_type(rfemu_type, rfemu_opt):</span><br><span style="color: hsl(120, 100%, 40%);">+    """Allocate a RFemulation child class based on type. Opts are passed to the newly created object."""</span><br><span style="color: hsl(120, 100%, 40%);">+    obj = KNOWN_RFEMU_TYPES.get(rfemu_type, None)</span><br><span style="color: hsl(120, 100%, 40%);">+    if not obj:</span><br><span style="color: hsl(120, 100%, 40%);">+        raise log.Error('RFemulation type not supported:', rfemu_type)</span><br><span style="color: hsl(120, 100%, 40%);">+    return obj(rfemu_opt)</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%);">+# vim: expandtab tabstop=4 shiftwidth=4</span><br><span>diff --git a/src/osmo_gsm_tester/obj/rfemu_amarisoftctrl.py b/src/osmo_gsm_tester/obj/rfemu_amarisoftctrl.py</span><br><span>new file mode 100644</span><br><span>index 0000000..1b980f1</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo_gsm_tester/obj/rfemu_amarisoftctrl.py</span><br><span>@@ -0,0 +1,61 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# osmo_gsm_tester: class defining a RF emulation object implemented using Amarisoft Ctl interface</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Copyright (C) 2020 by sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+# it under the terms of the GNU General Public License as</span><br><span style="color: hsl(120, 100%, 40%);">+# published by the Free Software Foundation, either version 3 of the</span><br><span style="color: hsl(120, 100%, 40%);">+# License, or (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+# but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+# GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+# along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import json</span><br><span style="color: hsl(120, 100%, 40%);">+from websocket import create_connection</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from ..core import log</span><br><span style="color: hsl(120, 100%, 40%);">+from .rfemu import RFemulation</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class RFemulationAmarisoftCtrl(RFemulation):</span><br><span style="color: hsl(120, 100%, 40%);">+##############</span><br><span style="color: hsl(120, 100%, 40%);">+# PROTECTED</span><br><span style="color: hsl(120, 100%, 40%);">+##############</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, conf):</span><br><span style="color: hsl(120, 100%, 40%);">+        super().__init__(conf, 'amarisoftctl')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.addr = conf.get('addr')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.port = conf.get('port')</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.addr is None:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('No "addr" attribute provided in supply conf!')</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.port is None:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('No "port" attribute provided in supply conf!')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.set_name('amarisoftctl(%s:%d)' % (self.addr, self.port))</span><br><span style="color: hsl(120, 100%, 40%);">+        self.cell_id = conf.get('cell_id')</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.cell_id is None:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('No "cell_id" attribute provided in supply conf!')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.ws = create_connection("ws://%s:%s" % (self.addr, self.port))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def __del__(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg('closing CTRL websocket')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.ws.close()</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%);">+# PUBLIC (test API included)</span><br><span style="color: hsl(120, 100%, 40%);">+#############################</span><br><span style="color: hsl(120, 100%, 40%);">+    def set_attenuation(self, db):</span><br><span style="color: hsl(120, 100%, 40%);">+        msg = { "message": "cell_gain", "cell_id": int(self.cell_id), "gain": -db }</span><br><span style="color: hsl(120, 100%, 40%);">+        msg_str = json.dumps(msg)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg('sending CTRL msg: "%s"' % msg_str)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.ws.send(msg_str)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg('waiting CTRL recv...')</span><br><span style="color: hsl(120, 100%, 40%);">+        result = self.ws.recv()</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg('Received CTRL msg: "%s"' % result)</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%);">+# vim: expandtab tabstop=4 shiftwidth=4</span><br><span>diff --git a/src/osmo_gsm_tester/obj/rfemu_minicircuits.py b/src/osmo_gsm_tester/obj/rfemu_minicircuits.py</span><br><span>new file mode 100644</span><br><span>index 0000000..896dada</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo_gsm_tester/obj/rfemu_minicircuits.py</span><br><span>@@ -0,0 +1,64 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# osmo_gsm_tester: class defining a RF emulation object implemented using a Minicircuits RC4DAT-6G-60 device</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Copyright (C) 2020 by sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+# it under the terms of the GNU General Public License as</span><br><span style="color: hsl(120, 100%, 40%);">+# published by the Free Software Foundation, either version 3 of the</span><br><span style="color: hsl(120, 100%, 40%);">+# License, or (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+# but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+# GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+# along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import urllib.request</span><br><span style="color: hsl(120, 100%, 40%);">+import xml.etree.ElementTree as ET</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from ..core import log</span><br><span style="color: hsl(120, 100%, 40%);">+from .rfemu import RFemulation</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# https://www.minicircuits.com/softwaredownload/Prog_Manual-6-Programmable_Attenuator.pdf</span><br><span style="color: hsl(120, 100%, 40%);">+class RFemulationMinicircuitsHTTP(RFemulation):</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    # HTTP request timeout, in seconds</span><br><span style="color: hsl(120, 100%, 40%);">+    HTTP_TIMEOUT = 5</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%);">+# PROTECTED</span><br><span style="color: hsl(120, 100%, 40%);">+##############</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, conf):</span><br><span style="color: hsl(120, 100%, 40%);">+        super().__init__(conf, 'minicircuits')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.addr = conf.get('addr')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.port = conf.get('port')</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.addr is None:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('No "addr" attribute provided in supply conf!')</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.port is None:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('No "port" attribute provided in supply conf!')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.set_name('minicircuits(%s:%d)' % (self.addr, self.port))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def _url_prefix(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        #http://10.12.1.216/:SetAttPerChan:1:0_2:0_3:0_4:0</span><br><span style="color: hsl(120, 100%, 40%);">+        return 'http://' + self.addr</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def _utl_set_attenauation(self, db):</span><br><span style="color: hsl(120, 100%, 40%);">+        return self._url_prefix() + '/:CHAN:' + str(port) + ':SETATT:' + str(db)</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%);">+# PUBLIC (test API included)</span><br><span style="color: hsl(120, 100%, 40%);">+#############################</span><br><span style="color: hsl(120, 100%, 40%);">+    def set_attenuation(self, db):</span><br><span style="color: hsl(120, 100%, 40%);">+        url = self._utl_set_attenauation(db)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg('sending HTTP req: "%s"' % url)</span><br><span style="color: hsl(120, 100%, 40%);">+        data = urllib.request.urlopen(url, timeout = self.HTTP_TIMEOUT).read()</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg('Received response: "%s"' % data)</span><br><span style="color: hsl(120, 100%, 40%);">+        #[Status]</span><br><span style="color: hsl(120, 100%, 40%);">+        # 0 Command failed or invalid attenuation set</span><br><span style="color: hsl(120, 100%, 40%);">+        # 1 Command completed successfully</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# vim: expandtab tabstop=4 shiftwidth=4</span><br><span>diff --git a/src/osmo_gsm_tester/resource.py b/src/osmo_gsm_tester/resource.py</span><br><span>index 61f2b11..09b6f8e 100644</span><br><span>--- a/src/osmo_gsm_tester/resource.py</span><br><span>+++ b/src/osmo_gsm_tester/resource.py</span><br><span>@@ -90,7 +90,6 @@</span><br><span>         'enb[].addr': schema.IPV4,</span><br><span>         'enb[].num_prb': schema.UINT,</span><br><span>         'enb[].transmission_mode': schema.LTE_TRANSMISSION_MODE,</span><br><span style="color: hsl(0, 100%, 40%);">-        'enb[].num_cells': schema.UINT,</span><br><span>         'enb[].rf_dev_type': schema.STR,</span><br><span>         'enb[].rf_dev_args': schema.STR,</span><br><span>         'enb[].additional_args': schema.STR,</span><br><span>@@ -107,6 +106,13 @@</span><br><span>         'enb[].a3_report_value': schema.INT,</span><br><span>         'enb[].a3_hysteresis': schema.INT,</span><br><span>         'enb[].a3_time_to_trigger': schema.INT,</span><br><span style="color: hsl(120, 100%, 40%);">+        'enb[].num_cells': schema.UINT,</span><br><span style="color: hsl(120, 100%, 40%);">+        'enb[].cell_list[].cell_id': schema.UINT,</span><br><span style="color: hsl(120, 100%, 40%);">+        'enb[].cell_list[].scell_list[]': schema.UINT,</span><br><span style="color: hsl(120, 100%, 40%);">+        'enb[].cell_list[].dl_earfcn': schema.UINT,</span><br><span style="color: hsl(120, 100%, 40%);">+        'enb[].cell_list[].dl_rfemu.type': schema.STR,</span><br><span style="color: hsl(120, 100%, 40%);">+        'enb[].cell_list[].dl_rfemu.addr': schema.IPV4,</span><br><span style="color: hsl(120, 100%, 40%);">+        'enb[].cell_list[].dl_rfemu.port': schema.UINT,</span><br><span>         'arfcn[].arfcn': schema.INT,</span><br><span>         'arfcn[].band': schema.BAND,</span><br><span>         'modem[].type': schema.STR,</span><br><span>diff --git a/src/osmo_gsm_tester/templates/amarisoft_enb.cfg.tmpl b/src/osmo_gsm_tester/templates/amarisoft_enb.cfg.tmpl</span><br><span>index d87e66a..5752ab8 100644</span><br><span>--- a/src/osmo_gsm_tester/templates/amarisoft_enb.cfg.tmpl</span><br><span>+++ b/src/osmo_gsm_tester/templates/amarisoft_enb.cfg.tmpl</span><br><span>@@ -55,36 +55,23 @@</span><br><span> </span><br><span>   /* list of cells */</span><br><span>   cell_list: [</span><br><span style="color: hsl(0, 100%, 40%);">-  {</span><br><span style="color: hsl(0, 100%, 40%);">-    // First cell</span><br><span style="color: hsl(0, 100%, 40%);">-    dl_earfcn: 2850,</span><br><span style="color: hsl(0, 100%, 40%);">-    rf_port: 0,</span><br><span style="color: hsl(0, 100%, 40%);">-    cell_id: 0x01,</span><br><span style="color: hsl(0, 100%, 40%);">-    n_id_cell: 1,</span><br><span style="color: hsl(0, 100%, 40%);">-    tac: 0x0001,</span><br><span style="color: hsl(0, 100%, 40%);">-    root_sequence_index: 204, /* PRACH root sequence index */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-% if enb.get('num_cells') == '2':</span><br><span style="color: hsl(0, 100%, 40%);">-    scell_list: [</span><br><span style="color: hsl(0, 100%, 40%);">-      { cell_id: 0x02, cross_carrier_scheduling: false, scheduling_cell_id: 0x01, ul_allowed: true},</span><br><span style="color: hsl(0, 100%, 40%);">-    ],</span><br><span style="color: hsl(0, 100%, 40%);">-% endif</span><br><span style="color: hsl(0, 100%, 40%);">-  },</span><br><span style="color: hsl(0, 100%, 40%);">-% if enb.get('num_cells') == '2':</span><br><span style="color: hsl(120, 100%, 40%);">+%for cell in enb.cell_list:</span><br><span>   {</span><br><span style="color: hsl(0, 100%, 40%);">-    // Second Cell</span><br><span style="color: hsl(0, 100%, 40%);">-    dl_earfcn: 3050,</span><br><span style="color: hsl(0, 100%, 40%);">-    rf_port: 1,</span><br><span style="color: hsl(0, 100%, 40%);">-    cell_id: 0x02,</span><br><span style="color: hsl(0, 100%, 40%);">-    n_id_cell: 2,</span><br><span style="color: hsl(120, 100%, 40%);">+    dl_earfcn: ${cell.dl_earfcn},</span><br><span style="color: hsl(120, 100%, 40%);">+    rf_port: ${loop.index},</span><br><span style="color: hsl(120, 100%, 40%);">+    cell_id: ${cell.cell_id},</span><br><span style="color: hsl(120, 100%, 40%);">+    n_id_cell: ${loop.index + 1},</span><br><span>     tac: 0x0001,</span><br><span style="color: hsl(0, 100%, 40%);">-    root_sequence_index: 205,</span><br><span style="color: hsl(120, 100%, 40%);">+    root_sequence_index: ${loop.index + 204}, /* PRACH root sequence index */</span><br><span> </span><br><span>     scell_list: [</span><br><span style="color: hsl(0, 100%, 40%);">-      { cell_id: 0x01, cross_carrier_scheduling: false, scheduling_cell_id: 0x02, ul_allowed: true},</span><br><span style="color: hsl(120, 100%, 40%);">+%for scell_id in cell.scell_list:</span><br><span style="color: hsl(120, 100%, 40%);">+      { cell_id: ${scell_id}, cross_carrier_scheduling: false, scheduling_cell_id: ${cell.cell_id}, ul_allowed: true},</span><br><span style="color: hsl(120, 100%, 40%);">+%endfor</span><br><span>     ],</span><br><span>   },</span><br><span style="color: hsl(0, 100%, 40%);">-% endif</span><br><span style="color: hsl(120, 100%, 40%);">+%endfor</span><br><span>   ], /* cell_list */</span><br><span> </span><br><span>   /* default cell parameters */</span><br><span>diff --git a/sysmocom/defaults.conf b/sysmocom/defaults.conf</span><br><span>index f3994bb..bf5bce1 100644</span><br><span>--- a/sysmocom/defaults.conf</span><br><span>+++ b/sysmocom/defaults.conf</span><br><span>@@ -123,6 +123,13 @@</span><br><span>   a3_report_value: 6</span><br><span>   a3_hysteresis: 0</span><br><span>   a3_time_to_trigger: 480</span><br><span style="color: hsl(120, 100%, 40%);">+  cell_list:</span><br><span style="color: hsl(120, 100%, 40%);">+   - cell_id: 0x01</span><br><span style="color: hsl(120, 100%, 40%);">+     dl_earfcn: 2850</span><br><span style="color: hsl(120, 100%, 40%);">+     scell_list: [0x02]</span><br><span style="color: hsl(120, 100%, 40%);">+   - cell_id: 0x02</span><br><span style="color: hsl(120, 100%, 40%);">+     dl_earfcn: 3050</span><br><span style="color: hsl(120, 100%, 40%);">+     scell_list: [0x01]</span><br><span> </span><br><span> srsenb:</span><br><span>   num_prb: 100</span><br><span>diff --git a/sysmocom/suites/4g/handover.py b/sysmocom/suites/4g/handover.py</span><br><span>new file mode 100755</span><br><span>index 0000000..3a49321</span><br><span>--- /dev/null</span><br><span>+++ b/sysmocom/suites/4g/handover.py</span><br><span>@@ -0,0 +1,29 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python3</span><br><span style="color: hsl(120, 100%, 40%);">+from osmo_gsm_tester.testenv import *</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+epc = suite.epc()</span><br><span style="color: hsl(120, 100%, 40%);">+enb = suite.enb()</span><br><span style="color: hsl(120, 100%, 40%);">+ue = suite.modem()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+epc.subscriber_add(ue)</span><br><span style="color: hsl(120, 100%, 40%);">+epc.start()</span><br><span style="color: hsl(120, 100%, 40%);">+enb.ue_add(ue)</span><br><span style="color: hsl(120, 100%, 40%);">+enb.start(epc)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+print('waiting for ENB to connect to EPC...')</span><br><span style="color: hsl(120, 100%, 40%);">+wait(epc.enb_is_connected, enb)</span><br><span style="color: hsl(120, 100%, 40%);">+print('ENB is connected to EPC')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ue.connect(enb)</span><br><span style="color: hsl(120, 100%, 40%);">+print('waiting for UE to attach...')</span><br><span style="color: hsl(120, 100%, 40%);">+wait(ue.is_connected, None)</span><br><span style="color: hsl(120, 100%, 40%);">+print('UE is attached')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+sleep(2)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rfemu = enb.get_rfemu()</span><br><span style="color: hsl(120, 100%, 40%);">+for att in range(1, 10, 1):</span><br><span style="color: hsl(120, 100%, 40%);">+    print("Setting cell attenuation %d..." % att)</span><br><span style="color: hsl(120, 100%, 40%);">+    rfemu.set_attenuation(att)</span><br><span style="color: hsl(120, 100%, 40%);">+    sleep(1)</span><br><span style="color: hsl(120, 100%, 40%);">+print("Done")</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/17842">change 17842</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/+/17842"/><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: I4fd30a3e37789b76bfaddc2beba1815154daab7f </div>
<div style="display:none"> Gerrit-Change-Number: 17842 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>