diff --git a/AFSK.cpp b/AFSK.cpp index 26ebbd2..1fcfab6 100644 --- a/AFSK.cpp +++ b/AFSK.cpp @@ -22,57 +22,69 @@ volatile unsigned long lastTx = 0; volatile unsigned long lastTxEnd = 0; volatile unsigned long lastRx = 0; -#define T_BIT ((unsigned int)(9600/1200)) +#define T_BIT ((unsigned int)(SAMPLERATE/BITRATE)) #ifdef PACKET_PREALLOCATE SimpleFIFO preallocPool; +AFSK::Packet preallocPackets[PPOOL_SIZE]; #endif void AFSK::Encoder::process() { - // Check what clock pulse we're on - if(bitClock == 0) { // We are onto our next bit timing - // We're on the start of a byte position, so fetch one - if(bitPosition == 0) { - if(preamble) { // Still in preamble - currentByte = HDLC_PREAMBLE; - --preamble; // Decrement by one - } else { - if(!packet) { // We aren't on a packet, grab one - // Unless we already sent enough - if(maxTx-- == 0) { - stop(); - lastTxEnd = millis(); - return; - } - packet = pBuf.getPacket(); - if(!packet) { // There actually weren't any - stop(); // Stop transmitting and return - lastTxEnd = millis(); - return; - } - lastTx = millis(); - currentBytePos = 0; + // We're on the start of a byte position, so fetch one + if(bitPosition == 0) { + if(preamble) { // Still in preamble + currentByte = HDLC_PREAMBLE; + --preamble; // Decrement by one + } else { + if(!packet) { // We aren't on a packet, grab one + // Unless we already sent enough + if(maxTx-- == 0) { + stop(); + lastTxEnd = millis(); + return; } - - // We ran out of actual data, provide an HDLC frame (idle) - if(currentBytePos++ == packet->len) { - pBuf.freePacket(packet); - packet = pBuf.getPacket(); // Get the next, if any - currentBytePos = 0; - currentByte = HDLC_FRAME; - hdlc = true; + packet = pBuf.getPacket(); + if(!packet) { // There actually weren't any + stop(); // Stop transmitting and return + lastTxEnd = millis(); + return; + } + lastTx = millis(); + currentBytePos = 0; + nextByte = HDLC_FRAME; // Our next output should be a frame boundary + hdlc = true; + } + + // We ran out of actual data, provide an HDLC frame (idle) + if(currentBytePos == packet->len && nextByte == 0) { + // We also get here if nextByte isn't set, to handle empty frames + pBuf.freePacket(packet); + packet = pBuf.getPacket(); // Get the next, if any + //packet = NULL; + currentBytePos = 0; + nextByte = 0; + currentByte = HDLC_FRAME; + hdlc = true; + } else { + if(nextByte) { + // We queued up something other than the actual stream to be sent next + currentByte = nextByte; + nextByte = 0; } else { - // Grab the next byte - currentByte = packet->getByte(); //[currentBytePos++]; - if(currentByte == HDLC_ESCAPE) { - currentByte = packet->getByte(); //[currentBytePos++]; - hdlc = true; + // Get the next byte to send, but if it's an HDLC frame, escape it + // and queue the real byte for the next cycle. + currentByte = packet->getByte(); + if(currentByte == HDLC_FRAME) { + nextByte = currentByte; + currentByte = HDLC_ESCAPE; } else { - hdlc = false; + currentBytePos++; } + hdlc = false; // If we get here, it will be NRZI bit stuffed } } } + } // Pickup the last bit currentBit = currentByte & 0x1; @@ -94,15 +106,12 @@ void AFSK::Encoder::process() { // So, if not a 1, toggle to the opposite tone if(!currentBit) currentTone = !currentTone; - } - - // Advance the bitclock here, to let first bit be sent early - if(++bitClock == T_BIT) - bitClock = 0; - + if(currentTone == 0) { + PORTD |= _BV(7); dds->setFrequency(AFSK_SPACE); } else { + PORTD &= ~_BV(7); dds->setFrequency(AFSK_MARK); } } @@ -120,7 +129,7 @@ bool AFSK::Encoder::start() { currentBit = 0; lastZero = 0; bitPosition = 0; - bitClock = 0; + //bitClock = 0; preamble = 0b110000; // 6.7ms each, 23 = 153ms done = false; hdlc = true; @@ -128,6 +137,7 @@ bool AFSK::Encoder::start() { currentBytePos = 0; maxTx = 3; sending = true; + nextByte = 0; dds->setFrequency(0); dds->on(); return true; @@ -137,13 +147,14 @@ void AFSK::Encoder::stop() { randomWait = 0; sending = false; done = true; + dds->setFrequency(0); dds->off(); } AFSK::Decoder::Decoder() { // Initialize the sampler delay line (phase shift) - for(unsigned char i = 0; i < SAMPLEPERBIT/2; i++) - delay_fifo.enqueue(0); + //for(unsigned char i = 0; i < SAMPLEPERBIT/2; i++) + // delay_fifo.enqueue(0); } bool AFSK::HDLCDecode::hdlcParse(bool bit, SimpleFIFO *fifo) { @@ -271,16 +282,14 @@ bool AFSK::Decoder::read() { bool escaped = false; if(c == HDLC_ESCAPE) { // We received an escaped byte, mark it escaped = true; - currentPacket->append(HDLC_ESCAPE); // Append without FCS + // Do we want to keep HDLC_ESCAPEs in the packet? + //currentPacket->append(HDLC_ESCAPE); // Append without FCS c = rx_fifo.dequeue(); // Reset to the next character } // Append all the bytes // This will include unescaped HDLC_FRAME bytes - //if(c == HDLC_FRAME && !escaped) - //currentPacket->append(c); // Framing bytes don't get FCS updates - //else - if(c != HDLC_FRAME) + if(c != HDLC_FRAME || escaped) // Append frame if it is escaped currentPacket->appendFCS(c); // Escaped characters and all else go into FCS if(currentPacket->len > PACKET_MAX_LEN) { @@ -376,6 +385,12 @@ AFSK::PacketBuffer::PacketBuffer() { for(unsigned char i = 0; i < PACKET_BUFFER_SIZE; ++i) { packets[i] = 0x0; } +#ifdef PACKET_PREALLOCATE + for(unsigned char i = 0; i < PPOOL_SIZE; ++i) { + // Put some empty packets in the FIFO + preallocPool.enqueue(&preallocPackets[i]); + } +#endif } unsigned char AFSK::PacketBuffer::readyCount() volatile { @@ -421,7 +436,7 @@ void AFSK::Packet::init(unsigned short dlen) { ready = 0; #ifdef PACKET_PREALLOCATE freeData = 0; - maxLen = 128; // Put it here instead + maxLen = PACKET_MAX_LEN; // Put it here instead #else freeData = 1; dataPtr = (uint8_t *)malloc(dlen+16); @@ -440,7 +455,9 @@ AFSK::Packet *AFSK::PacketBuffer::makePacket(unsigned short dlen) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { //Packet *p = findPooledPacket(); #ifdef PACKET_PREALLOCATE - p = preallocPool.dequeue(); + if(preallocPool.count()) + p = preallocPool.dequeue(); + else p = NULL; #else p = new Packet(); //(Packet *)malloc(sizeof(Packet)); #endif @@ -518,8 +535,163 @@ size_t AFSK::Packet::appendCallsign(const char *callsign, uint8_t ssid, bool fin appendFCS(ssidField); } -void AFSK::Packet::print(Stream *s) { +#ifdef PACKET_PARSER +// Process the AX25 frame and turn it into a bunch of useful strings +bool AFSK::Packet::parsePacket() { + uint8_t *d = dataPtr; + int i; + + // First 7 bytes are destination-ssid + for(i = 0; i < 6; i++) { + dstCallsign[i] = (*d++)>>1; + if(dstCallsign[i] == ' ') { + dstCallsign[i] = '\0'; + } + } + dstCallsign[6] = '\0'; + dstSSID = ((*d++)>>1) & 0xF; + + // Next 7 bytes are source-ssid + for(i = 0; i < 6; i++) { + srcCallsign[i] = (*d++)>>1; + if(srcCallsign[i] == ' ') { + srcCallsign[i] = '\0'; + } + } + srcCallsign[6] = '\0'; + srcSSID = *d++; // Don't shift yet, we need the LSB + + digipeater[0][0] = '\0'; // Set null in case we have none anyway + if((srcSSID & 1) == 0) { // Not the last address field + int digi; // Which digi we're on + for(digi = 0; digi < 8; digi++) { + for(i = 0; i < 6; i++) { + digipeater[digi][i] = (*d++)>>1; + if(digipeater[digi][i] == ' ') { + digipeater[digi][i] = '\0'; + } + } + uint8_t last = (*d) & 1; + digipeaterSSID[digi] = ((*d++)>>1) & 0xF; + if(last == 1) + break; + } + digipeater[digi][6] = '\0'; + for(digi += 1; digi<8; digi++) { // Empty out the rest of them + digipeater[digi][0] = '\0'; + } + } + + // Now handle the SSID itself + srcSSID >>= 1; + srcSSID &= 0xF; + + // After the address parsing, we end up on the control field + control = *d++; + // We have a PID if control type is U or I + // Control & 1 == 0 == I frame + // Control & 3 == 3 == U frame + if((control & 1) == 0 || (control & 3) == 3) + pid = *d++; + else pid = 0; + + // If there is no PID, we have no data + if(!pid) { + iFrameData = NULL; + return true; + } + + // At this point, we've walked far enough along that data is just at d + iFrameData = d; + + // Cheat a little by setting the first byte of the FCS to 0, making it a string + // First FCS byte is found at -2, HDLC flags aren't in this buffer + dataPtr[len-2] = '\0'; + + return true; +} +#endif + +void AFSK::Packet::printPacket(Stream *s) { uint8_t i; +#ifdef PACKET_PARSER + if(!parsePacket()) { + s->print(F("Packet not valid")); + return; + } + + s->print(srcCallsign); + if(srcSSID > 0) { + s->write('-'); + s->print(srcSSID); + } + s->print(F(" > ")); + s->print(dstCallsign); + if(dstSSID > 0) { + s->write('-'); + s->print(dstSSID); + } + s->write(' '); + if(digipeater[0][0] != '\0') { + s->print(F("via ")); + for(i = 0; i < 8; i++) { + if(digipeater[i][0] == '\0') + break; + s->print(digipeater[i]); + if(digipeaterSSID[i] != 0) { + s->write('-'); + s->print(digipeaterSSID[i]); + } + if((digipeaterSSID[i] & _BV(7)) == _BV(7)) { + s->write('*'); // Digipeated already + } + // If we might have more, check to add a comma + if(i < 7 && digipeater[i+1][0] != '\0') { + s->write(','); + } + s->write(' '); + } + } + + // This is an S frame, we can only print control info + if(control & 3 == 1) { + switch((control>>2)&3) { + case 0: + s->print(F("RR")); + break; + case 1: + s->print(F("RNR")); + break; + case 2: + s->print(F("REJ")); + break; + case 3: // Undefined + s->print(F("unk")); + break; + } + // Use a + to indicate poll bit + if(control & _BV(4) == _BV(4)) { + s->write('+'); + } + } else if((control & 3) == 3) { // U Frame + s->print(F("U(")); + s->print(control, HEX); + s->write(','); + s->print(pid, HEX); + s->print(F(") ")); + } else if((control & 1) == 0) { // I Frame + s->print(F("I(")); + s->print(control, HEX); + s->write(','); + s->print(pid, HEX); + s->print(F(") ")); + } + s->print(F("len ")); + s->print(len); + s->print(F(": ")); + s->print((char *)iFrameData); + s->println(); +#else // no packet parser, do a rudimentary print // Second 6 bytes are source callsign for(i=7; i<13; i++) { s->write(*(dataPtr+i)>>1); @@ -527,7 +699,7 @@ void AFSK::Packet::print(Stream *s) { // SSID s->write('-'); s->print((*(dataPtr+13) >> 1) & 0xF); - s->print(" -> "); + s->print(F(" -> ")); // First 6 bytes are destination callsign for(i=0; i<6; i++) { s->write(*(dataPtr+i)>>1); @@ -540,14 +712,23 @@ void AFSK::Packet::print(Stream *s) { for(i = 15; iwrite(*(dataPtr+i)); } +#endif } // Determine what we want to do on this ADC tick. void AFSK::timer() { - if(encoder.isSending()) + static uint8_t tcnt = 0; + if(++tcnt == T_BIT && encoder.isSending()) { + PORTD |= _BV(6); + // Only run the encoder every 8th tick + // This is actually DDS RefClk / 1200 = 8, set as T_BIT + // A different refclk needs a different value encoder.process(); - else + tcnt = 0; + PORTD &= ~_BV(6); + } else { decoder.process(((int8_t)(ADCH - 128))); + } } void AFSK::start(DDS *dds) { diff --git a/AFSK.h b/AFSK.h index 68504e7..e7b2418 100644 --- a/AFSK.h +++ b/AFSK.h @@ -15,15 +15,19 @@ #define PACKET_BUFFER_SIZE 2 #define PACKET_STATIC 0 +// Enable the packet parser which will tokenize the AX25 frame into easy strings +#define PACKET_PARSER + // If this is set, all the packet buffers will be pre-allocated at compile time // This will use more RAM, but can make it easier to do memory planning. // TODO: Make this actually work right and not crash. -//#define PACKET_PREALLOCATE +#define PACKET_PREALLOCATE -// This is with all the digis, two addresses, framing and full payload -// Two more bytes are added for HDLC_ESCAPEs -#define PACKET_MAX_LEN 512 -#define AX25_PACKET_HEADER_MINLEN 22 +// This is with all the digis, two addresses, and full payload +// Dst(7) + Src(7) + Digis(56) + Ctl(1) + PID(1) + Data(0-256) + FCS(2) +#define PACKET_MAX_LEN 330 +// Minimum is Dst + Src + Ctl + FCS +#define AX25_PACKET_HEADER_MINLEN 17 // HDLC framing bits #define HDLC_FRAME 0x7E @@ -65,9 +69,11 @@ public: } inline void start() { fcs = 0xffff; - *dataPos++ = HDLC_ESCAPE; - *dataPos++ = HDLC_FRAME; - len = 2; + // No longer put an explicit frame start here + //*dataPos++ = HDLC_ESCAPE; + //*dataPos++ = HDLC_FRAME; + //len = 2; + len = 0; } inline bool append(char c) { @@ -96,8 +102,9 @@ public: inline void finish() { append(~(fcs & 0xff)); append(~((fcs>>8) & 0xff)); - append(HDLC_ESCAPE); - append(HDLC_FRAME); + // No longer append the frame boundaries themselves + //append(HDLC_ESCAPE); + //append(HDLC_FRAME); ready = 1; } @@ -111,13 +118,27 @@ public: inline bool crcOK() { return (fcs == 0xF0B8); } - - void print(Stream *s); +#ifdef PACKET_PARSER + bool parsePacket(); +#endif + void printPacket(Stream *s); private: #ifdef PACKET_PREALLOCATE - uint8_t dataPtr[128]; + uint8_t dataPtr[PACKET_MAX_LEN]; // 256 byte I frame + headers max of 78 #else uint8_t *dataPtr; +#endif +#ifdef PACKET_PARSER + char srcCallsign[7]; + uint8_t srcSSID; + char dstCallsign[7]; + uint8_t dstSSID; + char digipeater[8][7]; + uint8_t digipeaterSSID[8]; + uint8_t *iFrameData; + uint8_t length; + uint8_t control; + uint8_t pid; #endif uint8_t *dataPos, *readPos; unsigned short fcs; @@ -156,6 +177,7 @@ public: done = true; packet = 0x0; currentBytePos = 0; + nextByte = 0; } void setDDS(DDS *d) { dds = d; } volatile inline bool isSending() volatile { @@ -184,12 +206,13 @@ public: byte lastZero : 3; byte bitPosition : 3; byte preamble : 6; - byte bitClock; + //byte bitClock; bool hdlc; + byte nextByte; byte maxTx; Packet *packet; PacketBuffer pBuf; - unsigned char currentBytePos; + unsigned int currentBytePos; volatile unsigned long randomWait; volatile bool done; DDS *dds; @@ -228,7 +251,7 @@ public: } private: Packet *currentPacket; - SimpleFIFO delay_fifo; + //SimpleFIFO delay_fifo; SimpleFIFO rx_fifo; // This should be drained fairly often int16_t iir_x[2]; int16_t iir_y[2]; @@ -243,12 +266,12 @@ public: inline bool read() { return decoder.read(); } - inline bool txReady() volatile { + volatile inline bool txReady() volatile { if(encoder.isDone() && encoder.hasPackets()) return true; return false; } - inline bool isDone() volatile { return encoder.isDone(); } + volatile inline bool isDone() volatile { return encoder.isDone(); } inline bool txStart() { if(decoder.isReceiving()) { encoder.setRandomWait();