Update direct retry CR controls
This commit is contained in:
1 parent
bb8e7140a9
commit
9a86090978
4 files changed
+92
-36
No files matched your search
@@ -559,18 +559,18 @@ This document provides an overview of CLI commands that can be sent to MeshCore
|
||||
#### View or change adaptive coding rate for direct retry packets
|
||||
**Usage:**
|
||||
- `get direct.retry.cr`
|
||||
- `set direct.retry.cr <cr4_min>,<cr5_min>,<cr8_max>`
|
||||
- `set direct.retry.cr <cr4_min>,<cr5_min>,<low>,<low>`
|
||||
- `set direct.retry.cr <cr4_min>,<cr5_min>,<cr7_min>,<cr8_max>`
|
||||
- `set direct.retry.cr off`
|
||||
|
||||
**Parameters:**
|
||||
- `cr4_min`: SNR in dB where retry packets use `CR4`
|
||||
- `cr5_min`: SNR in dB where retry packets use `CR5`
|
||||
- `cr7_min`: SNR in dB where retry packets use `CR7`
|
||||
- `cr8_max`: SNR in dB where retry packets use `CR8`
|
||||
- `low`: optional repeated low boundary; both low values must match
|
||||
|
||||
**Default:** `10.0,7.5,2.5,2.5`
|
||||
|
||||
**Note:** DM retry packets with a recent repeater table entry use that entry's SNR to pick a local transmit coding rate. With the default, SNR `10.0 dB` and up uses `CR4`, SNR `7.5 dB` and up uses `CR5`, SNR `2.5 dB` and down uses `CR8`, and the middle band uses `CR7`. `CR6` is never selected. The shorter form `set direct.retry.cr 10.0,7.5,2.5` is equivalent to `set direct.retry.cr 10.0,7.5,2.5,2.5`.
|
||||
**Note:** DM retry packets use the next-hop SNR from a recent repeater table entry to pick a local transmit coding rate; if no recent entry is available, retry packets use `CR5`. With the default, SNR `10.0 dB` and up uses `CR4`, SNR `7.5 dB` and up uses `CR5`, SNR `2.5 dB` and down uses `CR8`, and the middle band uses `CR7`. `CR6` is never selected. Use `set direct.retry.cr off` to disable adaptive coding-rate overrides. If adaptive selection chooses `CR4`, retries after the third attempt use `CR5`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -744,7 +744,8 @@ void MyMesh::onDirectRetryEvent(const char* event, const mesh::Packet* packet, u
|
||||
time_label = "echo_ms";
|
||||
}
|
||||
|
||||
MESH_DEBUG_PRINTLN("%s direct retry %s (retry=%u, type=%d, route=%s, payload_len=%d, hop=%s, next_hop=%s, pkt=%s, tbl=%s, %s=%lu)",
|
||||
uint8_t log_cr = (packet->tx_cr >= 4 && packet->tx_cr <= 8) ? packet->tx_cr : active_cr;
|
||||
MESH_DEBUG_PRINTLN("%s direct retry %s (retry=%u, type=%d, route=%s, payload_len=%d, hop=%s, next_hop=%s, pkt=%s, tbl=%s, cr=%u, %s=%lu)",
|
||||
getLogDateTime(),
|
||||
event,
|
||||
(unsigned int)retry_attempt,
|
||||
@@ -755,6 +756,7 @@ void MyMesh::onDirectRetryEvent(const char* event, const mesh::Packet* packet, u
|
||||
next_hop,
|
||||
snr_pkt_text,
|
||||
snr_table_text,
|
||||
(unsigned int)log_cr,
|
||||
time_label,
|
||||
(unsigned long)delay_millis);
|
||||
|
||||
@@ -762,7 +764,7 @@ void MyMesh::onDirectRetryEvent(const char* event, const mesh::Packet* packet, u
|
||||
File f = openAppend(PACKET_LOG_FILE);
|
||||
if (f) {
|
||||
f.print(getLogDateTime());
|
||||
f.printf(": DIRECT RETRY %s (retry=%u, type=%d, route=%s, payload_len=%d, hop=%s, next_hop=%s, pkt=%s, tbl=%s, %s=%lu)\n",
|
||||
f.printf(": DIRECT RETRY %s (retry=%u, type=%d, route=%s, payload_len=%d, hop=%s, next_hop=%s, pkt=%s, tbl=%s, cr=%u, %s=%lu)\n",
|
||||
event,
|
||||
(unsigned int)retry_attempt,
|
||||
(uint32_t)packet->getPayloadType(),
|
||||
@@ -772,6 +774,7 @@ void MyMesh::onDirectRetryEvent(const char* event, const mesh::Packet* packet, u
|
||||
next_hop,
|
||||
snr_pkt_text,
|
||||
snr_table_text,
|
||||
(unsigned int)log_cr,
|
||||
time_label,
|
||||
(unsigned long)delay_millis);
|
||||
f.close();
|
||||
@@ -847,6 +850,12 @@ bool MyMesh::allowDirectRetry(const mesh::Packet* packet, const uint8_t* next_ho
|
||||
return true;
|
||||
}
|
||||
uint8_t MyMesh::getDirectRetryCodingRateForSNR(int8_t snr_x4) const {
|
||||
if (_prefs.direct_retry_cr4_snr_x4 == 0
|
||||
&& _prefs.direct_retry_cr5_snr_x4 == 0
|
||||
&& _prefs.direct_retry_cr7_snr_x4 == 0
|
||||
&& _prefs.direct_retry_cr8_snr_x4 == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (snr_x4 >= _prefs.direct_retry_cr4_snr_x4) {
|
||||
return 4;
|
||||
}
|
||||
@@ -856,11 +865,13 @@ uint8_t MyMesh::getDirectRetryCodingRateForSNR(int8_t snr_x4) const {
|
||||
if (snr_x4 <= _prefs.direct_retry_cr8_snr_x4) {
|
||||
return 8;
|
||||
}
|
||||
if (snr_x4 >= _prefs.direct_retry_cr7_snr_x4) {
|
||||
return 7;
|
||||
}
|
||||
return 7;
|
||||
}
|
||||
void MyMesh::configureDirectRetryPacket(mesh::Packet* retry, const mesh::Packet* original, uint8_t retry_attempt) {
|
||||
(void) original;
|
||||
(void) retry_attempt;
|
||||
|
||||
if (retry == NULL || !retry->isRouteDirect()) {
|
||||
return;
|
||||
@@ -873,6 +884,7 @@ void MyMesh::configureDirectRetryPacket(mesh::Packet* retry, const mesh::Packet*
|
||||
case PAYLOAD_TYPE_RESPONSE:
|
||||
case PAYLOAD_TYPE_TXT_MSG:
|
||||
case PAYLOAD_TYPE_ANON_REQ:
|
||||
case PAYLOAD_TYPE_TRACE:
|
||||
case PAYLOAD_TYPE_MULTIPART:
|
||||
break;
|
||||
default:
|
||||
@@ -885,13 +897,20 @@ void MyMesh::configureDirectRetryPacket(mesh::Packet* retry, const mesh::Packet*
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* recent = ((const SimpleMeshTables *)getTables())->findRecentRepeaterByHash(prefix, prefix_len);
|
||||
if (recent == NULL) {
|
||||
if (_prefs.direct_retry_cr4_snr_x4 == 0
|
||||
&& _prefs.direct_retry_cr5_snr_x4 == 0
|
||||
&& _prefs.direct_retry_cr7_snr_x4 == 0
|
||||
&& _prefs.direct_retry_cr8_snr_x4 == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t retry_cr = getDirectRetryCodingRateForSNR(recent->snr_x4);
|
||||
if (retry_cr >= 4 && retry_cr <= 8 && retry_cr != active_cr) {
|
||||
const auto* recent = ((const SimpleMeshTables *)getTables())->findRecentRepeaterByHash(prefix, prefix_len);
|
||||
uint8_t retry_cr = (recent != NULL) ? getDirectRetryCodingRateForSNR(recent->snr_x4) : 5;
|
||||
if (retry_cr == 4 && retry_attempt > 3) {
|
||||
retry_cr = 5;
|
||||
}
|
||||
|
||||
if (retry_cr >= 4 && retry_cr <= 8 && retry_cr != 6 && retry_cr != active_cr) {
|
||||
retry->tx_cr = retry_cr;
|
||||
}
|
||||
}
|
||||
@@ -1294,6 +1313,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
||||
_prefs.direct_retry_preset = DIRECT_RETRY_PRESET_ROOFTOP;
|
||||
_prefs.direct_retry_cr4_snr_x4 = DIRECT_RETRY_CR4_MIN_SNR_X4_DEFAULT;
|
||||
_prefs.direct_retry_cr5_snr_x4 = DIRECT_RETRY_CR5_MIN_SNR_X4_DEFAULT;
|
||||
_prefs.direct_retry_cr7_snr_x4 = DIRECT_RETRY_CR7_MIN_SNR_X4_DEFAULT;
|
||||
_prefs.direct_retry_cr8_snr_x4 = DIRECT_RETRY_CR8_MAX_SNR_X4_DEFAULT;
|
||||
StrHelper::strncpy(_prefs.node_name, ADVERT_NAME, sizeof(_prefs.node_name));
|
||||
_prefs.node_lat = ADVERT_LAT;
|
||||
|
||||
+59
-25
@@ -92,29 +92,53 @@ static float directRetryCrX4ToDb(int8_t snr_x4) {
|
||||
static void setDirectRetryCrDefaults(NodePrefs* prefs) {
|
||||
prefs->direct_retry_cr4_snr_x4 = DIRECT_RETRY_CR4_MIN_SNR_X4_DEFAULT;
|
||||
prefs->direct_retry_cr5_snr_x4 = DIRECT_RETRY_CR5_MIN_SNR_X4_DEFAULT;
|
||||
prefs->direct_retry_cr7_snr_x4 = DIRECT_RETRY_CR7_MIN_SNR_X4_DEFAULT;
|
||||
prefs->direct_retry_cr8_snr_x4 = DIRECT_RETRY_CR8_MAX_SNR_X4_DEFAULT;
|
||||
}
|
||||
|
||||
static bool directRetryCrThresholdsAreValid(int8_t cr4_snr_x4, int8_t cr5_snr_x4, int8_t cr8_snr_x4) {
|
||||
return (cr4_snr_x4 != 0 || cr5_snr_x4 != 0 || cr8_snr_x4 != 0)
|
||||
&& cr4_snr_x4 >= cr5_snr_x4
|
||||
&& cr5_snr_x4 >= cr8_snr_x4;
|
||||
static void setDirectRetryCrOff(NodePrefs* prefs) {
|
||||
prefs->direct_retry_cr4_snr_x4 = 0;
|
||||
prefs->direct_retry_cr5_snr_x4 = 0;
|
||||
prefs->direct_retry_cr7_snr_x4 = 0;
|
||||
prefs->direct_retry_cr8_snr_x4 = 0;
|
||||
}
|
||||
|
||||
static bool directRetryCrThresholdsAreOff(int8_t cr4_snr_x4, int8_t cr5_snr_x4, int8_t cr7_snr_x4, int8_t cr8_snr_x4) {
|
||||
return cr4_snr_x4 == 0 && cr5_snr_x4 == 0 && cr7_snr_x4 == 0 && cr8_snr_x4 == 0;
|
||||
}
|
||||
|
||||
static bool directRetryCrThresholdsAreValid(int8_t cr4_snr_x4, int8_t cr5_snr_x4, int8_t cr7_snr_x4, int8_t cr8_snr_x4) {
|
||||
return directRetryCrThresholdsAreOff(cr4_snr_x4, cr5_snr_x4, cr7_snr_x4, cr8_snr_x4)
|
||||
|| ((cr4_snr_x4 != 0 || cr5_snr_x4 != 0 || cr7_snr_x4 != 0 || cr8_snr_x4 != 0)
|
||||
&& cr4_snr_x4 >= cr5_snr_x4
|
||||
&& cr5_snr_x4 >= cr7_snr_x4
|
||||
&& cr7_snr_x4 >= cr8_snr_x4);
|
||||
}
|
||||
|
||||
static void sanitizeDirectRetryCrThresholds(NodePrefs* prefs) {
|
||||
if (!directRetryCrThresholdsAreValid(prefs->direct_retry_cr4_snr_x4,
|
||||
prefs->direct_retry_cr5_snr_x4,
|
||||
prefs->direct_retry_cr7_snr_x4,
|
||||
prefs->direct_retry_cr8_snr_x4)) {
|
||||
setDirectRetryCrDefaults(prefs);
|
||||
}
|
||||
}
|
||||
|
||||
static void formatDirectRetryCrThresholds(const NodePrefs* prefs, char* reply) {
|
||||
char cr4[12], cr5[12], cr8[12];
|
||||
if (directRetryCrThresholdsAreOff(prefs->direct_retry_cr4_snr_x4,
|
||||
prefs->direct_retry_cr5_snr_x4,
|
||||
prefs->direct_retry_cr7_snr_x4,
|
||||
prefs->direct_retry_cr8_snr_x4)) {
|
||||
strcpy(reply, "> off");
|
||||
return;
|
||||
}
|
||||
|
||||
char cr4[12], cr5[12], cr7[12], cr8[12];
|
||||
strcpy(cr4, StrHelper::ftoa(directRetryCrX4ToDb(prefs->direct_retry_cr4_snr_x4)));
|
||||
strcpy(cr5, StrHelper::ftoa(directRetryCrX4ToDb(prefs->direct_retry_cr5_snr_x4)));
|
||||
strcpy(cr7, StrHelper::ftoa(directRetryCrX4ToDb(prefs->direct_retry_cr7_snr_x4)));
|
||||
strcpy(cr8, StrHelper::ftoa(directRetryCrX4ToDb(prefs->direct_retry_cr8_snr_x4)));
|
||||
sprintf(reply, "> %s,%s,%s,%s", cr4, cr5, cr8, cr8);
|
||||
sprintf(reply, "> %s,%s,%s,%s", cr4, cr5, cr7, cr8);
|
||||
}
|
||||
|
||||
static uint16_t directRetryPresetStepDefault(uint8_t preset) {
|
||||
@@ -198,35 +222,36 @@ static bool parseDirectRetryCrThresholds(char* value, NodePrefs* prefs) {
|
||||
if (value == NULL || prefs == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (strcmp(value, "off") == 0) {
|
||||
setDirectRetryCrOff(prefs);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* parts[4];
|
||||
int num = mesh::Utils::parseTextParts(value, parts, 4);
|
||||
if (num != 3 && num != 4) {
|
||||
const char* parts[5];
|
||||
int num = mesh::Utils::parseTextParts(value, parts, 5);
|
||||
if (num != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int8_t cr4_snr_x4;
|
||||
int8_t cr5_snr_x4;
|
||||
int8_t cr7_snr_x4;
|
||||
int8_t cr8_snr_x4;
|
||||
if (!parseDirectRetryCrDb(parts[0], cr4_snr_x4)
|
||||
|| !parseDirectRetryCrDb(parts[1], cr5_snr_x4)
|
||||
|| !parseDirectRetryCrDb(parts[num == 4 ? 3 : 2], cr8_snr_x4)) {
|
||||
|| !parseDirectRetryCrDb(parts[2], cr7_snr_x4)
|
||||
|| !parseDirectRetryCrDb(parts[3], cr8_snr_x4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num == 4) {
|
||||
int8_t repeated_low_snr_x4;
|
||||
if (!parseDirectRetryCrDb(parts[2], repeated_low_snr_x4) || repeated_low_snr_x4 != cr8_snr_x4) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!directRetryCrThresholdsAreValid(cr4_snr_x4, cr5_snr_x4, cr8_snr_x4)) {
|
||||
if (directRetryCrThresholdsAreOff(cr4_snr_x4, cr5_snr_x4, cr7_snr_x4, cr8_snr_x4)
|
||||
|| !directRetryCrThresholdsAreValid(cr4_snr_x4, cr5_snr_x4, cr7_snr_x4, cr8_snr_x4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
prefs->direct_retry_cr4_snr_x4 = cr4_snr_x4;
|
||||
prefs->direct_retry_cr5_snr_x4 = cr5_snr_x4;
|
||||
prefs->direct_retry_cr7_snr_x4 = cr7_snr_x4;
|
||||
prefs->direct_retry_cr8_snr_x4 = cr8_snr_x4;
|
||||
return true;
|
||||
}
|
||||
@@ -323,8 +348,10 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
sizeof(_prefs->direct_retry_cr4_snr_x4)); // 300
|
||||
retry_cr_read += file.read((uint8_t *)&_prefs->direct_retry_cr5_snr_x4,
|
||||
sizeof(_prefs->direct_retry_cr5_snr_x4)); // 301
|
||||
retry_cr_read += file.read((uint8_t *)&_prefs->direct_retry_cr7_snr_x4,
|
||||
sizeof(_prefs->direct_retry_cr7_snr_x4)); // 302
|
||||
retry_cr_read += file.read((uint8_t *)&_prefs->direct_retry_cr8_snr_x4,
|
||||
sizeof(_prefs->direct_retry_cr8_snr_x4)); // 302
|
||||
sizeof(_prefs->direct_retry_cr8_snr_x4)); // 303
|
||||
// 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)
|
||||
@@ -332,7 +359,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: 303
|
||||
// next: 304
|
||||
|
||||
// sanitise bad pref values
|
||||
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
|
||||
@@ -386,8 +413,14 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
} else {
|
||||
_prefs->direct_retry_step_ms = constrain(_prefs->direct_retry_step_ms, DIRECT_RETRY_STEP_MS_MIN, DIRECT_RETRY_STEP_MS_MAX);
|
||||
}
|
||||
if (retry_cr_read != sizeof(_prefs->direct_retry_cr4_snr_x4)
|
||||
if (retry_cr_read == sizeof(_prefs->direct_retry_cr4_snr_x4)
|
||||
+ sizeof(_prefs->direct_retry_cr5_snr_x4)
|
||||
+ sizeof(_prefs->direct_retry_cr7_snr_x4)) {
|
||||
_prefs->direct_retry_cr8_snr_x4 = _prefs->direct_retry_cr7_snr_x4;
|
||||
sanitizeDirectRetryCrThresholds(_prefs);
|
||||
} else if (retry_cr_read != sizeof(_prefs->direct_retry_cr4_snr_x4)
|
||||
+ sizeof(_prefs->direct_retry_cr5_snr_x4)
|
||||
+ sizeof(_prefs->direct_retry_cr7_snr_x4)
|
||||
+ sizeof(_prefs->direct_retry_cr8_snr_x4)) {
|
||||
setDirectRetryCrDefaults(_prefs);
|
||||
} else {
|
||||
@@ -467,8 +500,9 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
||||
file.write((uint8_t *)&_prefs->direct_retry_step_ms, sizeof(_prefs->direct_retry_step_ms)); // 298
|
||||
file.write((uint8_t *)&_prefs->direct_retry_cr4_snr_x4, sizeof(_prefs->direct_retry_cr4_snr_x4)); // 300
|
||||
file.write((uint8_t *)&_prefs->direct_retry_cr5_snr_x4, sizeof(_prefs->direct_retry_cr5_snr_x4)); // 301
|
||||
file.write((uint8_t *)&_prefs->direct_retry_cr8_snr_x4, sizeof(_prefs->direct_retry_cr8_snr_x4)); // 302
|
||||
// next: 303
|
||||
file.write((uint8_t *)&_prefs->direct_retry_cr7_snr_x4, sizeof(_prefs->direct_retry_cr7_snr_x4)); // 302
|
||||
file.write((uint8_t *)&_prefs->direct_retry_cr8_snr_x4, sizeof(_prefs->direct_retry_cr8_snr_x4)); // 303
|
||||
// next: 304
|
||||
|
||||
file.close();
|
||||
}
|
||||
@@ -954,7 +988,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
|
||||
savePrefs();
|
||||
formatDirectRetryCrThresholds(_prefs, reply);
|
||||
} else {
|
||||
strcpy(reply, "Error, expected cr4,cr5,cr8 or cr4,cr5,low,low");
|
||||
strcpy(reply, "Error, expected off or cr4,cr5,cr7,cr8");
|
||||
}
|
||||
} else if (memcmp(config, "owner.info ", 11) == 0) {
|
||||
config += 11;
|
||||
@@ -1516,7 +1550,7 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
savePrefs();
|
||||
formatDirectRetryCrThresholds(_prefs, reply);
|
||||
} else {
|
||||
strcpy(reply, "Error, expected cr4,cr5,cr8 or cr4,cr5,low,low");
|
||||
strcpy(reply, "Error, expected off or cr4,cr5,cr7,cr8");
|
||||
}
|
||||
} else if (memcmp(config, "owner.info ", 11) == 0) {
|
||||
config += 11;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
#define DIRECT_RETRY_CR4_MIN_SNR_X4_DEFAULT 40 // 10.0 dB and up => CR4
|
||||
#define DIRECT_RETRY_CR5_MIN_SNR_X4_DEFAULT 30 // 7.5 dB and up => CR5
|
||||
#define DIRECT_RETRY_CR7_MIN_SNR_X4_DEFAULT 10 // 2.5 dB and up => CR7
|
||||
#define DIRECT_RETRY_CR8_MAX_SNR_X4_DEFAULT 10 // 2.5 dB and down => CR8
|
||||
#define DIRECT_RETRY_CR_SNR_X4_MIN -128
|
||||
#define DIRECT_RETRY_CR_SNR_X4_MAX 127
|
||||
@@ -96,6 +97,7 @@ struct NodePrefs { // persisted to file
|
||||
uint16_t direct_retry_step_ms;
|
||||
int8_t direct_retry_cr4_snr_x4;
|
||||
int8_t direct_retry_cr5_snr_x4;
|
||||
int8_t direct_retry_cr7_snr_x4;
|
||||
int8_t direct_retry_cr8_snr_x4;
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user