blob: b4bc4e30f121a895927bcc9cc5ecdf4b84816217 [file] [log] [blame]
Harald Welte065dab82022-11-29 23:13:06 +01001/* V.110 frames according to ITU-T V.110
2 *
3 * This code implements the following functionality:
4 * - parsing/encoding of osmo_v110_decoded_frame from/to actual 80-bit V.110 frame
5 * - synchronous rate adapting of user bit rate to V.110 D-bits as per Table 6
6 *
7 * It is (at least initially) a very "naive" implementation, as it first and foremost
8 * aims to be functional and correct, rather than efficient in any way. Hence it
9 * operates on unpacked bits (ubit_t, 1 bit per byte), and has various intermediate
10 * representations and indirect function calls. If needed, a more optimized variant
11 * can always be developed later on.
12 */
13
14/* (C) 2022 by Harald Welte <laforge@osmocom.org>
15 *
16 * SPDX-License-Identifier: GPL-2.0+
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 */
28
29#include <stdint.h>
30#include <errno.h>
31
32#include <osmocom/core/bits.h>
33
34#include <osmocom/isdn/v110.h>
35
36/*************************************************************************
37 * V.110 frame decoding/encoding (ubits <-> struct with D/S/X/E bits)
38 *************************************************************************/
39
40/*! Decode a 80-bit V.110 frame present as 80 ubits into a struct osmo_v110_decoded_frame.
41 * \param[out] fr caller-allocated output data structure, filled by this function
42 * \param[in] ra_bits One V.110 frame as 80 unpacked bits.
43 * \param[in] n_bits number of unpacked bits provided in ra_bits
44 * \returns 0 in case of success; negative on error. */
45int osmo_v110_decode_frame(struct osmo_v110_decoded_frame *fr, const ubit_t *ra_bits, size_t n_bits)
46{
47 if (n_bits < 80)
48 return -EINVAL;
49
50 /* X1 .. X2 */
51 fr->x_bits[0] = ra_bits[2 * 8 + 7];
52 fr->x_bits[1] = ra_bits[7 * 8 + 7];
53
54 /* S1, S3, S4, S6, S8, S9 */
55 fr->s_bits[0] = ra_bits[1 * 8 + 7];
56 fr->s_bits[2] = ra_bits[3 * 8 + 7];
57 fr->s_bits[3] = ra_bits[4 * 8 + 7];
58 fr->s_bits[5] = ra_bits[6 * 8 + 7];
59 fr->s_bits[7] = ra_bits[8 * 8 + 7];
60 fr->s_bits[8] = ra_bits[9 * 8 + 7];
61
62 /* E1 .. E7 */
63 memcpy(fr->e_bits, ra_bits + 5 * 8 + 1, 7);
64
65 /* D-bits */
66 memcpy(fr->d_bits + 0 * 6, ra_bits + 1 * 8 + 1, 6);
67 memcpy(fr->d_bits + 1 * 6, ra_bits + 2 * 8 + 1, 6);
68 memcpy(fr->d_bits + 2 * 6, ra_bits + 3 * 8 + 1, 6);
69 memcpy(fr->d_bits + 3 * 6, ra_bits + 4 * 8 + 1, 6);
70
71 memcpy(fr->d_bits + 4 * 6, ra_bits + 6 * 8 + 1, 6);
72 memcpy(fr->d_bits + 5 * 6, ra_bits + 7 * 8 + 1, 6);
73 memcpy(fr->d_bits + 6 * 6, ra_bits + 8 * 8 + 1, 6);
74 memcpy(fr->d_bits + 7 * 6, ra_bits + 9 * 8 + 1, 6);
75
76 return 0;
77}
78
79/*! Encode a struct osmo_v110_decoded_frame into an 80-bit V.110 frame as ubits.
80 * \param[out] ra_bits caller-provided output buffer at leat 80 ubits large
81 * \param[in] n_bits length of ra_bits. Must be at least 80.
82 * \param[in] input data structure
83 * \returns number of bits written to ra_bits */
84int osmo_v110_encode_frame(ubit_t *ra_bits, size_t n_bits, const struct osmo_v110_decoded_frame *fr)
85{
86 if (n_bits < 80)
87 return -ENOSPC;
88
89 /* alignment pattern */
90 memset(ra_bits+0, 0, 8);
91 for (int i = 1; i < 10; i++)
92 ra_bits[i*8] = 1;
93
94 /* X1 .. X2 */
95 ra_bits[2 * 8 + 7] = fr->x_bits[0];
96 ra_bits[7 * 8 + 7] = fr->x_bits[1];
97
98 /* S1, S3, S4, S6, S8, S9 */
99 ra_bits[1 * 8 + 7] = fr->s_bits[0];
100 ra_bits[3 * 8 + 7] = fr->s_bits[2];
101 ra_bits[4 * 8 + 7] = fr->s_bits[3];
102 ra_bits[6 * 8 + 7] = fr->s_bits[5];
103 ra_bits[8 * 8 + 7] = fr->s_bits[7];
104 ra_bits[9 * 8 + 7] = fr->s_bits[8];
105
106 /* E1 .. E7 */
107 memcpy(ra_bits + 5 * 8 + 1, fr->e_bits, 7);
108
109 /* D-bits */
110 memcpy(ra_bits + 1 * 8 + 1, fr->d_bits + 0 * 6, 6);
111 memcpy(ra_bits + 2 * 8 + 1, fr->d_bits + 1 * 6, 6);
112 memcpy(ra_bits + 3 * 8 + 1, fr->d_bits + 2 * 6, 6);
113 memcpy(ra_bits + 4 * 8 + 1, fr->d_bits + 3 * 6, 6);
114
115 memcpy(ra_bits + 6 * 8 + 1, fr->d_bits + 4 * 6, 6);
116 memcpy(ra_bits + 7 * 8 + 1, fr->d_bits + 5 * 6, 6);
117 memcpy(ra_bits + 8 * 8 + 1, fr->d_bits + 6 * 6, 6);
118 memcpy(ra_bits + 9 * 8 + 1, fr->d_bits + 7 * 6, 6);
119
120 return 10 * 8;
121}
122
123/*! Print a encoded V.110 frame in the same table-like structure as the spec.
124 * \param outf output FILE stream to which to dump
125 * \param[in] fr unpacked bits to dump
126 * \param[in] in_len length of unpacked bits available at fr. */
127void osmo_v110_ubit_dump(FILE *outf, const ubit_t *fr, size_t in_len)
128{
129 if (in_len < 80)
130 fprintf(outf, "short input data\n");
131
132 for (unsigned int octet = 0; octet < 10; octet++) {
133 fprintf(outf, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
134 fr[octet * 8 + 0], fr[octet * 8 + 1], fr[octet * 8 + 2], fr[octet * 8 + 3],
135 fr[octet * 8 + 4], fr[octet * 8 + 5], fr[octet * 8 + 6], fr[octet * 8 + 7]);
136 }
137}
138
139/*************************************************************************
140 * RA1 synchronous rate adaptation
141 *************************************************************************/
142
143/* I actually couldn't find any reference as to the value of F(ill) bits */
144#define F 1
145
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700146/*! E1/E2/E3 bit values as per Table 5/V.110 */
147const ubit_t osmo_v110_e1e2e3[_NUM_OSMO_V110_SYNC_RA1][3] = {
148 [OSMO_V110_SYNC_RA1_600] = { 1, 0, 0 },
149 [OSMO_V110_SYNC_RA1_1200] = { 0, 1, 0 },
150 [OSMO_V110_SYNC_RA1_2400] = { 1, 1, 0 },
151 [OSMO_V110_SYNC_RA1_4800] = { 0, 1, 1 },
152 [OSMO_V110_SYNC_RA1_7200] = { 1, 0, 1 },
153 [OSMO_V110_SYNC_RA1_9600] = { 0, 1, 1 },
154 [OSMO_V110_SYNC_RA1_12000] = { 0, 0, 1 },
155 [OSMO_V110_SYNC_RA1_14400] = { 1, 0, 1 },
156 [OSMO_V110_SYNC_RA1_19200] = { 0, 1, 1 },
157 [OSMO_V110_SYNC_RA1_24000] = { 0, 0, 1 },
158 [OSMO_V110_SYNC_RA1_28800] = { 1, 0, 1 },
159 [OSMO_V110_SYNC_RA1_38400] = { 0, 1, 1 },
160};
161
Harald Welte065dab82022-11-29 23:13:06 +0100162/*! Adapt from 6 synchronous 600bit/s input bits to a decoded V.110 frame.
163 * \param[out] fr caller-allocated output frame to which E+D bits are stored
164 * \param[in] d_in input user bits
165 * \param[in] in_len number of bits in d_in. Must be 6.
166 * \returns 0 on success; negative in case of error. */
167static int v110_adapt_600_to_IR8000(struct osmo_v110_decoded_frame *fr, const ubit_t *d_in, size_t in_len)
168{
169 if (in_len != 6)
170 return -EINVAL;
171
172 /* Table 6a / V.110 */
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700173 osmo_v110_e1e2e3_set(fr->e_bits, OSMO_V110_SYNC_RA1_600);
Harald Welte065dab82022-11-29 23:13:06 +0100174 for (int i = 0; i < 6; i++)
175 memset(fr->d_bits + i*8, d_in[i], 8);
176
177 return 0;
178}
179
180static int v110_adapt_IR8000_to_600(ubit_t *d_out, size_t out_len, const struct osmo_v110_decoded_frame *fr)
181{
182 if (out_len < 6)
183 return -ENOSPC;
184
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700185 if (osmo_v110_e1e2e3_cmp(fr->e_bits, OSMO_V110_SYNC_RA1_600))
Harald Welte065dab82022-11-29 23:13:06 +0100186 return -EINVAL;
187
188 for (int i = 0; i < 6; i++) {
189 /* we only use one of the bits, not some kind of consistency check or majority vote */
190 d_out[i] = fr->d_bits[i*8];
191 }
192
193 return 6;
194}
195
196/*! Adapt from 12 synchronous 1200bit/s input bits to a decoded V.110 frame.
197 * \param[out] fr caller-allocated output frame to which E+D bits are stored
198 * \param[in] d_in input user bits
199 * \param[in] in_len number of bits in d_in. Must be 12.
200 * \returns 0 on success; negative in case of error. */
201static int v110_adapt_1200_to_IR8000(struct osmo_v110_decoded_frame *fr, const ubit_t *d_in, size_t in_len)
202{
203 if (in_len != 12)
204 return -EINVAL;
205
206 /* Table 6b / V.110 */
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700207 osmo_v110_e1e2e3_set(fr->e_bits, OSMO_V110_SYNC_RA1_1200);
Harald Welte065dab82022-11-29 23:13:06 +0100208 for (int i = 0; i < 12; i++)
209 memset(fr->d_bits + i*4, d_in[i], 4);
210
211 return 0;
212}
213
214static int v110_adapt_IR8000_to_1200(ubit_t *d_out, size_t out_len, const struct osmo_v110_decoded_frame *fr)
215{
216 if (out_len < 12)
217 return -ENOSPC;
218
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700219 if (osmo_v110_e1e2e3_cmp(fr->e_bits, OSMO_V110_SYNC_RA1_1200))
Harald Welte065dab82022-11-29 23:13:06 +0100220 return -EINVAL;
221
222 for (int i = 0; i < 12; i++) {
223 /* we only use one of the bits, not some kind of consistency check or majority vote */
224 d_out[i] = fr->d_bits[i*4];
225 }
226
227 return 12;
228}
229
230/*! Adapt from 24 synchronous 2400bit/s input bits to a decoded V.110 frame.
231 * \param[out] fr caller-allocated output frame to which E+D bits are stored
232 * \param[in] d_in input user bits
233 * \param[in] in_len number of bits in d_in. Must be 24.
234 * \returns 0 on success; negative in case of error. */
235static int v110_adapt_2400_to_IR8000(struct osmo_v110_decoded_frame *fr, const ubit_t *d_in, size_t in_len)
236{
237 if (in_len != 24)
238 return -EINVAL;
239
240 /* Table 6c / V.110 */
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700241 osmo_v110_e1e2e3_set(fr->e_bits, OSMO_V110_SYNC_RA1_2400);
Harald Welte065dab82022-11-29 23:13:06 +0100242 for (int i = 0; i < 24; i++) {
243 fr->d_bits[i*2 + 0] = d_in[i];
244 fr->d_bits[i*2 + 1] = d_in[i];
245 }
246
247 return 0;
248}
249
250static int v110_adapt_IR8000_to_2400(ubit_t *d_out, size_t out_len, const struct osmo_v110_decoded_frame *fr)
251{
252 if (out_len < 24)
253 return -ENOSPC;
254
Vadim Yanitskiy25127fb2023-03-17 17:08:18 +0700255 /* Table 6c / V.110 */
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700256 if (osmo_v110_e1e2e3_cmp(fr->e_bits, OSMO_V110_SYNC_RA1_2400))
Harald Welte065dab82022-11-29 23:13:06 +0100257 return -EINVAL;
258
259 for (int i = 0; i < 24; i++) {
260 /* we only use one of the bits, not some kind of consistency check or majority vote */
261 d_out[i] = fr->d_bits[i*2];
262 }
263
264 return 24;
265}
266
267/*! Adapt from 36 synchronous N x 3600bit/s input bits to a decoded V.110 frame.
268 * \param[out] fr caller-allocated output frame to which E+D bits are stored
269 * \param[in] d_in input user bits
270 * \param[in] in_len number of bits in d_in. Must be 36.
271 * \returns 0 on success; negative in case of error. */
272static int v110_adapt_Nx3600_to_IR(struct osmo_v110_decoded_frame *fr, const ubit_t *d_in, size_t in_len)
273{
274 int d_idx = 0;
275
276 if (in_len != 36)
277 return -EINVAL;
278
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700279 /* Table 6d / V.110 (7200 is one of Nx3600) */
280 osmo_v110_e1e2e3_set(fr->e_bits, OSMO_V110_SYNC_RA1_7200);
Harald Welte065dab82022-11-29 23:13:06 +0100281
282 memcpy(fr->d_bits + d_idx, d_in + 0, 10); d_idx += 10; /* D1..D10 */
283 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
284 memcpy(fr->d_bits + d_idx, d_in + 10, 2); d_idx += 2; /* D11..D12 */
285 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
286 memcpy(fr->d_bits + d_idx, d_in + 12, 2); d_idx += 2; /* D13..D14 */
287 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
288 memcpy(fr->d_bits + d_idx, d_in + 14, 14); d_idx += 14; /* D15..D28 */
289 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
290 memcpy(fr->d_bits + d_idx, d_in + 28, 2); d_idx += 2; /* D29..D30 */
291 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
292 memcpy(fr->d_bits + d_idx, d_in + 30, 2); d_idx += 2; /* D31..D32 */
293 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
294 memcpy(fr->d_bits + d_idx, d_in + 32, 4); d_idx += 4; /* D33..D36 */
295
296 OSMO_ASSERT(d_idx == 48);
297
298 return 0;
299}
300
301static int v110_adapt_IR_to_Nx3600(ubit_t *d_out, size_t out_len, const struct osmo_v110_decoded_frame *fr)
302{
303 int d_idx = 0;
304
305 if (out_len < 36)
306 return -ENOSPC;
307
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700308 /* Table 6d / V.110 (7200 is one of Nx3600) */
309 if (osmo_v110_e1e2e3_cmp(fr->e_bits, OSMO_V110_SYNC_RA1_7200))
Harald Welte065dab82022-11-29 23:13:06 +0100310 return -EINVAL;
311
312 memcpy(d_out + 0, fr->d_bits + d_idx, 10); d_idx += 10; /* D1..D10 */
313 d_idx += 2;
314 memcpy(d_out + 10, fr->d_bits + d_idx, 2); d_idx += 2; /* D11..D12 */
315 d_idx += 2;
316 memcpy(d_out + 12, fr->d_bits + d_idx, 2); d_idx += 2; /* D13..D14 */
317 d_idx += 2;
318 memcpy(d_out + 14, fr->d_bits + d_idx, 14); d_idx += 14;/* D15..D28 */
319 d_idx += 2;
320 memcpy(d_out + 28, fr->d_bits + d_idx, 2); d_idx += 2; /* D29..D30 */
321 d_idx += 2;
322 memcpy(d_out + 30, fr->d_bits + d_idx, 2); d_idx += 2; /* D31..D32 */
323 d_idx += 2;
324 memcpy(d_out + 32, fr->d_bits + d_idx, 4); d_idx += 4; /* D33..D36 */
325
326 OSMO_ASSERT(d_idx == 48);
327
328 return 36;
329}
330
331
332/*! Adapt from 48 synchronous N x 4800bit/s input bits to a decoded V.110 frame.
333 * \param[out] fr caller-allocated output frame to which E+D bits are stored
334 * \param[in] d_in input user bits
335 * \param[in] in_len number of bits in d_in. Must be 48.
336 * \returns 0 on success; negative in case of error. */
337static int v110_adapt_Nx4800_to_IR(struct osmo_v110_decoded_frame *fr, const ubit_t *d_in, size_t in_len)
338{
339 if (in_len != 48)
340 return -EINVAL;
341
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700342 /* Table 6e / V.110 (4800 is one of Nx4800) */
343 osmo_v110_e1e2e3_set(fr->e_bits, OSMO_V110_SYNC_RA1_4800);
Harald Welte065dab82022-11-29 23:13:06 +0100344
345 memcpy(fr->d_bits, d_in, 48);
346
347 return 0;
348}
349
350static int v110_adapt_IR_to_Nx4800(ubit_t *d_out, size_t out_len, const struct osmo_v110_decoded_frame *fr)
351{
352 if (out_len < 48)
353 return -ENOSPC;
354
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700355 /* Table 6e / V.110 (4800 is one of Nx4800) */
356 if (osmo_v110_e1e2e3_cmp(fr->e_bits, OSMO_V110_SYNC_RA1_4800))
Harald Welte065dab82022-11-29 23:13:06 +0100357 return -EINVAL;
358
359 memcpy(d_out, fr->d_bits, 48);
360
361 return 48;
362}
363
364/*! Adapt from 30 synchronous N x 12000bit/s input bits to a decoded V.110 frame.
365 * \param[out] fr caller-allocated output frame to which E+D bits are stored
366 * \param[in] d_in input user bits
367 * \param[in] in_len number of bits in d_in. Must be 30.
368 * \returns 0 on success; negative in case of error. */
369static int v110_adapt_Nx12000_to_IR(struct osmo_v110_decoded_frame *fr, const ubit_t *d_in, size_t in_len)
370{
371 int d_idx = 0;
372
373 if (in_len != 30)
374 return -EINVAL;
375
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700376 /* Table 6f / V.110 (12000 is one of Nx12000) */
377 osmo_v110_e1e2e3_set(fr->e_bits, OSMO_V110_SYNC_RA1_12000);
Harald Welte065dab82022-11-29 23:13:06 +0100378
379 memcpy(fr->d_bits + d_idx, d_in + 0, 10); d_idx += 10; /* D1..D10 */
380 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
381 memcpy(fr->d_bits + d_idx, d_in + 10, 2); d_idx += 2; /* D11..D12 */
382 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
383 memcpy(fr->d_bits + d_idx, d_in + 12, 2); d_idx += 2; /* D13..D14 */
384 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
385 fr->d_bits[d_idx++] = d_in[14]; /* D15 */
386 memset(fr->d_bits + d_idx, F, 3); d_idx += 3;
387 memcpy(fr->d_bits + d_idx, d_in + 15, 10); d_idx += 10; /* D16..D25 */
388 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
389 memcpy(fr->d_bits + d_idx, d_in + 25, 2); d_idx += 2; /* D26..D27 */
390 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
391 memcpy(fr->d_bits + d_idx, d_in + 27, 2); d_idx += 2; /* D28..D29 */
392 memset(fr->d_bits + d_idx, F, 2); d_idx += 2;
393 fr->d_bits[d_idx++] = d_in[29]; /* D30 */
394 memset(fr->d_bits + d_idx, F, 3); d_idx += 3;
395
396 OSMO_ASSERT(d_idx == 48);
397
398 return 0;
399}
400
401static int v110_adapt_IR_to_Nx12000(ubit_t *d_out, size_t out_len, const struct osmo_v110_decoded_frame *fr)
402{
403 int d_idx = 0;
404
405 if (out_len < 30)
406 return -ENOSPC;
407
Vadim Yanitskiy06922fa2024-01-16 19:56:02 +0700408 /* Table 6f / V.110 (12000 is one of Nx12000) */
409 if (osmo_v110_e1e2e3_cmp(fr->e_bits, OSMO_V110_SYNC_RA1_12000))
Harald Welte065dab82022-11-29 23:13:06 +0100410 return -EINVAL;
411
412 memcpy(d_out + 0, fr->d_bits + d_idx, 10); d_idx += 10; /* D1..D10 */
413 d_idx += 2;
414 memcpy(d_out + 10, fr->d_bits + d_idx, 2); d_idx += 2; /* D11..D12 */
415 d_idx += 2;
416 memcpy(d_out + 12, fr->d_bits + d_idx, 2); d_idx += 2; /* D13..D14 */
417 d_idx += 2;
418 d_out[14] = fr->d_bits[d_idx++]; /* D15 */
419 d_idx += 3;
420 memcpy(d_out + 15, fr->d_bits + d_idx, 10); d_idx += 10;/* D16..D25 */
421 d_idx += 2;
422 memcpy(d_out + 25, fr->d_bits + d_idx, 2); d_idx += 2; /* D26..D27 */
423 d_idx += 2;
424 memcpy(d_out + 27, fr->d_bits + d_idx, 2); d_idx += 2; /* D28..D29 */
425 d_idx += 2;
426 d_out[29] = fr->d_bits[d_idx++]; /* D30 */
427 d_idx += 3;
428
429 OSMO_ASSERT(d_idx == 48);
430
431 return 30;
432}
433
434/* definition of a synchronous V.110 RA1 rate adaptation. There is one for each supported tuple
435 * of user data rate and intermediate rate (IR). */
436struct osmo_v110_sync_ra1 {
437 unsigned int data_rate;
438 unsigned int intermediate_rate;
439 unsigned int user_data_chunk_bits;
440 /*! RA1 function in user bitrate -> intermediate rate direction */
441 int (*adapt_user_to_ir)(struct osmo_v110_decoded_frame *fr, const ubit_t *d_in, size_t in_len);
442 /*! RA1 function in intermediate rate -> user bitrate direction */
443 int (*adapt_ir_to_user)(ubit_t *d_out, size_t out_len, const struct osmo_v110_decoded_frame *fr);
444};
445
446/* all of the synchronous data signalling rates; see Table 1/V.110 */
447static const struct osmo_v110_sync_ra1 osmo_v110_sync_ra1_def[_NUM_OSMO_V110_SYNC_RA1] = {
448 [OSMO_V110_SYNC_RA1_600] = {
449 .data_rate = 600,
450 .intermediate_rate = 8000,
451 .user_data_chunk_bits = 6,
452 .adapt_user_to_ir = v110_adapt_600_to_IR8000,
453 .adapt_ir_to_user = v110_adapt_IR8000_to_600,
454 },
455 [OSMO_V110_SYNC_RA1_1200] = {
456 .data_rate = 1200,
457 .intermediate_rate = 8000,
458 .user_data_chunk_bits = 12,
459 .adapt_user_to_ir = v110_adapt_1200_to_IR8000,
460 .adapt_ir_to_user = v110_adapt_IR8000_to_1200,
461 },
462 [OSMO_V110_SYNC_RA1_2400] = {
463 .data_rate = 2400,
464 .intermediate_rate = 8000,
465 .user_data_chunk_bits = 24,
466 .adapt_user_to_ir = v110_adapt_2400_to_IR8000,
467 .adapt_ir_to_user = v110_adapt_IR8000_to_2400,
468 },
469 [OSMO_V110_SYNC_RA1_4800] = {
470 .data_rate = 4800,
471 .intermediate_rate = 8000,
472 .user_data_chunk_bits = 48,
473 .adapt_user_to_ir = v110_adapt_Nx4800_to_IR,
474 .adapt_ir_to_user = v110_adapt_IR_to_Nx4800,
475 },
476 [OSMO_V110_SYNC_RA1_7200] = {
477 .data_rate = 7200,
478 .intermediate_rate = 16000,
479 .user_data_chunk_bits = 36,
480 .adapt_user_to_ir = v110_adapt_Nx3600_to_IR,
481 .adapt_ir_to_user = v110_adapt_IR_to_Nx3600,
482 },
483 [OSMO_V110_SYNC_RA1_9600] = {
484 .data_rate = 9600,
485 .intermediate_rate = 16000,
486 .user_data_chunk_bits = 48,
487 .adapt_user_to_ir = v110_adapt_Nx4800_to_IR,
488 .adapt_ir_to_user = v110_adapt_IR_to_Nx4800,
489 },
490 [OSMO_V110_SYNC_RA1_12000] = {
491 .data_rate = 12000,
492 .intermediate_rate = 32000,
493 .user_data_chunk_bits = 30,
494 .adapt_user_to_ir = v110_adapt_Nx12000_to_IR,
495 .adapt_ir_to_user = v110_adapt_IR_to_Nx12000,
496 },
497 [OSMO_V110_SYNC_RA1_14400] = {
498 .data_rate = 14400,
499 .intermediate_rate = 32000,
500 .user_data_chunk_bits = 36,
501 .adapt_user_to_ir = v110_adapt_Nx3600_to_IR,
502 .adapt_ir_to_user = v110_adapt_IR_to_Nx3600,
503 },
504 [OSMO_V110_SYNC_RA1_19200] = {
505 .data_rate = 19200,
506 .intermediate_rate = 32000,
507 .user_data_chunk_bits = 48,
508 .adapt_user_to_ir = v110_adapt_Nx4800_to_IR,
509 .adapt_ir_to_user = v110_adapt_IR_to_Nx4800,
510 },
511 [OSMO_V110_SYNC_RA1_24000] = {
512 .data_rate = 24000,
513 .intermediate_rate = 64000,
514 .user_data_chunk_bits = 30,
515 .adapt_user_to_ir = v110_adapt_Nx12000_to_IR,
516 .adapt_ir_to_user = v110_adapt_IR_to_Nx12000,
517 },
518 [OSMO_V110_SYNC_RA1_28800] = {
519 .data_rate = 28800,
520 .intermediate_rate = 64000,
521 .user_data_chunk_bits = 36,
522 .adapt_user_to_ir = v110_adapt_Nx3600_to_IR,
523 .adapt_ir_to_user = v110_adapt_IR_to_Nx3600,
524 },
525 [OSMO_V110_SYNC_RA1_38400] = {
526 .data_rate = 38400,
527 .intermediate_rate = 64000,
528 .user_data_chunk_bits = 48,
529 .adapt_user_to_ir = v110_adapt_Nx4800_to_IR,
530 .adapt_ir_to_user = v110_adapt_IR_to_Nx4800,
531 },
532};
533
534/*! obtain the size (in number of bits) of the user data bits in one V.110
535 * frame for specified RA1 rate */
536int osmo_v110_sync_ra1_get_user_data_chunk_bitlen(enum osmo_v100_sync_ra1_rate rate)
537{
538 if (rate < 0 || rate >= _NUM_OSMO_V110_SYNC_RA1)
539 return -EINVAL;
540
541 return osmo_v110_sync_ra1_def[rate].user_data_chunk_bits;
542}
543
544/*! obtain the user data rate (in bits/s) for specified RA1 rate */
545int osmo_v110_sync_ra1_get_user_data_rate(enum osmo_v100_sync_ra1_rate rate)
546{
547 if (rate < 0 || rate >= _NUM_OSMO_V110_SYNC_RA1)
548 return -EINVAL;
549
550 return osmo_v110_sync_ra1_def[rate].data_rate;
551}
552
553/*! obtain the intermediate rate (in bits/s) for specified RA1 rate */
554int osmo_v110_sync_ra1_get_intermediate_rate(enum osmo_v100_sync_ra1_rate rate)
555{
556 if (rate < 0 || rate >= _NUM_OSMO_V110_SYNC_RA1)
557 return -EINVAL;
558
559 return osmo_v110_sync_ra1_def[rate].intermediate_rate;
560}
561
562/*! perform V.110 RA1 function in user rate -> intermediate rate direction.
563 * \param[in] rate specification of the user bitrate
564 * \param[out] fr caller-allocated output buffer for the [decoded] V.110 frame generated
565 * \param[in] d_in input user data (unpacked bits)
566 * \param[in] in_len length of user input data (in number of bits)
567 * \returns 0 on success; negative in case of error */
568int osmo_v110_sync_ra1_user_to_ir(enum osmo_v100_sync_ra1_rate rate, struct osmo_v110_decoded_frame *fr,
569 const ubit_t *d_in, size_t in_len)
570{
571 if (rate < 0 || rate >= _NUM_OSMO_V110_SYNC_RA1)
572 return -EINVAL;
573
574 return osmo_v110_sync_ra1_def[rate].adapt_user_to_ir(fr, d_in, in_len);
575}
576
577/*! perform V.110 RA1 function in intermediate rate -> user rate direction.
578 * \param[in] rate specification of the user bitrate
579 * \param[out] d_out caller-allocated output user data (unpacked bits)
580 * \param[out] out_len length of d_out output buffer
581 * \param[in] fr [decoded] V.110 frame used as input
582 * \returns number of unpacked bits written to d_out on success; negative in case of error */
583int osmo_v110_sync_ra1_ir_to_user(enum osmo_v100_sync_ra1_rate rate, ubit_t *d_out, size_t out_len,
584 const struct osmo_v110_decoded_frame *fr)
585{
586 if (rate < 0 || rate >= _NUM_OSMO_V110_SYNC_RA1)
587 return -EINVAL;
588
589 return osmo_v110_sync_ra1_def[rate].adapt_ir_to_user(d_out, out_len, fr);
590}