<p>Vadim Yanitskiy has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/12264">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">(WIP) trx_toolkit/fake_trx.py: refactor global class hierarchy<br><br>Change-Id: Ice44e2b22566b3652ef6d43896055963b13ab185<br>---<br>M src/target/trx_toolkit/burst_fwd.py<br>A src/target/trx_toolkit/clck_router_trx.py<br>D src/target/trx_toolkit/ctrl_if_bb.py<br>D src/target/trx_toolkit/ctrl_if_bts.py<br>A src/target/trx_toolkit/ctrl_if_trx.py<br>M src/target/trx_toolkit/fake_pm.py<br>M src/target/trx_toolkit/fake_trx.py<br>A src/target/trx_toolkit/transceiver.py<br>8 files changed, 614 insertions(+), 786 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/64/12264/1</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 3cb6acd..3a83753 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>@@ -2,7 +2,7 @@</span><br><span> # -*- coding: utf-8 -*-</span><br><span> </span><br><span> # TRX Toolkit</span><br><span style="color: hsl(0, 100%, 40%);">-# BTS <-> BB burst forwarding</span><br><span style="color: hsl(120, 100%, 40%);">+# Burst forwarding between transceivers</span><br><span> #</span><br><span> # (C) 2017-2018 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span> #</span><br><span>@@ -23,321 +23,58 @@</span><br><span> # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span> </span><br><span> import logging as log</span><br><span style="color: hsl(0, 100%, 40%);">-import random</span><br><span> </span><br><span> from data_msg import *</span><br><span> </span><br><span> class BurstForwarder:</span><br><span style="color: hsl(0, 100%, 40%);">-    """ Performs burst forwarding and preprocessing between MS and BTS.</span><br><span style="color: hsl(120, 100%, 40%);">+    """ Performs burst forwarding between transceivers.</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  == Pass-filtering parameters</span><br><span style="color: hsl(120, 100%, 40%);">+  BurstForwarder dispatches bursts between the list of given</span><br><span style="color: hsl(120, 100%, 40%);">+    FakeTRX (Transceiver) instances depending on the following</span><br><span style="color: hsl(120, 100%, 40%);">+    parameters of each transceiver:</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     BurstForwarder may drop or pass an UL/DL burst depending</span><br><span style="color: hsl(0, 100%, 40%);">-        on the following parameters:</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      - bts_freq / bb_freq - the current BTS / MS frequency</span><br><span style="color: hsl(0, 100%, 40%);">-     that was set using RXTUNE control command. By default,</span><br><span style="color: hsl(0, 100%, 40%);">-          both freq. values are set to None, so nothing is being</span><br><span style="color: hsl(0, 100%, 40%);">-          forwarded (i.e. bursts are getting dropped).</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            FIXME: currently, we don't care about TXTUNE command</span><br><span style="color: hsl(0, 100%, 40%);">-        and transmit frequencies. It would be great to distinguish</span><br><span style="color: hsl(0, 100%, 40%);">-      between RX and TX frequencies for both BTS and MS.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    - ts_pass_list - the list of active (i.e. configured)</span><br><span style="color: hsl(0, 100%, 40%);">-     timeslot numbers for the MS. A timeslot can be activated</span><br><span style="color: hsl(0, 100%, 40%);">-        or deactivated using SETSLOT control command from the MS.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       FIXME: there is no such list for the BTS side.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      == Preprocessing and measurement simulation</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     Since this is a virtual environment, we can simulate different</span><br><span style="color: hsl(0, 100%, 40%);">-  parameters of a virtual RF interface:</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     - ToA (Timing of Arrival) - measured difference between expected</span><br><span style="color: hsl(0, 100%, 40%);">-          and actual time of burst arrival in units of 1/256 of GSM symbol</span><br><span style="color: hsl(0, 100%, 40%);">-        periods. A pair of both base and threshold values defines a range</span><br><span style="color: hsl(0, 100%, 40%);">-       of ToA value randomization:</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       DL: from (toa256_dl_base - toa256_dl_threshold)</span><br><span style="color: hsl(0, 100%, 40%);">-               to (toa256_dl_base + toa256_dl_threshold),</span><br><span style="color: hsl(0, 100%, 40%);">-        UL: from (toa256_ul_base - toa256_ul_threshold)</span><br><span style="color: hsl(0, 100%, 40%);">-               to (toa256_ul_base + toa256_ul_threshold).</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    - RSSI (Received Signal Strength Indication) - measured "power" of</span><br><span style="color: hsl(0, 100%, 40%);">-      the signal (per burst) in dBm. A pair of both base and threshold</span><br><span style="color: hsl(0, 100%, 40%);">-        values defines a range of RSSI value randomization:</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       DL: from (rssi_dl_base - rssi_dl_threshold)</span><br><span style="color: hsl(0, 100%, 40%);">-                   to (rssi_dl_base + rssi_dl_threshold),</span><br><span style="color: hsl(0, 100%, 40%);">-            UL: from (rssi_ul_base - rssi_ul_threshold)</span><br><span style="color: hsl(0, 100%, 40%);">-                   to (rssi_ul_base + rssi_ul_threshold).</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      Please note that the randomization of both RSSI and ToA</span><br><span style="color: hsl(0, 100%, 40%);">- is optional, and can be enabled from the control interface.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     === Timing Advance handling</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     The BTS is using ToA measurements for UL bursts in order to calculate</span><br><span style="color: hsl(0, 100%, 40%);">-   Timing Advance value, that is then indicated to a MS, which in its turn</span><br><span style="color: hsl(0, 100%, 40%);">- shall apply this value to the transmitted signal in order to compensate</span><br><span style="color: hsl(0, 100%, 40%);">- the delay. Basically, every burst is transmitted in advance defined by</span><br><span style="color: hsl(0, 100%, 40%);">-  the indicated Timing Advance value. The valid range is 0..63, where</span><br><span style="color: hsl(0, 100%, 40%);">-     each unit means one GSM symbol advance. The actual Timing Advance value</span><br><span style="color: hsl(0, 100%, 40%);">- is set using SETTA control command from MS. By default, it's set to 0.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      === Path loss simulation - burst dropping</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       In some cases, e.g. due to a weak signal or high interference, a burst</span><br><span style="color: hsl(0, 100%, 40%);">-  can be lost, i.e. not detected by the receiver. This can also be</span><br><span style="color: hsl(0, 100%, 40%);">-        simulated using FAKE_DROP command on both control interfaces:</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     - burst_{dl|ul}_drop_amount - the amount of DL/UL bursts</span><br><span style="color: hsl(0, 100%, 40%);">-            to be dropped (i.e. not forwarded towards the MS/BTS),</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      - burst_{dl|ul}_drop_period - drop every X DL/UL burst, e.g.</span><br><span style="color: hsl(0, 100%, 40%);">-      1 - drop every consequent burst, 2 - drop every second burst, etc.</span><br><span style="color: hsl(120, 100%, 40%);">+          - execution state (running or idle),</span><br><span style="color: hsl(120, 100%, 40%);">+          - actual RX / TX frequencies,</span><br><span style="color: hsl(120, 100%, 40%);">+         - list of active timeslots.</span><br><span> </span><br><span>    """</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  def __init__(self, bts_link, bb_link):</span><br><span style="color: hsl(0, 100%, 40%);">-          self.bts_link = bts_link</span><br><span style="color: hsl(0, 100%, 40%);">-                self.bb_link = bb_link</span><br><span style="color: hsl(120, 100%, 40%);">+        def __init__(self, trx_list = []):</span><br><span style="color: hsl(120, 100%, 40%);">+            # List of Transceiver instances</span><br><span style="color: hsl(120, 100%, 40%);">+               self.trx_list = trx_list</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            # Init default parameters</span><br><span style="color: hsl(0, 100%, 40%);">-               self.reset_dl()</span><br><span style="color: hsl(0, 100%, 40%);">-         self.reset_ul()</span><br><span style="color: hsl(120, 100%, 40%);">+       def add_trx(self, trx):</span><br><span style="color: hsl(120, 100%, 40%);">+               if trx in self.trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                      log.error("TRX is already in the list")</span><br><span style="color: hsl(120, 100%, 40%);">+                     return</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      # Initialize (or reset to) default parameters for Downlink</span><br><span style="color: hsl(0, 100%, 40%);">-      def reset_dl(self):</span><br><span style="color: hsl(0, 100%, 40%);">-             # Unset current DL freq.</span><br><span style="color: hsl(0, 100%, 40%);">-                self.bts_freq = None</span><br><span style="color: hsl(120, 100%, 40%);">+          self.trx_list.append(trx)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           # Indicated RSSI / ToA values</span><br><span style="color: hsl(0, 100%, 40%);">-           self.toa256_dl_base = 0</span><br><span style="color: hsl(0, 100%, 40%);">-         self.rssi_dl_base = -60</span><br><span style="color: hsl(120, 100%, 40%);">+       def del_trx(self, trx):</span><br><span style="color: hsl(120, 100%, 40%);">+               if trx not in self.trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                  log.error("TRX is not in the list")</span><br><span style="color: hsl(120, 100%, 40%);">+                 return</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              # RSSI / ToA randomization threshold</span><br><span style="color: hsl(0, 100%, 40%);">-            self.toa256_dl_threshold = 0</span><br><span style="color: hsl(0, 100%, 40%);">-            self.rssi_dl_threshold = 0</span><br><span style="color: hsl(120, 100%, 40%);">+            self.trx_list.remove(trx)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           # Path loss simulation (burst dropping)</span><br><span style="color: hsl(0, 100%, 40%);">-         self.burst_dl_drop_amount = 0</span><br><span style="color: hsl(0, 100%, 40%);">-           self.burst_dl_drop_period = 1</span><br><span style="color: hsl(120, 100%, 40%);">+ def forward_msg(self, src_trx, rx_msg):</span><br><span style="color: hsl(120, 100%, 40%);">+               # Transform from L12TRX to TRX2L1</span><br><span style="color: hsl(120, 100%, 40%);">+             tx_msg = rx_msg.gen_trx2l1()</span><br><span style="color: hsl(120, 100%, 40%);">+          if tx_msg is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                    log.error("Forwarding failed, could not transform "</span><br><span style="color: hsl(120, 100%, 40%);">+                         "message (%s) => dropping..." % rx_msg.desc_hdr())</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     # Initialize (or reset to) default parameters for Uplink</span><br><span style="color: hsl(0, 100%, 40%);">-        def reset_ul(self):</span><br><span style="color: hsl(0, 100%, 40%);">-             # Unset current DL freq.</span><br><span style="color: hsl(0, 100%, 40%);">-                self.bb_freq = None</span><br><span style="color: hsl(120, 100%, 40%);">+           # Iterate over all known transceivers</span><br><span style="color: hsl(120, 100%, 40%);">+         for trx in self.trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                     if trx == src_trx:</span><br><span style="color: hsl(120, 100%, 40%);">+                            continue</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            # Indicated RSSI / ToA values</span><br><span style="color: hsl(0, 100%, 40%);">-           self.rssi_ul_base = -70</span><br><span style="color: hsl(0, 100%, 40%);">-         self.toa256_ul_base = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                       # Check transceiver state</span><br><span style="color: hsl(120, 100%, 40%);">+                     if not trx.running:</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue</span><br><span style="color: hsl(120, 100%, 40%);">+                      if trx.rx_freq != src_trx.tx_freq:</span><br><span style="color: hsl(120, 100%, 40%);">+                            continue</span><br><span style="color: hsl(120, 100%, 40%);">+                      if tx_msg.tn not in trx.ts_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                              continue</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            # RSSI / ToA randomization threshold</span><br><span style="color: hsl(0, 100%, 40%);">-            self.toa256_ul_threshold = 0</span><br><span style="color: hsl(0, 100%, 40%);">-            self.rssi_ul_threshold = 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-              # Path loss simulation (burst dropping)</span><br><span style="color: hsl(0, 100%, 40%);">-         self.burst_ul_drop_amount = 0</span><br><span style="color: hsl(0, 100%, 40%);">-           self.burst_ul_drop_period = 1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           # Init timeslot filter (drop everything by default)</span><br><span style="color: hsl(0, 100%, 40%);">-             self.ts_pass_list = []</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          # Reset Timing Advance value</span><br><span style="color: hsl(0, 100%, 40%);">-            self.ta = 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     # Converts TA value from symbols to</span><br><span style="color: hsl(0, 100%, 40%);">-     # units of 1/256 of GSM symbol periods</span><br><span style="color: hsl(0, 100%, 40%);">-  def calc_ta256(self):</span><br><span style="color: hsl(0, 100%, 40%);">-           return self.ta * 256</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    # Calculates a random ToA value for Downlink bursts</span><br><span style="color: hsl(0, 100%, 40%);">-     def calc_dl_toa256(self):</span><br><span style="color: hsl(0, 100%, 40%);">-               # Check if randomization is required</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.toa256_dl_threshold is 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                       return self.toa256_dl_base</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-              # Calculate a range for randomization</span><br><span style="color: hsl(0, 100%, 40%);">-           toa256_min = self.toa256_dl_base - self.toa256_dl_threshold</span><br><span style="color: hsl(0, 100%, 40%);">-             toa256_max = self.toa256_dl_base + self.toa256_dl_threshold</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Generate a random ToA value</span><br><span style="color: hsl(0, 100%, 40%);">-           toa256 = random.randint(toa256_min, toa256_max)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         return toa256</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   # Calculates a random ToA value for Uplink bursts</span><br><span style="color: hsl(0, 100%, 40%);">-       def calc_ul_toa256(self):</span><br><span style="color: hsl(0, 100%, 40%);">-               # Check if randomization is required</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.toa256_ul_threshold is 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                       return self.toa256_ul_base</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-              # Calculate a range for randomization</span><br><span style="color: hsl(0, 100%, 40%);">-           toa256_min = self.toa256_ul_base - self.toa256_ul_threshold</span><br><span style="color: hsl(0, 100%, 40%);">-             toa256_max = self.toa256_ul_base + self.toa256_ul_threshold</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Generate a random ToA value</span><br><span style="color: hsl(0, 100%, 40%);">-           toa256 = random.randint(toa256_min, toa256_max)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         return toa256</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   # Calculates a random RSSI value for Downlink bursts</span><br><span style="color: hsl(0, 100%, 40%);">-    def calc_dl_rssi(self):</span><br><span style="color: hsl(0, 100%, 40%);">-         # Check if randomization is required</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.rssi_dl_threshold is 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                 return self.rssi_dl_base</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Calculate a range for randomization</span><br><span style="color: hsl(0, 100%, 40%);">-           rssi_min = self.rssi_dl_base - self.rssi_dl_threshold</span><br><span style="color: hsl(0, 100%, 40%);">-           rssi_max = self.rssi_dl_base + self.rssi_dl_threshold</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           # Generate a random RSSI value</span><br><span style="color: hsl(0, 100%, 40%);">-          return random.randint(rssi_min, rssi_max)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       # Calculates a random RSSI value for Uplink bursts</span><br><span style="color: hsl(0, 100%, 40%);">-      def calc_ul_rssi(self):</span><br><span style="color: hsl(0, 100%, 40%);">-         # Check if randomization is required</span><br><span style="color: hsl(0, 100%, 40%);">-            if self.rssi_ul_threshold is 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                 return self.rssi_ul_base</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Calculate a range for randomization</span><br><span style="color: hsl(0, 100%, 40%);">-           rssi_min = self.rssi_ul_base - self.rssi_ul_threshold</span><br><span style="color: hsl(0, 100%, 40%);">-           rssi_max = self.rssi_ul_base + self.rssi_ul_threshold</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           # Generate a random RSSI value</span><br><span style="color: hsl(0, 100%, 40%);">-          return random.randint(rssi_min, rssi_max)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       # DL path loss simulation</span><br><span style="color: hsl(0, 100%, 40%);">-       def path_loss_sim_dl(self, msg):</span><br><span style="color: hsl(0, 100%, 40%);">-                # Burst dropping</span><br><span style="color: hsl(0, 100%, 40%);">-                if self.burst_dl_drop_amount > 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                    if msg.fn % self.burst_dl_drop_period == 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                             log.info("Simulation: dropping DL burst (fn=%u %% %u == 0)"</span><br><span style="color: hsl(0, 100%, 40%);">-                                   % (msg.fn, self.burst_dl_drop_period))</span><br><span style="color: hsl(0, 100%, 40%);">-                          self.burst_dl_drop_amount -= 1</span><br><span style="color: hsl(0, 100%, 40%);">-                          return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             return msg</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      # UL path loss simulation</span><br><span style="color: hsl(0, 100%, 40%);">-       def path_loss_sim_ul(self, msg):</span><br><span style="color: hsl(0, 100%, 40%);">-                # Burst dropping</span><br><span style="color: hsl(0, 100%, 40%);">-                if self.burst_ul_drop_amount > 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                    if msg.fn % self.burst_ul_drop_period == 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                             log.info("Simulation: dropping UL burst (fn=%u %% %u == 0)"</span><br><span style="color: hsl(0, 100%, 40%);">-                                   % (msg.fn, self.burst_ul_drop_period))</span><br><span style="color: hsl(0, 100%, 40%);">-                          self.burst_ul_drop_amount -= 1</span><br><span style="color: hsl(0, 100%, 40%);">-                          return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             return msg</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      # DL burst preprocessing</span><br><span style="color: hsl(0, 100%, 40%);">-        def preprocess_dl_burst(self, msg):</span><br><span style="color: hsl(0, 100%, 40%);">-             # Calculate both RSSI and ToA values</span><br><span style="color: hsl(0, 100%, 40%);">-            msg.toa256 = self.calc_dl_toa256()</span><br><span style="color: hsl(0, 100%, 40%);">-              msg.rssi = self.calc_dl_rssi()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  # UL burst preprocessing</span><br><span style="color: hsl(0, 100%, 40%);">-        def preprocess_ul_burst(self, msg):</span><br><span style="color: hsl(0, 100%, 40%);">-             # Calculate both RSSI and ToA values,</span><br><span style="color: hsl(0, 100%, 40%);">-           # also apply Timing Advance</span><br><span style="color: hsl(0, 100%, 40%);">-             msg.toa256 = self.calc_ul_toa256()</span><br><span style="color: hsl(0, 100%, 40%);">-              msg.toa256 -= self.calc_ta256()</span><br><span style="color: hsl(0, 100%, 40%);">-         msg.rssi = self.calc_ul_rssi()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  # Converts a L12TRX message to TRX2L1 message</span><br><span style="color: hsl(0, 100%, 40%);">-   def transform_msg(self, msg_raw):</span><br><span style="color: hsl(0, 100%, 40%);">-               # Attempt to parse a message</span><br><span style="color: hsl(0, 100%, 40%);">-            try:</span><br><span style="color: hsl(0, 100%, 40%);">-                    msg_l12trx = DATAMSG_L12TRX()</span><br><span style="color: hsl(0, 100%, 40%);">-                   msg_l12trx.parse_msg(bytearray(msg_raw))</span><br><span style="color: hsl(0, 100%, 40%);">-                except:</span><br><span style="color: hsl(0, 100%, 40%);">-                 log.error("Dropping unhandled DL message...")</span><br><span style="color: hsl(0, 100%, 40%);">-                 return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Compose a new message for L1</span><br><span style="color: hsl(0, 100%, 40%);">-          return msg_l12trx.gen_trx2l1()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  # Downlink handler: BTS -> BB</span><br><span style="color: hsl(0, 100%, 40%);">-        def bts2bb(self):</span><br><span style="color: hsl(0, 100%, 40%);">-               # Read data from socket</span><br><span style="color: hsl(0, 100%, 40%);">-         data, addr = self.bts_link.sock.recvfrom(512)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           # BB is not connected / tuned</span><br><span style="color: hsl(0, 100%, 40%);">-           if self.bb_freq is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                        return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Freq. filter</span><br><span style="color: hsl(0, 100%, 40%);">-          if self.bb_freq != self.bts_freq:</span><br><span style="color: hsl(0, 100%, 40%);">-                       return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Process a message</span><br><span style="color: hsl(0, 100%, 40%);">-             msg = self.transform_msg(data)</span><br><span style="color: hsl(0, 100%, 40%);">-          if msg is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                 return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Timeslot filter</span><br><span style="color: hsl(0, 100%, 40%);">-               if msg.tn not in self.ts_pass_list:</span><br><span style="color: hsl(0, 100%, 40%);">-                     return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Path loss simulation</span><br><span style="color: hsl(0, 100%, 40%);">-          msg = self.path_loss_sim_dl(msg)</span><br><span style="color: hsl(0, 100%, 40%);">-                if msg is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                 return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Burst preprocessing</span><br><span style="color: hsl(0, 100%, 40%);">-           self.preprocess_dl_burst(msg)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           # Validate and generate the payload</span><br><span style="color: hsl(0, 100%, 40%);">-             payload = msg.gen_msg()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         # Append two unused bytes at the end</span><br><span style="color: hsl(0, 100%, 40%);">-            # in order to keep the compatibility</span><br><span style="color: hsl(0, 100%, 40%);">-            payload += bytearray(2)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         # Send burst to BB</span><br><span style="color: hsl(0, 100%, 40%);">-              self.bb_link.send(payload)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      # Uplink handler: BB -> BTS</span><br><span style="color: hsl(0, 100%, 40%);">-  def bb2bts(self):</span><br><span style="color: hsl(0, 100%, 40%);">-               # Read data from socket</span><br><span style="color: hsl(0, 100%, 40%);">-         data, addr = self.bb_link.sock.recvfrom(512)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            # BTS is not connected / tuned</span><br><span style="color: hsl(0, 100%, 40%);">-          if self.bts_freq is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                       return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Freq. filter</span><br><span style="color: hsl(0, 100%, 40%);">-          if self.bb_freq != self.bts_freq:</span><br><span style="color: hsl(0, 100%, 40%);">-                       return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Process a message</span><br><span style="color: hsl(0, 100%, 40%);">-             msg = self.transform_msg(data)</span><br><span style="color: hsl(0, 100%, 40%);">-          if msg is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                 return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Timeslot filter</span><br><span style="color: hsl(0, 100%, 40%);">-               if msg.tn not in self.ts_pass_list:</span><br><span style="color: hsl(0, 100%, 40%);">-                     log.warning("TS %u is not configured, dropping UL burst..." % msg.tn)</span><br><span style="color: hsl(0, 100%, 40%);">-                 return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Path loss simulation</span><br><span style="color: hsl(0, 100%, 40%);">-          msg = self.path_loss_sim_ul(msg)</span><br><span style="color: hsl(0, 100%, 40%);">-                if msg is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                 return None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Burst preprocessing</span><br><span style="color: hsl(0, 100%, 40%);">-           self.preprocess_ul_burst(msg)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           # Validate and generate the payload</span><br><span style="color: hsl(0, 100%, 40%);">-             payload = msg.gen_msg()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         # Append two unused bytes at the end</span><br><span style="color: hsl(0, 100%, 40%);">-            # in order to keep the compatibility</span><br><span style="color: hsl(0, 100%, 40%);">-            payload += bytearray(2)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         # Send burst to BTS</span><br><span style="color: hsl(0, 100%, 40%);">-             self.bts_link.send(payload)</span><br><span style="color: hsl(120, 100%, 40%);">+                   trx.send_data_msg(tx_msg)</span><br><span>diff --git a/src/target/trx_toolkit/clck_router_trx.py b/src/target/trx_toolkit/clck_router_trx.py</span><br><span>new file mode 100755</span><br><span>index 0000000..c85286b</span><br><span>--- /dev/null</span><br><span>+++ b/src/target/trx_toolkit/clck_router_trx.py</span><br><span>@@ -0,0 +1,52 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python2</span><br><span style="color: hsl(120, 100%, 40%);">+# -*- coding: utf-8 -*-</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# TRX Toolkit</span><br><span style="color: hsl(120, 100%, 40%);">+# Clock distribution router for transceivers</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# All Rights Reserved</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 published by</span><br><span style="color: hsl(120, 100%, 40%);">+# the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+# (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 along</span><br><span style="color: hsl(120, 100%, 40%);">+# with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import logging as log</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from clck_gen import CLCKGen</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class CLCKRouterTRX(CLCKGen):</span><br><span style="color: hsl(120, 100%, 40%);">+        def __init__(self, trx_list, *clck_gen_argv):</span><br><span style="color: hsl(120, 100%, 40%);">+         CLCKGen.__init__(self, [], *clck_gen_argv)</span><br><span style="color: hsl(120, 100%, 40%);">+            self.trx_list = trx_list</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def poke(self, trx):</span><br><span style="color: hsl(120, 100%, 40%);">+          log.debug("CLCKRouterTRX poke!")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (trx.clck_if not in self.clck_links) and trx.running:</span><br><span style="color: hsl(120, 100%, 40%);">+                      # Transceiver was started</span><br><span style="color: hsl(120, 100%, 40%);">+                     log.debug("Transceiver was started")</span><br><span style="color: hsl(120, 100%, 40%);">+                        self.clck_links.append(trx.clck_if)</span><br><span style="color: hsl(120, 100%, 40%);">+           elif (trx.clck_if in self.clck_links) and not trx.running:</span><br><span style="color: hsl(120, 100%, 40%);">+                    # Transceiver was stopped</span><br><span style="color: hsl(120, 100%, 40%);">+                     log.debug("Transceiver was stopped")</span><br><span style="color: hsl(120, 100%, 40%);">+                        self.clck_links.remove(trx.clck_if)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # Start / stop clock generator</span><br><span style="color: hsl(120, 100%, 40%);">+                if (len(self.clck_links) > 0) and self.timer is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                      log.debug("Starting clock generator")</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.start()</span><br><span style="color: hsl(120, 100%, 40%);">+          elif (len(self.clck_links) is 0) and self.timer is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                  log.debug("Stopping clock generator")</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.stop()</span><br><span>diff --git a/src/target/trx_toolkit/ctrl_if_bb.py b/src/target/trx_toolkit/ctrl_if_bb.py</span><br><span>deleted file mode 100644</span><br><span>index fe7f3e8..0000000</span><br><span>--- a/src/target/trx_toolkit/ctrl_if_bb.py</span><br><span>+++ /dev/null</span><br><span>@@ -1,227 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-#!/usr/bin/env python2</span><br><span style="color: hsl(0, 100%, 40%);">-# -*- coding: utf-8 -*-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# TRX Toolkit</span><br><span style="color: hsl(0, 100%, 40%);">-# CTRL interface implementation (OsmocomBB specific)</span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# (C) 2016-2017 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# All Rights Reserved</span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(0, 100%, 40%);">-# it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(0, 100%, 40%);">-# the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(0, 100%, 40%);">-# (at your option) any later version.</span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(0, 100%, 40%);">-# but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(0, 100%, 40%);">-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(0, 100%, 40%);">-# GNU General Public License for more details.</span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(0, 100%, 40%);">-# with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(0, 100%, 40%);">-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-import logging as log</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-from ctrl_if import CTRLInterface</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-class CTRLInterfaceBB(CTRLInterface):</span><br><span style="color: hsl(0, 100%, 40%);">-  # Internal state variables</span><br><span style="color: hsl(0, 100%, 40%);">-      trx_started = False</span><br><span style="color: hsl(0, 100%, 40%);">-     burst_fwd = None</span><br><span style="color: hsl(0, 100%, 40%);">-        rx_freq = None</span><br><span style="color: hsl(0, 100%, 40%);">-  tx_freq = None</span><br><span style="color: hsl(0, 100%, 40%);">-  pm = None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       def __init__(self, *udp_link_args):</span><br><span style="color: hsl(0, 100%, 40%);">-             CTRLInterface.__init__(self, *udp_link_args)</span><br><span style="color: hsl(0, 100%, 40%);">-            log.info("Init CTRL interface for BB (%s)" % self.desc_link())</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        def parse_cmd(self, request):</span><br><span style="color: hsl(0, 100%, 40%);">-           # Power control</span><br><span style="color: hsl(0, 100%, 40%);">-         if self.verify_cmd(request, "POWERON", 0):</span><br><span style="color: hsl(0, 100%, 40%);">-                    log.debug("Recv POWERON CMD")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 # Ensure transceiver isn't working</span><br><span style="color: hsl(0, 100%, 40%);">-                  if self.trx_started:</span><br><span style="color: hsl(0, 100%, 40%);">-                            log.error("Transceiver already started")</span><br><span style="color: hsl(0, 100%, 40%);">-                              return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Ensure RX / TX freq. are set</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (self.rx_freq is None) or (self.tx_freq is None):</span><br><span style="color: hsl(0, 100%, 40%);">-                            log.error("RX / TX freq. are not set")</span><br><span style="color: hsl(0, 100%, 40%);">-                                return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       log.info("Starting transceiver...")</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.trx_started = True</span><br><span style="color: hsl(0, 100%, 40%);">-                 return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                elif self.verify_cmd(request, "POWEROFF", 0):</span><br><span style="color: hsl(0, 100%, 40%);">-                 log.debug("Recv POWEROFF cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.info("Stopping transceiver...")</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.trx_started = False</span><br><span style="color: hsl(0, 100%, 40%);">-                        return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Tuning Control</span><br><span style="color: hsl(0, 100%, 40%);">-                elif self.verify_cmd(request, "RXTUNE", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                   log.debug("Recv RXTUNE cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  # TODO: check freq range</span><br><span style="color: hsl(0, 100%, 40%);">-                        self.rx_freq = int(request[1]) * 1000</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.burst_fwd.bb_freq = self.rx_freq</span><br><span style="color: hsl(0, 100%, 40%);">-                   return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                elif self.verify_cmd(request, "TXTUNE", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                   log.debug("Recv TXTUNE cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  # TODO: check freq range</span><br><span style="color: hsl(0, 100%, 40%);">-                        self.tx_freq = int(request[1]) * 1000</span><br><span style="color: hsl(0, 100%, 40%);">-                   return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Power measurement</span><br><span style="color: hsl(0, 100%, 40%);">-             elif self.verify_cmd(request, "MEASURE", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                  log.debug("Recv MEASURE cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 if self.pm is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                             return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # TODO: check freq range</span><br><span style="color: hsl(0, 100%, 40%);">-                        meas_freq = int(request[1]) * 1000</span><br><span style="color: hsl(0, 100%, 40%);">-                      meas_dbm = str(self.pm.measure(meas_freq))</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                      return (0, [meas_dbm])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          elif self.verify_cmd(request, "SETSLOT", 2):</span><br><span style="color: hsl(0, 100%, 40%);">-                  log.debug("Recv SETSLOT cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 if self.burst_fwd is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                              return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Obtain TS index</span><br><span style="color: hsl(0, 100%, 40%);">-                       ts = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                    if ts not in range(0, 8):</span><br><span style="color: hsl(0, 100%, 40%);">-                               log.error("TS index should be in range: 0..7")</span><br><span style="color: hsl(0, 100%, 40%);">-                                return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse TS type</span><br><span style="color: hsl(0, 100%, 40%);">-                 ts_type = int(request[2])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # TS activation / deactivation</span><br><span style="color: hsl(0, 100%, 40%);">-                  # We don't care about ts_type</span><br><span style="color: hsl(0, 100%, 40%);">-                       if ts_type == 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                                # Deactivate TS (remove from TS pass-filter list)</span><br><span style="color: hsl(0, 100%, 40%);">-                               if ts in self.burst_fwd.ts_pass_list:</span><br><span style="color: hsl(0, 100%, 40%);">-                                   self.burst_fwd.ts_pass_list.remove(ts)</span><br><span style="color: hsl(0, 100%, 40%);">-                          else:</span><br><span style="color: hsl(0, 100%, 40%);">-                                   log.warning("TS %u was not activated before" % ts)</span><br><span style="color: hsl(0, 100%, 40%);">-                                    # TODO: uncomment as soon as RESET is introduced</span><br><span style="color: hsl(0, 100%, 40%);">-                                        # return -1</span><br><span style="color: hsl(0, 100%, 40%);">-                     else:</span><br><span style="color: hsl(0, 100%, 40%);">-                           # Activate TS (add to TS pass-filter list)</span><br><span style="color: hsl(0, 100%, 40%);">-                              if ts not in self.burst_fwd.ts_pass_list:</span><br><span style="color: hsl(0, 100%, 40%);">-                                       self.burst_fwd.ts_pass_list.append(ts)</span><br><span style="color: hsl(0, 100%, 40%);">-                          else:</span><br><span style="color: hsl(0, 100%, 40%);">-                                   log.warning("TS %u was already activated before" % ts)</span><br><span style="color: hsl(0, 100%, 40%);">-                                        # TODO: uncomment as soon as RESET is introduced</span><br><span style="color: hsl(0, 100%, 40%);">-                                        # return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                     return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Timing Advance</span><br><span style="color: hsl(0, 100%, 40%);">-                elif self.verify_cmd(request, "SETTA", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                    log.debug("Recv SETTA cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   # Save to the BurstForwarder instance</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.burst_fwd.ta = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                     return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Timing of Arrival simulation for Uplink</span><br><span style="color: hsl(0, 100%, 40%);">-               # Absolute form: CMD FAKE_TOA <BASE> <THRESH></span><br><span style="color: hsl(0, 100%, 40%);">-               elif self.verify_cmd(request, "FAKE_TOA", 2):</span><br><span style="color: hsl(0, 100%, 40%);">-                 log.debug("Recv FAKE_TOA cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        # Parse and apply both base and threshold</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.toa256_ul_base = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.burst_fwd.toa256_ul_threshold = int(request[2])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                    return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Timing of Arrival simulation for Uplink</span><br><span style="color: hsl(0, 100%, 40%);">-               # Relative form: CMD FAKE_TOA <+-BASE_DELTA></span><br><span style="color: hsl(0, 100%, 40%);">-              elif self.verify_cmd(request, "FAKE_TOA", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                 log.debug("Recv FAKE_TOA cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        # Parse and apply delta</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.burst_fwd.toa256_ul_base += int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # RSSI simulation for Uplink</span><br><span style="color: hsl(0, 100%, 40%);">-            # Absolute form: CMD FAKE_RSSI <BASE> <THRESH></span><br><span style="color: hsl(0, 100%, 40%);">-              elif self.verify_cmd(request, "FAKE_RSSI", 2):</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.debug("Recv FAKE_RSSI cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse and apply both base and threshold</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.rssi_ul_base = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.burst_fwd.rssi_ul_threshold = int(request[2])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                      return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # RSSI simulation for Uplink</span><br><span style="color: hsl(0, 100%, 40%);">-            # Relative form: CMD FAKE_RSSI <+-BASE_DELTA></span><br><span style="color: hsl(0, 100%, 40%);">-             elif self.verify_cmd(request, "FAKE_RSSI", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.debug("Recv FAKE_RSSI cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse and apply delta</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.burst_fwd.rssi_ul_base += int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Path loss simulation for UL: burst dropping</span><br><span style="color: hsl(0, 100%, 40%);">-           # Syntax: CMD FAKE_DROP <AMOUNT></span><br><span style="color: hsl(0, 100%, 40%);">-          # Dropping pattern: fn % 1 == 0</span><br><span style="color: hsl(0, 100%, 40%);">-         elif self.verify_cmd(request, "FAKE_DROP", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.debug("Recv FAKE_DROP cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse / validate amount of bursts</span><br><span style="color: hsl(0, 100%, 40%);">-                     num = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                   if num < 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                          log.error("FAKE_DROP amount shall not be negative")</span><br><span style="color: hsl(0, 100%, 40%);">-                           return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.burst_ul_drop_amount = num</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.burst_ul_drop_period = 1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Path loss simulation for UL: burst dropping</span><br><span style="color: hsl(0, 100%, 40%);">-           # Syntax: CMD FAKE_DROP <AMOUNT> <FN_PERIOD></span><br><span style="color: hsl(0, 100%, 40%);">-                # Dropping pattern: fn % period == 0</span><br><span style="color: hsl(0, 100%, 40%);">-            elif self.verify_cmd(request, "FAKE_DROP", 2):</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.debug("Recv FAKE_DROP cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse / validate amount of bursts</span><br><span style="color: hsl(0, 100%, 40%);">-                     num = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                   if num < 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                          log.error("FAKE_DROP amount shall not be negative")</span><br><span style="color: hsl(0, 100%, 40%);">-                           return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse / validate period</span><br><span style="color: hsl(0, 100%, 40%);">-                       period = int(request[2])</span><br><span style="color: hsl(0, 100%, 40%);">-                        if period <= 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                              log.error("FAKE_DROP period shall be greater than zero")</span><br><span style="color: hsl(0, 100%, 40%);">-                              return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.burst_ul_drop_amount = num</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.burst_ul_drop_period = period</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                    return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Wrong / unknown command</span><br><span style="color: hsl(0, 100%, 40%);">-               else:</span><br><span style="color: hsl(0, 100%, 40%);">-                   # We don't care about other commands,</span><br><span style="color: hsl(0, 100%, 40%);">-                       # so let's merely ignore them ;)</span><br><span style="color: hsl(0, 100%, 40%);">-                    log.debug("Ignore CMD %s" % request[0])</span><br><span style="color: hsl(0, 100%, 40%);">-                       return 0</span><br><span>diff --git a/src/target/trx_toolkit/ctrl_if_bts.py b/src/target/trx_toolkit/ctrl_if_bts.py</span><br><span>deleted file mode 100644</span><br><span>index cb38b67..0000000</span><br><span>--- a/src/target/trx_toolkit/ctrl_if_bts.py</span><br><span>+++ /dev/null</span><br><span>@@ -1,189 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-#!/usr/bin/env python2</span><br><span style="color: hsl(0, 100%, 40%);">-# -*- coding: utf-8 -*-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-# TRX Toolkit</span><br><span style="color: hsl(0, 100%, 40%);">-# CTRL interface implementation (OsmoBTS specific)</span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# (C) 2016-2017 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# All Rights Reserved</span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(0, 100%, 40%);">-# it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(0, 100%, 40%);">-# the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(0, 100%, 40%);">-# (at your option) any later version.</span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(0, 100%, 40%);">-# but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(0, 100%, 40%);">-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(0, 100%, 40%);">-# GNU General Public License for more details.</span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(0, 100%, 40%);">-# You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(0, 100%, 40%);">-# with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(0, 100%, 40%);">-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-import logging as log</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-from ctrl_if import CTRLInterface</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-class CTRLInterfaceBTS(CTRLInterface):</span><br><span style="color: hsl(0, 100%, 40%);">-   # Internal state variables</span><br><span style="color: hsl(0, 100%, 40%);">-      trx_started = False</span><br><span style="color: hsl(0, 100%, 40%);">-     burst_fwd = None</span><br><span style="color: hsl(0, 100%, 40%);">-        clck_gen = None</span><br><span style="color: hsl(0, 100%, 40%);">- rx_freq = None</span><br><span style="color: hsl(0, 100%, 40%);">-  tx_freq = None</span><br><span style="color: hsl(0, 100%, 40%);">-  pm = None</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       def __init__(self, *udp_link_args):</span><br><span style="color: hsl(0, 100%, 40%);">-             CTRLInterface.__init__(self, *udp_link_args)</span><br><span style="color: hsl(0, 100%, 40%);">-            log.info("Init CTRL interface for BTS (%s)" % self.desc_link())</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       def parse_cmd(self, request):</span><br><span style="color: hsl(0, 100%, 40%);">-           # Power control</span><br><span style="color: hsl(0, 100%, 40%);">-         if self.verify_cmd(request, "POWERON", 0):</span><br><span style="color: hsl(0, 100%, 40%);">-                    log.debug("Recv POWERON CMD")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 # Ensure transceiver isn't working</span><br><span style="color: hsl(0, 100%, 40%);">-                  if self.trx_started:</span><br><span style="color: hsl(0, 100%, 40%);">-                            log.error("Transceiver already started")</span><br><span style="color: hsl(0, 100%, 40%);">-                              return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Ensure RX / TX freq. are set</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (self.rx_freq is None) or (self.tx_freq is None):</span><br><span style="color: hsl(0, 100%, 40%);">-                            log.error("RX / TX freq. are not set")</span><br><span style="color: hsl(0, 100%, 40%);">-                                return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       log.info("Starting transceiver...")</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.trx_started = True</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 # Power emulation</span><br><span style="color: hsl(0, 100%, 40%);">-                       if self.pm is not None:</span><br><span style="color: hsl(0, 100%, 40%);">-                         self.pm.add_bts_list([self.tx_freq])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                    # Start clock indications</span><br><span style="color: hsl(0, 100%, 40%);">-                       if self.clck_gen is not None:</span><br><span style="color: hsl(0, 100%, 40%);">-                           self.clck_gen.start()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                elif self.verify_cmd(request, "POWEROFF", 0):</span><br><span style="color: hsl(0, 100%, 40%);">-                 log.debug("Recv POWEROFF cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.info("Stopping transceiver...")</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.trx_started = False</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        # Power emulation</span><br><span style="color: hsl(0, 100%, 40%);">-                       if self.pm is not None:</span><br><span style="color: hsl(0, 100%, 40%);">-                         self.pm.del_bts_list([self.tx_freq])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                    # Stop clock indications</span><br><span style="color: hsl(0, 100%, 40%);">-                        if self.clck_gen is not None:</span><br><span style="color: hsl(0, 100%, 40%);">-                           self.clck_gen.stop()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                    return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Tuning Control</span><br><span style="color: hsl(0, 100%, 40%);">-                elif self.verify_cmd(request, "RXTUNE", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                   log.debug("Recv RXTUNE cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  # TODO: check freq range</span><br><span style="color: hsl(0, 100%, 40%);">-                        self.rx_freq = int(request[1]) * 1000</span><br><span style="color: hsl(0, 100%, 40%);">-                   return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                elif self.verify_cmd(request, "TXTUNE", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                   log.debug("Recv TXTUNE cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  # TODO: check freq range</span><br><span style="color: hsl(0, 100%, 40%);">-                        self.tx_freq = int(request[1]) * 1000</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.burst_fwd.bts_freq = self.tx_freq</span><br><span style="color: hsl(0, 100%, 40%);">-                  return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Timing of Arrival simulation for Downlink</span><br><span style="color: hsl(0, 100%, 40%);">-             # Absolute form: CMD FAKE_TOA <BASE> <THRESH></span><br><span style="color: hsl(0, 100%, 40%);">-               elif self.verify_cmd(request, "FAKE_TOA", 2):</span><br><span style="color: hsl(0, 100%, 40%);">-                 log.debug("Recv FAKE_TOA cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        # Parse and apply both base and threshold</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.toa256_dl_base = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.burst_fwd.toa256_dl_threshold = int(request[2])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                    return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Timing of Arrival simulation for Downlink</span><br><span style="color: hsl(0, 100%, 40%);">-             # Relative form: CMD FAKE_TOA <+-BASE_DELTA></span><br><span style="color: hsl(0, 100%, 40%);">-              elif self.verify_cmd(request, "FAKE_TOA", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                 log.debug("Recv FAKE_TOA cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        # Parse and apply delta</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.burst_fwd.toa256_dl_base += int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                        return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # RSSI simulation for Downlink</span><br><span style="color: hsl(0, 100%, 40%);">-          # Absolute form: CMD FAKE_RSSI <BASE> <THRESH></span><br><span style="color: hsl(0, 100%, 40%);">-              elif self.verify_cmd(request, "FAKE_RSSI", 2):</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.debug("Recv FAKE_RSSI cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse and apply both base and threshold</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.rssi_dl_base = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.burst_fwd.rssi_dl_threshold = int(request[2])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                      return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # RSSI simulation for Downlink</span><br><span style="color: hsl(0, 100%, 40%);">-          # Relative form: CMD FAKE_RSSI <+-BASE_DELTA></span><br><span style="color: hsl(0, 100%, 40%);">-             elif self.verify_cmd(request, "FAKE_RSSI", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.debug("Recv FAKE_RSSI cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse and apply delta</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.burst_fwd.rssi_dl_base += int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Path loss simulation for DL: burst dropping</span><br><span style="color: hsl(0, 100%, 40%);">-           # Syntax: CMD FAKE_DROP <AMOUNT></span><br><span style="color: hsl(0, 100%, 40%);">-          # Dropping pattern: fn % 1 == 0</span><br><span style="color: hsl(0, 100%, 40%);">-         elif self.verify_cmd(request, "FAKE_DROP", 1):</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.debug("Recv FAKE_DROP cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse / validate amount of bursts</span><br><span style="color: hsl(0, 100%, 40%);">-                     num = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                   if num < 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                          log.error("FAKE_DROP amount shall not be negative")</span><br><span style="color: hsl(0, 100%, 40%);">-                           return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.burst_dl_drop_amount = num</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.burst_dl_drop_period = 1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Path loss simulation for DL: burst dropping</span><br><span style="color: hsl(0, 100%, 40%);">-           # Syntax: CMD FAKE_DROP <AMOUNT> <FN_PERIOD></span><br><span style="color: hsl(0, 100%, 40%);">-                # Dropping pattern: fn % period == 0</span><br><span style="color: hsl(0, 100%, 40%);">-            elif self.verify_cmd(request, "FAKE_DROP", 2):</span><br><span style="color: hsl(0, 100%, 40%);">-                        log.debug("Recv FAKE_DROP cmd")</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse / validate amount of bursts</span><br><span style="color: hsl(0, 100%, 40%);">-                     num = int(request[1])</span><br><span style="color: hsl(0, 100%, 40%);">-                   if num < 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                          log.error("FAKE_DROP amount shall not be negative")</span><br><span style="color: hsl(0, 100%, 40%);">-                           return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       # Parse / validate period</span><br><span style="color: hsl(0, 100%, 40%);">-                       period = int(request[2])</span><br><span style="color: hsl(0, 100%, 40%);">-                        if period <= 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                              log.error("FAKE_DROP period shall be greater than zero")</span><br><span style="color: hsl(0, 100%, 40%);">-                              return -1</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.burst_dl_drop_amount = num</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.burst_fwd.burst_dl_drop_period = period</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                    return 0</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                # Wrong / unknown command</span><br><span style="color: hsl(0, 100%, 40%);">-               else:</span><br><span style="color: hsl(0, 100%, 40%);">-                   # We don't care about other commands,</span><br><span style="color: hsl(0, 100%, 40%);">-                       # so let's merely ignore them ;)</span><br><span style="color: hsl(0, 100%, 40%);">-                    log.debug("Ignore CMD %s" % request[0])</span><br><span style="color: hsl(0, 100%, 40%);">-                       return 0</span><br><span>diff --git a/src/target/trx_toolkit/ctrl_if_trx.py b/src/target/trx_toolkit/ctrl_if_trx.py</span><br><span>new file mode 100644</span><br><span>index 0000000..1ab1990</span><br><span>--- /dev/null</span><br><span>+++ b/src/target/trx_toolkit/ctrl_if_trx.py</span><br><span>@@ -0,0 +1,133 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python2</span><br><span style="color: hsl(120, 100%, 40%);">+# -*- coding: utf-8 -*-</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# TRX Toolkit</span><br><span style="color: hsl(120, 100%, 40%);">+# CTRL interface implementation (common commands)</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2016-2018 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# All Rights Reserved</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 published by</span><br><span style="color: hsl(120, 100%, 40%);">+# the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+# (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 along</span><br><span style="color: hsl(120, 100%, 40%);">+# with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import logging as log</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from ctrl_if import CTRLInterface</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class CTRLInterfaceTRX(CTRLInterface):</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 style="color: hsl(120, 100%, 40%);">+  def __init__(self, trx, *udp_link_args):</span><br><span style="color: hsl(120, 100%, 40%);">+              CTRLInterface.__init__(self, *udp_link_args)</span><br><span style="color: hsl(120, 100%, 40%);">+          log.info("Init CTRL interface (%s)" % self.desc_link())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           # Link with Transceiver instance we belong to</span><br><span style="color: hsl(120, 100%, 40%);">+         self.trx = trx</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      def parse_cmd(self, request):</span><br><span style="color: hsl(120, 100%, 40%);">+         # Custom command handlers (prioritized)</span><br><span style="color: hsl(120, 100%, 40%);">+               res = self.trx.ctrl_cmd_handler(request)</span><br><span style="color: hsl(120, 100%, 40%);">+              if res is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return res</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          # Power control</span><br><span style="color: hsl(120, 100%, 40%);">+               if self.verify_cmd(request, "POWERON", 0):</span><br><span style="color: hsl(120, 100%, 40%);">+                  log.debug("Recv POWERON CMD")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     # Ensure transceiver isn't working</span><br><span style="color: hsl(120, 100%, 40%);">+                        if self.trx.running:</span><br><span style="color: hsl(120, 100%, 40%);">+                          log.error("Transceiver already started")</span><br><span style="color: hsl(120, 100%, 40%);">+                            return -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   # Ensure RX / TX freq. are set</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (self.trx.rx_freq is None) or (self.trx.tx_freq is None):</span><br><span style="color: hsl(120, 100%, 40%);">+                          log.error("RX / TX freq. are not set")</span><br><span style="color: hsl(120, 100%, 40%);">+                              return -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   log.info("Starting transceiver...")</span><br><span style="color: hsl(120, 100%, 40%);">+                 self.trx.running = True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     # Notify transceiver about that</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.trx.poweron_event_handler()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            elif self.verify_cmd(request, "POWEROFF", 0):</span><br><span style="color: hsl(120, 100%, 40%);">+                       log.debug("Recv POWEROFF cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    log.info("Stopping transceiver...")</span><br><span style="color: hsl(120, 100%, 40%);">+                 self.trx.running = False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    # Notify transceiver about that</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.trx.poweroff_event_handler()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Tuning Control</span><br><span style="color: hsl(120, 100%, 40%);">+              elif self.verify_cmd(request, "RXTUNE", 1):</span><br><span style="color: hsl(120, 100%, 40%);">+                 log.debug("Recv RXTUNE cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      # TODO: check freq range</span><br><span style="color: hsl(120, 100%, 40%);">+                      self.trx.rx_freq = int(request[1]) * 1000</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            elif self.verify_cmd(request, "TXTUNE", 1):</span><br><span style="color: hsl(120, 100%, 40%);">+                 log.debug("Recv TXTUNE cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      # TODO: check freq range</span><br><span style="color: hsl(120, 100%, 40%);">+                      self.trx.tx_freq = int(request[1]) * 1000</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            elif self.verify_cmd(request, "SETSLOT", 2):</span><br><span style="color: hsl(120, 100%, 40%);">+                        log.debug("Recv SETSLOT cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     # Obtain TS index</span><br><span style="color: hsl(120, 100%, 40%);">+                     ts = int(request[1])</span><br><span style="color: hsl(120, 100%, 40%);">+                  if ts not in range(0, 8):</span><br><span style="color: hsl(120, 100%, 40%);">+                             log.error("TS index should be in range: 0..7")</span><br><span style="color: hsl(120, 100%, 40%);">+                              return -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   # Parse TS type</span><br><span style="color: hsl(120, 100%, 40%);">+                       ts_type = int(request[2])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   # TS activation / deactivation</span><br><span style="color: hsl(120, 100%, 40%);">+                        # We don't care about ts_type</span><br><span style="color: hsl(120, 100%, 40%);">+                     if ts_type == 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                              # Deactivate TS (remove from the list of active timeslots)</span><br><span style="color: hsl(120, 100%, 40%);">+                            if ts in self.trx.ts_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                                    self.trx.ts_list.remove(ts)</span><br><span style="color: hsl(120, 100%, 40%);">+                           else:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 log.warning("TS %u was not activated before" % ts)</span><br><span style="color: hsl(120, 100%, 40%);">+                                  # TODO: uncomment as soon as RESET is introduced</span><br><span style="color: hsl(120, 100%, 40%);">+                                      # return -1</span><br><span style="color: hsl(120, 100%, 40%);">+                   else:</span><br><span style="color: hsl(120, 100%, 40%);">+                         # Activate TS (add to the list of active timeslots)</span><br><span style="color: hsl(120, 100%, 40%);">+                           if ts not in self.trx.ts_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                                        self.trx.ts_list.append(ts)</span><br><span style="color: hsl(120, 100%, 40%);">+                           else:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 log.warning("TS %u was already activated before" % ts)</span><br><span style="color: hsl(120, 100%, 40%);">+                                      # TODO: uncomment as soon as RESET is introduced</span><br><span style="color: hsl(120, 100%, 40%);">+                                      # return -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Wrong / unknown command</span><br><span style="color: hsl(120, 100%, 40%);">+             else:</span><br><span style="color: hsl(120, 100%, 40%);">+                 # We don't care about other commands,</span><br><span style="color: hsl(120, 100%, 40%);">+                     # so let's merely ignore them ;)</span><br><span style="color: hsl(120, 100%, 40%);">+                  log.debug("Ignore CMD %s" % request[0])</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0</span><br><span>diff --git a/src/target/trx_toolkit/fake_pm.py b/src/target/trx_toolkit/fake_pm.py</span><br><span>index 840b4e4..b2b176f 100644</span><br><span>--- a/src/target/trx_toolkit/fake_pm.py</span><br><span>+++ b/src/target/trx_toolkit/fake_pm.py</span><br><span>@@ -2,9 +2,9 @@</span><br><span> # -*- coding: utf-8 -*-</span><br><span> </span><br><span> # TRX Toolkit</span><br><span style="color: hsl(0, 100%, 40%);">-# Power measurement emulation for BB</span><br><span style="color: hsl(120, 100%, 40%);">+# Power measurement emulation</span><br><span> #</span><br><span style="color: hsl(0, 100%, 40%);">-# (C) 2017 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2017-2018 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span> #</span><br><span> # All Rights Reserved</span><br><span> #</span><br><span>@@ -25,29 +25,36 @@</span><br><span> from random import randint</span><br><span> </span><br><span> class FakePM:</span><br><span style="color: hsl(0, 100%, 40%);">-      # Freq. list for good power level</span><br><span style="color: hsl(0, 100%, 40%);">-       bts_list = []</span><br><span style="color: hsl(120, 100%, 40%);">+ def __init__(self, trx_list, noise_min, noise_max, trx_min, trx_max):</span><br><span style="color: hsl(120, 100%, 40%);">+         # List of Transceiver instances</span><br><span style="color: hsl(120, 100%, 40%);">+               self.trx_list = trx_list</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def __init__(self, noise_min, noise_max, bts_min, bts_max):</span><br><span>          # Save power level ranges</span><br><span>            self.noise_min = noise_min</span><br><span>           self.noise_max = noise_max</span><br><span style="color: hsl(0, 100%, 40%);">-              self.bts_min = bts_min</span><br><span style="color: hsl(0, 100%, 40%);">-          self.bts_max = bts_max</span><br><span style="color: hsl(120, 100%, 40%);">+                self.trx_min = trx_min</span><br><span style="color: hsl(120, 100%, 40%);">+                self.trx_max = trx_max</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      def measure(self, bts):</span><br><span style="color: hsl(0, 100%, 40%);">-         if bts in self.bts_list:</span><br><span style="color: hsl(0, 100%, 40%);">-                        return randint(self.bts_min, self.bts_max)</span><br><span style="color: hsl(0, 100%, 40%);">-              else:</span><br><span style="color: hsl(0, 100%, 40%);">-                   return randint(self.noise_min, self.noise_max)</span><br><span style="color: hsl(120, 100%, 40%);">+        @property</span><br><span style="color: hsl(120, 100%, 40%);">+     def rssi_noise(self):</span><br><span style="color: hsl(120, 100%, 40%);">+         return randint(self.noise_min, self.noise_max)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      def update_bts_list(self, new_list):</span><br><span style="color: hsl(0, 100%, 40%);">-            self.bts_list = new_list</span><br><span style="color: hsl(120, 100%, 40%);">+      @property</span><br><span style="color: hsl(120, 100%, 40%);">+     def rssi_trx(self):</span><br><span style="color: hsl(120, 100%, 40%);">+           return randint(self.trx_min, self.trx_max)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  def add_bts_list(self, add_list):</span><br><span style="color: hsl(0, 100%, 40%);">-               self.bts_list += add_list</span><br><span style="color: hsl(120, 100%, 40%);">+     def measure(self, freq):</span><br><span style="color: hsl(120, 100%, 40%);">+              # Iterate over all known transceivers</span><br><span style="color: hsl(120, 100%, 40%);">+         for trx in self.trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                     if not trx.running:</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def del_bts_list(self, del_list):</span><br><span style="color: hsl(0, 100%, 40%);">-               for item in del_list:</span><br><span style="color: hsl(0, 100%, 40%);">-                   if item in self.bts_list:</span><br><span style="color: hsl(0, 100%, 40%);">-                               self.bts_list.remove(item)</span><br><span style="color: hsl(120, 100%, 40%);">+                    # FIXME: we should average the rate of bursts</span><br><span style="color: hsl(120, 100%, 40%);">+                 # and indicated power / attenuation values for</span><br><span style="color: hsl(120, 100%, 40%);">+                        # all known transceivers</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    # Match given frequency</span><br><span style="color: hsl(120, 100%, 40%);">+                       if trx.tx_freq == freq:</span><br><span style="color: hsl(120, 100%, 40%);">+                               return self.rssi_trx</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                return self.rssi_noise</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 95261df..3068f83 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>@@ -31,13 +31,250 @@</span><br><span> import sys</span><br><span> </span><br><span> from app_common import ApplicationBase</span><br><span style="color: hsl(0, 100%, 40%);">-from ctrl_if_bts import CTRLInterfaceBTS</span><br><span style="color: hsl(0, 100%, 40%);">-from ctrl_if_bb import CTRLInterfaceBB</span><br><span> from burst_fwd import BurstForwarder</span><br><span style="color: hsl(120, 100%, 40%);">+from transceiver import Transceiver</span><br><span> from fake_pm import FakePM</span><br><span> </span><br><span> from udp_link import UDPLink</span><br><span style="color: hsl(0, 100%, 40%);">-from clck_gen import CLCKGen</span><br><span style="color: hsl(120, 100%, 40%);">+from clck_router_trx import CLCKRouterTRX</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class FakeTRX(Transceiver):</span><br><span style="color: hsl(120, 100%, 40%);">+     """ Fake transceiver with RF path (burst loss, RSSI, TA, ToA) simulation.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    == ToA / RSSI measurement simulation</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        Since this is a virtual environment, we can simulate different</span><br><span style="color: hsl(120, 100%, 40%);">+        parameters of the virtual RF interface:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       - ToA (Timing of Arrival) - measured difference between expected</span><br><span style="color: hsl(120, 100%, 40%);">+        and actual time of burst arrival in units of 1/256 of GSM symbol</span><br><span style="color: hsl(120, 100%, 40%);">+      periods. A pair of both base and threshold values defines a range</span><br><span style="color: hsl(120, 100%, 40%);">+     of ToA value randomization:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           from (toa256_base - toa256_rand_threshold)</span><br><span style="color: hsl(120, 100%, 40%);">+              to (toa256_base + toa256_rand_threshold).</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     - RSSI (Received Signal Strength Indication) - measured "power" of</span><br><span style="color: hsl(120, 100%, 40%);">+            the signal (per burst) in dBm. A pair of both base and threshold</span><br><span style="color: hsl(120, 100%, 40%);">+      values defines a range of RSSI value randomization:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           from (rssi_base - rssi_rand_threshold)</span><br><span style="color: hsl(120, 100%, 40%);">+          to (rssi_base + rssi_rand_threshold).</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       Please note that the randomization of both RSSI and ToA</span><br><span style="color: hsl(120, 100%, 40%);">+       is optional, and can be enabled from the control interface.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ === Timing Advance handling</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ The BTS is using ToA measurements for UL bursts in order to calculate</span><br><span style="color: hsl(120, 100%, 40%);">+ Timing Advance value, that is then indicated to a MS, which in its turn</span><br><span style="color: hsl(120, 100%, 40%);">+       shall apply this value to the transmitted signal in order to compensate</span><br><span style="color: hsl(120, 100%, 40%);">+       the delay. Basically, every burst is transmitted in advance defined by</span><br><span style="color: hsl(120, 100%, 40%);">+        the indicated Timing Advance value. The valid range is 0..63, where</span><br><span style="color: hsl(120, 100%, 40%);">+   each unit means one GSM symbol advance. The actual Timing Advance value</span><br><span style="color: hsl(120, 100%, 40%);">+       is set using SETTA control command from MS. By default, it's set to 0.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  === Path loss simulation - burst dropping</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   In some cases, e.g. due to a weak signal or high interference, a burst</span><br><span style="color: hsl(120, 100%, 40%);">+        can be lost, i.e. not detected by the receiver. This can also be</span><br><span style="color: hsl(120, 100%, 40%);">+      simulated using FAKE_DROP command on the control interface:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   - burst_drop_amount - the amount of DL/UL bursts</span><br><span style="color: hsl(120, 100%, 40%);">+        to be dropped (i.e. not forwarded towards the MS/BTS),</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    - burst_drop_period - drop a DL/UL burst if its (fn % period) == 0.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       TODO: add some notes about custom CTRL command handler</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%);">+  def __init__(self, *transceiver_args):</span><br><span style="color: hsl(120, 100%, 40%);">+                Transceiver.__init__(self, *transceiver_args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               # Actual ToA / RSSI / TA values</span><br><span style="color: hsl(120, 100%, 40%);">+               self.toa256_base = 0</span><br><span style="color: hsl(120, 100%, 40%);">+          self.rssi_base = -60</span><br><span style="color: hsl(120, 100%, 40%);">+          self.ta = 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # ToA / RSSI randomization threshold</span><br><span style="color: hsl(120, 100%, 40%);">+          self.toa256_rand_threshold = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                self.rssi_rand_threshold = 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                # Path loss simulation (burst dropping)</span><br><span style="color: hsl(120, 100%, 40%);">+               self.burst_drop_amount = 0</span><br><span style="color: hsl(120, 100%, 40%);">+            self.burst_drop_period = 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  @property</span><br><span style="color: hsl(120, 100%, 40%);">+     def toa256(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.toa256_rand_threshold is 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return self.toa256_base</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             # Generate a random ToA value in required range</span><br><span style="color: hsl(120, 100%, 40%);">+               toa256_min = self.toa256_base - self.toa256_rand_threshold</span><br><span style="color: hsl(120, 100%, 40%);">+            toa256_max = self.toa256_base + self.toa256_rand_threshold</span><br><span style="color: hsl(120, 100%, 40%);">+            return random.randint(toa256_min, toa256_max)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       @property</span><br><span style="color: hsl(120, 100%, 40%);">+     def rssi(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.rssi_rand_threshold is 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                     return self.rssi_base</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               # Generate a random RSSI value in required range</span><br><span style="color: hsl(120, 100%, 40%);">+              rssi_min = self.rssi_base - self.rssi_rand_threshold</span><br><span style="color: hsl(120, 100%, 40%);">+          rssi_max = self.rssi_base + self.rssi_rand_threshold</span><br><span style="color: hsl(120, 100%, 40%);">+          return random.randint(rssi_min, rssi_max)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   # Path loss simulation: burst dropping</span><br><span style="color: hsl(120, 100%, 40%);">+        # Returns: True - drop, False - keep</span><br><span style="color: hsl(120, 100%, 40%);">+  def sim_burst_drop(self, msg):</span><br><span style="color: hsl(120, 100%, 40%);">+                # Check if dropping is required</span><br><span style="color: hsl(120, 100%, 40%);">+               if self.burst_drop_amount is 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%);">+                if msg.fn % self.burst_drop_period == 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                      log.info("Simulation: dropping burst (fn=%u %% %u == 0)"</span><br><span style="color: hsl(120, 100%, 40%);">+                            % (msg.fn, self.burst_drop_period))</span><br><span style="color: hsl(120, 100%, 40%);">+                   self.burst_drop_amount -= 1</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%);">+         return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        def send_data_msg(self, msg):</span><br><span style="color: hsl(120, 100%, 40%);">+         # Complete message header</span><br><span style="color: hsl(120, 100%, 40%);">+             msg.toa256 = self.toa256</span><br><span style="color: hsl(120, 100%, 40%);">+              msg.rssi = self.rssi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                # Apply optional Timing Advance</span><br><span style="color: hsl(120, 100%, 40%);">+               if self.ta is not 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                  msg.toa256 -= self.ta * 256</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # TODO: make legacy mode configurable (via argv?)</span><br><span style="color: hsl(120, 100%, 40%);">+             self.data_if.send_msg(msg, legacy = True)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   # Triggered by POWERON command on CTRL</span><br><span style="color: hsl(120, 100%, 40%);">+        def poweron_event_handler(self):</span><br><span style="color: hsl(120, 100%, 40%);">+              log.debug("Recv POWERON event")</span><br><span style="color: hsl(120, 100%, 40%);">+             self.clck_router.poke(self)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # Triggered by POWEROFF command on CTRL</span><br><span style="color: hsl(120, 100%, 40%);">+       def poweroff_event_handler(self):</span><br><span style="color: hsl(120, 100%, 40%);">+             log.debug("Recv POWEROFF event")</span><br><span style="color: hsl(120, 100%, 40%);">+            self.clck_router.poke(self)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # FakeTRX specific CTRL command handler</span><br><span style="color: hsl(120, 100%, 40%);">+       def ctrl_cmd_handler(self, request):</span><br><span style="color: hsl(120, 100%, 40%);">+          # Timing of Arrival simulation</span><br><span style="color: hsl(120, 100%, 40%);">+                # Absolute form: CMD FAKE_TOA <BASE> <THRESH></span><br><span style="color: hsl(120, 100%, 40%);">+             if self.ctrl_if.verify_cmd(request, "FAKE_TOA", 2):</span><br><span style="color: hsl(120, 100%, 40%);">+                 log.debug("Recv FAKE_TOA cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    # Parse and apply both base and threshold</span><br><span style="color: hsl(120, 100%, 40%);">+                     self.toa256_base = int(request[1])</span><br><span style="color: hsl(120, 100%, 40%);">+                    self.toa256_rand_threshold = int(request[2])</span><br><span style="color: hsl(120, 100%, 40%);">+                  return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Timing of Arrival simulation</span><br><span style="color: hsl(120, 100%, 40%);">+                # Relative form: CMD FAKE_TOA <+-BASE_DELTA></span><br><span style="color: hsl(120, 100%, 40%);">+            elif self.ctrl_if.verify_cmd(request, "FAKE_TOA", 1):</span><br><span style="color: hsl(120, 100%, 40%);">+                       log.debug("Recv FAKE_TOA cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    # Parse and apply delta</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.toa256_base += int(request[1])</span><br><span style="color: hsl(120, 100%, 40%);">+                   return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # RSSI simulation</span><br><span style="color: hsl(120, 100%, 40%);">+             # Absolute form: CMD FAKE_RSSI <BASE> <THRESH></span><br><span style="color: hsl(120, 100%, 40%);">+            elif self.ctrl_if.verify_cmd(request, "FAKE_RSSI", 2):</span><br><span style="color: hsl(120, 100%, 40%);">+                      log.debug("Recv FAKE_RSSI cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   # Parse and apply both base and threshold</span><br><span style="color: hsl(120, 100%, 40%);">+                     self.rssi_base = int(request[1])</span><br><span style="color: hsl(120, 100%, 40%);">+                      self.rssi_rand_threshold = int(request[2])</span><br><span style="color: hsl(120, 100%, 40%);">+                    return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # RSSI simulation</span><br><span style="color: hsl(120, 100%, 40%);">+             # Relative form: CMD FAKE_RSSI <+-BASE_DELTA></span><br><span style="color: hsl(120, 100%, 40%);">+           elif self.ctrl_if.verify_cmd(request, "FAKE_RSSI", 1):</span><br><span style="color: hsl(120, 100%, 40%);">+                      log.debug("Recv FAKE_RSSI cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   # Parse and apply delta</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.rssi_base += int(request[1])</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Path loss simulation: burst dropping</span><br><span style="color: hsl(120, 100%, 40%);">+                # Syntax: CMD FAKE_DROP <AMOUNT></span><br><span style="color: hsl(120, 100%, 40%);">+                # Dropping pattern: fn % 1 == 0</span><br><span style="color: hsl(120, 100%, 40%);">+               elif self.ctrl_if.verify_cmd(request, "FAKE_DROP", 1):</span><br><span style="color: hsl(120, 100%, 40%);">+                      log.debug("Recv FAKE_DROP cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   # Parse / validate amount of bursts</span><br><span style="color: hsl(120, 100%, 40%);">+                   num = int(request[1])</span><br><span style="color: hsl(120, 100%, 40%);">+                 if num < 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                                log.error("FAKE_DROP amount shall not be negative")</span><br><span style="color: hsl(120, 100%, 40%);">+                         return -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   self.burst_drop_amount = num</span><br><span style="color: hsl(120, 100%, 40%);">+                  self.burst_drop_period = 1</span><br><span style="color: hsl(120, 100%, 40%);">+                    return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Path loss simulation: burst dropping</span><br><span style="color: hsl(120, 100%, 40%);">+                # Syntax: CMD FAKE_DROP <AMOUNT> <FN_PERIOD></span><br><span style="color: hsl(120, 100%, 40%);">+              # Dropping pattern: fn % period == 0</span><br><span style="color: hsl(120, 100%, 40%);">+          elif self.ctrl_if.verify_cmd(request, "FAKE_DROP", 2):</span><br><span style="color: hsl(120, 100%, 40%);">+                      log.debug("Recv FAKE_DROP cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   # Parse / validate amount of bursts</span><br><span style="color: hsl(120, 100%, 40%);">+                   num = int(request[1])</span><br><span style="color: hsl(120, 100%, 40%);">+                 if num < 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                                log.error("FAKE_DROP amount shall not be negative")</span><br><span style="color: hsl(120, 100%, 40%);">+                         return -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   # Parse / validate period</span><br><span style="color: hsl(120, 100%, 40%);">+                     period = int(request[2])</span><br><span style="color: hsl(120, 100%, 40%);">+                      if period <= 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                            log.error("FAKE_DROP period shall be greater than zero")</span><br><span style="color: hsl(120, 100%, 40%);">+                            return -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   self.burst_drop_amount = num</span><br><span style="color: hsl(120, 100%, 40%);">+                  self.burst_drop_period = period</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Unhandled command</span><br><span style="color: hsl(120, 100%, 40%);">+           return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class FakeTRX_BTS(FakeTRX):</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%);">+class FakeTRX_BB(FakeTRX):</span><br><span style="color: hsl(120, 100%, 40%);">+    # BB specific CTRL command handler</span><br><span style="color: hsl(120, 100%, 40%);">+    def ctrl_cmd_handler(self, request):</span><br><span style="color: hsl(120, 100%, 40%);">+          res = FakeTRX.ctrl_cmd_handler(self, request)</span><br><span style="color: hsl(120, 100%, 40%);">+         if res is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return res</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          # Power measurement</span><br><span style="color: hsl(120, 100%, 40%);">+           if self.ctrl_if.verify_cmd(request, "MEASURE", 1):</span><br><span style="color: hsl(120, 100%, 40%);">+                  log.debug("Recv MEASURE cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     # TODO: check freq range</span><br><span style="color: hsl(120, 100%, 40%);">+                      meas_freq = int(request[1]) * 1000</span><br><span style="color: hsl(120, 100%, 40%);">+                    meas_dbm = self.pm.measure(meas_freq)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       return (0, [str(meas_dbm)])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # Timing Advance</span><br><span style="color: hsl(120, 100%, 40%);">+              elif self.ctrl_if.verify_cmd(request, "SETTA", 1):</span><br><span style="color: hsl(120, 100%, 40%);">+                  log.debug("Recv SETTA cmd")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       # Store indicated value</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.trx.ta = int(request[1])</span><br><span style="color: hsl(120, 100%, 40%);">+                 return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Unhandled command</span><br><span style="color: hsl(120, 100%, 40%);">+           return None</span><br><span> </span><br><span> class Application(ApplicationBase):</span><br><span>       def __init__(self):</span><br><span>@@ -51,78 +288,65 @@</span><br><span>           self.app_init_logging(self.argv)</span><br><span> </span><br><span>         def run(self):</span><br><span style="color: hsl(0, 100%, 40%);">-          # Init TRX CTRL interface for BTS</span><br><span style="color: hsl(0, 100%, 40%);">-               self.bts_ctrl = CTRLInterfaceBTS(</span><br><span style="color: hsl(0, 100%, 40%);">-                       self.argv.bts_addr, self.argv.bts_base_port + 101,</span><br><span style="color: hsl(0, 100%, 40%);">-                      self.argv.trx_bind_addr, self.argv.bts_base_port + 1)</span><br><span style="color: hsl(120, 100%, 40%);">+         # Init TRX instance for BTS</span><br><span style="color: hsl(120, 100%, 40%);">+           self.bts_trx = FakeTRX_BTS(self.argv.trx_bind_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                   self.argv.bts_addr, self.argv.bts_base_port)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                # Init TRX CTRL interface for BB</span><br><span style="color: hsl(0, 100%, 40%);">-                self.bb_ctrl = CTRLInterfaceBB(</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.argv.bb_addr, self.argv.bb_base_port + 101,</span><br><span style="color: hsl(0, 100%, 40%);">-                        self.argv.trx_bind_addr, self.argv.bb_base_port + 1)</span><br><span style="color: hsl(120, 100%, 40%);">+          # Init TRX instance for BB</span><br><span style="color: hsl(120, 100%, 40%);">+            self.bb_trx = FakeTRX_BB(self.argv.trx_bind_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                     self.argv.bb_addr, self.argv.bb_base_port)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          # Burst forwarding between transceivers</span><br><span style="color: hsl(120, 100%, 40%);">+               self.burst_fwd = BurstForwarder()</span><br><span style="color: hsl(120, 100%, 40%);">+             self.burst_fwd.add_trx(self.bts_trx)</span><br><span style="color: hsl(120, 100%, 40%);">+          self.burst_fwd.add_trx(self.bb_trx)</span><br><span> </span><br><span>              # Power measurement emulation</span><br><span>                # Noise: -120 .. -105</span><br><span>                # BTS: -75 .. -50</span><br><span style="color: hsl(0, 100%, 40%);">-               self.pm = FakePM(-120, -105, -75, -50)</span><br><span style="color: hsl(120, 100%, 40%);">+                self.pm = FakePM(self.burst_fwd.trx_list, -120, -105, -75, -50)</span><br><span style="color: hsl(120, 100%, 40%);">+               self.bb_trx.pm = self.pm</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            # Share a FakePM instance between both BTS and BB</span><br><span style="color: hsl(0, 100%, 40%);">-               self.bts_ctrl.pm = self.pm</span><br><span style="color: hsl(0, 100%, 40%);">-              self.bb_ctrl.pm = self.pm</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               # Init DATA links</span><br><span style="color: hsl(0, 100%, 40%);">-               self.bts_data = UDPLink(</span><br><span style="color: hsl(0, 100%, 40%);">-                        self.argv.bts_addr, self.argv.bts_base_port + 102,</span><br><span style="color: hsl(0, 100%, 40%);">-                      self.argv.trx_bind_addr, self.argv.bts_base_port + 2)</span><br><span style="color: hsl(0, 100%, 40%);">-           self.bb_data = UDPLink(</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.argv.bb_addr, self.argv.bb_base_port + 102,</span><br><span style="color: hsl(0, 100%, 40%);">-                        self.argv.trx_bind_addr, self.argv.bb_base_port + 2)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            # BTS <-> BB burst forwarding</span><br><span style="color: hsl(0, 100%, 40%);">-             self.burst_fwd = BurstForwarder(self.bts_data, self.bb_data)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            # Share a BurstForwarder instance between BTS and BB</span><br><span style="color: hsl(0, 100%, 40%);">-            self.bts_ctrl.burst_fwd = self.burst_fwd</span><br><span style="color: hsl(0, 100%, 40%);">-                self.bb_ctrl.burst_fwd = self.burst_fwd</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         # Provide clock to BTS</span><br><span style="color: hsl(0, 100%, 40%);">-          self.bts_clck = UDPLink(</span><br><span style="color: hsl(0, 100%, 40%);">-                        self.argv.bts_addr, self.argv.bts_base_port + 100,</span><br><span style="color: hsl(0, 100%, 40%);">-                      self.argv.trx_bind_addr, self.argv.bts_base_port)</span><br><span style="color: hsl(0, 100%, 40%);">-               self.clck_gen = CLCKGen([self.bts_clck])</span><br><span style="color: hsl(0, 100%, 40%);">-                self.bts_ctrl.clck_gen = self.clck_gen</span><br><span style="color: hsl(120, 100%, 40%);">+                # Init clock router</span><br><span style="color: hsl(120, 100%, 40%);">+           self.clck_router = CLCKRouterTRX(self.burst_fwd.trx_list)</span><br><span style="color: hsl(120, 100%, 40%);">+             self.bts_trx.clck_router = self.clck_router</span><br><span style="color: hsl(120, 100%, 40%);">+           self.bb_trx.clck_router = self.clck_router</span><br><span> </span><br><span>               log.info("Init complete")</span><br><span> </span><br><span>              # Enter main loop</span><br><span>            while True:</span><br><span style="color: hsl(0, 100%, 40%);">-                     socks = [self.bts_ctrl.sock, self.bb_ctrl.sock,</span><br><span style="color: hsl(0, 100%, 40%);">-                         self.bts_data.sock, self.bb_data.sock]</span><br><span style="color: hsl(120, 100%, 40%);">+                        socks = [self.bts_trx.ctrl_if.sock, self.bb_trx.ctrl_if.sock,</span><br><span style="color: hsl(120, 100%, 40%);">+                         self.bts_trx.data_if.sock, self.bb_trx.data_if.sock]</span><br><span> </span><br><span>                     # Wait until we get any data on any socket</span><br><span>                   r_event, w_event, x_event = select.select(socks, [], [])</span><br><span> </span><br><span>                         # Downlink: BTS -> BB</span><br><span style="color: hsl(0, 100%, 40%);">-                        if self.bts_data.sock in r_event:</span><br><span style="color: hsl(0, 100%, 40%);">-                               self.burst_fwd.bts2bb()</span><br><span style="color: hsl(120, 100%, 40%);">+                       if self.bts_trx.data_if.sock in r_event:</span><br><span style="color: hsl(120, 100%, 40%);">+                              msg = self.bts_trx.recv_data_msg()</span><br><span style="color: hsl(120, 100%, 40%);">+                            if msg is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                   self.burst_fwd.forward_msg(self.bts_trx, msg)</span><br><span> </span><br><span>                    # Uplink: BB -> BTS</span><br><span style="color: hsl(0, 100%, 40%);">-                  if self.bb_data.sock in r_event:</span><br><span style="color: hsl(0, 100%, 40%);">-                                self.burst_fwd.bb2bts()</span><br><span style="color: hsl(120, 100%, 40%);">+                       if self.bb_trx.data_if.sock in r_event:</span><br><span style="color: hsl(120, 100%, 40%);">+                               msg = self.bb_trx.recv_data_msg()</span><br><span style="color: hsl(120, 100%, 40%);">+                             if msg is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                   self.burst_fwd.forward_msg(self.bb_trx, msg)</span><br><span> </span><br><span>                     # CTRL commands from BTS</span><br><span style="color: hsl(0, 100%, 40%);">-                        if self.bts_ctrl.sock in r_event:</span><br><span style="color: hsl(0, 100%, 40%);">-                               self.bts_ctrl.handle_rx()</span><br><span style="color: hsl(120, 100%, 40%);">+                     if self.bts_trx.ctrl_if.sock in r_event:</span><br><span style="color: hsl(120, 100%, 40%);">+                              self.bts_trx.ctrl_if.handle_rx()</span><br><span> </span><br><span>                         # CTRL commands from BB</span><br><span style="color: hsl(0, 100%, 40%);">-                 if self.bb_ctrl.sock in r_event:</span><br><span style="color: hsl(0, 100%, 40%);">-                                self.bb_ctrl.handle_rx()</span><br><span style="color: hsl(120, 100%, 40%);">+                      if self.bb_trx.ctrl_if.sock in r_event:</span><br><span style="color: hsl(120, 100%, 40%);">+                               self.bb_trx.ctrl_if.handle_rx()</span><br><span> </span><br><span>  def shutdown(self):</span><br><span>          log.info("Shutting down...")</span><br><span> </span><br><span>           # Stop clock generator</span><br><span style="color: hsl(0, 100%, 40%);">-          self.clck_gen.stop()</span><br><span style="color: hsl(120, 100%, 40%);">+          self.clck_router.stop()</span><br><span> </span><br><span>  def parse_argv(self):</span><br><span>                parser = argparse.ArgumentParser(prog = "fake_trx",</span><br><span>diff --git a/src/target/trx_toolkit/transceiver.py b/src/target/trx_toolkit/transceiver.py</span><br><span>new file mode 100644</span><br><span>index 0000000..f83d88c</span><br><span>--- /dev/null</span><br><span>+++ b/src/target/trx_toolkit/transceiver.py</span><br><span>@@ -0,0 +1,91 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python2</span><br><span style="color: hsl(120, 100%, 40%);">+# -*- coding: utf-8 -*-</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# TRX Toolkit</span><br><span style="color: hsl(120, 100%, 40%);">+# Transceiver implementation</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# All Rights Reserved</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 published by</span><br><span style="color: hsl(120, 100%, 40%);">+# the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+# (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 along</span><br><span style="color: hsl(120, 100%, 40%);">+# with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import logging as log</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from ctrl_if_trx import CTRLInterfaceTRX</span><br><span style="color: hsl(120, 100%, 40%);">+from data_if import DATAInterface</span><br><span style="color: hsl(120, 100%, 40%);">+from udp_link import UDPLink</span><br><span style="color: hsl(120, 100%, 40%);">+from data_msg import *</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class Transceiver:</span><br><span style="color: hsl(120, 100%, 40%);">+      """ Base transceiver class implementation.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   Represents a single transceiver, that can be used as for the BTS side,</span><br><span style="color: hsl(120, 100%, 40%);">+        as for the MS side. Usually, a single transceiver has DATA, CTRL and</span><br><span style="color: hsl(120, 100%, 40%);">+  CLCK interfaces, but since clock interface is not used by the MS side</span><br><span style="color: hsl(120, 100%, 40%);">+ at the moment, it is not being initialized.</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%);">+  def __init__(self, bind_addr, remote_addr, base_port):</span><br><span style="color: hsl(120, 100%, 40%);">+                # Init DATA interface</span><br><span style="color: hsl(120, 100%, 40%);">+         self.data_if = DATAInterface(</span><br><span style="color: hsl(120, 100%, 40%);">+                 remote_addr, base_port + 102,</span><br><span style="color: hsl(120, 100%, 40%);">+                 bind_addr, base_port + 2)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           # Init CTRL interface</span><br><span style="color: hsl(120, 100%, 40%);">+         self.ctrl_if = CTRLInterfaceTRX(self,</span><br><span style="color: hsl(120, 100%, 40%);">+                 remote_addr, base_port + 101,</span><br><span style="color: hsl(120, 100%, 40%);">+                 bind_addr, base_port + 1)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           # Init CLCK interface</span><br><span style="color: hsl(120, 100%, 40%);">+         self.clck_if = UDPLink(</span><br><span style="color: hsl(120, 100%, 40%);">+                       remote_addr, base_port + 100,</span><br><span style="color: hsl(120, 100%, 40%);">+                 bind_addr, base_port)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               # Connection info</span><br><span style="color: hsl(120, 100%, 40%);">+             self.remote_addr = remote_addr</span><br><span style="color: hsl(120, 100%, 40%);">+                self.bind_addr = bind_addr</span><br><span style="color: hsl(120, 100%, 40%);">+            self.base_port = base_port</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          # Internal state</span><br><span style="color: hsl(120, 100%, 40%);">+              self.running = False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                # Actual RX / TX frequencies</span><br><span style="color: hsl(120, 100%, 40%);">+          self.rx_freq = None</span><br><span style="color: hsl(120, 100%, 40%);">+           self.tx_freq = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # List of active (configured) timeslots</span><br><span style="color: hsl(120, 100%, 40%);">+               self.ts_list = []</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   def recv_data_msg(self):</span><br><span style="color: hsl(120, 100%, 40%);">+              # Read and parse data from socket</span><br><span style="color: hsl(120, 100%, 40%);">+             msg = self.data_if.recv_l12trx_msg()</span><br><span style="color: hsl(120, 100%, 40%);">+          if not msg:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # Make sure that transceiver is configured and running</span><br><span style="color: hsl(120, 100%, 40%);">+                if not self.running:</span><br><span style="color: hsl(120, 100%, 40%);">+                  log.warning("RX DATA message (%s), but transceiver "</span><br><span style="color: hsl(120, 100%, 40%);">+                                "is not running => dropping..." % msg.desc_hdr())</span><br><span style="color: hsl(120, 100%, 40%);">+                        return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # Make sure that indicated timeslot is configured</span><br><span style="color: hsl(120, 100%, 40%);">+             if msg.tn not in self.ts_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                        log.warning("RX DATA message (%s), but timeslot "</span><br><span style="color: hsl(120, 100%, 40%);">+                           "is not configured => dropping..." % msg.desc_hdr())</span><br><span style="color: hsl(120, 100%, 40%);">+                     return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         return msg</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/12264">change 12264</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/12264"/><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-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ice44e2b22566b3652ef6d43896055963b13ab185 </div>
<div style="display:none"> Gerrit-Change-Number: 12264 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Vadim Yanitskiy <axilirator@gmail.com> </div>