<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>