From 3a6766b0fddb6f29c105a3f08a1009ed2cdcda12 Mon Sep 17 00:00:00 2001 From: mikecarper Date: Fri, 8 May 2026 00:49:33 -0700 Subject: [PATCH] Improve flood retry bridge buckets --- build-iotthinks.sh | 23 ++++---- docs/cli_commands.md | 18 +++++- examples/simple_repeater/MyMesh.cpp | 92 ++++++++++++++++++++++++----- examples/simple_repeater/MyMesh.h | 10 +++- src/helpers/CommonCLI.cpp | 84 +++++++++++++++++--------- src/helpers/CommonCLI.h | 17 +++++- src/helpers/SimpleMeshTables.h | 2 - 7 files changed, 183 insertions(+), 63 deletions(-) mode change 100644 => 100755 build-iotthinks.sh diff --git a/build-iotthinks.sh b/build-iotthinks.sh old mode 100644 new mode 100755 index 7c654482..3e41b4d6 --- a/build-iotthinks.sh +++ b/build-iotthinks.sh @@ -1,10 +1,11 @@ -# sh ./build-repeaters-iotthinks.sh +#!/usr/bin/env bash +# ./build-iotthinks.sh export FIRMWARE_VERSION="PowerSaving15" ############# Repeaters ############# # Commonly-used boards ## ESP32 - 12 boards -sh build.sh build-firmware \ +./build.sh build-firmware \ Heltec_v3_repeater \ Heltec_WSL3_repeater \ heltec_v4_repeater \ @@ -19,7 +20,7 @@ Heltec_E290_repeater \ Heltec_Wireless_Tracker_repeater ## NRF52 - 13 boards -sh build.sh build-firmware \ +./build.sh build-firmware \ RAK_4631_repeater \ Heltec_t114_repeater \ Xiao_nrf52_repeater \ @@ -35,25 +36,25 @@ GAT562_30S_Mesh_Kit_repeater \ GAT562_Mesh_Tracker_Pro_repeater ## ESP32, SX1276 - 3 boards -sh build.sh build-firmware \ +./build.sh build-firmware \ Heltec_v2_repeater \ LilyGo_TLora_V2_1_1_6_repeater \ Tbeam_SX1276_repeater ## Ikoka - 3 boards -sh build.sh build-firmware \ +./build.sh build-firmware \ ikoka_nano_nrf_22dbm_repeater \ ikoka_nano_nrf_30dbm_repeater \ ikoka_nano_nrf_33dbm_repeater ############# Room Server ############# # ESP32 -sh build.sh build-firmware \ +./build.sh build-firmware \ Heltec_v3_room_server \ heltec_v4_room_server # NRF52 -sh build.sh build-firmware \ +./build.sh build-firmware \ RAK_4631_room_server \ Heltec_t114_room_server \ Xiao_nrf52_room_server \ @@ -63,7 +64,7 @@ RAK_3401_room_server ############# Companions BLE ############# # ESP32 -sh build.sh build-firmware \ +./build.sh build-firmware \ Heltec_v3_companion_radio_ble_ps \ heltec_v4_companion_radio_ble_ps \ heltec_v4_companion_radio_ble_ps_femoff \ @@ -71,7 +72,7 @@ Xiao_S3_WIO_companion_radio_ble \ Heltec_Wireless_Paper_companion_radio_ble # NRF52 -sh build.sh build-firmware \ +./build.sh build-firmware \ RAK_4631_companion_radio_ble \ Heltec_t114_companion_radio_ble \ Xiao_nrf52_companion_radio_ble \ @@ -82,11 +83,11 @@ RAK_3401_companion_radio_ble \ RAK_WisMesh_Tag_companion_radio_ble ############# Companions USB ############# -sh build.sh build-firmware \ +./build.sh build-firmware \ Heltec_v3_companion_radio_usb ############# Companions BLE PS ############# -sh build.sh build-firmware \ +./build.sh build-firmware \ Heltec_v3_companion_radio_ble_ps \ heltec_v4_companion_radio_ble_ps \ heltec_v4_3_companion_radio_ble_ps_femoff \ diff --git a/docs/cli_commands.md b/docs/cli_commands.md index c1041042..1a6e4233 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -821,7 +821,7 @@ This document provides an overview of CLI commands that can be sent to MeshCore **Default:** `off` -**Note:** Bridge mode uses bucket definitions instead of the single `flood.retry.prefixes` target list. If a flood comes from one fresh bucket, retry continues until every other fresh configured bucket has been heard or `flood.retry.count` is exhausted. +**Note:** Bridge mode uses bucket definitions instead of the single `flood.retry.prefixes` target list. It also has an implicit unconfigured catch-all bucket. If a flood comes from one fresh configured bucket, retry continues until every other fresh configured bucket plus the catch-all bucket has been heard or `flood.retry.count` is exhausted. If a flood comes from an unconfigured or pathless source, retry targets every fresh configured bucket. This means one configured bucket bridges between that bucket and everything else. Prefixes in `flood.retry.ignore` never count as heard bridge targets. --- @@ -832,7 +832,7 @@ This document provides an overview of CLI commands that can be sent to MeshCore **Parameters:** - `bucket`: Bucket number (`1`-`6`) -- `prefixes`: Up to 8 comma-separated 3-byte hex prefixes, such as `AABBCC,223344`; use `none` or `off` to clear +- `prefixes`: Up to 17 comma-separated 3-byte hex prefixes, such as `AABBCC,223344`; use `none` or `off` to clear **Default:** all buckets empty @@ -840,6 +840,20 @@ This document provides an overview of CLI commands that can be sent to MeshCore --- +#### View or change flood retry ignored prefixes +**Usage:** +- `get flood.retry.ignore` +- `set flood.retry.ignore ` + +**Parameters:** +- `prefixes`: Up to 8 comma-separated 3-byte hex prefixes, such as `AABBCC,223344`; use `none` or `off` to clear + +**Default:** empty + +**Note:** Ignored prefixes do not count as a heard bridge bucket or as the implicit catch-all bucket when bridge retry decides whether every target has repeated the flood. + +--- + ### ACL #### Add, update or remove permissions for a companion diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index ca86d27e..3fa770e9 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -912,6 +912,19 @@ bool MyMesh::floodRetryPrefixMatches(const mesh::Packet* packet) const { return false; } +bool MyMesh::floodRetryPrefixIgnored(const uint8_t* prefix, uint8_t prefix_len) const { + if (prefix == NULL || prefix_len == 0 || prefix_len > MAX_ROUTE_HASH_BYTES) { + return false; + } + for (int i = 0; i < FLOOD_RETRY_IGNORE_PREFIXES; i++) { + const uint8_t* ignored = _prefs.flood_retry_ignore_prefixes[i]; + if ((ignored[0] != 0 || ignored[1] != 0 || ignored[2] != 0) + && memcmp(ignored, prefix, prefix_len) == 0) { + return true; + } + } + return false; +} bool MyMesh::floodRetryPrefixFresh(const uint8_t* prefix, uint8_t prefix_len) const { const auto* recent = ((const SimpleMeshTables *)getTables())->findRecentRepeaterByHash(prefix, prefix_len); if (recent == NULL || recent->last_heard_millis == 0) { @@ -919,10 +932,22 @@ bool MyMesh::floodRetryPrefixFresh(const uint8_t* prefix, uint8_t prefix_len) co } return (uint32_t)(millis() - recent->last_heard_millis) <= 3600000UL; } -int MyMesh::floodRetryBucketForPrefix(const uint8_t* prefix, uint8_t prefix_len, bool require_fresh) const { +static const uint8_t FLOOD_RETRY_BRIDGE_OTHER_BUCKET = FLOOD_RETRY_BRIDGE_BUCKETS; + +static uint8_t floodRetryBucketMask(uint8_t bucket) { + if (bucket >= 8) { + return 0; + } + return (uint8_t)(1U << bucket); +} +int MyMesh::floodRetryBucketForPrefix(const uint8_t* prefix, uint8_t prefix_len, bool require_fresh, + bool include_other) const { if (prefix == NULL || prefix_len == 0 || prefix_len > MAX_ROUTE_HASH_BYTES) { return -1; } + if (floodRetryPrefixIgnored(prefix, prefix_len)) { + return -1; + } if (require_fresh && !floodRetryPrefixFresh(prefix, prefix_len)) { return -1; } @@ -935,18 +960,28 @@ int MyMesh::floodRetryBucketForPrefix(const uint8_t* prefix, uint8_t prefix_len, } } } + if (include_other) { + return FLOOD_RETRY_BRIDGE_OTHER_BUCKET; + } return -1; } +int MyMesh::floodRetryBucketForPathHop(const uint8_t* prefix, uint8_t prefix_len, uint8_t hop, + uint8_t progress_marker) const { + return floodRetryBucketForPrefix(prefix, prefix_len, hop < progress_marker, true); +} int MyMesh::floodRetrySourceBucket(const mesh::Packet* packet) const { - if (packet == NULL || packet->getPathHashCount() < 2) { + if (packet == NULL) { return -1; } uint8_t hash_size = packet->getPathHashSize(); if (hash_size == 0 || hash_size > MAX_ROUTE_HASH_BYTES) { return -1; } + if (packet->getPathHashCount() < 2) { + return FLOOD_RETRY_BRIDGE_OTHER_BUCKET; + } const uint8_t* source_prefix = &packet->path[(packet->getPathHashCount() - 2) * hash_size]; - return floodRetryBucketForPrefix(source_prefix, hash_size, true); + return floodRetryBucketForPrefix(source_prefix, hash_size, true, true); } uint8_t MyMesh::floodRetryBridgeTargetMask(uint8_t source_bucket) const { uint8_t mask = 0; @@ -957,15 +992,20 @@ uint8_t MyMesh::floodRetryBridgeTargetMask(uint8_t source_bucket) const { for (int i = 0; i < FLOOD_RETRY_BUCKET_PREFIXES; i++) { const uint8_t* configured = _prefs.flood_retry_bridge_buckets[bucket][i]; if ((configured[0] != 0 || configured[1] != 0 || configured[2] != 0) + && !floodRetryPrefixIgnored(configured, FLOOD_RETRY_PREFIX_LEN) && floodRetryPrefixFresh(configured, FLOOD_RETRY_PREFIX_LEN)) { - mask |= (uint8_t)(1U << bucket); + mask |= floodRetryBucketMask((uint8_t)bucket); break; } } } + if (source_bucket != FLOOD_RETRY_BRIDGE_OTHER_BUCKET) { + mask |= floodRetryBucketMask(FLOOD_RETRY_BRIDGE_OTHER_BUCKET); + } return mask; } -uint8_t MyMesh::floodRetryBridgeHeardMask(const mesh::Packet* packet, uint8_t source_bucket) const { +uint8_t MyMesh::floodRetryBridgeHeardMask(const mesh::Packet* packet, uint8_t source_bucket, + uint8_t progress_marker) const { if (packet == NULL || packet->getPathHashCount() == 0) { return 0; } @@ -977,9 +1017,13 @@ uint8_t MyMesh::floodRetryBridgeHeardMask(const mesh::Packet* packet, uint8_t so uint8_t mask = 0; const uint8_t* path = packet->path; for (int hop = 0; hop < packet->getPathHashCount(); hop++) { - int bucket = floodRetryBucketForPrefix(path, hash_size, true); + if (progress_marker > 0 && hop == progress_marker - 1) { + path += hash_size; + continue; + } + int bucket = floodRetryBucketForPathHop(path, hash_size, (uint8_t)hop, progress_marker); if (bucket >= 0 && bucket != source_bucket) { - mask |= (uint8_t)(1U << bucket); + mask |= floodRetryBucketMask((uint8_t)bucket); } path += hash_size; } @@ -1019,7 +1063,8 @@ MyMesh::FloodRetryBridgeState* MyMesh::floodRetryBridgeStateFor(const mesh::Pack return NULL; } - uint8_t heard_mask = floodRetryBridgeHeardMask(packet, (uint8_t)source_bucket) & target_mask; + uint8_t progress_marker = packet->getPathHashCount(); + uint8_t heard_mask = floodRetryBridgeHeardMask(packet, (uint8_t)source_bucket, progress_marker) & target_mask; if ((heard_mask & target_mask) == target_mask) { return NULL; } @@ -1029,6 +1074,7 @@ MyMesh::FloodRetryBridgeState* MyMesh::floodRetryBridgeStateFor(const mesh::Pack free_slot->source_bucket = (uint8_t)source_bucket; free_slot->target_mask = target_mask; free_slot->heard_mask = heard_mask; + free_slot->progress_marker = progress_marker; free_slot->active = true; return free_slot; } @@ -1088,8 +1134,13 @@ void MyMesh::refreshFloodRetryHeardRecent(const mesh::Packet* packet) { FloodRetryBridgeState* state = floodRetryBridgeStateFor(packet, false); if (state != NULL) { for (int hop = 0; hop < packet->getPathHashCount(); hop++) { - int bucket = floodRetryBucketForPrefix(path, hash_size, true); - if (bucket >= 0 && bucket != state->source_bucket && (state->target_mask & (uint8_t)(1U << bucket))) { + if (state->progress_marker > 0 && hop == state->progress_marker - 1) { + path += hash_size; + continue; + } + int bucket = floodRetryBucketForPathHop(path, hash_size, (uint8_t)hop, state->progress_marker); + uint8_t bucket_mask = bucket >= 0 ? floodRetryBucketMask((uint8_t)bucket) : 0; + if (bucket >= 0 && bucket != state->source_bucket && (state->target_mask & bucket_mask)) { tables->setRecentRepeater(path, hash_size, packet->_snr, false, true); } path += hash_size; @@ -1161,9 +1212,20 @@ bool MyMesh::formatFloodRetryHeard(char* dest, size_t dest_len, const mesh::Pack } const uint8_t* path = packet->path; for (int hop = 0; hop < packet->getPathHashCount(); hop++) { - int bucket = floodRetryBucketForPrefix(path, hash_size, true); - if (bucket >= 0 && bucket != state->source_bucket && (state->target_mask & (uint8_t)(1U << bucket))) { - size_t needed = (first ? 0 : 1) + 2 + 1 + ((size_t)hash_size * 2) + 1; + if (state->progress_marker > 0 && hop == state->progress_marker - 1) { + path += hash_size; + continue; + } + int bucket = floodRetryBucketForPathHop(path, hash_size, (uint8_t)hop, state->progress_marker); + uint8_t bucket_mask = bucket >= 0 ? floodRetryBucketMask((uint8_t)bucket) : 0; + if (bucket >= 0 && bucket != state->source_bucket && (state->target_mask & bucket_mask)) { + char bucket_label[8]; + if ((uint8_t)bucket == FLOOD_RETRY_BRIDGE_OTHER_BUCKET) { + strcpy(bucket_label, "other"); + } else { + snprintf(bucket_label, sizeof(bucket_label), "b%d", bucket + 1); + } + size_t needed = (first ? 0 : 1) + strlen(bucket_label) + 1 + ((size_t)hash_size * 2) + 1; if (remaining < needed) { if (remaining > 4) { strcpy(out, "..."); @@ -1174,7 +1236,7 @@ bool MyMesh::formatFloodRetryHeard(char* dest, size_t dest_len, const mesh::Pack *out++ = ','; remaining--; } - int n = snprintf(out, remaining, "b%d:", bucket + 1); + int n = snprintf(out, remaining, "%s:", bucket_label); if (n < 0 || (size_t)n >= remaining) { return dest[0] != 0; } @@ -1298,7 +1360,7 @@ bool MyMesh::isFloodRetryEchoTarget(const mesh::Packet* packet, uint8_t progress if (state == NULL) { return false; } - state->heard_mask |= floodRetryBridgeHeardMask(packet, state->source_bucket) & state->target_mask; + state->heard_mask |= floodRetryBridgeHeardMask(packet, state->source_bucket, state->progress_marker) & state->target_mask; return (state->heard_mask & state->target_mask) == state->target_mask; } if (hasFloodRetryPrefixes()) { diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index c189bda9..6716acd1 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -104,6 +104,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { uint8_t source_bucket; uint8_t target_mask; uint8_t heard_mask; + uint8_t progress_marker; bool active; }; mutable FloodRetryBridgeState flood_retry_bridge_states[MAX_FLOOD_RETRY_SLOTS]; @@ -138,11 +139,16 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { bool hasFloodRetryPrefixes() const; bool floodRetryPrefixMatches(const mesh::Packet* packet) const; bool floodRetryLastHopMatches(const mesh::Packet* packet) const; + bool floodRetryPrefixIgnored(const uint8_t* prefix, uint8_t prefix_len) const; bool floodRetryPrefixFresh(const uint8_t* prefix, uint8_t prefix_len) const; - int floodRetryBucketForPrefix(const uint8_t* prefix, uint8_t prefix_len, bool require_fresh) const; + int floodRetryBucketForPrefix(const uint8_t* prefix, uint8_t prefix_len, bool require_fresh, + bool include_other) const; + int floodRetryBucketForPathHop(const uint8_t* prefix, uint8_t prefix_len, uint8_t hop, + uint8_t progress_marker) const; int floodRetrySourceBucket(const mesh::Packet* packet) const; uint8_t floodRetryBridgeTargetMask(uint8_t source_bucket) const; - uint8_t floodRetryBridgeHeardMask(const mesh::Packet* packet, uint8_t source_bucket) const; + uint8_t floodRetryBridgeHeardMask(const mesh::Packet* packet, uint8_t source_bucket, + uint8_t progress_marker) const; FloodRetryBridgeState* floodRetryBridgeStateFor(const mesh::Packet* packet, bool create) const; void clearFloodRetryBridgeState(const mesh::Packet* packet); void refreshFloodRetryHeardRecent(const mesh::Packet* packet); diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 27b2eeb4..ab4513ca 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -213,11 +213,12 @@ static void formatFloodRetryPathGate(char* dest, uint8_t path_gate) { } } -static void formatFloodRetryPrefixes(char* dest, const NodePrefs* prefs) { +static void formatFloodRetryPrefixList(char* dest, const uint8_t prefixes[][FLOOD_RETRY_PREFIX_LEN], + uint8_t max_prefixes) { char* out = dest; bool first = true; - for (int i = 0; i < FLOOD_RETRY_PREFIX_SLOTS; i++) { - const uint8_t* prefix = prefs->flood_retry_prefixes[i]; + for (int i = 0; i < max_prefixes; i++) { + const uint8_t* prefix = prefixes[i]; if (prefix[0] == 0 && prefix[1] == 0 && prefix[2] == 0) { continue; } @@ -231,26 +232,16 @@ static void formatFloodRetryPrefixes(char* dest, const NodePrefs* prefs) { *out = 0; } +static void formatFloodRetryPrefixes(char* dest, const NodePrefs* prefs) { + formatFloodRetryPrefixList(dest, prefs->flood_retry_prefixes, FLOOD_RETRY_PREFIX_SLOTS); +} + static void formatFloodRetryBridgeBucket(char* dest, const NodePrefs* prefs, uint8_t bucket) { - char* out = dest; - bool first = true; if (bucket >= FLOOD_RETRY_BRIDGE_BUCKETS) { - *out = 0; + dest[0] = 0; return; } - for (int i = 0; i < FLOOD_RETRY_BUCKET_PREFIXES; i++) { - const uint8_t* prefix = prefs->flood_retry_bridge_buckets[bucket][i]; - if (prefix[0] == 0 && prefix[1] == 0 && prefix[2] == 0) { - continue; - } - if (!first) { - *out++ = ','; - } - mesh::Utils::toHex(out, prefix, FLOOD_RETRY_PREFIX_LEN); - out += FLOOD_RETRY_PREFIX_LEN * 2; - first = false; - } - *out = 0; + formatFloodRetryPrefixList(dest, prefs->flood_retry_bridge_buckets[bucket], FLOOD_RETRY_BUCKET_PREFIXES); } static bool parseFloodRetryPrefixes(NodePrefs* prefs, const char* value) { @@ -261,7 +252,7 @@ static bool parseFloodRetryPrefixes(NodePrefs* prefs, const char* value) { return true; } - char tmp[96]; + char tmp[FLOOD_RETRY_LIST_TEXT_MAX]; StrHelper::strncpy(tmp, value, sizeof(tmp)); const char* parts[FLOOD_RETRY_PREFIX_SLOTS + 1]; int num = mesh::Utils::parseTextParts(tmp, parts, FLOOD_RETRY_PREFIX_SLOTS + 1); @@ -290,20 +281,20 @@ static bool parseFloodRetryPrefixes(NodePrefs* prefs, const char* value) { } static bool parseFloodRetryPrefixList(uint8_t dest[][FLOOD_RETRY_PREFIX_LEN], uint8_t max_prefixes, const char* value) { - if (max_prefixes > FLOOD_RETRY_BUCKET_PREFIXES) { + if (max_prefixes > FLOOD_RETRY_LIST_PREFIXES) { return false; } - uint8_t parsed[FLOOD_RETRY_BUCKET_PREFIXES][FLOOD_RETRY_PREFIX_LEN]; + uint8_t parsed[FLOOD_RETRY_LIST_PREFIXES][FLOOD_RETRY_PREFIX_LEN]; memset(parsed, 0, sizeof(parsed)); if (value == NULL || value[0] == 0 || strcmp(value, "none") == 0 || strcmp(value, "off") == 0) { memcpy(dest, parsed, max_prefixes * FLOOD_RETRY_PREFIX_LEN); return true; } - char tmp[96]; + char tmp[FLOOD_RETRY_LIST_TEXT_MAX]; StrHelper::strncpy(tmp, value, sizeof(tmp)); - const char* parts[FLOOD_RETRY_BUCKET_PREFIXES + 1]; - int num = mesh::Utils::parseTextParts(tmp, parts, FLOOD_RETRY_BUCKET_PREFIXES + 1); + const char* parts[FLOOD_RETRY_LIST_PREFIXES + 1]; + int num = mesh::Utils::parseTextParts(tmp, parts, FLOOD_RETRY_LIST_PREFIXES + 1); if (num > max_prefixes) { return false; } @@ -436,7 +427,11 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { file.read((uint8_t *)&_prefs->flood_retry_prefs_magic[0], sizeof(_prefs->flood_retry_prefs_magic)); // 302 file.read((uint8_t *)&_prefs->flood_retry_prefixes[0][0], sizeof(_prefs->flood_retry_prefixes)); // 304 file.read((uint8_t *)&_prefs->flood_retry_bridge_enabled, sizeof(_prefs->flood_retry_bridge_enabled)); // 328 + memset(_prefs->flood_retry_bridge_buckets, 0, sizeof(_prefs->flood_retry_bridge_buckets)); + memset(_prefs->flood_retry_ignore_prefixes, 0, sizeof(_prefs->flood_retry_ignore_prefixes)); file.read((uint8_t *)&_prefs->flood_retry_bridge_buckets[0][0][0], sizeof(_prefs->flood_retry_bridge_buckets)); // 329 + size_t flood_retry_ignore_read = file.read((uint8_t *)&_prefs->flood_retry_ignore_prefixes[0][0], + sizeof(_prefs->flood_retry_ignore_prefixes)); // 635 // PowerSaving-only prefs stored radio_fem_rxgain at 291, before direct retry timing existed. if (radio_fem_rxgain_read != sizeof(_prefs->radio_fem_rxgain) && legacy_retry_attempts_read == sizeof(legacy_retry_attempts_or_radio_fem_rxgain) @@ -444,7 +439,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { || _prefs->direct_retry_timing_magic[1] != DIRECT_RETRY_TIMING_MAGIC_1)) { _prefs->radio_fem_rxgain = constrain(legacy_retry_attempts_or_radio_fem_rxgain, 0, 1); } - // next: 473 + // next: 659 // sanitise bad pref values _prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f); @@ -505,12 +500,16 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { memset(_prefs->flood_retry_prefixes, 0, sizeof(_prefs->flood_retry_prefixes)); _prefs->flood_retry_bridge_enabled = 0; memset(_prefs->flood_retry_bridge_buckets, 0, sizeof(_prefs->flood_retry_bridge_buckets)); + memset(_prefs->flood_retry_ignore_prefixes, 0, sizeof(_prefs->flood_retry_ignore_prefixes)); } else { _prefs->flood_retry_attempts = constrain(_prefs->flood_retry_attempts, FLOOD_RETRY_COUNT_MIN, FLOOD_RETRY_COUNT_MAX); if (_prefs->flood_retry_path_gate > 63 && _prefs->flood_retry_path_gate != FLOOD_RETRY_PATH_GATE_DISABLED) { _prefs->flood_retry_path_gate = floodRetryPresetPathDefault(_prefs->direct_retry_preset); } _prefs->flood_retry_bridge_enabled = constrain(_prefs->flood_retry_bridge_enabled, 0, 1); + if (flood_retry_ignore_read != sizeof(_prefs->flood_retry_ignore_prefixes)) { + memset(_prefs->flood_retry_ignore_prefixes, 0, sizeof(_prefs->flood_retry_ignore_prefixes)); + } } file.close(); @@ -591,7 +590,8 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) { file.write((uint8_t *)&_prefs->flood_retry_prefixes[0][0], sizeof(_prefs->flood_retry_prefixes)); // 304 file.write((uint8_t *)&_prefs->flood_retry_bridge_enabled, sizeof(_prefs->flood_retry_bridge_enabled)); // 328 file.write((uint8_t *)&_prefs->flood_retry_bridge_buckets[0][0][0], sizeof(_prefs->flood_retry_bridge_buckets)); // 329 - // next: 473 + file.write((uint8_t *)&_prefs->flood_retry_ignore_prefixes[0][0], sizeof(_prefs->flood_retry_ignore_prefixes)); // 635 + // next: 659 file.close(); } @@ -756,6 +756,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re } else if (memcmp(config, "flood.retry.prefixes", 20) == 0) { formatFloodRetryPrefixes(tmp, _prefs); sprintf(reply, "> %s", tmp[0] ? tmp : "none"); + } else if (memcmp(config, "flood.retry.ignore", 18) == 0) { + formatFloodRetryPrefixList(tmp, _prefs->flood_retry_ignore_prefixes, FLOOD_RETRY_IGNORE_PREFIXES); + sprintf(reply, "> %s", tmp[0] ? tmp : "none"); } else if (memcmp(config, "flood.retry.bridge", 18) == 0) { sprintf(reply, "> %s", _prefs->flood_retry_bridge_enabled ? "on" : "off"); } else if (memcmp(config, "flood.retry.bucket.", 19) == 0) { @@ -1061,6 +1064,15 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re } else { strcpy(reply, "Error, use comma-separated 3-byte hex prefixes"); } + } else if (memcmp(config, "flood.retry.ignore ", 19) == 0) { + if (parseFloodRetryPrefixList(_prefs->flood_retry_ignore_prefixes, + FLOOD_RETRY_IGNORE_PREFIXES, &config[19])) { + savePrefs(); + strcpy(reply, "OK"); + } else { + sprintf(reply, "Error, use up to %u comma-separated 3-byte hex prefixes", + (unsigned int)FLOOD_RETRY_IGNORE_PREFIXES); + } } else if (memcmp(config, "flood.retry.bridge ", 19) == 0) { if (memcmp(&config[19], "on", 2) == 0) { _prefs->flood_retry_bridge_enabled = 1; @@ -1084,7 +1096,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re savePrefs(); strcpy(reply, "OK"); } else { - strcpy(reply, "Error, use up to 8 comma-separated 3-byte hex prefixes"); + sprintf(reply, "Error, use up to %u comma-separated 3-byte hex prefixes", + (unsigned int)FLOOD_RETRY_BUCKET_PREFIXES); } } else if (memcmp(config, "direct.txdelay ", 15) == 0) { float f = atof(&config[15]); @@ -1674,6 +1687,15 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep } else { strcpy(reply, "Error, use comma-separated 3-byte hex prefixes"); } + } else if (memcmp(config, "flood.retry.ignore ", 19) == 0) { + if (parseFloodRetryPrefixList(_prefs->flood_retry_ignore_prefixes, + FLOOD_RETRY_IGNORE_PREFIXES, &config[19])) { + savePrefs(); + strcpy(reply, "OK"); + } else { + sprintf(reply, "Error, use up to %u comma-separated 3-byte hex prefixes", + (unsigned int)FLOOD_RETRY_IGNORE_PREFIXES); + } } else if (memcmp(config, "flood.retry.bridge ", 19) == 0) { if (memcmp(&config[19], "on", 2) == 0) { _prefs->flood_retry_bridge_enabled = 1; @@ -1697,7 +1719,8 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep savePrefs(); strcpy(reply, "OK"); } else { - strcpy(reply, "Error, use up to 8 comma-separated 3-byte hex prefixes"); + sprintf(reply, "Error, use up to %u comma-separated 3-byte hex prefixes", + (unsigned int)FLOOD_RETRY_BUCKET_PREFIXES); } } else if (memcmp(config, "direct.txdelay ", 15) == 0) { float f = atof(&config[15]); @@ -1947,6 +1970,9 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep } else if (memcmp(config, "flood.retry.prefixes", 20) == 0) { formatFloodRetryPrefixes(tmp, _prefs); sprintf(reply, "> %s", tmp[0] ? tmp : "none"); + } else if (memcmp(config, "flood.retry.ignore", 18) == 0) { + formatFloodRetryPrefixList(tmp, _prefs->flood_retry_ignore_prefixes, FLOOD_RETRY_IGNORE_PREFIXES); + sprintf(reply, "> %s", tmp[0] ? tmp : "none"); } else if (memcmp(config, "flood.retry.bridge", 18) == 0) { sprintf(reply, "> %s", _prefs->flood_retry_bridge_enabled ? "on" : "off"); } else if (memcmp(config, "flood.retry.bucket.", 19) == 0) { diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 321c3c8f..40806d49 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -48,7 +48,19 @@ #define FLOOD_RETRY_BRIDGE_BUCKETS 6 #endif #ifndef FLOOD_RETRY_BUCKET_PREFIXES - #define FLOOD_RETRY_BUCKET_PREFIXES 8 + #define FLOOD_RETRY_BUCKET_PREFIXES 17 +#endif +#ifndef FLOOD_RETRY_IGNORE_PREFIXES + #define FLOOD_RETRY_IGNORE_PREFIXES 8 +#endif +#ifndef FLOOD_RETRY_LIST_PREFIXES + #define FLOOD_RETRY_LIST_PREFIXES ((FLOOD_RETRY_IGNORE_PREFIXES > FLOOD_RETRY_BUCKET_PREFIXES) ? FLOOD_RETRY_IGNORE_PREFIXES : FLOOD_RETRY_BUCKET_PREFIXES) +#endif +#ifndef FLOOD_RETRY_LIST_TEXT_MAX + #define FLOOD_RETRY_LIST_TEXT_MAX (FLOOD_RETRY_LIST_PREFIXES * FLOOD_RETRY_PREFIX_LEN * 2 + FLOOD_RETRY_LIST_PREFIXES) +#endif +#ifndef COMMON_CLI_TMP_LEN + #define COMMON_CLI_TMP_LEN ((FLOOD_RETRY_LIST_TEXT_MAX > (PRV_KEY_SIZE * 2 + 4)) ? FLOOD_RETRY_LIST_TEXT_MAX : (PRV_KEY_SIZE * 2 + 4)) #endif struct NodePrefs { // persisted to file @@ -107,6 +119,7 @@ struct NodePrefs { // persisted to file uint8_t flood_retry_prefixes[FLOOD_RETRY_PREFIX_SLOTS][FLOOD_RETRY_PREFIX_LEN]; uint8_t flood_retry_bridge_enabled; uint8_t flood_retry_bridge_buckets[FLOOD_RETRY_BRIDGE_BUCKETS][FLOOD_RETRY_BUCKET_PREFIXES][FLOOD_RETRY_PREFIX_LEN]; + uint8_t flood_retry_ignore_prefixes[FLOOD_RETRY_IGNORE_PREFIXES][FLOOD_RETRY_PREFIX_LEN]; }; class CommonCLICallbacks { @@ -166,7 +179,7 @@ class CommonCLI { SensorManager* _sensors; RegionMap* _region_map; ClientACL* _acl; - char tmp[PRV_KEY_SIZE*2 + 4]; + char tmp[COMMON_CLI_TMP_LEN]; mesh::RTCClock* getRTCClock() { return _rtc; } void savePrefs(); diff --git a/src/helpers/SimpleMeshTables.h b/src/helpers/SimpleMeshTables.h index ca81b144..2d2125dd 100644 --- a/src/helpers/SimpleMeshTables.h +++ b/src/helpers/SimpleMeshTables.h @@ -175,8 +175,6 @@ public: f.write((const uint8_t *) &_next_idx, sizeof(_next_idx)); f.write((const uint8_t *) &_acks[0], sizeof(_acks)); f.write((const uint8_t *) &_next_ack_idx, sizeof(_next_ack_idx)); - f.write((const uint8_t *) &_recent_repeaters[0], sizeof(_recent_repeaters)); - f.write((const uint8_t *) &_next_recent_repeater_idx, sizeof(_next_recent_repeater_idx)); } #endif