<p>pespin <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/17847">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">enb: Implement initial RF emulation API<br><br>Two implementations are provided:<br>* Amarisoft Ctrl interface (websocket)<br>* Mini-Circuits Programmable Attenuator (HW, HTTP API) [1]<br><br>in Amarisoft ENBs, if no rfemu is configured explicitly, the Ctrl<br>interface one is used by default, while still being possible to use the<br>HW one.<br><br>[1] https://www.minicircuits.com/pdfs/RC4DAT-6G-60.pdf<br><br>Change-Id: Ie98a3fb9bcd2b87b96ecbb5b79e0f53981892a32<br>---<br>M src/osmo_gsm_tester/obj/enb.py<br>M src/osmo_gsm_tester/obj/enb_amarisoft.py<br>M src/osmo_gsm_tester/obj/enb_srs.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>7 files changed, 227 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/osmo_gsm_tester/obj/enb.py b/src/osmo_gsm_tester/obj/enb.py</span><br><span>index 340ea3a..59b5bfe 100644</span><br><span>--- a/src/osmo_gsm_tester/obj/enb.py</span><br><span>+++ b/src/osmo_gsm_tester/obj/enb.py</span><br><span>@@ -113,6 +113,11 @@</span><br><span>     def ue_max_rate(self, downlink=True):</span><br><span>         pass</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    @abstractmethod</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%);">+        'Get rfemu.RFemulation subclass implementation object for given cell index and direction.'</span><br><span style="color: hsl(120, 100%, 40%);">+        pass</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def addr(self):</span><br><span>         return self._addr</span><br><span> </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 996af19..0b748e0 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>@@ -209,6 +211,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>@@ -233,4 +237,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%);">+                         'ports': [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/enb_srs.py b/src/osmo_gsm_tester/obj/enb_srs.py</span><br><span>index c9721d1..e657b04 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>@@ -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 ('zmq', 'uhd', 'soapy', 'bladerf')</span><br><span>@@ -60,6 +61,7 @@</span><br><span>         super().__init__(suite_run, conf, srsENB.BINFILE)</span><br><span>         self.ue = None</span><br><span>         self.run_dir = 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_sib_file = None</span><br><span>         self.config_rr_file = None</span><br><span>@@ -221,6 +223,8 @@</span><br><span> </span><br><span>                 config.overlay(values, dict(enb=dict(rf_dev_args=rf_dev_args)))</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, srsENB.CFGFILE, values)</span><br><span>         self.gen_conf_file(self.config_sib_file, srsENB.CFGFILE_SIB, values)</span><br><span>         self.gen_conf_file(self.config_rr_file, srsENB.CFGFILE_RR, values)</span><br><span>@@ -243,4 +247,14 @@</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%);">+            raise log.Error('rfemu attribute not found in cell_list item!')</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..b2add6b</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo_gsm_tester/obj/rfemu.py</span><br><span>@@ -0,0 +1,57 @@</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%);">+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%);">+    if rfemu_type == 'amarisoftctl':</span><br><span style="color: hsl(120, 100%, 40%);">+        from .rfemu_amarisoftctrl import RFemulationAmarisoftCtrl</span><br><span style="color: hsl(120, 100%, 40%);">+        obj = RFemulationAmarisoftCtrl</span><br><span style="color: hsl(120, 100%, 40%);">+    elif rfemu_type == 'minicircuits':</span><br><span style="color: hsl(120, 100%, 40%);">+        from .rfemu_minicircuits import RFemulationMinicircuitsHTTP</span><br><span style="color: hsl(120, 100%, 40%);">+        obj = RFemulationMinicircuitsHTTP</span><br><span style="color: hsl(120, 100%, 40%);">+    else:</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%);">+</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..87e4cbd</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo_gsm_tester/obj/rfemu_amarisoftctrl.py</span><br><span>@@ -0,0 +1,62 @@</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('ports')</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 or len(self.port) != 1:</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.port = self.port[0]</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..eea3a0e</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo_gsm_tester/obj/rfemu_minicircuits.py</span><br><span>@@ -0,0 +1,67 @@</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.ports = conf.get('ports')</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.ports is None or len(self.ports) == 0:</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:%r)' % (self.addr, self.ports))</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%);">+        ports_str = ""</span><br><span style="color: hsl(120, 100%, 40%);">+        for port in self.ports:</span><br><span style="color: hsl(120, 100%, 40%);">+            ports_str = ports_str + str(port) + ":"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return self._url_prefix() + '/:CHAN:' + ports_str + '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%);">+        data_str = str(data, 'utf-8')</span><br><span style="color: hsl(120, 100%, 40%);">+        self.dbg('Received response: "%s"' % data_str)</span><br><span style="color: hsl(120, 100%, 40%);">+        if data_str != '1':</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('Mini-circuits attenuation device returned failure! %s' & data_str)</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 efb7d5a..d4757f3 100644</span><br><span>--- a/src/osmo_gsm_tester/resource.py</span><br><span>+++ b/src/osmo_gsm_tester/resource.py</span><br><span>@@ -111,6 +111,9 @@</span><br><span>         'enb[].cell_list[].cell_id': schema.UINT,</span><br><span>         'enb[].cell_list[].scell_list[]': schema.UINT,</span><br><span>         '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.ports[]': 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></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/17847">change 17847</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/+/17847"/><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: Ie98a3fb9bcd2b87b96ecbb5b79e0f53981892a32 </div>
<div style="display:none"> Gerrit-Change-Number: 17847 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: srs_andre <andre@softwareradiosystems.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>