Unify retry preset settings

This commit is contained in:
mikecarper committed 2026-05-08 10:53:21 -07:00
1 parent ae67293bcc
commit b475bde730
5 files changed
+437 -125

No files matched your search

+21 -24
View File
@@ -570,10 +570,10 @@ This document provides an overview of CLI commands that can be sent to MeshCore
---
#### View or change the direct retry timing preset
#### View or change the retry preset
**Usage:**
- `get direct.retry.preset`
- `set direct.retry.preset <value>`
- `get retry.preset`
- `set retry.preset <value>`
**Parameters:**
- `value`: `infra`|`rooftop`|`mobile` or `0`|`1`|`2`
@@ -581,11 +581,11 @@ This document provides an overview of CLI commands that can be sent to MeshCore
**Default:** `rooftop` (`1`)
**Presets:**
- `infra` (`0`): `275 ms` base wait, `4` retries, `150 ms` added per retry, SNR gate is SF floor + `15 dB`
- `rooftop` (`1`): `175 ms` base wait, `15` retries, `100 ms` added per retry, SNR gate is SF floor + `5 dB`
- `mobile` (`2`): `175 ms` base wait, `15` retries, `50 ms` added per retry, SNR gate is the SF floor
- `infra` (`0`): `275 ms` direct base wait, `4` direct retries, `150 ms` added per direct retry, SNR gate is SF floor + `15 dB`; flood retry defaults to `1` retry and path gate `1`
- `rooftop` (`1`): `175 ms` direct base wait, `15` direct retries, `100 ms` added per direct retry, SNR gate is SF floor + `5 dB`; flood retry defaults to `3` retries and path gate `2`
- `mobile` (`2`): `175 ms` direct base wait, `15` direct retries, `50 ms` added per direct retry, SNR gate is the SF floor; flood retry defaults to `3` retries and path gate `1`
**Note:** Selecting a preset copies those values into the direct retry settings and also resets flood retry defaults. You can refine `direct.retry.margin`, `direct.retry.count`, `direct.retry.base`, `direct.retry.step`, `flood.retry.count`, or `flood.retry.path` afterward. Retry delay is `direct.txdelay` jitter + base wait + packet-length airtime wait + per-attempt step.
**Note:** Selecting a preset copies those values into the direct retry settings and resets flood retry defaults. You can refine `direct.retry.margin`, `direct.retry.count`, `direct.retry.base`, `direct.retry.step`, `flood.retry.count`, or `flood.retry.path` afterward. Retry delay is `direct.txdelay` jitter + base wait + packet-length airtime wait + per-attempt step.
---
@@ -754,23 +754,6 @@ This document provides an overview of CLI commands that can be sent to MeshCore
---
#### View or change the flood retry preset
**Usage:**
- `get flood.retry.preset`
- `set flood.retry.preset <value>`
**Parameters:**
- `value`: `infra`|`rooftop`|`mobile` or `0`|`1`|`2`
**Presets:**
- `infra` (`0`): `1` retry, path gate `1`
- `rooftop` (`1`): `3` retries, path gate `2`
- `mobile` (`2`): `3` retries, path gate `1`
**Note:** This applies only the flood retry defaults. `set direct.retry.preset` also resets these flood retry defaults.
---
#### View or change the number of flood retry attempts
**Usage:**
- `get flood.retry.count`
@@ -797,6 +780,20 @@ This document provides an overview of CLI commands that can be sent to MeshCore
---
#### View or change whether advert packets are flood-retried
**Usage:**
- `get flood.retry.advert`
- `set flood.retry.advert <state>`
**Parameters:**
- `state`: `on` or `off`
**Default:** `off`
**Note:** When this is `off`, node advert packets (`PAYLOAD_TYPE_ADVERT`, type `4`) are not queued for flood retry.
---
#### View or change flood retry target prefixes
**Usage:**
- `get flood.retry.prefixes`
+308
View File
@@ -0,0 +1,308 @@
# Halo and Keymind Branch Settings
This file covers only CLI settings added by the Halo or Keymind branches. Use
`docs/cli_commands.md` for the general MeshCore CLI.
## Quick Start
Use this baseline when bringing a Halo or Keymind repeater onto the network:
```text
set retry.preset rooftop
set direct.retry.heard on
set flood.retry.advert off
set flood.retry.bridge off
set flood.retry.prefixes none
set flood.retry.ignore none
```
Then verify:
```text
get retry.preset
get direct.retry.heard
get flood.retry.advert
get flood.retry.prefixes
get flood.retry.ignore
```
Use prefixes from debug logs such as `path=7773D0>BEEBB0` or `heard=C7618C`. Prefix lists are comma-separated hex values, for example `71CE82,C7618C`.
## Prefix Worksheet
Keep Halo and Keymind prefixes in one place before programming buckets or ignore lists.
| Network | Prefix | Node or site | Use | Notes |
| --- | --- | --- | --- | --- |
| Halo | `A1B2C3` | example remote relay | bucket/target | Replace with real prefix |
| Keymind | `71CE82` | example observed relay | ignore/target | Replace with real prefix |
| Keymind | `C7618C` | example observed relay | ignore/target | Replace with real prefix |
## Common Examples
Disable retrying advert packets:
```text
set flood.retry.advert off
get flood.retry.advert
```
Ignore a relay as a successful flood retry echo:
```text
set flood.retry.ignore 71CE82,C7618C
get flood.retry.ignore
```
Only accept specific downstream relays as flood retry success:
```text
set flood.retry.prefixes BEEBB0,425E5C
get flood.retry.prefixes
```
Bridge two groups of repeaters:
```text
set flood.retry.bridge on
set flood.retry.bucket 1 71CE82,C7618C
set flood.retry.bucket 2 BEEBB0,425E5C
get flood.retry.bucket.1
get flood.retry.bucket.2
```
Return to simple non-bridge flood retry:
```text
set flood.retry.bridge off
set flood.retry.prefixes none
set flood.retry.ignore none
```
## Added Settings
| Setting | What it does | How to use | Example |
| --- | --- | --- | --- |
| `recent.repeater` | Shows or seeds 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>` | `set recent.repeater A1B2C3 -8.5` |
| `radio.fem.rxgain` | Controls the external LoRa FEM receive-path LNA where the board supports it. | `get radio.fem.rxgain`, `set radio.fem.rxgain on/off` | `set radio.fem.rxgain on` |
## Recent Repeater Table
Direct retry uses the recent repeater table when `direct.retry.heard` is `on`.
Bridge buckets also use this table: a configured bucket prefix is active only
when it was heard within the last hour.
Show learned rows:
```text
get recent.repeater
get recent.repeater 2
```
Seed or correct a prefix:
```text
set recent.repeater A1B2C3 -8.5
```
Rows are sorted by prefix width, then SNR. A full direct retry failure lowers
the matching row by `0.25 dB`.
## Direct Retry Settings
Direct retry applies to direct-routed packets. A queued resend is canceled when the next-hop echo is heard.
| Setting | What it does | How to use | Example |
| --- | --- | --- | --- |
| `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. | `get direct.retry.base`, `set direct.retry.base <10-5000>` | `set direct.retry.base 175` |
| `direct.retry.step` | Milliseconds added per retry attempt. | `get direct.retry.step`, `set direct.retry.step <0-5000>` | `set direct.retry.step 100` |
Preset details:
| Preset | Base | Count | Step | SNR gate |
| --- | ---: | ---: | ---: | --- |
| `infra` | `275 ms` | `4` | `150 ms` | SF floor + `15 dB` |
| `rooftop` | `175 ms` | `15` | `100 ms` | SF floor + `5 dB` |
| `mobile` | `175 ms` | `15` | `50 ms` | SF floor |
Example for a quiet fixed repeater:
```text
set retry.preset rooftop
set direct.retry.heard on
set direct.retry.margin 5
```
Example for a moving or weak-link node:
```text
set retry.preset mobile
set direct.retry.margin 0
```
## Flood And Advert Settings
Flood retry applies to flood-routed packets. A queued retry is canceled when a qualifying downstream echo is heard.
| Setting | What it does | How to use | Example |
| --- | --- | --- | --- |
| `flood.retry.count` | Maximum flood retry attempts after initial TX. `0` disables flood retry. | `get flood.retry.count`, `set flood.retry.count <0-3>` | `set flood.retry.count 3` |
| `flood.retry.path` | Maximum path hash count eligible for flood retry, or `off` to disable the gate. | `get flood.retry.path`, `set flood.retry.path <0-63/off>` | `set flood.retry.path 1` |
| `flood.retry.advert` | Allows or blocks retry for node advert packets (`type=4`). Default is `off`. | `get flood.retry.advert`, `set flood.retry.advert on/off` | `set flood.retry.advert off` |
| `flood.retry.prefixes` | Target prefixes. If set, only matching downstream echoes cancel a retry. | `get flood.retry.prefixes`, `set flood.retry.prefixes <prefixes/none/off>` | `set flood.retry.prefixes BEEBB0,425E5C` |
| `flood.retry.ignore` | Ignored prefixes. In non-bridge retry, ignored last-hop echoes do not cancel retry. | `get flood.retry.ignore`, `set flood.retry.ignore <prefixes/none/off>` | `set flood.retry.ignore 71CE82,C7618C` |
| `flood.retry.bridge` | Enables bucket-based bridge retry logic. | `get flood.retry.bridge`, `set flood.retry.bridge on/off` | `set flood.retry.bridge on` |
| `flood.retry.bucket.<n>` | Shows one bridge bucket. Buckets are numbered `1`-`6`. | `get flood.retry.bucket.<n>` | `get flood.retry.bucket.1` |
| `flood.retry.bucket` | Sets bridge bucket prefixes. | `set flood.retry.bucket <1-6> <prefixes/none/off>` | `set flood.retry.bucket 1 71CE82,C7618C` |
The shared retry preset sets these flood defaults:
| Preset | Retry count | Path gate |
| --- | ---: | ---: |
| `infra` | `1` | `1` |
| `rooftop` | `3` | `2` |
| `mobile` | `3` | `1` |
Example for Keymind path-gated retry:
```text
set retry.preset rooftop
set flood.retry.path 1
set flood.retry.advert off
set flood.retry.ignore 71CE82,C7618C
```
Example for Halo targeted retry:
```text
set flood.retry.bridge off
set flood.retry.prefixes A1B2C3,D4E5F6
set flood.retry.ignore none
```
Example for Halo/Keymind bridge retry:
```text
set flood.retry.bridge on
set flood.retry.bucket 1 A1B2C3,D4E5F6
set flood.retry.bucket 2 71CE82,C7618C
set flood.retry.advert off
```
## North South Buckets
Buckets describe groups of repeaters on different sides of this relay. Bucket
numbers do not have built-in meanings; this example uses bucket `1` for North
and bucket `2` for South.
```text
North bucket 1
+-----------------------+
| A1B2C3 D4E5F6 |
| North A North B |
+-----------+-----------+
|
v
+-----------+
| This node |
+-----------+
^
|
+-----------+-----------+
| 71CE82 C7618C |
| South A South B |
+-----------------------+
South bucket 2
```
Configure the buckets:
```text
set flood.retry.bridge on
set flood.retry.bucket 1 A1B2C3,D4E5F6
set flood.retry.bucket 2 71CE82,C7618C
set flood.retry.ignore none
```
Packet heard from the North:
```text
heard source
|
v
+--------------+ retry targets
| North bucket | -----> South bucket
| bucket 1 | -----> Other fresh/unbucketed relays
+--------------+
```
Packet heard from the South:
```text
heard source
|
v
+--------------+ retry targets
| South bucket | -----> North bucket
| bucket 2 | -----> Other fresh/unbucketed relays
+--------------+
```
Packet heard from an unbucketed or pathless source:
```text
heard source
|
v
+--------------+ retry targets
| Other bucket | -----> North bucket
| implicit | -----> South bucket
+--------------+
```
Bridge retry stays eligible until every target bucket has been heard or
`flood.retry.count` is exhausted. A configured bucket is a target only when at
least one of its prefixes is fresh in `recent.repeater`. Prefixes in
`flood.retry.ignore` never count as bucket hits.
## Troubleshooting
If advert packets are still retrying:
```text
get flood.retry.advert
set flood.retry.advert off
```
If ignored prefixes still appear in `flood retry good` logs:
```text
get flood.retry.ignore
set flood.retry.ignore <prefix>
```
The ignored prefix must match the last hop shown as `heard=<prefix>`. For example, this log needs `C7618C` in the ignore list:
```text
flood retry good (... path=7773D0>C7618C, heard=C7618C ...)
```
If retries are too aggressive:
```text
set flood.retry.count 1
set flood.retry.path 1
set direct.retry.count 4
```
If retries are too sparse:
```text
set retry.preset rooftop
set flood.retry.count 3
set flood.retry.path 2
```
+8 -4
View File
@@ -847,10 +847,10 @@ bool MyMesh::allowDirectRetry(const mesh::Packet* packet, const uint8_t* next_ho
return true;
}
uint8_t MyMesh::getDirectRetryPreset() const {
if (_prefs.direct_retry_preset <= DIRECT_RETRY_PRESET_MOBILE) {
return _prefs.direct_retry_preset;
if (_prefs.retry_preset <= RETRY_PRESET_MOBILE) {
return _prefs.retry_preset;
}
return DIRECT_RETRY_PRESET_ROOFTOP;
return RETRY_PRESET_ROOFTOP;
}
uint8_t MyMesh::getDirectRetryConfiguredMaxAttempts() const {
return constrain(_prefs.direct_retry_attempts, (uint8_t)1, (uint8_t)15);
@@ -1099,6 +1099,9 @@ bool MyMesh::allowFloodRetry(const mesh::Packet* packet) const {
if (_prefs.disable_fwd || constrain(_prefs.flood_retry_attempts, (uint8_t)0, (uint8_t)3) == 0) {
return false;
}
if (packet != NULL && packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && !_prefs.flood_retry_advert_enabled) {
return false;
}
if (!_prefs.flood_retry_bridge_enabled) {
return true;
}
@@ -1750,10 +1753,11 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.direct_retry_attempts = DIRECT_RETRY_ROOFTOP_COUNT;
_prefs.direct_retry_base_ms = DIRECT_RETRY_ROOFTOP_BASE_MS;
_prefs.direct_retry_step_ms = DIRECT_RETRY_ROOFTOP_STEP_MS;
_prefs.direct_retry_preset = DIRECT_RETRY_PRESET_ROOFTOP;
_prefs.retry_preset = RETRY_PRESET_ROOFTOP;
_prefs.flood_retry_attempts = 3;
_prefs.flood_retry_path_gate = 2;
_prefs.flood_retry_bridge_enabled = 0;
_prefs.flood_retry_advert_enabled = 0;
StrHelper::strncpy(_prefs.node_name, ADVERT_NAME, sizeof(_prefs.node_name));
_prefs.node_lat = ADVERT_LAT;
_prefs.node_lon = ADVERT_LON;
+95 -93
View File
@@ -29,11 +29,12 @@
#define DIRECT_RETRY_STEP_MS_DEFAULT DIRECT_RETRY_ROOFTOP_STEP_MS
#define DIRECT_RETRY_STEP_MS_MIN 0
#define DIRECT_RETRY_STEP_MS_MAX 5000
#define DIRECT_RETRY_PRESET_DEFAULT DIRECT_RETRY_PRESET_ROOFTOP
#define RETRY_PRESET_DEFAULT RETRY_PRESET_ROOFTOP
#define FLOOD_RETRY_PREFS_MAGIC_0 0xF4
#define FLOOD_RETRY_PREFS_MAGIC_1 0x52
#define FLOOD_RETRY_COUNT_MIN 0
#define FLOOD_RETRY_COUNT_MAX 3
#define FLOOD_RETRY_ADVERT_DEFAULT 0
// Believe it or not, this std C function is busted on some platforms!
static uint32_t _atoi(const char* sp) {
@@ -78,20 +79,20 @@ static float directRetryMarginX4ToDb(uint8_t margin_x4) {
return ((float)margin_x4) / 4.0f;
}
static uint8_t directRetryPresetOrDefault(uint8_t preset) {
if (preset <= DIRECT_RETRY_PRESET_MOBILE) {
static uint8_t retryPresetOrDefault(uint8_t preset) {
if (preset <= RETRY_PRESET_MOBILE) {
return preset;
}
return DIRECT_RETRY_PRESET_DEFAULT;
return RETRY_PRESET_DEFAULT;
}
static const char* directRetryPresetName(uint8_t preset) {
switch (directRetryPresetOrDefault(preset)) {
case DIRECT_RETRY_PRESET_INFRA:
static const char* retryPresetName(uint8_t preset) {
switch (retryPresetOrDefault(preset)) {
case RETRY_PRESET_INFRA:
return "infra";
case DIRECT_RETRY_PRESET_MOBILE:
case RETRY_PRESET_MOBILE:
return "mobile";
case DIRECT_RETRY_PRESET_ROOFTOP:
case RETRY_PRESET_ROOFTOP:
default:
return "rooftop";
}
@@ -113,36 +114,36 @@ static uint8_t directRetryEffectiveMarginX4(const NodePrefs* prefs) {
return constrain(prefs->direct_retry_snr_margin_db, (uint8_t)0, (uint8_t)DIRECT_RETRY_SNR_MARGIN_X4_MAX);
}
static uint16_t directRetryPresetStepDefault(uint8_t preset) {
switch (directRetryPresetOrDefault(preset)) {
case DIRECT_RETRY_PRESET_INFRA:
static uint16_t retryPresetStepDefault(uint8_t preset) {
switch (retryPresetOrDefault(preset)) {
case RETRY_PRESET_INFRA:
return DIRECT_RETRY_INFRA_STEP_MS;
case DIRECT_RETRY_PRESET_MOBILE:
case RETRY_PRESET_MOBILE:
return DIRECT_RETRY_MOBILE_STEP_MS;
case DIRECT_RETRY_PRESET_ROOFTOP:
case RETRY_PRESET_ROOFTOP:
default:
return DIRECT_RETRY_ROOFTOP_STEP_MS;
}
}
static uint8_t floodRetryPresetCountDefault(uint8_t preset) {
switch (directRetryPresetOrDefault(preset)) {
case DIRECT_RETRY_PRESET_INFRA:
switch (retryPresetOrDefault(preset)) {
case RETRY_PRESET_INFRA:
return 1;
case DIRECT_RETRY_PRESET_MOBILE:
case DIRECT_RETRY_PRESET_ROOFTOP:
case RETRY_PRESET_MOBILE:
case RETRY_PRESET_ROOFTOP:
default:
return 3;
}
}
static uint8_t floodRetryPresetPathDefault(uint8_t preset) {
switch (directRetryPresetOrDefault(preset)) {
case DIRECT_RETRY_PRESET_INFRA:
switch (retryPresetOrDefault(preset)) {
case RETRY_PRESET_INFRA:
return 1;
case DIRECT_RETRY_PRESET_MOBILE:
case RETRY_PRESET_MOBILE:
return 1;
case DIRECT_RETRY_PRESET_ROOFTOP:
case RETRY_PRESET_ROOFTOP:
default:
return 2;
}
@@ -157,33 +158,22 @@ static uint8_t floodRetryEffectiveCount(const NodePrefs* prefs) {
return constrain(prefs->flood_retry_attempts, (uint8_t)FLOOD_RETRY_COUNT_MIN, (uint8_t)FLOOD_RETRY_COUNT_MAX);
}
static uint8_t floodRetryPresetForPrefs(const NodePrefs* prefs) {
uint8_t count = floodRetryEffectiveCount(prefs);
uint8_t path_gate = prefs->flood_retry_path_gate;
for (uint8_t preset = DIRECT_RETRY_PRESET_INFRA; preset <= DIRECT_RETRY_PRESET_MOBILE; preset++) {
if (count == floodRetryPresetCountDefault(preset) && path_gate == floodRetryPresetPathDefault(preset)) {
return preset;
}
}
return directRetryPresetOrDefault(prefs->direct_retry_preset);
}
static void applyDirectRetryPreset(NodePrefs* prefs, uint8_t preset) {
prefs->direct_retry_preset = directRetryPresetOrDefault(preset);
switch (prefs->direct_retry_preset) {
case DIRECT_RETRY_PRESET_INFRA:
static void applyRetryPreset(NodePrefs* prefs, uint8_t preset) {
prefs->retry_preset = retryPresetOrDefault(preset);
switch (prefs->retry_preset) {
case RETRY_PRESET_INFRA:
prefs->direct_retry_base_ms = DIRECT_RETRY_INFRA_BASE_MS;
prefs->direct_retry_attempts = DIRECT_RETRY_INFRA_COUNT;
prefs->direct_retry_step_ms = DIRECT_RETRY_INFRA_STEP_MS;
prefs->direct_retry_snr_margin_db = DIRECT_RETRY_INFRA_MARGIN_X4;
break;
case DIRECT_RETRY_PRESET_MOBILE:
case RETRY_PRESET_MOBILE:
prefs->direct_retry_base_ms = DIRECT_RETRY_MOBILE_BASE_MS;
prefs->direct_retry_attempts = DIRECT_RETRY_MOBILE_COUNT;
prefs->direct_retry_step_ms = DIRECT_RETRY_MOBILE_STEP_MS;
prefs->direct_retry_snr_margin_db = DIRECT_RETRY_MOBILE_MARGIN_X4;
break;
case DIRECT_RETRY_PRESET_ROOFTOP:
case RETRY_PRESET_ROOFTOP:
default:
prefs->direct_retry_base_ms = DIRECT_RETRY_ROOFTOP_BASE_MS;
prefs->direct_retry_attempts = DIRECT_RETRY_ROOFTOP_COUNT;
@@ -191,7 +181,13 @@ static void applyDirectRetryPreset(NodePrefs* prefs, uint8_t preset) {
prefs->direct_retry_snr_margin_db = DIRECT_RETRY_ROOFTOP_MARGIN_X4;
break;
}
applyFloodRetryPreset(prefs, prefs->direct_retry_preset);
applyFloodRetryPreset(prefs, prefs->retry_preset);
}
static void formatRetryPreset(char* reply, const NodePrefs* prefs) {
sprintf(reply, "> %d,%s",
(uint32_t)retryPresetOrDefault(prefs->retry_preset),
retryPresetName(prefs->retry_preset));
}
static bool parseFloodRetryPathGate(const char* value, uint8_t& path_gate) {
@@ -316,21 +312,21 @@ static bool parseFloodRetryPrefixList(uint8_t dest[][FLOOD_RETRY_PREFIX_LEN], ui
return true;
}
static bool parseDirectRetryPreset(const char* value, uint8_t& preset) {
static bool parseRetryPreset(const char* value, uint8_t& preset) {
if (value == NULL) {
return false;
}
if (strcmp(value, "0") == 0 || strcmp(value, "infra") == 0
|| strcmp(value, "infa") == 0 || strcmp(value, "infrastructure") == 0) {
preset = DIRECT_RETRY_PRESET_INFRA;
preset = RETRY_PRESET_INFRA;
return true;
}
if (strcmp(value, "1") == 0 || strcmp(value, "rooftop") == 0) {
preset = DIRECT_RETRY_PRESET_ROOFTOP;
preset = RETRY_PRESET_ROOFTOP;
return true;
}
if (strcmp(value, "2") == 0 || strcmp(value, "mobile") == 0) {
preset = DIRECT_RETRY_PRESET_MOBILE;
preset = RETRY_PRESET_MOBILE;
return true;
}
return false;
@@ -418,7 +414,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
file.read((uint8_t *)&_prefs->direct_retry_timing_magic[0], sizeof(_prefs->direct_retry_timing_magic)); // 294
size_t radio_fem_rxgain_read = file.read((uint8_t *)&_prefs->radio_fem_rxgain,
sizeof(_prefs->radio_fem_rxgain)); // 296
file.read((uint8_t *)&_prefs->direct_retry_preset, sizeof(_prefs->direct_retry_preset)); // 297
file.read((uint8_t *)&_prefs->retry_preset, sizeof(_prefs->retry_preset)); // 297
size_t retry_step_read = file.read((uint8_t *)&_prefs->direct_retry_step_ms,
sizeof(_prefs->direct_retry_step_ms)); // 298
size_t flood_retry_attempts_read = file.read((uint8_t *)&_prefs->flood_retry_attempts,
@@ -432,6 +428,9 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
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
_prefs->flood_retry_advert_enabled = FLOOD_RETRY_ADVERT_DEFAULT;
size_t flood_retry_advert_read = file.read((uint8_t *)&_prefs->flood_retry_advert_enabled,
sizeof(_prefs->flood_retry_advert_enabled)); // 659
// 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)
@@ -487,29 +486,35 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
// sanitise settings
_prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean
_prefs->radio_fem_rxgain = constrain(_prefs->radio_fem_rxgain, 0, 1); // boolean
_prefs->direct_retry_preset = directRetryPresetOrDefault(_prefs->direct_retry_preset);
_prefs->retry_preset = retryPresetOrDefault(_prefs->retry_preset);
if (retry_step_read != sizeof(_prefs->direct_retry_step_ms)) {
_prefs->direct_retry_step_ms = directRetryPresetStepDefault(_prefs->direct_retry_preset);
_prefs->direct_retry_step_ms = retryPresetStepDefault(_prefs->retry_preset);
} else {
_prefs->direct_retry_step_ms = constrain(_prefs->direct_retry_step_ms, DIRECT_RETRY_STEP_MS_MIN, DIRECT_RETRY_STEP_MS_MAX);
}
if (flood_retry_attempts_read != sizeof(_prefs->flood_retry_attempts)
|| _prefs->flood_retry_prefs_magic[0] != FLOOD_RETRY_PREFS_MAGIC_0
|| _prefs->flood_retry_prefs_magic[1] != FLOOD_RETRY_PREFS_MAGIC_1) {
applyFloodRetryPreset(_prefs, _prefs->direct_retry_preset);
applyFloodRetryPreset(_prefs, _prefs->retry_preset);
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));
_prefs->flood_retry_advert_enabled = FLOOD_RETRY_ADVERT_DEFAULT;
} 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_path_gate = floodRetryPresetPathDefault(_prefs->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));
}
if (flood_retry_advert_read != sizeof(_prefs->flood_retry_advert_enabled)) {
_prefs->flood_retry_advert_enabled = FLOOD_RETRY_ADVERT_DEFAULT;
} else {
_prefs->flood_retry_advert_enabled = constrain(_prefs->flood_retry_advert_enabled, 0, 1);
}
}
file.close();
@@ -581,7 +586,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
uint8_t retry_timing_magic[2] = { DIRECT_RETRY_TIMING_MAGIC_0, DIRECT_RETRY_TIMING_MAGIC_1 };
file.write(retry_timing_magic, sizeof(retry_timing_magic)); // 294
file.write((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 296
file.write((uint8_t *)&_prefs->direct_retry_preset, sizeof(_prefs->direct_retry_preset)); // 297
file.write((uint8_t *)&_prefs->retry_preset, sizeof(_prefs->retry_preset)); // 297
file.write((uint8_t *)&_prefs->direct_retry_step_ms, sizeof(_prefs->direct_retry_step_ms)); // 298
file.write((uint8_t *)&_prefs->flood_retry_attempts, sizeof(_prefs->flood_retry_attempts)); // 300
file.write((uint8_t *)&_prefs->flood_retry_path_gate, sizeof(_prefs->flood_retry_path_gate)); // 301
@@ -591,7 +596,8 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
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
file.write((uint8_t *)&_prefs->flood_retry_ignore_prefixes[0][0], sizeof(_prefs->flood_retry_ignore_prefixes)); // 635
// next: 659
file.write((uint8_t *)&_prefs->flood_retry_advert_enabled, sizeof(_prefs->flood_retry_advert_enabled)); // 659
// next: 660
file.close();
}
@@ -747,6 +753,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->tx_delay_factor));
} else if (memcmp(config, "flood.max", 9) == 0) {
sprintf(reply, "> %d", (uint32_t)_prefs->flood_max);
} else if (memcmp(config, "retry.preset", 12) == 0) {
formatRetryPreset(reply, _prefs);
} else if (memcmp(config, "flood.retry.count", 17) == 0) {
sprintf(reply, "> %d", (uint32_t)floodRetryEffectiveCount(_prefs));
} else if (memcmp(config, "flood.retry.path", 16) == 0) {
@@ -759,6 +767,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
} 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.advert", 18) == 0) {
sprintf(reply, "> %s", _prefs->flood_retry_advert_enabled ? "on" : "off");
} 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) {
@@ -769,21 +779,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
} else {
sprintf(reply, "Error, bucket 1-%d", FLOOD_RETRY_BRIDGE_BUCKETS);
}
} else if (memcmp(config, "flood.retry.preset", 18) == 0) {
uint8_t preset = floodRetryPresetForPrefs(_prefs);
sprintf(reply, "> %d,%s",
(uint32_t)preset,
directRetryPresetName(preset));
} else if (memcmp(config, "direct.txdelay", 14) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->direct_tx_delay_factor));
} else if (memcmp(config, "direct.retry.heard", 18) == 0) {
sprintf(reply, "> %s", _prefs->direct_retry_recent_enabled ? "on" : "off");
} else if (memcmp(config, "direct.retry.margin", 19) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(directRetryMarginX4ToDb(directRetryEffectiveMarginX4(_prefs))));
} else if (memcmp(config, "direct.retry.preset", 19) == 0) {
sprintf(reply, "> %d,%s",
(uint32_t)directRetryPresetOrDefault(_prefs->direct_retry_preset),
directRetryPresetName(_prefs->direct_retry_preset));
} else if (memcmp(config, "direct.retry.count", 18) == 0) {
sprintf(reply, "> %d", (uint32_t)directRetryEffectiveCount(_prefs));
} else if (memcmp(config, "direct.retry.base", 17) == 0) {
@@ -1030,10 +1031,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
} else {
strcpy(reply, "Error, max 64");
}
} else if (memcmp(config, "flood.retry.preset ", 19) == 0) {
} else if (memcmp(config, "retry.preset ", 13) == 0) {
uint8_t preset;
if (parseDirectRetryPreset(&config[19], preset)) {
applyFloodRetryPreset(_prefs, preset);
if (parseRetryPreset(&config[13], preset)) {
applyRetryPreset(_prefs, preset);
savePrefs();
strcpy(reply, "OK");
} else {
@@ -1073,6 +1074,18 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
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.advert ", 19) == 0) {
if (memcmp(&config[19], "on", 2) == 0) {
_prefs->flood_retry_advert_enabled = 1;
savePrefs();
strcpy(reply, "OK");
} else if (memcmp(&config[19], "off", 3) == 0) {
_prefs->flood_retry_advert_enabled = 0;
savePrefs();
strcpy(reply, "OK");
} else {
strcpy(reply, "Error, must be on or off");
}
} else if (memcmp(config, "flood.retry.bridge ", 19) == 0) {
if (memcmp(&config[19], "on", 2) == 0) {
_prefs->flood_retry_bridge_enabled = 1;
@@ -1129,15 +1142,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
} else {
sprintf(reply, "Error, min 0 and max %d", DIRECT_RETRY_SNR_MARGIN_DB_MAX);
}
} else if (memcmp(config, "direct.retry.preset ", 20) == 0) {
uint8_t preset;
if (parseDirectRetryPreset(&config[20], preset)) {
applyDirectRetryPreset(_prefs, preset);
savePrefs();
strcpy(reply, "OK");
} else {
strcpy(reply, "Error, must be infra, rooftop, mobile, 0, 1, or 2");
}
} else if (memcmp(config, "direct.retry.count ", 19) == 0) {
int count = atoi(&config[19]);
if (count >= DIRECT_RETRY_COUNT_MIN && count <= DIRECT_RETRY_COUNT_MAX) {
@@ -1653,10 +1657,10 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
} else {
strcpy(reply, "Error, max 64");
}
} else if (memcmp(config, "flood.retry.preset ", 19) == 0) {
} else if (memcmp(config, "retry.preset ", 13) == 0) {
uint8_t preset;
if (parseDirectRetryPreset(&config[19], preset)) {
applyFloodRetryPreset(_prefs, preset);
if (parseRetryPreset(&config[13], preset)) {
applyRetryPreset(_prefs, preset);
savePrefs();
strcpy(reply, "OK");
} else {
@@ -1696,6 +1700,18 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
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.advert ", 19) == 0) {
if (memcmp(&config[19], "on", 2) == 0) {
_prefs->flood_retry_advert_enabled = 1;
savePrefs();
strcpy(reply, "OK");
} else if (memcmp(&config[19], "off", 3) == 0) {
_prefs->flood_retry_advert_enabled = 0;
savePrefs();
strcpy(reply, "OK");
} else {
strcpy(reply, "Error, must be on or off");
}
} else if (memcmp(config, "flood.retry.bridge ", 19) == 0) {
if (memcmp(&config[19], "on", 2) == 0) {
_prefs->flood_retry_bridge_enabled = 1;
@@ -1752,15 +1768,6 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
} else {
sprintf(reply, "Error, min 0 and max %d", DIRECT_RETRY_SNR_MARGIN_DB_MAX);
}
} else if (memcmp(config, "direct.retry.preset ", 20) == 0) {
uint8_t preset;
if (parseDirectRetryPreset(&config[20], preset)) {
applyDirectRetryPreset(_prefs, preset);
savePrefs();
strcpy(reply, "OK");
} else {
strcpy(reply, "Error, must be infra, rooftop, mobile, 0, 1, or 2");
}
} else if (memcmp(config, "direct.retry.count ", 19) == 0) {
int count = atoi(&config[19]);
if (count >= DIRECT_RETRY_COUNT_MIN && count <= DIRECT_RETRY_COUNT_MAX) {
@@ -1961,6 +1968,8 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->tx_delay_factor));
} else if (memcmp(config, "flood.max", 9) == 0) {
sprintf(reply, "> %d", (uint32_t)_prefs->flood_max);
} else if (memcmp(config, "retry.preset", 12) == 0) {
formatRetryPreset(reply, _prefs);
} else if (memcmp(config, "flood.retry.count", 17) == 0) {
sprintf(reply, "> %d", (uint32_t)floodRetryEffectiveCount(_prefs));
} else if (memcmp(config, "flood.retry.path", 16) == 0) {
@@ -1973,6 +1982,8 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
} 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.advert", 18) == 0) {
sprintf(reply, "> %s", _prefs->flood_retry_advert_enabled ? "on" : "off");
} 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) {
@@ -1983,21 +1994,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
} else {
sprintf(reply, "Error, bucket 1-%d", FLOOD_RETRY_BRIDGE_BUCKETS);
}
} else if (memcmp(config, "flood.retry.preset", 18) == 0) {
uint8_t preset = floodRetryPresetForPrefs(_prefs);
sprintf(reply, "> %d,%s",
(uint32_t)preset,
directRetryPresetName(preset));
} else if (memcmp(config, "direct.txdelay", 14) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->direct_tx_delay_factor));
} else if (memcmp(config, "direct.retry.heard", 18) == 0) {
sprintf(reply, "> %s", _prefs->direct_retry_recent_enabled ? "on" : "off");
} else if (memcmp(config, "direct.retry.margin", 19) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(directRetryMarginX4ToDb(directRetryEffectiveMarginX4(_prefs))));
} else if (memcmp(config, "direct.retry.preset", 19) == 0) {
sprintf(reply, "> %d,%s",
(uint32_t)directRetryPresetOrDefault(_prefs->direct_retry_preset),
directRetryPresetName(_prefs->direct_retry_preset));
} else if (memcmp(config, "direct.retry.count", 18) == 0) {
sprintf(reply, "> %d", (uint32_t)directRetryEffectiveCount(_prefs));
} else if (memcmp(config, "direct.retry.base", 17) == 0) {
+5 -4
View File
@@ -19,9 +19,9 @@
#define LOOP_DETECT_MODERATE 2
#define LOOP_DETECT_STRICT 3
#define DIRECT_RETRY_PRESET_INFRA 0
#define DIRECT_RETRY_PRESET_ROOFTOP 1
#define DIRECT_RETRY_PRESET_MOBILE 2
#define RETRY_PRESET_INFRA 0
#define RETRY_PRESET_ROOFTOP 1
#define RETRY_PRESET_MOBILE 2
#define DIRECT_RETRY_INFRA_BASE_MS 275
#define DIRECT_RETRY_INFRA_COUNT 4
@@ -111,7 +111,7 @@ struct NodePrefs { // persisted to file
uint8_t direct_retry_attempts;
uint16_t direct_retry_base_ms;
uint8_t direct_retry_timing_magic[2];
uint8_t direct_retry_preset;
uint8_t retry_preset;
uint16_t direct_retry_step_ms;
uint8_t flood_retry_attempts;
uint8_t flood_retry_path_gate;
@@ -120,6 +120,7 @@ struct NodePrefs { // persisted to file
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];
uint8_t flood_retry_advert_enabled;
};
class CommonCLICallbacks {