Retry 3 times with a 200ms,300ms,400ms backoff.

This commit is contained in:
mikecarper committed 2026-06-04 15:09:37 -07:00
1 parent 2af7b75d70
commit dbc4dda0ca
7 files changed
+236 -13

No files matched your search

+85
View File
@@ -77,6 +77,15 @@ const NeighbourInfo* MyMesh::findNeighbourByHash(const uint8_t* hash, uint8_t ha
return NULL;
}
bool MyMesh::allowRecentRepeaterPrefixStore(const uint8_t* prefix, uint8_t prefix_len, void* ctx) {
if (ctx == NULL || prefix == NULL || prefix_len == 0) {
return true;
}
const MyMesh* self = (const MyMesh*) ctx;
return self->findNeighbourByHash(prefix, prefix_len) == NULL;
}
void MyMesh::putNeighbour(const mesh::Identity &id, uint32_t timestamp, float snr) {
#if MAX_NEIGHBOURS // check if neighbours enabled
// find existing neighbour, else use least recently updated
@@ -510,6 +519,34 @@ void MyMesh::logTxFail(mesh::Packet *pkt, int len) {
}
}
void MyMesh::onDirectRetryEvent(const char* event, const mesh::Packet* packet, uint32_t delay_millis) {
if (packet == NULL) {
return;
}
MESH_DEBUG_PRINTLN("%s direct retry %s (type=%d, route=%s, payload_len=%d, delay=%lu)",
getLogDateTime(),
event,
(uint32_t)packet->getPayloadType(),
packet->isRouteDirect() ? "D" : "F",
(uint32_t)packet->payload_len,
(unsigned long)delay_millis);
if (_logging) {
File f = openAppend(PACKET_LOG_FILE);
if (f) {
f.print(getLogDateTime());
f.printf(": DIRECT RETRY %s (type=%d, route=%s, payload_len=%d, delay=%lu)\n",
event,
(uint32_t)packet->getPayloadType(),
packet->isRouteDirect() ? "D" : "F",
(uint32_t)packet->payload_len,
(unsigned long)delay_millis);
f.close();
}
}
}
int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
if (_prefs.rx_delay_base <= 0.0f) return 0;
return (int)((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time);
@@ -880,6 +917,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
active_bw = _prefs.bw;
active_sf = _prefs.sf;
active_cr = _prefs.cr;
((SimpleMeshTables *)getTables())->setRecentRepeaterAllowFilter(&MyMesh::allowRecentRepeaterPrefixStore, this);
}
void MyMesh::begin(FILESYSTEM *fs) {
@@ -901,6 +940,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
active_bw = _prefs.bw;
active_sf = _prefs.sf;
active_cr = _prefs.cr;
((SimpleMeshTables *)getTables())->setRecentRepeaterMinSNRX4(getDirectRetryMinSNRX4());
radio_set_tx_power(_prefs.tx_power_dbm);
updateAdvertTimer();
@@ -1250,6 +1290,48 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
} else {
strcpy(reply, "Err - ??");
}
} else if (memcmp(command, "recent.repeater", 15) == 0) {
const char* sub = command + 15;
while (*sub == ' ') sub++;
auto* tables = (SimpleMeshTables*)getTables();
if (*sub == 0) {
const auto* info = tables->getLatestRecentRepeater();
if (info == NULL) {
strcpy(reply, "> none");
} else {
char hex[(MAX_ROUTE_HASH_BYTES * 2) + 1];
mesh::Utils::toHex(hex, info->prefix, info->prefix_len);
sprintf(reply, "> %s,%s", hex, StrHelper::ftoa(((float)info->snr_x4) / 4.0f));
}
} else {
char* params = (char*) sub;
char* arg_snr = strchr(params, ' ');
if (arg_snr == NULL) {
strcpy(reply, "Err - usage: recent.repeater <prefix_hex> <snr_db>");
} else {
*arg_snr++ = 0;
while (*arg_snr == ' ') arg_snr++;
if (*arg_snr == 0) {
strcpy(reply, "Err - usage: recent.repeater <prefix_hex> <snr_db>");
} else {
int hex_len = strlen(params);
int prefix_len = hex_len / 2;
uint8_t prefix[MAX_ROUTE_HASH_BYTES] = {0};
if ((hex_len % 2) != 0 || prefix_len <= 0 || prefix_len > MAX_ROUTE_HASH_BYTES || !mesh::Utils::fromHex(prefix, prefix_len, params)) {
strcpy(reply, "Err - prefix must be 1-3 bytes hex");
} else {
float snr_db = strtof(arg_snr, nullptr);
int snr_x4 = (int)(snr_db * 4.0f + (snr_db >= 0.0f ? 0.5f : -0.5f));
snr_x4 = constrain(snr_x4, -128, 127);
if (tables->setRecentRepeater(prefix, (uint8_t)prefix_len, (int8_t)snr_x4)) {
strcpy(reply, "OK");
} else {
strcpy(reply, "Err - prefix is already in neighbors");
}
}
}
}
}
} else{
_cli.handleCommand(sender_timestamp, command, reply); // common CLI commands
}
@@ -1293,6 +1375,9 @@ void MyMesh::loop() {
MESH_DEBUG_PRINTLN("Radio params restored");
}
// Keep recent-prefix learning aligned with the live retry SNR gate.
((SimpleMeshTables *)getTables())->setRecentRepeaterMinSNRX4(getDirectRetryMinSNRX4());
// is pending dirty contacts write needed?
if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) {
acl.save(_fs);
+2
View File
@@ -119,6 +119,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
#endif
const NeighbourInfo* findNeighbourByHash(const uint8_t* hash, uint8_t hash_len) const;
static bool allowRecentRepeaterPrefixStore(const uint8_t* prefix, uint8_t prefix_len, void* ctx);
int8_t getDirectRetryMinSNRX4() const;
void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr);
uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data, bool is_flood);
@@ -148,6 +149,7 @@ protected:
uint32_t getDirectRetransmitDelay(const mesh::Packet* packet) override;
bool allowDirectRetry(const mesh::Packet* packet, const uint8_t* next_hop_hash, uint8_t next_hop_hash_len) const override;
uint32_t getDirectRetryEchoDelay(const mesh::Packet* packet) const override;
void onDirectRetryEvent(const char* event, const mesh::Packet* packet, uint32_t delay_millis) override;
int getInterferenceThreshold() const override {
return _prefs.interference_threshold;