Merge meshcore-dev dev with routing, WiFi and power-policy compatibility

Integrate upstream 1.18.0, delayed direct ACK forwarding, zero-scope routing, Waveshare LR1121 and dynamic WiFi variants. Preserve fork chemistry-aware power management and bounded multi-interface UI; retain retry/dedup safety while adding upstream ACK delay. Qualify LR1121 band power and HP-only Morse handling with native regressions.
This commit is contained in:
mikecarper committed 2026-10-15 13:30:41 -07:00
commit 285267e3a1
32 files changed
+765 -27

No files matched your search

+6 -6
View File
@@ -1145,13 +1145,14 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
removePathPrefix(pkt, pkt->getPathHashCount());
} else if (self_id.isHashMatch(pkt->path, pkt->getPathHashSize()) || maybeShortCircuitDirect(pkt)) {
if (allowPacketForward(pkt)) {
const uint32_t d = getDirectRetransmitDelay(pkt);
if (pkt->getPayloadType() == PAYLOAD_TYPE_MULTIPART) {
return forwardMultipartDirect(pkt);
return forwardMultipartDirect(pkt, d);
} else if (pkt->getPayloadType() == PAYLOAD_TYPE_ACK) {
if (!_tables->wasSeen(pkt)) { // don't retransmit!
_tables->markSeen(pkt);
removePathPrefix(pkt, 1);
routeDirectRecvAcks(pkt, 0);
routeDirectRecvAcks(pkt, d);
}
return ACTION_RELEASE;
}
@@ -1163,7 +1164,6 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
&& hasValidEncryptedPayloadLength(pkt->payload_len, 2);
removePathPrefix(pkt, 1);
uint32_t d = getDirectRetransmitDelay(pkt);
maybeScheduleDirectRetry(pkt, 0, final_hop_retry);
return ACTION_RETRANSMIT_DELAYED(0, d); // Routed traffic is HIGHEST priority
}
@@ -1563,7 +1563,7 @@ DispatcherAction Mesh::routeRecvPacket(Packet* packet) {
return ACTION_RELEASE;
}
DispatcherAction Mesh::forwardMultipartDirect(Packet* pkt) {
DispatcherAction Mesh::forwardMultipartDirect(Packet* pkt, uint32_t delay_millis) {
if (pkt == NULL || pkt->payload_len < 1) {
return ACTION_RELEASE;
}
@@ -1580,7 +1580,7 @@ DispatcherAction Mesh::forwardMultipartDirect(Packet* pkt) {
tmp.payload_len = pkt->payload_len - 1;
memcpy(tmp.payload, &pkt->payload[1], tmp.payload_len);
removePathPrefix(&tmp, 1);
routeDirectRecvAcks(&tmp, ((uint32_t)remaining + 1) * 300); // expect multipart ACKs 300ms apart (x2)
routeDirectRecvAcks(&tmp, delay_millis + ((uint32_t)remaining + 1) * 300); // expect multipart ACKs 300ms apart (x2)
}
}
return ACTION_RELEASE;
@@ -1590,7 +1590,6 @@ void Mesh::routeDirectRecvAcks(Packet* packet, uint32_t delay_millis) {
if (!packet->isMarkedDoNotRetransmit()) {
uint8_t extra = getExtraAckTransmitCount();
while (extra > 0) {
delay_millis += getDirectRetransmitDelay(packet) + 300;
auto a1 = createMultiAck(packet->payload, packet->payload_len, extra);
if (a1) {
a1->radio_reply = false; // relayed ACK, not a local response
@@ -1599,6 +1598,7 @@ void Mesh::routeDirectRecvAcks(Packet* packet, uint32_t delay_millis) {
a1->header |= ROUTE_TYPE_DIRECT;
maybeScheduleDirectRetry(a1, 0);
sendPacket(a1, 0, delay_millis);
delay_millis += 300;
}
extra--;
}
+1 -1
View File
@@ -216,7 +216,7 @@ class Mesh : public Dispatcher {
void decayOtaRelayBackoff();
void serviceLoopMaintenance();
//void routeRecvAcks(Packet* packet, uint32_t delay_millis);
DispatcherAction forwardMultipartDirect(Packet* pkt);
DispatcherAction forwardMultipartDirect(Packet* pkt, uint32_t delay_millis);
protected:
// Roles with lazily persisted state can veto an OTA reset until that state
+1
View File
@@ -288,6 +288,7 @@ int RegionMap::getTransportKeysFor(const RegionEntry& src, TransportKey dest[],
}
RegionEntry* RegionMap::findMatch(const mesh::Packet* packet, uint8_t mask) {
if (packet->transport_codes[0] == 0) return &wildcard;
for (int i = 0; i < num_regions; i++) {
auto region = &regions[i];
if ((region->flags & mask) == 0) { // does region allow this? (per 'mask' param)
+29
View File
@@ -12,6 +12,8 @@ class CustomLR1121 : public LR1121 {
bool _headerSeen = false;
bool _rx_boosted = false;
LR11x0MorseRfSwitch _morse_rf_switch;
int8_t _txPower = 0;
bool _txPowerSet = false;
public:
CustomLR1121(Module *mod) : LR1121(mod) { }
@@ -70,6 +72,33 @@ class CustomLR1121 : public LR1121 {
return len;
}
using LR1121::setOutputPower;
using LR1121::setFrequency;
int16_t setOutputPower(int8_t power) override {
#ifdef LR1121_FORCE_HP_PA
const bool force_hp = true; // boards with only RFO_HP_LF wired: never select the LP PA
#else
const bool force_hp = false;
#endif
// clip to the active PA's range (HF PA tops out at 13 dBm) rather than fail and keep the other band's PA
int8_t clipped = power;
checkOutputPower(power, &clipped, force_hp);
int16_t state = LR1121::setOutputPower(clipped, force_hp);
if (state == RADIOLIB_ERR_NONE) {
_txPower = power;
_txPowerSet = true;
}
return state;
}
int16_t setFrequency(float freq) override {
int16_t state = LR1121::setFrequency(freq);
// PA selection depends on the band, and set radio / tempradio don't call setTxPower
if (state == RADIOLIB_ERR_NONE && _txPowerSet) state = setOutputPower(_txPower);
return state;
}
float getFreqMHz() const { return freqMHz; }
int16_t setRxBoostedGainMode(bool en) {
+11 -2
View File
@@ -54,8 +54,17 @@ protected:
if (!_board->prepareRadioFrequency(frequency_mhz)) return RADIOLIB_ERR_INVALID_FREQUENCY;
auto* radio = static_cast<CustomLR1121*>(_radio);
const int16_t status = radio->setFrequency(frequency_mhz);
return status == RADIOLIB_ERR_NONE
? radio->setOutputPower(_dbm_valid ? _cur_dbm : LORA_TX_POWER, false, 304) : status;
if (status != RADIOLIB_ERR_NONE) return status;
#ifdef LR1121_FORCE_HP_PA
const bool force_hp = true;
#else
const bool force_hp = false;
#endif
// Preserve the Morse ramp while honoring HP-only wiring and the HF PA's
// 13 dBm ceiling, just like the normal packet-power path.
int8_t clipped = _dbm_valid ? _cur_dbm : LORA_TX_POWER;
radio->checkOutputPower(clipped, &clipped, force_hp);
return radio->setOutputPower(clipped, force_hp, 304);
}
bool restoreCarrierWaveModem() override {
if (_morse_rx_fsk_mode) {