Tune repeater flood controls and retries

This commit is contained in:
mikecarper
2026-07-07 00:47:19 -07:00
parent 220d44000e
commit 0613b2dcc2
8 changed files with 121 additions and 25 deletions
+39 -14
View File
@@ -531,7 +531,7 @@ send text.flood checking ridge link
**Parameters:**
- `state`: `on`|`off`
**Default:** `on`
**Default:** `flood.channel.data on`; `flood.channel.data.hops h=all`
---
@@ -771,19 +771,28 @@ send text.flood checking ridge link
#### Forward flood group data packets on repeaters
**Usage:**
- `get flood.channel.data`
- `get flood.channel.data.hops`
- `set flood.channel.data <on|off>`
- `set flood.channel.data.hops <all|1-7>`
**Parameters:**
- `on`: Retransmit received flood `GRP_DATA` channel packets.
- `off`: Do not retransmit received flood `GRP_DATA` channel packets.
- `all`: When `flood.channel.data` is `off`, block `GRP_DATA` at any received flood hop count.
- `1-7`: When `flood.channel.data` is `off`, repeat `GRP_DATA` at this hop count or lower and block longer paths.
**Default:** `on`
**Default:** `flood.channel.data on`; `flood.channel.data.hops h=all`
**Forwarding behavior:** Repeater firmware only. The repeater still receives and
logs the packet when logging is enabled; this only blocks retransmission.
This is checked before `flood.channel.block` and applies to flood `GRP_DATA`
packets regardless of channel key, subject to `flood.channel.block.hops`.
Flood group text (`GRP_TXT`) is unaffected by this setting.
packets regardless of channel key. Flood group text (`GRP_TXT`) is unaffected by
this setting.
`flood.channel.data.hops` is separate from `flood.channel.block.hops`.
`flood.channel.block.hops` does not restrict unkeyed `GRP_DATA` packets. With
the default `flood.channel.data on`, `GRP_DATA` repeats normally even when
`flood.channel.block.hops` is set for keyed channel blocks.
`get flood.channel.data` includes the active hop gate as `h=all` or `h>N`.
@@ -818,22 +827,29 @@ row with the same derived channel prefix or name, otherwise it uses the next
empty slot. If all 15 slots are full, the command fails. With `.n`, the command
writes that slot.
**Default row:** Repeater firmware seeds a new block list with
`#wardriving h=4` in slot 1. This is a normal row, so it can be changed with
`set flood.channel.block #wardriving h=<all|1-7|default>` or removed with
`del flood.channel.block #wardriving`. Once the block list has been saved, the
firmware uses the saved list and does not recreate the default after deletion.
**Forwarding behavior:** Repeater firmware only. This only affects received
flood `GRP_TXT` and `GRP_DATA` channel packets. The repeater still receives and
logs the packet, but it does not retransmit it when a configured block entry can
validate/decode it. If `flood.channel.data` is `off`, all flood `GRP_DATA`
packets over the hop gate are blocked before this per-channel check runs.
validate/decode it. If `flood.channel.data` is `off`, `GRP_DATA` packets are
checked against the separate `flood.channel.data.hops` gate before this
per-channel check runs.
**Hop gate:** `flood.channel.block.hops` defaults to `all`, which preserves the
original behavior. When set to `N` from `1` to `7`, both `flood.channel.data off`
and block rows that inherit the global setting only block packets whose received
flood path hash count is greater than `N`; packets at `N` hops or lower can
still repeat. For example, `set flood.channel.block.hops 1` repeats zero-hop and
one-hop matches but blocks two-hop and longer matches.
original behavior. When set to `N` from `1` to `7`, block rows that inherit the
global setting only block packets whose received flood path hash count is
greater than `N`; packets at `N` hops or lower can still repeat. For example,
`set flood.channel.block.hops 1` repeats zero-hop and one-hop matches but blocks
two-hop and longer matches.
Each block row can override the global hop gate with `h=<all|1-7|default>`.
For example, `set flood.channel.block #wardriving h=3` blocks `#wardriving`
matches above three hops, while `set flood.channel.block #bot h=7` blocks
For example, the seeded `#wardriving h=4` row blocks `#wardriving` matches
above four hops, while `set flood.channel.block #bot h=7` blocks
`#bot` matches above seven hops. Use `h=default` to make the row inherit the
global setting again.
@@ -856,7 +872,7 @@ MAC/decrypt.
set flood.channel.block #test
set flood.channel.block.2 9cd8fcf22a47333b591d96a2b848b73f #test
set flood.channel.block.hops 3
set flood.channel.block #wardriving h=3
set flood.channel.block #wardriving h=4
set flood.channel.block #bot h=7
get flood.channel.block
get flood.channel.block.hops
@@ -1383,6 +1399,9 @@ set flood.retry.bucket 2 none
**Default:** `15` with the `rooftop` preset
**Note:** Direct-routed type 2 text packets always use 21 retry attempts,
regardless of this setting or the short-path cap.
**Examples:**
```
get direct.retry.count
@@ -1405,6 +1424,9 @@ set direct.retry.count 15
**Explanation:**
- The first retry waits `base` milliseconds after the failed echo window.
- The failed echo window includes a packet-length add-on. TRACE and
ANON_REQ/type 7 packets keep the existing 4x line-time add-on. TXT_MSG/type 2
packets use 7x. Other direct retry packets use 6x.
- For non-TRACE direct paths shorter than 6 remaining hops, the effective wait is scaled by `hops / 6`.
- Non-TRACE direct paths with 6 or more remaining hops use the configured value unchanged.
- TRACE retries shorter than 16 remaining hops use `hops / 16`; 16 or more remaining hops use the configured value unchanged.
@@ -1433,6 +1455,9 @@ set direct.retry.base 500
**Explanation:**
- Retry delay is `base + attempt_index * step`.
- This is added after the failed echo window. TRACE and ANON_REQ/type 7 packets
keep the existing 4x packet-length add-on. TXT_MSG/type 2 packets use 7x.
Other direct retry packets use 6x.
- For non-TRACE direct paths shorter than 6 remaining hops, that computed delay is scaled by `hops / 6`.
- Non-TRACE direct paths with 6 or more remaining hops use the computed delay unchanged.
- TRACE retries shorter than 16 remaining hops use `hops / 16`; 16 or more remaining hops use the computed delay unchanged.
+6 -5
View File
@@ -77,9 +77,10 @@ set flood.retry.ignore none
| `battery.alert.low` | Warning threshold percentage. Must be greater than `battery.alert.critical`. | `get battery.alert.low`, `set battery.alert.low <1-100>` | `set battery.alert.low 20` |
| `battery.alert.critical` | Critical threshold percentage. Critical warnings repeat more often. | `get battery.alert.critical`, `set battery.alert.critical <0-99>` | `set battery.alert.critical 10` |
| `recent.repeater` | Shows, seeds, or clears the recent repeater prefix/SNR table used by direct retry and bridge freshness checks. | `get recent.repeater`, `get recent.repeater <page>`, `set recent.repeater <prefix> <snr_db>`, `clear recent.repeater` | `set recent.repeater A1B2C3 -8.5` |
| `flood.channel.data` | Turns forwarding of flood `GRP_DATA` channel packets on or off, subject to the channel block hop gate. | `get flood.channel.data`, `set flood.channel.data on/off` | `set flood.channel.data off` |
| `flood.channel.block` | Blocks selected flood `GRP_TXT`/`GRP_DATA` channels when the key validates the packet. Add `h=<all|1-7|default>` for a per-channel hop override. | `get flood.channel.block`, `set flood.channel.block[.n] <key|#channel> [name] [h=...]`, `del flood.channel.block[.n]` | `set flood.channel.block #wardriving h=3` |
| `flood.channel.block.hops` | Limits channel/data forwarding to short flood paths. `all` blocks matching packets at any hop count; `1`-`7` repeats packets at that hop count or lower and blocks longer matches. | `get flood.channel.block.hops`, `set flood.channel.block.hops <all|1-7>` | `set flood.channel.block.hops 3` |
| `flood.channel.data` | Turns forwarding of flood `GRP_DATA` channel packets on or off. With the default `on`, `GRP_DATA` repeats normally even when `flood.channel.block.hops` is set. | `get flood.channel.data`, `set flood.channel.data on/off` | `set flood.channel.data off` |
| `flood.channel.data.hops` | Separate hop gate used only when `flood.channel.data` is `off`; `all` blocks `GRP_DATA` at any hop count, `1`-`7` repeats at that hop count or lower and blocks longer paths. | `get flood.channel.data.hops`, `set flood.channel.data.hops <all|1-7>` | `set flood.channel.data.hops 7` |
| `flood.channel.block` | Blocks selected flood `GRP_TXT`/`GRP_DATA` channels when the key validates the packet. New repeater block lists start with editable/deletable `#wardriving h=4`. Add `h=<all|1-7|default>` for a per-channel hop override. | `get flood.channel.block`, `set flood.channel.block[.n] <key|#channel> [name] [h=...]`, `del flood.channel.block[.n]` | `set flood.channel.block #wardriving h=4` |
| `flood.channel.block.hops` | Limits keyed channel-block matches to short flood paths. `all` blocks matching packets at any hop count; `1`-`7` repeats packets at that hop count or lower and blocks longer matches. This does not restrict unkeyed `GRP_DATA`; use `flood.channel.data.hops` for that. | `get flood.channel.block.hops`, `set flood.channel.block.hops <all|1-7>` | `set flood.channel.block.hops 3` |
| `outpath` | Overrides the primary direct route used for replies to the current remote client. | `get outpath`, `set outpath <hops>`, `set outpath direct`, `set outpath clear`, `set outpath flood` | `set outpath A1B2C3,D4E5F6` |
| `altpath` | Adds a secondary direct route for repeater replies to the current remote client. | `get altpath`, `set altpath <hops>`, `set altpath direct`, `set altpath clear`, `set altpath flood` | `set altpath 71CE82,BA09F0` |
@@ -189,8 +190,8 @@ Direct retry applies to direct-routed packets. A queued resend is canceled when
| `retry.preset` | Applies shared direct and flood retry defaults. Values: `infra`, `rooftop`, `mobile` or `0`, `1`, `2`. | `get retry.preset`, `set retry.preset <value>` | `set retry.preset rooftop` |
| `direct.retry.heard` | Uses the recent repeater table as the direct retry eligibility gate. | `get direct.retry.heard`, `set direct.retry.heard on/off` | `set direct.retry.heard on` |
| `direct.retry.margin` | SNR margin in dB above the SF-specific receive floor. | `get direct.retry.margin`, `set direct.retry.margin <0-40>` | `set direct.retry.margin 5` |
| `direct.retry.count` | Maximum direct retry attempts after initial TX. | `get direct.retry.count`, `set direct.retry.count <1-15>` | `set direct.retry.count 15` |
| `direct.retry.base` | Base wait in milliseconds before retry; non-TRACE paths under 6 remaining hops scale by `hops / 6`, TRACE paths under 16 by `hops / 16`. | `get direct.retry.base`, `set direct.retry.base <10-5000>` | `set direct.retry.base 175` |
| `direct.retry.count` | Maximum direct retry attempts after initial TX. Direct-routed type 2 text packets always use 21 attempts regardless of this setting or the short-path cap. | `get direct.retry.count`, `set direct.retry.count <1-15>` | `set direct.retry.count 15` |
| `direct.retry.base` | Base wait in milliseconds before retry; packet-length add-on is 4x for TRACE and ANON_REQ/type 7, 7x for TXT_MSG/type 2, and 6x for other direct retry packets. Non-TRACE paths under 6 remaining hops scale by `hops / 6`, TRACE paths under 16 by `hops / 16`. | `get direct.retry.base`, `set direct.retry.base <10-5000>` | `set direct.retry.base 175` |
| `direct.retry.step` | Milliseconds added per retry attempt before the same short-path scaling. | `get direct.retry.step`, `set direct.retry.step <0-5000>` | `set direct.retry.step 100` |
| `direct.retry.cr` | Adaptive coding-rate thresholds for repeater direct retry packets. Repeaters use `CR4`, `CR5`, `CR7`, or `CR8`, then escalate by attempt: CR4, CR5, CR7, CR7, then CR8 from a CR4 start; CR5, CR7, CR7, then CR8 from a CR5 start. Non-repeaters start at the current radio CR and follow the same escalation pattern, clamped at CR8. | `get direct.retry.cr`, `set direct.retry.cr <cr4_min>,<cr5_min>,<cr7_min>,<cr8_max>`, `set direct.retry.cr off` | `set direct.retry.cr 10.0,7.5,2.5,0` |
+46 -3
View File
@@ -83,6 +83,10 @@
#define LAZY_CONTACTS_WRITE_DELAY 5000
#define FLOOD_CHANNEL_BLOCK_FILE "/flood_ch_block"
#define DEFAULT_FLOOD_CHANNEL_BLOCK_NAME "#wardriving"
#ifndef DEFAULT_FLOOD_CHANNEL_BLOCK_HOPS
#define DEFAULT_FLOOD_CHANNEL_BLOCK_HOPS 4
#endif
#ifndef REPEATERS_CHANNEL_KEY_HEX
#define REPEATERS_CHANNEL_KEY_HEX "89db441e2814dccf0dbd2e8cc5f501a3"
@@ -675,6 +679,14 @@ bool MyMesh::floodChannelBlockHopApplies(const mesh::Packet* packet, uint8_t max
return max_hops == FLOOD_CHANNEL_BLOCK_HOPS_ALL || packet->getPathHashCount() > max_hops;
}
bool MyMesh::floodChannelDataHopApplies(const mesh::Packet* packet) const {
if (packet == NULL) {
return false;
}
uint8_t max_hops = _prefs.flood_channel_data_max_hops;
return max_hops == FLOOD_CHANNEL_BLOCK_HOPS_ALL || packet->getPathHashCount() > max_hops;
}
bool MyMesh::floodChannelBlockMatches(const FloodChannelBlockEntry& entry, const mesh::Packet* packet) const {
if (!entry.active || packet == NULL || !packet->isRouteFlood()) {
return false;
@@ -715,7 +727,7 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->getPathHashCount() >= _prefs.flood_max_advert) return false;
if (!_prefs.flood_channel_data_enabled
&& packet->getPayloadType() == PAYLOAD_TYPE_GRP_DATA
&& floodChannelBlockHopApplies(packet, _prefs.flood_channel_block_max_hops)) {
&& floodChannelDataHopApplies(packet)) {
MESH_DEBUG_PRINTLN("allowPacketForward: flood.channel.data off, blocking GRP_DATA hops=%d",
packet->getPathHashCount());
return false;
@@ -992,7 +1004,14 @@ uint32_t MyMesh::getDirectRetryEchoDelay(const mesh::Packet* packet) const {
// Wait roughly long enough for our TX, the next hop's receive/forward window, and its echo back.
uint32_t bits = ((uint32_t)packet->getRawLength()) * 8;
uint32_t scaled_wait_millis = (uint32_t)((((float)bits) * 4.0f) / kbps);
uint8_t payload_type = packet->getPayloadType();
float length_factor = 6.0f;
if (payload_type == PAYLOAD_TYPE_TRACE || payload_type == PAYLOAD_TYPE_ANON_REQ) {
length_factor = 4.0f;
} else if (payload_type == PAYLOAD_TYPE_TXT_MSG) {
length_factor = 7.0f;
}
uint32_t scaled_wait_millis = (uint32_t)((((float)bits) * length_factor) / kbps);
return base_wait_millis + scaled_wait_millis;
}
@@ -1011,6 +1030,10 @@ static uint8_t decodeDirectRetryTraceHashSize(uint8_t flags, uint8_t route_bytes
}
uint8_t MyMesh::getDirectRetryMaxAttempts(const mesh::Packet* packet) const {
if (packet != NULL && packet->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) {
return 21;
}
uint8_t configured_attempts = getDirectRetryConfiguredMaxAttempts();
uint8_t total_hops = 0;
@@ -2212,6 +2235,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.flood_retry_advert_enabled = FLOOD_RETRY_ADVERT_DEFAULT;
_prefs.flood_channel_data_enabled = 1;
_prefs.flood_channel_block_max_hops = FLOOD_CHANNEL_BLOCK_HOPS_ALL;
_prefs.flood_channel_data_max_hops = FLOOD_CHANNEL_BLOCK_HOPS_ALL;
_prefs.battery_alert_enabled = 0;
_prefs.battery_alert_low_percent = BATTERY_ALERT_LOW_PERCENT_DEFAULT;
_prefs.battery_alert_critical_percent = BATTERY_ALERT_CRITICAL_PERCENT_DEFAULT;
@@ -3037,9 +3061,28 @@ void MyMesh::deriveFloodChannelBlockPrefix(const uint8_t* secret, uint8_t key_le
mesh::Utils::sha256(prefix, FLOOD_CHANNEL_BLOCK_PREFIX_LEN, secret, key_len);
}
void MyMesh::seedDefaultFloodChannelBlocks() {
auto& entry = flood_channel_blocks[0];
clearFloodChannelBlockEntry(entry);
entry.active = true;
entry.key_len = CIPHER_KEY_SIZE;
entry.max_hops = DEFAULT_FLOOD_CHANNEL_BLOCK_HOPS;
mesh::Utils::sha256(entry.secret, CIPHER_KEY_SIZE,
(const uint8_t*)DEFAULT_FLOOD_CHANNEL_BLOCK_NAME,
strlen(DEFAULT_FLOOD_CHANNEL_BLOCK_NAME));
memset(&entry.secret[CIPHER_KEY_SIZE], 0, PUB_KEY_SIZE - CIPHER_KEY_SIZE);
deriveFloodChannelBlockPrefix(entry.secret, entry.key_len, entry.hash_prefix);
StrHelper::strncpy(entry.name, DEFAULT_FLOOD_CHANNEL_BLOCK_NAME, sizeof(entry.name));
}
void MyMesh::loadFloodChannelBlocks() {
memset(flood_channel_blocks, 0, sizeof(flood_channel_blocks));
if (_fs == NULL || !_fs->exists(FLOOD_CHANNEL_BLOCK_FILE)) {
if (_fs == NULL) {
return;
}
if (!_fs->exists(FLOOD_CHANNEL_BLOCK_FILE)) {
seedDefaultFloodChannelBlocks();
saveFloodChannelBlocks();
return;
}
+2
View File
@@ -204,11 +204,13 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
bool isMillisTimerDue(unsigned long timestamp) const;
void loadFloodChannelBlocks();
bool saveFloodChannelBlocks();
void seedDefaultFloodChannelBlocks();
void clearFloodChannelBlockEntry(FloodChannelBlockEntry& entry);
void deriveFloodChannelBlockPrefix(const uint8_t* secret, uint8_t key_len,
uint8_t prefix[FLOOD_CHANNEL_BLOCK_PREFIX_LEN]) const;
uint8_t resolveFloodChannelBlockHops(uint8_t max_hops) const;
bool floodChannelBlockHopApplies(const mesh::Packet* packet, uint8_t max_hops) const;
bool floodChannelDataHopApplies(const mesh::Packet* packet) const;
bool floodChannelBlockMatches(const FloodChannelBlockEntry& entry, const mesh::Packet* packet) const;
bool shouldBlockFloodChannelForward(const mesh::Packet* packet) const;
int findFloodChannelBlockBySelector(const char* selector) const;
+1 -1
View File
@@ -4,7 +4,7 @@
namespace mesh {
static const uint8_t DIRECT_RETRY_MAX_ATTEMPTS_DEFAULT = 15;
static const uint8_t DIRECT_RETRY_MAX_ATTEMPTS_HARD_MAX = 15;
static const uint8_t DIRECT_RETRY_MAX_ATTEMPTS_HARD_MAX = 21;
static const uint8_t FLOOD_RETRY_MAX_ATTEMPTS_DEFAULT = 15;
static const uint8_t FLOOD_RETRY_MAX_ATTEMPTS_HARD_MAX = 15;
static const uint8_t FLOOD_RETRY_MAX_PATH_DEFAULT = 1;
+24 -2
View File
@@ -704,6 +704,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
_prefs->direct_retry_recent_enabled = DIRECT_RETRY_RECENT_DEFAULT;
_prefs->flood_channel_data_enabled = 1;
_prefs->flood_channel_block_max_hops = FLOOD_CHANNEL_BLOCK_HOPS_ALL;
_prefs->flood_channel_data_max_hops = FLOOD_CHANNEL_BLOCK_HOPS_ALL;
bool has_flood_retry_prefs = file.available() >= 2;
if (has_flood_retry_prefs) {
file.read((uint8_t *)&_prefs->flood_retry_attempts, sizeof(_prefs->flood_retry_attempts)); // 311
@@ -741,6 +742,9 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
if (file.available() >= (int)sizeof(_prefs->flood_channel_block_max_hops)) {
file.read((uint8_t *)&_prefs->flood_channel_block_max_hops, sizeof(_prefs->flood_channel_block_max_hops));
}
if (file.available() >= (int)sizeof(_prefs->flood_channel_data_max_hops)) {
file.read((uint8_t *)&_prefs->flood_channel_data_max_hops, sizeof(_prefs->flood_channel_data_max_hops));
}
}
// next: 674
@@ -807,6 +811,10 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
&& (_prefs->flood_channel_block_max_hops < 1 || _prefs->flood_channel_block_max_hops > 7)) {
_prefs->flood_channel_block_max_hops = FLOOD_CHANNEL_BLOCK_HOPS_ALL;
}
if (_prefs->flood_channel_data_max_hops != FLOOD_CHANNEL_BLOCK_HOPS_ALL
&& (_prefs->flood_channel_data_max_hops < 1 || _prefs->flood_channel_data_max_hops > 7)) {
_prefs->flood_channel_data_max_hops = FLOOD_CHANNEL_BLOCK_HOPS_ALL;
}
if (_prefs->battery_alert_low_percent < 1
|| _prefs->battery_alert_low_percent > 100
|| _prefs->battery_alert_critical_percent >= _prefs->battery_alert_low_percent) {
@@ -906,6 +914,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
file.write((uint8_t *)&_prefs->direct_retry_recent_enabled, sizeof(_prefs->direct_retry_recent_enabled));
file.write((uint8_t *)&_prefs->flood_channel_data_enabled, sizeof(_prefs->flood_channel_data_enabled));
file.write((uint8_t *)&_prefs->flood_channel_block_max_hops, sizeof(_prefs->flood_channel_block_max_hops));
file.write((uint8_t *)&_prefs->flood_channel_data_max_hops, sizeof(_prefs->flood_channel_data_max_hops));
// next: 674
file.close();
@@ -1550,6 +1559,15 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
} else {
strcpy(reply, "Error, must be 0-5000 ms");
}
} else if (memcmp(config, "flood.channel.data.hops ", 24) == 0) {
uint8_t max_hops;
if (parseFloodChannelBlockHops(&config[24], max_hops)) {
_prefs->flood_channel_data_max_hops = max_hops;
savePrefs();
strcpy(reply, "OK");
} else {
strcpy(reply, "Error, must be all or 1-7");
}
} else if (memcmp(config, "flood.channel.data ", 19) == 0) {
if (strcmp(&config[19], "on") == 0) {
_prefs->flood_channel_data_enabled = 1;
@@ -1940,9 +1958,13 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->rx_delay_base));
} else if (memcmp(config, "txdelay", 7) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->tx_delay_factor));
} else if (memcmp(config, "flood.channel.data", 18) == 0) {
} else if (strcmp(config, "flood.channel.data.hops") == 0) {
char hops[8];
formatFloodChannelBlockHops(hops, _prefs->flood_channel_block_max_hops);
formatFloodChannelBlockHops(hops, _prefs->flood_channel_data_max_hops);
sprintf(reply, "> %s", hops);
} else if (strcmp(config, "flood.channel.data") == 0) {
char hops[8];
formatFloodChannelBlockHops(hops, _prefs->flood_channel_data_max_hops);
sprintf(reply, "> %s %s", _prefs->flood_channel_data_enabled ? "on" : "off", hops);
} else if (memcmp(config, "flood.channel.block.hops", 24) == 0) {
char hops[8];
+1
View File
@@ -170,6 +170,7 @@ struct NodePrefs { // persisted to file
uint8_t direct_retry_recent_enabled;
uint8_t flood_channel_data_enabled;
uint8_t flood_channel_block_max_hops;
uint8_t flood_channel_data_max_hops;
};
class CommonCLICallbacks {
+2
View File
@@ -28,6 +28,8 @@ build_src_filter = ${lora_e5.build_src_filter}
[env:wio-e5-repeater_bridge_rs232]
extends = lora_e5
build_flags = ${lora_e5.build_flags}
-flto
-D MESH_ENABLE_RECENT_REPEATERS=1
-D LORA_TX_POWER=22
-D ADVERT_NAME='"WIO-E5 Repeater"'
-D ADMIN_PASSWORD='"password"'