diff options
Diffstat (limited to 'tests/v110/ta_test.c')
-rw-r--r-- | tests/v110/ta_test.c | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/tests/v110/ta_test.c b/tests/v110/ta_test.c new file mode 100644 index 00000000..833830ef --- /dev/null +++ b/tests/v110/ta_test.c @@ -0,0 +1,459 @@ +/* + * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/fsm.h> +#include <osmocom/core/bits.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/application.h> + +#include <osmocom/isdn/v110.h> +#include <osmocom/isdn/v110_ta.h> + +static void *test_ctx = NULL; + +/* inverse logic: ON = binary 0; OFF = binary 1 */ +#define V110_SX_BIT_ON 0 +#define V110_SX_BIT_OFF 1 + +/********************************************************************************* + * V.110 TA configuration and callbacks + *********************************************************************************/ + +static void v110_ta_test_rx_cb(void *priv, const ubit_t *buf, size_t buf_size) +{ + fprintf(stderr, "%s(buf_size=%zu): %s\n", + __func__, buf_size, osmo_ubit_dump(buf, buf_size)); +} + +static void v110_ta_test_tx_cb(void *priv, ubit_t *buf, size_t buf_size) +{ + for (size_t i = 0; i < buf_size; i++) + buf[i] = (i & 1); + fprintf(stderr, "%s(buf_size=%zu): %s\n", + __func__, buf_size, osmo_ubit_dump(buf, buf_size)); +} + +static void v110_ta_test_status_update_cb(void *priv, unsigned int status) +{ + fprintf(stderr, "%s(status=0x%08x)\n", __func__, status); +} + +static const struct osmo_v110_ta_cfg v110_ta_test_cfg = { + .rate = OSMO_V110_SYNC_RA1_9600, + .rx_cb = &v110_ta_test_rx_cb, + .tx_cb = &v110_ta_test_tx_cb, + .status_update_cb = &v110_ta_test_status_update_cb, +}; + +/********************************************************************************* + * various helper functions + *********************************************************************************/ + +static void v110_ta_test_init_df(struct osmo_v110_decoded_frame *df) +{ + /* quickly set all the bits to binary '1' */ + memset(df, 1, sizeof(*df)); + /* D-bits: 0101... pattern */ + for (unsigned int i = 0; i < MAX_D_BITS; i += 2) + df->d_bits[i] = 0; + /* E-bits: E1/E2/E3 indicate 9600 bps */ + df->e_bits[0] = 0; +} + +static void v110_ta_test_dump_df(const struct osmo_v110_decoded_frame *df) +{ + fprintf(stderr, " D-bits: %s\n", osmo_ubit_dump(&df->d_bits[0], MAX_D_BITS)); + fprintf(stderr, " E-bits: %s\n", osmo_ubit_dump(&df->e_bits[0], MAX_E_BITS)); + fprintf(stderr, " S-bits: %s\n", osmo_ubit_dump(&df->s_bits[0], MAX_S_BITS)); + fprintf(stderr, " X-bits: %s\n", osmo_ubit_dump(&df->x_bits[0], MAX_X_BITS)); +} + +static void v110_ta_test_dump_circuit(const struct osmo_v110_ta *ta, + enum osmo_v110_ta_circuit circuit, + bool exp_state) +{ + bool state = osmo_v110_ta_get_circuit(ta, circuit); + + fprintf(stderr, "circuit %s (%s) is %s (expected to be %s)\n", + osmo_v110_ta_circuit_name(circuit), + osmo_v110_ta_circuit_desc(circuit), + state ? "ON" : "OFF", + exp_state ? "ON" : "OFF"); +} + +static void v110_ta_test_set_circuit(struct osmo_v110_ta *ta, + enum osmo_v110_ta_circuit circuit, + bool active) +{ + int rc; + + fprintf(stderr, "setting circuit %s (%s) %s\n", + osmo_v110_ta_circuit_name(circuit), + osmo_v110_ta_circuit_desc(circuit), + active ? "ON" : "OFF"); + + rc = osmo_v110_ta_set_circuit(ta, circuit, active); + fprintf(stderr, "osmo_v110_ta_set_circuit() returns %d\n", rc); +} + +/********************************************************************************* + * the actual tests + *********************************************************************************/ + +static void test_idle_ready(void) +{ + struct osmo_v110_decoded_frame df = { 0 }; + struct osmo_v110_ta *ta; + int rc; + + fprintf(stderr, "\n==== Running %s()\n", __func__); + + ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg); + OSMO_ASSERT(ta != NULL); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + fprintf(stderr, "Initial status: 0x%08x\n", osmo_v110_ta_get_status(ta)); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, false); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, false); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, false); + + fprintf(stderr, "osmo_v110_ta_frame_in(): all bits set to binary '1'\n"); + memset(&df, 1, sizeof(df)); + v110_ta_test_dump_df(&df); + rc = osmo_v110_ta_frame_in(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc); + + fprintf(stderr, "osmo_v110_ta_frame_out(): expecting all bits set to binary '1'\n"); + rc = osmo_v110_ta_frame_out(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc); + if (rc == 0) + v110_ta_test_dump_df(&df); + + v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, true); + v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, false); + v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, true); + + osmo_v110_ta_free(ta); +} + +static void test_conn_ta_line(void) +{ + struct osmo_v110_decoded_frame df = { 0 }; + struct osmo_v110_ta *ta; + int rc; + + fprintf(stderr, "\n==== Running %s()\n", __func__); + + ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg); + OSMO_ASSERT(ta != NULL); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, true); + + /* we expect the TA FSM to be in V110_TA_ST_CON_TA_TO_LINE */ + + fprintf(stderr, "osmo_v110_ta_frame_out(): S-/X-bits are expected to be 1 (OFF)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): D-/E-bits are all expected to be 1\n"); + rc = osmo_v110_ta_frame_out(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc); + if (rc == 0) + v110_ta_test_dump_df(&df); + + /* TODO: test implicit sync by sending V110_TA_EV_RX_FRAME_IND */ + + fprintf(stderr, "osmo_v110_ta_sync_ind(): the lower layer indicates sync event\n"); + osmo_v110_ta_sync_ind(ta); + + fprintf(stderr, "osmo_v110_ta_frame_out(): S-/X-bits are expected to be 0 (ON)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): D-/E-bits are all expected to be 1\n"); + rc = osmo_v110_ta_frame_out(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc); + if (rc == 0) + v110_ta_test_dump_df(&df); + + fprintf(stderr, "osmo_v110_ta_frame_in(): S-/X-bits are OFF, expect no state change\n"); + v110_ta_test_init_df(&df); + v110_ta_test_dump_df(&df); + rc = osmo_v110_ta_frame_in(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc); + + fprintf(stderr, "osmo_v110_ta_frame_in(): S-/X-bits are ON, expect state change\n"); + memset(&df.s_bits[0], V110_SX_BIT_ON, sizeof(df.s_bits)); + memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits)); + v110_ta_test_dump_df(&df); + rc = osmo_v110_ta_frame_in(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc); + + /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */ + + osmo_v110_ta_free(ta); +} + +static void _test_data_transfer_enter(struct osmo_v110_ta *ta) +{ + struct osmo_v110_decoded_frame df; + int rc; + + OSMO_ASSERT(osmo_v110_ta_get_circuit(ta, OSMO_V110_TA_C_108) == false); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, true); + + /* we expect the TA FSM to be in V110_TA_ST_CON_TA_TO_LINE */ + + fprintf(stderr, "osmo_v110_ta_sync_ind(): the lower layer indicates sync event\n"); + osmo_v110_ta_sync_ind(ta); + + fprintf(stderr, "osmo_v110_ta_frame_in(): S-/X-bits are ON, expect state change\n"); + v110_ta_test_init_df(&df); + memset(&df.s_bits[0], V110_SX_BIT_ON, sizeof(df.s_bits)); + memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits)); + v110_ta_test_dump_df(&df); + rc = osmo_v110_ta_frame_in(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc); + + /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */ +} + +static void test_data_transfer(void) +{ + struct osmo_v110_decoded_frame df = { 0 }; + struct osmo_v110_ta *ta; + int rc; + + fprintf(stderr, "\n==== Running %s()\n", __func__); + + ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg); + OSMO_ASSERT(ta != NULL); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + _test_data_transfer_enter(ta); + + /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */ + + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, true); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, true); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, true); + + fprintf(stderr, "osmo_v110_ta_frame_out(): S-/X-bits are expected to be 0 (ON)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): E1..E3-bits are expected to be 011 (9600)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): we also expect the .tx_cb() to be called\n"); + rc = osmo_v110_ta_frame_out(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc); + if (rc == 0) + v110_ta_test_dump_df(&df); + + fprintf(stderr, "osmo_v110_ta_frame_in(): feed that frame that we pulled out back into the TA\n"); + rc = osmo_v110_ta_frame_in(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc); + + osmo_v110_ta_free(ta); +} + +static void test_data_transfer_disc_local(void) +{ + struct osmo_v110_decoded_frame df = { 0 }; + struct osmo_v110_ta *ta; + int rc; + + fprintf(stderr, "\n==== Running %s()\n", __func__); + + ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg); + OSMO_ASSERT(ta != NULL); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + _test_data_transfer_enter(ta); + + /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */ + + fprintf(stderr, "local TE initiates disconnection\n"); + v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, false); + + /* we expect the TA FSM to be in V110_TA_ST_DISCONNECTING */ + + fprintf(stderr, "osmo_v110_ta_frame_out(): S-bits are expected to be 1 (OFF)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): X-bits are expected to be 0 (ON)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): D-bits are all expected to be 0\n"); + rc = osmo_v110_ta_frame_out(ta, &df); /* TODO: what E-bits do we expect? */ + fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc); + if (rc == 0) + v110_ta_test_dump_df(&df); + + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, false); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, true); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, true); + + fprintf(stderr, "osmo_v110_ta_frame_in(): S-/X-bits are ON, expect no state change\n"); + v110_ta_test_init_df(&df); + memset(&df.s_bits[0], V110_SX_BIT_ON, sizeof(df.s_bits)); + memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits)); + v110_ta_test_dump_df(&df); + rc = osmo_v110_ta_frame_in(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc); + + fprintf(stderr, "osmo_v110_ta_frame_in(): S-bits are OFF, expect state change\n"); + v110_ta_test_init_df(&df); + memset(&df.s_bits[0], V110_SX_BIT_OFF, sizeof(df.s_bits)); + memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits)); + v110_ta_test_dump_df(&df); + rc = osmo_v110_ta_frame_in(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, false); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, false); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, false); + + osmo_v110_ta_free(ta); +} + +static void test_data_transfer_disc_remote(void) +{ + struct osmo_v110_decoded_frame df = { 0 }; + struct osmo_v110_ta *ta; + int rc; + + fprintf(stderr, "\n==== Running %s()\n", __func__); + + ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg); + OSMO_ASSERT(ta != NULL); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + _test_data_transfer_enter(ta); + + /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */ + + fprintf(stderr, "remote TE initiates disconnection\n"); + fprintf(stderr, "osmo_v110_ta_frame_in(): S-bits are OFF, X-bits are ON\n"); + fprintf(stderr, "osmo_v110_ta_frame_in(): D-bits are all set to 0\n"); + v110_ta_test_init_df(&df); + memset(&df.s_bits[0], V110_SX_BIT_OFF, sizeof(df.s_bits)); + memset(&df.x_bits[0], V110_SX_BIT_ON, sizeof(df.x_bits)); + memset(&df.d_bits[0], 0, sizeof(df.d_bits)); + v110_ta_test_dump_df(&df); + rc = osmo_v110_ta_frame_in(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_in() returns %d\n", rc); + + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, false); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, false); + + fprintf(stderr, "local TE confirms disconnection\n"); + v110_ta_test_set_circuit(ta, OSMO_V110_TA_C_108, false); + + /* we expect the TA FSM to be in V110_TA_ST_DISCONNECTING */ + + osmo_v110_ta_desync_ind(ta); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_106, false); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_107, false); + v110_ta_test_dump_circuit(ta, OSMO_V110_TA_C_109, false); + + osmo_v110_ta_free(ta); +} + +static void test_syncing(void) +{ + struct osmo_v110_decoded_frame df = { 0 }; + struct osmo_v110_ta *ta; + int rc; + + fprintf(stderr, "\n==== Running %s()\n", __func__); + + ta = osmo_v110_ta_alloc(test_ctx, __func__, &v110_ta_test_cfg); + OSMO_ASSERT(ta != NULL); + + /* we expect the TA FSM to be in V110_TA_ST_IDLE_READY */ + + _test_data_transfer_enter(ta); + + /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */ + + fprintf(stderr, "osmo_v110_ta_sync_ind(): the lower layer indicates out-of-sync event\n"); + osmo_v110_ta_desync_ind(ta); + + /* we expect the TA FSM to be in V110_TA_ST_RESYNCING */ + + fprintf(stderr, "osmo_v110_ta_frame_out(): S-bits are expected to be 0 (ON)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): X-bits are expected to be 1 (OFF)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): D-bits are to be set by .tx_cb()\n"); + rc = osmo_v110_ta_frame_out(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc); + if (rc == 0) + v110_ta_test_dump_df(&df); + + fprintf(stderr, "osmo_v110_ta_sync_ind(): the lower layer indicates sync event\n"); + osmo_v110_ta_sync_ind(ta); + + /* we expect the TA FSM to be in V110_TA_ST_DATA_TRANSFER */ + + fprintf(stderr, "osmo_v110_ta_frame_out(): S-bits are expected to be 0 (ON)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): X-bits are expected to be 0 (ON)\n"); + fprintf(stderr, "osmo_v110_ta_frame_out(): D-bits are to be set by .tx_cb()\n"); + rc = osmo_v110_ta_frame_out(ta, &df); + fprintf(stderr, "osmo_v110_ta_frame_out() returns %d\n", rc); + if (rc == 0) + v110_ta_test_dump_df(&df); + + osmo_v110_ta_free(ta); +} + +int main(int argc, char **argv) +{ + test_ctx = talloc_named_const(NULL, 0, __FILE__); + + osmo_init_logging2(test_ctx, NULL); + log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE); + log_set_print_level(osmo_stderr_target, 1); + log_set_print_category(osmo_stderr_target, 1); + log_set_print_category_hex(osmo_stderr_target, 0); + log_set_use_color(osmo_stderr_target, 0); + + osmo_fsm_log_addr(false); + osmo_fsm_log_timeouts(true); + + log_set_category_filter(osmo_stderr_target, DLGLOBAL, 1, LOGL_DEBUG); + + test_idle_ready(); + test_conn_ta_line(); + /* TODO: test_conn_ta_line_timeout() */ + test_data_transfer(); + test_data_transfer_disc_local(); + test_data_transfer_disc_remote(); + /* TODO: test_disc_timeout() */ + test_syncing(); + /* TODO: test_syncing_timeout() */ + + log_fini(); + OSMO_ASSERT(talloc_total_blocks(test_ctx) == 1); + talloc_free(test_ctx); + + return 0; +} |