mirror of
https://github.com/markqvist/OpenModem.git
synced 2025-05-21 15:50:32 -04:00
Initial KISS support
This commit is contained in:
parent
9addf50a33
commit
6e3d8d9987
18 changed files with 1521 additions and 164 deletions
16
Modem/afsk.c
16
Modem/afsk.c
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
195
Modem/main.c
195
Modem/main.c
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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"
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue