diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index 0e23405e5..40b29db72 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -181,6 +181,9 @@ template bool LR11x0Interface::reconfigure() err = lora.setOutputPower(power); assert(err == RADIOLIB_ERR_NONE); + // Initialize AGC/AFC reset timing (30 second interval) + nextAgcResetMs = millis() + THIRY_SECONDS_MS; + startReceive(); // restart receiving return RADIOLIB_ERR_NONE; diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index 0f32f3427..7ab6f2465 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -248,6 +248,9 @@ bool RF95Interface::reconfigure() if (err != RADIOLIB_ERR_NONE) RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING); + // Initialize AGC reset timing + nextAgcResetMs = millis() + 30000; + startReceive(); // restart receiving return RADIOLIB_ERR_NONE; diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 3717e8780..3d58a9caa 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -37,7 +37,7 @@ void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in) RadioLibInterface::RadioLibInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, PhysicalLayer *_iface) - : NotifiedWorkerThread("RadioIf"), module(hal, cs, irq, rst, busy), iface(_iface) + : NotifiedWorkerThread("RadioIf"), module(hal, cs, irq, rst, busy), iface(_iface), nextAgcResetMs(0) { instance = this; #if defined(ARCH_STM32WL) && defined(USE_SX1262) @@ -245,6 +245,9 @@ currently active. */ void RadioLibInterface::onNotify(uint32_t notification) { + // Check for AGC reset before processing notifications + checkAndPerformAgcReset(); + switch (notification) { case ISR_TX: handleTransmitInterrupt(); @@ -552,4 +555,46 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp) return res == RADIOLIB_ERR_NONE; } +} + +void RadioLibInterface::checkAndPerformAgcReset() +{ + // Use a sensible default of 30 seconds for AGC/AFC reset + // Based on MeshCore's approach and SX126x datasheet recommendations + static const uint32_t AGC_RESET_INTERVAL_MS = 30 * 1000U; + + uint32_t now = millis(); + + // Add debug info on first call or when nextAgcResetMs is not set + static bool first_call = true; + if (first_call || nextAgcResetMs == 0) { + LOG_DEBUG("AGC reset: now=%u, nextAgcResetMs=%u, first_call=%d", now, nextAgcResetMs, first_call); + first_call = false; + if (nextAgcResetMs == 0) { + // Initialize if not set by reconfigure() + nextAgcResetMs = now + AGC_RESET_INTERVAL_MS; + LOG_DEBUG("AGC reset initialized to %u", nextAgcResetMs); + } + } + + if (now < nextAgcResetMs) { + return; // Not time yet + } + + // Only reset if we're not actively sending, receiving, or processing packets + if (isSending() || isActivelyReceiving() || isReceiving) { + // Postpone reset by a short delay to avoid interfering with active operations + nextAgcResetMs = now + 1000; // Retry in 1 second + LOG_DEBUG("AGC reset postponed - radio busy"); + return; + } + + LOG_INFO("Performing AGC/AFC reset via startReceive()"); + + // Use MeshCore's approach: issue startReceive() to reset AGC/AFC + // This is cleaner than direct register manipulation and works across all radio types + startReceive(); + + // Schedule next reset + nextAgcResetMs = now + AGC_RESET_INTERVAL_MS; } \ No newline at end of file diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 3444b1a2c..651fc01c4 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -16,6 +16,8 @@ #define RADIOLIB_PIN_TYPE uint32_t +#define THIRY_SECONDS_MS 30000 + // In addition to the default Rx flags, we need the PREAMBLE_DETECTED flag to detect whether we are actively receiving #define MESHTASTIC_RADIOLIB_IRQ_RX_FLAGS (RADIOLIB_IRQ_RX_DEFAULT_FLAGS | (1 << RADIOLIB_IRQ_PREAMBLE_DETECTED)) @@ -181,8 +183,18 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified protected: uint32_t activeReceiveStart = 0; + /** Track when we should next perform an AGC/AFC reset */ + uint32_t nextAgcResetMs = 0; + bool receiveDetected(uint16_t irq, ulong syncWordHeaderValidFlag, ulong preambleDetectedFlag); + /** + * Perform AGC/AFC reset by issuing a startReceive() call if enough time has passed + * and we're not currently receiving or transmitting. + * Based on MeshCore's approach of using RadioLib startReceive() to reset AGC. + */ + void checkAndPerformAgcReset(); + /** Do any hardware setup needed on entry into send configuration for the radio. * Subclasses can customize, but must also call this base method */ virtual void configHardwareForSend(); diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 3fc2562b3..9ef9f13fe 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -228,6 +228,9 @@ template bool SX126xInterface::reconfigure() LOG_ERROR("SX126X setOutputPower %s%d", radioLibErr, err); assert(err == RADIOLIB_ERR_NONE); + // Initialize AGC/AFC reset timing (30 second interval) + nextAgcResetMs = millis() + THIRY_SECONDS_MS; + startReceive(); // restart receiving return RADIOLIB_ERR_NONE; diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index cbc98eeb1..a119c3d2a 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -150,6 +150,9 @@ template bool SX128xInterface::reconfigure() LOG_ERROR("SX128X setOutputPower %s%d", radioLibErr, err); assert(err == RADIOLIB_ERR_NONE); + // Initialize AGC/AFC reset timing (30 second interval) + nextAgcResetMs = millis() + THIRY_SECONDS_MS; + startReceive(); // restart receiving return RADIOLIB_ERR_NONE;