blob: 664dc984c62e1542d1d0fe04fc23b95ddf05538c [file] [log] [blame]
Harald Welte6879bb02020-05-02 22:27:14 +02001/* Dummy TRX for sening PRBS test sequences into osmo-bts-trx to test
2 * the decoder/receiver processing in osmo-bts-trx as well as any
3 * additional PRBS testing code.
4 *
5 * The purpose of this program is to use it as a mock dummy MS-side
6 * transmitter of GSM bursts that contain encoded PRBS sequences,
7 * similar to what one would normally do with an arbitrary
8 * function/waveform generator or BERT tester in hardware.
9 *
10 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
11 * All Rights Reserved
12 *
13 * Licensed under terms of the GNU Generral Public License, Version 2,
14 * or (at your option) any later version.
15 */
16
17#include <stdint.h>
18#include <string.h>
19#include <stdio.h>
20#include <errno.h>
21#include <unistd.h>
22
23#include <netinet/in.h>
24
25#include <osmocom/core/bits.h>
26#include <osmocom/core/utils.h>
27#include <osmocom/core/prbs.h>
28#include <osmocom/core/socket.h>
29#include <osmocom/gsm/gsm_utils.h>
30#include <osmocom/coding/gsm0503_coding.h>
31
32/***********************************************************************
33 * GSM Constants
34 ***********************************************************************/
35
36#define GSM_FR_BYTES 33
37#define GSM_BURST_BITS 116
38#define GSM_4BURST_BITS (GSM_BURST_BITS*4)
39#define GSM_BURST_LEN 148
40
41
42/***********************************************************************
43 * TRX Interface / Protocol
44 ***********************************************************************/
45
46#define TRX_BASE_PORT 5700
47/* DATA port on the TRX side */
48#define TRX_PORT_CTRL_TRX(C) (TRX_BASE_PORT+(2*(C))+1)
49#define TRX_PORT_DATA_TRX(C) (TRX_BASE_PORT+(2*(C))+2)
50#define TRX_PORT_CTRL_BTS(C) (TRX_PORT_CTRL_TRX(C)+100)
51#define TRX_PORT_DATA_BTS(C) (TRX_PORT_DATA_TRX(C)+100)
52
53struct trx_ul_msg {
54 uint8_t ts;
55 uint32_t fn;
56 uint8_t rssi;
57 uint16_t t_offs;
Harald Welte546516d2017-12-02 23:01:29 +010058 uint8_t bits[148]; /* 0..255, *NOT* sbit_t */
Harald Welte6879bb02020-05-02 22:27:14 +020059} __attribute__((packed));
60
61struct trx_dl_msg {
62 uint8_t ts;
63 uint32_t fn;
64 uint8_t att_db;
65 ubit_t bits[148];
66} __attribute__((packed));
67
68
69/***********************************************************************
70 * Helper Functions
71 ***********************************************************************/
72
73static int ubits2trxbits(uint8_t *sbits, const ubit_t *ubits, unsigned int count)
74{
75 unsigned int i;
76
77 for (i = 0; i < count; i++) {
78 if ((*ubits++) & 1) {
79 *sbits++ = 255;
80 } else {
81 *sbits++ = 0;
82 }
83 }
84
85 return count;
86}
87
88static int __attribute__((__unused__)) dec(const ubit_t *bursts_u)
89{
90 sbit_t bursts_s[GSM_4BURST_BITS*2];
91 uint8_t dec_tch_data[GSM_FR_BYTES];
92 int n_errors, n_bits_total;
93 int rc;
94
95 /* convert from u_bit (tx) to s_bit (rx) */
96 osmo_ubit2sbit(bursts_s, bursts_u, sizeof(bursts_s));
97
98 rc = gsm0503_tch_fr_decode(dec_tch_data, bursts_s, 1, 0, &n_errors, &n_bits_total);
99 printf("rc=%d, n_errors=%d, n_bits_total=%d: %s\n", rc, n_errors, n_bits_total,
100 osmo_hexdump(dec_tch_data, sizeof(dec_tch_data)));
101
102 return rc;
103}
104
105/*! \brief Training Sequences (TS 05.02 Chapter 5.2.3) */
106static const ubit_t _sched_tsc[8][26] = {
107 { 0,0,1,0,0,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,1,0,1,1,1, },
108 { 0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,0,1,0,1,1,0,1,1,1, },
109 { 0,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,0,0,0,1,1,1,0, },
110 { 0,1,0,0,0,1,1,1,1,0,1,1,0,1,0,0,0,1,0,0,0,1,1,1,1,0, },
111 { 0,0,0,1,1,0,1,0,1,1,1,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1, },
112 { 0,1,0,0,1,1,1,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,1,0,1,0, },
113 { 1,0,1,0,0,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,0,1,1,1,1,1, },
114 { 1,1,1,0,1,1,1,1,0,0,0,1,0,0,1,0,1,1,1,0,1,1,1,1,0,0, },
115};
116
117/***********************************************************************
118 * state + processing functions
119 ***********************************************************************/
120
121/* state we have to keep for one physical channel */
122struct pchan_data {
123 /* PRBS state */
124 struct osmo_prbs_state st;
125 /* unpacked PRBS bits, generated from PRBS */
126 ubit_t prbs_u[4+260];
127 /* packed frame (to be sent) */
128 uint8_t tch_data[GSM_FR_BYTES];
129 /* burst bits (ubit) to be transmitted */
130 ubit_t bursts[GSM_4BURST_BITS*2]; /* 116 * 8 */
131 /* burst bits (sbit) 'as if received' */
132 sbit_t bursts_s[GSM_4BURST_BITS*2];
133 /* next to-be transmitted burst number */
134 unsigned int burst_nr;
135 /* training sequence code */
136 unsigned int tsc;
Harald Welte546516d2017-12-02 23:01:29 +0100137
138 /* loose 'count' bursts every 'nth_mframe' on TRX-BTS interface */
139 struct {
140 unsigned int count;
141 unsigned int nth_mframe;
142 } sim_lost_bursts;
143
144 /* zero 'count' bursts every 'nth_mframe' on TRX-BTS interface */
145 struct {
146 unsigned int count;
147 unsigned int nth_mframe;
148 } sim_zero_bursts;
149
150 /* flip every 'nth_bit' of the PRNG oudput before encoding */
151 struct {
152 unsigned int nth_bit;
153 unsigned int i;
154 } sim_flip_codec_bits;
155
156 unsigned int i;
Harald Welte6879bb02020-05-02 22:27:14 +0200157};
158
159struct ts_data {
160 struct pchan_data pchan[2];
161};
162
163struct trx_data {
164 struct ts_data ts[8];
165};
166
167static struct trx_data g_trx_data;
168
169/* initialize the state for one TRX */
170static void trx_data_init(struct trx_data *trx)
171{
172 int i;
173
174 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
175 struct ts_data *ts = &trx->ts[i];
176 int j;
177 for (j = 0; j < ARRAY_SIZE(ts->pchan); j++) {
178 struct pchan_data *pchan = &ts->pchan[j];
179
180 memset(pchan, 0, sizeof(*pchan));
181 osmo_prbs_state_init(&pchan->st, &osmo_prbs9);
182 pchan->tsc = 7;
183 }
184 }
185}
186
Harald Welte546516d2017-12-02 23:01:29 +0100187/* apply any intentional errors to the output of the PRBS sequence */
188static void apply_errors_prbs(struct pchan_data *pchan)
189{
Harald Weltecf35c372020-05-07 23:55:56 +0200190 int i;
191
192 for (i = 0; i < sizeof(pchan->prbs_u)-4; i++) {
Harald Welte546516d2017-12-02 23:01:29 +0100193 pchan->sim_flip_codec_bits.i++;
194 if (pchan->sim_flip_codec_bits.i == pchan->sim_flip_codec_bits.nth_bit) {
195 pchan->sim_flip_codec_bits.i = 0;
196 pchan->prbs_u[4+i] ^= 0x01;
197 }
198 }
199}
200
Harald Welte6879bb02020-05-02 22:27:14 +0200201/*! obtain the next to-be-transmitted burst for the given pchan
202 * \param pchan physical channel on which we operate
203 * \param[in] fn frame number
204 * \param[out] burst_out caller-provided buffer for 148 unpacked output bits
205 * \retruns number of bits stored in \a burst_out */
206static int pchan_get_next_burst(struct pchan_data *pchan, uint32_t fn, ubit_t *burst_out)
207{
208 uint32_t fn26 = fn % 26;
209 int rc;
210
211 if (fn26 == 0 || fn26 == 4 || fn26 == 8 || fn26 == 13 || fn26 == 17 || fn26 == 21)
212 pchan->burst_nr = 0;
213
214 if (fn26 == 12 || fn26 == 25) {
215 memset(burst_out, 0, GSM_BURST_LEN);
216 return GSM_BURST_LEN;
217 }
218
219 if (pchan->burst_nr == 0) {
220 /* generate PRBS output in ubit format, skipping first nibble for 260-264 padding */
221 const uint8_t prefix[] = { 0xd0 };
222 osmo_pbit2ubit(pchan->prbs_u, prefix, 4);
223 rc = osmo_prbs_get_ubits(pchan->prbs_u+4, sizeof(pchan->prbs_u)-4, &pchan->st);
224 OSMO_ASSERT(rc == sizeof(pchan->prbs_u)-4);
Harald Welte546516d2017-12-02 23:01:29 +0100225
226 apply_errors_prbs(pchan);
227
Harald Welte6879bb02020-05-02 22:27:14 +0200228 /* pack to PBIT format */
229 rc = osmo_ubit2pbit(pchan->tch_data, pchan->prbs_u, sizeof(pchan->prbs_u));
230 //memset(pchan->tch_data, 0xff, sizeof(pchan->tch_data));
231
232 printf("%s\n", osmo_hexdump(pchan->tch_data, GSM_FR_BYTES));
233
234 /* shift buffer by 4 bursts for interleaving */
235 memcpy(pchan->bursts, pchan->bursts + GSM_4BURST_BITS, GSM_4BURST_BITS);
236 memset(pchan->bursts + GSM_4BURST_BITS, 0, GSM_4BURST_BITS);
237
238 /* encode block (codec frame) into four bursts */
239 rc = gsm0503_tch_fr_encode(pchan->bursts, pchan->tch_data, GSM_FR_BYTES, 1);
240 OSMO_ASSERT(rc == 0);
Harald Welte546516d2017-12-02 23:01:29 +0100241#if 0
Harald Weltecf35c372020-05-07 23:55:56 +0200242 int i;
243 for (i = 0; i < sizeof(pchan->bursts); i += GSM_BURST_BITS)
Harald Welte6879bb02020-05-02 22:27:14 +0200244 printf("\t%s\n", osmo_ubit_dump(pchan->bursts + i, GSM_BURST_BITS));
245
Harald Welte546516d2017-12-02 23:01:29 +0100246 dec(pchan->bursts);
247#endif
Harald Welte6879bb02020-05-02 22:27:14 +0200248 }
249
250 /* for all bursts: format 148 symbols from 116 input bits */
251 ubit_t *burst = pchan->bursts + pchan->burst_nr * GSM_BURST_BITS;
Harald Welte546516d2017-12-02 23:01:29 +0100252// printf("TX(%u): %s\n", pchan->burst_nr, osmo_ubit_dump(burst, GSM_BURST_BITS));
Harald Welte6879bb02020-05-02 22:27:14 +0200253 memset(burst_out, 0, 3); /* guard bits */
254 memcpy(burst_out+3, burst, 58); /* firrst half */
255 memcpy(burst_out+61, _sched_tsc[pchan->tsc], 26); /* midamble */
256 memcpy(burst_out+87, burst+58, 58); /* second half */
257 memset(burst_out+145, 0, 3); /* guard bits */
258
259 /* increment burst number for next call */
260 pchan->burst_nr += 1;
Harald Welte6879bb02020-05-02 22:27:14 +0200261
262 return GSM_BURST_LEN;
263}
264
265static int pchan_process_ts_fn(struct pchan_data *pchan, uint32_t fn, uint8_t *burst_t)
266{
267 ubit_t burst_u[GSM_BURST_LEN];
268 int rc;
269
270 rc = pchan_get_next_burst(pchan, fn, burst_u);
271 OSMO_ASSERT(rc == sizeof(burst_u));
272
273 /* convert from u_bit (tx) to s_bit (rx) */
274 ubits2trxbits(burst_t, burst_u, GSM_BURST_LEN);
275
276 return GSM_BURST_LEN;
277}
278
279/* read TRX DL data from BTS, write TRX UL data to BTS */
280static int read_and_process(int fd)
281{
282 /* receive (downlink) buffer */
283 uint8_t rx_dl_buf[1024];
284 struct trx_dl_msg *dl_msg = (struct trx_dl_msg *) rx_dl_buf;
285 /* transmit (uplink) buffer */
286 uint8_t tx_ul_buf[1024];
287 struct trx_ul_msg *ul_msg = (struct trx_ul_msg *) tx_ul_buf;
288 /* other variables */
289 struct pchan_data *pchan;
Harald Welte546516d2017-12-02 23:01:29 +0100290 uint32_t fn;
Harald Welte6879bb02020-05-02 22:27:14 +0200291 uint8_t rc;
292
293 /* do a blocking read on the socket and receive DL from BTS */
294 rc = read(fd, rx_dl_buf, sizeof(rx_dl_buf));
295 if (rc < sizeof(*dl_msg))
296 return rc;
297
Harald Welte546516d2017-12-02 23:01:29 +0100298 fn = ntohl(dl_msg->fn);
Harald Welte6879bb02020-05-02 22:27:14 +0200299
300 if (dl_msg->ts >= ARRAY_SIZE(g_trx_data.ts))
301 return -ENODEV;
302
303 if (dl_msg->ts != 2)
304 return 0;
305
Harald Welte546516d2017-12-02 23:01:29 +0100306 printf("FN=%s TS=%u\n", gsm_fn_as_gsmtime_str(fn), dl_msg->ts);
Harald Welte6879bb02020-05-02 22:27:14 +0200307
308 /* FIXME: second pchan for TCH/H */
309 pchan = &g_trx_data.ts[dl_msg->ts].pchan[0];
310
Harald Welte546516d2017-12-02 23:01:29 +0100311 rc = pchan_process_ts_fn(pchan, fn, (uint8_t *) ul_msg->bits);
Harald Welte6879bb02020-05-02 22:27:14 +0200312 OSMO_ASSERT(rc == sizeof(ul_msg->bits));
313
314 /* copy over timeslot and frame number */
Harald Welte546516d2017-12-02 23:01:29 +0100315 ul_msg->fn = htonl(fn);
Harald Welte6879bb02020-05-02 22:27:14 +0200316 ul_msg->ts = dl_msg->ts;
317
Harald Welte546516d2017-12-02 23:01:29 +0100318 /* simulate lost frames on TRX <-> BTS interface */
319 if (pchan->sim_lost_bursts.count) {
320 /* count number of 26-multiframes */
321 static int count = 0;
322 if (fn % 26 == 0)
323 count++;
324
325 /* every 10th multiframe, drop two entire block of 8 bursts */
326 if (count % pchan->sim_lost_bursts.nth_mframe == 0 &&
327 (fn % 26) <= pchan->sim_lost_bursts.count) {
328 printf("===> SKIPPING BURST\n");
329 return 0;
330 }
331 }
332
333 /* simulate zero-ed frames on TRX <-> BTS interface */
334 if (pchan->sim_zero_bursts.count) {
335 /* count number of 26-multiframes */
336 static int count = 0;
337 if (fn % 26 == 0)
338 count++;
339
340 /* every 10th multiframe, drop two entire block of 8 bursts */
341 if (count % pchan->sim_zero_bursts.nth_mframe == 0 &&
342 (fn % 26) <= pchan->sim_zero_bursts.count) {
343 memset(ul_msg->bits, 0, sizeof(ul_msg->bits));
344 printf("===> ZEROING BURST\n");
345 }
346 }
347
Harald Welte6879bb02020-05-02 22:27:14 +0200348 /* write uplink message towards BTS */
349 rc = write(fd, tx_ul_buf, sizeof(*ul_msg));
350 if (rc < sizeof(*ul_msg))
351 return -EIO;
352
353 return 0;
354}
355
356static int open_trx_data_sock(unsigned int trx_nr, const char *bts_host)
357{
358 int rc;
359
360 rc = osmo_sock_init2(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, TRX_PORT_DATA_TRX(trx_nr),
361 bts_host, TRX_PORT_DATA_BTS(trx_nr),
362 OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_BIND);
363 return rc;
364}
365
366
367int main(int argc, char **argv)
368{
369 int fd;
370
371 trx_data_init(&g_trx_data);
372
Harald Welte546516d2017-12-02 23:01:29 +0100373 //g_trx_data.ts[2].pchan[0].sim_zero_bursts.count = 8;
374 //g_trx_data.ts[2].pchan[0].sim_zero_bursts.nth_mframe = 10;
375 g_trx_data.ts[2].pchan[0].sim_flip_codec_bits.nth_bit = 260*4;
376
Harald Welte6879bb02020-05-02 22:27:14 +0200377 fd = open_trx_data_sock(0, "127.0.0.1");
378 if (fd < 0)
379 exit(1);
380
381 while (1) {
382 read_and_process(fd);
383 }
384
385 return 0;
386}