Files
ZephCore/zephcore/src/StaticPoolPacketManager.cpp
T
liquidraver a7d073900e core: restore upstream shape for the shared mesh core
- Mesh, Dispatcher, Packet, packet pool and the core headers rebuilt from
  Arduino MeshCore's text; ZephCore changes re-applied, each fenced
  `// ZEPHCORE:` (diff vs upstream: 4540 -> 1147 lines)
- upstream header layout; MainBoard gains handleCommand/loop and the other
  upstream members; RNG::nextInt back in Utils.cpp
- packet logging moved to the roles' log hooks (helpers/PacketLog.h)
- zero-hop direct ACKs deduplicated and length-checked as upstream
- RadioIncludes.h -> src/, LoRaConfig.h -> helpers/
- .editorconfig: shared files keep upstream formatting

Verified: 10 role builds, per-function disassembly review, bench DM/ACK
regression (T1000-E, Wio L1, XIAO S3 on 1.17.4) incl. via live repeater.
2026-09-23 13:39:48 +02:00

192 lines
5.8 KiB
C++

#include <mesh/StaticPoolPacketManager.h>
#include <string.h>
// ZEPHCORE: log module for the pool's warnings.
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(zephcore_pktpool, CONFIG_ZEPHCORE_LORA_LOG_LEVEL);
// ZEPHCORE: static storage — no heap in the packet path. Upstream sizes the pool
// at runtime (new[]); here pool and queues are compile-time and file-local.
#define POOL_SIZE 32
#define QUEUE_SIZE 32
namespace {
struct PacketQueue {
mesh::Packet* _table[QUEUE_SIZE];
uint8_t _pri_table[QUEUE_SIZE];
uint32_t _schedule_table[QUEUE_SIZE];
int _num;
PacketQueue() : _num(0) {
memset(_table, 0, sizeof(_table));
}
int count() const { return _num; }
mesh::Packet* itemAt(int i) const {
if (i < 0 || i >= _num) return NULL;
return _table[i];
}
int 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* 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
return removeByIdx(best_idx);
}
mesh::Packet* removeByIdx(int i) {
if (i < 0 || 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 add(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for) {
if (_num == QUEUE_SIZE) {
return false;
}
_table[_num] = packet;
_pri_table[_num] = priority;
_schedule_table[_num] = scheduled_for;
_num++;
return true;
}
// ZEPHCORE: eviction and schedule access (reactive backoff, re-queue priority).
int findLowestPriority() const { // least important entry, -1 when empty
if (_num == 0) return -1;
uint8_t worst = 0;
int idx = 0;
for (int j = 0; j < _num; j++) {
if (_pri_table[j] >= worst) {
worst = _pri_table[j];
idx = j;
}
}
return idx;
}
uint32_t scheduleAt(int i) const { return (i < _num) ? _schedule_table[i] : 0; }
uint8_t peekPriority(uint32_t now) const { // what get(now) would return; 0xFF if none due
uint8_t best = 0xFF;
for (int j = 0; j < _num; j++) {
if ((int32_t)(_schedule_table[j] - now) > 0) continue;
if (_pri_table[j] < best) best = _pri_table[j];
}
return best;
}
bool reschedule(int i, uint32_t new_scheduled_for) {
if (i >= _num) return false;
_schedule_table[i] = new_scheduled_for;
return true;
}
};
mesh::Packet packet_pool[POOL_SIZE];
PacketQueue unused, send_queue;
bool initialized = false;
// load up our unusued Packet pool (on first use: no static-init ordering hazard)
void init_pool() {
if (initialized) return;
initialized = true;
for (int i = 0; i < POOL_SIZE; i++) {
unused.add(&packet_pool[i], 0, 0);
}
}
} // namespace
mesh::Packet* StaticPoolPacketManager::allocNew() {
init_pool(); // ZEPHCORE
return unused.removeByIdx(0); // just get first one (returns NULL if empty)
}
void StaticPoolPacketManager::free(mesh::Packet* packet) {
if (packet == NULL) return;
if (!unused.add(packet, 0, 0)) {
LOG_WRN("free: unused queue full, possible double-free"); // ZEPHCORE: WRN, not debug-only
}
}
void StaticPoolPacketManager::queueOutbound(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for) {
if (packet == NULL) return;
if (send_queue.add(packet, priority, scheduled_for)) return;
// ZEPHCORE: queue full — evict the least important entry if the new packet is
// more important (lower number); otherwise drop the new one (as upstream).
int worst = send_queue.findLowestPriority();
if (worst >= 0 && send_queue._pri_table[worst] > priority) {
uint8_t evicted_pri = send_queue._pri_table[worst];
mesh::Packet* evicted = send_queue.removeByIdx(worst);
LOG_WRN("queueOutbound: FULL — evicted type=%d pri=%d for type=%d pri=%d",
evicted->getPayloadType(), evicted_pri, packet->getPayloadType(), priority);
free(evicted);
send_queue.add(packet, priority, scheduled_for);
} else {
LOG_WRN("queueOutbound: FULL (%d entries) — dropping type=%d pri=%d",
send_queue.count(), packet->getPayloadType(), priority);
free(packet);
}
}
mesh::Packet* StaticPoolPacketManager::getNextOutbound(uint32_t now) {
return send_queue.get(now);
}
int StaticPoolPacketManager::getOutboundCount(uint32_t now) const {
return send_queue.countBefore(now);
}
int StaticPoolPacketManager::getOutboundTotal() const {
return send_queue.count();
}
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);
}
// ZEPHCORE: schedule access instead of the inbound queue.
uint32_t StaticPoolPacketManager::getOutboundSchedule(int i) const {
return send_queue.scheduleAt(i);
}
bool StaticPoolPacketManager::rescheduleOutbound(int i, uint32_t new_scheduled_for) {
return send_queue.reschedule(i, new_scheduled_for);
}
uint8_t StaticPoolPacketManager::peekNextOutboundPriority(uint32_t now) const {
return send_queue.peekPriority(now);
}