<p>fixeria has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmocom-bb/+/14579">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">trx_toolkit/data_msg.py: implement header version 0x01 coding<br><br>The new version mostly adds new fields to the TRX2L1 message:<br><br>  +------+-----+-----+-----+-----+--------------------+<br>  | RSSI | ToA | MTS | C/I | L16 | soft-bits (254..0) |<br>  +------+-----+-----+-----+-----+--------------------+<br><br>  where:<br><br>    - MTS (1 octet)  - Modulation and Training Sequence info,<br>    - C/I (2 octets) - Carrier-to-Interference ratio (big endian),<br>    - L16 (2 octets) - length of burst (big endian).<br><br>In case of L12TRX, the burst bits are now also encoded as L16V:<br><br>  +-----+-----+--------------------+<br>  | PWR | L16 | hard-bits (1 or 0) |<br>  +-----+-----+--------------------+<br><br>== Coding of MTS: Modulation and Training Sequence info<br><br>3GPP TS 45.002 version 15.1.0 defines several modulation types,<br>and a few sets of training sequences for each type. The most<br>common are GMSK and 8-PSK (which is used in EDGE).<br><br>  +-----------------+---------------------------------------+<br>  | 7 6 5 4 3 2 1 0 | bit numbers (value range)             |<br>  +-----------------+---------------------------------------+<br>  | . . . . . X X X | Training Sequence Code (0..7)         |<br>  +-----------------+---------------------------------------+<br>  | . X X X X . . . | Modulation, TS set number (see below) |<br>  +-----------------+---------------------------------------+<br>  | X . . . . . . . | IDLE / nope frame indication (0 or 1) |<br>  +-----------------+---------------------------------------+<br><br>The bit number 7 (MSB) is set to high when either nothing has been<br>detected, or during IDLE frames, so we can deliver noise levels,<br>and avoid clock gaps on the L1 side. Other bits are ignored,<br>and should be set to low (0) in this case. L16 shall be set to 0x00.<br><br>== Coding of modulation and TS set number<br><br>GMSK has 4 sets of training sequences (see tables 5.2.3a-d),<br>while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets.<br>Access and Synchronization bursts also have several synch.<br>sequences.<br><br>  +-----------------+---------------------------------------+<br>  | 7 6 5 4 3 2 1 0 | bit numbers (value range)             |<br>  +-----------------+---------------------------------------+<br>  | . 0 0 X X . . . | GMSK, 4 TS sets (0..3)                |<br>  +-----------------+---------------------------------------+<br>  | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1)               |<br>  +-----------------+---------------------------------------+<br>  | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1)               |<br>  +-----------------+---------------------------------------+<br>  | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1)               |<br>  +-----------------+---------------------------------------+<br>  | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1)               |<br>  +-----------------+---------------------------------------+<br>  | . 1 1 1 X . . . | RESERVED (0)                          |<br>  +-----------------+---------------------------------------+<br><br>== C/I: Carrier-to-Interference ratio<br><br>The C/I value is computed from the training sequence of each burst,<br>where we can compare the "ideal" training sequence with the actual<br>training sequence and then express that in dB.<br><br>Change-Id: Ie810c5a482d1c908994e8cdd32a2ea641ae7cedd<br>Related: OS#4006<br>---<br>M src/target/trx_toolkit/data_msg.py<br>1 file changed, 289 insertions(+), 32 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/79/14579/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/target/trx_toolkit/data_msg.py b/src/target/trx_toolkit/data_msg.py</span><br><span>index 8a114f7..8d52764 100644</span><br><span>--- a/src/target/trx_toolkit/data_msg.py</span><br><span>+++ b/src/target/trx_toolkit/data_msg.py</span><br><span>@@ -25,8 +25,17 @@</span><br><span> import random</span><br><span> import struct</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+from enum import IntEnum</span><br><span> from gsm_shared import *</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+class Modulation(IntEnum):</span><br><span style="color: hsl(120, 100%, 40%);">+     """ Modulation types defined in 3GPP TS 45.002 """</span><br><span style="color: hsl(120, 100%, 40%);">+      ModGMSK  = 0b0000</span><br><span style="color: hsl(120, 100%, 40%);">+     Mod8PSK  = 0b0100</span><br><span style="color: hsl(120, 100%, 40%);">+     ModAQPSK = 0b0110</span><br><span style="color: hsl(120, 100%, 40%);">+     Mod16QAM = 0b1000</span><br><span style="color: hsl(120, 100%, 40%);">+     Mod32QAM = 0b1010</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> class DATAMSG:</span><br><span>        """ TRXD (DATA) message codec (common part).</span><br><span> </span><br><span>@@ -45,6 +54,12 @@</span><br><span> </span><br><span>     while the message specific headers and bit types are different.</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   NOTE: since version 0x01, the burst bits are encoded as L16V:</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%);">+   | L16 (2 octets, BE) | burst bits |</span><br><span style="color: hsl(120, 100%, 40%);">+   +--------------------+------------+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      The common header is represented by this class, which is the</span><br><span>         parent of both DATAMSG_L12TRX and DATAMSG_TRX2L2 (see below),</span><br><span>        and has the following fields:</span><br><span>@@ -99,6 +114,12 @@</span><br><span>          self.fn = fn</span><br><span>                 self.tn = tn</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      # The common header length</span><br><span style="color: hsl(120, 100%, 40%);">+    @property</span><br><span style="color: hsl(120, 100%, 40%);">+     def CHDR_LEN(self):</span><br><span style="color: hsl(120, 100%, 40%);">+           # (VER + TN) + FN</span><br><span style="color: hsl(120, 100%, 40%);">+             return 1 + 4</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       # Generates message specific header</span><br><span>  def gen_hdr(self):</span><br><span>           raise NotImplementedError</span><br><span>@@ -227,7 +248,13 @@</span><br><span>             buf += hdr</span><br><span> </span><br><span>               # Generate burst</span><br><span style="color: hsl(0, 100%, 40%);">-                buf += self.gen_burst()</span><br><span style="color: hsl(120, 100%, 40%);">+               burst = self.gen_burst()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Starting from version 0x01, the burst bits are</span><br><span style="color: hsl(120, 100%, 40%);">+              # encoded as L16V (length is 2 octets, big endian).</span><br><span style="color: hsl(120, 100%, 40%);">+           if self.ver >= 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+                       buf += struct.pack(">H", len(burst))</span><br><span style="color: hsl(120, 100%, 40%);">+             buf += burst</span><br><span> </span><br><span>             # This is a rudiment from (legacy) OpenBTS transceiver,</span><br><span>              # some L1 implementations still expect two dummy bytes.</span><br><span>@@ -241,8 +268,8 @@</span><br><span>                # Calculate message length</span><br><span>           length = len(msg)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           # Check length</span><br><span style="color: hsl(0, 100%, 40%);">-          if length < (self.HDR_LEN + GSM_BURST_LEN):</span><br><span style="color: hsl(120, 100%, 40%);">+                # Make sure we have at least header</span><br><span style="color: hsl(120, 100%, 40%);">+           if length < self.HDR_LEN:</span><br><span>                         raise ValueError("Message is to short")</span><br><span> </span><br><span>                # Parse version and TDMA TN</span><br><span>@@ -255,9 +282,38 @@</span><br><span>           # Specific message part</span><br><span>              self.parse_hdr(msg)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-         # Copy burst, skipping header</span><br><span style="color: hsl(0, 100%, 40%);">-           msg_burst = msg[self.HDR_LEN:]</span><br><span style="color: hsl(0, 100%, 40%);">-          self.parse_burst(msg_burst)</span><br><span style="color: hsl(120, 100%, 40%);">+           # We're done with the header now</span><br><span style="color: hsl(120, 100%, 40%);">+          msg = msg[self.HDR_LEN:]</span><br><span style="color: hsl(120, 100%, 40%);">+              length -= self.HDR_LEN</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              # Verify the burst length</span><br><span style="color: hsl(120, 100%, 40%);">+             if self.ver == 0x00:</span><br><span style="color: hsl(120, 100%, 40%);">+                  # For version 0x00, we can either have as much as</span><br><span style="color: hsl(120, 100%, 40%);">+                     # a GSM burst length, or an EDGE burst length.</span><br><span style="color: hsl(120, 100%, 40%);">+                        if length in (GSM_BURST_LEN, EDGE_BURST_LEN):</span><br><span style="color: hsl(120, 100%, 40%);">+                         pass</span><br><span style="color: hsl(120, 100%, 40%);">+                  # Some ancient transceivers append 2 dummy octets</span><br><span style="color: hsl(120, 100%, 40%);">+                     elif (length - 2) in (GSM_BURST_LEN, EDGE_BURST_LEN):</span><br><span style="color: hsl(120, 100%, 40%);">+                         msg = msg[:-2]</span><br><span style="color: hsl(120, 100%, 40%);">+                                length -= 2</span><br><span style="color: hsl(120, 100%, 40%);">+                   else:</span><br><span style="color: hsl(120, 100%, 40%);">+                         raise ValueError("Odd burst length")</span><br><span style="color: hsl(120, 100%, 40%);">+                elif self.ver >= 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+                     # Starting from version 0x01, the burst bits are</span><br><span style="color: hsl(120, 100%, 40%);">+                      # encoded as L16V (length is 2 octets, big endian).</span><br><span style="color: hsl(120, 100%, 40%);">+                   if length < 2:</span><br><span style="color: hsl(120, 100%, 40%);">+                             raise ValueError("Missing burst LV")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      burst_len = struct.unpack(">H", msg[:2])[0]</span><br><span style="color: hsl(120, 100%, 40%);">+                      if burst_len != (length - 2):</span><br><span style="color: hsl(120, 100%, 40%);">+                         raise ValueError("Odd burst length")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      # We're done with L16 header</span><br><span style="color: hsl(120, 100%, 40%);">+                      msg = msg[2:]</span><br><span style="color: hsl(120, 100%, 40%);">+                 length -= 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # Parse burst</span><br><span style="color: hsl(120, 100%, 40%);">+         self.parse_burst(msg)</span><br><span> </span><br><span> class DATAMSG_L12TRX(DATAMSG):</span><br><span>  """ L12TRX (L1 -> TRX) message codec.</span><br><span>@@ -266,13 +322,24 @@</span><br><span>      or an Uplink burst on the MS side, and has the following</span><br><span>     message specific fixed-size header preceding the burst bits:</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      == Version 0x00</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      +-----+--------------------+</span><br><span>         | PWR | hard-bits (1 or 0) |</span><br><span>         +-----+--------------------+</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      where PWR (1 octet) is relative (to the full-scale amplitude)</span><br><span style="color: hsl(0, 100%, 40%);">-   transmit power level in dB. The absolute value is set on</span><br><span style="color: hsl(0, 100%, 40%);">-        the control interface.</span><br><span style="color: hsl(120, 100%, 40%);">+        == Version 0x01</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%);">+    | PWR | L16 | hard-bits (1 or 0) |</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%);">+        where:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        - PWR (1 octet)  - relative (to the full-scale amplitude) transmit</span><br><span style="color: hsl(120, 100%, 40%);">+                       power level in dB. The absolute value is set</span><br><span style="color: hsl(120, 100%, 40%);">+                          on the control interface.</span><br><span style="color: hsl(120, 100%, 40%);">+          - L16 (2 octets) - length of burst (big endian).</span><br><span> </span><br><span>       Each hard-bit (1 or 0) of the burst is represented using one</span><br><span>         byte (0x01 or 0x00 respectively).</span><br><span>@@ -280,13 +347,26 @@</span><br><span>    """</span><br><span> </span><br><span>       # Constants</span><br><span style="color: hsl(0, 100%, 40%);">-     HDR_LEN = 6</span><br><span>  PWR_MIN = 0x00</span><br><span>       PWR_MAX = 0xff</span><br><span> </span><br><span>   # Specific message fields</span><br><span>    pwr = None</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        # Calculates header length depending on its version</span><br><span style="color: hsl(120, 100%, 40%);">+   @property</span><br><span style="color: hsl(120, 100%, 40%);">+     def HDR_LEN(self):</span><br><span style="color: hsl(120, 100%, 40%);">+            # Common header length</span><br><span style="color: hsl(120, 100%, 40%);">+                length = self.CHDR_LEN</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              # Message specific header length</span><br><span style="color: hsl(120, 100%, 40%);">+              if self.ver in (0x00, 0x01):</span><br><span style="color: hsl(120, 100%, 40%);">+                  length += 1 # PWR</span><br><span style="color: hsl(120, 100%, 40%);">+             else:</span><br><span style="color: hsl(120, 100%, 40%);">+                 raise IndexError("Unhandled version %u" % self.ver)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               return length</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      # Validates the message fields</span><br><span>       def validate(self):</span><br><span>          # Validate common fields</span><br><span>@@ -349,13 +429,8 @@</span><br><span> </span><br><span>  # Parses message specific burst</span><br><span>      def parse_burst(self, burst):</span><br><span style="color: hsl(0, 100%, 40%);">-           length = len(burst)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Distinguish between GSM and EDGE</span><br><span style="color: hsl(0, 100%, 40%);">-              if length >= EDGE_BURST_LEN:</span><br><span style="color: hsl(0, 100%, 40%);">-                 self.burst = list(burst[:EDGE_BURST_LEN])</span><br><span style="color: hsl(0, 100%, 40%);">-               else:</span><br><span style="color: hsl(0, 100%, 40%);">-                   self.burst = list(burst[:GSM_BURST_LEN])</span><br><span style="color: hsl(120, 100%, 40%);">+              # Nothing to do, we already have hard-bits</span><br><span style="color: hsl(120, 100%, 40%);">+            self.burst = list(burst)</span><br><span> </span><br><span>         # Transforms this message to TRX2L1 message</span><br><span>  def gen_trx2l1(self, ver = None):</span><br><span>@@ -376,16 +451,79 @@</span><br><span>    or a Downlink burst on the MS side, and has the following</span><br><span>    message specific fixed-size header preceding the burst bits:</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      == Version 0x00</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      +------+-----+--------------------+</span><br><span>          | RSSI | ToA | soft-bits (254..0) |</span><br><span>          +------+-----+--------------------+</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     == Version 0x01</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%);">+         | RSSI | ToA | MTS | C/I | L16 | soft-bits (254..0) |</span><br><span style="color: hsl(120, 100%, 40%);">+         +------+-----+-----+-----+-----+--------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    where:</span><br><span> </span><br><span>     - RSSI (1 octet) - Received Signal Strength Indication</span><br><span>                          encoded without the negative sign.</span><br><span>        - ToA (2 octets) - Timing of Arrival in units of 1/256</span><br><span>                          of symbol (big endian).</span><br><span style="color: hsl(120, 100%, 40%);">+    - MTS (1 octet)  - Modulation and Training Sequence info.</span><br><span style="color: hsl(120, 100%, 40%);">+     - C/I (2 octets) - Carrier-to-Interference ratio (big endian).</span><br><span style="color: hsl(120, 100%, 40%);">+        - L16 (2 octets) - length of burst (big endian).</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  == Coding of TS: Training Sequence and modulation</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   3GPP TS 45.002 version 15.1.0 defines several modulation types,</span><br><span style="color: hsl(120, 100%, 40%);">+       and a few sets of training sequences for each type. The most</span><br><span style="color: hsl(120, 100%, 40%);">+  common are GMSK and 8-PSK (which is used in EDGE).</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%);">+   | 7 6 5 4 3 2 1 0 | bit numbers (value range)             |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | . . . . . X X X | Training Sequence Code (0..7)         |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | . X X X X . . . | Modulation, TS set number (see below) |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | X . . . . . . . | IDLE / nope frame indication (0 or 1) |</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%);">+       The bit number 7 (MSB) is set to high when either nothing has been</span><br><span style="color: hsl(120, 100%, 40%);">+    detected, or during IDLE frames, so we can deliver noise levels,</span><br><span style="color: hsl(120, 100%, 40%);">+      and avoid clock gaps on the L1 side. Other bits are ignored,</span><br><span style="color: hsl(120, 100%, 40%);">+  and should be set to low (0) in this case. L16 shall be set to 0x00.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        == Coding of modulation and TS set number</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   GMSK has 4 sets of training sequences (see tables 5.2.3a-d),</span><br><span style="color: hsl(120, 100%, 40%);">+  while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets.</span><br><span style="color: hsl(120, 100%, 40%);">+ Access and Synchronization bursts also have several synch.</span><br><span style="color: hsl(120, 100%, 40%);">+    sequences.</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%);">+   | 7 6 5 4 3 2 1 0 | bit numbers (value range)             |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | . 0 0 X X . . . | GMSK, 4 TS sets (0..3)                |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1)               |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1)               |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1)               |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1)               |</span><br><span style="color: hsl(120, 100%, 40%);">+   +-----------------+---------------------------------------+</span><br><span style="color: hsl(120, 100%, 40%);">+   | . 1 1 1 X . . . | RESERVED (0)                          |</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%);">+       == C/I: Carrier-to-Interference ratio</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       The C/I value can be computed from the training sequence of each</span><br><span style="color: hsl(120, 100%, 40%);">+      burst, where we can compare the "ideal" training sequence with</span><br><span style="color: hsl(120, 100%, 40%);">+      the actual training sequence and then express that in dB.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   == Coding of the burst bits</span><br><span> </span><br><span>      Unlike to be transmitted bursts, the received bursts are designated</span><br><span>  using the soft-bits notation, so the receiver can indicate its</span><br><span>@@ -398,9 +536,6 @@</span><br><span> </span><br><span>     """</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  # Constants</span><br><span style="color: hsl(0, 100%, 40%);">-     HDR_LEN = 8</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>  # rxlev2dbm(0..63) gives us [-110..-47], plus -10 dbm for noise</span><br><span>      RSSI_MIN = -120</span><br><span>      RSSI_MAX = -47</span><br><span>@@ -409,10 +544,42 @@</span><br><span>       TOA256_MIN = -32768</span><br><span>  TOA256_MAX = 32767</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        # TSC (Training Sequence Code) range</span><br><span style="color: hsl(120, 100%, 40%);">+  TSC_RANGE = range(0, 8)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     # IDLE frame / nope detection indicator</span><br><span style="color: hsl(120, 100%, 40%);">+       NOPE_IND = (1 << 7)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  # Specific message fields</span><br><span>    rssi = None</span><br><span>  toa256 = None</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     # Version 0x01 specific (default values)</span><br><span style="color: hsl(120, 100%, 40%);">+      mod_type = Modulation.ModGMSK</span><br><span style="color: hsl(120, 100%, 40%);">+ nope_ind = False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    tsc_set = None</span><br><span style="color: hsl(120, 100%, 40%);">+        tsc = None</span><br><span style="color: hsl(120, 100%, 40%);">+    ci = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   # Calculates header length depending on its version</span><br><span style="color: hsl(120, 100%, 40%);">+   @property</span><br><span style="color: hsl(120, 100%, 40%);">+     def HDR_LEN(self):</span><br><span style="color: hsl(120, 100%, 40%);">+            # Common header length</span><br><span style="color: hsl(120, 100%, 40%);">+                length = self.CHDR_LEN</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              # Message specific header length</span><br><span style="color: hsl(120, 100%, 40%);">+              if self.ver == 0x00:</span><br><span style="color: hsl(120, 100%, 40%);">+                  # RSSI + ToA</span><br><span style="color: hsl(120, 100%, 40%);">+                  length += 1 + 2</span><br><span style="color: hsl(120, 100%, 40%);">+               elif self.ver == 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+                        # RSSI + ToA + TS + C/I</span><br><span style="color: hsl(120, 100%, 40%);">+                       length += 1 + 2 + 1 + 2</span><br><span style="color: hsl(120, 100%, 40%);">+               else:</span><br><span style="color: hsl(120, 100%, 40%);">+                 raise IndexError("Unhandled version %u" % self.ver)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               return length</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      # Validates the message fields</span><br><span>       def validate(self):</span><br><span>          # Validate common fields</span><br><span>@@ -459,6 +626,17 @@</span><br><span>              self.rssi = self.rand_rssi()</span><br><span>                 self.toa256 = self.rand_toa256()</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+          if self.ver >= 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.mod_type = random.choice(list(Modulation))</span><br><span style="color: hsl(120, 100%, 40%);">+                       if self.mod_type == Modulation.ModGMSK:</span><br><span style="color: hsl(120, 100%, 40%);">+                               self.tsc_set = random.randint(0, 3)</span><br><span style="color: hsl(120, 100%, 40%);">+                   else:</span><br><span style="color: hsl(120, 100%, 40%);">+                         self.tsc_set = random.randint(0, 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                   self.tsc = random.choice(self.TSC_RANGE)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    # FIXME: C/I: Carrier-to-Interference ratio</span><br><span style="color: hsl(120, 100%, 40%);">+                   self.ci = random.choice(range(-100, 100))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  # Generates human-readable header description</span><br><span>        def desc_hdr(self):</span><br><span>          # Describe the common part</span><br><span>@@ -470,9 +648,61 @@</span><br><span>            if self.toa256 is not None:</span><br><span>                  result += ("toa256=%d " % self.toa256)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+          if self.ver >= 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+                       if not self.nope_ind:</span><br><span style="color: hsl(120, 100%, 40%);">+                         if self.mod_type is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 result += ("%s " % self.mod_type)</span><br><span style="color: hsl(120, 100%, 40%);">+                           if self.tsc_set is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                  result += ("set=%u " % self.tsc_set)</span><br><span style="color: hsl(120, 100%, 40%);">+                                if self.tsc is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                      result += ("tsc=%u " % self.tsc)</span><br><span style="color: hsl(120, 100%, 40%);">+                            if self.ci is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                       result += ("C/I=%d " % self.ci)</span><br><span style="color: hsl(120, 100%, 40%);">+                     else:</span><br><span style="color: hsl(120, 100%, 40%);">+                         result += "IDLE / NOP IND"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>               # Strip useless whitespace and return</span><br><span>                return result.strip()</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     # Encodes Modulation and Training Sequence info</span><br><span style="color: hsl(120, 100%, 40%);">+       def gen_mts(self):</span><br><span style="color: hsl(120, 100%, 40%);">+            # IDLE / nope indication has no MTS info</span><br><span style="color: hsl(120, 100%, 40%);">+              if self.nope_ind:</span><br><span style="color: hsl(120, 100%, 40%);">+                     return self.NOPE_IND</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                # TSC: . . . . . X X X</span><br><span style="color: hsl(120, 100%, 40%);">+                mts = self.tsc & 0b111</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          # MTS: . X X X X . . .</span><br><span style="color: hsl(120, 100%, 40%);">+                mts |= self.mod_type << 3</span><br><span style="color: hsl(120, 100%, 40%);">+               mts |= self.tsc_set << 3</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              return mts</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  # Parses Modulation and Training Sequence info</span><br><span style="color: hsl(120, 100%, 40%);">+        def parse_mts(self, mts):</span><br><span style="color: hsl(120, 100%, 40%);">+             # IDLE / nope indication has no MTS info</span><br><span style="color: hsl(120, 100%, 40%);">+              self.nope_ind = (mts & self.NOPE_IND) > 0</span><br><span style="color: hsl(120, 100%, 40%);">+              if self.nope_ind:</span><br><span style="color: hsl(120, 100%, 40%);">+                     self.mod_type = None</span><br><span style="color: hsl(120, 100%, 40%);">+                  self.tsc_set = None</span><br><span style="color: hsl(120, 100%, 40%);">+                   self.tsc = None</span><br><span style="color: hsl(120, 100%, 40%);">+                       return</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              # TSC: . . . . . X X X</span><br><span style="color: hsl(120, 100%, 40%);">+                self.tsc = mts & 0b111</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          # MTS: . X X X X . . .</span><br><span style="color: hsl(120, 100%, 40%);">+                mts = (mts >> 3) & 0b1111</span><br><span style="color: hsl(120, 100%, 40%);">+           if (mts & 0b1100) > 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                 # Mask: . . . . M M M S</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.mod_type = Modulation(mts & 0b1110)</span><br><span style="color: hsl(120, 100%, 40%);">+                  self.tsc_set = mts & 0b1</span><br><span style="color: hsl(120, 100%, 40%);">+          else:</span><br><span style="color: hsl(120, 100%, 40%);">+                 # GMSK: . . . . 0 0 S S</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.mod_type = Modulation.ModGMSK</span><br><span style="color: hsl(120, 100%, 40%);">+                    self.tsc_set = mts & 0b11</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      # Generates message specific header part</span><br><span>     def gen_hdr(self):</span><br><span>           # Allocate an empty byte-array</span><br><span>@@ -485,6 +715,20 @@</span><br><span>                # Big endian, 2 bytes (int32_t)</span><br><span>              buf += struct.pack(">h", self.toa256)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                if self.ver >= 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+                       # Modulation and Training Sequence info</span><br><span style="color: hsl(120, 100%, 40%);">+                       mts = self.gen_mts()</span><br><span style="color: hsl(120, 100%, 40%);">+                  buf.append(mts)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     # C/I: Carrier-to-Interference ratio</span><br><span style="color: hsl(120, 100%, 40%);">+                  # 2 octets, big endian (int16_t)</span><br><span style="color: hsl(120, 100%, 40%);">+                      # FIXME: Dummy filling (C/I)</span><br><span style="color: hsl(120, 100%, 40%);">+                  if not self.nope_ind:</span><br><span style="color: hsl(120, 100%, 40%);">+                         # FIXME!!!</span><br><span style="color: hsl(120, 100%, 40%);">+                            buf += bytearray(2)</span><br><span style="color: hsl(120, 100%, 40%);">+                   else:</span><br><span style="color: hsl(120, 100%, 40%);">+                         buf += bytearray(2)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                return buf</span><br><span> </span><br><span>       # Parses message specific header part</span><br><span>@@ -495,6 +739,18 @@</span><br><span>                 # Parse ToA (Time of Arrival)</span><br><span>                self.toa256 = struct.unpack(">h", hdr[6:8])[0]</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+               if self.ver >= 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+                       # Modulation and Training Sequence info</span><br><span style="color: hsl(120, 100%, 40%);">+                       self.parse_mts(hdr[8])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      # C/I: Carrier-to-Interference ratio</span><br><span style="color: hsl(120, 100%, 40%);">+                  # 2 octets, big endian (int16_t)</span><br><span style="color: hsl(120, 100%, 40%);">+                      if not self.nope_ind:</span><br><span style="color: hsl(120, 100%, 40%);">+                         # FIXME!!!</span><br><span style="color: hsl(120, 100%, 40%);">+                            self.ci = None</span><br><span style="color: hsl(120, 100%, 40%);">+                        else:</span><br><span style="color: hsl(120, 100%, 40%);">+                         self.ci = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     # Generates message specific burst</span><br><span>   def gen_burst(self):</span><br><span>                 # Convert soft-bits to unsigned soft-bits</span><br><span>@@ -505,19 +761,8 @@</span><br><span> </span><br><span>         # Parses message specific burst</span><br><span>      def parse_burst(self, burst):</span><br><span style="color: hsl(0, 100%, 40%);">-           length = len(burst)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Distinguish between GSM and EDGE</span><br><span style="color: hsl(0, 100%, 40%);">-              if length >= EDGE_BURST_LEN:</span><br><span style="color: hsl(0, 100%, 40%);">-                 burst_usbits = list(burst[:EDGE_BURST_LEN])</span><br><span style="color: hsl(0, 100%, 40%);">-             else:</span><br><span style="color: hsl(0, 100%, 40%);">-                   burst_usbits = list(burst[:GSM_BURST_LEN])</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>           # Convert unsigned soft-bits to soft-bits</span><br><span style="color: hsl(0, 100%, 40%);">-               burst_sbits = self.usbit2sbit(burst_usbits)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             # Save</span><br><span style="color: hsl(0, 100%, 40%);">-          self.burst = burst_sbits</span><br><span style="color: hsl(120, 100%, 40%);">+              self.burst = self.usbit2sbit(burst)</span><br><span> </span><br><span>      # Transforms this message to L12TRX message</span><br><span>  def gen_l12trx(self, ver = None):</span><br><span>@@ -682,6 +927,18 @@</span><br><span> </span><br><span>                 log.info("Check header version %u coding: OK" % ver)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+            # Match version specific fields</span><br><span style="color: hsl(120, 100%, 40%);">+               if msg_trx2l1.ver >= 0x01:</span><br><span style="color: hsl(120, 100%, 40%);">+                 log.info("TRX2L1: %s" % msg_trx2l1.desc_hdr())</span><br><span style="color: hsl(120, 100%, 40%);">+                      log.info("TRX2L1: %s" % msg_trx2l1_dec.desc_hdr())</span><br><span style="color: hsl(120, 100%, 40%);">+                  assert(msg_trx2l1_dec.nope_ind == msg_trx2l1.nope_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+                        assert(msg_trx2l1_dec.mod_type == msg_trx2l1.mod_type)</span><br><span style="color: hsl(120, 100%, 40%);">+                        assert(msg_trx2l1_dec.tsc_set == msg_trx2l1.tsc_set)</span><br><span style="color: hsl(120, 100%, 40%);">+                  assert(msg_trx2l1_dec.tsc == msg_trx2l1.tsc)</span><br><span style="color: hsl(120, 100%, 40%);">+                  assert(msg_trx2l1_dec.ci == msg_trx2l1.ci)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          log.info("Check version %u specific header coding: OK" % ver)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>            msg_trx2l1_gen = msg_l12trx.gen_trx2l1()</span><br><span>             msg_l12trx_gen = msg_trx2l1.gen_l12trx()</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmocom-bb/+/14579">change 14579</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmocom-bb/+/14579"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmocom-bb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ie810c5a482d1c908994e8cdd32a2ea641ae7cedd </div>
<div style="display:none"> Gerrit-Change-Number: 14579 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: fixeria <axilirator@gmail.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>