Add configurable event mode hop limit (#11275)

* feat: resolve event mode hop limit

* feat: bake event mode hop limit

* fix: honor event mode hop cap in routing

* docs: expose event mode hop limit preference

* fix: enforce event hop defaults across routing

* docs: clarify event hop override behavior

* refactor: simplify event mode hop preference

* fix: cap equal event hop limit
This commit is contained in:
Benjamin Faershtein
2026-07-29 10:54:48 +00:00
committed by GitHub
parent b4ff1df864
commit 0fef83d434
8 changed files with 126 additions and 13 deletions
+1 -1
View File
@@ -92,7 +92,7 @@ uint32_t Default::getConfiguredOrMinimumValue(uint32_t configured, uint32_t minV
uint8_t Default::getConfiguredOrDefaultHopLimit(uint8_t configured)
{
#if USERPREFS_EVENT_MODE
return (configured > HOP_RELIABLE) ? HOP_RELIABLE : config.lora.hop_limit;
return (configured >= eventModeHopLimit) ? eventModeHopLimit : config.lora.hop_limit;
#else
return (configured >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit;
#endif
+15 -1
View File
@@ -5,6 +5,7 @@
#include <cmath>
#include <cstdint>
#include <meshUtils.h>
#include <type_traits>
#define ONE_DAY 24 * 60 * 60
#define ONE_MINUTE_MS 60 * 1000
#define THIRTY_SECONDS_MS 30 * 1000
@@ -75,7 +76,20 @@ enum class TrafficType { POSITION, TELEMETRY };
class Default
{
#if USERPREFS_EVENT_MODE && defined(USERPREFS_EVENT_MODE_HOP_LIMIT)
static constexpr auto eventModeHopLimitSetting = USERPREFS_EVENT_MODE_HOP_LIMIT;
#else
static constexpr auto eventModeHopLimitSetting = HOP_RELIABLE;
#endif
using EventModeHopLimitType = typename std::remove_cv<decltype(eventModeHopLimitSetting)>::type;
static_assert(std::is_integral<EventModeHopLimitType>::value && !std::is_same<EventModeHopLimitType, bool>::value &&
eventModeHopLimitSetting >= 0 && eventModeHopLimitSetting <= HOP_MAX,
"USERPREFS_EVENT_MODE_HOP_LIMIT must be an integer between 0 and 7");
public:
static constexpr uint8_t eventModeHopLimit = static_cast<uint8_t>(eventModeHopLimitSetting);
static constexpr uint8_t eventModeRelayHopLimit = eventModeHopLimit > 0 ? eventModeHopLimit - 1 : 0;
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
@@ -129,4 +143,4 @@ class Default
return 1.0 + (nodesOverForty * throttlingFactor); // Each number of online node scales by throttle factor
}
}
};
};
+17 -5
View File
@@ -1,4 +1,5 @@
#include "NextHopRouter.h"
#include "Default.h"
#include "MeshTypes.h"
#include "meshUtils.h"
#if !MESHTASTIC_EXCLUDE_TRACEROUTE
@@ -9,6 +10,18 @@
#endif
#include "NodeDB.h"
#if USERPREFS_EVENT_MODE
static void capEventRelayHops(meshtastic_MeshPacket *packet)
{
if (packet->hop_limit <= Default::eventModeRelayHopLimit)
return;
const uint8_t reduction = packet->hop_limit - Default::eventModeRelayHopLimit;
packet->hop_start = reduction <= packet->hop_start ? packet->hop_start - reduction : 0;
packet->hop_limit = Default::eventModeRelayHopLimit;
}
#endif
NextHopRouter::NextHopRouter() {}
bool NextHopRouter::relayOpaquePacket(const meshtastic_MeshPacket *p)
@@ -26,6 +39,9 @@ bool NextHopRouter::relayOpaquePacket(const meshtastic_MeshPacket *p)
if (!relay)
return false;
relay->hop_limit--;
#if USERPREFS_EVENT_MODE
capEventRelayHops(relay);
#endif
relay->relay_node = nodeDB->getLastByteOfNodeNum(getNodeNum());
// The interface declines some packets (NODENUM_BROADCAST_NO_LORA) with ERRNO_SHOULD_RELEASE,
// which leaves the copy ours to free. Dropping it here would leak a pool slot per opaque frame.
@@ -211,11 +227,7 @@ bool NextHopRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p)
LOG_INFO("favorite-ROUTER/CLIENT_BASE-to-ROUTER/CLIENT_BASE rebroadcast: preserving hop_limit");
}
#if USERPREFS_EVENT_MODE
if (tosend->hop_limit > 2) {
// if we are "correcting" the hop_limit, "correct" the hop_start by the same amount to preserve hops away.
tosend->hop_start -= (tosend->hop_limit - 2);
tosend->hop_limit = 2;
}
capEventRelayHops(tosend);
#endif
ErrorCode res =
+4
View File
@@ -927,7 +927,11 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
config.lora.override_frequency = USERPREFS_LORACONFIG_OVERRIDE_FREQUENCY;
#endif
#if USERPREFS_EVENT_MODE
config.lora.hop_limit = Default::eventModeHopLimit;
#else
config.lora.hop_limit = HOP_RELIABLE;
#endif
#ifdef USERPREFS_CONFIG_LORA_IGNORE_MQTT
config.lora.ignore_mqtt = USERPREFS_CONFIG_LORA_IGNORE_MQTT;
#else
+7 -6
View File
@@ -64,19 +64,20 @@ void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketI
uint8_t RoutingModule::getHopLimitForResponse(const meshtastic_MeshPacket &mp)
{
const int8_t hopsUsed = getHopsAway(mp);
const uint8_t responseHopLimit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
if (hopsUsed >= 0) {
if (hopsUsed > (int32_t)(config.lora.hop_limit)) {
// In event mode, we never want to send packets with more than our default 3 hops.
#if !(EVENTMODE) // This falls through to the default.
if (hopsUsed > static_cast<int32_t>(responseHopLimit)) {
// In event mode, never exceed the configured event hop limit.
#if !USERPREFS_EVENT_MODE // This falls through to the default.
return hopsUsed; // If the request used more hops than the limit, use the same amount of hops
#endif
} else if (mp.hop_start == 0) {
return 0; // The requesting node wanted 0 hops, so the response also uses a direct/local path.
} else if ((uint8_t)(hopsUsed + 2) < config.lora.hop_limit) {
} else if (static_cast<uint8_t>(hopsUsed + 2) < responseHopLimit) {
return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different
}
}
return Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); // Use the default hop limit
return responseHopLimit;
}
meshtastic_MeshPacket *RoutingModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
@@ -93,4 +94,4 @@ RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_RO
// LocalOnly requires either the from or to to be a known node
// knownOnly specifically requires the from to be a known node.
encryptedOk = true;
}
}