trxcon/l1sched: clarify TDMA Fn (mod 26) maps
[osmocom-bb.git] / src / target / trx_toolkit / gsm_shared.py
blob5f59ba6f247e46d7a0ca062ffc6c8983a1e61140
1 # -*- coding: utf-8 -*-
3 # TRX Toolkit
4 # Common GSM constants and helpers
6 # (C) 2018-2020 by Vadim Yanitskiy <axilirator@gmail.com>
7 # Contributions by sysmocom - s.f.m.c. GmbH
9 # All Rights Reserved
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 from enum import Enum
23 # TDMA definitions
24 GSM_SUPERFRAME = 26 * 51
25 GSM_HYPERFRAME = 2048 * GSM_SUPERFRAME
27 # Burst length
28 GMSK_BURST_LEN = 148
29 EDGE_BURST_LEN = GMSK_BURST_LEN * 3
31 class BurstType(Enum):
32 """ Burst types defined in 3GPP TS 45.002 """
33 DUMMY = ("DB") # Dummy burst (5.2.6)
34 SYNC = ("SB") # Synchronization Burst (5.2.5)
35 FREQ = ("FB") # Frequency correction Burst (5.2.4)
36 ACCESS = ("AB") # Access Burst (5.2.7)
37 NORMAL = ("NB") # Normal Burst (5.2.3)
38 # HSR = ("HB") # Higher symbol rate burst (5.2.3a)
40 class TrainingSeqGMSK(Enum):
41 """ Training Sequences defined in 3GPP TS 45.002 """
43 # Training Sequences for Access Burst (table 5.2.7-3)
44 AB_TS0 = (0, BurstType.ACCESS, "01001011011111111001100110101010001111000")
45 AB_TS1 = (1, BurstType.ACCESS, "01010100111110001000011000101111001001101")
46 AB_TS2 = (2, BurstType.ACCESS, "11101111001001110101011000001101101110111")
47 AB_TS4 = (4, BurstType.ACCESS, "11001001110001001110000000001101010110010")
49 # Training Sequences for Access Burst (table 5.2.7-4)
50 AB_TS3 = (3, BurstType.ACCESS, "10001000111010111011010000010000101100010")
51 AB_TS5 = (5, BurstType.ACCESS, "01010000111111110101110101101100110010100")
52 AB_TS6 = (6, BurstType.ACCESS, "01011110011101011110110100010011000010111")
53 AB_TS7 = (7, BurstType.ACCESS, "01000010110000011101001010111011100010000")
55 # Training Sequences for Synchronization Burst (table 5.2.5-3)
56 SB_TS0 = (0, BurstType.SYNC, "1011100101100010000001000000111100101101010001010111011000011011")
57 SB_TS1 = (1, BurstType.SYNC, "1110111001101011001010000011111011110100011111101100101100010101")
58 SB_TS2 = (2, BurstType.SYNC, "1110110000110111010100010101101001111000000100000010001101001110")
59 SB_TS3 = (3, BurstType.SYNC, "1011101000111101110101101111010010001011010000001000111010011000")
61 # Training Sequences for Normal Burst (table 5.2.3a, TSC set 1)
62 NB_TS0 = (0, BurstType.NORMAL, "00100101110000100010010111")
63 NB_TS1 = (1, BurstType.NORMAL, "00101101110111100010110111")
64 NB_TS2 = (2, BurstType.NORMAL, "01000011101110100100001110")
65 NB_TS3 = (3, BurstType.NORMAL, "01000111101101000100011110")
66 NB_TS4 = (4, BurstType.NORMAL, "00011010111001000001101011")
67 NB_TS5 = (5, BurstType.NORMAL, "01001110101100000100111010")
68 NB_TS6 = (6, BurstType.NORMAL, "10100111110110001010011111")
69 NB_TS7 = (7, BurstType.NORMAL, "11101111000100101110111100")
71 # TODO: more TSC sets from tables 5.2.3b-d
73 def __init__(self, tsc, bt, seq_str, tsc_set = 0):
74 # Training Sequence Code
75 self.tsc = tsc
76 # Burst type
77 self.bt = bt
79 # Training Sequence Code set
80 # NOTE: unlike the specs. we count from zero
81 self.tsc_set = tsc_set
83 # Generate Training Sequence bits
84 self.seq = [int(x) for x in seq_str]
86 @classmethod
87 def pick(self, burst):
88 # Normal burst TS (26 bits)
89 nb_seq = burst[3 + 57 + 1:][:26]
90 # Access burst TS (41 bits)
91 ab_seq = burst[8:][:41]
92 # Sync Burst TS (64 bits)
93 sb_seq = burst[3 + 39:][:64]
95 for ts in list(self):
96 # Ugly Python way of writing 'switch' statement
97 if ts.bt is BurstType.NORMAL and ts.seq == nb_seq:
98 return ts
99 elif ts.bt is BurstType.ACCESS and ts.seq == ab_seq:
100 return ts
101 elif ts.bt is BurstType.SYNC and ts.seq == sb_seq:
102 return ts
104 return None
106 class HoppingParams:
107 """ Hopping sequence generation as per 3GPP TS 45.002, section 6.2.3.
109 Based on firmware/layer1/rfch.c:rfch_hop_seq_gen() by Sylvain Munaut.
113 # Magic numbers for pseudo-random hopping sequence generation
114 RNTABLE = [
115 48, 98, 63, 1, 36, 95, 78, 102, 94, 73,
116 0, 64, 25, 81, 76, 59, 124, 23, 104, 100,
117 101, 47, 118, 85, 18, 56, 96, 86, 54, 2,
118 80, 34, 127, 13, 6, 89, 57, 103, 12, 74,
119 55, 111, 75, 38, 109, 71, 112, 29, 11, 88,
120 87, 19, 3, 68, 110, 26, 33, 31, 8, 45,
121 82, 58, 40, 107, 32, 5, 106, 92, 62, 67,
122 77, 108, 122, 37, 60, 66, 121, 42, 51, 126,
123 117, 114, 4, 90, 43, 52, 53, 113, 120, 72,
124 16, 49, 7, 79, 119, 61, 22, 84, 9, 97,
125 91, 15, 21, 24, 46, 39, 93, 105, 65, 70,
126 125, 99, 17, 123,
129 def __init__(self, hsn, maio, ma):
130 # Make sure MA is not empty
131 ma_len = len(ma)
132 if ma_len == 0: # TODO: or rather > 1?
133 raise ValueError("Mobile Allocation is empty")
135 self.hsn = hsn
136 self.maio = maio
137 self.ma = ma
139 # Pre-calculate 2 ** NBIN in advance
140 self._pnm = (ma_len >> 0) | (ma_len >> 1) \
141 | (ma_len >> 2) | (ma_len >> 3) \
142 | (ma_len >> 4) | (ma_len >> 5) \
143 | (ma_len >> 6)
145 def __str__(self):
146 fmt = "hsn=%u, maio=%u, ma_len=%u"
147 return fmt % (self.hsn, self.maio, len(self.ma))
149 @staticmethod
150 def fn2gsm_time(fn):
151 t1 = fn // (26 * 51)
152 t2 = fn % 26
153 t3 = fn % 51
154 tc = (fn // 51) % 8
155 return (t1, t2, t3, tc)
157 # Resolve current ARFCN using the given TDMA frame number
158 def resolve(self, fn):
159 # Cyclic hopping
160 if self.hsn == 0:
161 mai = (fn + self.maio) % len(self.ma)
162 return self.ma[mai]
164 # Pseudo random hopping
165 (t1, t2, t3, tc) = self.fn2gsm_time(fn)
166 ma_len = len(self.ma)
168 rn_idx = (self.hsn ^ (t1 & 63)) + t3
169 m = t2 + self.RNTABLE[rn_idx]
170 mp = m & self._pnm
172 s = mp if mp < ma_len else (mp + t3 & self._pnm) % ma_len
173 mai = (s + self.maio) % ma_len
174 return self.ma[mai]