<p>laforge <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmocom-bb/+/14585">View Change</a></p><div style="white-space:pre-wrap">Approvals:
osmith: Looks good to me, approved
Jenkins Builder: Verified
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">trx_toolkit/fake_trx.py: basic TRXD version 0x01 support<br><br>Since the new TRXD header format has been introduced, FakeTRX needs<br>to be able to fill it correctly. In particular, the following:<br><br> - Modulation, which can be determined from the burst length;<br> - Training Sequence Code (and set), which needs to be detected<br> by comparing the burst bits of L12TRX message against known<br> training sequences (only GMSK and the default TS set for now);<br> - C/I (Carrier-to-Interference ratio), which can be simulated<br> later on, as instructed on the TRXC interface ('FAKE_CI').<br><br>The actual TRXD header version is stored in the instance of class<br>DATAInterface. By default (at startup), legacy version 0 is used.<br>The version negotiation is supposed to be performed on the TRXC<br>interface, and to be implemented in a follow-up change.<br><br>Different Transceivers may use different header versions, thus in<br>FakeTRX.send_data_msg() we need to override the original version<br>of the L12TRX message, and generate the corresponding PDU.<br><br>Limitations:<br><br> - NOPE / IDLE indications are not (yet) supported;<br> - TSC detection: GMSK modulation only.<br><br>Change-Id: I164f5ae4ce7694d6e324aab927a04e96d489ebd8<br>Related: OS#4006<br>---<br>M src/target/trx_toolkit/burst_fwd.py<br>M src/target/trx_toolkit/data_if.py<br>M src/target/trx_toolkit/fake_trx.py<br>3 files changed, 78 insertions(+), 5 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/target/trx_toolkit/burst_fwd.py b/src/target/trx_toolkit/burst_fwd.py</span><br><span>index 164271f..1d5dd7b 100644</span><br><span>--- a/src/target/trx_toolkit/burst_fwd.py</span><br><span>+++ b/src/target/trx_toolkit/burst_fwd.py</span><br><span>@@ -84,4 +84,4 @@</span><br><span> if tx_msg.tn not in trx.ts_list:</span><br><span> continue</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- trx.send_data_msg(src_trx, tx_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ trx.send_data_msg(src_trx, rx_msg, tx_msg)</span><br><span>diff --git a/src/target/trx_toolkit/data_if.py b/src/target/trx_toolkit/data_if.py</span><br><span>index 027fd85..10df438 100644</span><br><span>--- a/src/target/trx_toolkit/data_if.py</span><br><span>+++ b/src/target/trx_toolkit/data_if.py</span><br><span>@@ -4,7 +4,7 @@</span><br><span> # TRX Toolkit</span><br><span> # DATA interface implementation</span><br><span> #</span><br><span style="color: hsl(0, 100%, 40%);">-# (C) 2017-2018 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2017-2019 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span> #</span><br><span> # All Rights Reserved</span><br><span> #</span><br><span>@@ -29,9 +29,29 @@</span><br><span> </span><br><span> class DATAInterface(UDPLink):</span><br><span> def __init__(self, *udp_link_args):</span><br><span style="color: hsl(120, 100%, 40%);">+ # Default header version (legacy)</span><br><span style="color: hsl(120, 100%, 40%);">+ self._hdr_ver = 0x00</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> UDPLink.__init__(self, *udp_link_args)</span><br><span> log.debug("Init TRXD interface (%s)" % self.desc_link())</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ def set_hdr_ver(self, ver):</span><br><span style="color: hsl(120, 100%, 40%);">+ if not ver in DATAMSG.known_versions:</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%);">+ self._hdr_ver = ver</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 match_hdr_ver(self, msg):</span><br><span style="color: hsl(120, 100%, 40%);">+ if msg.ver == self._hdr_ver:</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%);">+ log.error("(%s) Rx DATA message (%s) with unexpected header "</span><br><span style="color: hsl(120, 100%, 40%);">+ "version %u (!= expected %u), ignoring..."</span><br><span style="color: hsl(120, 100%, 40%);">+ % (self.desc_link(), msg.desc_hdr(),</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.ver, self._hdr_ver))</span><br><span style="color: hsl(120, 100%, 40%);">+ return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> def recv_raw_data(self):</span><br><span> data, _ = self.sock.recvfrom(512)</span><br><span> return data</span><br><span>@@ -49,6 +69,11 @@</span><br><span> "from R:%s:%u" % (self.remote_addr, self.remote_port))</span><br><span> return None</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ # Make sure the header version matches</span><br><span style="color: hsl(120, 100%, 40%);">+ # the configured one (self._hdr_ver)</span><br><span style="color: hsl(120, 100%, 40%);">+ if not self.match_hdr_ver(msg):</span><br><span style="color: hsl(120, 100%, 40%);">+ return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return msg</span><br><span> </span><br><span> def recv_trx2l1_msg(self):</span><br><span>@@ -64,6 +89,11 @@</span><br><span> "from R:%s:%u" % (self.remote_addr, self.remote_port))</span><br><span> return None</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ # Make sure the header version matches</span><br><span style="color: hsl(120, 100%, 40%);">+ # the configured one (self._hdr_ver)</span><br><span style="color: hsl(120, 100%, 40%);">+ if not self.match_hdr_ver(msg):</span><br><span style="color: hsl(120, 100%, 40%);">+ return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return msg</span><br><span> </span><br><span> def send_msg(self, msg, legacy = False):</span><br><span>diff --git a/src/target/trx_toolkit/fake_trx.py b/src/target/trx_toolkit/fake_trx.py</span><br><span>index 928333f..de0e6ff 100755</span><br><span>--- a/src/target/trx_toolkit/fake_trx.py</span><br><span>+++ b/src/target/trx_toolkit/fake_trx.py</span><br><span>@@ -35,9 +35,11 @@</span><br><span> from app_common import ApplicationBase</span><br><span> from burst_fwd import BurstForwarder</span><br><span> from transceiver import Transceiver</span><br><span style="color: hsl(120, 100%, 40%);">+from data_msg import Modulation</span><br><span> from clck_gen import CLCKGen</span><br><span> from trx_list import TRXList</span><br><span> from fake_pm import FakePM</span><br><span style="color: hsl(120, 100%, 40%);">+from gsm_shared import *</span><br><span> </span><br><span> class FakeTRX(Transceiver):</span><br><span> """ Fake transceiver with RF path (burst loss, RSSI, TA, ToA) simulation.</span><br><span>@@ -98,18 +100,21 @@</span><br><span> </span><br><span> TOA256_BASE_DEFAULT = 0</span><br><span> RSSI_BASE_DEFAULT = -60</span><br><span style="color: hsl(120, 100%, 40%);">+ CI_BASE_DEFAULT = 90</span><br><span> </span><br><span> def __init__(self, *trx_args, **trx_kwargs):</span><br><span> Transceiver.__init__(self, *trx_args, **trx_kwargs)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- # Actual ToA / RSSI / TA values</span><br><span style="color: hsl(120, 100%, 40%);">+ # Actual ToA, RSSI, C/I, TA values</span><br><span> self.toa256_base = self.TOA256_BASE_DEFAULT</span><br><span> self.rssi_base = self.RSSI_BASE_DEFAULT</span><br><span style="color: hsl(120, 100%, 40%);">+ self.ci_base = self.CI_BASE_DEFAULT</span><br><span> self.ta = 0</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- # ToA / RSSI randomization threshold</span><br><span style="color: hsl(120, 100%, 40%);">+ # ToA, RSSI, C/I randomization thresholds</span><br><span> self.toa256_rand_threshold = 0</span><br><span> self.rssi_rand_threshold = 0</span><br><span style="color: hsl(120, 100%, 40%);">+ self.ci_rand_threshold = 0</span><br><span> </span><br><span> # Path loss simulation (burst dropping)</span><br><span> self.burst_drop_amount = 0</span><br><span>@@ -137,6 +142,17 @@</span><br><span> rssi_max = self.rssi_base + self.rssi_rand_threshold</span><br><span> return random.randint(rssi_min, rssi_max)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ @property</span><br><span style="color: hsl(120, 100%, 40%);">+ def ci(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ # Check if randomization is required</span><br><span style="color: hsl(120, 100%, 40%);">+ if self.ci_rand_threshold is 0:</span><br><span style="color: hsl(120, 100%, 40%);">+ return self.ci_base</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # Generate a random C/I value in required range</span><br><span style="color: hsl(120, 100%, 40%);">+ ci_min = self.ci_base - self.ci_rand_threshold</span><br><span style="color: hsl(120, 100%, 40%);">+ ci_max = self.ci_base + self.ci_rand_threshold</span><br><span style="color: hsl(120, 100%, 40%);">+ return random.randint(ci_min, ci_max)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # Path loss simulation: burst dropping</span><br><span> # Returns: True - drop, False - keep</span><br><span> def sim_burst_drop(self, msg):</span><br><span>@@ -152,14 +168,41 @@</span><br><span> </span><br><span> return False</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ def _handle_data_msg_v1(self, src_msg, msg):</span><br><span style="color: hsl(120, 100%, 40%);">+ # TODO: NOPE indications are not (yet) supported</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.nope_ind = False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # C/I (Carrier-to-Interference ratio)</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.ci = self.ci</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # Pick modulation type by burst length</span><br><span style="color: hsl(120, 100%, 40%);">+ bl = len(src_msg.burst)</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.mod_type = Modulation.pick_by_bl(bl)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # Pick TSC (Training Sequence Code) and TSC set</span><br><span style="color: hsl(120, 100%, 40%);">+ if msg.mod_type is Modulation.ModGMSK:</span><br><span style="color: hsl(120, 100%, 40%);">+ ss = TrainingSeqGMSK.pick(src_msg.burst)</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.tsc = ss.tsc if ss is not None else 0</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.tsc_set = ss.tsc_set if ss is not None else 0</span><br><span style="color: hsl(120, 100%, 40%);">+ else: # TODO: other modulation types (at least 8-PSK)</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.tsc_set = 0</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.tsc = 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # Takes (partially initialized) TRX2L1 message,</span><br><span> # simulates RF path parameters (such as RSSI),</span><br><span> # and sends towards the L1</span><br><span style="color: hsl(0, 100%, 40%);">- def send_data_msg(self, src_trx, msg):</span><br><span style="color: hsl(120, 100%, 40%);">+ def send_data_msg(self, src_trx, src_msg, msg):</span><br><span style="color: hsl(120, 100%, 40%);">+ # Override header version</span><br><span style="color: hsl(120, 100%, 40%);">+ msg.ver = self.data_if._hdr_ver</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # Complete message header</span><br><span> msg.toa256 = self.toa256</span><br><span> msg.rssi = self.rssi</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ # Version specific fields</span><br><span style="color: hsl(120, 100%, 40%);">+ if msg.ver >= 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+ self._handle_data_msg_v1(src_msg, msg)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # Apply optional Timing Advance</span><br><span> if src_trx.ta is not 0:</span><br><span> msg.toa256 -= src_trx.ta * 256</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmocom-bb/+/14585">change 14585</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/osmocom-bb/+/14585"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmocom-bb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I164f5ae4ce7694d6e324aab927a04e96d489ebd8 </div>
<div style="display:none"> Gerrit-Change-Number: 14585 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: fixeria <axilirator@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Hoernchen <ewild@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: fixeria <axilirator@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: osmith <osmith@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>