scrub APC and bump to 1.16.6

This commit is contained in:
liquidraver
2026-07-20 09:55:32 +02:00
parent b58994661b
commit 13b5e2fcf3
38 changed files with 277 additions and 1351 deletions
-8
View File
@@ -7,9 +7,6 @@
#include <mesh/Dispatcher.h>
#include <mesh/ContentionTracker.h>
#ifdef CONFIG_ZEPHCORE_APC
#include <mesh/PowerController.h>
#endif
#include <mesh/RTC.h>
namespace mesh {
@@ -43,11 +40,6 @@ public:
ContentionTracker& getContentionTracker() { return _contention; }
const ContentionTracker& getContentionTracker() const { return _contention; }
protected:
#ifdef CONFIG_ZEPHCORE_APC
PowerController _power_ctrl;
PowerController& getPowerController() { return _power_ctrl; }
const PowerController& getPowerController() const { return _power_ctrl; }
#endif
void extendPendingRetransmit(uint32_t hash32);
DispatcherAction onRecvPacket(Packet *pkt) override;
-135
View File
@@ -1,135 +0,0 @@
/*
* SPDX-License-Identifier: MIT
* Adaptive Power Control (APC) — echo-based TX power reduction
*
* Measures the full-power link budget to downstream neighbors by
* tracking true echoes: flood dupes that provably routed through
* this node (our path hash at the position we appended it). Echo
* SNR is measured from the NEIGHBOR's fixed-power TX, so it does
* not respond to our own reduction — the control law subtracts the
* current reduction itself (path reciprocity) and regulates the
* neighbor's predicted margin to the target.
*
* Rogue filtering: when 2+ distinct neighbors echo the same packet,
* clusters their SNRs within 6 dB of the best. An isolated high
* outlier (rogue, badly placed neighbor) is dropped.
*/
#pragma once
#include <stdint.h>
namespace mesh {
class PowerController {
public:
/* path_pos sentinel for packets we originated: nobody else had the
* content before our TX, so every dupe is a true echo. */
static constexpr uint8_t PATH_POS_ORIGINATED = 0xFF;
PowerController();
/* Enable/disable APC. When disabled, APC tracking/math is bypassed. */
void setEnabled(bool en);
bool isEnabled() const { return _enabled; }
/* Set current spreading factor (needed for margin calculation). */
void setSF(uint8_t sf) { _sf = sf; }
/* Set target link margin in dB. Higher = more conservative
* (better for networks with poor-RX hardware). Default 16 dB. */
void setTargetMargin(uint8_t margin_db) { _target_margin_x4 = (int)margin_db * 4; }
uint8_t getTargetMargin() const { return (uint8_t)(_target_margin_x4 / 4); }
/* Called when we queue a flood packet for TX. path_pos = path index
* at which we appended our own hash (forwarded floods), or
* PATH_POS_ORIGINATED for packets we originated. */
void trackTransmit(uint32_t hash32, uint32_t now_ms, uint8_t path_pos);
/* Called for every received flood dupe. Verifies the dupe actually
* routed through us (true echo), attributes it to the transmitting
* neighbor (last path entry) and updates that source's best SNR.
* Returns true if the dupe matched a tracked transmit and passed
* the true-echo gate. */
bool recordEcho(uint32_t hash32, int8_t snr_x4, uint32_t now_ms,
const uint8_t *path, uint8_t path_count,
uint8_t hash_size, const uint8_t *self_hash);
/* Finalize expired entries, update EMA, adjust power, handle
* staleness. Call from maintenanceLoop (~5 s). */
void tick(uint32_t now_ms);
/* Current TX power reduction in dBm (0 to MAX_REDUCTION_DB).
* Returns 0 when disabled. */
int8_t getPowerReduction() const { return _enabled ? _power_reduction_db : 0; }
/* Current margin estimate in dB (for diagnostics). */
float getMarginEstimate() const;
/* Source count from most recently finalized entry (diagnostics). */
uint8_t getLastSourceCount() const { return _last_source_count; }
/* Finalized-entry counters (diagnostics): entries with at least one
* true echo vs entries that expired unechoed. */
uint32_t getEchoCount() const { return _echo_count; }
uint32_t getNoEchoCount() const { return _noecho_count; }
bool isWarmedUp() const { return _finalized_count >= WARMUP_COUNT; }
bool isStale(uint32_t now_ms) const;
private:
static constexpr int RING_SIZE = 16;
static constexpr uint32_t ECHO_WINDOW_MS = 10000; /* 10s: covers SF12 2-hop echo */
static constexpr uint32_t STALE_MS = 120000; /* 2 min */
static constexpr int EMA_SHIFT = 2; /* alpha = 1/4 */
static constexpr int WARMUP_COUNT = 3;
static constexpr int MAX_SOURCES = 3;
static constexpr int8_t STEP_DOWN_DB = 3; /* max reduction increase per tick */
static constexpr int8_t STEP_UP_DB = 6; /* max reduction decrease per tick */
static constexpr int8_t MAX_REDUCTION_DB = 12;
static constexpr int CLUSTER_WIDTH_X4 = 24; /* 6 dB in x4 */
static constexpr int DEFAULT_TARGET_MARGIN_X4 = 64; /* 16 dB * 4 */
static constexpr int HYSTERESIS_X4 = 4; /* 1 dB * 4 deadband */
/* Consecutive unechoed transmissions (while reduced) that trip an
* immediate return to full power + margin re-warmup. */
static constexpr int NOECHO_TRIP_COUNT = 2;
struct Source {
uint8_t hash;
int8_t snr_x4;
};
struct EchoEntry {
uint32_t hash32;
uint32_t timestamp_ms;
uint8_t source_count;
uint8_t sf_at_track; /* SF when packet was transmitted */
uint8_t path_pos; /* our path index, or PATH_POS_ORIGINATED */
int8_t reduction_at_track; /* power reduction in effect at track time */
Source sources[MAX_SOURCES];
bool active;
};
EchoEntry _ring[RING_SIZE];
int _next_idx;
int32_t _margin_ema_x256; /* fixed-point EMA (x4 * 64) */
int _finalized_count;
uint32_t _last_echo_ms;
uint32_t _echo_count;
uint32_t _noecho_count;
uint8_t _noecho_streak;
int8_t _power_reduction_db;
bool _enabled;
uint8_t _sf;
uint8_t _last_source_count;
int _target_margin_x4;
void finalizeEntry(int idx);
int findEntry(uint32_t hash32) const;
int8_t computeRobustSNR(const EchoEntry &entry) const;
/* SNR threshold for a given SF (x4 fixed point). */
static int8_t sfThresholdX4(uint8_t sf);
};
} /* namespace mesh */
-2
View File
@@ -38,8 +38,6 @@ public:
virtual float getLastSNR() const { return 0; }
/* Adaptive Power Control */
virtual void setTxPowerReduction(int8_t reduction_db) { (void)reduction_db; }
virtual int8_t getTxPowerReduction() const { return 0; }
/* Adaptive CAD (LBT detPeak calibration). Default no-ops for radios
* without hardware CAD (SX127x). */