Keep retry cancellation and radio recovery scoped to their owners
Cancel packets retained by the radio driver when their mesh retry is retired. Echo-confirmed delivery completes application replies; explicit cancellation releases failure references. Let active transmissions finish and prevent a cancelled packet from returning after a driver timeout. Preserve final direct-echo waits when only the other radio profile or crossover policy changes. Recover verified radio-profile settings from backup even when filesystem repair fails, and protect the backup after a failed save rollback. Add regressions for direct and flood cancellation, confirmed command replies, active TX completion and timeouts, subsequent packet cleanup, independent profile echo ownership, and storage rename/removal failures.
This commit is contained in:
1 parent
dde87f1d15
commit
e720132a8b
8 files changed
+274
-29
No files matched your search
+12
-17
@@ -306,7 +306,12 @@ void Mesh::loop() {
|
||||
for (int i = 0; i < TOTAL_DIRECT_RETRY_SLOTS; ++i) {
|
||||
if (!_direct_retries[i].active) continue;
|
||||
const auto* packet = _direct_retries[i].queued ? _direct_retries[i].packet : _direct_retries[i].trigger_packet;
|
||||
if (_direct_retries[i].waiting_final_echo || (packet && !isPacketRadioCurrent(packet))) retireDirectRetrySlot(i);
|
||||
// Final direct echoes retain metadata only. Their slot still identifies
|
||||
// the profile, so changing the other channel must not cancel the wait.
|
||||
const uint8_t profile = i / MAX_DIRECT_RETRY_SLOTS;
|
||||
if ((_direct_retries[i].waiting_final_echo
|
||||
&& _retry_radio_generations[profile] != p->generation[profile])
|
||||
|| (packet && !isPacketRadioCurrent(packet))) retireDirectRetrySlot(i);
|
||||
}
|
||||
for (int i = 0; i < TOTAL_FLOOD_RETRY_SLOTS; ++i) {
|
||||
if (!_flood_retries[i].active) continue;
|
||||
@@ -1443,12 +1448,13 @@ void Mesh::clearDirectRetrySlot(int idx) {
|
||||
if (rebuild_timeout) rebuildNextDirectRetryTimeout();
|
||||
}
|
||||
|
||||
void Mesh::retireDirectRetrySlot(int idx) {
|
||||
void Mesh::retireDirectRetrySlot(int idx, bool delivered) {
|
||||
if (idx < 0 || idx >= TOTAL_DIRECT_RETRY_SLOTS || !_direct_retries[idx].active) {
|
||||
return;
|
||||
}
|
||||
|
||||
Packet* retry = _direct_retries[idx].queued ? _direct_retries[idx].packet : NULL;
|
||||
cancelOutboundRadioRetry(retry ? retry : _direct_retries[idx].trigger_packet, delivered);
|
||||
if (retry != NULL && retry != getOutboundInFlight()) {
|
||||
for (int j = 0; j < _mgr->getOutboundTotal(); j++) {
|
||||
if (_mgr->getOutboundByIdx(j) != retry) continue;
|
||||
@@ -1627,18 +1633,6 @@ bool Mesh::cancelDirectRetryOnEcho(const Packet* packet) {
|
||||
onDirectRetryEvent("good", _direct_retries[i].packet, echo_millis, retry_attempt,
|
||||
_direct_retries[i].next_hop_hash, _direct_retries[i].next_hop_hash_len,
|
||||
_direct_retries[i].payload_type);
|
||||
if (_direct_retries[i].queued) {
|
||||
for (int j = 0; j < _mgr->getOutboundTotal(); j++) {
|
||||
if (_mgr->getOutboundByIdx(j) == _direct_retries[i].packet) {
|
||||
Packet* pending = _mgr->removeOutboundByIdx(j);
|
||||
if (pending) {
|
||||
releasePacket(pending);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
clearDirectRetrySlot(i);
|
||||
} else {
|
||||
if (_direct_retries[i].trigger_packet != NULL) {
|
||||
_direct_retries[i].trigger_packet->_snr = echo_snr_x4;
|
||||
@@ -1648,8 +1642,8 @@ bool Mesh::cancelDirectRetryOnEcho(const Packet* packet) {
|
||||
: (uint32_t)(_ms->getMillis() - _direct_retries[i].echo_wait_started_at);
|
||||
onDirectRetryEvent("good", _direct_retries[i].trigger_packet, echo_millis, _direct_retries[i].retry_attempts_sent + 1,
|
||||
_direct_retries[i].next_hop_hash, _direct_retries[i].next_hop_hash_len);
|
||||
clearDirectRetrySlot(i);
|
||||
}
|
||||
retireDirectRetrySlot(i, true);
|
||||
cleared = true;
|
||||
}
|
||||
|
||||
@@ -2045,12 +2039,13 @@ void Mesh::clearFloodRetrySlot(int idx) {
|
||||
if (rebuild_timeout) rebuildNextFloodRetryTimeout();
|
||||
}
|
||||
|
||||
void Mesh::retireFloodRetrySlot(int idx) {
|
||||
void Mesh::retireFloodRetrySlot(int idx, bool delivered) {
|
||||
if (idx < 0 || idx >= TOTAL_FLOOD_RETRY_SLOTS || !_flood_retries[idx].active) {
|
||||
return;
|
||||
}
|
||||
|
||||
Packet* retry = _flood_retries[idx].queued ? _flood_retries[idx].packet : NULL;
|
||||
cancelOutboundRadioRetry(retry ? retry : _flood_retries[idx].trigger_packet, delivered);
|
||||
if (retry != NULL && retry != getOutboundInFlight()) {
|
||||
for (int j = 0; j < _mgr->getOutboundTotal(); j++) {
|
||||
if (_mgr->getOutboundByIdx(j) != retry) continue;
|
||||
@@ -2479,7 +2474,7 @@ bool Mesh::cancelFloodRetryOnEcho(const Packet* packet) {
|
||||
: _flood_retries[i].retry_attempts_sent + 1;
|
||||
onFloodRetryEvent("good", packet, echo_millis, retry_attempt);
|
||||
|
||||
retireFloodRetrySlot(i);
|
||||
retireFloodRetrySlot(i, true);
|
||||
cleared = true;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user