10#ifdef IOHOME_LR1121_FIRMWARE_UPDATE
13#include "esphome/core/application.h"
25constexpr uint32_t LR1121_UPDATER_RESET_PULSE_MS = 10;
28constexpr uint32_t LR1121_UPDATER_BOOTLOADER_ENTRY_WAIT_MS = 500;
31constexpr uint32_t LR1121_UPDATER_POST_ENTRY_SETTLE_MS = 100;
40constexpr uint32_t LR1121_UPDATER_POST_REBOOT_SETTLE_MS = 50;
55class BusyPinAsResetStrapGuard {
57 explicit BusyPinAsResetStrapGuard(InternalGPIOPin *busy_pin)
58 : busy_pin_(busy_pin), restore_flags_(busy_pin->get_flags()) {
59 this->busy_pin_->pin_mode(gpio::FLAG_OUTPUT);
60 this->busy_pin_->digital_write(
false);
62 ~BusyPinAsResetStrapGuard() { this->busy_pin_->pin_mode(this->restore_flags_); }
63 BusyPinAsResetStrapGuard(
const BusyPinAsResetStrapGuard &) =
delete;
64 BusyPinAsResetStrapGuard &operator=(
const BusyPinAsResetStrapGuard &) =
delete;
67 InternalGPIOPin *busy_pin_;
68 gpio::Flags restore_flags_;
73Lr1121FirmwareUpdater::Lr1121FirmwareUpdater(
SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *busy_pin)
74 : spi_(spi), rst_pin_(rst_pin), busy_pin_(busy_pin) {
79 this->rst_pin_->setup();
80 this->busy_pin_->setup();
83bool Lr1121FirmwareUpdater::wait_busy_(uint32_t timeout_ms) {
84 return poll_until([
this] {
return !this->busy_pin_->digital_read(); }, timeout_ms).ready;
87bool Lr1121FirmwareUpdater::write_command_(uint16_t opcode,
const uint8_t *params,
size_t len,
88 uint32_t busy_timeout_ms) {
89 if (!this->wait_busy_(busy_timeout_ms))
91 this->spi_->spi_enable();
92 this->spi_->spi_write((opcode >> 8) & 0xFF);
93 this->spi_->spi_write(opcode & 0xFF);
94 for (
size_t i = 0; i < len; i++)
95 this->spi_->spi_write(params[i]);
96 this->spi_->spi_disable();
100bool Lr1121FirmwareUpdater::read_command_(uint16_t opcode,
const uint8_t *params,
size_t params_len, uint8_t *out,
101 size_t out_len, uint32_t busy_timeout_ms) {
102 if (!this->write_command_(opcode, params, params_len, busy_timeout_ms))
104 if (!this->wait_busy_(busy_timeout_ms))
106 this->spi_->spi_enable();
107 this->spi_->spi_read();
108 for (
size_t i = 0; i < out_len; i++)
109 out[i] = this->spi_->spi_read();
110 this->spi_->spi_disable();
114bool Lr1121FirmwareUpdater::read_normal_version(uint8_t &device_type, uint8_t &fw_major, uint8_t &fw_minor) {
115 uint8_t resp[4] = {0};
116 if (!this->read_command_(LR1121_UPDATER_CMD_GET_VERSION,
nullptr, 0, resp,
sizeof(resp),
117 LR1121_UPDATER_BUSY_TIMEOUT_MS))
121 device_type = resp[1];
127bool Lr1121FirmwareUpdater::enter_bootloader(uint8_t &type, uint16_t &bootloader_version) {
129 BusyPinAsResetStrapGuard
const busy_guard(this->busy_pin_);
130 this->rst_pin_->digital_write(
false);
131 delay(LR1121_UPDATER_RESET_PULSE_MS);
132 this->rst_pin_->digital_write(
true);
133 delay(LR1121_UPDATER_BOOTLOADER_ENTRY_WAIT_MS);
135 delay(LR1121_UPDATER_POST_ENTRY_SETTLE_MS);
137 return this->read_bootloader_version(type, bootloader_version);
140bool Lr1121FirmwareUpdater::read_bootloader_version(uint8_t &type, uint16_t &bootloader_version) {
141 uint8_t resp[4] = {0};
142 if (!this->read_command_(LR1121_UPDATER_CMD_GET_VERSION,
nullptr, 0, resp,
sizeof(resp),
143 LR1121_UPDATER_BUSY_TIMEOUT_MS))
149 bootloader_version = (
static_cast<uint16_t
>(resp[2]) << 8) | resp[3];
153#ifdef IOHOME_LR1121_BOOTLOADER_UPDATE
155bool Lr1121FirmwareUpdater::update_bootloader() {
156 if (!this->write_command_(LR1121_UPDATER_CMD_UPDATE_BOOTLOADER,
nullptr, 0, LR1121_UPDATER_BUSY_TIMEOUT_MS))
163 return this->wait_busy_(LR1121_UPDATER_BOOTLOADER_UPDATE_BUSY_TIMEOUT_MS);
166bool Lr1121FirmwareUpdater::read_updater_status(Lr1121UpdaterStatus &status) {
167 if (!this->wait_busy_(LR1121_UPDATER_BUSY_TIMEOUT_MS))
171 uint8_t data[6] = {0};
172 this->spi_->spi_enable();
173 for (
unsigned char &
byte : data)
174 byte = this->spi_->spi_read();
175 this->spi_->spi_disable();
178 status.interrupt_active = (data[0] & 0x01) != 0;
179 status.command_status =
static_cast<Lr1121UpdaterCommandStatus
>(data[0] >> 1);
180 status.running_from_flash = (data[1] & 0x01) != 0;
181 status.chip_mode =
static_cast<uint8_t
>((data[1] & 0x0F) >> 1);
182 status.reset_status =
static_cast<uint8_t
>((data[1] & 0xF0) >> 4);
183 status.irq_status = (
static_cast<uint32_t
>(data[2]) << 24) | (
static_cast<uint32_t
>(data[3]) << 16) |
184 (
static_cast<uint32_t
>(data[4]) << 8) |
static_cast<uint32_t
>(data[5]);
188bool Lr1121FirmwareUpdater::verify_bootloader(Lr1121BootloaderVerification &report) {
189 uint8_t resp[4] = {0};
190 if (!this->read_command_(LR1121_UPDATER_CMD_VERIFY_BOOTLOADER,
nullptr, 0, resp,
sizeof(resp),
191 LR1121_UPDATER_BUSY_TIMEOUT_MS))
196 const uint8_t check_byte = resp[0];
197 report.signature_verified = (check_byte & 0x01) != 0;
198 report.version_verified = (check_byte & 0x02) != 0;
199 report.use_case_verified = (check_byte & 0x04) != 0;
200 report.version_major_verified = (check_byte & 0x08) != 0;
201 report.version_minor_verified = (check_byte & 0x10) != 0;
202 report.anti_rollback_verified = (check_byte & 0x20) != 0;
203 report.use_case = resp[1];
204 report.version_major = resp[2];
205 report.version_minor = resp[3];
209bool Lr1121FirmwareUpdater::updater_reboot(
bool stay_in_bootloader) {
210 uint8_t
const param = stay_in_bootloader ? 0x03 : 0x00;
211 if (!this->write_command_(LR1121_UPDATER_CMD_UPDATER_REBOOT, ¶m, 1, LR1121_UPDATER_BUSY_TIMEOUT_MS))
216 delay(LR1121_UPDATER_POST_REBOOT_SETTLE_MS);
222bool Lr1121FirmwareUpdater::erase_flash() {
223 if (!this->write_command_(LR1121_UPDATER_CMD_ERASE_FLASH,
nullptr, 0, LR1121_UPDATER_BUSY_TIMEOUT_MS))
228 return this->wait_busy_(LR1121_UPDATER_ERASE_BUSY_TIMEOUT_MS);
231bool Lr1121FirmwareUpdater::write_image(
const uint32_t *image,
size_t word_count,
232 const std::function<
void(
size_t,
size_t)> &on_progress) {
234 while (written < word_count) {
235 size_t const chunk_words = std::min<size_t>(LR1121_UPDATER_FLASH_CHUNK_WORDS, word_count - written);
236 uint32_t
const offset_bytes =
static_cast<uint32_t
>(written *
sizeof(uint32_t));
238 uint8_t params[4 + LR1121_UPDATER_FLASH_CHUNK_WORDS * 4];
239 params[0] =
static_cast<uint8_t
>(offset_bytes >> 24);
240 params[1] =
static_cast<uint8_t
>(offset_bytes >> 16);
241 params[2] =
static_cast<uint8_t
>(offset_bytes >> 8);
242 params[3] =
static_cast<uint8_t
>(offset_bytes);
243 for (
size_t i = 0; i < chunk_words; i++) {
244 uint32_t
const word = image[written + i];
245 params[4 + i * 4 + 0] =
static_cast<uint8_t
>(word >> 24);
246 params[4 + i * 4 + 1] =
static_cast<uint8_t
>(word >> 16);
247 params[4 + i * 4 + 2] =
static_cast<uint8_t
>(word >> 8);
248 params[4 + i * 4 + 3] =
static_cast<uint8_t
>(word);
251 if (!this->write_command_(LR1121_UPDATER_CMD_WRITE_FLASH_ENCRYPTED, params, 4 + chunk_words * 4,
252 LR1121_UPDATER_BUSY_TIMEOUT_MS))
255 written += chunk_words;
260 on_progress(written, word_count);
265bool Lr1121FirmwareUpdater::read_hash(uint8_t *out,
size_t out_len) {
266 if (out_len < LR1121_UPDATER_HASH_LENGTH)
268 return this->read_command_(LR1121_UPDATER_CMD_GET_HASH,
nullptr, 0, out, LR1121_UPDATER_HASH_LENGTH,
269 LR1121_UPDATER_BUSY_TIMEOUT_MS);
272bool Lr1121FirmwareUpdater::reboot(
bool stay_in_bootloader) {
273 uint8_t
const param = stay_in_bootloader ? 0x03 : 0x00;
274 if (!this->write_command_(LR1121_UPDATER_CMD_REBOOT, ¶m, 1, LR1121_UPDATER_BUSY_TIMEOUT_MS))
282 delay(LR1121_UPDATER_POST_REBOOT_SETTLE_MS);
Interface for SPI bus access.
PollResult poll_until(Ready ready, uint32_t timeout_ms)
Poll ready() until it is true or timeout_ms has passed, feeding the watchdog between samples.
LR1121 bootloader-mode-*and*-loader-mode SPI transport, standalone from the running RadioDriver.
Preemption-safe "poll a condition until it holds or a deadline passes" helper.