mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-13 22:32:27 +00:00
Compare commits
3 Commits
cc4c41167c
...
adaptive-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
901a91bd89 | ||
|
|
6249fc6917 | ||
|
|
4be400fceb |
@@ -303,4 +303,16 @@ template <typename T> bool LR11x0Interface<T>::sleep()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> bool LR11x0Interface<T>::setRadioCodingRate(uint8_t cr)
|
||||
{
|
||||
int state = lora.setCodingRate(cr);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
LOG_WARN("Failed to set coding rate to 4/%d, error %d", cr, state);
|
||||
return false;
|
||||
}
|
||||
LOG_DEBUG("Set coding rate to 4/%d", cr);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -65,5 +65,8 @@ template <class T> class LR11x0Interface : public RadioLibInterface
|
||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
||||
|
||||
virtual void setStandby() override;
|
||||
|
||||
/// Efficient method to set coding rate without full reconfiguration
|
||||
virtual bool setRadioCodingRate(uint8_t cr) override;
|
||||
};
|
||||
#endif
|
||||
@@ -221,6 +221,14 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key)
|
||||
auto old = findPendingPacket(key);
|
||||
if (old) {
|
||||
auto p = old->packet;
|
||||
|
||||
// Restore original coding rate since retransmissions are no longer needed
|
||||
if (iface) {
|
||||
if (iface->restoreOriginalCodingRate()) {
|
||||
LOG_DEBUG("Restored default CR after successful ACK for packet 0x%x", p->id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue
|
||||
to avoid canceling a transmission if it was ACKed super fast via MQTT */
|
||||
if (old->numRetransmissions < NUM_RELIABLE_RETX - 1) {
|
||||
@@ -280,6 +288,11 @@ int32_t NextHopRouter::doRetransmissions()
|
||||
// FIXME, handle 51 day rolloever here!!!
|
||||
if (p.nextTxMsec <= now) {
|
||||
if (p.numRetransmissions == 0) {
|
||||
// Final failure - restore original coding rate before giving up
|
||||
if (iface) {
|
||||
iface->restoreOriginalCodingRate();
|
||||
}
|
||||
|
||||
if (isFromUs(p.packet)) {
|
||||
LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x", p.packet->from, p.packet->to,
|
||||
p.packet->id);
|
||||
@@ -292,6 +305,23 @@ int32_t NextHopRouter::doRetransmissions()
|
||||
LOG_DEBUG("Sending retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d", p.packet->from, p.packet->to,
|
||||
p.packet->id, p.numRetransmissions);
|
||||
|
||||
// Calculate retry count (NUM_RELIABLE_RETX-1 = 2 initially, counts down)
|
||||
uint8_t retryCount = (NUM_RELIABLE_RETX - 1) - p.numRetransmissions;
|
||||
|
||||
LOG_DEBUG("Retransmit packet id=0x%x, numRetransmissions=%d, retryCount=%d", p.packet->id, p.numRetransmissions,
|
||||
retryCount);
|
||||
|
||||
// Apply adaptive coding rate for better reliability on retries
|
||||
bool adaptiveCrApplied = false;
|
||||
if (iface) {
|
||||
adaptiveCrApplied = iface->setAdaptiveCodingRate(retryCount);
|
||||
if (adaptiveCrApplied) {
|
||||
LOG_INFO("Applied adaptive coding rate for retry %d", retryCount);
|
||||
} else {
|
||||
LOG_DEBUG("No adaptive coding rate change needed for retry %d", retryCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBroadcast(p.packet->to)) {
|
||||
if (p.numRetransmissions == 1) {
|
||||
// Last retransmission, reset next_hop (fallback to FloodingRouter)
|
||||
@@ -312,7 +342,7 @@ int32_t NextHopRouter::doRetransmissions()
|
||||
FloodingRouter::send(packetPool.allocCopy(*p.packet));
|
||||
}
|
||||
|
||||
// Queue again
|
||||
// Queue again for next retry
|
||||
--p.numRetransmissions;
|
||||
setNextTx(&p);
|
||||
}
|
||||
|
||||
@@ -337,4 +337,17 @@ bool RF95Interface::sleep()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RF95Interface::setRadioCodingRate(uint8_t cr)
|
||||
{
|
||||
// Direct hardware call for efficient coding rate change
|
||||
int state = lora->setCodingRate(cr);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
LOG_WARN("Failed to set coding rate to 4/%d, error %d", cr, state);
|
||||
return false;
|
||||
}
|
||||
LOG_DEBUG("Set coding rate to 4/%d", cr);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -65,6 +65,9 @@ class RF95Interface : public RadioLibInterface
|
||||
*/
|
||||
virtual void configHardwareForSend() override;
|
||||
|
||||
/// Efficient method to set coding rate without full reconfiguration
|
||||
virtual bool setRadioCodingRate(uint8_t cr) override;
|
||||
|
||||
private:
|
||||
/** Some boards require GPIO control of tx vs rx paths */
|
||||
void setTransmitEnable(bool txon);
|
||||
|
||||
@@ -529,7 +529,7 @@ void RadioInterface::applyModemConfig()
|
||||
cr = 5;
|
||||
sf = 10;
|
||||
break;
|
||||
default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal.
|
||||
default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default
|
||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
||||
cr = 5;
|
||||
sf = 11;
|
||||
@@ -563,6 +563,7 @@ void RadioInterface::applyModemConfig()
|
||||
if (bw == 1600)
|
||||
bw = 1625.0;
|
||||
}
|
||||
originalCr = cr;
|
||||
|
||||
if ((myRegion->freqEnd - myRegion->freqStart) < bw / 1000) {
|
||||
static const char *err_string = "Regional frequency range is smaller than bandwidth. Fall back to default preset";
|
||||
@@ -636,6 +637,10 @@ void RadioInterface::applyModemConfig()
|
||||
LOG_INFO("channel_num: %d", channel_num + 1);
|
||||
LOG_INFO("frequency: %f", getFreq());
|
||||
LOG_INFO("Slot time: %u msec", slotTimeMsec);
|
||||
|
||||
// Save the original coding rate for potential adaptive retransmissions
|
||||
originalCr = cr;
|
||||
LOG_DEBUG("Default coding rate: 4/%d", originalCr);
|
||||
}
|
||||
|
||||
/** Slottime is the time to detect a transmission has started, consisting of:
|
||||
@@ -724,3 +729,65 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
|
||||
sendingPacket = p;
|
||||
return p->encrypted.size + sizeof(PacketHeader);
|
||||
}
|
||||
|
||||
bool RadioInterface::setAdaptiveCodingRate(uint8_t retryCount)
|
||||
{
|
||||
// Save original coding rate if this is the first retry
|
||||
if (retryCount == 0) {
|
||||
originalCr = cr;
|
||||
}
|
||||
|
||||
// Progressive coding rate adaptation for better reliability
|
||||
// Calculate the target coding rate based on retry count
|
||||
uint8_t newCr;
|
||||
|
||||
if (originalCr == 5) {
|
||||
// Special progression for default CR 5: 5 -> 7 -> 8 -> 8 (skip 6)
|
||||
switch (retryCount) {
|
||||
case 0:
|
||||
newCr = 7;
|
||||
break; // Skip 6, go to 7
|
||||
case 1:
|
||||
newCr = 8;
|
||||
break; // Maximum robustness
|
||||
case 2:
|
||||
newCr = 8;
|
||||
break; // Stay at maximum
|
||||
default:
|
||||
newCr = 8;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Standard progression for other coding rates
|
||||
newCr = originalCr + retryCount + 1;
|
||||
// Clamp to maximum coding rate of 8
|
||||
if (newCr > 8) {
|
||||
newCr = 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the calculated coding rate for this retry
|
||||
LOG_INFO("Adaptive coding rate: retry %d, changing CR from 4/%d to 4/%d", retryCount, cr, newCr);
|
||||
cr = newCr;
|
||||
// Use the more efficient direct coding rate change method if available
|
||||
return setRadioCodingRate(cr);
|
||||
}
|
||||
|
||||
bool RadioInterface::restoreOriginalCodingRate()
|
||||
{
|
||||
if (cr != originalCr) {
|
||||
LOG_INFO("Restoring original coding rate from 4/%d to 4/%d", cr, originalCr);
|
||||
cr = originalCr;
|
||||
// Use the more efficient direct coding rate change method if available
|
||||
return setRadioCodingRate(cr);
|
||||
}
|
||||
|
||||
return false; // No change made
|
||||
}
|
||||
|
||||
bool RadioInterface::setRadioCodingRate(uint8_t cr)
|
||||
{
|
||||
// Default implementation falls back to full reconfigure
|
||||
// Subclasses should override this for more efficient direct coding rate changes
|
||||
return reconfigure();
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ class RadioInterface
|
||||
float bw = 125;
|
||||
uint8_t sf = 9;
|
||||
uint8_t cr = 5;
|
||||
uint8_t originalCr = cr; // Store original coding rate for restoration after adaptive retransmissions
|
||||
|
||||
const uint8_t NUM_SYM_CAD = 2; // Number of symbols used for CAD, 2 is the default since RadioLib 6.3.0 as per AN1200.48
|
||||
const uint8_t NUM_SYM_CAD_24GHZ = 4; // Number of symbols used for CAD in 2.4 GHz, 4 is recommended in AN1200.22 of SX1280
|
||||
@@ -156,6 +157,14 @@ class RadioInterface
|
||||
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
|
||||
virtual bool findInTxQueue(NodeNum from, PacketId id) { return false; }
|
||||
|
||||
/**
|
||||
* Get the frequency we saved.
|
||||
*/
|
||||
virtual float getFreq();
|
||||
|
||||
// Whether we use the default frequency slot given our LoRa config (region and modem preset)
|
||||
static bool uses_default_frequency_slot;
|
||||
|
||||
// methods from radiohead
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
@@ -203,24 +212,39 @@ class RadioInterface
|
||||
* @return num msecs for the packet
|
||||
*/
|
||||
uint32_t getPacketTime(const meshtastic_MeshPacket *p);
|
||||
uint32_t getPacketTime(uint32_t totalPacketLen);
|
||||
|
||||
uint32_t getPacketTime(uint32_t payloadSize);
|
||||
|
||||
/**
|
||||
* Adaptive coding rate for retransmissions
|
||||
* Set a more robust coding rate for better reliability on retries
|
||||
* @param retryCount How many retries this is (0 = first retry, 1 = second retry, etc.)
|
||||
* @return true if coding rate was changed and radio was reconfigured
|
||||
*/
|
||||
virtual bool setAdaptiveCodingRate(uint8_t retryCount);
|
||||
|
||||
/**
|
||||
* Restore the original coding rate after adaptive transmission
|
||||
* @return true if coding rate was restored and radio was reconfigured
|
||||
*/
|
||||
virtual bool restoreOriginalCodingRate();
|
||||
|
||||
/**
|
||||
* Set the radio coding rate directly (more efficient than full reconfigure)
|
||||
* @param cr Coding rate (5-8, representing 4/5 to 4/8)
|
||||
* @return true if coding rate was set successfully
|
||||
*/
|
||||
virtual bool setRadioCodingRate(uint8_t cr);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Get the channel we saved.
|
||||
*/
|
||||
uint32_t getChannelNum();
|
||||
|
||||
/**
|
||||
* Get the frequency we saved.
|
||||
*/
|
||||
virtual float getFreq();
|
||||
|
||||
/// Some boards (1st gen Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
||||
virtual bool isIRQPending() { return false; }
|
||||
|
||||
// Whether we use the default frequency slot given our LoRa config (region and modem preset)
|
||||
static bool uses_default_frequency_slot;
|
||||
|
||||
protected:
|
||||
int8_t power = 17; // Set by applyModemConfig()
|
||||
|
||||
|
||||
@@ -552,4 +552,11 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
|
||||
|
||||
return res == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool RadioLibInterface::setRadioCodingRate(uint8_t cr)
|
||||
{
|
||||
// Default implementation just calls reconfigure()
|
||||
// Subclasses should override this for more efficient direct coding rate changes
|
||||
return reconfigure();
|
||||
}
|
||||
@@ -204,6 +204,15 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
*/
|
||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0;
|
||||
|
||||
/**
|
||||
* Set the coding rate on the radio hardware directly
|
||||
* Base implementation just calls reconfigure(), but subclasses should override
|
||||
* for more efficient direct coding rate changes
|
||||
* @param cr The coding rate to set (5-8 for 4/5 to 4/8)
|
||||
* @return true if successful
|
||||
*/
|
||||
virtual bool setRadioCodingRate(uint8_t cr);
|
||||
|
||||
/**
|
||||
* Subclasses must override, implement and then call into this base class implementation
|
||||
*/
|
||||
|
||||
@@ -371,4 +371,16 @@ template <typename T> void SX126xInterface<T>::setTransmitEnable(bool txon)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T> bool SX126xInterface<T>::setRadioCodingRate(uint8_t cr)
|
||||
{
|
||||
// Direct hardware call for efficient coding rate change
|
||||
int state = lora.setCodingRate(cr);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
LOG_WARN("Failed to set coding rate to 4/%d, error %d", cr, state);
|
||||
return false;
|
||||
}
|
||||
LOG_DEBUG("Set coding rate to 4/%d", cr);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -72,6 +72,9 @@ template <class T> class SX126xInterface : public RadioLibInterface
|
||||
|
||||
virtual void setStandby() override;
|
||||
|
||||
/// Efficient method to set coding rate without full reconfiguration
|
||||
virtual bool setRadioCodingRate(uint8_t cr) override;
|
||||
|
||||
private:
|
||||
/** Some boards require GPIO control of tx vs rx paths */
|
||||
void setTransmitEnable(bool txon);
|
||||
|
||||
@@ -322,4 +322,17 @@ template <typename T> bool SX128xInterface<T>::sleep()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> bool SX128xInterface<T>::setRadioCodingRate(uint8_t cr)
|
||||
{
|
||||
// Direct hardware call for efficient coding rate change
|
||||
int state = lora.setCodingRate(cr);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
LOG_WARN("Failed to set coding rate to 4/%d, error %d", cr, state);
|
||||
return false;
|
||||
}
|
||||
LOG_DEBUG("Set coding rate to 4/%d", cr);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -67,4 +67,7 @@ template <class T> class SX128xInterface : public RadioLibInterface
|
||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
||||
|
||||
virtual void setStandby() override;
|
||||
|
||||
/// Efficient method to set coding rate without full reconfiguration
|
||||
virtual bool setRadioCodingRate(uint8_t cr) override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user