Initial KISS support

This commit is contained in:
Mark Qvist 2014-11-10 00:02:19 +01:00
parent 9addf50a33
commit 6e3d8d9987
18 changed files with 1521 additions and 164 deletions

View file

@ -13,6 +13,10 @@
#include <struct/fifobuf.h> // FIFO buffer implementation from BertOS
#include <string.h> // String operations, primarily used for memset function
#if SERIAL_PROTOCOL == PROTOCOL_KISS
extern unsigned long kiss_preamble;
extern unsigned long kiss_tail;
#endif
//////////////////////////////////////////////////////
// Definitions and some useful macros //
@ -449,14 +453,22 @@ static void afsk_txStart(Afsk *afsk) {
LED_TX_ON();
// We also need to calculate how many HDLC_FLAG
// bytes we need to send in preamble
afsk->preambleLength = DIV_ROUND(CONFIG_AFSK_PREAMBLE_LEN * BITRATE, 8000);
#if SERIAL_PROTOCOL == PROTOCOL_KISS
afsk->preambleLength = DIV_ROUND(kiss_preamble * BITRATE, 8000);
#else
afsk->preambleLength = DIV_ROUND(CONFIG_AFSK_PREAMBLE_LEN * BITRATE, 8000);
#endif
AFSK_DAC_IRQ_START();
}
// We make the same calculation for the tail length,
// but this needs to be atomic, since the txStart
// function could potentially be called while we
// are already transmitting.
ATOMIC(afsk->tailLength = DIV_ROUND(CONFIG_AFSK_TRAILER_LEN * BITRATE, 8000));
#if SERIAL_PROTOCOL == PROTOCOL_KISS
ATOMIC(afsk->tailLength = DIV_ROUND(kiss_tail * BITRATE, 8000));
#else
ATOMIC(afsk->tailLength = DIV_ROUND(CONFIG_AFSK_TRAILER_LEN * BITRATE, 8000));
#endif
}
// This is the DAC ISR, called at sampling rate whenever the DAC IRQ is on.

View file

@ -2,9 +2,16 @@
#ifndef FSK_CFG
#define FSK_CFG
// Serial options
#define PROTOCOL_SIMPLE_SERIAL 0x01
#define PROTOCOL_KISS 0x02
#define SERIAL_PROTOCOL PROTOCOL_SIMPLE_SERIAL
//#define SERIAL_PROTOCOL PROTOCOL_KISS
// Debug & test options
#define SERIAL_DEBUG false
#define PASSALL false
#define PASSALL true
#define AUTOREPLY false
// Modem options

View file

