mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-07-30 08:09:20 +00:00
PR #1795 changed PacketQueue::countBefore() to use signed 2's complement arithmetic for millis wraparound safety. However, this broke the 0xFFFFFFFF sentinel pattern used by callers to mean "count all packets regardless of schedule". With the signed comparison, countBefore(0xFFFFFFFF) always returns 0, causing hasPendingWork() to report false and repeaters to sleep with packets still queued. Stats reporting also shows queue_len as 0. Add an early-return for the sentinel value before the loop, and document the sentinel convention on the virtual interface and implementation.
121 lines
3.4 KiB
C++
121 lines
3.4 KiB
C++
#include "StaticPoolPacketManager.h"
|
|
|
|
PacketQueue::PacketQueue(int max_entries) {
|
|
_table = new mesh::Packet*[max_entries];
|
|
_pri_table = new uint8_t[max_entries];
|
|
_schedule_table = new uint32_t[max_entries];
|
|
_size = max_entries;
|
|
_num = 0;
|
|
}
|
|
|
|
int PacketQueue::countBefore(uint32_t now) const {
|
|
if (now == 0xFFFFFFFF) return _num; // sentinel: count all entries regardless of schedule
|
|
int n = 0;
|
|
for (int j = 0; j < _num; j++) {
|
|
if ((int32_t)(_schedule_table[j] - now) > 0) continue; // scheduled for future... ignore for now
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
mesh::Packet* PacketQueue::get(uint32_t now) {
|
|
uint8_t min_pri = 0xFF;
|
|
int best_idx = -1;
|
|
for (int j = 0; j < _num; j++) {
|
|
if ((int32_t)(_schedule_table[j] - now) > 0) continue; // scheduled for future... ignore for now
|
|
if (_pri_table[j] < min_pri) { // select most important priority amongst non-future entries
|
|
min_pri = _pri_table[j];
|
|
best_idx = j;
|
|
}
|
|
}
|
|
if (best_idx < 0) return NULL; // empty, or all items are still in the future
|
|
|
|
mesh::Packet* top = _table[best_idx];
|
|
int i = best_idx;
|
|
_num--;
|
|
while (i < _num) {
|
|
_table[i] = _table[i+1];
|
|
_pri_table[i] = _pri_table[i+1];
|
|
_schedule_table[i] = _schedule_table[i+1];
|
|
i++;
|
|
}
|
|
return top;
|
|
}
|
|
|
|
mesh::Packet* PacketQueue::removeByIdx(int i) {
|
|
if (i >= _num) return NULL; // invalid index
|
|
|
|
mesh::Packet* item = _table[i];
|
|
_num--;
|
|
while (i < _num) {
|
|
_table[i] = _table[i+1];
|
|
_pri_table[i] = _pri_table[i+1];
|
|
_schedule_table[i] = _schedule_table[i+1];
|
|
i++;
|
|
}
|
|
return item;
|
|
}
|
|
|
|
bool PacketQueue::add(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for) {
|
|
if (_num == _size) {
|
|
return false;
|
|
}
|
|
_table[_num] = packet;
|
|
_pri_table[_num] = priority;
|
|
_schedule_table[_num] = scheduled_for;
|
|
_num++;
|
|
return true;
|
|
}
|
|
|
|
StaticPoolPacketManager::StaticPoolPacketManager(int pool_size): unused(pool_size), send_queue(pool_size), rx_queue(pool_size) {
|
|
// load up our unusued Packet pool
|
|
for (int i = 0; i < pool_size; i++) {
|
|
unused.add(new mesh::Packet(), 0, 0);
|
|
}
|
|
}
|
|
|
|
mesh::Packet* StaticPoolPacketManager::allocNew() {
|
|
return unused.removeByIdx(0); // just get first one (returns NULL if empty)
|
|
}
|
|
|
|
void StaticPoolPacketManager::free(mesh::Packet* packet) {
|
|
unused.add(packet, 0, 0);
|
|
}
|
|
|
|
void StaticPoolPacketManager::queueOutbound(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for) {
|
|
if (!send_queue.add(packet, priority, scheduled_for)) {
|
|
MESH_DEBUG_PRINTLN("queueOutbound: send queue full, dropping packet");
|
|
free(packet);
|
|
}
|
|
}
|
|
|
|
mesh::Packet* StaticPoolPacketManager::getNextOutbound(uint32_t now) {
|
|
//send_queue.sort(); // sort by scheduled_for/priority first
|
|
return send_queue.get(now);
|
|
}
|
|
|
|
int StaticPoolPacketManager::getOutboundCount(uint32_t now) const {
|
|
return send_queue.countBefore(now);
|
|
}
|
|
|
|
int StaticPoolPacketManager::getFreeCount() const {
|
|
return unused.count();
|
|
}
|
|
|
|
mesh::Packet* StaticPoolPacketManager::getOutboundByIdx(int i) {
|
|
return send_queue.itemAt(i);
|
|
}
|
|
mesh::Packet* StaticPoolPacketManager::removeOutboundByIdx(int i) {
|
|
return send_queue.removeByIdx(i);
|
|
}
|
|
|
|
void StaticPoolPacketManager::queueInbound(mesh::Packet* packet, uint32_t scheduled_for) {
|
|
if (!rx_queue.add(packet, 0, scheduled_for)) {
|
|
MESH_DEBUG_PRINTLN("queueInbound: rx queue full, dropping packet");
|
|
free(packet);
|
|
}
|
|
}
|
|
mesh::Packet* StaticPoolPacketManager::getNextInbound(uint32_t now) {
|
|
return rx_queue.get(now);
|
|
}
|