blob: 5e9d5ab8d4ac25016eae626f6be6b029ba240961 [file] [log] [blame]
Harald Weltec4cfb802022-11-29 23:16:52 +01001/*************************************************************************
2 * GSM CSD modified V.110 frame decoding/encoding (ubits <-> struct with D/S/X/E bits)
3 *************************************************************************/
4
5/* (C) 2022 by Harald Welte <laforge@osmocom.org>
6 *
7 * SPDX-License-Identifier: GPL-2.0+
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20#include <errno.h>
21#include <osmocom/core/bits.h>
22#include <osmocom/isdn/v110.h>
23
24/*! Decode a 60-bit GSM 12kbit/s CSD frame present as 60 ubits into a struct osmo_v110_decoded_frame.
25 * \param[out] caller-allocated output data structure, filled by this function
26 * \param[in] ra_bits One V.110 frame as 60 unpacked bits. */
27int osmo_csd_12k_6k_decode_frame(struct osmo_v110_decoded_frame *fr, const ubit_t *ra_bits, size_t n_bits)
28{
29 /* 3GPP TS 44.021 Section 8.1.2 / 8.1.3
30 D1 D2 D3 D4 D5 D6 S1
31 D7 D8 D9 D10 D11 D12 X
32 D13 D14 D15 D16 D17 D18 S3
33 D19 D20 D21 D22 D23 D24 S4
34 E4 E5 E6 E7 D25 D26 D27
35 D28 D29 D30 S6 D31 D32 D33
36 D34 D35 D36 X D37 D38 D39
37 D40 D41 D42 S8 D43 D44 D45
38 D46 D47 D48 S9 */
39
40 if (n_bits < 60)
41 return -EINVAL;
42
43 /* X1 .. X2 */
44 fr->x_bits[0] = ra_bits[1 * 7 + 6];
45 fr->x_bits[1] = ra_bits[6 * 7 + 3];
46
47 /* S1, S3, S4, S6, S8, S9 */
48 fr->s_bits[0] = ra_bits[0 * 7 + 6];
49 fr->s_bits[2] = ra_bits[2 * 7 + 6];
50 fr->s_bits[3] = ra_bits[3 * 7 + 6];
51 fr->s_bits[5] = ra_bits[5 * 7 + 3];
52 fr->s_bits[7] = ra_bits[7 * 7 + 3];
53 fr->s_bits[8] = ra_bits[8 * 7 + 3];
54
55 /* E1 .. E3 must be set by out-of-band knowledge! */
56
57 /* E4 .. E7 */
58 memcpy(fr->e_bits+3, ra_bits + 4 * 7 + 0, 4);
59
60 /* D-bits */
61 memcpy(fr->d_bits + 0 * 6 + 0, ra_bits + 0 * 7 + 0, 6);
62 memcpy(fr->d_bits + 1 * 6 + 0, ra_bits + 1 * 7 + 0, 6);
63 memcpy(fr->d_bits + 2 * 6 + 0, ra_bits + 2 * 7 + 0, 6);
64 memcpy(fr->d_bits + 3 * 6 + 0, ra_bits + 3 * 7 + 0, 6);
65 memcpy(fr->d_bits + 4 * 6 + 0, ra_bits + 4 * 7 + 4, 3);
66 memcpy(fr->d_bits + 4 * 6 + 3, ra_bits + 5 * 7 + 0, 3);
67 memcpy(fr->d_bits + 5 * 6 + 0, ra_bits + 5 * 7 + 4, 3);
68 memcpy(fr->d_bits + 5 * 6 + 3, ra_bits + 6 * 7 + 0, 3);
69 memcpy(fr->d_bits + 6 * 6 + 0, ra_bits + 6 * 7 + 4, 3);
70 memcpy(fr->d_bits + 6 * 6 + 3, ra_bits + 7 * 7 + 0, 3);
71 memcpy(fr->d_bits + 7 * 6 + 0, ra_bits + 7 * 7 + 4, 3);
72 memcpy(fr->d_bits + 7 * 6 + 3, ra_bits + 8 * 7 + 0, 3);
73
74 return 0;
75}
76
77int osmo_csd_12k_6k_encode_frame(ubit_t *ra_bits, size_t ra_bits_size, const struct osmo_v110_decoded_frame *fr)
78{
79 if (ra_bits_size < 60)
80 return -EINVAL;
81
82 /* X1 .. X2 */
83 ra_bits[1 * 7 + 6] = fr->x_bits[0];
84 ra_bits[6 * 7 + 3] = fr->x_bits[1];
85
86 /* S1, S3, S4, S6, S8, S9 */
87 ra_bits[0 * 7 + 6] = fr->s_bits[0];
88 ra_bits[2 * 7 + 6] = fr->s_bits[2];
89 ra_bits[3 * 7 + 6] = fr->s_bits[3];
90 ra_bits[5 * 7 + 3] = fr->s_bits[5];
91 ra_bits[7 * 7 + 3] = fr->s_bits[7];
92 ra_bits[8 * 7 + 3] = fr->s_bits[8];
93
94 /* E1 .. E3 are dropped */
95
96 /* E4 .. E7 */
97 memcpy(ra_bits + 4 * 7 + 0, fr->e_bits+3, 4);
98
99 /* D-bits */
100 memcpy(ra_bits + 0 * 7 + 0, fr->d_bits + 0 * 6 + 0, 6);
101 memcpy(ra_bits + 1 * 7 + 0, fr->d_bits + 1 * 6 + 0, 6);
102 memcpy(ra_bits + 2 * 7 + 0, fr->d_bits + 2 * 6 + 0, 6);
103 memcpy(ra_bits + 3 * 7 + 0, fr->d_bits + 3 * 6 + 0, 6);
104 memcpy(ra_bits + 4 * 7 + 4, fr->d_bits + 4 * 6 + 0, 3);
105 memcpy(ra_bits + 5 * 7 + 0, fr->d_bits + 4 * 6 + 3, 3);
106 memcpy(ra_bits + 5 * 7 + 4, fr->d_bits + 5 * 6 + 0, 3);
107 memcpy(ra_bits + 6 * 7 + 0, fr->d_bits + 5 * 6 + 3, 3);
108 memcpy(ra_bits + 6 * 7 + 4, fr->d_bits + 6 * 6 + 0, 3);
109 memcpy(ra_bits + 7 * 7 + 0, fr->d_bits + 6 * 6 + 3, 3);
110 memcpy(ra_bits + 7 * 7 + 4, fr->d_bits + 7 * 6 + 0, 3);
111 memcpy(ra_bits + 8 * 7 + 0, fr->d_bits + 7 * 6 + 3, 3);
112
113 return 60;
114}
115
116/*! Decode a 36-bit GSM 3k6kbit/s CSD frame present as 36 ubits into a struct osmo_v110_decoded_frame.
117 * \param[out] caller-allocated output data structure, filled by this function
118 * \param[in] ra_bits One V.110 frame as 36 unpacked bits. */
119int osmo_csd_3k6_decode_frame(struct osmo_v110_decoded_frame *fr, const ubit_t *ra_bits, size_t n_bits)
120{
121
122 /* 3GPP TS 44.021 Section 8.1.4
123 D1 D2 D3 S1 D4 D5 D6 X
124 D7 D8 D9 S3 D10 D11 D12 S4
125 E4 E5 E6 E7 D13 D14 D15 S6
126 D16 D17 D18 X D19 D20 D21 S8
127 D22 D23 D24 S9
128 */
129
130 if (n_bits < 36)
131 return -EINVAL;
132
133 /* X1 .. X2 */
134 fr->x_bits[0] = ra_bits[0 * 8 + 7];
135 fr->x_bits[1] = ra_bits[3 * 8 + 3];
136
137 /* S1, S3, S4, S6, S8, S9 */
138 fr->s_bits[0] = ra_bits[0 * 8 + 3];
139 fr->s_bits[2] = ra_bits[1 * 8 + 3];
140 fr->s_bits[3] = ra_bits[1 * 8 + 7];
141 fr->s_bits[5] = ra_bits[2 * 8 + 7];
142 fr->s_bits[7] = ra_bits[3 * 8 + 7];
143 fr->s_bits[8] = ra_bits[4 * 8 + 3];
144
145 /* E1 .. E3 must be set by out-of-band knowledge! */
146
147 /* E4 .. E7 */
148 memcpy(fr->e_bits+3, ra_bits + 2 * 8 + 0, 4);
149
150 /* D-bits */
151 unsigned int d_idx = 0;
152 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 0]; /* D1 */
153 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 0]; /* D1 */
154 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 1]; /* D2 */
155 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 1]; /* D2 */
156 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 2]; /* D3 */
157 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 2]; /* D3 */
158 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 4]; /* D4 */
159 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 4]; /* D4 */
160 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 5]; /* D5 */
161 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 5]; /* D5 */
162 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 6]; /* D6 */
163 fr->d_bits[d_idx++] = ra_bits[0 * 8 + 6]; /* D6 */
164
165 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 0]; /* D7 */
166 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 0]; /* D7 */
167 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 1]; /* D8 */
168 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 1]; /* D8 */
169 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 2]; /* D9 */
170 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 2]; /* D9 */
171 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 4]; /* D10 */
172 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 4]; /* D10 */
173 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 5]; /* D11 */
174 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 5]; /* D11 */
175 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 6]; /* D12 */
176 fr->d_bits[d_idx++] = ra_bits[1 * 8 + 6]; /* D12 */
177
178 fr->d_bits[d_idx++] = ra_bits[2 * 8 + 4]; /* D13 */
179 fr->d_bits[d_idx++] = ra_bits[2 * 8 + 4]; /* D13 */
180 fr->d_bits[d_idx++] = ra_bits[2 * 8 + 5]; /* D14 */
181 fr->d_bits[d_idx++] = ra_bits[2 * 8 + 5]; /* D14 */
182 fr->d_bits[d_idx++] = ra_bits[2 * 8 + 6]; /* D15 */
183 fr->d_bits[d_idx++] = ra_bits[2 * 8 + 6]; /* D15 */
184
185 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 0]; /* D16 */
186 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 0]; /* D16 */
187 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 1]; /* D17 */
188 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 1]; /* D17 */
189 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 2]; /* D18 */
190 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 2]; /* D18 */
191 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 4]; /* D19 */
192 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 4]; /* D19 */
193 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 5]; /* D20 */
194 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 5]; /* D20 */
195 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 6]; /* D21 */
196 fr->d_bits[d_idx++] = ra_bits[3 * 8 + 6]; /* D21 */
197
198 fr->d_bits[d_idx++] = ra_bits[4 * 8 + 0]; /* D22 */
199 fr->d_bits[d_idx++] = ra_bits[4 * 8 + 0]; /* D22 */
200 fr->d_bits[d_idx++] = ra_bits[4 * 8 + 1]; /* D23 */
201 fr->d_bits[d_idx++] = ra_bits[4 * 8 + 1]; /* D23 */
202 fr->d_bits[d_idx++] = ra_bits[4 * 8 + 2]; /* D24 */
203 fr->d_bits[d_idx++] = ra_bits[4 * 8 + 2]; /* D24 */
204
205 OSMO_ASSERT(d_idx == 48);
206
207 return 0;
208}
209
210int osmo_csd_3k6_encode_frame(ubit_t *ra_bits, size_t ra_bits_size, const struct osmo_v110_decoded_frame *fr)
211{
212 if (ra_bits_size < 36)
213 return -EINVAL;
214
215 /* X1 .. X2 */
216 ra_bits[0 * 8 + 7] = fr->x_bits[0];
217 ra_bits[3 * 8 + 3] = fr->x_bits[1];
218
219 /* S1, S3, S4, S6, S8, S9 */
220 ra_bits[0 * 8 + 3] = fr->s_bits[0];
221 ra_bits[1 * 8 + 3] = fr->s_bits[2];
222 ra_bits[1 * 8 + 7] = fr->s_bits[3];
223 ra_bits[2 * 8 + 7] = fr->s_bits[5];
224 ra_bits[3 * 8 + 7] = fr->s_bits[7];
225 ra_bits[4 * 8 + 3] = fr->s_bits[8];
226
227 /* E1 .. E3 are ignored */
228
229 /* E4 .. E7 */
230 memcpy(ra_bits + 2 * 8 + 0, fr->e_bits+3, 4);
231
232 /* D-bits */
233 unsigned int d_idx = 0;
234 ra_bits[0 * 8 + 0] = fr->d_bits[d_idx]; d_idx += 2;
235 ra_bits[0 * 8 + 1] = fr->d_bits[d_idx]; d_idx += 2;
236 ra_bits[0 * 8 + 2] = fr->d_bits[d_idx]; d_idx += 2;
237 ra_bits[0 * 8 + 4] = fr->d_bits[d_idx]; d_idx += 2;
238 ra_bits[0 * 8 + 5] = fr->d_bits[d_idx]; d_idx += 2;
239 ra_bits[0 * 8 + 6] = fr->d_bits[d_idx]; d_idx += 2;
240
241 ra_bits[1 * 8 + 0] = fr->d_bits[d_idx]; d_idx += 2;
242 ra_bits[1 * 8 + 1] = fr->d_bits[d_idx]; d_idx += 2;
243 ra_bits[1 * 8 + 2] = fr->d_bits[d_idx]; d_idx += 2;
244 ra_bits[1 * 8 + 4] = fr->d_bits[d_idx]; d_idx += 2;
245 ra_bits[1 * 8 + 5] = fr->d_bits[d_idx]; d_idx += 2;
246 ra_bits[1 * 8 + 6] = fr->d_bits[d_idx]; d_idx += 2;
247
248 ra_bits[2 * 8 + 4] = fr->d_bits[d_idx]; d_idx += 2;
249 ra_bits[2 * 8 + 5] = fr->d_bits[d_idx]; d_idx += 2;
250 ra_bits[2 * 8 + 6] = fr->d_bits[d_idx]; d_idx += 2;
251
252 ra_bits[3 * 8 + 0] = fr->d_bits[d_idx]; d_idx += 2;
253 ra_bits[3 * 8 + 1] = fr->d_bits[d_idx]; d_idx += 2;
254 ra_bits[3 * 8 + 2] = fr->d_bits[d_idx]; d_idx += 2;
255 ra_bits[3 * 8 + 4] = fr->d_bits[d_idx]; d_idx += 2;
256 ra_bits[3 * 8 + 5] = fr->d_bits[d_idx]; d_idx += 2;
257 ra_bits[3 * 8 + 6] = fr->d_bits[d_idx]; d_idx += 2;
258
259 ra_bits[4 * 8 + 0] = fr->d_bits[d_idx]; d_idx += 2;
260 ra_bits[4 * 8 + 1] = fr->d_bits[d_idx]; d_idx += 2;
261 ra_bits[4 * 8 + 2] = fr->d_bits[d_idx]; d_idx += 2;
262
263 OSMO_ASSERT(d_idx == 48);
264
265 return 36;
266}
267
268/*! Print a encoded "CSD modififed V.110" frame in the same table-like structure as the spec.
269 * \param outf output FILE stream to which to dump
270 * \param[in] fr unpacked bits to dump
271 * \param[in] in_len length of unpacked bits available at fr. */
272void osmo_csd_ubit_dump(FILE *outf, const ubit_t *fr, size_t in_len)
273{
274 switch (in_len) {
275 case 60:
276 for (unsigned int septet = 0; septet < 9; septet++) {
277 if (septet < 8) {
278 fprintf(outf, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", fr[septet * 7 + 0],
279 fr[septet * 7 + 1], fr[septet * 7 + 2], fr[septet * 7 + 3],
280 fr[septet * 7 + 4], fr[septet * 7 + 5], fr[septet*7 + 6]);
281 } else {
282 fprintf(outf, "%d\t%d\t%d\t%d\n", fr[septet * 7 + 0],
283 fr[septet * 7 + 1], fr[septet * 7 + 2], fr[septet * 7 + 3]);
284 }
285 }
286 break;
287 case 36:
288 for (unsigned int octet = 0; octet < 5; octet++) {
289 if (octet < 4) {
290 fprintf(outf, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
291 fr[octet * 8 + 0], fr[octet * 8 + 1], fr[octet * 8 + 2],
292 fr[octet * 8 + 3], fr[octet * 8 + 4], fr[octet * 8 + 5],
293 fr[octet * 8 + 6], fr[octet * 8 + 7]);
294 } else {
295 fprintf(outf, "%d\t%d\t%d\t%d\n", fr[octet * 8 + 0],
296 fr[octet * 8 + 1], fr[octet * 8 + 2], fr[octet * 8 + 3]);
297 }
298 }
299 break;
300 default:
301 fprintf(outf, "invalid input data length: %zu\n", in_len);
302 }
303}