blob: 60bfad7ccb13026a11e3fc41ea21dc46e6b335d4 [file] [log] [blame]
Harald Welte78861c02020-05-14 13:28:07 +02001/* GSM A-bis TRAU frame synchronization as per TS 48.060 / 48.061 */
2
3/* (C) 2020 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <stdint.h>
24
25#include <osmocom/core/msgb.h>
26#include <osmocom/core/bits.h>
27#include <osmocom/core/fsm.h>
28
29#include "ubit_buf.h"
30#include <osmocom/trau/trau_sync.h>
31
32#define S(x) (1 << (x))
33
Philipp Maier4934ff52022-11-03 16:07:19 +010034#define MAX_TRAU_BYTES 160
Philipp Maier9c9289c2023-02-13 16:43:52 +010035#define MAX_TRAU_SYNC_PATTERN 8
36#define PRIMARY_PATTERN 0
Harald Welte78861c02020-05-14 13:28:07 +020037
38#define T_SYNC 1
39
40struct sync_pattern {
41 /* provided by user */
42 const char *name; /*!< human-readable name */
43 const uint8_t byte_pattern[MAX_TRAU_BYTES]; /*!< bytes to match against */
44 const uint8_t byte_mask[MAX_TRAU_BYTES]; /*!< mask applied before matching */
45 uint8_t byte_len; /*!< length of mask in bytes */
46
47 /* generated by code */
48 ubit_t ubit_pattern[MAX_TRAU_BYTES*8]; /*!< bits to match against */
49 ubit_t ubit_mask[MAX_TRAU_BYTES*8]; /*!< mask applied before matching */
50 uint8_t bitcount; /*!< number of high bits in mask */
51};
52
53static struct sync_pattern sync_patterns[] = {
54 [OSMO_TRAU_SYNCP_16_FR_EFR] = {
55 /* TS 08.60 Section 4.8.1 */
56 .name = "FR/EFR",
57 .byte_pattern = {
58 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
59 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
60 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
61 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
62 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
63 },
64 .byte_mask = {
65 0xff, 0xff, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
66 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
67 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
68 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
69 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
70 },
71 .byte_len = 40,
72 },
73 [OSMO_TRAU_SYNCP_8_HR] = {
74 /* TS 08.61 Section 6.8.2.1.1 */
75 .name = "HR8",
76 .byte_pattern = {
77 0x00, 0x80, 0x40, 0x80,
78 0x80, 0x80, 0x80, 0x80,
79 0x80, 0x80, 0x80, 0x80,
80 0x80, 0x80, 0x80, 0x80,
81 0x80, 0x80, 0x80, 0x80,
82 },
83 .byte_mask = {
84 0xff, 0x80, 0xC0, 0x80,
85 0x80, 0x80, 0x80, 0x80,
86 0x80, 0x80, 0x80, 0x80,
87 0x80, 0x80, 0x80, 0x80,
88 0x80, 0x80, 0x80, 0x80,
89 },
90 .byte_len = 20,
91 },
92 [OSMO_TRAU_SYNCP_8_AMR_LOW] = {
93 /* TS 08.61 Section 6.8.2.1.2 */
94 /* The frame synchronisation for No_Speech frames and the speech frames of the three lower codec modes */
95 .name = "AMR8_LOW",
96 .byte_pattern = {
97 0x00, 0x80, 0x80, 0x40,
98 0x80, 0x80, 0x80, 0x80,
99 0x80, 0x80, 0x80, 0x80,
100 0x80, 0x80, 0x80, 0x80,
101 0x80, 0x80, 0x80, 0x80,
102 },
103 .byte_mask = {
104 0xff, 0x80, 0x80, 0xC0,
105 0x80, 0x80, 0x80, 0x80,
106 0x80, 0x80, 0x80, 0x80,
107 0x80, 0x80, 0x80, 0x80,
108 0x80, 0x80, 0x80, 0x80,
109 },
110 .byte_len = 20,
111 },
112 [OSMO_TRAU_SYNCP_8_AMR_6K7] = {
113 /* The frame synchronisation for the speech frames for codec mode 6,70 kBit/s */
114 .name = "AMR8_67",
115 .byte_pattern = {
116 0x00, 0x80, 0x80, 0x80,
117 0x80, 0x00, 0x80, 0x00,
118 0x80, 0x00, 0x80, 0x00,
119 0x80, 0x00, 0x80, 0x00,
120 0x80, 0x00, 0x80, 0x00,
121 },
122 .byte_mask = {
123 0xff, 0x80, 0x80, 0x80,
124 0x80, 0x80, 0x80, 0x00,
125 0x80, 0x00, 0x80, 0x00,
126 0x80, 0x00, 0x80, 0x00,
127 0x80, 0x00, 0x80, 0x00,
128 },
129 .byte_len = 20
130 },
131 [OSMO_TRAU_SYNCP_8_AMR_7K4] = {
132 /* The frame synchronisation for the speech frames for codec mode 7,40 kBit/s */
133 .name = "AMR8_74",
134 .byte_pattern = {
135 0x20, 0x00, 0x80, 0x00,
136 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x00, 0x00,
139 0x00, 0x00, 0x00, 0x00,
140 },
141 .byte_mask = {
142 0xe0, 0x80, 0x80, 0x80,
143 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00,
147 },
148 .byte_len = 20,
149 },
Harald Welte9d90eb92022-11-29 20:46:52 +0100150 [OSMO_TRAU_SYNCP_V110] = {
151 /* See Table 2 of ITU-T V.110 */
152 .name = "V110",
153 .byte_pattern = {
154 0x00, 0x80, 0x80, 0x80, 0x80,
155 0x80, 0x80, 0x80, 0x80, 0x80,
156 },
157 .byte_mask = {
158 0xff, 0x80, 0x80, 0x80, 0x80,
159 0x80, 0x80, 0x80, 0x80, 0x80,
160 },
161 .byte_len = 10,
162 },
Philipp Maiercf890392022-09-01 18:48:14 +0200163 [OSMO_TRAU_SYNCP_16_ER_CCU] = {
164 .name = "Ericsson CCU 16 kbps",
165 .byte_pattern = {
166 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 },
172 .byte_mask = {
173 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 },
179 .byte_len = 40,
Harald Welte78861c02020-05-14 13:28:07 +0200180 },
Philipp Maierf2649502022-12-20 12:38:26 +0100181 [OSMO_TRAU_SYNCP_64_ER_CCU] = {
182 .name = "Ericsson CCU 64 kbps",
183 .byte_pattern = {
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 },
205 .byte_mask = {
206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
207 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 },
227 .byte_len = 160,
228 },
Philipp Maier7ff2afc2023-02-13 17:14:58 +0100229 [OSMO_TRAU_SYNCP_64_ER_CCU_MCS9] = {
230 .name = "Ericsson CCU 64 kbps MCS9",
231 .byte_pattern = {
232 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 },
253 .byte_mask = {
254 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274 },
275 .byte_len = 160,
276 },
Harald Welte78861c02020-05-14 13:28:07 +0200277};
278
Harald Welte78861c02020-05-14 13:28:07 +0200279static void expand_sync_pattern(struct sync_pattern *pat)
280{
281 osmo_pbit2ubit(pat->ubit_pattern, pat->byte_pattern, pat->byte_len*8);
282 osmo_pbit2ubit(pat->ubit_mask, pat->byte_mask, pat->byte_len*8);
283}
284
285static unsigned int count_one_bits(const ubit_t *in, unsigned int in_bits)
286{
287 unsigned int i, count = 0;
288
289 for (i = 0; i < in_bits; i++) {
290 if (in[i])
291 count++;
292 }
293 return count;
294}
295
296static void sync_pattern_register(struct sync_pattern *p)
297{
298 expand_sync_pattern(p);
299 p->bitcount = count_one_bits(p->ubit_mask, p->byte_len*8);
300}
301
302#if 0
303/*! correlate pattern with unpacked bits from buffer.
304 * \param[in] pattern sync_pattern against which we shall compare
305 * \param[in] bits unpacked bits to compare against pattern
306 * \param[in] num_bits number of unpacked bits
307 * \returns number of bits not matching pattern; -1 if insufficient bits available. */
308static int correlate_pattern_ubits(const struct sync_pattern *pattern,
309 const ubit_t *bits, size_t num_bits)
310{
311 int i, num_wrong = 0;
312
313 if (num_bits < pattern->byte_len*8)
314 return -1; /* insufficient data */
315
316 for (i = 0; i < pattern->byte_len *8; i++) {
317 /* if mask doesn't contain '1', we can skip this octet */
318 if (!pattern->ubit_mask)
319 continue;
320 if (bits[i] != pattern->ubit_pattern[i])
321 num_wrong++;
322 }
323
324 return num_wrong;
325}
326#endif
327
328struct trau_rx_sync_state {
329 /*! call-back to be called for every TRAU frame (called with
330 * bits=NULL in case of frame sync loss */
331 frame_out_cb_t out_cb;
332 /*! opaque user data; passed to out_cb */
333 void *user_data;
334
335 /*! history of received bits */
336 ubit_t history[MAX_TRAU_BYTES*8+1]; /* +1 not required, but helps to expose bugs */
337 /*! index of next-to-be-written ubit in history */
338 unsigned int history_idx;
Philipp Maier9c9289c2023-02-13 16:43:52 +0100339 /*! the pattern(s) we are trying to sync to */
340 const struct sync_pattern *pattern[MAX_TRAU_SYNC_PATTERN];
Harald Welte78861c02020-05-14 13:28:07 +0200341 /*! number of consecutive frames without sync */
342 unsigned int num_consecutive_errors;
343};
344
345/* correlate the history (up to the last received bit) against the pattern */
Philipp Maier9c9289c2023-02-13 16:43:52 +0100346static int correlate_history_against_pattern(struct trau_rx_sync_state *tss, const struct sync_pattern *pattern)
Harald Welte78861c02020-05-14 13:28:07 +0200347{
Harald Welte78861c02020-05-14 13:28:07 +0200348 int i, start, num_wrong = 0;
349
350 /* compute index of first bit in history array */
351 start = (ARRAY_SIZE(tss->history) + tss->history_idx - pattern->byte_len*8)
352 % ARRAY_SIZE(tss->history);
353
354 OSMO_ASSERT(ARRAY_SIZE(tss->history) >= pattern->byte_len*8);
355
356 for (i = 0; i < pattern->byte_len*8; i++) {
357 unsigned int pos = (start + i) % ARRAY_SIZE(tss->history);
358
359 /* if mask doesn't contain '1', we can skip this octet */
360 if (!pattern->ubit_mask[i])
361 continue;
362 if (tss->history[pos] != pattern->ubit_pattern[i])
363 num_wrong++;
364 }
365
366 return num_wrong;
367}
368
Philipp Maier9c9289c2023-02-13 16:43:52 +0100369/* correlate the history (up to the last received bit) against multiple patterns */
370static int correlate_history_against_patterns(struct trau_rx_sync_state *tss)
371{
372 size_t pat_index;
373 int num_wrong;
374 int num_wrong_best = MAX_TRAU_BYTES * 8;
375
376 for (pat_index = PRIMARY_PATTERN; pat_index < MAX_TRAU_SYNC_PATTERN; pat_index++) {
377 const struct sync_pattern *pattern;
378
379 pattern = tss->pattern[pat_index];
380 if (!pattern)
381 continue;
382 num_wrong = correlate_history_against_pattern(tss, pattern);
383
384 /* We cannot achieve a better result than 0 errors */
385 if (num_wrong == 0)
386 return 0;
387
388 /* Keep track on the best result */
389 if (num_wrong < num_wrong_best)
390 num_wrong_best = num_wrong;
391 }
392
393 return num_wrong_best;
394}
395
Harald Welte78861c02020-05-14 13:28:07 +0200396/* add (append) one ubit to the history; wrap as needed */
397static void rx_history_add_bit(struct trau_rx_sync_state *tss, ubit_t bit)
398{
399 tss->history[tss->history_idx] = bit;
400 /* simply wrap around at the end */
401 tss->history_idx = (tss->history_idx + 1) % ARRAY_SIZE(tss->history);
402}
403
404/* append bits to history. We assume that this does NOT wrap */
405static void rx_history_add_bits(struct trau_rx_sync_state *tss, const ubit_t *bits, size_t n_bits)
406{
Philipp Maier9c9289c2023-02-13 16:43:52 +0100407 unsigned int frame_bits_remaining = tss->pattern[PRIMARY_PATTERN]->byte_len*8 - tss->history_idx;
Harald Welte78861c02020-05-14 13:28:07 +0200408 OSMO_ASSERT(frame_bits_remaining >= n_bits);
409 memcpy(&tss->history[tss->history_idx], bits, n_bits);
410 tss->history_idx = tss->history_idx + n_bits;
411}
412
413/* align the history, i.e. next received bit is start of frame */
414static void rx_history_align(struct trau_rx_sync_state *tss)
415{
416 ubit_t tmp[sizeof(tss->history)];
417 size_t history_size = sizeof(tss->history);
Philipp Maier9c9289c2023-02-13 16:43:52 +0100418 size_t pattern_bits = tss->pattern[PRIMARY_PATTERN]->byte_len*8;
Harald Welte78861c02020-05-14 13:28:07 +0200419 size_t first_bit = (history_size + tss->history_idx - pattern_bits) % history_size;
420 int i;
421
422 /* we need to shift the last received frame to the start of the history buffer;
423 * do this in two steps: First copy to a local buffer on the stack, using modulo-arithmetic
424 * as index into the history. Second, copy it back to history */
425
426 for (i = 0; i < pattern_bits; i++)
427 tmp[i] = tss->history[(first_bit + i) % history_size];
428
429 memcpy(tss->history, tmp, history_size);
430 tss->history_idx = 0;
431}
432
433enum trau_sync_state {
434 WAIT_FRAME_ALIGN,
435 FRAME_ALIGNED,
436 /* if at least 3 consecutive frames with each at least one framing error have been received */
437 FRAME_ALIGNMENT_LOST,
438};
439
440enum trau_sync_event {
441 TRAUSYNC_E_RESET,
442 /*! a buffer of bits was received (msgb with ubits) */
443 TRAUSYNC_E_RX_BITS,
444};
445
446static const struct value_string trau_sync_event_names[] = {
447 { TRAUSYNC_E_RESET, "RESET" },
448 { TRAUSYNC_E_RX_BITS, "RX_BITS" },
449 { 0, NULL }
450};
451
452
453static void trau_sync_wait_align(struct osmo_fsm_inst *fi, uint32_t event, void *data)
454{
455 struct trau_rx_sync_state *tss = (struct trau_rx_sync_state *) fi->priv;
456 struct ubit_buf *ubb;
457
458 switch (event) {
459 case TRAUSYNC_E_RX_BITS:
460 ubb = data;
461 /* append every bit individually + check if we have sync */
462 while (ubb_length(ubb) > 0) {
463 ubit_t bit = ubb_pull_ubit(ubb);
464 int rc;
465
466 rx_history_add_bit(tss, bit);
Philipp Maier9c9289c2023-02-13 16:43:52 +0100467
468 /* Apply only the primary pattern while waiting for the alignment */
469 rc = correlate_history_against_pattern(tss, tss->pattern[PRIMARY_PATTERN]);
Harald Welte78861c02020-05-14 13:28:07 +0200470 if (!rc) {
471 osmo_fsm_inst_state_chg(fi, FRAME_ALIGNED, 0, 0);
472 /* treat remainder of input bits in correct state */
473 osmo_fsm_inst_dispatch(fi, TRAUSYNC_E_RX_BITS, ubb);
474 return;
475 }
476 }
477 break;
478 default:
479 OSMO_ASSERT(0);
480 }
481}
482
483static void trau_sync_aligned_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
484{
485 struct trau_rx_sync_state *tss = (struct trau_rx_sync_state *) fi->priv;
486 /* dispatch aligned frame to user */
487 rx_history_align(tss);
Philipp Maier9c9289c2023-02-13 16:43:52 +0100488 tss->out_cb(tss->user_data, tss->history, tss->pattern[PRIMARY_PATTERN]->byte_len*8);
Harald Welte78861c02020-05-14 13:28:07 +0200489}
490
491static void trau_sync_aligned(struct osmo_fsm_inst *fi, uint32_t event, void *data)
492{
493 struct trau_rx_sync_state *tss = (struct trau_rx_sync_state *) fi->priv;
494 struct ubit_buf *ubb;
495 int rc;
496
497 switch (event) {
498 case TRAUSYNC_E_RX_BITS:
499 ubb = data;
500 while (ubb_length(ubb)) {
Philipp Maier9c9289c2023-02-13 16:43:52 +0100501 unsigned int frame_bits_remaining = tss->pattern[PRIMARY_PATTERN]->byte_len*8 - tss->history_idx;
Harald Welte78861c02020-05-14 13:28:07 +0200502 if (ubb_length(ubb) < frame_bits_remaining) {
503 /* frame not filled by this message; just add data */
504 rx_history_add_bits(tss, ubb_data(ubb), ubb_length(ubb));
505 ubb_pull(ubb, ubb_length(ubb));
506 } else {
507 /* append as many bits as are missing in the current frame */
508 rx_history_add_bits(tss, ubb_data(ubb), frame_bits_remaining);
509 ubb_pull(ubb, frame_bits_remaining);
510
Philipp Maier9c9289c2023-02-13 16:43:52 +0100511 /* check if we still have frame sync using the primary and all secondary patterns */
512 rc = correlate_history_against_patterns(tss);
Harald Welte78861c02020-05-14 13:28:07 +0200513 if (rc > 0) {
514 tss->num_consecutive_errors++;
515 if (tss->num_consecutive_errors >= 3) {
516 tss->history_idx = 0;
517 /* send NULL frame to user */
518 tss->out_cb(tss->user_data, NULL, 0);
519 osmo_fsm_inst_state_chg(fi, FRAME_ALIGNMENT_LOST, 1, T_SYNC);
520 osmo_fsm_inst_dispatch(fi, TRAUSYNC_E_RX_BITS, ubb);
521 return;
522 }
523 } else
524 tss->num_consecutive_errors = 0;
525
526 /* dispatch aligned frame to user */
527 tss->out_cb(tss->user_data, tss->history, tss->history_idx);
528 tss->history_idx = 0;
529 }
530 }
531 break;
532 default:
533 OSMO_ASSERT(0);
534 }
535}
536
537static void trau_sync_alignment_lost(struct osmo_fsm_inst *fi, uint32_t event, void *data)
538{
539 /* we try to restore sync for some amount of time before generating an error */
540
541 switch (event) {
542 case TRAUSYNC_E_RX_BITS:
543 trau_sync_wait_align(fi, event, data);
544 break;
545 default:
546 OSMO_ASSERT(0);
547 }
548}
549
550static void trau_sync_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
551{
552 switch (event) {
553 case TRAUSYNC_E_RESET:
554 osmo_fsm_inst_state_chg(fi, WAIT_FRAME_ALIGN, 0, 0);
555 break;
556 default:
557 OSMO_ASSERT(0);
558 }
559}
560
561static int trau_sync_timeout(struct osmo_fsm_inst *fi)
562{
563 switch (fi->T) {
564 case T_SYNC:
565 /* if Tsync expires before frame synchronization is
566 * again obtained the TRAU initiates sending of the
567 * urgent alarm pattern described in clause 4.10.2. */
568 osmo_fsm_inst_state_chg(fi, WAIT_FRAME_ALIGN, 0, 0);
569 break;
570 default:
571 OSMO_ASSERT(0);
572 }
573 return 0;
574}
575
576static const struct osmo_fsm_state trau_sync_states[] = {
577 [WAIT_FRAME_ALIGN] = {
578 .name = "WAIT_FRAME_ALIGN",
579 .in_event_mask = S(TRAUSYNC_E_RX_BITS),
580 .out_state_mask = S(FRAME_ALIGNED),
581 .action = trau_sync_wait_align,
582 },
583 [FRAME_ALIGNED] = {
584 .name = "FRAME_ALIGNED",
585 .in_event_mask = S(TRAUSYNC_E_RX_BITS),
586 .out_state_mask = S(FRAME_ALIGNMENT_LOST) | S(WAIT_FRAME_ALIGN),
587 .action = trau_sync_aligned,
588 .onenter = trau_sync_aligned_onenter,
589 },
590 [FRAME_ALIGNMENT_LOST] = {
591 .name = "FRAME_ALIGNMENT_LOST",
592 .in_event_mask = S(TRAUSYNC_E_RX_BITS),
593 .out_state_mask = S(WAIT_FRAME_ALIGN) | S(FRAME_ALIGNED),
594 .action = trau_sync_alignment_lost,
595 },
596};
597
598static struct osmo_fsm trau_sync_fsm = {
599 .name = "trau_sync",
600 .states = trau_sync_states,
601 .num_states = ARRAY_SIZE(trau_sync_states),
602 .allstate_event_mask = S(TRAUSYNC_E_RESET),
603 .allstate_action = trau_sync_allstate,
604 .timer_cb = trau_sync_timeout,
605 .log_subsys = DLGLOBAL,
606 .event_names = trau_sync_event_names,
607};
608
609
610struct osmo_fsm_inst *
611osmo_trau_sync_alloc(void *ctx, const char *name, frame_out_cb_t frame_out_cb,
Harald Weltece700742022-11-30 18:07:36 +0100612 enum osmo_trau_sync_pat_id pat_id, void *user_data)
Harald Welte78861c02020-05-14 13:28:07 +0200613{
614 struct trau_rx_sync_state *tss;
615 struct osmo_fsm_inst *fi;
616
617 if (pat_id >= ARRAY_SIZE(sync_patterns))
618 return NULL;
619
Keithbbff3042021-04-28 21:33:00 -0500620 fi = osmo_fsm_inst_alloc(&trau_sync_fsm, ctx, NULL, LOGL_INFO, name);
Harald Welte78861c02020-05-14 13:28:07 +0200621 if (!fi)
622 return NULL;
623 tss = talloc_zero(fi, struct trau_rx_sync_state);
624 if (!tss) {
625 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
626 return NULL;
627 }
628 fi->priv = tss;
629
630 tss->out_cb = frame_out_cb;
631 tss->user_data = user_data;
Philipp Maier9c9289c2023-02-13 16:43:52 +0100632 tss->pattern[PRIMARY_PATTERN] = &sync_patterns[pat_id];
Harald Welte78861c02020-05-14 13:28:07 +0200633
Philipp Maier8eae96f2020-07-31 20:01:42 +0200634 /* An unusued E1 timeslot normally would send an idle signal that
635 * has all bits set to one. In order to prevent false-positive
636 * synchronization on startup we set all history bits to 1, to make
637 * it look like a signal from an unused timeslot. */
638 memset(tss->history, 1, sizeof(tss->history));
639
Harald Welte78861c02020-05-14 13:28:07 +0200640 return fi;
641}
642
Harald Weltece700742022-11-30 18:07:36 +0100643void osmo_trau_sync_set_pat(struct osmo_fsm_inst *fi, enum osmo_trau_sync_pat_id pat_id)
Philipp Maier8d150012020-08-07 17:13:57 +0200644{
645 struct trau_rx_sync_state *tss = fi->priv;
646
Philipp Maier9c9289c2023-02-13 16:43:52 +0100647 /* Clear the pattern list to get rid of all secondary pattern settings */
648 memset(tss->pattern, 0, sizeof(tss->pattern));
649
650 /* Set the primary pattern and reset the FSM */
651 tss->pattern[PRIMARY_PATTERN] = &sync_patterns[pat_id];
652 osmo_fsm_inst_state_chg(fi, FRAME_ALIGNMENT_LOST, 0, 0);
653}
654
655void osmo_trau_sync_set_secondary_pat(struct osmo_fsm_inst *fi, enum osmo_trau_sync_pat_id pat_id, size_t pat_index)
656{
657 struct trau_rx_sync_state *tss = fi->priv;
658
659 OSMO_ASSERT(pat_index > PRIMARY_PATTERN);
660 OSMO_ASSERT(pat_index < ARRAY_SIZE(tss->pattern));
661
662 /* Make sure that only a pattern of the same size can be set as secondary pattern */
663 OSMO_ASSERT(tss->pattern[PRIMARY_PATTERN]->byte_len == sync_patterns[pat_id].byte_len);
664
665 tss->pattern[pat_index] = &sync_patterns[pat_id];
Philipp Maier8d150012020-08-07 17:13:57 +0200666 osmo_fsm_inst_state_chg(fi, FRAME_ALIGNMENT_LOST, 0, 0);
667}
668
Harald Welte78861c02020-05-14 13:28:07 +0200669void osmo_trau_sync_rx_ubits(struct osmo_fsm_inst *fi, const ubit_t *bits, size_t n_bits)
670{
671 struct ubit_buf ubb;
672 ubb_init(&ubb, bits, n_bits);
673 osmo_fsm_inst_dispatch(fi, TRAUSYNC_E_RX_BITS, &ubb);
674}
675
676static void __attribute__((constructor)) on_dso_load_sync(void)
677{
678 int i;
679
680 for (i = 0; i < ARRAY_SIZE(sync_patterns); i++)
681 sync_pattern_register(&sync_patterns[i]);
Harald Welteab8e0662020-08-06 11:56:52 +0200682 OSMO_ASSERT(osmo_fsm_register(&trau_sync_fsm) == 0);
Harald Welte78861c02020-05-14 13:28:07 +0200683}