Add ax25_send, update test.
authorbatt <batt@38d2e660-2303-0410-9eaa-f027e97ec537>
Wed, 7 Oct 2009 21:39:43 +0000 (21:39 +0000)
committerbatt <batt@38d2e660-2303-0410-9eaa-f027e97ec537>
Wed, 7 Oct 2009 21:39:43 +0000 (21:39 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@3040 38d2e660-2303-0410-9eaa-f027e97ec537

bertos/net/ax25.c
bertos/net/ax25.h
bertos/net/ax25_test.c

index 968e387f477815d1f2bf1f1f1b42cffe18e4eea4..889136595f52997830d310eb5cf342bce1d6f12e 100644 (file)
 #define LOG_FORMAT AX25_LOG_FORMAT
 #include <cfg/log.h>
 
-#include <string.h> //memset
+#include <string.h> //memset, memcmp
+#include <ctype.h>  //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);
index d6213cf43859422e3260f1d087c365c277a71faf..5daabd5b4b9481cfe2ad382f8e6302dfe16c3593 100644 (file)
@@ -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.
  *
index 31a7ed36722af351548100c432344d12e65ed620..2016eadbfa18dea4eb85fc7858de20c45574a44a 100644 (file)
 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;
 }