diff options
| author | info@mode42.com <info@mode42.com> | 2026-08-07 18:25:13 +0000 |
|---|---|---|
| committer | info@mode42.com <info@mode42.com> | 2026-08-07 18:25:13 +0000 |
| commit | 04d965d67a7264a1c7c211494aebda1953df7603 (patch) | |
| tree | 0ebd700a6e219f84a26a656f4bee8778bc75da7b /stacks/max25-bcpr/tests | |
Initial push
Diffstat (limited to 'stacks/max25-bcpr/tests')
| -rw-r--r-- | stacks/max25-bcpr/tests/test_config_offline.c | 53 | ||||
| -rw-r--r-- | stacks/max25-bcpr/tests/test_hdlc_offline.c | 110 |
2 files changed, 163 insertions, 0 deletions
diff --git a/stacks/max25-bcpr/tests/test_config_offline.c b/stacks/max25-bcpr/tests/test_config_offline.c new file mode 100644 index 0000000..8b40a6a --- /dev/null +++ b/stacks/max25-bcpr/tests/test_config_offline.c @@ -0,0 +1,53 @@ +/* + * Offline config parse test — no UART. + */ +#include "bcpr/bcpr_config.h" + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +int main(void) +{ + const char *path = "share/max25-bcpr.ini.example"; + bcpr_config_t cfg; + char cwd[512]; + + if (!getcwd(cwd, sizeof(cwd))) { + return 1; + } + /* Prefer path relative to build or source. */ + if (access(path, R_OK) != 0) { + path = "../share/max25-bcpr.ini.example"; + } + if (access(path, R_OK) != 0) { + path = "../../stacks/max25-bcpr/share/max25-bcpr.ini.example"; + } + if (bcpr_config_load(&cfg, path) != 0) { + /* Write a minimal temp INI. */ + FILE *f = fopen("/tmp/max25-bcpr-test.ini", "w"); + if (!f) { + return 1; + } + fputs("[max25-bcpr]\ndry_run = yes\nstate_dir = /tmp/max25-bcpr\n" + "[bc0]\nserial = /dev/ttyS0\niobase = 0x3f8\nirq = 4\n" + "mode = ser12*\nkiss_link = /tmp/max25-bcpr/kiss-bc0\n", + f); + fclose(f); + path = "/tmp/max25-bcpr-test.ini"; + if (bcpr_config_load(&cfg, path) != 0) { + fprintf(stderr, "FAIL: load\n"); + return 1; + } + } + if (cfg.n_dev < 1 || !cfg.dev[0].enabled) { + fprintf(stderr, "FAIL: no bc0\n"); + return 1; + } + if (cfg.dev[0].irq != 4 || cfg.dev[0].iobase != 0x3f8) { + fprintf(stderr, "FAIL: irq/iobase\n"); + return 1; + } + puts("OK: test_config_offline"); + return 0; +} diff --git a/stacks/max25-bcpr/tests/test_hdlc_offline.c b/stacks/max25-bcpr/tests/test_hdlc_offline.c new file mode 100644 index 0000000..d05d5b6 --- /dev/null +++ b/stacks/max25-bcpr/tests/test_hdlc_offline.c @@ -0,0 +1,110 @@ +/* + * Offline HDLC unit test — CRC, bitstuff roundtrip, no UART / UART I/O. + */ +#include "bcpr/bcpr_crc.h" +#include "bcpr/bcpr_hdlc.h" + +#include <stdio.h> +#include <string.h> + +static int g_got; +static uint8_t g_rx[BCPR_MAXFLEN + 4]; +static int g_rx_len; + +static void on_frame(const uint8_t *kiss, int len, void *ud) +{ + (void)ud; + if (len > 0 && len <= (int)sizeof(g_rx)) { + memcpy(g_rx, kiss, (size_t)len); + g_rx_len = len; + g_got = 1; + } +} + +static int test_crc(void) +{ + uint8_t buf[16]; + memcpy(buf, "TEST", 4); + bcpr_append_crc_ccitt(buf, 4); + if (!bcpr_check_crc_ccitt(buf, 6)) { + fprintf(stderr, "FAIL: CRC check\n"); + return 1; + } + buf[0] ^= 0xff; + if (bcpr_check_crc_ccitt(buf, 6)) { + fprintf(stderr, "FAIL: CRC should fail on corrupt\n"); + return 1; + } + return 0; +} + +static int test_roundtrip(void) +{ + bcpr_hdlc_t tx, rx; + bcpr_channel_t ch = { .tx_delay = 2, .tx_tail = 1, .slottime = 1, + .ppersist = 255, .fulldup = 1 }; + uint8_t kiss[32]; + int i, words = 0; + + bcpr_hdlc_init(&tx, 1200, &ch); + bcpr_hdlc_init(&rx, 1200, &ch); + + kiss[0] = 0; /* KISS DATA */ + memcpy(kiss + 1, "HELLO", 5); + if (bcpr_hdlc_queue_kiss(&tx, kiss, 6) != 0) { + fprintf(stderr, "FAIL: queue\n"); + return 1; + } + bcpr_hdlc_arbitrate(&tx); + if (!bcpr_hdlc_ptt(&tx)) { + fprintf(stderr, "FAIL: PTT not set\n"); + return 1; + } + + g_got = 0; + g_rx_len = 0; + /* Drain TX bit words into RX putbits path. */ + for (i = 0; i < 4096 && !g_got; i++) { + unsigned w; + bcpr_hdlc_transmitter(&tx); + w = bcpr_hdlc_getbits(&tx); + if (w) { + bcpr_hdlc_putbits(&rx, w); + words++; + bcpr_hdlc_receiver(&rx, on_frame, NULL); + } else if (!bcpr_hdlc_ptt(&tx)) { + bcpr_hdlc_transmitter(&tx); + /* flush remaining */ + while (!g_got) { + w = bcpr_hdlc_getbits(&tx); + if (!w) { + break; + } + bcpr_hdlc_putbits(&rx, w); + bcpr_hdlc_receiver(&rx, on_frame, NULL); + } + break; + } + } + + if (!g_got) { + fprintf(stderr, "FAIL: no RX frame (words=%d)\n", words); + return 1; + } + if (g_rx_len < 6 || g_rx[0] != 0 || memcmp(g_rx + 1, "HELLO", 5) != 0) { + fprintf(stderr, "FAIL: payload mismatch len=%d\n", g_rx_len); + return 1; + } + return 0; +} + +int main(void) +{ + int rc = 0; + rc |= test_crc(); + rc |= test_roundtrip(); + if (rc == 0) { + puts("OK: test_hdlc_offline"); + } + return rc; +} |
