BeRTOS
|
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 }