blob: 833830effa78ebe8facc9d33d9e5a8f58ecace4c [file] [log] [blame]
Vadim Yanitskiy85554db2023-03-14 20:33:51 +01001/*
2 * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
3 * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
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.
16 *
17 */
18
19#include <stdio.h>
20#include <stdint.h>
21#include <stdbool.h>
22
23#include <osmocom/core/fsm.h>
24#include <osmocom/core/bits.h>
25#include <osmocom/core/logging.h>
26#include <osmocom/core/application.h>
27
28#include <osmocom/isdn/v110.h>
29#include <osmocom/isdn/v110_ta.h>
30
31static void *test_ctx = NULL;
32
33/* inverse logic: ON = binary 0; OFF = binary 1 */
34#define V110_SX_BIT_ON 0
35#define V110_SX_BIT_OFF 1
36
37/*********************************************************************************
38 * V.110 TA configuration and callbacks
39 *********************************************************************************/
40
41static void v110_ta_test_rx_cb(void *priv, const ubit_t *buf, size_t buf_size)
42{
43 fprintf(stderr, "%s(buf_size=%zu): %s\n",
44 __func__, buf_size, osmo_ubit_dump(buf, buf_size));
45}
46
47static void v110_ta_test_tx_cb(void *priv, ubit_t *buf, size_t buf_size)
48{
49 for (size_t i = 0; i < buf_size; i++)
50 buf[i] = (i & 1);
51 fprintf(stderr, "%s(buf_size=%zu): %s\n",
52 __func__, buf_size, osmo_ubit_dump(buf, buf_size));
53}
54
55static void v110_ta_test_status_update_cb(void *priv, unsigned int status)
56{
57 fprintf(stderr, "%s(status=0x%08x)\n", __func__, status);
58}
59
60static const struct osmo_v110_ta_cfg v110_ta_test_cfg = {
61 .rate = OSMO_V110_SYNC_RA1_9600,
62 .rx_cb = &v110_ta_test_rx_cb,
63 .tx_cb = &v110_ta_test_tx_cb,
64 .status_update_cb = &v110_ta_test_status_update_cb,
65};
66
67/*********************************************************************************
68 * various helper functions
69 *********************************************************************************/
70
71static void v110_ta_test_init_df(struct osmo_v110_decoded_frame *df)
72{
73 /* quickly set all the bits to binary '1' */
74 memset(df, 1, sizeof(*df));
75 /* D-bits: 0101... pattern */
76 for (unsigned int i = 0; i < MAX_D_BITS; i += 2)
77 df->d_bits[i] = 0;
78 /* E-bits: E1/E2/E3 indicate 9600 bps */
79 df->e_bits[0] = 0;
80}
81
82static void v110_ta_test_dump_df(const struct osmo_v110_decoded_frame *df)
83{
84 fprintf(stderr, " D-bits: %s\n", osmo_ubit_dump(&df->d_bits[0], MAX_D_BITS));
85 fprintf(stderr, " E-bits: %s\n", osmo_ubit_dump(&df->e_bits[0], MAX_E_BITS));
86 fprintf(stderr, " S-bits: %s\n", osmo_ubit_dump(&df->s_bits[0], MAX_S_BITS));
87 fprintf(stderr, " X-bits: %s\n", osmo_ubit_dump(&df->x_bits[0], MAX_X_BITS));
88}
89
90static void v110_ta_test_dump_circuit(const struct osmo_v110_ta *ta,
91 enum osmo_v110_ta_circuit circuit,
92 bool exp_state)
93{
94 bool state = osmo_v110_ta_get_circuit(ta, circuit);
95
96 fprintf(stderr, "circuit %s (%s) is %s (expected to be %s)\n",
97 osmo_v110_ta_circuit_name(circuit),
98 osmo_v110_ta_circuit_desc(circuit),
99 state ? "ON" : "OFF",
100 exp_state ? "ON" : "OFF");
101}
102
103static void v110_ta_test_set_circuit(struct osmo_v110_ta *ta,
104 enum osmo_v110_ta_circuit circuit,
105 bool active)
106{
107 int rc;
108
109 fprintf(stderr, "setting circuit %s (%s) %s\n",
110 osmo_v110_ta_circuit_name(circuit),
111 osmo_v110_ta_circuit_desc(circuit),
112 active ? "ON" : "OFF");
113
114 rc = osmo_v110_ta_set_circuit(ta, circuit, active);
115 fprintf(stderr, "osmo_v110_ta_set_circuit() returns %d\n", rc);
116}
117
118/*********************************************************************************
119 * the actual tests
120 *********************************************************************************/
121
122static void test_idle_ready(void)
123{
124 struct osmo_v110_decoded_frame df = { 0 };
125 struct osmo_v110_ta *ta;
126 int rc;
127
128 fprintf(stderr, "\n==== Running %s()\n", __func__);
129
130 ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg);
131 OSMO_ASSERT(ta != NULL);
132
133 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
134
135 fprintf(stderr, "Initial status: 0x%08x\n", osmo_v110_ta_get_status(ta));
136 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, false);
137 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, false);
138 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, false);
139
140 fprintf(stderr, "osmo_v110_ta_frame_in(): all bits set to binary '1'\n");
141 memset(&df, 1, sizeof(df));
142 v110_ta_test_dump_df(&df);
143 rc = osmo_v110_ta_frame_in(ta, &df);
144 fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc);
145
146 fprintf(stderr, "osmo_v110_ta_frame_out(): expecting all bits set to binary '1'\n");
147 rc = osmo_v110_ta_frame_out(ta, &df);
148 fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc);
149 if (rc == 0)
150 v110_ta_test_dump_df(&df);
151
152 v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, true);
153 v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, false);
154 v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, true);
155
156 osmo_v110_ta_free(ta);
157}
158
159static void test_conn_ta_line(void)
160{
161 struct osmo_v110_decoded_frame df = { 0 };
162 struct osmo_v110_ta *ta;
163 int rc;
164
165 fprintf(stderr, "\n==== Running %s()\n", __func__);
166
167 ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg);
168 OSMO_ASSERT(ta != NULL);
169
170 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
171
172 v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, true);
173
174 /* we expect the TA FSM to be in V110_TA_ST_CON_TA_TO_LINE */
175
176 fprintf(stderr, "osmo_v110_ta_frame_out(): S-/X-bits are expected to be 1 (OFF)\n");
177 fprintf(stderr, "osmo_v110_ta_frame_out(): D-/E-bits are all expected to be 1\n");
178 rc = osmo_v110_ta_frame_out(ta, &df);
179 fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc);
180 if (rc == 0)
181 v110_ta_test_dump_df(&df);
182
183 /* TODO: test implicit sync by sending V110_TA_EV_RX_FRAME_IND */
184
185 fprintf(stderr, "osmo_v110_ta_sync_ind(): the lower layer indicates sync event\n");
186 osmo_v110_ta_sync_ind(ta);
187
188 fprintf(stderr, "osmo_v110_ta_frame_out(): S-/X-bits are expected to be 0 (ON)\n");
189 fprintf(stderr, "osmo_v110_ta_frame_out(): D-/E-bits are all expected to be 1\n");
190 rc = osmo_v110_ta_frame_out(ta, &df);
191 fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc);
192 if (rc == 0)
193 v110_ta_test_dump_df(&df);
194
195 fprintf(stderr, "osmo_v110_ta_frame_in(): S-/X-bits are OFF, expect no state change\n");
196 v110_ta_test_init_df(&df);
197 v110_ta_test_dump_df(&df);
198 rc = osmo_v110_ta_frame_in(ta, &df);
199 fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc);
200
201 fprintf(stderr, "osmo_v110_ta_frame_in(): S-/X-bits are ON, expect state change\n");
202 memset(&df.s_bits[0], V110_SX_BIT_ON, sizeof(df.s_bits));
203 memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits));
204 v110_ta_test_dump_df(&df);
205 rc = osmo_v110_ta_frame_in(ta, &df);
206 fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc);
207
208 /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */
209
210 osmo_v110_ta_free(ta);
211}
212
213static void _test_data_transfer_enter(struct osmo_v110_ta *ta)
214{
215 struct osmo_v110_decoded_frame df;
216 int rc;
217
218 OSMO_ASSERT(osmo_v110_ta_get_circuit(ta, OSMO_V110_TA_C_108) == false);
219
220 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
221
222 v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, true);
223
224 /* we expect the TA FSM to be in V110_TA_ST_CON_TA_TO_LINE */
225
226 fprintf(stderr, "osmo_v110_ta_sync_ind(): the lower layer indicates sync event\n");
227 osmo_v110_ta_sync_ind(ta);
228
229 fprintf(stderr, "osmo_v110_ta_frame_in(): S-/X-bits are ON, expect state change\n");
230 v110_ta_test_init_df(&df);
231 memset(&df.s_bits[0], V110_SX_BIT_ON, sizeof(df.s_bits));
232 memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits));
233 v110_ta_test_dump_df(&df);
234 rc = osmo_v110_ta_frame_in(ta, &df);
235 fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc);
236
237 /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */
238}
239
240static void test_data_transfer(void)
241{
242 struct osmo_v110_decoded_frame df = { 0 };
243 struct osmo_v110_ta *ta;
244 int rc;
245
246 fprintf(stderr, "\n==== Running %s()\n", __func__);
247
248 ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg);
249 OSMO_ASSERT(ta != NULL);
250
251 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
252
253 _test_data_transfer_enter(ta);
254
255 /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */
256
257 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, true);
258 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, true);
259 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, true);
260
261 fprintf(stderr, "osmo_v110_ta_frame_out(): S-/X-bits are expected to be 0 (ON)\n");
262 fprintf(stderr, "osmo_v110_ta_frame_out(): E1..E3-bits are expected to be 011 (9600)\n");
263 fprintf(stderr, "osmo_v110_ta_frame_out(): we also expect the .tx_cb() to be called\n");
264 rc = osmo_v110_ta_frame_out(ta, &df);
265 fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc);
266 if (rc == 0)
267 v110_ta_test_dump_df(&df);
268
269 fprintf(stderr, "osmo_v110_ta_frame_in(): feed that frame that we pulled out back into the TA\n");
270 rc = osmo_v110_ta_frame_in(ta, &df);
271 fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc);
272
273 osmo_v110_ta_free(ta);
274}
275
276static void test_data_transfer_disc_local(void)
277{
278 struct osmo_v110_decoded_frame df = { 0 };
279 struct osmo_v110_ta *ta;
280 int rc;
281
282 fprintf(stderr, "\n==== Running %s()\n", __func__);
283
284 ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg);
285 OSMO_ASSERT(ta != NULL);
286
287 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
288
289 _test_data_transfer_enter(ta);
290
291 /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */
292
293 fprintf(stderr, "local TE initiates disconnection\n");
294 v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, false);
295
296 /* we expect the TA FSM to be in V110_TA_ST_DISCONNECTING */
297
298 fprintf(stderr, "osmo_v110_ta_frame_out(): S-bits are expected to be 1 (OFF)\n");
299 fprintf(stderr, "osmo_v110_ta_frame_out(): X-bits are expected to be 0 (ON)\n");
300 fprintf(stderr, "osmo_v110_ta_frame_out(): D-bits are all expected to be 0\n");
301 rc = osmo_v110_ta_frame_out(ta, &df); /* TODO: what E-bits do we expect? */
302 fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc);
303 if (rc == 0)
304 v110_ta_test_dump_df(&df);
305
306 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, false);
307 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, true);
308 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, true);
309
310 fprintf(stderr, "osmo_v110_ta_frame_in(): S-/X-bits are ON, expect no state change\n");
311 v110_ta_test_init_df(&df);
312 memset(&df.s_bits[0], V110_SX_BIT_ON, sizeof(df.s_bits));
313 memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits));
314 v110_ta_test_dump_df(&df);
315 rc = osmo_v110_ta_frame_in(ta, &df);
316 fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc);
317
318 fprintf(stderr, "osmo_v110_ta_frame_in(): S-bits are OFF, expect state change\n");
319 v110_ta_test_init_df(&df);
320 memset(&df.s_bits[0], V110_SX_BIT_OFF, sizeof(df.s_bits));
321 memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits));
322 v110_ta_test_dump_df(&df);
323 rc = osmo_v110_ta_frame_in(ta, &df);
324 fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc);
325
326 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
327
328 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, false);
329 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, false);
330 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, false);
331
332 osmo_v110_ta_free(ta);
333}
334
335static void test_data_transfer_disc_remote(void)
336{
337 struct osmo_v110_decoded_frame df = { 0 };
338 struct osmo_v110_ta *ta;
339 int rc;
340
341 fprintf(stderr, "\n==== Running %s()\n", __func__);
342
343 ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg);
344 OSMO_ASSERT(ta != NULL);
345
346 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
347
348 _test_data_transfer_enter(ta);
349
350 /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */
351
352 fprintf(stderr, "remote TE initiates disconnection\n");
353 fprintf(stderr, "osmo_v110_ta_frame_in(): S-bits are OFF, X-bits are ON\n");
354 fprintf(stderr, "osmo_v110_ta_frame_in(): D-bits are all set to 0\n");
355 v110_ta_test_init_df(&df);
356 memset(&df.s_bits[0], V110_SX_BIT_OFF, sizeof(df.s_bits));
357 memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits));
358 memset(&df.d_bits[0], 0, sizeof(df.d_bits));
359 v110_ta_test_dump_df(&df);
360 rc = osmo_v110_ta_frame_in(ta, &df);
361 fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc);
362
363 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, false);
364 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, false);
365
366 fprintf(stderr, "local TE confirms disconnection\n");
367 v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, false);
368
369 /* we expect the TA FSM to be in V110_TA_ST_DISCONNECTING */
370
371 osmo_v110_ta_desync_ind(ta);
372
373 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
374
375 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, false);
376 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, false);
377 v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, false);
378
379 osmo_v110_ta_free(ta);
380}
381
382static void test_syncing(void)
383{
384 struct osmo_v110_decoded_frame df = { 0 };
385 struct osmo_v110_ta *ta;
386 int rc;
387
388 fprintf(stderr, "\n==== Running %s()\n", __func__);
389
390 ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg);
391 OSMO_ASSERT(ta != NULL);
392
393 /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */
394
395 _test_data_transfer_enter(ta);
396
397 /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */
398
399 fprintf(stderr, "osmo_v110_ta_sync_ind(): the lower layer indicates out-of-sync event\n");
400 osmo_v110_ta_desync_ind(ta);
401
402 /* we expect the TA FSM to be in V110_TA_ST_RESYNCING */
403
404 fprintf(stderr, "osmo_v110_ta_frame_out(): S-bits are expected to be 0 (ON)\n");
405 fprintf(stderr, "osmo_v110_ta_frame_out(): X-bits are expected to be 1 (OFF)\n");
406 fprintf(stderr, "osmo_v110_ta_frame_out(): D-bits are to be set by .tx_cb()\n");
407 rc = osmo_v110_ta_frame_out(ta, &df);
408 fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc);
409 if (rc == 0)
410 v110_ta_test_dump_df(&df);
411
412 fprintf(stderr, "osmo_v110_ta_sync_ind(): the lower layer indicates sync event\n");
413 osmo_v110_ta_sync_ind(ta);
414
415 /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */
416
417 fprintf(stderr, "osmo_v110_ta_frame_out(): S-bits are expected to be 0 (ON)\n");
418 fprintf(stderr, "osmo_v110_ta_frame_out(): X-bits are expected to be 0 (ON)\n");
419 fprintf(stderr, "osmo_v110_ta_frame_out(): D-bits are to be set by .tx_cb()\n");
420 rc = osmo_v110_ta_frame_out(ta, &df);
421 fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc);
422 if (rc == 0)
423 v110_ta_test_dump_df(&df);
424
425 osmo_v110_ta_free(ta);
426}
427
428int main(int argc, char **argv)
429{
430 test_ctx = talloc_named_const(NULL, 0, __FILE__);
431
432 osmo_init_logging2(test_ctx, NULL);
433 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
434 log_set_print_level(osmo_stderr_target, 1);
435 log_set_print_category(osmo_stderr_target, 1);
436 log_set_print_category_hex(osmo_stderr_target, 0);
437 log_set_use_color(osmo_stderr_target, 0);
438
439 osmo_fsm_log_addr(false);
440 osmo_fsm_log_timeouts(true);
441
442 log_set_category_filter(osmo_stderr_target, DLGLOBAL, 1, LOGL_DEBUG);
443
444 test_idle_ready();
445 test_conn_ta_line();
446 /* TODO: test_conn_ta_line_timeout() */
447 test_data_transfer();
448 test_data_transfer_disc_local();
449 test_data_transfer_disc_remote();
450 /* TODO: test_disc_timeout() */
451 test_syncing();
452 /* TODO: test_syncing_timeout() */
453
454 log_fini();
455 OSMO_ASSERT(talloc_total_blocks(test_ctx) == 1);
456 talloc_free(test_ctx);
457
458 return 0;
459}