From 63a35af8aab90ed049447a2837666a52f13b9598 Mon Sep 17 00:00:00 2001 From: batt Date: Wed, 7 Oct 2009 21:39:43 +0000 Subject: [PATCH] Add ax25_send, update test. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@3040 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/net/ax25.c | 67 +++++++++++++++++++++++++++++++++++++++--- bertos/net/ax25.h | 20 +++++++++++++ bertos/net/ax25_test.c | 24 +++++++++++++-- 3 files changed, 104 insertions(+), 7 deletions(-) diff --git a/bertos/net/ax25.c b/bertos/net/ax25.c index 968e387f..88913659 100644 --- a/bertos/net/ax25.c +++ b/bertos/net/ax25.c @@ -48,12 +48,12 @@ #define LOG_FORMAT AX25_LOG_FORMAT #include -#include //memset +#include //memset, memcmp +#include //isalnum, toupper #define DECODE_CALL(buf, addr) \ for (unsigned i = 0; i < sizeof((addr)); i++) \ { \ - ASSERT(!(*(buf) & 0x01)); \ (addr)[i] = *(buf)++ >> 1; \ } @@ -93,14 +93,14 @@ static void ax25_decode(AX25Ctx *ctx) msg.ctrl = *buf++; if (msg.ctrl != AX25_CTRL_UI) { - LOG_INFO("Only UI frames are handled, got [%02X]\n", msg.ctrl); + LOG_WARN("Only UI frames are handled, got [%02X]\n", msg.ctrl); return; } msg.pid = *buf++; if (msg.pid != AX25_PID_NOLAYER3) { - LOG_INFO("Only frames without layer3 protocol are handled, got [%02X]\n", msg.pid); + LOG_WARN("Only frames without layer3 protocol are handled, got [%02X]\n", msg.pid); return; } @@ -174,6 +174,65 @@ void ax25_poll(AX25Ctx *ctx) } } +static void ax25_putchar(AX25Ctx *ctx, uint8_t c) +{ + if (c == HDLC_FLAG || c == HDLC_RESET + || c == AX25_ESC) + kfile_putc(AX25_ESC, ctx->ch); + ctx->crc_out = updcrc_ccitt(c, ctx->crc_out); + kfile_putc(c, ctx->ch); +} + +static void ax25_sendCall(AX25Ctx *ctx, const AX25Call *addr) +{ + unsigned len = MIN(sizeof(addr->call), strlen(addr->call)); + + for (unsigned i = 0; i < len; i++) + { + uint8_t c = addr->call[i]; + ASSERT(isalnum(c) || c == ' '); + c = toupper(c); + ax25_putchar(ctx, c << 1); + } + + /* Fill with spaces the rest of the CALL if it's shorter */ + if (len < sizeof(addr->call)) + for (unsigned i = 0; i < sizeof(addr->call) - len; i++) + ax25_putchar(ctx, ' ' << 1); +} + +void ax25_send(AX25Ctx *ctx, const AX25Call *dst, const AX25Call *src, const void *_buf, size_t len) +{ + const uint8_t *buf = (const uint8_t *)_buf; + + ctx->crc_out = CRC_CCITT_INIT_VAL; + kfile_putc(HDLC_FLAG, ctx->ch); + + ax25_sendCall(ctx, dst); + ax25_putchar(ctx, dst->ssid << 1); + + ax25_sendCall(ctx, src); + ax25_putchar(ctx, (src->ssid << 1) | 0x01); + ax25_putchar(ctx, AX25_CTRL_UI); + ax25_putchar(ctx, AX25_PID_NOLAYER3); + + while (len--) + ax25_putchar(ctx, *buf++); + + /* + * According to AX25 protocol, + * CRC is sent in reverse order! + */ + uint8_t crcl = (ctx->crc_out & 0xff) ^ 0xff; + uint8_t crch = (ctx->crc_out >> 8) ^ 0xff; + ax25_putchar(ctx, crcl); + ax25_putchar(ctx, crch); + + ASSERT(ctx->crc_out == AX25_CRC_CORRECT); + + kfile_putc(HDLC_FLAG, ctx->ch); +} + void ax25_init(AX25Ctx *ctx, KFile *channel, ax25_callback_t hook) { ASSERT(ctx); diff --git a/bertos/net/ax25.h b/bertos/net/ax25.h index d6213cf4..5daabd5b 100644 --- a/bertos/net/ax25.h +++ b/bertos/net/ax25.h @@ -95,6 +95,13 @@ typedef struct AX25Call uint8_t ssid; ///< SSID (secondary station ID) for the call } AX25Call; +/** + * Create an AX25Call structure on the fly and return its pointer. + * \param str callsign, can be 6 characters or shorter. + * \param id ssid associated with the callsign. + */ +#define AX25_CALL(str, id) ({ static const AX25Call _call = { .call = (str), .ssid = (id) }; &_call; }) + /** * Maximum number of Repeaters in a AX25 message. */ @@ -146,6 +153,19 @@ typedef struct AX25Msg */ void ax25_poll(AX25Ctx *ctx); +/** + * Send an AX25 frame on the channel. + * \param ctx AX25 context to operate on. + * \param dst the destination callsign for the frame, \see AX25_CALL + * for a handy way to create a callsign on the fly. + * \param src the source callsign for the frame, \see AX25_CALL + * for a handy way to create a callsign on the fly. + * \param _buf payload buffer. + * \param len length of the payload. + */ +void ax25_send(AX25Ctx *ctx, const AX25Call *dst, const AX25Call *src, const void *_buf, size_t len); + + /** * Init the AX25 protocol decoder. * diff --git a/bertos/net/ax25_test.c b/bertos/net/ax25_test.c index 31a7ed36..2016eadb 100644 --- a/bertos/net/ax25_test.c +++ b/bertos/net/ax25_test.c @@ -48,15 +48,29 @@ static AX25Ctx ax25; static KFileMem mem; +#define APRS_MSG \ + 0x3D, 0x34, 0x36, 0x30, 0x33, 0x2E, 0x36, 0x33, \ + 0x4E, 0x2F, 0x30, 0x31, 0x34, 0x33, 0x31, 0x2E, \ + 0x32, 0x36, 0x45, 0x2D, 0x4F, 0x70, 0x2E, 0x20, \ + 0x41, 0x6E, 0x64, 0x72, 0x65, 0x6A + uint8_t aprs_packet[] = { HDLC_FLAG, - 0x82, 0xA0, 0xA4, 0xA6, 0x40, 0x40, 0xE0, 0xA6, 0x6A, 0x6E, 0x98, 0x9C, 0x40, 0x61, 0x03, 0xF0, - 0x3D, 0x34, 0x36, 0x30, 0x33, 0x2E, 0x36, 0x33, 0x4E, 0x2F, 0x30, 0x31, 0x34, 0x33, 0x31, 0x2E, - 0x32, 0x36, 0x45, 0x2D, 0x4F, 0x70, 0x2E, 0x20, 0x41, 0x6E, 0x64, 0x72, 0x65, 0x6A, 0x40, 0x65, + 0x82, 0xA0, 0xA4, 0xA6, 0x40, 0x40, 0xE0, /* dst */ + 0xA6, 0x6A, 0x6E, 0x98, 0x9C, 0x40, 0x61, /* src */ + 0x03, /* ctrl */ + 0xF0, /* pid */ + APRS_MSG, /* payload */ + 0x40, 0x65, /* CRC */ HDLC_FLAG, }; +uint8_t buf[] = { APRS_MSG }; +KFileMem mem1; +uint8_t aprs_packet_check[256]; + + static void msg_callback(AX25Msg *msg) { ASSERT(strncmp(msg->dst.call, "APRS ", 6) == 0); @@ -73,6 +87,7 @@ int ax25_testSetup(void) { kdbg_init(); kfilemem_init(&mem, aprs_packet, sizeof(aprs_packet)); + kfilemem_init(&mem1, aprs_packet_check, sizeof(aprs_packet_check)); ax25_init(&ax25, &mem.fd, msg_callback); return 0; } @@ -85,6 +100,9 @@ int ax25_testTearDown(void) int ax25_testRun(void) { ax25_poll(&ax25); + ax25_init(&ax25, &mem1.fd, NULL); + ax25_send(&ax25, AX25_CALL("aprs", 0x70), AX25_CALL("s57ln", 0x30), buf, sizeof(buf)); + ASSERT(memcmp(aprs_packet, aprs_packet_check, sizeof(aprs_packet)) == 0); return 0; } -- 2.25.1