From a22b814d63e7dc241b1ffa691b7e36dabaff6621 Mon Sep 17 00:00:00 2001 From: Stephen Olesen Date: Mon, 13 Jul 2015 18:55:07 -0600 Subject: [PATCH] KISS TNC mode for the AX25 stack and example. --- KISS.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++ KISS.h | 35 +++++++++++++++++ examples/KISS/KISS.ino | 36 +++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 KISS.cpp create mode 100644 KISS.h create mode 100644 examples/KISS/KISS.ino diff --git a/KISS.cpp b/KISS.cpp new file mode 100644 index 0000000..06a2115 --- /dev/null +++ b/KISS.cpp @@ -0,0 +1,88 @@ +#include +#include "AFSK.h" +#include "KISS.h" + +//AFSK::Packet kissPacket; +bool inFrame = false; +uint8_t kissBuffer[PACKET_MAX_LEN]; +uint16_t kissLen = 0; + +// Inside the KISS loop, we basically wait for data to come in from the +// KISS equipment, and look if we have anything to relay along +void KISS::loop() { + static bool currentlySending = false; + if(radio->afsk.decoder.read() || radio->afsk.rxPacketCount()) { + // A true return means something was put onto the packet FIFO + // If we actually have data packets in the buffer, process them all now + while(radio->afsk.rxPacketCount()) { + AFSK::Packet *packet = radio->afsk.getRXPacket(); + if(packet) { + writePacket(packet); + AFSK::PacketBuffer::freePacket(packet); + } + } + } + // Check if we have incoming data to turn into a packet + if(io->available()) { + uint8_t c = (uint8_t)io->read(); + if(c == KISS_FEND) { + if(inFrame && kissLen > 0) { + int i; + AFSK::Packet *packet = AFSK::PacketBuffer::makePacket(PACKET_MAX_LEN); + packet->start(); + for(i = 0; i < kissLen; i++) { + packet->append(kissBuffer[i]); + } + packet->finish(); + radio->afsk.encoder.putPacket(packet); + } + kissLen = 0; + inFrame = false; + } + // We're inside the boundaries of a FEND + if(inFrame) { + // Unescape the incoming data + if(c == KISS_FESC) { + c = io->read(); + if(c == KISS_TFESC) { + c = KISS_FESC; + } else { + c = KISS_FEND; + } + } + kissBuffer[kissLen++] = c; + } + if(kissLen == 0 && c != KISS_FEND) { + if((c & 0xf) == 0) // First byte<3:0> should be a 0, otherwise we're having options + inFrame = true; + } + } + if(radio->afsk.txReady()) { + radio->setModeTransmit(); + currentlySending = true; + if(!radio->afsk.txStart()) { // Unable to start for some reason + radio->setModeReceive(); + currentlySending = false; + } + } + if(currentlySending && radio->afsk.encoder.isDone()) { + radio->setModeReceive(); + currentlySending = false; + } +} + +void KISS::writePacket(AFSK::Packet *p) { + int i; + io->write(KISS_FEND); + io->write((uint8_t)0); // Host to TNC port identifier + for(i = 0; i < p->len-2; i++) { + char c = p->getByte(i); + if(c == KISS_FEND || c == KISS_FESC) { + io->write(KISS_FESC); + io->write((c==KISS_FEND?KISS_TFEND:KISS_TFESC)); + } else { + io->write(c); + } + } + io->write(KISS_FEND); +} diff --git a/KISS.h b/KISS.h new file mode 100644 index 0000000..dd839e6 --- /dev/null +++ b/KISS.h @@ -0,0 +1,35 @@ +#ifndef _KISS_H_ +#define _KISS_H_ + +#include +#include "AFSK.h" + +#define KISS_FEND 0xC0 +#define KISS_FESC 0xDB +#define KISS_TFEND 0xDC +#define KISS_TFESC 0xDD + +class KISS { +public: + KISS(Stream *_io, HamShield *h, DDS *d) : io(_io), radio(h), dds(d) {} + bool read(); + void writePacket(AFSK::Packet *); + void loop(); + inline void isr() { + static uint8_t tcnt = 0; + TIFR1 = _BV(ICF1); // Clear the timer flag + dds->clockTick(); + if(++tcnt == (DDS_REFCLK_DEFAULT/9600)) { + PORTD |= _BV(2); // Diagnostic pin (D2) + radio->afsk.timer(); + tcnt = 0; + } + PORTD &= ~(_BV(2)); + } +private: + Stream *io; + HamShield *radio; + DDS *dds; +}; + +#endif /* _KISS_H_ */ diff --git a/examples/KISS/KISS.ino b/examples/KISS/KISS.ino new file mode 100644 index 0000000..7cec7e1 --- /dev/null +++ b/examples/KISS/KISS.ino @@ -0,0 +1,36 @@ +#define DDS_REFCLK_DEFAULT 19200 + +#include +#include +#include + +HamShield radio; +DDS dds; +KISS kiss(&Serial, &radio, &dds); + +void setup() { + pinMode(2, OUTPUT); + pinMode(3, OUTPUT); + pinMode(11, INPUT); + + Serial.begin(9600); + Wire.begin(); + radio.initialize(); + radio.setVHF(); + radio.setSQOff(); + radio.setFrequency(145010); + I2Cdev::writeWord(A1846S_DEV_ADDR_SENLOW, 0x30, 0x06); + I2Cdev::writeWord(A1846S_DEV_ADDR_SENLOW, 0x30, 0x26); + I2Cdev::writeWord(A1846S_DEV_ADDR_SENLOW, 0x44, 0b0000011111111111); + + dds.start(); + radio.afsk.start(&dds); +} + +void loop() { + kiss.loop(); +} + +ISR(ADC_vect) { + kiss.isr(); +}