BeRTOS
ax25.c
Go to the documentation of this file.
00001 
00041 #include "ax25.h"
00042 #include "cfg/cfg_ax25.h"
00043 
00044 #include <algo/crc_ccitt.h>
00045 
00046 #define LOG_LEVEL  AX25_LOG_LEVEL
00047 #define LOG_FORMAT AX25_LOG_FORMAT
00048 #include <cfg/log.h>
00049 
00050 #include <string.h> //memset, memcmp
00051 #include <ctype.h>  //isalnum, toupper
00052 
00053 #if CONFIG_AX25_RPT_LST
00054     #define AX25_SET_REPEATED(msg, idx, val) \
00055         do \
00056         { \
00057             if (val) \
00058                 (msg)->rpt_flags |= BV(idx) ; \
00059             else \
00060                 (msg)->rpt_flags &= ~BV(idx) ; \
00061         } while(0) 
00062 #endif
00063 
00064 #define DECODE_CALL(buf, addr) \
00065     for (unsigned i = 0; i < sizeof((addr)); i++) \
00066     { \
00067         char c = (*(buf)++ >> 1); \
00068         (addr)[i] = (c == ' ') ? '\x0' : c; \
00069     }
00070 
00071 static void ax25_decode(AX25Ctx *ctx)
00072 {
00073     AX25Msg msg;
00074     uint8_t *buf = ctx->buf;
00075 
00076     DECODE_CALL(buf, msg.dst.call);
00077     msg.dst.ssid = (*buf++ >> 1) & 0x0F;
00078 
00079     DECODE_CALL(buf, msg.src.call);
00080     msg.src.ssid = (*buf >> 1) & 0x0F;
00081 
00082     LOG_INFO("SRC[%.6s-%d], DST[%.6s-%d]\n", msg.src.call, msg.src.ssid, msg.dst.call, msg.dst.ssid);
00083 
00084     /* Repeater addresses */
00085     #if CONFIG_AX25_RPT_LST
00086         for (msg.rpt_cnt = 0; !(*buf++ & 0x01) && (msg.rpt_cnt < countof(msg.rpt_lst)); msg.rpt_cnt++)
00087         {
00088             DECODE_CALL(buf, msg.rpt_lst[msg.rpt_cnt].call);
00089             msg.rpt_lst[msg.rpt_cnt].ssid = (*buf >> 1) & 0x0F;
00090             AX25_SET_REPEATED(&msg, msg.rpt_cnt, (*buf & 0x80));
00091 
00092             LOG_INFO("RPT%d[%.6s-%d]%c\n", msg.rpt_cnt, 
00093                 msg.rpt_lst[msg.rpt_cnt].call, 
00094                 msg.rpt_lst[msg.rpt_cnt].ssid,
00095                 (AX25_REPEATED(&msg, msg.rpt_cnt) ? '*' : ' '));
00096         }
00097     #else
00098         while (!(*buf++ & 0x01))
00099         {
00100             char rpt[6];
00101             uint8_t ssid;
00102             DECODE_CALL(buf, rpt);
00103             ssid = (*buf >> 1) & 0x0F;
00104             LOG_INFO("RPT[%.6s-%d]\n", rpt, ssid);
00105         }
00106     #endif
00107 
00108     msg.ctrl = *buf++;
00109     if (msg.ctrl != AX25_CTRL_UI)
00110     {
00111         LOG_WARN("Only UI frames are handled, got [%02X]\n", msg.ctrl);
00112         return;
00113     }
00114 
00115     msg.pid = *buf++;
00116     if (msg.pid != AX25_PID_NOLAYER3)
00117     {
00118         LOG_WARN("Only frames without layer3 protocol are handled, got [%02X]\n", msg.pid);
00119         return;
00120     }
00121 
00122     msg.len = ctx->frm_len - 2 - (buf - ctx->buf);
00123     msg.info = buf;
00124     LOG_INFO("DATA: %.*s\n", msg.len, msg.info);
00125 
00126     if (ctx->hook)
00127         ctx->hook(&msg);
00128 }
00129 
00130 
00141 void ax25_poll(AX25Ctx *ctx)
00142 {
00143     int c;
00144 
00145     while ((c = kfile_getc(ctx->ch)) != EOF)
00146     {
00147         if (!ctx->escape && c == HDLC_FLAG)
00148         {
00149             if (ctx->frm_len >= AX25_MIN_FRAME_LEN)
00150             {
00151                 if (ctx->crc_in == AX25_CRC_CORRECT)
00152                 {
00153                     LOG_INFO("Frame found!\n");
00154                     ax25_decode(ctx);
00155                 }
00156                 else
00157                 {
00158                     LOG_INFO("CRC error, computed [%04X]\n", ctx->crc_in);
00159                 }
00160             }
00161             ctx->sync = true;
00162             ctx->crc_in = CRC_CCITT_INIT_VAL;
00163             ctx->frm_len = 0;
00164             continue;
00165         }
00166 
00167         if (!ctx->escape && c == HDLC_RESET)
00168         {
00169             LOG_INFO("HDLC reset\n");
00170             ctx->sync = false;
00171             continue;
00172         }
00173 
00174         if (!ctx->escape && c == AX25_ESC)
00175         {
00176             ctx->escape = true;
00177             continue;
00178         }
00179 
00180         if (ctx->sync)
00181         {
00182             if (ctx->frm_len < CONFIG_AX25_FRAME_BUF_LEN)
00183             {
00184                 ctx->buf[ctx->frm_len++] = c;
00185                 ctx->crc_in = updcrc_ccitt(c, ctx->crc_in);
00186             }
00187             else
00188             {
00189                 LOG_INFO("Buffer overrun");
00190                 ctx->sync = false;
00191             }
00192         }
00193         ctx->escape = false;
00194     }
00195 
00196     if (kfile_error(ctx->ch))
00197     {
00198         LOG_ERR("Channel error [%04x]\n", kfile_error(ctx->ch));
00199         kfile_clearerr(ctx->ch);
00200     }
00201 }
00202 
00203 static void ax25_putchar(AX25Ctx *ctx, uint8_t c)
00204 {
00205     if (c == HDLC_FLAG || c == HDLC_RESET
00206         || c == AX25_ESC)
00207         kfile_putc(AX25_ESC, ctx->ch);
00208     ctx->crc_out = updcrc_ccitt(c, ctx->crc_out);
00209     kfile_putc(c, ctx->ch);
00210 }
00211 
00212 static void ax25_sendCall(AX25Ctx *ctx, const AX25Call *addr, bool last)
00213 {
00214     unsigned len = MIN(sizeof(addr->call), strlen(addr->call));
00215 
00216     for (unsigned i = 0; i < len; i++)
00217     {
00218         uint8_t c = addr->call[i];
00219         ASSERT(isalnum(c) || c == ' ');
00220         c = toupper(c);
00221         ax25_putchar(ctx, c << 1);
00222     }
00223 
00224     /* Fill with spaces the rest of the CALL if it's shorter */
00225     if (len < sizeof(addr->call))
00226         for (unsigned i = 0; i < sizeof(addr->call) - len; i++)
00227             ax25_putchar(ctx, ' ' << 1);
00228 
00229     /* The bit7 "has-been-repeated" flag is not implemented here */
00230     /* Bits6:5 should be set to 1 for all SSIDs (0x60) */
00231     /* The bit0 of last call SSID should be set to 1 */
00232     uint8_t ssid = 0x60 | (addr->ssid << 1) | (last ? 0x01 : 0);
00233     ax25_putchar(ctx, ssid);
00234 }
00235 
00245 void ax25_sendVia(AX25Ctx *ctx, const AX25Call *path, size_t path_len, const void *_buf, size_t len)
00246 {
00247     const uint8_t *buf = (const uint8_t *)_buf;
00248     ASSERT(path);
00249     ASSERT(path_len >= 2);
00250 
00251     ctx->crc_out = CRC_CCITT_INIT_VAL;
00252     kfile_putc(HDLC_FLAG, ctx->ch);
00253 
00254 
00255     /* Send call */
00256     for (size_t i = 0; i < path_len; i++)
00257         ax25_sendCall(ctx, &path[i], (i == path_len - 1));
00258 
00259     ax25_putchar(ctx, AX25_CTRL_UI);
00260     ax25_putchar(ctx, AX25_PID_NOLAYER3);
00261 
00262     while (len--)
00263         ax25_putchar(ctx, *buf++);
00264 
00265     /*
00266      * According to AX25 protocol,
00267      * CRC is sent in reverse order!
00268      */
00269     uint8_t crcl = (ctx->crc_out & 0xff) ^ 0xff;
00270     uint8_t crch = (ctx->crc_out >> 8) ^ 0xff;
00271     ax25_putchar(ctx, crcl);
00272     ax25_putchar(ctx, crch);
00273 
00274     ASSERT(ctx->crc_out == AX25_CRC_CORRECT);
00275 
00276     kfile_putc(HDLC_FLAG, ctx->ch);
00277 }
00278 
00279 static void print_call(KFile *ch, const AX25Call *call)
00280 {
00281     kfile_printf(ch, "%.6s", call->call);
00282     if (call->ssid)
00283         kfile_printf(ch, "-%d", call->ssid);
00284 }
00285 
00291 void ax25_print(KFile *ch, const AX25Msg *msg)
00292 {
00293     print_call(ch, &msg->src);
00294     kfile_putc('>', ch);
00295     print_call(ch, &msg->dst);
00296 
00297     #if CONFIG_AX25_RPT_LST
00298     for (int i = 0; i < msg->rpt_cnt; i++)
00299     {
00300         kfile_putc(',', ch);
00301         print_call(ch, &msg->rpt_lst[i]);
00302         /* Print a '*' if packet has already been transmitted 
00303          * by this repeater */
00304         if (AX25_REPEATED(msg, i))
00305             kfile_putc('*', ch);
00306     }
00307     #endif
00308 
00309     kfile_printf(ch, ":%.*s\n", msg->len, msg->info);
00310 }
00311 
00312 
00320 void ax25_init(AX25Ctx *ctx, KFile *channel, ax25_callback_t hook)
00321 {
00322     ASSERT(ctx);
00323     ASSERT(channel);
00324 
00325     memset(ctx, 0, sizeof(*ctx));
00326     ctx->ch = channel;
00327     ctx->hook = hook;
00328     ctx->crc_in = ctx->crc_out = CRC_CCITT_INIT_VAL;
00329 }