fix: keep a repeater frame until the radio queue takes it

The frame was popped before queueTx(), so whenever the radio queue was busy
it was lost.  Peek it instead, only remove it once it is queued (or TX is
suspended), and don't try while the queue has no room.  The repeater buffer
moves to TxBuffer.h/.cpp so it can be unit tested.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-12 18:31:39 +02:00
parent e1c76bc2af
commit 7e9687c023
6 changed files with 227 additions and 80 deletions

55
src/TxBuffer.cpp Normal file
View file

@ -0,0 +1,55 @@
#include "TxBuffer.h"
int8_t somfy_tx_queue_t::oldest() const {
// The newest index is at position 0 so the oldest is the last one in use.
for(int8_t i = MAX_TX_BUFFER - 1; i >= 0; i--) {
if(this->index[i] < MAX_TX_BUFFER) return i;
}
return -1;
}
bool somfy_tx_queue_t::peek(somfy_tx_t *tx) const {
const int8_t i = this->oldest();
if(i < 0) return false;
memcpy(tx, &this->items[this->index[i]], sizeof(somfy_tx_t));
return true;
}
bool somfy_tx_queue_t::pop(somfy_tx_t *tx) {
const int8_t i = this->oldest();
if(i < 0) return false;
uint8_t ndx = this->index[i];
memcpy(tx, &this->items[ndx], sizeof(somfy_tx_t));
this->items[ndx].clear();
if(this->length > 0) this->length--;
this->index[i] = 255;
return true;
}
void somfy_tx_queue_t::push(uint8_t hwsync, uint8_t *payload, uint8_t bit_length) {
if(this->length >= MAX_TX_BUFFER) {
// We have overflowed the buffer simply empty the last item
// in this instance we will simply throw it away.
uint8_t ndx = this->index[MAX_TX_BUFFER - 1];
if(ndx < MAX_TX_BUFFER) this->items[ndx].clear();
this->index[MAX_TX_BUFFER - 1] = 255;
this->length--;
}
uint8_t first = 0;
// Place this record in the first empty slot. There will
// be one since we cleared a space above should there
// be an overflow.
for(uint8_t i = 0; i < MAX_TX_BUFFER; i++) {
if(this->items[i].bit_length == 0) {
first = i;
this->items[i].bit_length = bit_length;
this->items[i].hwsync = hwsync;
memcpy(&this->items[i].payload, payload, sizeof(this->items[i].payload));
break;
}
}
// Move the index so that it is the at position 0. The oldest item will fall off.
for(uint8_t i = MAX_TX_BUFFER - 1; i > 0; i--) {
this->index[i] = this->index[i - 1];
}
this->length++;
// When popping from the queue we always pull from the end
this->index[0] = first;
}