comment overhaul

This commit is contained in:
liquidraver committed 2026-03-28 20:53:59 +01:00
1 parent 64c19b7eaa
commit 33fa19a7f5
52 files changed
+636 -2854

No files matched your search

+7 -11
View File
@@ -17,11 +17,10 @@ ContentionTracker::ContentionTracker()
memset(_ring, 0, sizeof(_ring));
}
/* FNV-1a hash of payload_type + first 8 bytes of payload.
* Cheap and sufficient for 16-entry correlation. */
/* FNV-1a over payload_type + first 8 payload bytes */
uint32_t ContentionTracker::computePacketHash32(const Packet *pkt)
{
uint32_t h = 0x811c9dc5u; /* FNV offset basis */
uint32_t h = 0x811c9dc5u; /* FNV-1a offset basis */
uint8_t t = pkt->getPayloadType();
h = (h ^ t) * 0x01000193u;
int n = pkt->payload_len < 8 ? pkt->payload_len : 8;
@@ -50,14 +49,13 @@ void ContentionTracker::finalizeEntry(int idx)
int32_t diff = (int32_t)sample_x256 - (int32_t)_ema_x256;
if (_finalized_count < WARMUP_PACKETS) {
/* During warmup, seed the EMA directly */
/* Warmup: seed EMA with fast convergence */
if (_finalized_count == 0) {
_ema_x256 = sample_x256;
} else {
_ema_x256 = (uint32_t)((int32_t)_ema_x256 + (diff >> 1));
}
} else {
/* Normal EMA update: ema += (sample - ema) >> shift */
_ema_x256 = (uint32_t)((int32_t)_ema_x256 + (diff >> EMA_SHIFT));
}
@@ -69,7 +67,7 @@ void ContentionTracker::trackRetransmit(uint32_t hash32, uint32_t now_ms)
{
_last_retransmit_ms = now_ms;
/* If ring is full, finalize the oldest active entry */
/* Evict oldest if ring slot occupied */
if (_ring[_next_idx].active) {
finalizeEntry(_next_idx);
}
@@ -91,7 +89,6 @@ bool ContentionTracker::recordDupeIfTracked(uint32_t hash32, uint32_t now_ms)
Entry &e = _ring[idx];
/* Check if entry has expired */
if (now_ms - e.first_seen_ms > WINDOW_MS) {
finalizeEntry(idx);
return false;
@@ -111,7 +108,7 @@ uint16_t ContentionTracker::getReactiveHeadroom(uint32_t hash32, uint32_t airtim
uint32_t per_dupe = (uint32_t)(_backoff_multiplier * (float)airtime_ms);
if (per_dupe == 0) return 0;
/* Hard cap on total reactive extension per packet */
/* Hard cap: REACTIVE_HARD_CAP_MS total extension per packet */
if (_ring[idx].reactive_added_ms >= REACTIVE_HARD_CAP_MS) return 0;
uint32_t remaining = REACTIVE_HARD_CAP_MS - _ring[idx].reactive_added_ms;
@@ -130,14 +127,13 @@ void ContentionTracker::addReactiveExtension(uint32_t hash32, uint16_t added_ms)
void ContentionTracker::tick(uint32_t now_ms)
{
/* Finalize expired entries */
for (int i = 0; i < RING_SIZE; i++) {
if (_ring[i].active && now_ms - _ring[i].first_seen_ms > WINDOW_MS) {
finalizeEntry(i);
}
}
/* Staleness decay: if no retransmit in 5 minutes, decay toward 0 */
/* Decay EMA toward 0 if no retransmit in STALE_MS */
if (_last_retransmit_ms != 0 && now_ms - _last_retransmit_ms > STALE_MS) {
if (_ema_x256 > 0) {
_ema_x256 -= _ema_x256 >> EMA_SHIFT;
@@ -152,7 +148,7 @@ float ContentionTracker::getContentionEstimate() const
float ContentionTracker::getFloodDelayFactor() const
{
if (!isWarmedUp()) return 0.5f;
if (!isWarmedUp()) return 0.5f; /* conservative default before warmup */
float est = getContentionEstimate();
if (est <= 0.0f) return MIN_FLOOD_FACTOR;
+14 -21
View File
@@ -12,7 +12,6 @@
LOG_MODULE_REGISTER(zephcore_dispatcher, CONFIG_ZEPHCORE_LORA_LOG_LEVEL);
#if IS_ENABLED(CONFIG_ZEPHCORE_PACKET_LOGGING)
/* Payload types for [src -> dest] logging */
#define PAYLOAD_TYPE_REQ 0x00
#define PAYLOAD_TYPE_RESPONSE 0x01
#define PAYLOAD_TYPE_TXT_MSG 0x02
@@ -21,7 +20,7 @@ LOG_MODULE_REGISTER(zephcore_dispatcher, CONFIG_ZEPHCORE_LORA_LOG_LEVEL);
namespace mesh {
#define MAX_RX_DELAY_MILLIS 32000
#define MAX_RX_DELAY_MILLIS 32000 /* upper bound for score-based RX delay */
Dispatcher::Dispatcher(Radio &radio, MillisecondClock &ms, PacketManager &mgr)
: _radio(&radio), _ms(&ms), _mgr(&mgr)
@@ -54,7 +53,7 @@ void Dispatcher::begin()
uint8_t Dispatcher::getDutyCyclePercent() const
{
return 10;
return 10; /* EU 868 default: 10% duty cycle */
}
bool Dispatcher::isAdminPacket(const Packet *pkt)
@@ -66,8 +65,7 @@ bool Dispatcher::isAdminPacket(const Packet *pkt)
int Dispatcher::calcRxDelay(float score, uint32_t air_time) const
{
/* Lookup table: (10^(0.85 - i*0.1) - 1) for i=0..10 (score 0.0 to 1.0)
* Replaces powf() to save ~1.9KB flash. Linear interpolation between entries. */
/* LUT: 10^(0.85 - i*0.1) - 1, i=0..10; replaces powf() (~1.9KB saved) */
static const float lut[11] = {
6.0793f, 4.6236f, 3.4674f, 2.5489f, 1.8184f, 1.2389f,
0.7783f, 0.4125f, 0.1220f, -0.1089f, -0.2921f
@@ -83,12 +81,12 @@ int Dispatcher::calcRxDelay(float score, uint32_t air_time) const
uint32_t Dispatcher::getCADFailRetryDelay() const
{
return 200;
return 200; /* ms between CAD retries; ~2 LoRa symbol periods at SF8/62.5k */
}
uint32_t Dispatcher::getCADFailMaxDuration() const
{
return 4000;
return 4000; /* ms; ~20 retry attempts before giving up */
}
void Dispatcher::loop()
@@ -130,14 +128,10 @@ void Dispatcher::loop()
void Dispatcher::maintenanceLoop()
{
/* Noise floor calibration — one EMA tick per housekeeping cycle */
_radio->triggerNoiseFloorCalibrate(getInterferenceThreshold());
/* RX mode watchdog — detect if radio is stuck in neither RX nor TX.
* Count TX time as "active" so rapid consecutive relays on a busy
* repeater don't falsely trigger the flag: the housekeeping timer
* (5 s) can miss brief RX windows between TXes, leaving
* radio_nonrx_start stale and firing the watchdog spuriously. */
/* RX mode watchdog: TX counts as "active" to avoid false triggers
* when the 5s housekeeping timer misses brief RX windows. */
bool is_active = _radio->isInRecvMode() || !_radio->isSendComplete();
if (is_active != prev_isrecv_mode) {
prev_isrecv_mode = is_active;
@@ -145,11 +139,11 @@ void Dispatcher::maintenanceLoop()
radio_nonrx_start = (uint32_t)_ms->getMillis();
}
}
if (!is_active && (uint32_t)_ms->getMillis() - radio_nonrx_start > 8000) {
if (!is_active && (uint32_t)_ms->getMillis() - radio_nonrx_start > 8000) { /* 8s stall threshold */
_err_flags |= ERR_EVENT_STARTRX_TIMEOUT;
}
/* AGC reset — periodic warm sleep + recalibration */
/* Periodic AGC recalibration */
if (getAGCResetInterval() > 0 && millisHasNowPassed(next_agc_reset_time)) {
_radio->resetAGC();
next_agc_reset_time = futureMillis(getAGCResetInterval());
@@ -175,7 +169,7 @@ bool Dispatcher::tryParsePacket(Packet *pkt, const uint8_t *raw, int len)
pkt->path_len = raw[i++];
uint8_t path_mode = pkt->path_len >> 6;
if (path_mode == 3) { // Reserved for future
if (path_mode == 3) { /* reserved path mode */
LOG_WRN("tryParsePacket: unsupported path mode: 3");
return false;
}
@@ -200,14 +194,13 @@ bool Dispatcher::tryParsePacket(Packet *pkt, const uint8_t *raw, int len)
void Dispatcher::checkRecv()
{
/* Drain ALL queued LoRa packets per wake.
* k_event is a bitfield (not a counter), so multiple ISR arrivals
* may only produce one wake. We must empty the ring each time. */
/* k_event is a bitfield — multiple ISR arrivals coalesce into one
* wake, so drain the entire ring each time. */
for (;;) {
uint8_t raw[MAX_TRANS_UNIT + 1];
int len = _radio->recvRaw(raw, MAX_TRANS_UNIT);
if (len <= 0) {
break; /* ring empty — done */
break;
}
logRxRaw(_radio->getLastSNR(), _radio->getLastRSSI(), raw, len);
@@ -222,7 +215,7 @@ void Dispatcher::checkRecv()
uint32_t air_time = 0;
if (tryParsePacket(pkt, raw, len)) {
pkt->_snr = (int8_t)(_radio->getLastSNR() * 4.0f);
pkt->_snr = (int8_t)(_radio->getLastSNR() * 4.0f); /* x4 fixed-point SNR */
score = _radio->packetScore(_radio->getLastSNR(), len);
air_time = _radio->getEstAirtimeFor(len);
rx_air_time += air_time;