diff options
Diffstat (limited to 'tests/soft_uart')
-rw-r--r-- | tests/soft_uart/soft_uart_test.c | 658 | ||||
-rw-r--r-- | tests/soft_uart/soft_uart_test.ok | 278 |
2 files changed, 936 insertions, 0 deletions
diff --git a/tests/soft_uart/soft_uart_test.c b/tests/soft_uart/soft_uart_test.c new file mode 100644 index 00000000..7280bdcd --- /dev/null +++ b/tests/soft_uart/soft_uart_test.c @@ -0,0 +1,658 @@ +/* + * (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 <errno.h> +#include <stdio.h> +#include <stdint.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/soft_uart.h> + +#define SUART_TEST_BEGIN \ + do { \ + printf("\nExecuting %s\n", __func__); \ + } while (0) + +static struct { + size_t data_len; + const uint8_t *data; +} g_tx_cb_cfg; + +static void suart_rx_cb(void *priv, struct msgb *msg, unsigned int flags) +{ + fprintf(stdout, "%s(flags=%02x): %s\n", + __func__, flags, msgb_hexdump(msg)); + msgb_free(msg); +} + +static void suart_tx_cb(void *priv, struct msgb *msg) +{ + size_t n_bytes; + + n_bytes = OSMO_MIN(g_tx_cb_cfg.data_len, msg->data_len); + if (g_tx_cb_cfg.data != NULL && n_bytes > 0) + memcpy(msgb_put(msg, n_bytes), g_tx_cb_cfg.data, n_bytes); + + fprintf(stdout, "%s(len=%u/%u): %s\n", + __func__, msg->len, msg->data_len, msgb_hexdump(msg)); +} + +static void suart_status_change_cb(void *priv, unsigned int status) +{ + fprintf(stdout, "%s(status=0x%08x)\n", __func__, status); +} + +static const struct osmo_soft_uart_cfg suart_test_default_cfg = { + .num_data_bits = 8, + .num_stop_bits = 1, + .parity_mode = OSMO_SUART_PARITY_NONE, + .rx_buf_size = 128, + .rx_cb = &suart_rx_cb, + .tx_cb = &suart_tx_cb, + .status_change_cb = &suart_status_change_cb, +}; + +static void test_rx_exec(struct osmo_soft_uart *suart, + const char *input) +{ + for (unsigned int i = 0; input[i] != '\0'; i++) { + ubit_t ubit; + int rc; + + switch (input[i]) { + case '0': + case '1': + ubit = input[i] - '0'; + rc = osmo_soft_uart_rx_ubits(suart, &ubit, 1); + OSMO_ASSERT(rc == 0); /* 0 on success */ + break; + case 'F': + printf("%s() @ %u: flush the Rx buffer\n", __func__, i); + osmo_soft_uart_flush_rx(suart); + break; + case ' ': /* padding */ + continue; + default: + printf("%s() @ %u: unknown opcode '%c'\n", + __func__, i, input[i]); + break; + } + } +} + +static void test_rx(void) +{ + struct osmo_soft_uart_cfg cfg; + struct osmo_soft_uart *suart; + + SUART_TEST_BEGIN; + + suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg); + OSMO_ASSERT(suart != NULL); + + osmo_soft_uart_set_rx(suart, true); + + printf("======== testing 8-N-1 (no data)\n"); + test_rx_exec(suart, "F11111F11111F"); + + printf("======== testing 8-N-1 (fill up flush)\n"); + cfg = suart_test_default_cfg; + cfg.rx_buf_size = 4; + osmo_soft_uart_configure(suart, &cfg); + test_rx_exec(suart, "11111" /* no data */ + "0 01111011 1" + "0 10110101 1" + "0 01111101 1" + "0 11110111 1" /* filled up, expect flush */ + "0 00000000 1" + "0 01010101 1" + "0 10101010 1" + "0 11111111 1" /* filled up, expect flush */ + "F" /* flush! (for sanity) */ + ); + + printf("======== testing 8-N-1 (HELLO)\n"); + cfg = suart_test_default_cfg; + cfg.num_stop_bits = 1; + osmo_soft_uart_configure(suart, &cfg); + test_rx_exec(suart, "111111" /* no data */ + "0 00010010 1F" /* 'H', flush! */ + "0 10100010 1F" /* 'E', flush! */ + "1111111111111" /* no data */ + "0 00110010 1F" /* 'L', flush! */ + "0 00110010 1F" /* 'L', flush! */ + "1111111111111" /* no data */ + "0 11110010 1F" /* 'O', flush! */ + ); + + printf("======== testing 8-N-1 (framing errors)\n"); + test_rx_exec(suart, "11111" /* no data */ + "0 00000000 0" /* stop bit != 1, expect flush */ + "0 01010101 0" /* stop bit != 1, expect flush */ + "0 11111111 1" /* stop bit == 1, recovery */ + "F" /* flush! */ + ); + + printf("======== testing 8-N-2 (HELLO)\n"); + cfg = suart_test_default_cfg; + cfg.num_stop_bits = 2; + osmo_soft_uart_configure(suart, &cfg); + test_rx_exec(suart, "11111111" /* no data */ + "0 00010010 1F1F" /* 'H', flush! */ + "0 10100010 1F1F" /* 'E', flush! */ + "111111111111111" /* no data */ + "0 00110010 1F1F" /* 'L', flush! */ + "0 00110010 1F1F" /* 'L', flush! */ + "111111111111111" /* no data */ + "0 11110010 1F1F" /* 'O', flush! */ + ); + + printf("======== testing 8-N-2 (framing errors)\n"); + test_rx_exec(suart, "11111" /* no data */ + "0 00000000 00" /* stop bit != 1, expect flush */ + "0 01010101 01" /* stop bit != 1, expect flush */ + "0 10101010 10" /* stop bit != 1, expect flush */ + "0 11111111 11" /* stop bit == 1, recovery */ + "F" /* flush! (for sanity) */ + ); + + + printf("======== testing 8-E-1 (invalid parity)\n"); + cfg = suart_test_default_cfg; + cfg.parity_mode = OSMO_SUART_PARITY_EVEN; + osmo_soft_uart_configure(suart, &cfg); + test_rx_exec(suart, "1111111" /* no data */ + "0 00000000 1 1" /* odd parity, expect flush */ + "0 10000000 0 1" /* odd parity, expect flush */ + "0 11111111 1 1" /* odd parity, expect flush */ + "F" /* flush! (for sanity) */ + ); + printf("======== testing 8-E-1 (valid parity)\n"); + test_rx_exec(suart, "1111111" /* no data */ + "0 00000000 0 1" + "0 11111111 0 1" + "0 01010101 0 1" + "0 10101010 0 1" + "F" /* flush! */ + "0 00000001 1 1" + "0 00000111 1 1" + "0 00011111 1 1" + "0 01111111 1 1" + "F" /* flush! */ + ); + + printf("======== testing 8-O-1 (invalid parity)\n"); + cfg = suart_test_default_cfg; + cfg.parity_mode = OSMO_SUART_PARITY_ODD; + osmo_soft_uart_configure(suart, &cfg); + test_rx_exec(suart, + "0 00000000 0 1" /* even parity, expect flush */ + "0 10000000 1 1" /* even parity, expect flush */ + "0 11111111 0 1" /* even parity, expect flush */ + "F" /* flush! (for sanity) */ + ); + printf("======== testing 8-O-1 (valid parity)\n"); + test_rx_exec(suart, "1111111" /* no data */ + "0 00000000 1 1" + "0 11111111 1 1" + "0 01010101 1 1" + "0 10101010 1 1" + "F" /* flush! */ + "0 00000001 0 1" + "0 00000111 0 1" + "0 00011111 0 1" + "0 01111111 0 1" + "F" /* flush! */ + ); + + osmo_soft_uart_free(suart); +} + +static void test_rx_flush(void) +{ + struct osmo_soft_uart_cfg cfg; + struct osmo_soft_uart *suart; + + SUART_TEST_BEGIN; + + suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg); + OSMO_ASSERT(suart != NULL); + + printf("calling osmo_soft_uart_flush_rx() while Rx disabled\n"); + osmo_soft_uart_flush_rx(suart); + + printf("enabling the receiver\n"); + osmo_soft_uart_set_rx(suart, true); + + printf("calling osmo_soft_uart_flush_rx() while Rx enabled, but no data\n"); + osmo_soft_uart_flush_rx(suart); + + /* FIXME: this scenario demonstrates a problem that may occur when the user + * flushes the Rx buffer manually while the soft-UART state reflects flags + * of an incomplete symbol, for which we're waiting the stop bit. */ + printf("testing corner case: manual flushing during a parity error (8-E-1)\n"); + cfg = suart_test_default_cfg; + cfg.parity_mode = OSMO_SUART_PARITY_EVEN; + osmo_soft_uart_configure(suart, &cfg); + test_rx_exec(suart, "1111111" /* no data */ + "0 01010101 0 1" /* even parity, correct */ + "0 10101010 0 1" /* even parity, correct */ + "0 11111111 1" /* odd parity, incorrect, but stop bit is pending */ + "F" /* manual flush happens before receiving the stop bit */ + "1" /* finally, the stop bit is received */ + ); + /* test_rx_exec() @ 47: flush the Rx buffer + * suart_rx_cb(flags=02): aa 55 <--- this is wrong, should be flags=00 + * suart_rx_cb(flags=02): ff <--- this is expected due to odd parity */ + + + osmo_soft_uart_free(suart); +} + +static void test_tx_rx_exec_one(struct osmo_soft_uart *suart, + size_t n_bits_total, size_t n_bits_frame) +{ + ubit_t tx_buf[n_bits_total]; + ubit_t *ptr = &tx_buf[0]; + int rc; + + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], n_bits_total); + OSMO_ASSERT(rc == n_bits_total); + + rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], n_bits_total); + OSMO_ASSERT(rc == 0); + osmo_soft_uart_flush_rx(suart); + + printf("%s(n_bits_total=%zu):", __func__, n_bits_total); + while (n_bits_total > 0) { + size_t n_bits = OSMO_MIN(n_bits_frame, n_bits_total); + printf(" %s", osmo_ubit_dump(ptr, n_bits)); + n_bits_total -= n_bits; + ptr += n_bits; + } + printf("\n"); +} + +static void test_tx_rx_exec(struct osmo_soft_uart *suart, size_t n_bits_frame) +{ + const uint8_t tx_data[][4] = { + { 0xde, 0xad, 0xbe, 0xef }, + { 0x00, 0xaa, 0x55, 0xff }, + { 0x01, 0x02, 0x04, 0x08 }, + { 0x10, 0x20, 0x40, 0x80 }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(tx_data); i++) { + g_tx_cb_cfg.data_len = 4; + g_tx_cb_cfg.data = tx_data[i]; + test_tx_rx_exec_one(suart, 4 * n_bits_frame, n_bits_frame); + } + + g_tx_cb_cfg.data_len = 0; + g_tx_cb_cfg.data = NULL; + test_tx_rx_exec_one(suart, 4 * n_bits_frame, n_bits_frame); +} + +static void test_tx_rx(void) +{ + struct osmo_soft_uart_cfg cfg; + struct osmo_soft_uart *suart; + int rc; + + SUART_TEST_BEGIN; + + suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg); + OSMO_ASSERT(suart != NULL); + + /* expect -EAGAIN when the transmitter is not enabled */ + rc = osmo_soft_uart_tx_ubits(suart, NULL, 42); + OSMO_ASSERT(rc == -EAGAIN); + /* expect -EAGAIN when the receiver is not enabled */ + rc = osmo_soft_uart_rx_ubits(suart, NULL, 42); + OSMO_ASSERT(rc == -EAGAIN); + + osmo_soft_uart_set_tx(suart, true); + osmo_soft_uart_set_rx(suart, true); + + printf("======== testing 8-N-1\n"); + test_tx_rx_exec(suart, (1 + 8 + 1)); + + printf("======== testing 8-N-2\n"); + cfg = suart_test_default_cfg; + cfg.num_stop_bits = 2; + osmo_soft_uart_configure(suart, &cfg); + test_tx_rx_exec(suart, (1 + 8 + 2)); + + printf("======== testing 8-E-1\n"); + cfg = suart_test_default_cfg; + cfg.parity_mode = OSMO_SUART_PARITY_EVEN; + osmo_soft_uart_configure(suart, &cfg); + test_tx_rx_exec(suart, (1 + 8 + 1 + 1)); + + printf("======== testing 8-O-1\n"); + cfg = suart_test_default_cfg; + cfg.parity_mode = OSMO_SUART_PARITY_ODD; + osmo_soft_uart_configure(suart, &cfg); + test_tx_rx_exec(suart, (1 + 8 + 1 + 1)); + + printf("======== testing 8-M-1\n"); + cfg = suart_test_default_cfg; + cfg.parity_mode = OSMO_SUART_PARITY_MARK; + osmo_soft_uart_configure(suart, &cfg); + test_tx_rx_exec(suart, (1 + 8 + 1 + 1)); + + printf("======== testing 8-S-1\n"); + cfg = suart_test_default_cfg; + cfg.parity_mode = OSMO_SUART_PARITY_SPACE; + osmo_soft_uart_configure(suart, &cfg); + test_tx_rx_exec(suart, (1 + 8 + 1 + 1)); + + printf("======== testing 6-N-1\n"); + cfg = suart_test_default_cfg; + cfg.num_data_bits = 6; + osmo_soft_uart_configure(suart, &cfg); + test_tx_rx_exec(suart, (1 + 6 + 1)); + + osmo_soft_uart_free(suart); +} + +static void test_tx_rx_pull_n(unsigned int n) +{ + struct osmo_soft_uart *suart; + ubit_t tx_buf[32]; + int rc; + + SUART_TEST_BEGIN; + + suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg); + OSMO_ASSERT(suart != NULL); + + osmo_soft_uart_set_tx(suart, true); + osmo_soft_uart_set_rx(suart, true); + + g_tx_cb_cfg.data = (void *)"\x55"; + g_tx_cb_cfg.data_len = 1; + + printf("======== pulling %lu bits (%u at a time)\n", sizeof(tx_buf), n); + for (unsigned int i = 0; i < sizeof(tx_buf); i += n) { + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[i], n); + OSMO_ASSERT(rc == n); + } + printf("%s\n", osmo_ubit_dump(&tx_buf[0], sizeof(tx_buf))); + + printf("======== feeding %lu bits into the receiver\n", sizeof(tx_buf)); + rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + osmo_soft_uart_flush_rx(suart); + + osmo_soft_uart_free(suart); +} + +static void test_modem_status(void) +{ + struct osmo_soft_uart *suart; + unsigned int status; + + SUART_TEST_BEGIN; + + suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg); + OSMO_ASSERT(suart != NULL); + + printf("initial status=0x%08x\n", osmo_soft_uart_get_status(suart)); + + printf("de-asserting DCD, which was not asserted\n"); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DCD, false); + OSMO_ASSERT(osmo_soft_uart_get_status(suart) == 0x00); /* no change */ + + printf("asserting both RI and DCD, expecting the callback to be called twice\n"); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_RI, true); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DCD, true); + status = osmo_soft_uart_get_status(suart); + OSMO_ASSERT(status == (OSMO_SUART_STATUS_F_RI | OSMO_SUART_STATUS_F_DCD)); + + printf("de-asserting RI, expecting the callback to be called\n"); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_RI, false); + status = osmo_soft_uart_get_status(suart); + OSMO_ASSERT(status == (OSMO_SUART_STATUS_F_DCD)); + + printf("resetting to 0x00, expecting the callback to be called\n"); + osmo_soft_uart_set_status(suart, 0x00); + OSMO_ASSERT(osmo_soft_uart_get_status(suart) == 0x00); + + osmo_soft_uart_free(suart); +} + +static void test_flow_control_dtr_dsr(void) +{ + struct osmo_soft_uart_cfg cfg; + struct osmo_soft_uart *suart; + ubit_t tx_buf[40]; + int rc; + + SUART_TEST_BEGIN; + + g_tx_cb_cfg.data = (void *)"\x42\x42\x42\x42"; + g_tx_cb_cfg.data_len = 4; + + cfg = suart_test_default_cfg; + cfg.flow_ctrl_mode = OSMO_SUART_FLOW_CTRL_DTR_DSR; + + suart = osmo_soft_uart_alloc(NULL, __func__, &cfg); + OSMO_ASSERT(suart != NULL); + + osmo_soft_uart_set_tx(suart, true); + osmo_soft_uart_set_rx(suart, true); + + /* expect the initial status to be 0 (all lines de-asserted) */ + printf("initial status=0x%08x\n", osmo_soft_uart_get_status(suart)); + + memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */ + + printf("expecting osmo_soft_uart_tx_ubits() to yield nothing\n"); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + + printf("expecting osmo_soft_uart_rx_ubits() to yield nothing\n"); + rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + osmo_soft_uart_flush_rx(suart); + + /* both DTR and DSR are asserted, expect both Rx and Tx to work */ + printf("======== asserting both DTR and DSR\n"); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DTR, true); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DSR, true); + + memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */ + + printf("expecting osmo_soft_uart_tx_ubits() to " + "yield %zu bits (requesting %zu bits)\n", + sizeof(tx_buf), sizeof(tx_buf)); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == sizeof(tx_buf)); + printf("%s\n", osmo_ubit_dump(&tx_buf[0], sizeof(tx_buf))); + + printf("expecting osmo_soft_uart_rx_ubits() to " + "consume %zu bits and yield %zu chars\n", + sizeof(tx_buf), sizeof(tx_buf) / 10); + rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + osmo_soft_uart_flush_rx(suart); + + memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */ + + /* make the transmitter consume one char, but pull only 2 bits */ + printf("expecting osmo_soft_uart_tx_ubits() to " + "yield 2 bits (requesting 2 bits)\n"); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], 2); + OSMO_ASSERT(rc == 2); + + /* CTS gets de-asserted, the transmitter is shutting down */ + printf("======== de-asserting DSR\n"); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DSR, false); + + /* expect only the remaining 8 bits to be pulled out */ + printf("expecting osmo_soft_uart_tx_ubits() to " + "yield 8 bits (requesting %zu bits)\n", sizeof(tx_buf)); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[2], sizeof(tx_buf) - 2); + OSMO_ASSERT(rc == 8); + + printf("expecting osmo_soft_uart_rx_ubits() to " + "consume %zu bits and yield a pending char\n", sizeof(tx_buf)); + rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + osmo_soft_uart_flush_rx(suart); + + osmo_soft_uart_free(suart); +} + +static void test_flow_control_rts_cts(void) +{ + struct osmo_soft_uart_cfg cfg; + struct osmo_soft_uart *suart; + ubit_t tx_buf[40]; + int rc; + + SUART_TEST_BEGIN; + + g_tx_cb_cfg.data = (void *)"\x42\x42\x42\x42"; + g_tx_cb_cfg.data_len = 4; + + cfg = suart_test_default_cfg; + cfg.flow_ctrl_mode = OSMO_SUART_FLOW_CTRL_RTS_CTS; + + suart = osmo_soft_uart_alloc(NULL, __func__, &cfg); + OSMO_ASSERT(suart != NULL); + + osmo_soft_uart_set_tx(suart, true); + osmo_soft_uart_set_rx(suart, true); + + /* expect the initial status to be 0 (all lines de-asserted) */ + printf("initial status=0x%08x\n", osmo_soft_uart_get_status(suart)); + + memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */ + + printf("expecting osmo_soft_uart_tx_ubits() to yield nothing\n"); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + + printf("expecting osmo_soft_uart_rx_ubits() to yield nothing\n"); + rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + osmo_soft_uart_flush_rx(suart); + + /* both RTS/RTR and CTS are asserted, expect both Rx and Tx to work */ + printf("======== asserting both CTS and RTS/RTR\n"); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_CTS, true); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_RTS_RTR, true); + + memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */ + + printf("expecting osmo_soft_uart_tx_ubits() to " + "yield %zu bits (requesting %zu bits)\n", + sizeof(tx_buf), sizeof(tx_buf)); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == sizeof(tx_buf)); + printf("%s\n", osmo_ubit_dump(&tx_buf[0], sizeof(tx_buf))); + + printf("expecting osmo_soft_uart_rx_ubits() to " + "consume %zu bits and yield %zu chars\n", + sizeof(tx_buf), sizeof(tx_buf) / 10); + rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + osmo_soft_uart_flush_rx(suart); + + memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */ + + /* make the transmitter consume one char, but pull only 2 bits */ + printf("expecting osmo_soft_uart_tx_ubits() to " + "yield 2 bits (requesting 2 bits)\n"); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], 2); + OSMO_ASSERT(rc == 2); + + /* CTS gets de-asserted, the transmitter is shutting down */ + printf("======== de-asserting CTS\n"); + osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_CTS, false); + + /* expect only the remaining 8 bits to be pulled out */ + printf("expecting osmo_soft_uart_tx_ubits() to " + "yield 8 bits (requesting %zu bits)\n", sizeof(tx_buf)); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[2], sizeof(tx_buf) - 2); + OSMO_ASSERT(rc == 8); + + printf("expecting osmo_soft_uart_rx_ubits() to " + "consume %zu bits and yield a pending char\n", sizeof(tx_buf)); + rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf)); + OSMO_ASSERT(rc == 0); + osmo_soft_uart_flush_rx(suart); + + osmo_soft_uart_free(suart); +} + +static void test_tx_pull(void) +{ + struct osmo_soft_uart *suart; + ubit_t tx_buf[25 * 2]; + int rc; + + SUART_TEST_BEGIN; + + g_tx_cb_cfg.data = (void *)"\x42\x42\x42\x42\x42"; + g_tx_cb_cfg.data_len = 5; + + suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg); + OSMO_ASSERT(suart != NULL); + + osmo_soft_uart_set_tx(suart, true); + + printf("pulling 25 bits (first time) out of the transmitter\n"); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf) / 2); + OSMO_ASSERT(rc == 25); + + printf("pulling 25 bits (second time) out of the transmitter\n"); + rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[25], sizeof(tx_buf) / 2); + OSMO_ASSERT(rc == 25); + + /* FIXME: we pull total 25 + 25 == 50 bits out of the transmitter, which is enough + * to fit 5 characters (assuming 8-N-1). However, the current impelementation would + * pull only 2 + 2 == characters total, wasting 5 + 5 == 10 bits for padding. */ + + osmo_soft_uart_free(suart); +} + +int main(int argc, char **argv) +{ + test_rx(); + test_rx_flush(); + test_tx_rx(); + + /* test pulling small number of bits at a time */ + test_tx_rx_pull_n(1); + test_tx_rx_pull_n(2); + test_tx_rx_pull_n(4); + test_tx_rx_pull_n(8); + + test_tx_pull(); + + /* test flow control */ + test_modem_status(); + test_flow_control_dtr_dsr(); + test_flow_control_rts_cts(); + + return 0; +} diff --git a/tests/soft_uart/soft_uart_test.ok b/tests/soft_uart/soft_uart_test.ok new file mode 100644 index 00000000..dcd7ceb4 --- /dev/null +++ b/tests/soft_uart/soft_uart_test.ok @@ -0,0 +1,278 @@ + +Executing test_rx +======== testing 8-N-1 (no data) +test_rx_exec() @ 0: flush the Rx buffer +test_rx_exec() @ 6: flush the Rx buffer +test_rx_exec() @ 12: flush the Rx buffer +======== testing 8-N-1 (fill up flush) +suart_rx_cb(flags=00): de ad be ef +suart_rx_cb(flags=00): 00 aa 55 ff +test_rx_exec() @ 101: flush the Rx buffer +======== testing 8-N-1 (HELLO) +test_rx_exec() @ 18: flush the Rx buffer +suart_rx_cb(flags=00): 48 +test_rx_exec() @ 31: flush the Rx buffer +suart_rx_cb(flags=00): 45 +test_rx_exec() @ 57: flush the Rx buffer +suart_rx_cb(flags=00): 4c +test_rx_exec() @ 70: flush the Rx buffer +suart_rx_cb(flags=00): 4c +test_rx_exec() @ 96: flush the Rx buffer +suart_rx_cb(flags=00): 4f +======== testing 8-N-1 (framing errors) +suart_rx_cb(flags=01): 00 +suart_rx_cb(flags=01): aa +test_rx_exec() @ 41: flush the Rx buffer +suart_rx_cb(flags=00): ff +======== testing 8-N-2 (HELLO) +test_rx_exec() @ 20: flush the Rx buffer +test_rx_exec() @ 22: flush the Rx buffer +suart_rx_cb(flags=00): 48 +test_rx_exec() @ 35: flush the Rx buffer +test_rx_exec() @ 37: flush the Rx buffer +suart_rx_cb(flags=00): 45 +test_rx_exec() @ 65: flush the Rx buffer +test_rx_exec() @ 67: flush the Rx buffer +suart_rx_cb(flags=00): 4c +test_rx_exec() @ 80: flush the Rx buffer +test_rx_exec() @ 82: flush the Rx buffer +suart_rx_cb(flags=00): 4c +test_rx_exec() @ 110: flush the Rx buffer +test_rx_exec() @ 112: flush the Rx buffer +suart_rx_cb(flags=00): 4f +======== testing 8-N-2 (framing errors) +suart_rx_cb(flags=01): 00 +suart_rx_cb(flags=01): aa +suart_rx_cb(flags=01): 55 +test_rx_exec() @ 57: flush the Rx buffer +suart_rx_cb(flags=00): ff +======== testing 8-E-1 (invalid parity) +suart_rx_cb(flags=02): 00 +suart_rx_cb(flags=02): 01 +suart_rx_cb(flags=02): ff +test_rx_exec() @ 49: flush the Rx buffer +======== testing 8-E-1 (valid parity) +test_rx_exec() @ 63: flush the Rx buffer +suart_rx_cb(flags=00): 00 ff aa 55 +test_rx_exec() @ 120: flush the Rx buffer +suart_rx_cb(flags=00): 80 e0 f8 fe +======== testing 8-O-1 (invalid parity) +suart_rx_cb(flags=02): 00 +suart_rx_cb(flags=02): 01 +suart_rx_cb(flags=02): ff +test_rx_exec() @ 42: flush the Rx buffer +======== testing 8-O-1 (valid parity) +test_rx_exec() @ 63: flush the Rx buffer +suart_rx_cb(flags=00): 00 ff aa 55 +test_rx_exec() @ 120: flush the Rx buffer +suart_rx_cb(flags=00): 80 e0 f8 fe + +Executing test_rx_flush +calling osmo_soft_uart_flush_rx() while Rx disabled +enabling the receiver +calling osmo_soft_uart_flush_rx() while Rx enabled, but no data +testing corner case: manual flushing during a parity error (8-E-1) +test_rx_exec() @ 47: flush the Rx buffer +suart_rx_cb(flags=02): aa 55 +suart_rx_cb(flags=02): ff + +Executing test_tx_rx +======== testing 8-N-1 +suart_tx_cb(len=4/4): de ad be ef +suart_rx_cb(flags=00): de ad be ef +test_tx_rx_exec_one(n_bits_total=40): 0011110111 0101101011 0011111011 0111101111 +suart_tx_cb(len=4/4): 00 aa 55 ff +suart_rx_cb(flags=00): 00 aa 55 ff +test_tx_rx_exec_one(n_bits_total=40): 0000000001 0010101011 0101010101 0111111111 +suart_tx_cb(len=4/4): 01 02 04 08 +suart_rx_cb(flags=00): 01 02 04 08 +test_tx_rx_exec_one(n_bits_total=40): 0100000001 0010000001 0001000001 0000100001 +suart_tx_cb(len=4/4): 10 20 40 80 +suart_rx_cb(flags=00): 10 20 40 80 +test_tx_rx_exec_one(n_bits_total=40): 0000010001 0000001001 0000000101 0000000011 +suart_tx_cb(len=0/4): +test_tx_rx_exec_one(n_bits_total=40): 1111111111 1111111111 1111111111 1111111111 +======== testing 8-N-2 +suart_tx_cb(len=4/4): de ad be ef +suart_rx_cb(flags=00): de ad be ef +test_tx_rx_exec_one(n_bits_total=44): 00111101111 01011010111 00111110111 01111011111 +suart_tx_cb(len=4/4): 00 aa 55 ff +suart_rx_cb(flags=00): 00 aa 55 ff +test_tx_rx_exec_one(n_bits_total=44): 00000000011 00101010111 01010101011 01111111111 +suart_tx_cb(len=4/4): 01 02 04 08 +suart_rx_cb(flags=00): 01 02 04 08 +test_tx_rx_exec_one(n_bits_total=44): 01000000011 00100000011 00010000011 00001000011 +suart_tx_cb(len=4/4): 10 20 40 80 +suart_rx_cb(flags=00): 10 20 40 80 +test_tx_rx_exec_one(n_bits_total=44): 00000100011 00000010011 00000001011 00000000111 +suart_tx_cb(len=0/4): +test_tx_rx_exec_one(n_bits_total=44): 11111111111 11111111111 11111111111 11111111111 +======== testing 8-E-1 +suart_tx_cb(len=4/4): de ad be ef +suart_rx_cb(flags=00): de ad be ef +test_tx_rx_exec_one(n_bits_total=44): 00111101101 01011010111 00111110101 01111011111 +suart_tx_cb(len=4/4): 00 aa 55 ff +suart_rx_cb(flags=00): 00 aa 55 ff +test_tx_rx_exec_one(n_bits_total=44): 00000000001 00101010101 01010101001 01111111101 +suart_tx_cb(len=4/4): 01 02 04 08 +suart_rx_cb(flags=00): 01 02 04 08 +test_tx_rx_exec_one(n_bits_total=44): 01000000011 00100000011 00010000011 00001000011 +suart_tx_cb(len=4/4): 10 20 40 80 +suart_rx_cb(flags=00): 10 20 40 80 +test_tx_rx_exec_one(n_bits_total=44): 00000100011 00000010011 00000001011 00000000111 +suart_tx_cb(len=0/4): +test_tx_rx_exec_one(n_bits_total=44): 11111111111 11111111111 11111111111 11111111111 +======== testing 8-O-1 +suart_tx_cb(len=4/4): de ad be ef +suart_rx_cb(flags=00): de ad be ef +test_tx_rx_exec_one(n_bits_total=44): 00111101111 01011010101 00111110111 01111011101 +suart_tx_cb(len=4/4): 00 aa 55 ff +suart_rx_cb(flags=00): 00 aa 55 ff +test_tx_rx_exec_one(n_bits_total=44): 00000000011 00101010111 01010101011 01111111111 +suart_tx_cb(len=4/4): 01 02 04 08 +suart_rx_cb(flags=00): 01 02 04 08 +test_tx_rx_exec_one(n_bits_total=44): 01000000001 00100000001 00010000001 00001000001 +suart_tx_cb(len=4/4): 10 20 40 80 +suart_rx_cb(flags=00): 10 20 40 80 +test_tx_rx_exec_one(n_bits_total=44): 00000100001 00000010001 00000001001 00000000101 +suart_tx_cb(len=0/4): +test_tx_rx_exec_one(n_bits_total=44): 11111111111 11111111111 11111111111 11111111111 +======== testing 8-M-1 +suart_tx_cb(len=4/4): de ad be ef +suart_rx_cb(flags=00): de ad be ef +test_tx_rx_exec_one(n_bits_total=44): 00111101111 01011010111 00111110111 01111011111 +suart_tx_cb(len=4/4): 00 aa 55 ff +suart_rx_cb(flags=00): 00 aa 55 ff +test_tx_rx_exec_one(n_bits_total=44): 00000000011 00101010111 01010101011 01111111111 +suart_tx_cb(len=4/4): 01 02 04 08 +suart_rx_cb(flags=00): 01 02 04 08 +test_tx_rx_exec_one(n_bits_total=44): 01000000011 00100000011 00010000011 00001000011 +suart_tx_cb(len=4/4): 10 20 40 80 +suart_rx_cb(flags=00): 10 20 40 80 +test_tx_rx_exec_one(n_bits_total=44): 00000100011 00000010011 00000001011 00000000111 +suart_tx_cb(len=0/4): +test_tx_rx_exec_one(n_bits_total=44): 11111111111 11111111111 11111111111 11111111111 +======== testing 8-S-1 +suart_tx_cb(len=4/4): de ad be ef +suart_rx_cb(flags=00): de ad be ef +test_tx_rx_exec_one(n_bits_total=44): 00111101101 01011010101 00111110101 01111011101 +suart_tx_cb(len=4/4): 00 aa 55 ff +suart_rx_cb(flags=00): 00 aa 55 ff +test_tx_rx_exec_one(n_bits_total=44): 00000000001 00101010101 01010101001 01111111101 +suart_tx_cb(len=4/4): 01 02 04 08 +suart_rx_cb(flags=00): 01 02 04 08 +test_tx_rx_exec_one(n_bits_total=44): 01000000001 00100000001 00010000001 00001000001 +suart_tx_cb(len=4/4): 10 20 40 80 +suart_rx_cb(flags=00): 10 20 40 80 +test_tx_rx_exec_one(n_bits_total=44): 00000100001 00000010001 00000001001 00000000101 +suart_tx_cb(len=0/4): +test_tx_rx_exec_one(n_bits_total=44): 11111111111 11111111111 11111111111 11111111111 +======== testing 6-N-1 +suart_tx_cb(len=4/4): de ad be ef +suart_rx_cb(flags=00): 1e 2d 3e 2f +test_tx_rx_exec_one(n_bits_total=32): 00111101 01011011 00111111 01111011 +suart_tx_cb(len=4/4): 00 aa 55 ff +suart_rx_cb(flags=00): 00 2a 15 3f +test_tx_rx_exec_one(n_bits_total=32): 00000001 00101011 01010101 01111111 +suart_tx_cb(len=4/4): 01 02 04 08 +suart_rx_cb(flags=00): 01 02 04 08 +test_tx_rx_exec_one(n_bits_total=32): 01000001 00100001 00010001 00001001 +suart_tx_cb(len=4/4): 10 20 40 80 +suart_rx_cb(flags=00): 10 20 00 00 +test_tx_rx_exec_one(n_bits_total=32): 00000101 00000011 00000001 00000001 +suart_tx_cb(len=0/4): +test_tx_rx_exec_one(n_bits_total=32): 11111111 11111111 11111111 11111111 + +Executing test_tx_rx_pull_n +======== pulling 32 bits (1 at a time) +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +01010101010101010101010101010101 +======== feeding 32 bits into the receiver +suart_rx_cb(flags=00): 55 55 55 + +Executing test_tx_rx_pull_n +======== pulling 32 bits (2 at a time) +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +01010101010101010101010101010101 +======== feeding 32 bits into the receiver +suart_rx_cb(flags=00): 55 55 55 + +Executing test_tx_rx_pull_n +======== pulling 32 bits (4 at a time) +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +01010101011101010101011101010101 +======== feeding 32 bits into the receiver +suart_rx_cb(flags=00): 55 55 + +Executing test_tx_rx_pull_n +======== pulling 32 bits (8 at a time) +suart_tx_cb(len=1/1): 55 +suart_tx_cb(len=1/1): 55 +01010101011111110101010101111111 +======== feeding 32 bits into the receiver +suart_rx_cb(flags=00): 55 55 + +Executing test_tx_pull +pulling 25 bits (first time) out of the transmitter +suart_tx_cb(len=2/2): 42 42 +pulling 25 bits (second time) out of the transmitter +suart_tx_cb(len=2/2): 42 42 + +Executing test_modem_status +initial status=0x00000000 +de-asserting DCD, which was not asserted +asserting both RI and DCD, expecting the callback to be called twice +suart_status_change_cb(status=0x00000008) +suart_status_change_cb(status=0x0000000a) +de-asserting RI, expecting the callback to be called +suart_status_change_cb(status=0x00000002) +resetting to 0x00, expecting the callback to be called +suart_status_change_cb(status=0x00000000) + +Executing test_flow_control_dtr_dsr +initial status=0x00000000 +expecting osmo_soft_uart_tx_ubits() to yield nothing +expecting osmo_soft_uart_rx_ubits() to yield nothing +======== asserting both DTR and DSR +suart_status_change_cb(status=0x00000001) +suart_status_change_cb(status=0x00000005) +expecting osmo_soft_uart_tx_ubits() to yield 40 bits (requesting 40 bits) +suart_tx_cb(len=4/4): 42 42 42 42 +0010000101001000010100100001010010000101 +expecting osmo_soft_uart_rx_ubits() to consume 40 bits and yield 4 chars +suart_rx_cb(flags=00): 42 42 42 42 +expecting osmo_soft_uart_tx_ubits() to yield 2 bits (requesting 2 bits) +suart_tx_cb(len=1/1): 42 +======== de-asserting DSR +suart_status_change_cb(status=0x00000001) +expecting osmo_soft_uart_tx_ubits() to yield 8 bits (requesting 40 bits) +expecting osmo_soft_uart_rx_ubits() to consume 40 bits and yield a pending char +suart_rx_cb(flags=00): 42 + +Executing test_flow_control_rts_cts +initial status=0x00000000 +expecting osmo_soft_uart_tx_ubits() to yield nothing +expecting osmo_soft_uart_rx_ubits() to yield nothing +======== asserting both CTS and RTS/RTR +suart_status_change_cb(status=0x00000020) +suart_status_change_cb(status=0x00000030) +expecting osmo_soft_uart_tx_ubits() to yield 40 bits (requesting 40 bits) +suart_tx_cb(len=4/4): 42 42 42 42 +0010000101001000010100100001010010000101 +expecting osmo_soft_uart_rx_ubits() to consume 40 bits and yield 4 chars +suart_rx_cb(flags=00): 42 42 42 42 +expecting osmo_soft_uart_tx_ubits() to yield 2 bits (requesting 2 bits) +suart_tx_cb(len=1/1): 42 +======== de-asserting CTS +suart_status_change_cb(status=0x00000010) +expecting osmo_soft_uart_tx_ubits() to yield 8 bits (requesting 40 bits) +expecting osmo_soft_uart_rx_ubits() to consume 40 bits and yield a pending char +suart_rx_cb(flags=00): 42 |