blob: 9c9baa77a5f0912bb4c31ab688ea7bfc7993cc40 [file] [log] [blame]
Harald Welte254b9242020-05-11 08:38:51 +02001/* New (2020) TRAU frame handling according to GSM TS 48.060 + 48.061 */
2
3/* (C) 2020 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * SPDX-License-Identifier: AGPL-3.0+
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22#include "internal.h"
23
24#include <unistd.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <errno.h>
29
30#include <osmocom/trau/trau_frame.h>
31#include <osmocom/core/logging.h>
32
33/*! \addtogroup trau_frame
34 * @{
35 *
36 * \file trau_frame.c
37 */
38
39static uint32_t get_bits(const ubit_t *bitbuf, int offset, int num)
40{
41 int i;
42 uint32_t ret = 0;
43
44 for (i = offset; i < offset + num; i++) {
45 ret = ret << 1;
46 if (bitbuf[i])
47 ret |= 1;
48 }
49 return ret;
50}
51
52const struct value_string osmo_trau_frame_type_names[] = {
53 { OSMO_TRAU_FT_NONE, "NONE" },
54 { OSMO_TRAU16_FT_FR, "FR" },
55 { OSMO_TRAU16_FT_HR, "HR" },
56 { OSMO_TRAU16_FT_EFR, "EFR" },
57 { OSMO_TRAU16_FT_AMR, "AMR" },
58 { OSMO_TRAU16_FT_OAM, "OAM" },
59 { OSMO_TRAU16_FT_DATA, "DATA" },
60 { OSMO_TRAU16_FT_EDATA, "EDATA" },
61 { OSMO_TRAU16_FT_D145_SYNC, "D145_SYNC" },
62 { OSMO_TRAU16_FT_DATA_HR, "DATA_HR" },
63 { OSMO_TRAU16_FT_IDLE, "IDLE" },
64 { OSMO_TRAU8_SPEECH, "8SPEECH" },
65 { OSMO_TRAU8_DATA, "8DATA" },
66 { OSMO_TRAU8_OAM, "8OAM" },
67 { OSMO_TRAU8_AMR_LOW, "8AMR_LOW" },
68 { OSMO_TRAU8_AMR_6k7, "8AMR_6k7" },
69 { OSMO_TRAU8_AMR_7k4, "8AMR_7k4" },
70 { 0, NULL }
71};
72
73/*********************************************************************************
74 * New API; introduced in 2020 for use by osmo-mgw
75 *********************************************************************************/
76
Harald Weltedd9ee982020-08-02 15:53:46 +020077/* Bits C21..C22 (16k) or C4..C5 (8k) */
78enum ts48060_amr_frame_classification {
79 TS48060_AMR_FC_SPEECH_GOOD = 0x3,
80 TS48060_AMR_FC_SPEECH_DEGRADED = 0x2,
81 TS48060_AMR_FC_SPEECH_BAD = 0x1,
82 TS48060_AMR_FC_NO_SPEECH = 0x0,
83};
84
Harald Welte254b9242020-05-11 08:38:51 +020085/* 16k sub-slots */
86static const ubit_t ft_fr_up_bits[5] = { 0, 0, 0, 1, 0 };
87static const ubit_t ft_fr_down_bits[5] = { 1, 1, 1, 0, 0 };
88static const ubit_t ft_data_up_bits[5] = { 0, 1, 0, 0, 0 };
89static const ubit_t ft_data_down_bits[5] = { 1, 0, 1, 1, 0 };
90static const ubit_t ft_idle_up_bits[5] = { 1, 0, 0, 0, 0 };
91static const ubit_t ft_idle_down_bits[5] = { 0, 1, 1, 1, 0 };
92static const ubit_t ft_efr_bits[5] = { 1, 1, 0, 1, 0 };
93static const ubit_t ft_amr_bits[5] = { 0, 0, 1, 1, 0 };
94static const ubit_t ft_oam_up_bits[5] = { 0, 0, 1, 0, 1 };
95static const ubit_t ft_oam_down_bits[5] = { 1, 1, 0, 1, 1 };
96static const ubit_t ft_d145s_bits[5] = { 1, 0, 1, 0, 0 };
97static const ubit_t ft_edata_bits[5] = { 1, 1, 1, 1, 1 };
98
99/* 8k sub-slots */
100static const ubit_t ft_hr_up_bits[5] = { 0, 0, 0, 1, 1 };
101static const ubit_t ft_hr_down_bits[5] = { 1, 1, 1, 0, 1 };
102static const ubit_t ft_data_hr_up_bits[5] = { 0, 1, 0, 0, 1 };
103static const ubit_t ft_data_hr_down_bits[5] = { 1, 0, 1, 1, 1 };
104
105
106/* generate the sync pattern described in TS 08.60 4.8.1 */
107static void encode_sync16(ubit_t *trau_bits)
108{
109 int i;
110
111 /* 16 '0' bits in header */
112 memset(trau_bits, 0, 16);
113 /* '1'-bit in regular intervals */
114 for (i = 16; i < 40*8; i += 16)
115 trau_bits[i] = 1;
116}
117
118#define T16_500us 8 /* 500 us = 8 bits */
119#define T16_250us 4 /* 250 us = 4 bits */
120
Harald Weltedd9ee982020-08-02 15:53:46 +0200121#define T8_250us 2 /* 250 us = 2 bits */
122#define T8_125us 1 /* 125 us = 1 bits */
123
Harald Welte254b9242020-05-11 08:38:51 +0200124/* How many 16k bits to delay / advance (TS 48.060 Section 5.5.1.1.1) */
Harald Weltedd9ee982020-08-02 15:53:46 +0200125static int trau_frame_16_ta_us(uint8_t c6_11)
Harald Welte254b9242020-05-11 08:38:51 +0200126{
127 if (c6_11 <= 0x27)
Harald Weltedd9ee982020-08-02 15:53:46 +0200128 return c6_11 * 500; /* delay frame N x 500us */
Harald Welte254b9242020-05-11 08:38:51 +0200129 else if (c6_11 == 0x3e)
Harald Weltedd9ee982020-08-02 15:53:46 +0200130 return 250; /* delay frame 250us */
Harald Welte254b9242020-05-11 08:38:51 +0200131 else if (c6_11 == 0x3f)
Harald Weltedd9ee982020-08-02 15:53:46 +0200132 return -250; /* advance frame 250us */
Harald Welte254b9242020-05-11 08:38:51 +0200133 else
134 return 0;
135}
136
Harald Weltedd9ee982020-08-02 15:53:46 +0200137/* How many 8k bits to delay / advance (TS 48.061 Table 6.1) */
138static int trau_frame_8_ta_us(uint8_t c6_8)
139{
140 /* TA2..TA1..TA0 == C6..C7..C8 */
141 switch (c6_8) {
142 case 0x7:
143 return 0;
144 case 0x6:
145 return -250;
146 case 0x5:
147 return 250;
148 case 0x3:
149 return 500;
150 case 0x4:
151 return 1000;
152 case 0x2:
153 return 2000;
154 case 0x1:
155 return 6000;
156 case 0:
157 return 9000;
158 default:
159 return 0;
160 }
161}
162
163/*! Determine the time alignment in us requested by CCU in a UL frame */
164int osmo_trau_frame_dl_ta_us(const struct osmo_trau_frame *fr)
165{
166 uint8_t c6_11, c6_8, fc;
167
168 /* timing alignment is only communicated from CCU to TRAU in UL */
169 if (fr->dir == OSMO_TRAU_DIR_DL)
170 return 0;
171
172 switch (fr->type) {
173 case OSMO_TRAU16_FT_FR:
174 case OSMO_TRAU16_FT_EFR:
175 case OSMO_TRAU16_FT_HR:
176 case OSMO_TRAU16_FT_AMR:
177 c6_11 = (fr->c_bits[5] << 5) | (fr->c_bits[6] << 4) | (fr->c_bits[7] << 3) |
178 (fr->c_bits[8] << 2) | (fr->c_bits[9] << 1) | (fr->c_bits[10] << 0);
179 return trau_frame_16_ta_us(c6_11);
180 break;
181
182 case OSMO_TRAU8_SPEECH:
183 c6_8 = (fr->c_bits[5] << 2) | (fr->c_bits[6] << 1) | (fr->c_bits[7] << 0);
184 return trau_frame_8_ta_us(c6_8);
185 break;
186
187 case OSMO_TRAU8_AMR_LOW:
188 fc = (fr->c_bits[3] << 1) | (fr->c_bits[4] << 0);
189 if (fc == TS48060_AMR_FC_NO_SPEECH) {
190 c6_11 = (fr->c_bits[5] << 5) | (fr->c_bits[6] << 4) | (fr->c_bits[7] << 3) |
191 (fr->c_bits[8] << 2) | (fr->c_bits[9] << 1) | (fr->c_bits[10] << 0);
192 /* For AMR speech on 8 kBit/s submultiplexing the same procedures as for AMR
193 * speech on 16 kBit/s submultiplexing shall be applied, see 3GPP TS 48.060 */
194 return trau_frame_16_ta_us(c6_11);
195 } else
196 return 0;
197 break;
198
199 default:
200 return 0;
201 }
202}
203
204static int encode16_handle_ta(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
205{
206 if (fr->dir == OSMO_TRAU_DIR_DL) {
207 int num_bits = fr->dl_ta_usec * T16_250us / 250;
208 if (num_bits > 0) {
209 if (num_bits > 39 * 8)
210 num_bits = 39;
211 memset(trau_bits + 40 * 8, 1, num_bits);
212 return 40 * 8 + num_bits;
213 } else if (num_bits < 0) {
214 if (num_bits < -1 * T16_250us)
215 num_bits = -1 * T16_250us;
216 return 40 * 8 + num_bits;
217 }
218 }
219 return 40 * 8;
220}
221
222static int encode8_handle_ta(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
223{
224 if (fr->dir == OSMO_TRAU_DIR_DL) {
225 int num_bits = fr->dl_ta_usec * T8_250us / 250;
226 if (num_bits > 0) {
227 if (num_bits > 20 * 8 - 2)
228 num_bits = 20 * 8 - 2;
229 memset(trau_bits + 20 * 8, 1, num_bits);
230 return 20 * 8 + num_bits;
231 } else if (num_bits < 0) {
232 if (num_bits < -1 * T8_250us)
233 num_bits = -2;
234 return 20 * 8 + num_bits;
235 }
236 }
237 return 20 * 8;
238}
239
Harald Welte254b9242020-05-11 08:38:51 +0200240/* TS 08.60 Section 3.1.1 */
241static int encode16_fr(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
242{
243 const ubit_t *cbits5;
244 int i;
245 int d_idx = 0;
246
247 switch (fr->type) {
248 case OSMO_TRAU16_FT_IDLE:
249 if (fr->dir == OSMO_TRAU_DIR_UL)
250 cbits5 = ft_idle_up_bits;
251 else
252 cbits5 = ft_idle_down_bits;
253 break;
254 case OSMO_TRAU16_FT_FR:
255 if (fr->dir == OSMO_TRAU_DIR_UL)
256 cbits5 = ft_fr_up_bits;
257 else
258 cbits5 = ft_fr_down_bits;
259 break;
260 case OSMO_TRAU16_FT_EFR:
261 cbits5 = ft_efr_bits;
262 break;
263 default:
264 return -EINVAL;
265 }
266
267 encode_sync16(trau_bits);
268
269 /* C1 .. C5 */
270 memcpy(trau_bits + 17, cbits5 + 0, 5);
271 /* C6 .. C15 */
272 memcpy(trau_bits + 17 + 5, fr->c_bits + 5, 15 - 5);
273 /* D1 .. D255 */
274 for (i = 32; i < 304; i += 16) {
275 trau_bits[i] = 1;
276 memcpy(trau_bits + i + 1, fr->d_bits + d_idx, 15);
277 d_idx += 15;
278 }
279 /* D256 .. D260 */
280 trau_bits[304] = 1;
281 memcpy(trau_bits + 305, fr->d_bits + d_idx, 5);
282 /* C16 .. C21 */
283 memcpy(trau_bits + 310, fr->c_bits + 15, 6);
284
285 /* T1 .. T4 */
286 memcpy(trau_bits + 316, fr->t_bits+0, 4);
287
288 /* handle timing adjustment */
Harald Weltedd9ee982020-08-02 15:53:46 +0200289 return encode16_handle_ta(trau_bits, fr);
Harald Welte254b9242020-05-11 08:38:51 +0200290}
291
292/* TS 08.60 Section 3.1.1 */
293static int decode16_fr(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
294 enum osmo_trau_frame_direction dir)
295{
296 int i;
297 int d_idx = 0;
298
299 /* C1 .. C15 */
300 memcpy(fr->c_bits + 0, trau_bits + 17, 15);
301 /* C16 .. C21 */
302 memcpy(fr->c_bits + 15, trau_bits + 310, 6);
303 /* T1 .. T4 */
304 memcpy(fr->t_bits + 0, trau_bits + 316, 4);
305 /* D1 .. D255 */
306 for (i = 32; i < 304; i+= 16) {
307 memcpy(fr->d_bits + d_idx, trau_bits + i + 1, 15);
308 d_idx += 15;
309 }
310 /* D256 .. D260 */
311 memcpy(fr->d_bits + d_idx, trau_bits + 305, 5);
312
313 return 0;
314}
315
316/* TS 08.60 Section 3.1.2 */
317static int encode16_amr(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
318{
319 const ubit_t *cbits5 = ft_amr_bits;
320 int i, d_idx;
321
322 encode_sync16(trau_bits);
323
324 /* C1 .. C5 */
325 memcpy(trau_bits + 17, cbits5 + 0, 5);
326 /* C6 .. C15 */
327 memcpy(trau_bits + 17 + 5, fr->c_bits + 5, 15 - 5);
328
329 trau_bits[32] = 1;
330 /* C16 .. C25 */
331 memcpy(trau_bits + 33, fr->c_bits + 15, 10);
332 /* D1 .. D5 */
333 memcpy(trau_bits + 43, fr->d_bits + 0, 5);
334
335 /* D6 .. D256 */
336 for (i = 48, d_idx = 5; i <= 315; i += 16, d_idx += 15) {
337 trau_bits[i] = 1;
338 memcpy(trau_bits + i + 1, fr->d_bits + d_idx, 15);
339 }
340
341 /* T1 .. T4 */
342 memcpy(trau_bits + 316, fr->t_bits + 0, 4);
343
Harald Weltedd9ee982020-08-02 15:53:46 +0200344 return encode16_handle_ta(trau_bits, fr);
345
Harald Welte254b9242020-05-11 08:38:51 +0200346 /* FIXME: handle TAE (Timing Alignment Extension) */
Harald Welte254b9242020-05-11 08:38:51 +0200347}
348
349/* TS 08.60 Section 3.1.2 */
350static int decode16_amr(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
351 enum osmo_trau_frame_direction dir)
352{
353 int i;
354 int d_idx = 0;
355
356 /* C1 .. C15 */
357 memcpy(fr->c_bits + 0, trau_bits + 17, 15);
358 /* C16 .. C25 */
359 memcpy(fr->c_bits + 15, trau_bits + 33, 10);
360 /* T1 .. T4 */
361 memcpy(fr->t_bits + 0, trau_bits + 316, 4);
362 /* D1 .. D5 */
363 memcpy(fr->d_bits, trau_bits + 43, 5);
364 d_idx += 5;
365 /* D6 .. D245 */
366 for (i = 48; i < 304; i += 16) {
367 memcpy(fr->d_bits + d_idx, trau_bits + i + 1, 15);
368 d_idx += 15;
369 }
370 /* D246 .. D256 */
371 memcpy(fr->d_bits + d_idx, trau_bits + 305, 11);
372
373 return 0;
374}
375
376/* TS 08.60 Section 3.2 */
377static int encode16_oam(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
378{
379 const ubit_t *cbits5;
380 int i, d_idx;
381
382 if (fr->dir == OSMO_TRAU_DIR_UL)
383 cbits5 = ft_oam_up_bits;
384 else
385 cbits5 = ft_oam_down_bits;
386
387 encode_sync16(trau_bits);
388
389 /* C1 .. C5 */
390 memcpy(trau_bits + 17, cbits5, 5);
391 /* C6 .. C15 */
392 memcpy(trau_bits + 17 + 5, fr->c_bits, 15 - 5);
393
394 /* D1 .. D255 */
395 for (i = 32, d_idx = 0; i < 304; i += 16, d_idx += 15) {
396 trau_bits[i] = 1;
397 memcpy(trau_bits + i + 1, fr->d_bits + d_idx, 15);
398 }
399 /* D256 .. D264 */
400 memcpy(trau_bits + 305, fr->d_bits + 256, 9);
401
402 /* S1 .. S6 */
403 memcpy(trau_bits + 314, fr->s_bits, 6);
404
405 return 40 * 8;
406}
407
408/* TS 08.60 Section 3.2 */
409static int decode16_oam(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
410 enum osmo_trau_frame_direction dir)
411{
412 int i, d_idx;
413
414 /* C1 .. C15 */
415 memcpy(fr->c_bits + 0, trau_bits + 17, 15);
416
417 /* D1 .. D255 */
418 for (i = 33, d_idx = 0; i < 312; i+= 16, d_idx += 15)
419 memcpy(fr->d_bits + d_idx, trau_bits + i + 1, 15);
420 /* D256 .. D264 */
421 memcpy(fr->d_bits+d_idx, trau_bits + 305, 9);
422
423 /* S1 .. S6 */
424 memcpy(fr->s_bits, trau_bits + 314, 6);
425
426 return 0;
427}
428
429/* TS 08.61 Section 5.1.1.1 */
430static int encode16_hr(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
431{
432 int d_idx = 0;
433 const ubit_t *cbits5;
434
435 if (fr->dir == OSMO_TRAU_DIR_UL)
436 cbits5 = ft_hr_up_bits;
437 else
438 cbits5 = ft_hr_down_bits;
439
440 encode_sync16(trau_bits);
441
442 /* C1 .. C5 */
443 memcpy(trau_bits + 17, cbits5, 5);
444 /* C6 .. C15 */
445 memcpy(trau_bits + 17 + 5, fr->c_bits + 5, 10);
446
447 /* UFI */
448 trau_bits[33] = fr->ufi;
449
450 /* D1 .. D14 */
451 memcpy(trau_bits + 4 * 8 + 2, fr->d_bits+d_idx, 14); d_idx += 14;
452 /* D15 .. D29 */
453 memcpy(trau_bits + 6 * 8 + 1, fr->d_bits+d_idx, 15); d_idx += 15;
454 /* D30 .. D44 */
455 memcpy(trau_bits + 8 * 8 + 1, fr->d_bits+d_idx, 15); d_idx += 15;
456 /* CRC */
457 memcpy(trau_bits + 10 * 8 + 1, fr->crc_bits, 3);
458 /* D45 .. D56 */
459 memcpy(trau_bits + 10 * 8 + 4, fr->d_bits+d_idx, 12); d_idx += 12;
460 /* D57 .. D71 */
461 memcpy(trau_bits + 12 * 8 + 1, fr->d_bits+d_idx, 15); d_idx += 15;
462 /* D72 .. D86 */
463 memcpy(trau_bits + 14 * 8 + 1, fr->d_bits+d_idx, 15); d_idx += 15;
464 /* D87 .. D101 */
465 memcpy(trau_bits + 16 * 8 + 1, fr->d_bits+d_idx, 15); d_idx += 15;
466 /* D102 .. D112 */
467 memcpy(trau_bits + 18 * 8 + 1, fr->d_bits+d_idx, 11); d_idx += 11;
468
469 memset(trau_bits + 19 * 8 + 4, 0x01, 4 + 18 * 8 + 6);
470 /* C16 .. C21 */
471 memcpy(trau_bits + 38 * 8 + 6, fr->c_bits + 15, 6);
472
473 /* T1 .. T4 */
474 memcpy(trau_bits + 39 * 8 + 4, fr->t_bits, 4);
475
476 /* handle timing adjustment */
Harald Weltedd9ee982020-08-02 15:53:46 +0200477 return encode16_handle_ta(trau_bits, fr);
Harald Welte254b9242020-05-11 08:38:51 +0200478}
479
480/* TS 08.61 Section 5.1.1.1 */
481static int decode16_hr(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
482 enum osmo_trau_frame_direction dir)
483{
484 int d_idx = 0;
485
486 /* C1 .. C15 */
487 memcpy(fr->c_bits + 0, trau_bits + 17, 15);
488 /* C16 .. C21 */
489 memcpy(fr->c_bits + 15, trau_bits + 38 * 8 + 6, 6);
490 /* T1 .. T4 */
491 memcpy(fr->t_bits + 0, trau_bits + 39 * 8 + 4, 4);
492
493 /* UFI */
494 fr->ufi = trau_bits[33];
495 /* D1 .. D14 */
496 memcpy(fr->d_bits + d_idx, trau_bits + 4 * 8 + 2, 14); d_idx += 14;
497 /* D15 .. D29 */
498 memcpy(fr->d_bits + d_idx, trau_bits + 6 * 8 + 1, 15); d_idx += 15;
499 /* D30 .. D44 */
500 memcpy(fr->d_bits + d_idx, trau_bits + 8 * 8 + 1, 15); d_idx += 15;
501 /* CRC0..2 */
502 memcpy(fr->crc_bits, trau_bits + 10 * 8 + 1, 3);
503 /* D45 .. D56 */
504 memcpy(fr->d_bits + d_idx, trau_bits + 10 * 8 + 4, 12); d_idx += 12;
505 /* D57 .. D71 */
506 memcpy(fr->d_bits + d_idx, trau_bits + 12 * 8 + 1, 15); d_idx += 15;
507 /* D72 .. D86 */
508 memcpy(fr->d_bits + d_idx, trau_bits + 14 * 8 + 1, 15); d_idx += 15;
509 /* D87 .. D101 */
510 memcpy(fr->d_bits + d_idx, trau_bits + 16 * 8 + 1, 15); d_idx += 15;
511 /* D102 .. D112 */
512 memcpy(fr->d_bits + d_idx, trau_bits + 18 * 8 + 1, 11); d_idx += 11;
513
514 return 0;
515}
516
517static struct osmo_trau_frame fr_idle_frame = {
518 .type = OSMO_TRAU16_FT_IDLE,
519 .dir = OSMO_TRAU_DIR_DL,
520 .t_bits = { 1, 1, 1, 1 },
521};
522#define TRAU_FRAME_BITS (40*8)
523static ubit_t encoded_idle_frame[TRAU_FRAME_BITS];
524static int dbits_initted = 0;
525
526/*! \brief return pointer to global buffer containing a TRAU idle frame */
527static ubit_t *trau_idle_frame(void)
528{
529 /* only initialize during the first call */
530 if (!dbits_initted) {
531 /* set all D-bits to 1 */
532 memset(&fr_idle_frame.d_bits, 0x01, 260);
533
534 memset(&fr_idle_frame.c_bits, 0x01, 25); /* spare are set to 1 */
535 /* set Downlink Idle Speech Frame pattern */
536 fr_idle_frame.c_bits[0] = 0; /* C1 */
537 fr_idle_frame.c_bits[1] = 1; /* C2 */
538 fr_idle_frame.c_bits[2] = 1; /* C3 */
539 fr_idle_frame.c_bits[3] = 1; /* C4 */
540 fr_idle_frame.c_bits[4] = 0; /* C5 */
541 /* set no Time Alignment pattern */
542 fr_idle_frame.c_bits[5] = 0; /* C6 */
543 fr_idle_frame.c_bits[6] = 0; /* C7 */
544 fr_idle_frame.c_bits[7] = 0; /* C8 */
545 fr_idle_frame.c_bits[8] = 0; /* C9 */
546 fr_idle_frame.c_bits[9] = 0; /* C10 */
547 fr_idle_frame.c_bits[10] = 0; /* C11 */
548 /* already set to 1, but maybe we need to modify it in the future */
549 fr_idle_frame.c_bits[11] = 1; /* C12 (UFE), good frame */
550 fr_idle_frame.c_bits[15] = 1; /* C16 (SP), no DTX */
551
552 encode16_fr(encoded_idle_frame, &fr_idle_frame);
553 dbits_initted = 1; /* set it to 1 to not call it again */
554 }
555 return encoded_idle_frame;
556}
557
558/* TS 08.60 Section 3.4 */
559static int encode16_idle(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
560{
561 memcpy(trau_bits, trau_idle_frame(), 40*8);
562 return 40 * 8;
563}
564
565/* TS 08.60 Section 3.3.1 */
566static int decode16_data(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
567 enum osmo_trau_frame_direction dir)
568{
569 int i, d_idx = 0;
570
571 /* C1 .. C15 */
572 memcpy(fr->c_bits + 0, trau_bits + 17, 15);
573
574 /* D1 .. D63 */
575 for (i = 0; i < 9; i++) {
576 memcpy(fr->d_bits + d_idx, trau_bits + (4 + i) * 8 + 1, 7);
577 d_idx += 7;
578 }
579 /* D64 .. D126 */
580 for (i = 0; i < 9; i++) {
581 memcpy(fr->d_bits + d_idx, trau_bits + (13 + i) * 8 + 1, 7);
582 d_idx += 7;
583 }
584
585 /* D127 .. D189 */
586 for (i = 0; i < 9; i++) {
587 memcpy(fr->d_bits + d_idx, trau_bits + (22 + i) * 8 + 1, 7);
588 d_idx += 7;
589 }
590
591 /* D190 .. D252 */
592 for (i = 0; i < 9; i++) {
593 memcpy(fr->d_bits + d_idx, trau_bits + (31 + i) * 8 + 1, 7);
594 d_idx += 7;
595 }
596
597 return 0;
598}
599
600/* TS 08.60 Section 3.3.1 */
601static int encode16_data(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
602{
603 const ubit_t *cbits5;
604 int i, d_idx = 0;
605
606 if (fr->dir == OSMO_TRAU_DIR_UL)
607 cbits5 = ft_data_up_bits;
608 else
609 cbits5 = ft_data_down_bits;
610
611 encode_sync16(trau_bits);
612
613 /* C1 .. C5 */
614 memcpy(trau_bits + 17, cbits5, 5);
615 /* C6 .. C15 */
616 memcpy(trau_bits + 17 + 5, fr->c_bits + 5, 15 - 5);
617
618 /* D1 .. D63 */
619 for (i = 0; i < 9; i++) {
620 unsigned int offset = (4 + i) * 8;
621 trau_bits[offset] = 1;
622 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
623 d_idx += 7;
624 }
625
626 /* D64 .. D126 */
627 for (i = 0; i < 9; i++) {
628 unsigned int offset = (13 + i) * 8;
629 trau_bits[offset] = 1;
630 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
631 d_idx += 7;
632 }
633
634 /* D127 .. D189 */
635 for (i = 0; i < 9; i++) {
636 unsigned int offset = (22 + i) * 8;
637 trau_bits[offset] = 1;
638 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
639 d_idx += 7;
640 }
641
642 /* D190 .. D252 */
643 for (i = 0; i < 9; i++) {
644 unsigned int offset = (31 + i) * 8;
645 trau_bits[offset] = 1;
646 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
647 d_idx += 7;
648 }
649
650 return 40 * 8;
651}
652
653/* TS 08.60 3.3.2 */
654static int decode16_edata(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
655 enum osmo_trau_frame_direction dir)
656{
657 /* C1 .. C13 */
658 memcpy(fr->c_bits, trau_bits + 17, 13);
659
660 /* M1 .. M2 */
661 memcpy(fr->m_bits, trau_bits + 30, 2);
662
663 /* D1 .. D288 */
664 memcpy(fr->d_bits, trau_bits + 4 * 8, 288);
665
666 return 0;
667}
668
669/* TS 08.60 Section 3.3.2 */
670static int encode16_edata(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
671{
672 const ubit_t *cbits5;
673
674 if (fr->type == OSMO_TRAU16_FT_D145_SYNC)
675 cbits5 = ft_d145s_bits;
676 else
677 cbits5 = ft_edata_bits;
678
679 /* C1 .. C5 */
680 memcpy(trau_bits + 17, cbits5, 5);
681
682 /* C6 .. C13 */
683 memcpy(trau_bits + 17 + 5, fr->c_bits + 5, 8);
684
685 /* M1 .. M2 */
686 memcpy(trau_bits + 30, fr->m_bits, 2);
687
688 /* D1 .. D288 */
689 memcpy(trau_bits + 4 * 8, fr->d_bits, 288);
690
691 return 40 * 8;
692}
693
694/* TS 08.61 Section 5.1.2 */
695static int decode16_data_hr(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
696 enum osmo_trau_frame_direction dir)
697{
698 int i, d_idx = 0;
699
700 /* C1 .. C15 */
701 memcpy(fr->c_bits+0, trau_bits + 17, 15);
702
703 /* D1 .. D63 */
704 for (i = 0; i < 9; i++) {
705 memcpy(fr->d_bits + d_idx, trau_bits + (4 + i) * 8 + 1, 7);
706 d_idx += 7;
707 }
708
709 /* D'1 .. D'63 (mapped to D64..D127) */
710 for (i = 0; i < 9; i++) {
711 memcpy(fr->d_bits + d_idx, trau_bits + (22 + i) * 8 + 1, 7);
712 d_idx += 7;
713 }
714
715 return 0;
716}
717
718/* TS 08.61 Section 5.1.2 */
719static int encode16_data_hr(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
720{
721 const ubit_t *cbits5;
722 int i, d_idx = 0;
723
724 if (fr->dir == OSMO_TRAU_DIR_UL)
725 cbits5 = ft_data_hr_up_bits;
726 else
727 cbits5 = ft_data_hr_down_bits;
728
729 encode_sync16(trau_bits);
730
731 /* C1 .. C5 */
732 memcpy(trau_bits + 17, cbits5, 5);
733 /* C6 .. C15 */
734 memcpy(trau_bits + 17 + 5, fr->c_bits + 5, 15 - 5);
735
736 /* D1 .. D63 */
737 for (i = 4; i < 4 + 9; i++) {
738 unsigned int offset = i * 8;
739 trau_bits[offset] = 1;
740 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
741 d_idx += 7;
742 }
743
744 memset(trau_bits + 13*8, 1, 9*8);
745
746 /* D'1 .. D'63 (mapped to D64..D127) */
747 for (i = 22; i < 22 + 9; i++) {
748 unsigned int offset = i * 8;
749 trau_bits[offset] = 1;
750 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
751 d_idx += 7;
752 }
753
754 memset(trau_bits + 31*8, 1, 9*8);
755
756 return 40 * 8;
757}
758
759/* TS 08.61 Section 5.2.1.1 */
760static int decode8_hr(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
761 enum osmo_trau_frame_direction dir)
762{
763 int i, d_idx = 0;
764
765 /* C1 .. C5 */
766 memcpy(fr->c_bits, trau_bits + 9, 5);
767 /* XC1 .. XC2 */
768 memcpy(fr->xc_bits, trau_bits + 8 + 6, 2);
769 /* XC3 .. XC6 */
770 memcpy(fr->xc_bits + 2, trau_bits + 2 * 8 + 2, 4);
771 /* D1 .. D2 */
772 memcpy(fr->d_bits + d_idx, trau_bits + 2 * 8 + 6, 2);
773 d_idx += 2;
774
775 /* D1 .. D44 */
776 for (i = 3; i < 3 + 6; i++) {
777 int offset = i * 8;
778 memcpy(fr->d_bits + d_idx, trau_bits + offset + 1, 7);
779 d_idx += 7;
780 }
781
782 /* CRC0 .. CRC2 */
783 fr->crc_bits[2] = trau_bits[82];
784 fr->crc_bits[1] = trau_bits[83];
785 fr->crc_bits[0] = trau_bits[84];
786
787 /* D45 .. D48 */
788 memcpy(fr->d_bits + d_idx, trau_bits + 85, 4);
789
790 /* D49 .. D111 */
791 for (i = 10; i < 10 + 10; i++) {
792 int offset = i * 8;
793 memcpy(fr->d_bits + d_idx, trau_bits + offset + 1, 7);
794 d_idx += 7;
795 }
796 /* D112 */
797 fr->d_bits[d_idx++] = trau_bits[19 * 8 + 1];
798
799 /* C6 .. C9 */
800 memcpy(fr->c_bits + 5, trau_bits + 19 * 8 + 2, 4);
801
802 /* T1 .. T2 */
803 fr->t_bits[0] = trau_bits[19 * 8 + 6];
804 fr->t_bits[1] = trau_bits[19 * 8 + 7];
805
806 return 0;
807}
808
809/* compute the odd parity bit of the given input bit sequence */
810static ubit_t compute_odd_parity(const ubit_t *in, unsigned int num_bits)
811{
812 int i;
813 unsigned int sum = 0;
814
815 for (i = 0; i < num_bits; i++) {
816 if (in[i])
817 sum++;
818 }
819
Harald Welte1f310f72020-08-06 11:54:39 +0200820 if (sum & 1)
Harald Welte254b9242020-05-11 08:38:51 +0200821 return 0;
822 else
823 return 1;
824}
825
826/* TS 08.61 Section 5.2.1.1 */
827static int encode8_hr(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
828{
829 int i, d_idx = 0;
830
831 /* sync pattern */
832 memset(trau_bits, 0, 8);
833 trau_bits[8] = 1;
834 trau_bits[16] = 0;
835 trau_bits[17] = 1;
836 for (i = 3; i < 20; i++)
837 trau_bits[i * 8] = 1;
838
839 /* C1 .. C5 */
840 ubit_t *cbits_out = trau_bits + 1 * 8 + 1;
841 if (fr->dir == OSMO_TRAU_DIR_UL) {
842 cbits_out[0] = 0;
843 cbits_out[1] = 0;
844 cbits_out[2] = 0;
845 cbits_out[3] = 1;
846 cbits_out[4] = 1;
847 } else {
848 cbits_out[0] = 0;
849 cbits_out[1] = 0;
850 cbits_out[2] = 0;
851 cbits_out[3] = fr->c_bits[3];
852 cbits_out[4] = compute_odd_parity(cbits_out, 4);
853 }
854
855 /* XC1 .. XC2 */
856 memcpy(trau_bits + 1 * 8 + 6, fr->xc_bits, 2);
857 /* XC3 .. XC6 */
858 memcpy(trau_bits + 2 * 8 + 2, fr->xc_bits, 4);
859 /* D1 .. D2 */
860 memcpy(trau_bits + 2 * 8 + 6, fr->d_bits, 2);
861 d_idx += 2;
862
863 /* D1 .. D44 */
864 for (i = 3; i < 3 + 6; i++) {
865 int offset = i * 8;
866 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
867 d_idx += 7;
868 };
869
870 /* CRC0 .. CRC2 */
871 trau_bits[82] = fr->crc_bits[2];
872 trau_bits[83] = fr->crc_bits[1];
873 trau_bits[84] = fr->crc_bits[0];
874
875 /* D49 .. D111 */
876 for (i = 10; i < 10 + 10; i++) {
877 int offset = i * 8;
878 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
879 d_idx += 7;
880 }
881 /* D112 */
882 trau_bits[19 * 8 + 1] = fr->d_bits[d_idx++];
883
884 /* C6 .. C9 */
885 memcpy(trau_bits + 19 * 8 + 2, fr->c_bits + 5, 4);
886
Harald Welte254b9242020-05-11 08:38:51 +0200887 /* T1 .. T2 */
888 trau_bits[19 * 8 + 6] = fr->t_bits[0];
889 trau_bits[19 * 8 + 7] = fr->t_bits[1];
890
Harald Weltedd9ee982020-08-02 15:53:46 +0200891 /* handle timing adjustment */
892 return encode8_handle_ta(trau_bits, fr);
Harald Welte254b9242020-05-11 08:38:51 +0200893}
894
895/* TS 08.61 Section 5.2.1.2.1 */
896static int decode8_amr_low(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
897 enum osmo_trau_frame_direction dir)
898{
899 int i, d_idx = 0;
900
901 /* D1 .. D7 */
902 memcpy(fr->d_bits + d_idx, trau_bits + 1 * 8 + 1, 7);
903 d_idx += 7;
904 /* C1 .. C5 */
905 memcpy(fr->c_bits, trau_bits + 2 * 8 + 1, 5);
906 /* D8 .. D9 */
907 memcpy(fr->d_bits + d_idx, trau_bits + 2 * 8 + 6, 2);
908 d_idx += 2;
909 /* D10 .. D15 */
910 memcpy(fr->d_bits + d_idx, trau_bits + 3 * 8 + 2, 6);
911 d_idx += 6;
912 /* D16 .. D120 */
913 for (i = 4; i < 19; i++) {
914 int offset = i * 8;
915 memcpy(fr->d_bits + d_idx, trau_bits + offset + 1, 7);
916 d_idx += 7;
917 }
918 /* D121 .. D126 */
919 memcpy(fr->d_bits + d_idx, trau_bits + 19 * 8 + 1, 6);
920 d_idx += 6;
921
922 /* T1 */
923 fr->t_bits[0] = trau_bits[19 * 8 + 7];
924
925 return 0;
926}
927
928/* TS 08.61 Section 5.2.1.2.1 */
929static int encode8_amr_low(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
930{
931 int i, d_idx = 0;
932
933 /* sync pattern */
934 memset(trau_bits, 0, 8);
935 trau_bits[8] = 1;
936 trau_bits[16] = 1;
937 trau_bits[24] = 0;
938 trau_bits[25] = 1;
939 for (i = 4; i < 20; i++)
940 trau_bits[i * 8] = 1;
941
942 /* D1 .. D7 */
943 memcpy(trau_bits + 1 * 8 + 1, fr->d_bits + d_idx, 7);
944 d_idx += 7;
945 /* C1 .. C5 */
946 memcpy(trau_bits + 2 * 8 + 1, fr->c_bits, 5);
947 /* D8 .. D9 */
948 memcpy(trau_bits + 2 * 8 + 6, fr->d_bits + d_idx, 2);
949 d_idx += 2;
950 /* D10 .. D15 */
951 memcpy(trau_bits + 3 * 8 + 2, fr->d_bits + d_idx, 6);
952 d_idx += 6;
953 /* D16 .. D120 */
954 for (i = 4; i < 19; i++) {
955 int offset = i * 8;
956 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 7);
957 d_idx += 7;
958 }
959 /* D121 .. D126 */
960 memcpy(trau_bits + 19 * 8 + 1, fr->d_bits + d_idx, 6);
961 d_idx += 6;
962
963 /* T1 */
964 trau_bits[19 * 8 + 7] = fr->t_bits[0];
965
Harald Weltedd9ee982020-08-02 15:53:46 +0200966 return encode8_handle_ta(trau_bits, fr);
Harald Welte254b9242020-05-11 08:38:51 +0200967}
968
969/* TS 08.61 Section 5.2.1.2.2 */
970static int decode8_amr_67(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
971 enum osmo_trau_frame_direction dir)
972{
973 int i, d_idx = 0;
974
975 /* D1 .. D7 */
976 memcpy(fr->d_bits + d_idx, trau_bits + 1 * 8 + 1, 7);
977 d_idx += 7;
978 /* C1 .. C3 */
979 memcpy(fr->c_bits, trau_bits + 2 * 8 + 1, 3);
980 /* D8 .. D11 */
981 memcpy(fr->d_bits + d_idx, trau_bits + 2 * 8 + 4, 4);
982 d_idx += 4;
983 /* D12 .. D39 */
984 for (i = 3; i < 7; i++) {
985 int offset = i * 8;
986 memcpy(fr->d_bits + d_idx, trau_bits + offset + 2, 7);
987 d_idx += 7;
988 }
989
990 /* D40 .. D137 */
991 for (i = 7; i < 20; i+= 2) {
992 int offset = i * 8;
993 memcpy(fr->d_bits + d_idx, trau_bits + offset + 1, 15);
994 d_idx += 15;
995 }
996
997 return 0;
998}
999
1000/* TS 08.61 Section 5.1.2.2 */
1001static int encode8_amr_67(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
1002{
1003 int i, d_idx = 0;
1004
1005 /* sync pattern */
1006 memset(trau_bits, 0, 8);
1007 trau_bits[1 * 8] = 1;
1008 trau_bits[2 * 8] = 1;
1009 trau_bits[3 * 8] = 1;
1010 trau_bits[4 * 8] = 1;
1011 trau_bits[5 * 8] = 0;
1012 for (i = 5; i < 20; i += 2)
1013 trau_bits[i * 8] = 1;
1014
1015 /* D1 .. D7 */
1016 memcpy(trau_bits + 1 * 8 + 1, fr->d_bits + d_idx, 7);
1017 d_idx += 7;
1018 /* C1 .. C3 */
1019 memcpy(trau_bits + 2 * 8 + 1, fr->c_bits, 3);
1020 /* D8 .. D11 */
1021 memcpy(trau_bits + 2 * 8 + 4, fr->d_bits + d_idx, 4);
1022 d_idx += 4;
1023 /* D12 .. D39 */
1024 for (i = 3; i < 7; i++) {
1025 int offset = i * 8;
1026 memcpy(trau_bits + offset + 2, fr->d_bits + d_idx, 7);
1027 d_idx += 7;
1028 }
1029
1030 /* D40 .. D137 */
1031 for (i = 7; i < 20; i+= 2) {
1032 int offset = i * 8;
1033 memcpy(trau_bits + offset + 1, fr->d_bits + d_idx, 15);
1034 d_idx += 15;
1035 }
1036
Harald Weltedd9ee982020-08-02 15:53:46 +02001037 return encode8_handle_ta(trau_bits, fr);
Harald Welte254b9242020-05-11 08:38:51 +02001038}
1039
1040/* TS 08.61 Section 5.1.2.3 */
1041static int decode8_amr_74(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
1042 enum osmo_trau_frame_direction dir)
1043{
1044 int d_idx = 0;
1045
1046 /* D1 .. D5 */
1047 memcpy(fr->d_bits + d_idx, trau_bits + 3, 5);
1048 d_idx += 5;
1049 /* D6 .. D12 */
1050 memcpy(fr->d_bits + d_idx, trau_bits + 1 * 8 + 1, 7);
1051 d_idx += 7;
1052 /* C1.. C3 */
1053 memcpy(fr->c_bits, trau_bits + 2 * 8 + 1, 3);
1054 /* D13 .. D16 */
1055 memcpy(fr->d_bits + d_idx, trau_bits + 2 * 8 + 4, 4);
1056 d_idx += 4;
1057 /* D17 .. D23 */
1058 memcpy(fr->d_bits + d_idx, trau_bits + 3 * 8 + 1, 7);
1059 d_idx += 7;
1060 /* D24 .. D151 */
1061 memcpy(fr->d_bits + d_idx, trau_bits + 4 * 8, 16 * 8);
1062
1063 return 0;
1064}
1065
1066/* TS 08.61 Section 5.1.2.3 */
1067static int encode8_amr_74(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
1068{
1069 int d_idx = 0;
1070
1071 /* sync pattern */
1072 trau_bits[0] = 0;
1073 trau_bits[1] = 0;
1074 trau_bits[2] = 1;
1075 trau_bits[1*8] = 0;
1076 trau_bits[2*8] = 1;
1077 trau_bits[3*8] = 0;
1078
1079 /* D1 .. D5 */
1080 memcpy(trau_bits + 3, fr->d_bits + d_idx, 5);
1081 d_idx += 5;
1082 /* D6 .. D12 */
1083 memcpy(trau_bits + 1 * 8 + 1, fr->d_bits + d_idx, 7);
1084 d_idx += 7;
1085 /* C1.. C3 */
1086 memcpy(trau_bits + 2 * 8 + 1, fr->c_bits, 3);
1087 /* D13 .. D16 */
1088 memcpy(trau_bits + 2 * 8 + 4, fr->d_bits + d_idx, 4);
1089 d_idx += 4;
1090 /* D17 .. D23 */
1091 memcpy(trau_bits + 3 * 8 + 1, fr->d_bits + d_idx, 7);
1092 d_idx += 7;
1093 /* D24 .. D151 */
1094 memcpy(trau_bits + 4 * 8, fr->d_bits + d_idx, 16 * 8);
1095
Harald Weltedd9ee982020-08-02 15:53:46 +02001096 return encode8_handle_ta(trau_bits, fr);
Harald Welte254b9242020-05-11 08:38:51 +02001097}
1098
1099/* TS 08.61 Section 5.2.2 */
1100static int decode8_data(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
1101 enum osmo_trau_frame_direction dir)
1102{
1103 int i, d_idx = 0;
1104
1105 /* C1 .. C5 */
1106 memcpy(fr->c_bits, trau_bits + 1 * 8 + 1, 5);
1107 /* D1 .. D2 */
1108 memcpy(fr->d_bits + d_idx, trau_bits + 1 * 8 + 6, 2);
1109 d_idx += 2;
1110 /* D3 .. D8 */
1111 memcpy(fr->d_bits + d_idx, trau_bits + 2 * 8 + 2, 6);
1112 /* D9 .. D57 + D'1 .. D'57 */
1113 for (i = 3; i < 20; i++) {
1114 memcpy(fr->d_bits + d_idx, trau_bits + i * 8 + 1, 7);
1115 d_idx += 7;
1116 }
1117 /* D'58 .. D'62 */
1118 memcpy(fr->d_bits + d_idx, trau_bits + 19 * 8 + 1, 6);
1119 d_idx += 6;
1120
1121 return 0;
1122}
1123
1124/* TS 08.61 Section 5.2.2 */
1125static int encode8_data(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
1126{
1127 int i, d_idx = 0;
1128
1129 /* sync pattern */
1130 memset(trau_bits, 0, 8);
1131 trau_bits[1 * 8] = 1;
1132 trau_bits[2 * 8] = 0;
1133 trau_bits[2 * 8 + 1] = 1;
1134 for (i = 3; i < 19; i++)
1135 trau_bits[i * 8] = 1;
1136 trau_bits[19 * 8 + 7] = 1;
1137
1138 /* C1 .. C5 */
1139 memcpy(trau_bits + 1 * 8 + 1, fr->c_bits, 5);
1140 /* D1 .. D2 */
1141 memcpy(trau_bits + 1 * 8 + 6, fr->d_bits + d_idx, 2);
1142 d_idx += 2;
1143 /* D3 .. D8 */
1144 memcpy(trau_bits + 2 * 8 + 2, fr->d_bits + d_idx, 6);
1145 /* D9 .. D57 + D'1 .. D'57 */
1146 for (i = 3; i < 20; i++) {
1147 memcpy(trau_bits + i * 8 + 1, fr->d_bits + d_idx, 7);
1148 d_idx += 7;
1149 }
1150 /* D'58 .. D'62 */
1151 memcpy(trau_bits + 19 * 8 + 1, fr->d_bits + d_idx, 6);
1152 d_idx += 6;
1153
1154 return 20 * 8;
1155}
1156
1157/* TS 08.61 Section 5.2.3 */
1158static int decode8_oam(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
1159 enum osmo_trau_frame_direction dir)
1160{
1161 int i, d_idx = 0;
1162
1163 /* C1 .. C5 */
1164 memcpy(fr->c_bits, trau_bits + 1 * 8 + 1, 5);
1165 /* XC1 .. XC2 */
1166 memcpy(fr->xc_bits, trau_bits + 1 * 8 + 6, 2);
1167 /* XC3 .. XC6 */
1168 memcpy(fr->xc_bits + 2, trau_bits + 2 * 8 + 2, 4);
1169 /* D1 .. D2 */
1170 memcpy(fr->d_bits + d_idx, trau_bits + 2 * 8 + 6, 2);
1171 d_idx += 2;
1172 /* D3 .. D114 */
1173 for (i = 3; i < 19; i++) {
1174 memcpy(fr->d_bits + d_idx, trau_bits + i * 8 + 1, 7);
1175 d_idx += 7;
1176 }
1177 /* D115 .. D120 */
1178 memcpy(fr->d_bits + d_idx, trau_bits + 19 * 8 + 1, 6);
1179 d_idx += 7;
1180
1181 return 0;
1182}
1183
1184/* TS 08.61 Section 5.2.3 */
1185static int encode8_oam(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
1186{
1187 int i, d_idx = 0;
1188
1189 /* sync pattern */
1190 memset(trau_bits, 0, 8);
1191 trau_bits[1 * 8 + 0] = 1;
1192 trau_bits[2 * 8 + 0] = 0;
1193 trau_bits[2 * 8 + 1] = 1;
1194 for (i = 3; i < 20; i++)
1195 trau_bits[i * 8] = 1;
1196
1197 /* C1 .. C5 */
1198 memcpy(trau_bits + 1 * 8 + 1, fr->c_bits, 5);
1199 /* XC1 .. XC2 */
1200 memcpy(trau_bits + 1 * 8 + 6, fr->xc_bits, 2);
1201 /* XC3 .. XC6 */
1202 memcpy(trau_bits + 2 * 8 + 2, fr->xc_bits + 2, 4);
1203 /* D1 .. D2 */
1204 memcpy(trau_bits + 2 * 8 + 6, fr->d_bits + d_idx, 2);
1205 d_idx += 2;
1206 /* D3 .. D114 */
1207 for (i = 3; i < 19; i++) {
1208 memcpy(trau_bits + i * 8 + 1, fr->d_bits + d_idx, 7);
1209 d_idx += 7;
1210 }
1211 /* D115 .. D120 */
1212 memcpy(trau_bits + 19 * 8 + 1, fr->d_bits + d_idx, 6);
1213 d_idx += 7;
1214
1215 return 20 * 8;
1216}
1217
1218
1219/*! Encode a TRAU frame from its decoded representation to a sequence of unpacked bits.
1220 * \param[out] bits caller-allocated buffer for unpacked outpud bits
1221 * \param[in] n_bits size of 'bits' oputput buffer in number of unpacked bits
1222 * \param[in] fr decoded representation of TRAU frame to be encoded
1223 * \return 0 number of unpacked output bits generated; negative in case of error */
1224int osmo_trau_frame_encode(ubit_t *bits, size_t n_bits, const struct osmo_trau_frame *fr)
1225{
Harald Welte95e2dfb2020-08-02 16:01:14 +02001226 /* check for sufficient space provided by caller in output buffer */
1227 switch (fr->type) {
1228 case OSMO_TRAU16_FT_FR:
1229 case OSMO_TRAU16_FT_EFR:
1230 case OSMO_TRAU16_FT_HR:
1231 case OSMO_TRAU16_FT_AMR:
1232 /* timing alignment may happen: increased space requirement */
1233 if (n_bits < 2 * 40 * 8 - 1)
1234 return -ENOSPC;
1235 break;
1236 case OSMO_TRAU16_FT_OAM:
1237 case OSMO_TRAU16_FT_IDLE:
1238 case OSMO_TRAU16_FT_DATA_HR:
1239 case OSMO_TRAU16_FT_DATA:
1240 case OSMO_TRAU16_FT_D145_SYNC:
1241 case OSMO_TRAU16_FT_EDATA:
1242 if (n_bits < 1 * 40 * 8)
1243 return -ENOSPC;
1244 break;
1245 case OSMO_TRAU8_SPEECH:
1246 case OSMO_TRAU8_AMR_LOW:
1247 case OSMO_TRAU8_AMR_6k7:
1248 case OSMO_TRAU8_AMR_7k4:
1249 /* timing alignment may happen: increased space requirement */
1250 if (n_bits < 2 * 20 * 8 - 1)
1251 return -ENOSPC;
Harald Welte2f80b932020-08-06 11:57:50 +02001252 break;
Harald Welte95e2dfb2020-08-02 16:01:14 +02001253 case OSMO_TRAU8_DATA:
1254 case OSMO_TRAU8_OAM:
1255 if (n_bits < 1 * 20 * 8)
1256 return -ENOSPC;
1257 break;
1258 case OSMO_TRAU_FT_NONE:
1259 break;
1260 default:
1261 return -EINVAL;
1262 }
1263
Harald Welte254b9242020-05-11 08:38:51 +02001264 switch (fr->type) {
1265 case OSMO_TRAU16_FT_FR:
1266 case OSMO_TRAU16_FT_EFR:
1267 return encode16_fr(bits, fr);
1268 case OSMO_TRAU16_FT_HR:
1269 return encode16_hr(bits, fr);
1270 case OSMO_TRAU16_FT_AMR:
1271 return encode16_amr(bits, fr);
1272 case OSMO_TRAU16_FT_OAM:
1273 return encode16_oam(bits, fr);
1274 case OSMO_TRAU16_FT_IDLE:
1275 return encode16_idle(bits, fr);
1276 case OSMO_TRAU16_FT_DATA_HR:
1277 return encode16_data_hr(bits, fr);
1278 case OSMO_TRAU16_FT_DATA:
1279 return encode16_data(bits, fr);
1280 case OSMO_TRAU16_FT_D145_SYNC:
1281 case OSMO_TRAU16_FT_EDATA:
1282 return encode16_edata(bits, fr);
1283 case OSMO_TRAU8_SPEECH:
1284 return encode8_hr(bits, fr);
1285 case OSMO_TRAU8_DATA:
1286 return encode8_data(bits, fr);
1287 case OSMO_TRAU8_OAM:
1288 return encode8_oam(bits, fr);
1289 case OSMO_TRAU8_AMR_LOW:
1290 return encode8_amr_low(bits, fr);
1291 case OSMO_TRAU8_AMR_6k7:
1292 return encode8_amr_67(bits, fr);
1293 case OSMO_TRAU8_AMR_7k4:
1294 return encode8_amr_74(bits, fr);
1295 case OSMO_TRAU_FT_NONE:
1296 default:
1297 return -EINVAL;
1298 }
1299}
1300
1301/*! Decode/parse a 16k TRAU frame from unpacked bits to decoded format.
1302 * \param[out] fr caller-allocated output data structure
1303 * \param[in] bits unpacked bits containing raw TRAU frame; must be aligned
1304 * \param[in] dir direction (uplink/downlink)
1305 * \returns 0 in case of success; negative on error */
1306int osmo_trau_frame_decode_16k(struct osmo_trau_frame *fr, const ubit_t *bits,
1307 enum osmo_trau_frame_direction dir)
1308{
1309 uint8_t cbits5 = get_bits(bits, 17, 5);
1310
1311 fr->type = OSMO_TRAU_FT_NONE;
1312 fr->dir = dir;
Harald Weltedd9ee982020-08-02 15:53:46 +02001313 fr->dl_ta_usec = 0;
Harald Welte254b9242020-05-11 08:38:51 +02001314
1315 switch (cbits5) {
1316 case TRAU_FT_FR_UP:
1317 case TRAU_FT_FR_DOWN:
1318 fr->type = OSMO_TRAU16_FT_FR;
1319 return decode16_fr(fr, bits, dir);
1320 case TRAU_FT_IDLE_UP:
1321 case TRAU_FT_IDLE_DOWN:
1322 fr->type = OSMO_TRAU16_FT_IDLE;
1323 return decode16_fr(fr, bits, dir);
1324 case TRAU_FT_EFR:
1325 fr->type = OSMO_TRAU16_FT_EFR;
1326 return decode16_fr(fr, bits, dir);
1327 case TRAU_FT_AMR:
1328 fr->type = OSMO_TRAU16_FT_AMR;
1329 return decode16_amr(fr, bits, dir);
1330 case TRAU_FT_OM_UP:
1331 case TRAU_FT_OM_DOWN:
1332 fr->type = OSMO_TRAU16_FT_OAM;
1333 return decode16_oam(fr, bits, dir);
1334 case TRAU_FT_DATA_UP:
1335 case TRAU_FT_DATA_DOWN:
1336 fr->type = OSMO_TRAU16_FT_DATA;
1337 return decode16_data(fr, bits, dir);
1338 case TRAU_FT_HR_UP:
1339 case TRAU_FT_HR_DOWN:
1340 fr->type = OSMO_TRAU16_FT_HR;
1341 return decode16_hr(fr, bits, dir);
1342 case TRAU_FT_DATA_UP_HR:
1343 case TRAU_FT_DATA_DOWN_HR:
1344 fr->type = OSMO_TRAU16_FT_DATA_HR;
1345 return decode16_data_hr(fr, bits, dir);
1346 case TRAU_FT_EDATA:
1347 fr->type = OSMO_TRAU16_FT_EDATA;
1348 return decode16_edata(fr, bits, dir);
1349 case TRAU_FT_D145_SYNC:
1350 fr->type = OSMO_TRAU16_FT_D145_SYNC;
1351 return decode16_edata(fr, bits, dir);
1352
1353 default:
1354 return -EINVAL;
1355 }
1356}
1357
1358#define TRAU8_FT_AMR_NO_SPEECH_CMI 0x10 /* 1, 0, 0, 0, 0 */
1359#define TRAU8_FT_AMR_NO_SPEECH_CMR 0x14 /* 1, 0, 1, 0, 0 */
1360#define TRAU8_FT_AMR_475_515_590 0..7
1361
1362const uint8_t bit8_0[16] = { 0, };
1363
1364/*!< check sync pattern for hr/data/oam */
1365static bool is_hr(const ubit_t *bits)
1366{
1367 int i;
1368
1369 /* TS 08.61 Section 6.8.2.1.1 */
1370 if (memcmp(bits, bit8_0, sizeof(bit8_0)))
1371 return false;
1372 if (bits[8] != 1)
1373 return false;
1374 if (bits[16] != 0 || bits[17] != 1)
1375 return false;
1376 for (i = 24; i < 20 * 8; i += 16) {
1377 if (bits[i] != 1)
1378 return false;
1379 }
1380 return true;
1381}
1382
1383
1384/*!< check sync pattern for AMR No_Speech + low bit rate */
1385static bool is_amr_low(const ubit_t *bits)
1386{
1387 int i;
1388
1389 /* TS 08.61 Section 6.8.2.1.2 */
1390 if (memcmp(bits, bit8_0, sizeof(bit8_0)))
1391 return false;
1392 if (bits[8] != 1)
1393 return false;
1394 if (bits[16] != 1)
1395 return false;
1396 if (bits[24] != 0 || bits[25] != 1)
1397 return false;
1398 for (i = 32; i < 20 * 8; i += 16) {
1399 if (bits[i] != 1)
1400 return false;
1401 }
1402 return true;
1403}
1404
1405/*!< check sync pattern for AMR 6.7kBit/s */
1406static bool is_amr_67(const ubit_t *bits)
1407{
1408 int i;
1409
1410 /* TS 08.61 Section 6.8.2.1.3 */
1411 if (memcmp(bits, bit8_0, sizeof(bit8_0)))
1412 return false;
1413 if (bits[8] != 1)
1414 return false;
1415 if (bits[16] != 1)
1416 return false;
1417 if (bits[24] != 1)
1418 return false;
1419 if (bits[32] != 1)
1420 return false;
1421 if (bits[40] != 0)
1422 return false;
1423 for (i = 48; i < 20 * 8; i+= 16)
1424 if (bits[i] != 1)
1425 return false;
1426
1427 return true;
1428}
1429
1430/*!< check sync pattern for AMR 7.4kBit/s */
1431static bool is_amr_74(const ubit_t *bits)
1432{
1433 if (bits[0] != 0 || bits[1] != 0 || bits[2] != 0)
1434 return false;
1435 if (bits[8] != 0)
1436 return false;
1437 if (bits[16] != 1)
1438 return false;
1439 if (bits[24] != 0)
1440 return false;
1441
1442 return true;
1443}
1444
1445/*! Decode/parse a 8k TRAU frame from unpacked bits to decoded format.
1446 * \param[out] fr caller-allocated output data structure
1447 * \param[in] bits unpacked bits containing raw TRAU frame; must be aligned
1448 * \param[in] dir direction (uplink/downlink)
1449 * \returns 0 in case of success; negative on error */
1450int osmo_trau_frame_decode_8k(struct osmo_trau_frame *fr, const ubit_t *bits,
1451 enum osmo_trau_frame_direction dir)
1452{
1453 fr->type = OSMO_TRAU_FT_NONE;
1454 fr->dir = dir;
Harald Weltedd9ee982020-08-02 15:53:46 +02001455 fr->dl_ta_usec = 0;
Harald Welte254b9242020-05-11 08:38:51 +02001456
1457 if (is_hr(bits)) {
1458 /* normal sync pattern */
1459 uint8_t cbits5 = get_bits(bits, 9, 5);
1460 if (dir == OSMO_TRAU_DIR_UL) {
1461 switch (cbits5) { /* Section 5.2.4.1.1 */
1462 case 0x02:
1463 return decode8_hr(fr, bits, dir);
1464 case 0x07:
1465 return decode8_data(fr, bits, dir);
1466 case 0x13:
1467 return decode8_oam(fr, bits, dir);
1468 }
1469 } else {
1470 /* Downlink */
1471 switch (cbits5 >> 2) { /* Section 5.2.4.1.2 */
1472 case 0:
1473 return decode8_hr(fr, bits, dir);
1474 case 1:
1475 return decode8_data(fr, bits, dir);
1476 case 2:
1477 return decode8_oam(fr, bits, dir);
1478 }
1479 }
1480 } else if (is_amr_low(bits)) {
1481 return decode8_amr_low(fr, bits, dir);
1482 } else if (is_amr_67(bits)) {
1483 return decode8_amr_67(fr, bits, dir);
1484 } else if (is_amr_74(bits)) {
1485 return decode8_amr_74(fr, bits, dir);
1486 }
1487
1488 return -EINVAL;
1489}
1490
1491/* }@ */