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