This project is a collection of former (and some new) projects connected together to make an APRS digipeater, which doubles as an APRS weather station, with PE1RXF telemetry server capabilities.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
4.9 KiB

10 months ago
#include <stdlib.h>
#include <string.h>
#include "device.h"
#include "KISS.h"
static uint8_t serialBuffer[LLP_MAX_DATA_SIZE]; // Buffer for holding incoming serial data
LLPCtx *llpCtx;
Afsk *channel;
Serial *serial;
size_t frame_len;
bool IN_FRAME;
bool ESCAPE;
bool FLOWCONTROL;
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 = 255;
ticks_t timeout_ticks;
void kiss_init(LLPCtx *ctx, Afsk *afsk, Serial *ser) {
llpCtx = ctx;
serial = ser;
channel = afsk;
FLOWCONTROL = false;
}
void kiss_messageCallback(LLPCtx *ctx) {
#if (SERIAL_FRAMING == SERIAL_FRAMING_DIRECT)
for (unsigned i = 0; i < ctx->frame_len; i++) {
uint8_t b = ctx->buf[i];
fputc(b, &serial->uart0);
}
#else
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);
#endif
}
void kiss_csma(LLPCtx *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) {
//llp_sendRaw(ctx, buf, len);
llp_broadcast(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
llp_poll(llpCtx);
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;
}
}
}
}
if (FLOWCONTROL) {
while (!ctx->ready_for_data) { /* Wait */ }
fputc(FEND, &serial->uart0);
fputc(CMD_READY, &serial->uart0);
fputc(0x01, &serial->uart0);
fputc(FEND, &serial->uart0);
}
}
void kiss_checkTimeout(bool force) {
if (force || (IN_FRAME && timer_clock() - timeout_ticks > ms_to_ticks(TX_MAXWAIT))) {
kiss_csma(llpCtx, serialBuffer, frame_len);
IN_FRAME = false;
frame_len = 0;
}
}
void kiss_serialCallback(uint8_t sbyte) {
#if SERIAL_FRAMING == SERIAL_FRAMING_DIRECT
timeout_ticks = timer_clock();
IN_FRAME = true;
serialBuffer[frame_len++] = sbyte;
if (frame_len >= LLP_MAX_DATA_SIZE) kiss_checkTimeout(true);
#else
if (IN_FRAME && sbyte == FEND && command == CMD_DATA) {
IN_FRAME = false;
kiss_csma(llpCtx, serialBuffer, frame_len);
} else if (sbyte == FEND) {
IN_FRAME = true;
command = CMD_UNKNOWN;
frame_len = 0;
} else if (IN_FRAME && frame_len < LLP_MAX_DATA_SIZE) {
// 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;
} else if (command == CMD_READY) {
if (sbyte == 0x00) {
FLOWCONTROL = false;
} else {
FLOWCONTROL = true;
}
}
}
#endif
}