Pr2 tmm basic#10706
Conversation
⚡ Try this PR in the Web FlasherWarning This is an automated, unreviewed CI test build. Back up your device configuration Supported boards built by this PR (24)
Build artifacts expire on 2026-07-20. Updated for |
Firmware Size Report22 targets | vs
Show 17 more target(s)
Updated for c301941 |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Reworks the TrafficManagementModule cache implementation (linear-scan unified cache + epoch rebase) and introduces persistence-backed “warm” long-tail node retention plus a next-hop overflow hint cache to keep routing/PKI working after NodeDB eviction.
Changes:
- Replace TMM’s cuckoo-hash cache/indexing with flat arrays + linear scan, add sliding epoch rebase, and add next-hop overflow hint storage/preload.
- Add WarmNodeStore (file-backed generally, raw-flash ring on nRF52840) and integrate it into NodeDB eviction/migration + PKI DM key lookup.
- Add/adjust unit tests and nRF52 linker/build guards to reserve the warm-store flash region.
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| variants/nrf52840/nrf52840.ini | Pins nRF52840 base env to a warm-store-safe linker script for S140 v6. |
| variants/nrf52840/nrf52.ini | Adds a post-link build guard to prevent the image overlapping the warm-store flash region. |
| test/test_warm_store/test_main.cpp | New unit tests for WarmNodeStore admission/eviction/take() and persistence. |
| test/test_traffic_management/test_main.cpp | Extends TMM tests for congestion-gated hop exhaustion and next-hop overflow cache behavior. |
| test/test_nodedb_blocked/test_main.cpp | New tests for NodeDB migration + favorite/ignored retention with warm-tier demotion. |
| src/platform/nrf52/nrf52840_s140_v7.ld | Shrinks FLASH region to reserve 0xEA000–0xED000 for WarmNodeStore ring. |
| src/platform/nrf52/nrf52840_s140_v6.ld | Adds a new S140 v6 linker script variant with the same warm-store reservation. |
| src/modules/TrafficManagementModule.h | Updates docs and adds APIs/fields for next-hop cache + epoch rebase. |
| src/modules/TrafficManagementModule.cpp | Implements flat caches, next-hop overflow cache, preload, and epoch rebase logic. |
| src/modules/TraceRouteModule.cpp | Mirrors traceroute-derived next-hop info into TMM overflow cache. |
| src/modules/AdminModule.cpp | Routes favorite/ignore changes through NodeDB’s protected-node cap enforcement. |
| src/mesh/mesh-pb-constants.h | Adjusts MAX_NUM_NODES defaults, adds MAX_SATELLITE_NODES/WARM_NODE_COUNT, enables HAS_TRAFFIC_MANAGEMENT by default. |
| src/mesh/generated/meshtastic/deviceonly.pb.h | Updates generated max size constant due to proto size changes. |
| src/mesh/WarmNodeStore.h | Introduces WarmNodeStore API + persistence design and nRF52840 ring layout. |
| src/mesh/WarmNodeStore.cpp | Implements WarmNodeStore memory/persistence (raw-flash ring or warm.dat snapshot). |
| src/mesh/Router.cpp | Uses NodeDB::copyPublicKey() so PKI DMs can decrypt/encrypt for warm-tier nodes. |
| src/mesh/NodeDB.h | Adds warm tier, protected-node cap API, satellite caps, and public key copy helper. |
| src/mesh/NodeDB.cpp | Implements migration demotion to warm tier, satellite caps, protected-node cap, and warm-tier persistence. |
| src/mesh/NextHopRouter.cpp | Stores ACK-confirmed next hops in both NodeDB and TMM, and consults TMM as fallback. |
| src/mesh/Default.h | Changes default position-dedup grid precision (24 → 19 bits). |
| src/graphics/draw/MenuHandler.cpp | Surfaces protected-node-cap failures when favoriting/ignoring via UI. |
| extra_scripts/nrf52_warm_region.py | New post-link guard to fail builds that overlap reserved warm-store flash. |
|
We probably need to update the app and online maps to accommodate locations not updating over few hours. Currently the maps seem to lose a nodes location if it's not sent every 2 or 3 hours. |
e28ef4b to
48a1b68
Compare
6ffdf97 to
09bd29d
Compare
93d412f to
453eecf
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 26 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
src/modules/TrafficManagementModule.cpp:705
USERPREFS_TMM_APPLY_TO_PRIVATE_CHANNELSis documented (and used inalterReceived()) as extending both position dedup and precision clamping to private/custom-key channels, but the dedup gate here is hard-coded tochannels.isWellKnownChannel(). As a result, compiling the flag still won't enable dedup on private channels.
if (!isFromUs(&mp) && !isToUs(&mp)) {
if (channels.isWellKnownChannel(mp.channel) && mp.decoded.portnum == meshtastic_PortNum_POSITION_APP) {
meshtastic_Position pos = meshtastic_Position_init_zero;
if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Position_msg, &pos)) {
if (shouldDropPosition(&mp, &pos, nowMs)) {
logAction("drop", &mp, "position-dedup");
incrementStat(&stats.position_dedup_drops);
ignoreRequest = true; // Suppress NAK
return ProcessMessage::STOP; // Consumed — duplicate will not be rebroadcast
}
1e49f67 to
0c953c3
Compare
Adds the Traffic Management module (TMM) plus the NodeDB/warm-store and next-hop foundations it builds on: - Unified per-node cache (flat array, 8-bit relative ticks) shared by all features; role-aware throttles for tracker / lost-and-found. - Position deduplication: drop unchanged position rebroadcasts within a configurable interval; precision driven off the channel ceiling (clamped to the public-key max on well-known channels). Enabled by default at 11h. - Per-node rate limiting and unknown-packet filtering (config-driven; a non-zero companion field enables each feature -- no bool toggles). - NodeInfo direct response from cache with role-based hop clamps. - Persistent next-hop overflow store: confirmed hops have no TTL, are seeded from NodeInfoLite at boot, and survive hot-store eviction. - Three-tier sender-role resolution (hot NodeInfoLite -> warm store -> TMM cache). Role is cached write-time (seeded on first track, refreshed from NodeInfo), pins its cache entry like a next-hop hint, and is evicted last. - Warm store caches device role + protected category across reboot/eviction. - PositionModule stationary floor for tracker / lost-and-found. - PSRAM gating for warm/satellite/TMM cache sizes; STM32WL excluded. Protobufs: TrafficManagementConfig trimmed to the five uint32 fields actually used; submodule repointed to protobufs develop. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eshtastic#10706) Adds the Traffic Management module (TMM) plus the NodeDB/warm-store and next-hop foundations it builds on: - Unified per-node cache (flat array, 8-bit relative ticks) shared by all features; role-aware throttles for tracker / lost-and-found. - Position deduplication: drop unchanged position rebroadcasts within a configurable interval; precision driven off the channel ceiling (clamped to the public-key max on well-known channels). Enabled by default at 11h. - Per-node rate limiting and unknown-packet filtering (config-driven; a non-zero companion field enables each feature -- no bool toggles). - NodeInfo direct response from cache with role-based hop clamps. - Persistent next-hop overflow store: confirmed hops have no TTL, are seeded from NodeInfoLite at boot, and survive hot-store eviction. - Three-tier sender-role resolution (hot NodeInfoLite -> warm store -> TMM cache). Role is cached write-time (seeded on first track, refreshed from NodeInfo), pins its cache entry like a next-hop hint, and is evicted last. - Warm store caches device role + protected category across reboot/eviction. - PositionModule stationary floor for tracker / lost-and-found. - PSRAM gating for warm/satellite/TMM cache sizes; STM32WL excluded. Protobufs: TrafficManagementConfig trimmed to the five uint32 fields actually used; submodule repointed to protobufs develop. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Reworks the TrafficManagementModule cache layer and adds a routing-hint overflow store.
Stacks on #10745 — review/merge after it; the shared NodeDB/WarmNodeStore files belong to #10745 .
What's in this PR
1. Position deduplication (
TrafficManagementModule)Fingerprints each relayed position broadcast (4-bit lat + 4-bit lon nibble from the truncated coordinates, remapped so
0x00→0xFFmatching therelay_nodesentinel idiom) and suppresses rebroadcasts of the same fingerprint within a configurable window (default 11 h). Only fires on well-known channels (modem-preset name + PSK size ≤ 1). The fingerprint occupies the pre-existingpos_fingerprintbyte in the 10-byte cache entry — no struct growth.2. Relayed-position precision clamp (
TrafficManagementModule)alterReceived()clamps theprecision_bitsof any relayed position broadcast down to the channel's configuredmodule_settings.position_precisionceiling. Prevents a node from forwarding coordinates finer than the channel was configured to carry (e.g. a LongFast channel set to 13-bit / ~5 km). Ham mode is exempt; lost-and-found is not exempt (removed the prior exemption). Controlled bychannels.isWellKnownChannel(); opt-inUSERPREFS_TMM_APPLY_TO_PRIVATE_CHANNELSextends it to private channels.3. Role-aware dedup exceptions
originRole()resolves a packet's originator viaNodeDB::getNodeRole(), which falls through to the warm-tier cached role when the node has been evicted from the hot store (built on the warm-store role caching from PR1.5).New defaults in
Default.h:4.
Channels::isWellKnownChannel()New predicate: PSK size ≤ 1 and channel name matches any modem-preset display name. Broader than
isDefaultChannel(which requires the current preset name + PSK byte0x01); catches user-named channels like a "LongFast" channel running under MediumFast modem settings.5. PositionModule stationary / fixed-position floor
sendOurPosition()now applies a 12 h broadcast floor when the device is stationary (position unchanged within the broadcast precision cell) or hasfixed_position = true. A real move still triggers the normal smart-broadcast path immediately.Role nuances:
fixed_position = true: all roles hold to the 12 h floor; pinning yourself forfeits the tracker exception.New helpers split out for unit-testability:
positionUnchangedSinceLastSend(),positionWithinPrecisionCell(),effectiveBroadcastIntervalMs().6.
NodeDB::getNodeRole()Hot-store (with-user) lookup → warm-tier
lookupMeta()fallback →CLIENT. Lets role-aware TMM/PositionModule policy keep firing for tracker/L&F nodes aged out of the hot store.7. AdminModule protected-node cap
set_favorite_nodeandset_ignored_nodevia remote admin now log a warning and refuse when the node is in the warm-tier protected category (groundwork for the hop-trimming protected-node path in PR2.5).8.
preloadNextHopsFromNodeDB→boolReturn type changed from
voidtobool. Returnsfalsewhen prerequisites aren't ready yet (NodeDB not initialized), so callers can retry on a later pass rather than silently doing nothing.Compatibility
precision_bitsin the position payload, which was already populated).isWellKnownChanneland the dedup/clamp features default to well-known channels only — custom-key channels are unaffected unlessUSERPREFS_TMM_APPLY_TO_PRIVATE_CHANNELSis set.🤝 Attestations