Update LoRa firmware on Thinknode M7 (#11337)

This commit is contained in:
Jonathan Bennett 2026-08-04 06:03:30 -07:00 committed by GitHub
parent b026bfbd98
commit 7302db1672
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 3 deletions

View file

@ -4,6 +4,25 @@
#include "configuration.h"
#include "error.h"
#include "mesh/NodeDB.h"
// A variant may define LR11X0_UPDATE_FIRMWARE_TO to a Semtech transceiver firmware version (e.g. 0x0402) to
// bake that image in and update the radio on first boot. Every supported image is 61320 words, so this costs
// ~240 kB of flash regardless of the version chosen - only enable it on a variant with the headroom, and
// only for as long as it takes to update the affected units.
#ifdef LR11X0_UPDATE_FIRMWARE_TO
#if LR11X0_UPDATE_FIRMWARE_TO == 0x0402
#define RADIOLIB_LR1110_FIRMWARE_0402
#elif LR11X0_UPDATE_FIRMWARE_TO == 0x0401
#define RADIOLIB_LR1110_FIRMWARE_0401
#elif LR11X0_UPDATE_FIRMWARE_TO == 0x0307
#define RADIOLIB_LR1110_FIRMWARE_0307
#else
// Note: RadioLib ships lr1110_transceiver_0308.h but has no selector for it in LR11x0_firmware.h.
#error "LR11X0_UPDATE_FIRMWARE_TO must be one of 0x0307, 0x0401, 0x0402"
#endif
#include <modules/LR11x0/LR11x0_firmware.h>
#endif
#ifdef LR11X0_DIO_AS_RF_SWITCH
#include "rfswitch.h"
#elif ARCH_PORTDUINO
@ -117,14 +136,59 @@ template <typename T> bool LR11x0Interface<T>::init()
// \todo Display actual typename of the adapter, not just `LR11x0`
LOG_INFO("LR11x0 init result %d", res);
if (res == RADIOLIB_ERR_CHIP_NOT_FOUND || res == RADIOLIB_ERR_SPI_CMD_FAILED)
return false;
if (res == RADIOLIB_ERR_CHIP_NOT_FOUND || res == RADIOLIB_ERR_SPI_CMD_FAILED) {
#ifdef LR11X0_UPDATE_FIRMWARE_TO
// An interrupted update leaves the radio sitting in bootloader mode, where begin() fails. Retry the
// flash from here rather than giving up, otherwise the device could never recover on its own.
LOG_WARN("LR11x0 did not start; attempting firmware recovery in case an update was interrupted");
if (lora.updateFirmware(lr11xx_firmware_image, LR11XX_FIRMWARE_IMAGE_SIZE, true) == RADIOLIB_ERR_NONE) {
LOG_INFO("LR1110 firmware recovery succeeded, re-initializing radio");
res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
}
#endif
if (res != RADIOLIB_ERR_NONE)
return false;
}
LR11x0VersionInfo_t version;
res = lora.getVersionInfo(&version);
if (res == RADIOLIB_ERR_NONE)
if (res == RADIOLIB_ERR_NONE) {
LOG_DEBUG("LR11x0 Device %d, HW %d, FW %d.%d, WiFi %d.%d, GNSS %d.%d", version.device, version.hardware, version.fwMajor,
version.fwMinor, version.fwMajorWiFi, version.fwMinorWiFi, version.fwGNSS, version.almanacGNSS);
transceiverFw = ((uint16_t)version.fwMajor << 8) | version.fwMinor;
transceiverDevice = version.device;
}
#ifdef LR11X0_UPDATE_FIRMWARE_TO
// One-shot transceiver firmware update, opt-in per variant. Only runs when the part is an LR1110 running
// older firmware than the baked-in image, so once it has succeeded it is a no-op on subsequent boots.
if (transceiverDevice == RADIOLIB_LR11X0_DEVICE_LR1110 && transceiverFw != 0 && transceiverFw < LR11X0_UPDATE_FIRMWARE_TO) {
LOG_WARN("LR1110 transceiver FW %d.%d is older than %d.%d - updating now. DO NOT POWER OFF: this "
"erases and rewrites the radio's own flash.",
transceiverFw >> 8, transceiverFw & 0xFF, LR11X0_UPDATE_FIRMWARE_TO >> 8, LR11X0_UPDATE_FIRMWARE_TO & 0xFF);
int upd = lora.updateFirmware(lr11xx_firmware_image, LR11XX_FIRMWARE_IMAGE_SIZE, true);
if (upd != RADIOLIB_ERR_NONE) {
// The radio is likely sitting in bootloader mode. It is not bricked - the update is retried on
// the next boot because the version check above will still see old (or unreadable) firmware.
LOG_ERROR("LR1110 firmware update FAILED %s%d - power-cycle to retry", radioLibErr, upd);
return false;
}
LOG_INFO("LR1110 firmware update complete, re-initializing radio");
res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
if (res != RADIOLIB_ERR_NONE) {
LOG_ERROR("LR11x0 re-init after firmware update failed %s%d", radioLibErr, res);
return false;
}
if (lora.getVersionInfo(&version) == RADIOLIB_ERR_NONE) {
transceiverFw = ((uint16_t)version.fwMajor << 8) | version.fwMinor;
transceiverDevice = version.device;
LOG_INFO("LR1110 now running transceiver FW %d.%d", version.fwMajor, version.fwMinor);
}
}
#endif
LOG_INFO("Frequency set to %f", getFreq());
LOG_INFO("Bandwidth set to %f", bw);

View file

@ -39,6 +39,11 @@ template <class T> class LR11x0Interface : public RadioLibInterface
int16_t getCurrentRSSI() override;
/// Transceiver firmware version as (major << 8 | minor), and which LR11x0 part this is. Captured at
/// init() from getVersionInfo(); 0 if the query failed.
uint16_t transceiverFw = 0;
uint8_t transceiverDevice = 0;
/**
* Glue functions called from ISR land
*/

View file

@ -33,6 +33,14 @@
#define LR11X0_DIO3_TCXO_VOLTAGE 1.8
#define LR11X0_DIO_AS_RF_SWITCH
// TEMPORARY: units shipped with LR1110 transceiver FW 0x0303 (the original 2020 release), which cannot
// reliably demodulate 500 kHz LoRa - Turbo presets fail RX with ~41% byte errors while TX and narrower
// bandwidths are fine. 0x0303 also predates GetLoRaRxHeaderInfos, which computePacketTime() calls on every
// received packet. Confirmed fixed by updating to 0x0307; targeting 0x0402 additionally picks up the
// out-of-band emission fix for consecutive LoRa transmissions (0x0401) and three CVE fixes (0x0402).
// Costs ~240 kB of flash. Remove once the affected units are updated.
#define LR11X0_UPDATE_FIRMWARE_TO 0x0402
#define HAS_ETHERNET 1
#define USE_CH390D 1