fix(lora): skip DIO detach when no ISR is attached (#11386)

* fix(lora): skip DIO detach when no ISR is attached

Fixes #11371

* fix(lora): latch the ISR-armed flag instead of tracking attach state

The flag is now written once from task context and only read from ISR context.
This commit is contained in:
Thomas Göttgens
2026-08-10 12:39:25 +00:00
committed by GitHub
parent 512154ff97
commit 80d16234e5
11 files changed
+38 -18

No files matched your search

+1 -1
View File
@@ -318,7 +318,7 @@ template <typename T> bool LR11x0Interface<T>::reconfigure()
return true;
}
template <typename T> void LR11x0Interface<T>::disableInterrupt()
template <typename T> void LR11x0Interface<T>::clearRadioIsr()
{
lora.clearIrqAction();
}
+2 -2
View File
@@ -47,12 +47,12 @@ template <class T> class LR11x0Interface : public RadioLibInterface
/**
* Glue functions called from ISR land
*/
virtual void disableInterrupt() override;
virtual void clearRadioIsr() override;
/**
* Enable a particular ISR callback glue function
*/
virtual void enableInterrupt(void (*callback)()) { lora.setIrqAction(callback); }
virtual void setRadioIsr(void (*callback)()) override { lora.setIrqAction(callback); }
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() override;
+1 -1
View File
@@ -323,7 +323,7 @@ template <typename T> bool LR20x0Interface<T>::reconfigure()
return success;
}
template <typename T> void LR20x0Interface<T>::disableInterrupt()
template <typename T> void LR20x0Interface<T>::clearRadioIsr()
{
lora.clearIrqAction();
}
+2 -2
View File
@@ -42,12 +42,12 @@ template <class T> class LR20x0Interface : public RadioLibInterface
/**
* Glue functions called from ISR land
*/
virtual void disableInterrupt() override;
virtual void clearRadioIsr() override;
/**
* Enable a particular ISR callback glue function
*/
virtual void enableInterrupt(void (*callback)()) { lora.setIrqAction(callback); }
virtual void setRadioIsr(void (*callback)()) override { lora.setIrqAction(callback); }
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() override;
+1 -1
View File
@@ -201,7 +201,7 @@ bool RF95Interface::init()
return res == RADIOLIB_ERR_NONE;
}
void RF95Interface::disableInterrupt()
void RF95Interface::clearRadioIsr()
{
lora->clearDio0Action();
}
+2 -2
View File
@@ -35,14 +35,14 @@ class RF95Interface : public RadioLibInterface
/**
* Glue functions called from ISR land
*/
virtual void disableInterrupt() override;
virtual void clearRadioIsr() override;
int16_t getCurrentRSSI() override;
/**
* Enable a particular ISR callback glue function
*/
virtual void enableInterrupt(void (*callback)()) { lora->setDio0Action(callback, RISING); }
virtual void setRadioIsr(void (*callback)()) override { lora->setDio0Action(callback, RISING); }
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() override;
+22 -2
View File
@@ -99,6 +99,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
bool isReceiving = false;
/// has the radio IRQ ever been armed? latches true and is never cleared, so ISR context only reads it
volatile bool isrEverArmed = false;
protected:
// Noise floor tracking - rolling window of samples.
static const uint8_t NOISE_FLOOR_SAMPLES = 20;
@@ -144,13 +147,26 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
/**
* Glue functions called from ISR land
*
* Skip the detach until the IRQ has been armed once: the first setStandby() runs before any
* enableInterrupt(), and ESP-IDF logs "GPIO isr service is not installed" for that call.
*/
virtual void disableInterrupt() = 0;
void disableInterrupt()
{
if (!isrEverArmed)
return;
clearRadioIsr();
}
/**
* Enable a particular ISR callback glue function
*/
virtual void enableInterrupt(void (*)()) = 0;
void enableInterrupt(void (*callback)())
{
// Latch before arming: the ISR can fire the moment the handler is installed.
isrEverArmed = true;
setRadioIsr(callback);
}
/**
* Poll as a backup to catch missed edge-triggered interrupts.
@@ -300,6 +316,10 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0;
/** Chip specific arm/disarm of the radio IRQ; call enableInterrupt()/disableInterrupt() instead */
virtual void setRadioIsr(void (*callback)()) = 0;
virtual void clearRadioIsr() = 0;
/**
* Subclasses must override, implement and then call into this base class implementation
*/
+2 -2
View File
@@ -250,7 +250,7 @@ template <typename T> int16_t SX126xInterface<T>::getCurrentRSSI()
return (int16_t)round(rssi);
}
template <typename T> void SX126xInterface<T>::enableInterrupt(void (*callback)())
template <typename T> void SX126xInterface<T>::setRadioIsr(void (*callback)())
{
#ifdef LORA_DIO1_SOFTWARE_POLL
irqPollingActive = true;
@@ -261,7 +261,7 @@ template <typename T> void SX126xInterface<T>::enableInterrupt(void (*callback)(
#endif
}
template <typename T> void SX126xInterface<T>::disableInterrupt()
template <typename T> void SX126xInterface<T>::clearRadioIsr()
{
#ifdef LORA_DIO1_SOFTWARE_POLL
irqPollingActive = false;
+2 -2
View File
@@ -47,12 +47,12 @@ template <class T> class SX126xInterface : public RadioLibInterface
/**
* Glue functions called from ISR land
*/
virtual void disableInterrupt() override;
virtual void clearRadioIsr() override;
/**
* Enable a particular ISR callback glue function
*/
virtual void enableInterrupt(void (*callback)()) override;
virtual void setRadioIsr(void (*callback)()) override;
#ifdef LORA_DIO1_SOFTWARE_POLL
void handleSoftwareLoraIrqPoll() override;
+1 -1
View File
@@ -156,7 +156,7 @@ template <typename T> bool SX128xInterface<T>::reconfigure()
return true;
}
template <typename T> void SX128xInterface<T>::disableInterrupt()
template <typename T> void SX128xInterface<T>::clearRadioIsr()
{
lora.clearDio1Action();
}
+2 -2
View File
@@ -43,12 +43,12 @@ template <class T> class SX128xInterface : public RadioLibInterface
/**
* Glue functions called from ISR land
*/
virtual void disableInterrupt() override;
virtual void clearRadioIsr() override;
/**
* Enable a particular ISR callback glue function
*/
virtual void enableInterrupt(void (*callback)()) { lora.setDio1Action(callback); }
virtual void setRadioIsr(void (*callback)()) override { lora.setDio1Action(callback); }
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() override;