@ -25,8 +25,6 @@
#include "cfg/debug.h" // Debug configuration from BertOS
#endif
#define SERIAL_PROTOCOL PROTOCOL_SIMPLE_SERIAL
//////////////////////////////////////////////////////
// A few definitions //
//////////////////////////////////////////////////////
@ -38,17 +36,21 @@ static Serial ser; // Declare a serial interface struct
#define ADC_CH 0 // Define which channel (pin) we want
// for the ADC (this is A0 on arduino)
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
static uint8_t serialBuffer[CONFIG_AX25_FRAME_BUF_LEN+1]; // Buffer for holding incoming serial data
static int sbyte; // For holding byte read from serial port
static size_t serialLen = 0; // Counter for counting length of data from serial
static bool sertx = false; // Flag signifying whether it's time to send data
// received on the serial port.
#endif
static uint8_t serialBuffer[CONFIG_AX25_FRAME_BUF_LEN+1]; // Buffer for holding incoming serial data
static int sbyte; // For holding byte read from serial port
static size_t serialLen = 0; // Counter for counting length of data from serial
static bool sertx = false; // Flag signifying whether it's time to send data
// received on the serial port.
#if SERIAL_PROTOCOL == PROTOCOL_KISS
static uint8_t sbyte; // For holding byte read from serial port
#endif
#define SER_BUFFER_FULL (serialLen < CONFIG_AX25_FRAME_BUF_LEN-1)
//////////////////////////////////////////////////////
// And here comes the actual program :) //
//////////////////////////////////////////////////////
@ -56,15 +58,19 @@ static bool sertx = false; // Flag signifying whether it's
// This is a callback we register with the protocol,
// so we can process each packet as they are decoded.
// Right now it just prints the packet to the serial port.
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
static void message_callback(struct AX25Msg *msg)
{
if (SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL) {
ss_messageCallback(msg, &ser);
}
if (SERIAL_PROTOCOL == PROTOCOL_KISS) {
// Not implemented yet
}
ss_messageCallback(msg, &ser);
}
#endif
#if SERIAL_PROTOCOL == PROTOCOL_KISS
static void message_callback(struct AX25Ctx *ctx)
{
kiss_messageCallback(ctx);
}
#endif
// Simple initialization function.
static void init(void)
@ -90,9 +96,16 @@ static void init(void)
// ... and a protocol context with the modem
ax25_init(&ax25, &afsk.fd, message_callback);
// Init SimpleSerial
ss_init(&ax25);
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
// Init SimpleSerial
ss_init(&ax25);
#endif
#if SERIAL_PROTOCOL == PROTOCOL_KISS
// Init KISS
kiss_init(&ax25, &ser);
#endif
// That's all!
}
@ -100,77 +113,93 @@ int main(void)
{
// Start by running the main initialization
init();
// Record the current tick count for time-keeping
ticks_t start = timer_clock();
// Go into ye good ol' infinite loop
while (1)
{
// First we instruct the protocol to check for
// incoming data
ax25_poll(&ax25);
#if SERIAL_PROTOCOL == PROTOCOL_KISS
while (1) {
// First we instruct the protocol to check for
// incoming data
ax25_poll(&ax25);
// Poll for incoming serial data
if (!sertx && ser_available(&ser)) {
// We then read a byte from the serial port.
// Notice that we use "_nowait" since we can't
// have this blocking execution until a byte
// comes in.
sbyte = ser_getchar_nowait(&ser);
// If SERIAL_DEBUG is specified we'll handle
// serial data as direct human input and only
// transmit when we get a LF character
#if SERIAL_DEBUG
// If we have not yet surpassed the maximum frame length
// and the byte is not a "transmit" (newline) character,
// we should store it for transmission.
if ((serialLen < CONFIG_AX25_FRAME_BUF_LEN) && (sbyte != 10)) {
// Put the read byte into the buffer;
serialBuffer[serialLen] = sbyte;
// Increment the read length counter
serialLen++;
} else {
// If one of the above conditions were actually the
// case, it means we have to transmit, se we set
// transmission flag to true.
sertx = true;
}
#else
// Otherwise we assume the modem is running
// in automated mode, and we push out data
// as it becomes available. We either transmit
// immediately when the max frame length has
// been reached, or when we get no input for
// a certain amount of time.
if (serialLen < CONFIG_AX25_FRAME_BUF_LEN-1) {
// Put the read byte into the buffer;
serialBuffer[serialLen] = sbyte;
// Increment the read length counter
serialLen++;
} else {
// If max frame length has been reached
// we need to transmit.
serialBuffer[serialLen] = sbyte;
serialLen++;
sertx = true;
}
start = timer_clock();
#endif
} else {
if (!SERIAL_DEBUG && serialLen > 0 && timer_clock() - start > ms_to_ticks(TX_MAXWAIT)) {
sertx = true;
if (ser_available(&ser)) {
sbyte = ser_getchar_nowait(&ser);
kiss_serialCallback(sbyte);
}
}
if (sertx) {
ss_serialCallback(serialBuffer, serialLen, &ser, &ax25);
sertx = false;
serialLen = 0;
}
#endif
}
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
// Record the current tick count for time-keeping
ticks_t start = timer_clock();
// Go into ye good ol' infinite loop
while (1) {
// First we instruct the protocol to check for
// incoming data
ax25_poll(&ax25);
// Poll for incoming serial data
if (!sertx && ser_available(&ser)) {
// We then read a byte from the serial port.
// Notice that we use "_nowait" since we can't
// have this blocking execution until a byte
// comes in.
sbyte = ser_getchar_nowait(&ser);
// If SERIAL_DEBUG is specified we'll handle
// serial data as direct human input and only
// transmit when we get a LF character
#if SERIAL_DEBUG
// If we have not yet surpassed the maximum frame length
// and the byte is not a "transmit" (newline) character,
// we should store it for transmission.
if ((serialLen < CONFIG_AX25_FRAME_BUF_LEN) && (sbyte != 10)) {
// Put the read byte into the buffer;
serialBuffer[serialLen] = sbyte;
// Increment the read length counter
serialLen++;
} else {
// If one of the above conditions were actually the
// case, it means we have to transmit, se we set
// transmission flag to true.
sertx = true;
}
#else
// Otherwise we assume the modem is running
// in automated mode, and we push out data
// as it becomes available. We either transmit
// immediately when the max frame length has
// been reached, or when we get no input for
// a certain amount of time.
if (serialLen < CONFIG_AX25_FRAME_BUF_LEN-1) {
// Put the read byte into the buffer;
serialBuffer[serialLen] = sbyte;
// Increment the read length counter
serialLen++;
} else {
// If max frame length has been reached
// we need to transmit.
serialBuffer[serialLen] = sbyte;
serialLen++;
sertx = true;
}
start = timer_clock();
#endif
} else {
if (!SERIAL_DEBUG && serialLen > 0 && timer_clock() - start > ms_to_ticks(TX_MAXWAIT)) {
sertx = true;
}
}
if (sertx) {
ss_serialCallback(serialBuffer, serialLen, &ser, &ax25);
sertx = false;
serialLen = 0;
}
}
#endif
return 0;
}

View file

@ -0,0 +1,81 @@
#include <stdlib.h>
#include <string.h>
#include <avr/eeprom.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include <drv/timer.h> // Timer driver from BertOS
#include "KISS.h"
static uint8_t serialBuffer[CONFIG_AX25_FRAME_BUF_LEN+1]; // Buffer for holding incoming serial data
AX25Ctx *ax25ctx;
Serial *serial;
size_t frame_len;
bool IN_FRAME;
bool ESCAPE;
uint8_t command = CMD_UNKNOWN;
unsigned long kiss_preamble = CONFIG_AFSK_PREAMBLE_LEN;
unsigned long kiss_tail = CONFIG_AFSK_TRAILER_LEN;
void kiss_init(AX25Ctx *ax25, Serial *ser) {
ax25ctx = ax25;
serial = ser;
}
void kiss_messageCallback(AX25Ctx *ctx) {
kfile_putc(FEND, &serial->fd);
kfile_putc(0x00, &serial->fd);
for (unsigned i = 0; i < ctx->frm_len; i++) {
uint8_t b = ctx->buf[i];
if (b == FEND) {
kfile_putc(FESC, &serial->fd);
kfile_putc(TFEND, &serial->fd);
} else if (b == FESC) {
kfile_putc(FESC, &serial->fd);
kfile_putc(TFESC, &serial->fd);
} else {
kfile_putc(b, &serial->fd);
}
}
kfile_putc(FEND, &serial->fd);
}
void fon(void) {
long ts = 300000;
while (ts--) PORTB |= BV(2);
}
void kiss_serialCallback(uint8_t sbyte) {
if (IN_FRAME && sbyte == FEND && command == CMD_DATA) {
IN_FRAME = false;
ax25_sendRaw(ax25ctx, serialBuffer, frame_len);
} else if (sbyte == FEND) {
IN_FRAME = true;
command = CMD_UNKNOWN;
frame_len = 0;
} else if (IN_FRAME && frame_len < CONFIG_AX25_FRAME_BUF_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) {
kiss_preamble = sbyte * 10UL;
} else if (command == CMD_TXTAIL) {
kiss_tail = sbyte * 10;
}
}
}

View file

@ -1,10 +1,27 @@
#ifndef PROTOCOL_KISS
#define PROTOCOL_KISS 0x02
#ifndef _PROTOCOL_KISS
#define _PROTOCOL_KISS 0x02
#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
#include <net/ax25.h>
#include <drv/ser.h>
void kiss_init(AX25Ctx *ax25, Serial *ser);
void kiss_messageCallback(AX25Ctx *ctx);
void kiss_serialCallback(uint8_t sbyte);
void fon(void);
#endif

View file

@ -1,9 +1,8 @@
#ifndef PROTOCOL_SIMPLE_SERIAL
#ifndef _PROTOCOL_SIMPLE_SERIAL
#define _PROTOCOL_SIMPLE_SERIAL 0x01
#include <net/ax25.h>
#include <drv/ser.h>
#define PROTOCOL_SIMPLE_SERIAL 0x01
#define DEFAULT_CALLSIGN "NOCALL"
#define DEFAULT_DESTINATION_CALL "APZMDM"