mirror of
https://github.com/markqvist/OpenModem.git
synced 2025-05-02 06:26:24 -04:00
Initial commit
This commit is contained in:
commit
05d62b594e
18 changed files with 1551 additions and 0 deletions
77
protocol/AX25.c
Normal file
77
protocol/AX25.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include <string.h>
|
||||
#include "AX25.h"
|
||||
#include "protocol/HDLC.h"
|
||||
#include "util/CRC-CCIT.h"
|
||||
#include "../hardware/AFSK.h"
|
||||
|
||||
void ax25_init(AX25Ctx *ctx, FILE *channel, ax25_callback_t hook) {
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->ch = channel;
|
||||
ctx->hook = hook;
|
||||
ctx->crc_in = ctx->crc_out = CRC_CCIT_INIT_VAL;
|
||||
}
|
||||
|
||||
static void ax25_decode(AX25Ctx *ctx) {
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
if (ctx->hook) ctx->hook(ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ax25_poll(AX25Ctx *ctx) {
|
||||
int c;
|
||||
|
||||
while ((c = fgetc(ctx->ch)) != EOF) {
|
||||
if (!ctx->escape && c == HDLC_FLAG) {
|
||||
if (ctx->frame_len >= AX25_MIN_FRAME_LEN) {
|
||||
if (ctx->crc_in == AX25_CRC_CORRECT) {
|
||||
ax25_decode(ctx);
|
||||
}
|
||||
}
|
||||
ctx->sync = true;
|
||||
ctx->crc_in = CRC_CCIT_INIT_VAL;
|
||||
ctx->frame_len = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ctx->escape && c == HDLC_RESET) {
|
||||
ctx->sync = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ctx->escape && c == AX25_ESC) {
|
||||
ctx->escape = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx->sync) {
|
||||
if (ctx->frame_len < AX25_MAX_FRAME_LEN) {
|
||||
ctx->buf[ctx->frame_len++] = c;
|
||||
ctx->crc_in = update_crc_ccit(c, ctx->crc_in);
|
||||
} else {
|
||||
ctx->sync = false;
|
||||
}
|
||||
}
|
||||
ctx->escape = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ax25_putchar(AX25Ctx *ctx, uint8_t c)
|
||||
{
|
||||
if (c == HDLC_FLAG || c == HDLC_RESET || c == AX25_ESC) fputc(AX25_ESC, ctx->ch);
|
||||
ctx->crc_out = update_crc_ccit(c, ctx->crc_out);
|
||||
fputc(c, ctx->ch);
|
||||
}
|
||||
|
||||
void ax25_sendRaw(AX25Ctx *ctx, void *_buf, size_t len) {
|
||||
ctx->crc_out = CRC_CCIT_INIT_VAL;
|
||||
fputc(HDLC_FLAG, ctx->ch);
|
||||
const uint8_t *buf = (const uint8_t *)_buf;
|
||||
while (len--) ax25_putchar(ctx, *buf++);
|
||||
|
||||
uint8_t crcl = (ctx->crc_out & 0xff) ^ 0xff;
|
||||
uint8_t crch = (ctx->crc_out >> 8) ^ 0xff;
|
||||
ax25_putchar(ctx, crcl);
|
||||
ax25_putchar(ctx, crch);
|
||||
|
||||
fputc(HDLC_FLAG, ctx->ch);
|
||||
}
|
37
protocol/AX25.h
Normal file
37
protocol/AX25.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef PROTOCOL_AX25_H
|
||||
#define PROTOCOL_AX25_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define AX25_MIN_FRAME_LEN 18
|
||||
#define AX25_MAX_FRAME_LEN 850
|
||||
|
||||
#define AX25_CRC_CORRECT 0xF0B8
|
||||
|
||||
#define AX25_CTRL_UI 0x03
|
||||
#define AX25_PID_NOLAYER3 0xF0
|
||||
|
||||
struct AX25Ctx; // Forward declaration
|
||||
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
typedef void (*ax25_callback_t)(struct AX25Ctx *ctx);
|
||||
#endif
|
||||
|
||||
typedef struct AX25Ctx
|
||||
{
|
||||
uint8_t buf[AX25_MAX_FRAME_LEN];
|
||||
FILE *ch;
|
||||
size_t frame_len;
|
||||
uint16_t crc_in;
|
||||
uint16_t crc_out;
|
||||
ax25_callback_t hook;
|
||||
bool sync;
|
||||
bool escape;
|
||||
} AX25Ctx;
|
||||
|
||||
void ax25_poll(AX25Ctx *ctx);
|
||||
void ax25_sendRaw(AX25Ctx *ctx, void *_buf, size_t len);
|
||||
void ax25_init(AX25Ctx *ctx, FILE *channel, ax25_callback_t hook);
|
||||
|
||||
#endif
|
8
protocol/HDLC.h
Normal file
8
protocol/HDLC.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef PROTOCOL_HDLC_H
|
||||
#define PROTOCOL_HDLC_H
|
||||
|
||||
#define HDLC_FLAG 0x7E
|
||||
#define HDLC_RESET 0x7F
|
||||
#define AX25_ESC 0x1B
|
||||
|
||||
#endif
|
120
protocol/KISS.c
Normal file
120
protocol/KISS.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "KISS.h"
|
||||
|
||||
static uint8_t serialBuffer[AX25_MAX_FRAME_LEN]; // Buffer for holding incoming serial data
|
||||
AX25Ctx *ax25ctx;
|
||||
Afsk *channel;
|
||||
Serial *serial;
|
||||
size_t frame_len;
|
||||
bool IN_FRAME;
|
||||
bool ESCAPE;
|
||||
|
||||
uint8_t command = CMD_UNKNOWN;
|
||||
unsigned long custom_preamble = CONFIG_AFSK_PREAMBLE_LEN;
|
||||
unsigned long custom_tail = CONFIG_AFSK_TRAILER_LEN;
|
||||
|
||||
unsigned long slotTime = 200;
|
||||
uint8_t p = 63;
|
||||
|
||||
void kiss_init(AX25Ctx *ax25, Afsk *afsk, Serial *ser) {
|
||||
ax25ctx = ax25;
|
||||
serial = ser;
|
||||
channel = afsk;
|
||||
}
|
||||
|
||||
void kiss_messageCallback(AX25Ctx *ctx) {
|
||||
fputc(FEND, &serial->uart0);
|
||||
fputc(0x00, &serial->uart0);
|
||||
for (unsigned i = 0; i < ctx->frame_len; i++) {
|
||||
uint8_t b = ctx->buf[i];
|
||||
if (b == FEND) {
|
||||
fputc(FESC, &serial->uart0);
|
||||
fputc(TFEND, &serial->uart0);
|
||||
} else if (b == FESC) {
|
||||
fputc(FESC, &serial->uart0);
|
||||
fputc(TFESC, &serial->uart0);
|
||||
} else {
|
||||
fputc(b, &serial->uart0);
|
||||
}
|
||||
}
|
||||
fputc(FEND, &serial->uart0);
|
||||
}
|
||||
|
||||
void kiss_csma(AX25Ctx *ctx, uint8_t *buf, size_t len) {
|
||||
bool sent = false;
|
||||
while (!sent) {
|
||||
//puts("Waiting in CSMA");
|
||||
if(!channel->hdlc.receiving) {
|
||||
uint8_t tp = rand() & 0xFF;
|
||||
if (tp < p) {
|
||||
ax25_sendRaw(ctx, buf, len);
|
||||
sent = true;
|
||||
} else {
|
||||
ticks_t start = timer_clock();
|
||||
long slot_ticks = ms_to_ticks(slotTime);
|
||||
while (timer_clock() - start < slot_ticks) {
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (!sent && channel->hdlc.receiving) {
|
||||
// Continously poll the modem for data
|
||||
// while waiting, so we don't overrun
|
||||
// receive buffers
|
||||
ax25_poll(ax25ctx);
|
||||
|
||||
if (channel->status != 0) {
|
||||
// If an overflow or other error
|
||||
// occurs, we'll back off and drop
|
||||
// this packet silently.
|
||||
channel->status = 0;
|
||||
sent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void kiss_serialCallback(uint8_t sbyte) {
|
||||
if (IN_FRAME && sbyte == FEND && command == CMD_DATA) {
|
||||
IN_FRAME = false;
|
||||
kiss_csma(ax25ctx, serialBuffer, frame_len);
|
||||
} else if (sbyte == FEND) {
|
||||
IN_FRAME = true;
|
||||
command = CMD_UNKNOWN;
|
||||
frame_len = 0;
|
||||
} else if (IN_FRAME && frame_len < AX25_MAX_FRAME_LEN) {
|
||||
// Have a look at the command byte first
|
||||
if (frame_len == 0 && command == CMD_UNKNOWN) {
|
||||
// MicroModem supports only one HDLC port, so we
|
||||
// strip off the port nibble of the command byte
|
||||
sbyte = sbyte & 0x0F;
|
||||
command = sbyte;
|
||||
} else if (command == CMD_DATA) {
|
||||
if (sbyte == FESC) {
|
||||
ESCAPE = true;
|
||||
} else {
|
||||
if (ESCAPE) {
|
||||
if (sbyte == TFEND) sbyte = FEND;
|
||||
if (sbyte == TFESC) sbyte = FESC;
|
||||
ESCAPE = false;
|
||||
}
|
||||
serialBuffer[frame_len++] = sbyte;
|
||||
}
|
||||
} else if (command == CMD_TXDELAY) {
|
||||
custom_preamble = sbyte * 10UL;
|
||||
} else if (command == CMD_TXTAIL) {
|
||||
custom_tail = sbyte * 10;
|
||||
} else if (command == CMD_SLOTTIME) {
|
||||
slotTime = sbyte * 10;
|
||||
} else if (command == CMD_P) {
|
||||
p = sbyte;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
29
protocol/KISS.h
Normal file
29
protocol/KISS.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef _PROTOCOL_KISS
|
||||
#define _PROTOCOL_KISS 0x02
|
||||
|
||||
#include "../hardware/AFSK.h"
|
||||
#include "../hardware/Serial.h"
|
||||
#include "../util/time.h"
|
||||
#include "AX25.h"
|
||||
|
||||
#define FEND 0xC0
|
||||
#define FESC 0xDB
|
||||
#define TFEND 0xDC
|
||||
#define TFESC 0xDD
|
||||
|
||||
#define CMD_UNKNOWN 0xFE
|
||||
#define CMD_DATA 0x00
|
||||
#define CMD_TXDELAY 0x01
|
||||
#define CMD_P 0x02
|
||||
#define CMD_SLOTTIME 0x03
|
||||
#define CMD_TXTAIL 0x04
|
||||
#define CMD_FULLDUPLEX 0x05
|
||||
#define CMD_SETHARDWARE 0x06
|
||||
#define CMD_RETURN 0xFF
|
||||
|
||||
void kiss_init(AX25Ctx *ax25, Afsk *afsk, Serial *ser);
|
||||
void kiss_csma(AX25Ctx *ctx, uint8_t *buf, size_t len);
|
||||
void kiss_messageCallback(AX25Ctx *ctx);
|
||||
void kiss_serialCallback(uint8_t sbyte);
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue