blob: fe4577e568a0da02c4cad9ebb771169ac10d2e24 [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
75unsigned int string_to_ubit(ubit_t * ubits, char *string)
76{
77 unsigned int len;
78 unsigned int i;
79
80 len = strlen(string);
81
82 for (i = 0; i < len; i++) {
83 ubits[i] = string[i] & 1;
84 }
85
86 return len;
87}
88
89void test_gsm0503_detect_afs_dtx_frame(char *string)
90{
91 ubit_t ubits[512];
92 uint8_t dtx_frame_type;
93 int n_errors;
94 int n_bits_total;
95
96 string_to_ubit(ubits, string);
97 dtx_frame_type = gsm0503_detect_afs_dtx_frame(&n_errors, &n_bits_total, ubits);
98 printf(" ==> %s, n_errors=%i, n_bits_total=%i\n", gsm0503_amr_dtx_frame_name(dtx_frame_type),
99 n_errors, n_bits_total);
100}
101
102void test_gsm0503_detect_ahs_dtx_frame(char *string)
103{
104 ubit_t ubits[512];
105 uint8_t dtx_frame_type;
106 int n_errors;
107 int n_bits_total;
108
109 string_to_ubit(ubits, string);
110 dtx_frame_type = gsm0503_detect_ahs_dtx_frame(&n_errors, &n_bits_total, ubits);
111 printf(" ==> %s, n_errors=%i, n_bits_total=%i\n", gsm0503_amr_dtx_frame_name(dtx_frame_type),
112 n_errors, n_bits_total);
113}
114
Vadim Yanitskiyf673fd52022-05-18 01:16:27 +0300115static void test_gsm0503_tch_afhs_decode_dtx(const sbit_t *bursts, size_t offset,
116 enum gsm0503_amr_dtx_frames *amr_last_dtx,
117 bool full_rate, const char *test_desc)
118{
119 uint8_t tch_data[128]; /* just to be safe */
120 int n_errors = 0, n_bits_total = 0;
121 int rc;
122
123 printf("Running %s(at offset=%zu): testing %s\n", __func__, offset, test_desc);
124
125 /* Dummy (not really important) values */
126 uint8_t codec[4] = { 0, 1, 2, 3 };
127 int codecs = ARRAY_SIZE(codec);
128 uint8_t ul_cmr = 0;
129 uint8_t ul_ft = 0;
130
131 if (full_rate) {
132 rc = gsm0503_tch_afs_decode_dtx(&tch_data[0], &bursts[offset], false,
133 codec, codecs, &ul_ft, &ul_cmr,
134 &n_errors, &n_bits_total,
135 (uint8_t *)amr_last_dtx);
136 } else {
137 rc = gsm0503_tch_ahs_decode_dtx(&tch_data[0], &bursts[offset], false, false,
138 codec, codecs, &ul_ft, &ul_cmr,
139 &n_errors, &n_bits_total,
140 (uint8_t *)amr_last_dtx);
141 }
142 printf(" ==> gsm0503_tch_a%cs_decode_dtx() yields '%s' (rc=%d, BER %d/%d)\n",
143 full_rate ? 'f' : 'h', gsm0503_amr_dtx_frame_name(*amr_last_dtx),
144 rc, n_errors, n_bits_total);
145 if (rc > 0)
146 printf(" ====> tch_data[] = { %s }\n", osmo_hexdump_nospc(tch_data, rc));
147}
148
149static void test_gsm0503_tch_afhs_decode_dtx_sid_update(void)
150{
151 enum gsm0503_amr_dtx_frames amr_last_dtx = AMR_OTHER;
152 sbit_t bursts[BURST_PLEN * 12]; /* 12 bursts */
153 int rc;
154
155 /* 456 soft-bits containing an AFS_SID_UPDATE frame (captured on the air) */
156 const char *afs_sid_update = \
157 "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"
158 "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"
159 "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"
160 "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"
161 "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"
162 "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"
163 "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"
164 "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"
165 "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"
166 "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"
167 "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"
168 "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"
169 "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"
170 "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"
171 "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"
172 "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";
173
174 memset(&bursts[0], 0, sizeof(bursts));
175 rc = osmo_hexparse(afs_sid_update, (uint8_t *)&bursts[BURST_PLEN * 4], BURST_PLEN * 8);
176 OSMO_ASSERT(rc == BURST_PLEN * 4);
177
178 /* Test detection of AFS_SID_UPDATE (marker) */
179 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 0, &amr_last_dtx, true /* AFS */,
180 "detection of AFS_SID_UPDATE");
181
182 /* Test decoding of AFS_SID_UPDATE_CN (actual SID) */
183 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 4, &amr_last_dtx, true /* AFS */,
184 "decoding of AFS_SID_UPDATE");
185
186 /* 456 soft-bits containing an AHS_SID_UPDATE frame (captured on the air) */
187 const char *ahs_sid_update = \
188 "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"
189 "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"
190 "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"
191 "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"
192 "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"
193 "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"
194 "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"
195 "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"
196 "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"
197 "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"
198 "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"
199 "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"
200 "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"
201 "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"
202 "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"
203 "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";
204
205 memset(&bursts[0], 0, sizeof(bursts));
206 rc = osmo_hexparse(ahs_sid_update, (uint8_t *)&bursts[BURST_PLEN * 2], BURST_PLEN * 10);
207 OSMO_ASSERT(rc == BURST_PLEN * 4);
208
209 /* Test detection and decoding of AHS_SID_UPDATE */
210 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 0, &amr_last_dtx, false /* AHS */,
211 "detection/decoding of AHS_SID_UPDATE");
212 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 2, &amr_last_dtx, false /* AHS */,
213 "detection/decoding of AHS_SID_UPDATE");
214 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 4, &amr_last_dtx, false /* AHS */,
215 "detection/decoding of AHS_SID_UPDATE");
216}
217
Vadim Yanitskiy32aff352022-05-18 02:23:25 +0300218static void test_gsm0503_tch_afhs_decode_dtx_facch(void)
219{
220 enum gsm0503_amr_dtx_frames amr_last_dtx;
221 sbit_t bursts[BURST_PLEN * 8]; /* 8 bursts */
222 unsigned int i;
223
224 /* Set stealing bits to provoke FACCH/[FH] detection */
225 for (i = 0; i < 8; i++) {
226 sbit_t *burst = &bursts[BURST_PLEN * i];
227 memset(&burst[0], 0, BURST_PLEN);
228 burst[i >> 2 ? 57 : 58] = -127;
229 }
230
231 amr_last_dtx = AFS_SID_UPDATE;
232 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 0,
233 &amr_last_dtx, true /* AFS */,
234 "tagging of FACCH/F");
235 OSMO_ASSERT(amr_last_dtx == AMR_OTHER);
236
237 amr_last_dtx = AHS_SID_UPDATE;
238 test_gsm0503_tch_afhs_decode_dtx(&bursts[0], BURST_PLEN * 0,
239 &amr_last_dtx, false /* AHS */,
240 "tagging of FACCH/H");
241 OSMO_ASSERT(amr_last_dtx == AMR_OTHER);
242}
243
Philipp Maier898c9c62020-02-06 14:25:01 +0100244int main(int argc, char **argv)
245{
246 printf("FR AMR DTX FRAMES:\n");
247 test_gsm0503_detect_afs_dtx_frame(sample_afs_sid_frame);
248 test_gsm0503_detect_afs_dtx_frame(sample_afs_sid_update_frame);
249 test_gsm0503_detect_afs_dtx_frame(sample_afs_onset_frame);
250 printf("HR AMR DTX FRAMES:\n");
251 test_gsm0503_detect_ahs_dtx_frame(sample_ahs_sid_update_frame);
252 test_gsm0503_detect_ahs_dtx_frame(sample_ahs_sid_first_p1_frame);
253 test_gsm0503_detect_ahs_dtx_frame(sample_ahs_sid_first_p2_frame);
254 test_gsm0503_detect_ahs_dtx_frame(sample_ahs_onset_frame);
255 test_gsm0503_detect_ahs_dtx_frame(sample_sid_first_inh_frame);
256 test_gsm0503_detect_ahs_dtx_frame(sample_sid_update_inh_frame);
257
Vadim Yanitskiyf673fd52022-05-18 01:16:27 +0300258 test_gsm0503_tch_afhs_decode_dtx_sid_update();
Vadim Yanitskiy32aff352022-05-18 02:23:25 +0300259 test_gsm0503_tch_afhs_decode_dtx_facch();
Vadim Yanitskiyf673fd52022-05-18 01:16:27 +0300260
Philipp Maier898c9c62020-02-06 14:25:01 +0100261 return EXIT_SUCCESS;
262}