Improve flood retry bridge buckets

This commit is contained in:
mikecarper
2026-05-08 00:50:17 -07:00
parent 4e1002029c
commit 3a6766b0fd
7 changed files with 183 additions and 63 deletions
Regular → Executable
+12 -11
View File
@@ -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 \
+16 -2
View File
@@ -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 <prefixes>`
**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
+77 -15
View File
@@ -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()) {
+8 -2
View File
@@ -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);
+55 -29
View File
@@ -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) {
+15 -2
View File
@@ -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();
-2
View File
@@ -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