blob: 21d1751ef9c885298139da8b26eba15836c83f51 [file] [log] [blame]
Philipp Maier898c9c62020-02-06 14:25:01 +01001/*
2 * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
3 * Author: Philipp Maier <pmaier@sysmocom.de>
4 * All Rights Reserved
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 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 General Public License for more details.
17 *
Philipp Maier898c9c62020-02-06 14:25:01 +010018 */
19
20#include <string.h>
21#include <stdio.h>
22#include <stdint.h>
23#include <osmocom/core/utils.h>
Vadim Yanitskiyf673fd52022-05-18 01:16:27 +030024#include <osmocom/coding/gsm0503_coding.h>
Philipp Maier898c9c62020-02-06 14:25:01 +010025#include <osmocom/coding/gsm0503_amr_dtx.h>
26
Vadim Yanitskiyf673fd52022-05-18 01:16:27 +030027/* Length of payload bits in a Normal Burst */
28#define BURST_PLEN (57 * 2 + 2)
29
Philipp Maier898c9c62020-02-06 14:25:01 +010030char sample_afs_sid_frame[] =
31 {
32"111111110000000011001100101010100100010011111111001000100111011110011001001100111100110010011001111011100100010011111111001000100111011110011001001100111100110010011001111011100100010011111111001000100111011110011001001100111100110010011001111011100100010011111111001000100111011110011001001100111100110010011001111011100100010011111111001000100111011110011001001100111100110010011001111011100100010011111111001000100111011110011001001100111100110010011001"
33};
34
35char sample_afs_sid_update_frame[] =
36 {
37"111111110000000011001100101010100000010000001111111100101011011110001001000000110111110000001001011111101111010011001111100000101000011111001001111100110111110011111001001111101100010001001111000000100100011100111001100000111000110000111001010011101111010011111111010000101100011100111001111100110111110011111001110011101000010010001111110000100000011111001001011100110011110010111001101111100011010001111111001100100100011111111001000000110000110000001001"
38};
39
40char sample_afs_onset_frame[] =
41 {
42"111111110000000011001100101010100000111100000000111111000100101000111111100000000111110010001010001111110100000011111100111110100100111111000000110011001011101001001111011100001011110000001010010011111100000000111100111110101000111110110000111111000000101011111111010000001100110000111010111111111000000010111100000010100100111100110000100011001000101000111111101100001011110000111010011111110011000010111100101110101100111111000000010011001111101000001111"
43};
44
45char sample_ahs_sid_update_frame[] =
46 {
47"111100001100101010110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110000110110100011001000011010000000000000001111010010000000000001000000000010110000000011001000000000000000100000101000000000000000001010100000010010000000000010000111110001110110110011001101000000000100100011001000001010000100100000000011"
48};
49
50char sample_ahs_sid_first_p1_frame[] =
51 {
52"111100001100101001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001111001001001011010110001101100101001110001111001110100110010000111101110110110000100100011111001001110000011110110001010010101100001010100000111101110110001010000111110001110110110011001101001111000011101001010011100011000111010110000011"
53};
54
55char sample_ahs_sid_first_p2_frame[] =
56 {
57"111110100100000010100000110111001110101100000100101001011101100011101010010000001010010010001100101010100100010111110101110011011110101000010100111000001001110111101110010101001110000010001101101011110000000011100100110110011111100011001000001101100101001110001111001110100110010000111101110110110000100100011111001001110000011110110001010010101100001010100000111101110110001010000111110001110110110011001101001111000011101001010011100011000111010110000011"
58};
59
60char sample_ahs_onset_frame[] =
61 {
62"111101011000101001010000111001000111011110000000011110001110010011011111100000101101101001101110011111010000000001010010110001101101110100000010011110101100010001011101101010000111100011101100111101011010100011110010110001001111100011001000011010000000000000001010010010000000000001000000000000100000000011001000000000000000100000101000000000000000010010000101010010000000000010101100111110101000110110011001000000000100100011001000001010000100100000001100"
63};
64
65char sample_sid_first_inh_frame[] =
66 {
67"xBxBxBxBxBxBxBxBxBxBxBxBxBxBxBxBx1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0x0x0x0x1x1x0x1x1x0"
68};
69
70char sample_sid_update_inh_frame[] =
71 {
72"xBxBxBxBxBxBxBxBxBxBxBxBxBxBxBxBx0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1x1x1x1x0x0x1x0x0x1"
73};
74
Vadim Yanitskiycc4213e2022-05-24 04:17:23 +070075unsigned int string_to_sbit(sbit_t *sbits, char *string)
Philipp Maier898c9c62020-02-06 14:25:01 +010076{
77 unsigned int len;
78 unsigned int i;
79
80 len = strlen(string);
81
82 for (i = 0; i < len; i++) {
Vadim Yanitskiycc4213e2022-05-24 04:17:23 +070083 sbits[i] = string[i] == '1' ? -127 : 127;
Philipp Maier898c9c62020-02-06 14:25:01 +010084 }
85
86 return len;
87}
88
89void test_gsm0503_detect_afs_dtx_frame(char *string)
90{
Vadim Yanitskiycc4213e2022-05-24 04:17:23 +070091 sbit_t sbits[512];
Philipp Maier898c9c62020-02-06 14:25:01 +010092 uint8_t dtx_frame_type;
93 int n_errors;
94 int n_bits_total;
Vadim Yanitskiycc4213e2022-05-24 04:17:23 +070095 int mode_id = -1;
Philipp Maier898c9c62020-02-06 14:25:01 +010096
Vadim Yanitskiycc4213e2022-05-24 04:17:23 +070097 string_to_sbit(sbits, string);
98 dtx_frame_type = gsm0503_detect_afs_dtx_frame2(&n_errors, &n_bits_total, &mode_id, sbits);
99 printf(" ==> %s, n_errors=%d, n_bits_total=%d, mode_id=%d\n",
100 gsm0503_amr_dtx_frame_name(dtx_frame_type),
101 n_errors, n_bits_total, mode_id);
Philipp Maier898c9c62020-02-06 14:25:01 +0100102}
103
104void test_gsm0503_detect_ahs_dtx_frame(char *string)
105{
Vadim Yanitskiycc4213e2022-05-24 04:17:23 +0700106 sbit_t sbits[512];
Philipp Maier898c9c62020-02-06 14:25:01 +0100107 uint8_t dtx_frame_type;
108 int n_errors;
109 int n_bits_total;
Vadim Yanitskiycc4213e2022-05-24 04:17:23 +0700110 int mode_id = -1;
Philipp Maier898c9c62020-02-06 14:25:01 +0100111
Vadim Yanitskiycc4213e2022-05-24 04:17:23 +0700112 string_to_sbit(sbits, string);
113 dtx_frame_type = gsm0503_detect_ahs_dtx_frame2(&n_errors, &n_bits_total, &mode_id, sbits);
114 printf(" ==> %s, n_errors=%d, n_bits_total=%d, mode_id=%d\n",
115 gsm0503_amr_dtx_frame_name(dtx_frame_type),
116 n_errors, n_bits_total, mode_id);
Philipp Maier898c9c62020-02-06 14:25:01 +0100117}
118
Vadim Yanitskiyf673fd52022-05-18 01:16:27 +0300119static void test_gsm0503_tch_afhs_decode_dtx(const sbit_t *bursts, size_t offset,
120 enum gsm0503_amr_dtx_frames *amr_last_dtx,
121 bool full_rate, const char *test_desc)
122{
123 uint8_t tch_data[128]; /* just to be safe */
124 int n_errors = 0, n_bits_total = 0;
125 int rc;
126
127 printf("Running %s(at offset=%zu): testing %s\n", __func__, offset, test_desc);
128
129 /* Dummy (not really important) values */
130 uint8_t codec[4] = { 0, 1, 2, 3 };
131 int codecs = ARRAY_SIZE(codec);
132 uint8_t ul_cmr = 0;
133 uint8_t ul_ft = 0;
134
135 if (full_rate) {
136 rc = gsm0503_tch_afs_decode_dtx(&tch_data[0], &bursts[offset], false,
137 codec, codecs, &ul_ft, &ul_cmr,
138 &n_errors, &n_bits_total,
139 (uint8_t *)amr_last_dtx);
140 } else {
141 rc = gsm0503_tch_ahs_decode_dtx(&tch_data[0], &bursts[offset], false, false,
142 codec, codecs, &ul_ft, &ul_cmr,
143 &n_errors, &n_bits_total,
144 (uint8_t *)amr_last_dtx);
145 }
146 printf(" ==> gsm0503_tch_a%cs_decode_dtx() yields '%s' (rc=%d, BER %d/%d)\n",
147 full_rate ? 'f' : 'h', gsm0503_amr_dtx_frame_name(*amr_last_dtx),
148 rc, n_errors, n_bits_total);
149 if (rc > 0)
150 printf(" ====> tch_data[] = { %s }\n", osmo_hexdump_nospc(tch_data, rc));
151}
152
153static void test_gsm0503_tch_afhs_decode_dtx_sid_update(void)
154{
155 enum gsm0503_amr_dtx_frames amr_last_dtx = AMR_OTHER;
156 sbit_t bursts[BURST_PLEN * 12]; /* 12 bursts */
157 int rc;
158
159 /* 456 soft-bits containing an AFS_SID_UPDATE frame (captured on the air) */
160 const char *afs_sid_update = \
161 "94 81 83 76 7b 81 6b 7f 76 8c 81 81 81 86 71 7f 75 81 6d 7a 81 6b 7f 78 8a 87 70 75 8e"
162 "81 8d 7f 81 70 72 81 7f 85 86 7f 93 81 8a 74 7f 71 89 8a 75 7f 7f 78 8c 81 8b 7f 81 7f"
163 "7f 7f 70 8a 8b 7f 90 81 81 81 8a 77 7f 7f 70 81 70 71 86 8e 7f 81 7f 81 75 72 87 8c 76"
164 "7f 72 8e 81 81 81 81 92 7f 8c 81 92 7f 8c 89 7f 81 7f 8f 8b 77 76 86 8c 78 73 88 81 8b"
165 "81 7f 8c 85 77 7b 8d 81 81 81 8b 7f 81 7f 8e 81 8e 7f 8a 8a 7f 93 85 6b 7f 7f 72 81 6f"
166 "76 89 81 81 81 8a 73 7f 72 88 87 73 7f 73 81 7f 81 7f 92 87 73 78 81 6f 7f 71 81 76 77"
167 "6f 81 7f 81 71 7f 6e 81 75 77 83 81 81 90 7f 8b 88 76 76 8a 8d 76 74 81 7f 92 81 81 8b"
168 "78 72 81 77 76 81 6c 7c 8b 81 81 8d 7f 8b 81 8e 74 7f 7f 72 81 7f 81 74 7f 71 81 75 7f"
169 "8e 81 81 8c 72 79 85 8c 78 75 8c 8a 7f 90 81 8e 77 77 81 70 7f 7f 71 81 7f 81 7f 8e 89"
170 "7f 8f 81 8f 7f 8c 8d 7f 81 7f 81 6f 7f 71 8a 87 7f 81 6f 77 81 7f 8d 88 73 79 8a 8a 7f"
171 "7f 7f 7f 7f 76 8b 81 8c 77 7c 8a 81 91 7f 81 76 79 81 71 7f 7f 6f 84 8e 78 7f 7f 7f 74"
172 "88 86 7b 77 81 6f 7f 7f 7f 7f 7f 75 81 70 7f 76 89 81 81 81 8d 78 74 84 81 8e 7f 8d 8a"
173 "7f 79 8c 87 7f 81 7f 81 6f 7f 75 8d 8a 7f 81 7f 92 81 81 85 76 7f 6f 8c 88 6c 7f 73 91"
174 "81 8d 71 7f 7f 73 8d 88 7f 81 7f 91 86 6f 7f 73 8e 81 8d 79 78 81 72 74 8c 86 72 7f 77"
175 "6e 81 7f 81 77 76 81 72 74 81 6f 7f 6f 8d 81 91 7f 81 6d 7f 6d 81 6c 7f 6c 81 7f 81 7f"
176 "8c 8b 7f 8e 89 74 74 8c 81 81 81 81 81 92 7f 8e 8b 7f 93 81 8f 7f 90 81 8d 74 7b 8b 89";
177
178 memset(&bursts[0], 0, sizeof(bursts));
179 rc = osmo_hexparse(afs_sid_update, (uint8_t *)&bursts[BURST_PLEN * 4], BURST_PLEN * 8);
180 OSMO_ASSERT(rc == BURST_PLEN * 4);
181
182 /* Test detection of AFS_SID_UPDATE (marker) */
183 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 0, &amr_last_dtx, true /* AFS */,
184 "detection of AFS_SID_UPDATE");
185
186 /* Test decoding of AFS_SID_UPDATE_CN (actual SID) */
187 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 4, &amr_last_dtx, true /* AFS */,
188 "decoding of AFS_SID_UPDATE");
189
190 /* 456 soft-bits containing an AHS_SID_UPDATE frame (captured on the air) */
191 const char *ahs_sid_update = \
192 "81 67 7f 7f 7f 71 8f 88 6f 73 81 7e 81 6b 7f 7e 7d 6f 8f 8a 72 76 92 81 82 81 8f 6d 6f"
193 "81 7f 92 8c 7f 97 81 8e 6f 7f 7c 7f 6e 81 7e 81 6e 73 81 7f 93 8d 6f 7f 6c 81 6b 7f 72"
194 "7c 7c 7d 7f 6f 8f 81 94 7f 92 8d 6e 7d 7d 7f 6c 8b 8e 73 71 81 7f 92 90 7f 81 6e 6e 81"
195 "7f 94 8e 70 7f 6e 8c 8d 77 7f 6a 81 7f 81 70 6d 81 6c 71 8c 91 7f 90 8e 73 6e 81 6d 7f"
196 "81 8b 71 6e 81 7f 82 7c 81 7f 81 6d 73 81 6c 6d 81 6d 7f 6e 81 7e 81 6b 7f 7f 7f 6b 81"
197 "6e 6f 81 68 7f 71 91 81 82 81 8e 70 7f 7c 7d 7f 70 81 7f 91 8f 7f 81 6c 7f 71 81 6d 74"
198 "6f 8f 81 92 7f 82 7f 91 8b 7f 81 6b 7f 6d 81 6b 6f 81 6f 6e 90 81 81 92 7f 94 81 95 7f"
199 "96 81 96 70 7f 72 8f 81 95 7f 81 6f 70 81 7f 90 92 7f 81 6c 70 81 6b 7f 6f 8d 8d 7f 81"
200 "77 81 6a 7e 7e 73 92 8c 7f 81 6a 7f 6c 8e 8e 6e 7f 71 8e 8d 7e 81 6d 7f 6c 81 6d 6c 81"
201 "7f 94 81 92 7f 97 81 92 6e 7f 70 8c 8b 73 73 91 81 93 7f 81 70 72 81 7d 81 71 70 81 7f"
202 "7d 7f 6d 90 8d 73 76 92 81 92 6f 7d 7d 70 91 81 8f 73 75 8c 90 7f 94 81 91 70 7f 7d 7e"
203 "70 8d 8d 73 7f 7c 7e 6a 81 7e 81 6d 7f 6a 81 6f 7f 7f 71 8e 81 82 81 81 81 96 72 7e 7d"
204 "81 8d 7f 81 68 7f 7e 7c 7b 7f 6c 81 6a 7f 7f 71 8f 8d 7f 81 6c 72 8e 88 70 70 81 6d 70"
205 "8d 90 7f 81 7e 95 81 94 7f 92 8b 6e 7f 7f 70 8c 8c 73 75 91 81 91 6d 7d 7e 7b 7c 7d 71"
206 "6c 89 91 7f 81 7f 95 81 93 7f 95 90 7f 81 6d 70 81 6f 75 8c 8e 75 71 81 6e 70 8d 8d 7f"
207 "91 92 7f 81 7f 94 8d 70 71 81 6e 6d 81 6e 75 8e 81 93 70 7f 70 8f 8c 7f 81 6d 6f 81 6a";
208
209 memset(&bursts[0], 0, sizeof(bursts));
210 rc = osmo_hexparse(ahs_sid_update, (uint8_t *)&bursts[BURST_PLEN * 2], BURST_PLEN * 10);
211 OSMO_ASSERT(rc == BURST_PLEN * 4);
212
213 /* Test detection and decoding of AHS_SID_UPDATE */
214 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 0, &amr_last_dtx, false /* AHS */,
215 "detection/decoding of AHS_SID_UPDATE");
216 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 2, &amr_last_dtx, false /* AHS */,
217 "detection/decoding of AHS_SID_UPDATE");
218 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 4, &amr_last_dtx, false /* AHS */,
219 "detection/decoding of AHS_SID_UPDATE");
220}
221
Vadim Yanitskiy32aff352022-05-18 02:23:25 +0300222static void test_gsm0503_tch_afhs_decode_dtx_facch(void)
223{
224 enum gsm0503_amr_dtx_frames amr_last_dtx;
225 sbit_t bursts[BURST_PLEN * 8]; /* 8 bursts */
226 unsigned int i;
227
228 /* Set stealing bits to provoke FACCH/[FH] detection */
229 for (i = 0; i < 8; i++) {
230 sbit_t *burst = &bursts[BURST_PLEN * i];
231 memset(&burst[0], 0, BURST_PLEN);
232 burst[i >> 2 ? 57 : 58] = -127;
233 }
234
235 amr_last_dtx = AFS_SID_UPDATE;
236 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 0,
237 &amr_last_dtx, true /* AFS */,
238 "tagging of FACCH/F");
239 OSMO_ASSERT(amr_last_dtx == AMR_OTHER);
240
241 amr_last_dtx = AHS_SID_UPDATE;
242 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 0,
243 &amr_last_dtx, false /* AHS */,
244 "tagging of FACCH/H");
245 OSMO_ASSERT(amr_last_dtx == AMR_OTHER);
246}
247
Philipp Maier898c9c62020-02-06 14:25:01 +0100248int main(int argc, char **argv)
249{
250 printf("FR AMR DTX FRAMES:\n");
251 test_gsm0503_detect_afs_dtx_frame(sample_afs_sid_frame);
252 test_gsm0503_detect_afs_dtx_frame(sample_afs_sid_update_frame);
253 test_gsm0503_detect_afs_dtx_frame(sample_afs_onset_frame);
254 printf("HR AMR DTX FRAMES:\n");
255 test_gsm0503_detect_ahs_dtx_frame(sample_ahs_sid_update_frame);
256 test_gsm0503_detect_ahs_dtx_frame(sample_ahs_sid_first_p1_frame);
257 test_gsm0503_detect_ahs_dtx_frame(sample_ahs_sid_first_p2_frame);
258 test_gsm0503_detect_ahs_dtx_frame(sample_ahs_onset_frame);
259 test_gsm0503_detect_ahs_dtx_frame(sample_sid_first_inh_frame);
260 test_gsm0503_detect_ahs_dtx_frame(sample_sid_update_inh_frame);
261
Vadim Yanitskiyf673fd52022-05-18 01:16:27 +0300262 test_gsm0503_tch_afhs_decode_dtx_sid_update();
Vadim Yanitskiy32aff352022-05-18 02:23:25 +0300263 test_gsm0503_tch_afhs_decode_dtx_facch();
Vadim Yanitskiyf673fd52022-05-18 01:16:27 +0300264
Philipp Maier898c9c62020-02-06 14:25:01 +0100265 return EXIT_SUCCESS;
266}