blob: d536e443cf757563154a80f3b30f9d0eb227821a [file] [log] [blame]
Vadim Yanitskiy3262f822016-09-23 01:48:59 +07001/*
2 * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
3 * (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Vadim Yanitskiy3262f822016-09-23 01:48:59 +070016 */
17
18#include <stdio.h>
19#include <errno.h>
20#include <unistd.h>
21#include <string.h>
22#include <stdlib.h>
23
24#include <osmocom/core/bits.h>
25#include <osmocom/core/utils.h>
26
Vadim Yanitskiyb3340222023-05-26 01:07:18 +070027#include <osmocom/gsm/protocol/gsm_04_08.h>
Vadim Yanitskiy3262f822016-09-23 01:48:59 +070028#include <osmocom/coding/gsm0503_coding.h>
29
Max458a6f52017-11-28 17:26:54 +010030#define DUMP_U_AT(b, x, u) do { \
31 printf("%s %02x %02x ", osmo_ubit_dump(b + x, 57), b[57 + x], b[58 + x]); \
32 printf("%s\n", osmo_ubit_dump(b + 59 + x, 57)); \
33 if (u <= x) \
34 return; \
35 } while(0)
36
37#define DUMP_S_AT(b, x, u) do { \
38 printf("%s %02x %02x ", osmo_hexdump(b + x, 57), b[57 + x], b[58 + x]); \
39 printf("%s\n", osmo_hexdump(b + 59 + x, 57)); \
40 if (u <= x) \
41 return; \
42 } while(0)
43
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +070044/* Similar to OSMO_ASSERT, but does not panic() */
45#define CHECK_RC_OR_RET(exp, action) \
46 if (!(exp)) { \
47 printf("%s(%s): assert %s failed\n", __func__, action, #exp); \
48 return; \
49 }
50
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +070051#ifdef DEBUG
52#define printd(fmt, args...) printf(fmt, ##args)
53#else
54#define printd(fmt, args...)
55#endif
56
Pau Espin Pedrol41911d02018-02-01 12:10:33 +010057static inline void dump_ubits(ubit_t *bursts_u, unsigned until)
Max458a6f52017-11-28 17:26:54 +010058{
59 printf("U-Bits:\n");
60 DUMP_U_AT(bursts_u, 0, until);
61 DUMP_U_AT(bursts_u, 116, until);
62 DUMP_U_AT(bursts_u, 232, until);
63 DUMP_U_AT(bursts_u, 348, until);
64 DUMP_U_AT(bursts_u, 464, until);
65 DUMP_U_AT(bursts_u, 580, until);
66 DUMP_U_AT(bursts_u, 696, until);
67 DUMP_U_AT(bursts_u, 812, until);
68}
69
Pau Espin Pedrol41911d02018-02-01 12:10:33 +010070static inline void dump_sbits(uint8_t *bursts_s, unsigned until)
Max458a6f52017-11-28 17:26:54 +010071{
72 printf("S-Bits:\n");
73 DUMP_S_AT(bursts_s, 0, until);
74 DUMP_S_AT(bursts_s, 116, until);
75 DUMP_S_AT(bursts_s, 232, until);
76 DUMP_S_AT(bursts_s, 348, until);
77 DUMP_S_AT(bursts_s, 464, until);
78 DUMP_S_AT(bursts_s, 580, until);
79 DUMP_S_AT(bursts_s, 696, until);
80 DUMP_S_AT(bursts_s, 812, until);
81}
82
Vadim Yanitskiy3262f822016-09-23 01:48:59 +070083static void test_xcch(uint8_t *l2)
84{
85 uint8_t result[23];
86 ubit_t bursts_u[116 * 4];
87 sbit_t bursts_s[116 * 4];
88 int n_errors, n_bits_total;
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +070089 int rc;
Vadim Yanitskiy3262f822016-09-23 01:48:59 +070090
91 /* Encode L2 message */
Max0176b4a2017-11-28 18:04:23 +010092 printf("Encoding: %s\n", osmo_hexdump(l2, 23));
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +070093 rc = gsm0503_xcch_encode(bursts_u, l2);
94 CHECK_RC_OR_RET(rc == 0, "encoding");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +070095
96 /* Prepare soft-bits */
Max29d489f2017-11-28 14:54:32 +010097 osmo_ubit2sbit(bursts_s, bursts_u, 116 * 4);
Max458a6f52017-11-28 17:26:54 +010098 dump_ubits(bursts_u, 348);
99 dump_sbits((uint8_t *)bursts_s, 348);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700100
101 /* Destroy some bits */
102 memset(bursts_s, 0, 30);
103 memset(bursts_s + 116, 0, 30);
104
105 /* Decode, correcting errors */
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700106 rc = gsm0503_xcch_decode(result, bursts_s, &n_errors, &n_bits_total);
107 CHECK_RC_OR_RET(rc == 0, "decoding");
108
Max0176b4a2017-11-28 18:04:23 +0100109 printf("Decoded: %s\n", osmo_hexdump(result, 23));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700110 printf("xcch_decode: n_errors=%d n_bits_total=%d ber=%.2f\n",
111 n_errors, n_bits_total, (float) n_errors / n_bits_total);
112
Max33dbecb2017-11-28 19:49:05 +0100113 OSMO_ASSERT(n_bits_total == 456);
114 OSMO_ASSERT(!memcmp(l2, result, 23));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700115
Max0176b4a2017-11-28 18:04:23 +0100116 printf("\n");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700117}
118
119static void test_rach(uint8_t bsic, uint8_t ra)
120{
Maxa4785902019-03-05 11:30:39 +0100121 int rc;
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700122 uint8_t result;
123 ubit_t bursts_u[36];
124 sbit_t bursts_s[36];
125
126 /* Encode L2 message */
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700127 printd("Encoding: %02x\n", ra);
Maxa4785902019-03-05 11:30:39 +0100128 rc = gsm0503_rach_ext_encode(bursts_u, ra, bsic, false);
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700129 CHECK_RC_OR_RET(rc == 0, "encoding");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700130
131 /* Prepare soft-bits */
Max29d489f2017-11-28 14:54:32 +0100132 osmo_ubit2sbit(bursts_s, bursts_u, 36);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700133
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700134 printd("U-Bits: %s\n", osmo_ubit_dump(bursts_u, 36));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700135
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700136 printd("S-Bits: %s\n", osmo_hexdump((uint8_t *)bursts_s, 36));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700137
138 /* Destroy some bits */
139 memset(bursts_s + 6, 0, 8);
140
141 /* Decode, correcting errors */
Maxa4785902019-03-05 11:30:39 +0100142 rc = gsm0503_rach_decode_ber(&result, bursts_s, bsic, NULL, NULL);
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700143 CHECK_RC_OR_RET(rc == 0, "decoding");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700144
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700145 printd("Decoded: %02x\n", result);
Max32e56412017-10-16 14:58:00 +0200146 if (ra != result)
147 printf("FAIL [RACH]: encoded %u != %u decoded\n", ra, result);
148
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700149 printd("\n");
Max32e56412017-10-16 14:58:00 +0200150}
151
152static void test_rach_ext(uint8_t bsic, uint16_t ra)
153{
Maxa4785902019-03-05 11:30:39 +0100154 int rc;
Max32e56412017-10-16 14:58:00 +0200155 uint16_t result = 3000; /* Max ext. RA is 2^11 = 2048 */
156 ubit_t bursts_u[36];
157 sbit_t bursts_s[36];
158
159 /* Encode L2 message */
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700160 printd("Encoding: %02x\n", ra);
Maxa4785902019-03-05 11:30:39 +0100161 rc = gsm0503_rach_ext_encode(bursts_u, ra, bsic, true);
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700162 CHECK_RC_OR_RET(rc == 0, "encoding");
Max32e56412017-10-16 14:58:00 +0200163
164 /* Prepare soft-bits */
165 osmo_ubit2sbit(bursts_s, bursts_u, 36);
166
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700167 printd("U-Bits: %s\n", osmo_ubit_dump(bursts_u, 36));
Max32e56412017-10-16 14:58:00 +0200168
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700169 printd("S-Bits: %s\n", osmo_hexdump((uint8_t *)bursts_s, 36));
Max32e56412017-10-16 14:58:00 +0200170
171 /* Destroy some bits */
172 memset(bursts_s + 9, 0, 8);
173
174 /* Decode, correcting errors */
Maxa4785902019-03-05 11:30:39 +0100175 rc = gsm0503_rach_ext_decode_ber(&result, bursts_s, bsic, NULL, NULL);
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700176 CHECK_RC_OR_RET(rc == 0, "decoding");
Max32e56412017-10-16 14:58:00 +0200177
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700178 printd("Decoded: %02x\n", result);
Max32e56412017-10-16 14:58:00 +0200179 if (ra != result)
180 printf("FAIL [RACH ext]: encoded %u != %u decoded\n", ra, result);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700181
Vadim Yanitskiy0f4919e2020-03-30 18:19:17 +0700182 printd("\n");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700183}
184
Vadim Yanitskiy41ce6752020-03-31 19:15:28 +0700185static void test_rach_11bit_sample(uint8_t bsic, const sbit_t *payload)
186{
187 int n_errors, n_bits_total;
188 uint16_t ra11;
189 int rc;
190
191 /* Decode, correcting errors */
192 rc = gsm0503_rach_ext_decode_ber(&ra11, payload, bsic, &n_errors, &n_bits_total);
193 if (rc) {
194 printf("%s(): decoding failed (rc=%d)\n", __func__, rc);
195 return;
196 }
197
198 printf("Decoded RA11: 0x%03x\n", ra11);
199}
200
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700201static void test_sch(uint8_t *info)
202{
203 uint8_t result[4];
204 ubit_t bursts_u[78];
205 sbit_t bursts_s[78];
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700206 int rc;
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700207
208 /* Zero bits 25 and above */
209 info[3] &= 1;
210 result[3] = 0;
211
212 /* Encode L2 message */
Max0176b4a2017-11-28 18:04:23 +0100213 printf("Encoding: %s\n", osmo_hexdump(info, 4));
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700214 rc = gsm0503_sch_encode(bursts_u, info);
215 CHECK_RC_OR_RET(rc == 0, "encoding");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700216
217 /* Prepare soft-bits */
Max29d489f2017-11-28 14:54:32 +0100218 osmo_ubit2sbit(bursts_s, bursts_u, 78);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700219
Max0176b4a2017-11-28 18:04:23 +0100220 printf("U-Bits: %s\n", osmo_ubit_dump(bursts_u, 78));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700221
Max0176b4a2017-11-28 18:04:23 +0100222 printf("S-Bits: %s\n", osmo_hexdump((uint8_t *)bursts_s, 78));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700223
224 /* Destroy some bits */
225 memset(bursts_s + 6, 0, 10);
226
227 /* Decode, correcting errors */
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700228 rc = gsm0503_sch_decode(result, bursts_s);
229 CHECK_RC_OR_RET(rc == 0, "decoding");
230
Max0176b4a2017-11-28 18:04:23 +0100231 printf("Decoded: %s\n", osmo_hexdump(result, 4));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700232
Max33dbecb2017-11-28 19:49:05 +0100233 OSMO_ASSERT(!memcmp(info, result, 4));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700234
Max0176b4a2017-11-28 18:04:23 +0100235 printf("\n");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700236}
237
238static void test_fr(uint8_t *speech, int len)
239{
240 uint8_t result[33];
241 ubit_t bursts_u[116 * 8];
242 sbit_t bursts_s[116 * 8];
243 int n_errors, n_bits_total;
244 int rc;
245
246 memset(bursts_u, 0x23, sizeof(bursts_u));
247 memset(bursts_s, 0, sizeof(bursts_s));
248
249 /* Encode L2 message */
Max0176b4a2017-11-28 18:04:23 +0100250 printf("Encoding: %s\n", osmo_hexdump(speech, len));
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700251 rc = gsm0503_tch_fr_encode(bursts_u, speech, len, 1);
252 CHECK_RC_OR_RET(rc == 0, "encoding");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700253
254 /* Prepare soft-bits */
Max29d489f2017-11-28 14:54:32 +0100255 osmo_ubit2sbit(bursts_s, bursts_u, 116 * 8);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700256
Max458a6f52017-11-28 17:26:54 +0100257 dump_ubits(bursts_u, 812);
258 dump_sbits((uint8_t *)bursts_s, 812);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700259
260 /* Destroy some bits */
261 memset(bursts_s + 6, 0, 20);
262
263 /* Decode, correcting errors */
264 rc = gsm0503_tch_fr_decode(result, bursts_s, 1, len == 31,
265 &n_errors, &n_bits_total);
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700266 CHECK_RC_OR_RET(rc == len, "decoding");
267
Max0176b4a2017-11-28 18:04:23 +0100268 printf("Decoded: %s\n", osmo_hexdump(result, len));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700269 printf("tch_fr_decode: n_errors=%d n_bits_total=%d ber=%.2f\n",
270 n_errors, n_bits_total, (float)n_errors/n_bits_total);
271
Max33dbecb2017-11-28 19:49:05 +0100272 OSMO_ASSERT(!memcmp(speech, result, len));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700273
Max0176b4a2017-11-28 18:04:23 +0100274 printf("\n");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700275}
276
277static void test_hr(uint8_t *speech, int len)
278{
279 uint8_t result[23];
280 ubit_t bursts_u[116 * 6];
281 sbit_t bursts_s[116 * 6];
282 int n_errors, n_bits_total;
283 int rc;
284
285 memset(bursts_u, 0x23, sizeof(bursts_u));
286 memset(bursts_s, 0, sizeof(bursts_s));
287
288 /* Encode L2 message */
Max0176b4a2017-11-28 18:04:23 +0100289 printf("Encoding: %s\n", osmo_hexdump(speech, len));
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700290 rc = gsm0503_tch_hr_encode(bursts_u, speech, len);
291 CHECK_RC_OR_RET(rc == 0, "encoding");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700292
293 /* Prepare soft-bits */
Max29d489f2017-11-28 14:54:32 +0100294 osmo_ubit2sbit(bursts_s, bursts_u, 116 * 6);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700295
Max458a6f52017-11-28 17:26:54 +0100296 dump_ubits(bursts_u, 580);
297 dump_sbits((uint8_t *)bursts_s, 580);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700298
299 /* Destroy some bits */
300 memset(bursts_s + 6, 0, 20);
301
302 /* Decode, correcting errors */
Vadim Yanitskiye677fcc2023-05-25 14:52:29 +0700303 rc = gsm0503_tch_hr_decode2(result, bursts_s, 0,
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700304 &n_errors, &n_bits_total);
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700305 CHECK_RC_OR_RET(rc == len, "decoding");
306
Max0176b4a2017-11-28 18:04:23 +0100307 printf("Decoded: %s\n", osmo_hexdump(result, len));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700308 printf("tch_hr_decode: n_errors=%d n_bits_total=%d ber=%.2f\n",
309 n_errors, n_bits_total, (float)n_errors/n_bits_total);
310
Max33dbecb2017-11-28 19:49:05 +0100311 OSMO_ASSERT(!memcmp(speech, result, len));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700312
Max0176b4a2017-11-28 18:04:23 +0100313 printf("\n");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700314}
315
Vadim Yanitskiyb3340222023-05-26 01:07:18 +0700316static void test_facch(const uint8_t *data, bool half_rate)
317{
318 ubit_t bursts_u[116 * 8 * 2] = { 0 };
319 sbit_t bursts_s[116 * 8 * 2] = { 0 };
320 int rc;
321
322 /* Encode the given FACCH message three times (at different offsets) */
323 printf("%s(FACCH/%c): encoding: %s\n",
324 __func__, half_rate ? 'H' : 'F',
325 osmo_hexdump(&data[0], GSM_MACBLOCK_LEN));
326 for (unsigned int i = 0; i < 3; i++) {
327 ubit_t *pos = &bursts_u[116 * 4 * i];
328
329 if (half_rate)
330 rc = gsm0503_tch_hr_facch_encode(pos, &data[0]);
331 else
332 rc = gsm0503_tch_fr_facch_encode(pos, &data[0]);
333 CHECK_RC_OR_RET(rc == 0, "encoding");
334 }
335
336 /* Prepare soft-bits */
337 osmo_ubit2sbit(bursts_s, bursts_u, sizeof(bursts_s));
338
339 /* Decode three FACCH messages (at different offsets) */
340 for (unsigned int i = 0; i < 3; i++) {
341 const sbit_t *pos = &bursts_s[116 * 4 * i];
342 uint8_t result[GSM_MACBLOCK_LEN];
343 int n_errors, n_bits_total;
344
345 if (half_rate)
346 rc = gsm0503_tch_hr_facch_decode(&result[0], pos,
347 &n_errors, &n_bits_total);
348 else
349 rc = gsm0503_tch_fr_facch_decode(&result[0], pos,
350 &n_errors, &n_bits_total);
351 CHECK_RC_OR_RET(rc == GSM_MACBLOCK_LEN, "decoding");
352
353 printf("%s(FACCH/%c): decoded (BER=%d/%d): %s\n",
354 __func__, half_rate ? 'H' : 'F', n_errors, n_bits_total,
355 osmo_hexdump(result, GSM_MACBLOCK_LEN));
356 }
357
358 printf("\n");
359}
360
Pau Espin Pedrolce28d2e2020-04-07 16:30:57 +0200361struct test_macblock {
362 bool is_egprs;
363 uint16_t exp_burst_bits;
364 uint16_t l2_len;
365 uint8_t l2[54];
366};
367
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200368static const struct test_macblock test_macblock[] = {
Pau Espin Pedrolce28d2e2020-04-07 16:30:57 +0200369 /* Random frame */
370 { false,
371 GSM0503_GPRS_BURSTS_NBITS,
372 54,
373 { 0xa3, 0xaf, 0x5f, 0xc6, 0x36, 0x43, 0x44, 0xab,
374 0xd9, 0x6d, 0x7d, 0x62, 0x24, 0xc9, 0xd2, 0x92,
375 0xfa, 0x27, 0x5d, 0x71, 0x7a, 0x59, 0xa8, 0x42,
376 0xa3, 0xaf, 0x5f, 0xc6, 0x36, 0x43, 0x44, 0xab,
377 0xa3, 0xaf, 0x5f, 0xc6, 0x36, 0x43, 0x44, 0xab,
378 0xd9, 0x6d, 0x7d, 0x62, 0x24, 0xc9, 0xd2, 0x92,
379 0xfa, 0x27, 0x5d, 0x71, 0x7a, 0xa8 }
380 },
381 /* jolly frame */
382 { false,
383 GSM0503_GPRS_BURSTS_NBITS,
384 23,
385 { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
386 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
387 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }
388 },
389/*
390GSM RLC/MAC: EGPRS DL HEADER
391 0... .... .... 0000 = DL TFI: 0
392 0... .... crumb 1 of DL TFI (decoded above)
393 .00. .... = RRBP: Reserved Block: (N+13) mod 2715648 (0)
394 ...0 0... = ES/P: RRBP field is not valid (no Polling) (0)
395 .... .111 = USF: 7
396 01.. .... 0000 0000 .... ...0 = BSN: 1
397 01.. .... crumb 2 of BSN (decoded above)
398 ..00 .... = PR: 0 dB (included) to 3 dB (excluded) less than BCCH level - P0 (0)
399 .... 0000 crumb 0 of DL TFI (decoded above)
400 0000 0000 crumb 1 of BSN (decoded above)
401 .00. .... = SPB (DL): No retransmission (0)
402 ...1 011. = CPS: MCS-1/P1 (0x0b)
403 .... ...0 crumb 0 of BSN (decoded above)
404GSM RLC/MAC: EGPRS DL DATA BLOCK 1 (BSN 1)
405 .... ..0. = FBI: Current Block is not last RLC data block in TBF
406 .... ...0 = Extension: Extension octet follows immediately
407 0000 100. = Length Indicator: 4
408 .... ...0 = Extension: Extension octet follows immediately
409 0010 000. = Length Indicator: 16
410 .... ...1 = Extension: No extension octet follows
411 data segment: LI[0]=4 indicates: (Last segment of) LLC frame (4 octets)
412 Data (4 bytes)
413 Data: 012b2b2b
414 [Length: 4]
415 data segment: LI[1]=16 indicates: (Last segment of) LLC frame (16 octets)
416 Data (16 bytes)
417 Data: 43c0012b2b2b2b2b2b2b2b2b2b2b2b2b
418 [Length: 16]
419*/
420 { true,
421 GSM0503_GPRS_BURSTS_NBITS,
422 27,
423 { 0x07, 0x40, 0x00, 0x16, 0x10, 0x42, 0x02, 0x56,
424 0x56, 0x56, 0x86, 0x80, 0x03, 0x56, 0x56, 0x56,
425 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56,
426 0x56, 0x56, 0x00 }
427 },
428};
429
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200430static void test_pdtch(const struct test_macblock *tmb, int len)
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700431{
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200432 uint8_t l2[len], result[len];
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700433 ubit_t bursts_u[116 * 4];
434 sbit_t bursts_s[116 * 4];
435 int n_errors, n_bits_total;
436 int rc;
437
438 /* Zero the not coded tail bits */
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200439 memcpy(l2, tmb->l2, len);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700440 switch (len) {
441 case 34:
442 case 54:
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200443 l2[len - 1] &= 0x7f;
Vadim Yanitskiy74b31ac2023-12-08 03:58:36 +0700444 result[len - 1] = 0x00;
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700445 break;
446 case 40:
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200447 l2[len - 1] &= 0x07;
Vadim Yanitskiy74b31ac2023-12-08 03:58:36 +0700448 result[len - 1] = 0x00;
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700449 break;
450 }
451
452 /* Encode L2 message */
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200453 printf("Encoding: %s\n", osmo_hexdump(l2, len));
Pau Espin Pedrolce28d2e2020-04-07 16:30:57 +0200454 if (tmb->is_egprs)
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200455 rc = gsm0503_pdtch_egprs_encode(bursts_u, l2, len);
Pau Espin Pedrolce28d2e2020-04-07 16:30:57 +0200456 else
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200457 rc = gsm0503_pdtch_encode(bursts_u, l2, len);
Pau Espin Pedrolce28d2e2020-04-07 16:30:57 +0200458 CHECK_RC_OR_RET(rc == (int)tmb->exp_burst_bits, "encoding");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700459
460 /* Prepare soft-bits */
Max29d489f2017-11-28 14:54:32 +0100461 osmo_ubit2sbit(bursts_s, bursts_u, 116 * 4);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700462
Max458a6f52017-11-28 17:26:54 +0100463 dump_ubits(bursts_u, 348);
464 dump_sbits((uint8_t *)bursts_s, 348);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700465
466 /* Decode */
Pau Espin Pedrolce28d2e2020-04-07 16:30:57 +0200467 if (tmb->is_egprs) {
468 /* gsm0503_pdtch_egprs_decode() is meant to decode EGPRS UL frames, so we cannot use it here */
469 rc = gsm0503_pdtch_egprs_decode(result, bursts_s, rc, NULL, &n_errors, &n_bits_total);
470 OSMO_ASSERT(rc == -EIO);
471 return;
472 } else {
473 rc = gsm0503_pdtch_decode(result, bursts_s, NULL, &n_errors, &n_bits_total);
474 }
Vadim Yanitskiyca466cf2020-03-30 18:12:19 +0700475 CHECK_RC_OR_RET(rc == len, "decoding");
476
Max0176b4a2017-11-28 18:04:23 +0100477 printf("Decoded: %s\n", osmo_hexdump(result, len));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700478 printf("pdtch_decode: n_errors=%d n_bits_total=%d ber=%.2f\n",
479 n_errors, n_bits_total, (float)n_errors/n_bits_total);
480
Pau Espin Pedrole7d0d702020-04-09 16:16:53 +0200481 OSMO_ASSERT(!memcmp(l2, result, len));
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700482
Max0176b4a2017-11-28 18:04:23 +0100483 printf("\n");
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700484}
485
486uint8_t test_l2[][23] = {
487 /* Dummy frame */
488 { 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
491 /* Random frame */
492 { 0xa3, 0xaf, 0x5f, 0xc6, 0x36, 0x43, 0x44, 0xab,
493 0xd9, 0x6d, 0x7d, 0x62, 0x24, 0xc9, 0xd2, 0x92,
494 0xfa, 0x27, 0x5d, 0x71, 0x7a, 0x59, 0xa8 },
495 /* jolly frame */
496 { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
497 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
498 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 },
499};
500
Vadim Yanitskiy41ce6752020-03-31 19:15:28 +0700501/* 11-bit Access Burst soft-bits (payload only) from an EGPRS capable phone (BSIC 63) */
502static const sbit_t test_rach_11bit[6][36] = {
503 { 103, 109, -108, -110, 107, 108, -106, -120, -121,
504 -120, -105, 122, -104, -109, 108, 109, -109, -111,
505 107, 111, -105, -119, -121, -104, 122, -120, 121,
506 -99, -121, -120, -122, -106, 109, 109, -108, -111 },
507
508 { 103, 109, -109, -109, 106, 107, -106, -121, -121,
509 -120, -106, 121, -120, 117, -122, 101, 109, -122,
510 120, -120, 101, 118, 120, 102, -125, 101, 110,
511 -120, 121, -101, -121, -118, -121, -106, 108, 121 },
512
513 { -121, -122, -104, 123, -104, -108, 122, -104, -121,
514 -121, -102, 124, -105, -110, 107, 109, -108, -109,
515 121, -122, 101, 107, -121, 105, 108, -110, -107,
516 124, -104, -109, 120, -122, 100, 122, 104, -123 },
517
518 { -122, -123, -103, 123, -105, -109, 122, -105, -121,
519 -120, -104, 122, -120, 121, -101, -122, -120, -120,
520 -119, -105, 120, -106, -108, 123, -104, -113, 105,
521 122, 101, -122, 119, -122, 117, -121, 119, -122 },
522
523 { 105, 110, -109, -109, 107, 108, -108, -120, -120,
524 -121, -106, 121, -104, -107, 106, 108, -108, -108,
525 108, 107, -105, -120, -122, -104, 122, -119, 121,
526 -103, -122, -118, -120, -106, 108, 108, -110, -111 },
527
528 { 120, -103, -123, -104, 119, -121, 100, 123, 106,
529 -109, -107, 121, -122, 118, -121, 103, 108, -122,
530 120, -119, 121, -103, -121, -119, -121, -103, 124,
531 -106, -108, 122, -103, -106, 121, -120, 119, -121 },
532};
533
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700534uint8_t test_speech_fr[33];
535uint8_t test_speech_efr[31];
Vadim Yanitskiye677fcc2023-05-25 14:52:29 +0700536uint8_t test_speech_hr[14];
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700537
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700538struct csd_test_case {
539 const char *name;
540 unsigned int num_bits;
541 int (*enc_fn)(ubit_t *out, const ubit_t *in);
542 int (*dec_fn)(ubit_t *out, const sbit_t *in, int *ne, int *nb);
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700543 bool half_rate;
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700544};
545
546static const struct csd_test_case csd_tests[] = {
547 {
548 .name = "TCH/F9.6",
549 .num_bits = 4 * 60,
550 .enc_fn = &gsm0503_tch_fr96_encode,
551 .dec_fn = &gsm0503_tch_fr96_decode,
552 },
553 {
554 .name = "TCH/F4.8",
555 .num_bits = 2 * 60,
556 .enc_fn = &gsm0503_tch_fr48_encode,
557 .dec_fn = &gsm0503_tch_fr48_decode,
558 },
559 {
560 .name = "TCH/H4.8",
561 .num_bits = 4 * 60,
562 .enc_fn = &gsm0503_tch_hr48_encode,
563 .dec_fn = &gsm0503_tch_hr48_decode,
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700564 .half_rate = true,
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700565 },
566 {
Vadim Yanitskiyfadda012023-07-08 06:30:55 +0700567 .name = "TCH/F2.4",
568 .num_bits = 2 * 36,
569 .enc_fn = &gsm0503_tch_fr24_encode,
570 .dec_fn = &gsm0503_tch_fr24_decode,
571 },
572 {
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700573 .name = "TCH/H2.4",
Vadim Yanitskiyfadda012023-07-08 06:30:55 +0700574 .num_bits = 4 * 36,
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700575 .enc_fn = &gsm0503_tch_hr24_encode,
576 .dec_fn = &gsm0503_tch_hr24_decode,
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700577 .half_rate = true,
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700578 },
579 {
580 .name = "TCH/F14.4",
581 .num_bits = 290,
582 .enc_fn = &gsm0503_tch_fr144_encode,
583 .dec_fn = &gsm0503_tch_fr144_decode,
584 },
585};
586
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700587static void test_csd(const struct csd_test_case *tc, bool facch)
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700588{
589 const uint8_t patterns[] = { 0x00, 0xaa, 0xff };
590 ubit_t bursts_u[116 * (22 + 8)] = { 0 };
591 sbit_t bursts_s[116 * (22 + 8)] = { 0 };
592 ubit_t data[512];
593 int rc;
594
595 /* Encode three data blocks, each block filled-in with a pattern */
596 for (unsigned int i = 0; i < ARRAY_SIZE(patterns); i++) {
597 for (unsigned int j = 0; j < tc->num_bits; j++)
598 data[j] = (patterns[i] & (1 << (j % 8))) != 0;
599
600 rc = tc->enc_fn(&bursts_u[i * 4 * 116], &data[0]);
601 CHECK_RC_OR_RET(rc == 0, "encoding");
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700602
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700603 /* Test FACCH bitstealing */
604 if (facch && i == 1) {
605 memset(&data, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
606 if (tc->half_rate)
607 rc = gsm0503_tch_hr_facch_encode(&bursts_u[116 * 4], &data[0]);
608 else
609 rc = gsm0503_tch_fr_facch_encode(&bursts_u[116 * 4], &data[0]);
610 CHECK_RC_OR_RET(rc == 0, "encoding FACCH");
611 }
612 }
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700613
614 /* Prepare soft-bits */
615 osmo_ubit2sbit(&bursts_s[0], &bursts_u[0], sizeof(bursts_s));
616
617 /* Decode the soft-bits, print decoded blocks */
618 for (unsigned int i = 0; i < ARRAY_SIZE(patterns); i++) {
619 int n_errors, n_bits_total;
620
621 rc = tc->dec_fn(&data[0], &bursts_s[i * 4 * 116],
622 &n_errors, &n_bits_total);
623 CHECK_RC_OR_RET(rc == tc->num_bits, "decoding");
624
625 printf("%s(%s): block #%u (pattern 0x%02x): n_errors=%d / n_bits_total=%d\n",
626 __func__, tc->name, i, patterns[i], n_errors, n_bits_total);
627
628 for (unsigned int j = 0; j < tc->num_bits; j++) {
629 if (j && j % 64 == 0)
630 printf("\n");
631 else if (j && j % 8 == 0)
632 printf(" ");
633 printf("%c", data[j] ? '1' : '0');
634 }
635 printf("\n");
636 }
637
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700638 /* Test FACCH bitstealing if requested */
639 if (facch) {
640 int n_errors = 0, n_bits_total = 0;
641
642 if (tc->half_rate) {
643 rc = gsm0503_tch_hr_facch_decode(&data[0], &bursts_s[116 * 4],
644 &n_errors, &n_bits_total);
645 } else {
646 rc = gsm0503_tch_fr_facch_decode(&data[0], &bursts_s[116 * 4],
647 &n_errors, &n_bits_total);
648 }
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700649 CHECK_RC_OR_RET(rc == GSM_MACBLOCK_LEN, "decoding FACCH");
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700650
651 printf("%s(%s): FACCH/%c (pattern 0x2b): n_errors=%d / n_bits_total=%d\n",
652 __func__, tc->name, tc->half_rate ? 'H' : 'F', n_errors, n_bits_total);
653 printf("%s\n", osmo_hexdump(&data[0], GSM_MACBLOCK_LEN));
654 }
655
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700656 printf("\n");
657}
658
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700659int main(int argc, char **argv)
660{
661 int i, len_l2, len_mb;
662
Vadim Yanitskiy88c61c32020-03-30 20:50:49 +0700663 len_l2 = ARRAY_SIZE(test_l2);
664 len_mb = ARRAY_SIZE(test_macblock);
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700665
666 for (i = 0; i < len_l2; i++)
667 test_xcch(test_l2[i]);
668
669 for (i = 0; i < 256; i++) {
670 test_rach(0x3f, i);
671 test_rach(0x00, i);
672 test_rach(0x1a, i);
673 }
674
Max32e56412017-10-16 14:58:00 +0200675 for (i = 0; i < 2048; i++) {
676 test_rach_ext(0x3f, i);
677 test_rach_ext(0x00, i);
678 test_rach_ext(0x1a, i);
679 }
680
Vadim Yanitskiy41ce6752020-03-31 19:15:28 +0700681 for (i = 0; i < ARRAY_SIZE(test_rach_11bit); i++)
682 test_rach_11bit_sample(0x3f, test_rach_11bit[i]);
683 printf("\n");
684
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700685 for (i = 0; i < len_l2; i++)
686 test_sch(test_l2[i]);
687
688 for (i = 0; i < sizeof(test_speech_fr); i++)
689 test_speech_fr[i] = i;
690 test_speech_fr[0] = 0xd0;
691 test_fr(test_speech_fr, sizeof(test_speech_fr));
692
693 for (i = 0; i < sizeof(test_speech_efr); i++)
694 test_speech_efr[i] = i;
695 test_speech_efr[0] = 0xc0;
696 test_fr(test_speech_efr, sizeof(test_speech_efr));
697
698 for (i = 0; i < len_l2; i++)
699 test_fr(test_l2[i], sizeof(test_l2[0]));
700
701 for (i = 0; i < sizeof(test_speech_hr); i++)
702 test_speech_hr[i] = i * 17;
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700703 test_hr(test_speech_hr, sizeof(test_speech_hr));
704
705 for (i = 0; i < len_l2; i++)
706 test_hr(test_l2[i], sizeof(test_l2[0]));
707
708 for (i = 0; i < len_mb; i++) {
Pau Espin Pedrolce28d2e2020-04-07 16:30:57 +0200709 if (test_macblock[i].is_egprs) {
710 test_pdtch(&test_macblock[i], test_macblock[i].l2_len);
711 } else {
712 test_pdtch(&test_macblock[i], 23);
713 test_pdtch(&test_macblock[i], 34);
714 test_pdtch(&test_macblock[i], 40);
715 test_pdtch(&test_macblock[i], 54);
716 }
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700717 }
718
Vadim Yanitskiyb3340222023-05-26 01:07:18 +0700719 printf("\nTesting FACCH/F codec:\n");
720 for (i = 0; i < ARRAY_SIZE(test_l2); i++)
721 test_facch(test_l2[i], false);
722 printf("\nTesting FACCH/H codec:\n");
723 for (i = 0; i < ARRAY_SIZE(test_l2); i++)
724 test_facch(test_l2[i], true);
725
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700726 printf("\nTesting CSD functions (no FACCH):\n");
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700727 for (i = 0; i < ARRAY_SIZE(csd_tests); i++)
Vadim Yanitskiy31f761f2023-05-26 01:27:07 +0700728 test_csd(&csd_tests[i], false);
729 printf("\nTesting CSD functions (with FACCH):\n");
730 for (i = 0; i < ARRAY_SIZE(csd_tests); i++)
731 test_csd(&csd_tests[i], true);
Vadim Yanitskiy9a228272023-05-20 18:54:13 +0700732
Vadim Yanitskiy3262f822016-09-23 01:48:59 +0700733 printf("Success\n");
734
735 return 0;
736}