@@ -282,54 +282,6 @@ bool MyMesh::clientProtectionAllowsSuppress(const mesh::Packet* pkt, uint32_t no
282282 return false ; // Tier B
283283}
284284
285- // --- Payload-class suppression policy (noise-aware) -----------------------------
286- // A repeater's retransmit ADDS airtime. On a congested/noisy channel every extra TX
287- // worsens the collision problem, so "stay silent rather than repeat" applies to the
288- // payload classes whose loss is cheap/self-healing. The class decides whether a
289- // redundant rebroadcast may be cancelled on a busy channel:
290- // 0 = NEVER (payload-critical): REQ, RESPONSE, TXT_MSG, ACK, MULTIPART -- always
291- // re-forward (subject to the normal dedup/coverage logic); noise never vetoes.
292- // 1 = CONFIDENCE-ONLY (best-effort but not disposable): TRACE, CONTROL, GRP_TXT,
293- // GRP_DATA, PATH, ANON_REQ -- suppressible on a quiet channel, forwarded on a
294- // noisy one. TRACE/CONTROL live here (NOT in tier 2): they are measurement and
295- // discovery plumbing -- TRACE feeds the coverage graph this suppressor relies
296- // on, CONTROL drives neighbour discovery -- so dropping them on a noisy channel
297- // would starve that data and risk a self-reinforcing collapse of the reach graph.
298- // 2 = CHEAP (self-healing): ADVERT (periodic re-send) -- suppressible even on a noisy
299- // channel (silence > repeat); adverts are rate-limited and re-sent periodically.
300- uint8_t MyMesh::floodSuppressTier (const mesh::Packet* pkt) const {
301- switch (pkt->getPayloadType ()) {
302- case PAYLOAD_TYPE_ADVERT :
303- return 2 ; // cheap: self-healing (periodic re-send) -- suppressible even when noisy
304- case PAYLOAD_TYPE_TRACE :
305- case PAYLOAD_TYPE_CONTROL :
306- case PAYLOAD_TYPE_GRP_TXT :
307- case PAYLOAD_TYPE_GRP_DATA :
308- case PAYLOAD_TYPE_PATH :
309- case PAYLOAD_TYPE_ANON_REQ :
310- return 1 ; // confidence-only: suppressible only on a quiet channel (forwarded when noisy)
311- default :
312- return 0 ; // never: REQ/RESPONSE/TXT_MSG/ACK/MULTIPART/RAW_CUSTOM
313- }
314- }
315-
316- // Channel-state gate for suppression. On a busy/noisy channel an extra TX amplifies the
317- // collision problem, so when the channel IS noisy we suppress only the cheap (self-healing)
318- // class (silence > repeat) and keep the confidence-only classes forwarding. "Noisy" is relative:
319- // the measured floor is at least `margin` dB above THIS SITE's slowly-tracked quiet baseline
320- // (see updateAdaptiveFloodParams), so no expert absolute-dBm value is needed. Margin is AUTO
321- // (firmware default) unless an explicit CLI override is set. Until the baseline is learned
322- // (first cycle, ~60s) we assume noisy -- the safe direction (keep confidence classes forwarding).
323- bool MyMesh::noiseGateAllowsSuppress (const mesh::Packet* pkt) const {
324- uint8_t tier = floodSuppressTier (pkt);
325- if (tier == 0 ) return false ; // payload-critical: never suppress
326- int8_t margin = (_prefs.flood_suppress_noise_margin == FLOOD_SUPPRESS_NOISE_MARGIN_AUTO )
327- ? FLOOD_SUPPRESS_NOISE_MARGIN_DEFAULT : _prefs.flood_suppress_noise_margin ;
328- bool noisy = (_fs_floor_baseline <= -999 ) ||
329- ((int )_radio->getNoiseFloor () >= _fs_floor_baseline + (int )margin);
330- return noisy ? (tier == 2 ) : true ; // noisy: only cheap; quiet: tier 1 or 2
331- }
332-
333285// --- Active TRACE coverage measurement ----------------------------------------
334286// Send one round-trip coverage TRACE: visit-list [a, b, self] with 2-byte hashes.
335287// It walks self->a->b->self; the SNR measured at b of a's forward (path_snrs[1])
@@ -956,17 +908,6 @@ int8_t MyMesh::effectiveFloodSuppressSnrLo() const {
956908// loop(); sets _fs_adaptive_active. Under #if MAX_NEIGHBOURS (else adaptive stays inactive and
957909// effectiveFloodSuppressC falls back to FLOOD_SUPPRESS_FALLBACK_C).
958910void MyMesh::updateAdaptiveFloodParams () {
959- // --- Noise-floor baseline (relative noise gate) ---
960- // getNoiseFloor() is the median-estimated ambient (RadioLibWrappers). We track its quiet
961- // minimum as THIS SITE's baseline: fast follow downward (got quieter), slow 1/16 approach
962- // upward (a persistent rise -- e.g. a new interferer -- slowly becomes the new baseline, so the
963- // gate eventually re-opens; mirrors the median estimator's bounded hold-release). "noisy" is
964- // then floor >= baseline + margin -- deployment-independent, no expert absolute-dBm. Runs every
965- // cycle (60s) when flood suppression is on, independent of MAX_NEIGHBOURS.
966- int cur_floor = _radio->getNoiseFloor ();
967- if (_fs_floor_baseline <= -999 ) _fs_floor_baseline = cur_floor; // first sample
968- else if (cur_floor < _fs_floor_baseline) _fs_floor_baseline = cur_floor; // fast down
969- else _fs_floor_baseline += (cur_floor - _fs_floor_baseline) / 16 ; // slow up
970911#if MAX_NEIGHBOURS
971912 int n = 0 ;
972913 int8_t snr_x4[MAX_NEIGHBOURS ];
@@ -1174,19 +1115,14 @@ void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
11741115 }
11751116
11761117 // (d) suppress iff no isolated-uncovered peer, every coverage peer covered, and
1177- // client-protection allows it (3-tier, always active). The noise gate then
1178- // decides by payload class: on a busy channel only cheap (self-healing)
1179- // payloads are suppressed (silence > repeat); payload-critical ones forward.
1118+ // client-protection allows it (3-tier, always active). Channel state does not
1119+ // enter the decision: under load the redundant TX itself IS the load.
11801120 if (!e->must_cover_self && allNearNeighboursCovered (*e, now)
11811121 && clientProtectionAllowsSuppress (pkt, now)) {
1182- if (noiseGateAllowsSuppress (pkt)) {
1183- e->suppressed = true ;
1184- _fs_suppressed++; // our rebroadcast was made redundant
1185- _fs_supp_graph++;
1186- cancelPendingFloodOutbound (hash);
1187- } else {
1188- _fs_noise_blocked++; // graph said redundant, noise gate vetoed
1189- }
1122+ e->suppressed = true ;
1123+ _fs_suppressed++; // our rebroadcast was made redundant
1124+ _fs_supp_graph++;
1125+ cancelPendingFloodOutbound (hash);
11901126 }
11911127#endif
11921128 }
@@ -1199,8 +1135,9 @@ void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
11991135 // proof (e.g. the forwarders are rank >cap, so no TRACE edge covers them). The
12001136 // graph result always wins: this only fires when the graph could not prove
12011137 // coverage, and never overrides must_cover_self (an uncovered top-N neighbour M
1202- // definitively owes coverage to -- only M's own TX can reach it). Same noise gate
1203- // + client protection as the graph path.
1138+ // definitively owes coverage to -- only M's own TX can reach it). Same client
1139+ // protection as the graph path; channel state and payload class do not gate this
1140+ // (deliberate -- see README).
12041141 if (e && !e->suppressed && !is_new) {
12051142 uint8_t c = effectiveFloodSuppressC ();
12061143 if (c > 0 && e->snr_fallback_wcount < 255 ) {
@@ -1209,8 +1146,7 @@ void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
12091146 int8_t lo = effectiveFloodSuppressSnrLo ();
12101147 e->snr_fallback_wcount += (snr >= hi) ? 2 : (snr < lo) ? 0 : 1 ;
12111148 if (e->snr_fallback_wcount >= c && !e->snr_fallback_suppressed && !e->must_cover_self &&
1212- clientProtectionAllowsSuppress (pkt, getRTCClock ()->getCurrentTime ()) &&
1213- noiseGateAllowsSuppress (pkt)) {
1149+ clientProtectionAllowsSuppress (pkt, getRTCClock ()->getCurrentTime ())) {
12141150 e->snr_fallback_suppressed = true ;
12151151 e->suppressed = true ;
12161152 _fs_suppressed++;
@@ -1696,10 +1632,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
16961632 _fs_pending_c = 0 ;
16971633 _fs_adaptive_active = false ; // until neighbour data is available -> static fallback
16981634 _fs_next_recompute_ms = 0 ;
1699- _fs_floor_baseline = -999 ; // noise-floor baseline: not yet learned -> gate assumes noisy
17001635 _fs_seen = 0 ;
17011636 _fs_suppressed = 0 ;
1702- _fs_supp_graph = _fs_supp_snr_fallback = _fs_noise_blocked = 0 ;
1637+ _fs_supp_graph = _fs_supp_snr_fallback = 0 ;
17031638 next_local_advert = next_flood_advert = 0 ;
17041639 dirty_contacts_expiry = 0 ;
17051640 set_radio_at = revert_radio_at = 0 ;
@@ -1746,9 +1681,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
17461681 _prefs.flood_suppress_snr_lo = 0 ; // dB: weak overheard forward => ignored (preserve edge)
17471682 _prefs.flood_suppress_delay_x = 3 ; // extra TX-delay multiplier for central flood relays (wider cancel window)
17481683 _prefs.trace_tx_power_dbm = 10 ; // TX power for coverage TRACE probes only (near links are strong; less disturbance)
1749- // SNR-repeat fallback is fixed ON (not configurable). The noise gate's margin defaults to AUTO
1750- // (firmware derives "noisy" relative to this site's baseline); an explicit override is optional.
1751- _prefs.flood_suppress_noise_margin = FLOOD_SUPPRESS_NOISE_MARGIN_AUTO ; // relative gate (auto margin)
1684+ // SNR-repeat fallback is fixed ON (not configurable).
17521685
17531686 // bridge defaults
17541687 _prefs.bridge_enabled = 1 ; // enabled
@@ -2046,11 +1979,11 @@ void MyMesh::formatFloodSuppressRatioReply(char *reply) {
20461979 if (!_prefs.flood_suppress ) return ; // plain "> off" when the master switch is off
20471980 StatsFormatHelper::formatFloodSuppressRatio (reply, _fs_suppressed, _fs_seen);
20481981 // Append the suppression-path breakdown: graph=coverage-graph suppressions,
2049- // snr_fallback=SNR-repeat fallback suppressions, nblk=graph-suppressions vetoed
2050- // by the noise gate. Lets the operator see WHICH mechanism is doing the work.
1982+ // snr_fallback=SNR-repeat fallback suppressions. Lets the operator see WHICH
1983+ // mechanism is doing the work.
20511984 char extra[64 ];
2052- sprintf (extra, " (graph=%lu snr_fallback=%lu nblk=%lu )" , (unsigned long )_fs_supp_graph,
2053- (unsigned long )_fs_supp_snr_fallback, ( unsigned long )_fs_noise_blocked );
1985+ sprintf (extra, " (graph=%lu snr_fallback=%lu)" , (unsigned long )_fs_supp_graph,
1986+ (unsigned long )_fs_supp_snr_fallback);
20541987 strcat (reply, extra);
20551988}
20561989
@@ -2205,7 +2138,7 @@ void MyMesh::clearStats() {
22052138 ((SimpleMeshTables *)getTables ())->resetStats ();
22062139 _fs_seen = 0 ;
22072140 _fs_suppressed = 0 ;
2208- _fs_supp_graph = _fs_supp_snr_fallback = _fs_noise_blocked = 0 ;
2141+ _fs_supp_graph = _fs_supp_snr_fallback = 0 ;
22092142 _meas_sent = _meas_returned = _meas_edge = _meas_timeout = _meas_neg = 0 ;
22102143 _meas_harvested = _meas_harvest_neg = 0 ;
22112144}
0 commit comments