From 163c6b021fceeec025576f5000c6e3c7a0e248d7 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Thu, 28 May 2020 22:18:19 +0200 Subject: [PATCH] Reworked queue and buffering --- Config.h | 47 +++------- Framing.h | 3 - RNode_Firmware.ino | 215 +++++++++++++++++++++++++-------------------- Utilities.h | 159 +++++++++++++++++++++++++++++++++ 4 files changed, 290 insertions(+), 134 deletions(-) diff --git a/Config.h b/Config.h index 3d76536..144d78b 100644 --- a/Config.h +++ b/Config.h @@ -4,18 +4,14 @@ #define CONFIG_H #define MAJ_VERS 0x01 - #define MIN_VERS 0x0D + #define MIN_VERS 0x0E - #define MCU_328P 0x90 #define MCU_1284P 0x91 #define MODE_HOST 0x11 #define MODE_TNC 0x12 - #if defined(__AVR_ATmega328P__) - #define MCU_VARIANT MCU_328P - #warning "Firmware is being compiled for atmega328p based boards" - #elif defined(__AVR_ATmega1284P__) + #if defined(__AVR_ATmega1284P__) #define MCU_VARIANT MCU_1284P #warning "Firmware is being compiled for atmega1284p based boards" #else @@ -25,22 +21,11 @@ #define MTU 500 #define SINGLE_MTU 255 #define HEADER_L 1 + #define MIN_L 1 + #define CMD_L 4 // MCU dependent configuration parameters - #if MCU_VARIANT == MCU_328P - const int pin_cs = 7; - const int pin_reset = 6; - const int pin_dio = 2; - const int pin_led_rx = 5; - const int pin_led_tx = 4; - - #define FLOW_CONTROL_ENABLED true - #define QUEUE_SIZE 0 - - #define EEPROM_SIZE 512 - #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED - #endif #if MCU_VARIANT == MCU_1284P const int pin_cs = 4; @@ -49,10 +34,9 @@ const int pin_led_rx = 12; const int pin_led_tx = 13; - #define FLOW_CONTROL_ENABLED true - #define QUEUE_SIZE 24 - #define QUEUE_BUF_SIZE (QUEUE_SIZE+1) - #define QUEUE_MEM QUEUE_BUF_SIZE * MTU + #define CONFIG_UART_BUFFER_SIZE 6750 + #define CONFIG_QUEUE_SIZE 6750 + #define CONFIG_QUEUE_MAX_LENGTH 70 #define EEPROM_SIZE 4096 #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED @@ -67,7 +51,6 @@ // SX1276 RSSI offset to get dBm value from // packet RSSI register const int rssi_offset = 157; - const int snr_offset = 128; // Default LoRa settings int lora_sf = 0; @@ -91,23 +74,19 @@ uint8_t last_snr_raw = 0x00; size_t read_len = 0; uint8_t seq = 0xFF; + + // Incoming packet buffer uint8_t pbuf[MTU]; - uint8_t sbuf[MTU]; + + // KISS command buffer uint8_t cbuf[CMD_L]; - #if QUEUE_SIZE > 0 - uint8_t tbuf[MTU]; - uint8_t qbuf[QUEUE_MEM]; - size_t queued_lengths[QUEUE_BUF_SIZE]; - #endif + // LoRa transmit buffer + uint8_t tbuf[MTU]; uint32_t stat_rx = 0; uint32_t stat_tx = 0; - bool outbound_ready = false; - size_t queue_head = 0; - size_t queue_tail = 0; - bool stat_signal_detected = false; bool stat_signal_synced = false; bool stat_rx_ongoing = false; diff --git a/Framing.h b/Framing.h index 10b380c..80ec1cd 100644 --- a/Framing.h +++ b/Framing.h @@ -55,9 +55,6 @@ size_t frame_len; bool IN_FRAME = false; bool ESCAPE = false; - bool SERIAL_READING = false; uint8_t command = CMD_UNKNOWN; - uint32_t last_serial_read = 0; - uint32_t serial_read_timeout_ms = 60; #endif \ No newline at end of file diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index b961f11..4eeb49b 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -2,27 +2,49 @@ #include #include "Utilities.h" +FIFOBuffer serialFIFO; +uint8_t serialBuffer[CONFIG_UART_BUFFER_SIZE]; + +FIFOBuffer16 packet_starts; +size_t packet_starts_buf[CONFIG_QUEUE_MAX_LENGTH+1]; + +FIFOBuffer16 packet_lengths; +size_t packet_lengths_buf[CONFIG_QUEUE_MAX_LENGTH+1]; + +uint8_t packet_queue[CONFIG_QUEUE_SIZE]; + +volatile uint8_t queue_height = 0; +volatile size_t queued_bytes = 0; +volatile size_t queue_cursor = 0; +volatile size_t current_packet_start = 0; + void setup() { // Seed the PRNG randomSeed(analogRead(0)); // Initialise serial communication + memset(serialBuffer, 0, sizeof(serialBuffer)); + fifo_init(&serialFIFO, serialBuffer, sizeof(serialBuffer)); + Serial.begin(serial_baudrate); while (!Serial); + serial_timer_init(); + // Configure input and output pins pinMode(pin_led_rx, OUTPUT); pinMode(pin_led_tx, OUTPUT); // Initialise buffers memset(pbuf, 0, sizeof(pbuf)); - memset(sbuf, 0, sizeof(sbuf)); memset(cbuf, 0, sizeof(cbuf)); - #if QUEUE_SIZE > 0 - memset(qbuf, 0, sizeof(qbuf)); - memset(queued_lengths, 0, sizeof(queued_lengths)); - #endif + memset(packet_queue, 0, sizeof(packet_queue)); + memset(packet_starts_buf, 0, sizeof(packet_starts)); + memset(packet_lengths_buf, 0, sizeof(packet_lengths)); + + fifo16_init(&packet_starts, packet_starts_buf, sizeof(packet_starts_buf)); + fifo16_init(&packet_lengths, packet_lengths_buf, sizeof(packet_lengths_buf)); // Set chip select, reset and interrupt // pins for the LoRa module @@ -188,67 +210,38 @@ void receiveCallback(int packet_size) { } } - -bool outboundReady() { - #if QUEUE_SIZE > 0 - if (queue_head != queue_tail) { - return true; - } else { - return false; - } - #else - return outbound_ready; - #endif -} - bool queueFull() { - size_t new_queue_head = (queue_head+1)%QUEUE_BUF_SIZE; - if (new_queue_head == queue_tail) { - return true; - } else { - return false; - } + return (queue_height < CONFIG_QUEUE_MAX_LENGTH && queued_bytes < CONFIG_QUEUE_SIZE); } -void enqueuePacket(size_t length) { - size_t new_queue_head = (queue_head+1)%QUEUE_BUF_SIZE; - if (new_queue_head != queue_tail) { - queued_lengths[queue_head] = length; - size_t insert_addr = queue_head * MTU; - for (int i = 0; i < length; i++) { - qbuf[insert_addr+i] = sbuf[i]; +volatile bool queue_flushing = false; +void flushQueue(void) { + if (!queue_flushing) { + queue_flushing = true; + + size_t processed = 0; + for (size_t n = 0; n < queue_height; n++) { + size_t start = fifo16_pop_locked(&packet_starts); + size_t length = fifo16_pop_locked(&packet_lengths); + + if (length >= MIN_L) { + for (size_t i = 0; i < length; i++) { + size_t pos = (start+i)%CONFIG_QUEUE_SIZE; + tbuf[i] = packet_queue[pos]; + } + + transmit(length); + processed++; + } } - queue_head = new_queue_head; - if (!queueFull()) { - kiss_indicate_ready(); - } - } else { - kiss_indicate_error(ERROR_QUEUE_FULL); } + + queue_height = 0; + queued_bytes = 0; + queue_flushing = false; + kiss_indicate_ready(); } -#if QUEUE_SIZE > 0 -void processQueue() { - size_t fetch_address = queue_tail*MTU; - size_t fetch_length = queued_lengths[queue_tail]; - - for (int i = 0; i < fetch_length; i++) { - tbuf[i] = qbuf[fetch_address+i]; - qbuf[fetch_address+i] = 0x00; - } - - queued_lengths[queue_tail] = 0; - - queue_tail = ++queue_tail%QUEUE_BUF_SIZE; - - transmit(fetch_length); - - if (!queueFull()) { - kiss_indicate_ready(); - } -} -#endif - void transmit(size_t size) { if (radio_online) { if (!promisc) { @@ -264,11 +257,7 @@ void transmit(size_t size) { LoRa.write(header); written++; for (size_t i; i < size; i++) { - #if QUEUE_SIZE > 0 - LoRa.write(tbuf[i]); - #else - LoRa.write(sbuf[i]); - #endif + LoRa.write(tbuf[i]); written++; @@ -298,11 +287,7 @@ void transmit(size_t size) { LoRa.beginPacket(); for (size_t i; i < size; i++) { - #if QUEUE_SIZE > 0 - LoRa.write(tbuf[i]); - #else - LoRa.write(sbuf[i]); - #endif + LoRa.write(tbuf[i]); written++; } @@ -315,26 +300,35 @@ void transmit(size_t size) { kiss_indicate_error(ERROR_TXFAILED); led_indicate_error(5); } - - #if QUEUE_SIZE == 0 - if (FLOW_CONTROL_ENABLED) - kiss_indicate_ready(); - #endif } void serialCallback(uint8_t sbyte) { if (IN_FRAME && sbyte == FEND && command == CMD_DATA) { IN_FRAME = false; - if (QUEUE_SIZE == 0) { - if (outbound_ready) { - kiss_indicate_error(ERROR_QUEUE_FULL); - } else { - outbound_ready = true; - } - } else { - enqueuePacket(frame_len); + if (queue_height < CONFIG_QUEUE_MAX_LENGTH && queued_bytes < CONFIG_QUEUE_SIZE) { + size_t s = current_packet_start; + size_t e = queue_cursor-1; if (e == -1) e = CONFIG_QUEUE_SIZE-1; + size_t l; + + if (s != e) { + l = (s < e) ? e - s + 1 : CONFIG_QUEUE_SIZE - s + e + 1; + } else { + l = 1; + } + + if (l >= MIN_L) { + queue_height++; + + fifo16_push_locked(&packet_starts, s); + fifo16_push_locked(&packet_lengths, l); + + current_packet_start = queue_cursor; + } } + + if (!queueFull()) kiss_indicate_ready(); + } else if (sbyte == FEND) { IN_FRAME = true; command = CMD_UNKNOWN; @@ -352,7 +346,11 @@ void serialCallback(uint8_t sbyte) { if (sbyte == TFESC) sbyte = FESC; ESCAPE = false; } - sbuf[frame_len++] = sbyte; + if (queue_height < CONFIG_QUEUE_MAX_LENGTH && queued_bytes < CONFIG_QUEUE_SIZE) { + queued_bytes++; + packet_queue[queue_cursor++] = sbyte; + if (queue_cursor == CONFIG_QUEUE_SIZE) queue_cursor = 0; + } } } else if (command == CMD_FREQUENCY) { if (sbyte == FESC) { @@ -566,19 +564,20 @@ void validateStatus() { void loop() { if (radio_online) { checkModemStatus(); - if (outboundReady() && !SERIAL_READING) { + + if (queue_height > 0) { if (!dcd_waiting) updateModemStatus(); + if (!dcd && !dcd_led) { if (dcd_waiting) delay(lora_rx_turnaround_ms); + updateModemStatus(); + if (!dcd) { dcd_waiting = false; - #if QUEUE_SIZE > 0 - processQueue(); - #else - outbound_ready = false; - transmit(frame_len); - #endif + + flushQueue(); + } } else { dcd_waiting = true; @@ -594,14 +593,36 @@ void loop() { } } - if (Serial.available()) { - SERIAL_READING = true; - char sbyte = Serial.read(); + serial_poll(); +} + +void serial_poll() { + while (!fifo_isempty_locked(&serialFIFO)) { + char sbyte = fifo_pop_locked(&serialFIFO); serialCallback(sbyte); - last_serial_read = millis(); - } else { - if (SERIAL_READING && millis()-last_serial_read >= serial_read_timeout_ms) { - SERIAL_READING = false; + } +} + +void buffer_serial() { + while (Serial.available()) { + char c = Serial.read(); + if (!fifo_isfull_locked(&serialFIFO)) { + fifo_push_locked(&serialFIFO, c); } } } + +void serial_timer_init() { + TCCR3A = 0; + TCCR3B = _BV(CS10) | + _BV(WGM33)| + _BV(WGM32); + + ICR3 = 23704; // Approximation of 16Mhz / 675 + + TIMSK3 = _BV(ICIE3); +} + +ISR(TIMER3_CAPT_vect) { + buffer_serial(); +} \ No newline at end of file diff --git a/Utilities.h b/Utilities.h index 2753fad..9aae3f6 100644 --- a/Utilities.h +++ b/Utilities.h @@ -1,4 +1,6 @@ #include +#include +#include #include "LoRa.h" #include "ROM.h" #include "Config.h" @@ -468,3 +470,160 @@ void unlock_rom() { led_indicate_error(50); eeprom_erase(); } + +typedef struct FIFOBuffer +{ + unsigned char *begin; + unsigned char *end; + unsigned char * volatile head; + unsigned char * volatile tail; +} FIFOBuffer; + +inline bool fifo_isempty(const FIFOBuffer *f) { + return f->head == f->tail; +} + +inline bool fifo_isfull(const FIFOBuffer *f) { + return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1); +} + +inline void fifo_push(FIFOBuffer *f, unsigned char c) { + *(f->tail) = c; + + if (f->tail == f->end) { + f->tail = f->begin; + } else { + f->tail++; + } +} + +inline unsigned char fifo_pop(FIFOBuffer *f) { + if(f->head == f->end) { + f->head = f->begin; + return *(f->end); + } else { + return *(f->head++); + } +} + +inline void fifo_flush(FIFOBuffer *f) { + f->head = f->tail; +} + +static inline bool fifo_isempty_locked(const FIFOBuffer *f) { + bool result; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + result = fifo_isempty(f); + } + return result; +} + +static inline bool fifo_isfull_locked(const FIFOBuffer *f) { + bool result; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + result = fifo_isfull(f); + } + return result; +} + +static inline void fifo_push_locked(FIFOBuffer *f, unsigned char c) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + fifo_push(f, c); + } +} + +static inline unsigned char fifo_pop_locked(FIFOBuffer *f) { + unsigned char c; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + c = fifo_pop(f); + } + return c; +} + +inline void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size) { + f->head = f->tail = f->begin = buffer; + f->end = buffer + size -1; +} + +inline size_t fifo_len(FIFOBuffer *f) { + return f->end - f->begin; +} + +typedef struct FIFOBuffer16 +{ + size_t *begin; + size_t *end; + size_t * volatile head; + size_t * volatile tail; +} FIFOBuffer16; + +inline bool fifo16_isempty(const FIFOBuffer16 *f) { + return f->head == f->tail; +} + +inline bool fifo16_isfull(const FIFOBuffer16 *f) { + return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1); +} + +inline void fifo16_push(FIFOBuffer16 *f, size_t c) { + *(f->tail) = c; + + if (f->tail == f->end) { + f->tail = f->begin; + } else { + f->tail++; + } +} + +inline size_t fifo16_pop(FIFOBuffer16 *f) { + if(f->head == f->end) { + f->head = f->begin; + return *(f->end); + } else { + return *(f->head++); + } +} + +inline void fifo16_flush(FIFOBuffer16 *f) { + f->head = f->tail; +} + +static inline bool fifo16_isempty_locked(const FIFOBuffer16 *f) { + bool result; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + result = fifo16_isempty(f); + } + return result; +} + +static inline bool fifo16_isfull_locked(const FIFOBuffer16 *f) { + bool result; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + result = fifo16_isfull(f); + } + return result; +} + +static inline void fifo16_push_locked(FIFOBuffer16 *f, size_t c) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + fifo16_push(f, c); + } +} + +static inline size_t fifo16_pop_locked(FIFOBuffer16 *f) { + size_t c; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + c = fifo16_pop(f); + } + return c; +} + +inline void fifo16_init(FIFOBuffer16 *f, size_t *buffer, size_t size) { + f->head = f->tail = f->begin = buffer; + f->end = buffer + (size/sizeof(size_t)) - 2; +} + +inline size_t fifo16_len(FIFOBuffer16 *f) { + return ((f->end - f->begin))/sizeof(size_t); +} +