10#ifdef IOHOME_LR1121_FIRMWARE_UPDATE
12#include "esphome/core/application.h"
24constexpr uint32_t LR1121_UPDATER_RESET_PULSE_MS = 10;
27constexpr uint32_t LR1121_UPDATER_BOOTLOADER_ENTRY_WAIT_MS = 500;
30constexpr uint32_t LR1121_UPDATER_POST_ENTRY_SETTLE_MS = 100;
39constexpr uint32_t LR1121_UPDATER_POST_REBOOT_SETTLE_MS = 50;
54class BusyPinAsResetStrapGuard {
56 explicit BusyPinAsResetStrapGuard(InternalGPIOPin *busy_pin)
57 : busy_pin_(busy_pin), restore_flags_(busy_pin->get_flags()) {
58 this->busy_pin_->pin_mode(gpio::FLAG_OUTPUT);
59 this->busy_pin_->digital_write(
false);
61 ~BusyPinAsResetStrapGuard() { this->busy_pin_->pin_mode(this->restore_flags_); }
62 BusyPinAsResetStrapGuard(
const BusyPinAsResetStrapGuard &) =
delete;
63 BusyPinAsResetStrapGuard &operator=(
const BusyPinAsResetStrapGuard &) =
delete;
66 InternalGPIOPin *busy_pin_;
67 gpio::Flags restore_flags_;
72Lr1121FirmwareUpdater::Lr1121FirmwareUpdater(
SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *busy_pin)
73 : spi_(spi), rst_pin_(rst_pin), busy_pin_(busy_pin) {
78 this->rst_pin_->setup();
79 this->busy_pin_->setup();
82bool Lr1121FirmwareUpdater::wait_busy_(uint32_t timeout_ms) {
83 uint32_t
const start = millis();
84 while (this->busy_pin_->digital_read()) {
85 if (millis() - start > timeout_ms)
92bool Lr1121FirmwareUpdater::write_command_(uint16_t opcode,
const uint8_t *params,
size_t len,
93 uint32_t busy_timeout_ms) {
94 if (!this->wait_busy_(busy_timeout_ms))
96 this->spi_->spi_enable();
97 this->spi_->spi_write((opcode >> 8) & 0xFF);
98 this->spi_->spi_write(opcode & 0xFF);
99 for (
size_t i = 0; i < len; i++)
100 this->spi_->spi_write(params[i]);
101 this->spi_->spi_disable();
105bool Lr1121FirmwareUpdater::read_command_(uint16_t opcode,
const uint8_t *params,
size_t params_len, uint8_t *out,
106 size_t out_len, uint32_t busy_timeout_ms) {
107 if (!this->write_command_(opcode, params, params_len, busy_timeout_ms))
109 if (!this->wait_busy_(busy_timeout_ms))
111 this->spi_->spi_enable();
112 this->spi_->spi_read();
113 for (
size_t i = 0; i < out_len; i++)
114 out[i] = this->spi_->spi_read();
115 this->spi_->spi_disable();
119bool Lr1121FirmwareUpdater::read_normal_version(uint8_t &device_type, uint8_t &fw_major, uint8_t &fw_minor) {
120 uint8_t resp[4] = {0};
121 if (!this->read_command_(LR1121_UPDATER_CMD_GET_VERSION,
nullptr, 0, resp,
sizeof(resp),
122 LR1121_UPDATER_BUSY_TIMEOUT_MS))
126 device_type = resp[1];
132bool Lr1121FirmwareUpdater::enter_bootloader(uint8_t &type, uint16_t &bootloader_version) {
134 BusyPinAsResetStrapGuard
const busy_guard(this->busy_pin_);
135 this->rst_pin_->digital_write(
false);
136 delay(LR1121_UPDATER_RESET_PULSE_MS);
137 this->rst_pin_->digital_write(
true);
138 delay(LR1121_UPDATER_BOOTLOADER_ENTRY_WAIT_MS);
140 delay(LR1121_UPDATER_POST_ENTRY_SETTLE_MS);
142 return this->read_bootloader_version(type, bootloader_version);
145bool Lr1121FirmwareUpdater::read_bootloader_version(uint8_t &type, uint16_t &bootloader_version) {
146 uint8_t resp[4] = {0};
147 if (!this->read_command_(LR1121_UPDATER_CMD_GET_VERSION,
nullptr, 0, resp,
sizeof(resp),
148 LR1121_UPDATER_BUSY_TIMEOUT_MS))
154 bootloader_version = (
static_cast<uint16_t
>(resp[2]) << 8) | resp[3];
158#ifdef IOHOME_LR1121_BOOTLOADER_UPDATE
160bool Lr1121FirmwareUpdater::update_bootloader() {
161 if (!this->write_command_(LR1121_UPDATER_CMD_UPDATE_BOOTLOADER,
nullptr, 0, LR1121_UPDATER_BUSY_TIMEOUT_MS))
168 return this->wait_busy_(LR1121_UPDATER_BOOTLOADER_UPDATE_BUSY_TIMEOUT_MS);
171bool Lr1121FirmwareUpdater::read_updater_status(Lr1121UpdaterStatus &status) {
172 if (!this->wait_busy_(LR1121_UPDATER_BUSY_TIMEOUT_MS))
176 uint8_t data[6] = {0};
177 this->spi_->spi_enable();
178 for (
unsigned char &
byte : data)
179 byte = this->spi_->spi_read();
180 this->spi_->spi_disable();
183 status.interrupt_active = (data[0] & 0x01) != 0;
184 status.command_status =
static_cast<Lr1121UpdaterCommandStatus
>(data[0] >> 1);
185 status.running_from_flash = (data[1] & 0x01) != 0;
186 status.chip_mode =
static_cast<uint8_t
>((data[1] & 0x0F) >> 1);
187 status.reset_status =
static_cast<uint8_t
>((data[1] & 0xF0) >> 4);
188 status.irq_status = (
static_cast<uint32_t
>(data[2]) << 24) | (
static_cast<uint32_t
>(data[3]) << 16) |
189 (
static_cast<uint32_t
>(data[4]) << 8) |
static_cast<uint32_t
>(data[5]);
193bool Lr1121FirmwareUpdater::verify_bootloader(Lr1121BootloaderVerification &report) {
194 uint8_t resp[4] = {0};
195 if (!this->read_command_(LR1121_UPDATER_CMD_VERIFY_BOOTLOADER,
nullptr, 0, resp,
sizeof(resp),
196 LR1121_UPDATER_BUSY_TIMEOUT_MS))
201 const uint8_t check_byte = resp[0];
202 report.signature_verified = (check_byte & 0x01) != 0;
203 report.version_verified = (check_byte & 0x02) != 0;
204 report.use_case_verified = (check_byte & 0x04) != 0;
205 report.version_major_verified = (check_byte & 0x08) != 0;
206 report.version_minor_verified = (check_byte & 0x10) != 0;
207 report.anti_rollback_verified = (check_byte & 0x20) != 0;
208 report.use_case = resp[1];
209 report.version_major = resp[2];
210 report.version_minor = resp[3];
214bool Lr1121FirmwareUpdater::updater_reboot(
bool stay_in_bootloader) {
215 uint8_t
const param = stay_in_bootloader ? 0x03 : 0x00;
216 if (!this->write_command_(LR1121_UPDATER_CMD_UPDATER_REBOOT, ¶m, 1, LR1121_UPDATER_BUSY_TIMEOUT_MS))
221 delay(LR1121_UPDATER_POST_REBOOT_SETTLE_MS);
227bool Lr1121FirmwareUpdater::erase_flash() {
228 if (!this->write_command_(LR1121_UPDATER_CMD_ERASE_FLASH,
nullptr, 0, LR1121_UPDATER_BUSY_TIMEOUT_MS))
233 return this->wait_busy_(LR1121_UPDATER_ERASE_BUSY_TIMEOUT_MS);
236bool Lr1121FirmwareUpdater::write_image(
const uint32_t *image,
size_t word_count,
237 const std::function<
void(
size_t,
size_t)> &on_progress) {
239 while (written < word_count) {
240 size_t const chunk_words = std::min<size_t>(LR1121_UPDATER_FLASH_CHUNK_WORDS, word_count - written);
241 uint32_t
const offset_bytes =
static_cast<uint32_t
>(written *
sizeof(uint32_t));
243 uint8_t params[4 + LR1121_UPDATER_FLASH_CHUNK_WORDS * 4];
244 params[0] =
static_cast<uint8_t
>(offset_bytes >> 24);
245 params[1] =
static_cast<uint8_t
>(offset_bytes >> 16);
246 params[2] =
static_cast<uint8_t
>(offset_bytes >> 8);
247 params[3] =
static_cast<uint8_t
>(offset_bytes);
248 for (
size_t i = 0; i < chunk_words; i++) {
249 uint32_t
const word = image[written + i];
250 params[4 + i * 4 + 0] =
static_cast<uint8_t
>(word >> 24);
251 params[4 + i * 4 + 1] =
static_cast<uint8_t
>(word >> 16);
252 params[4 + i * 4 + 2] =
static_cast<uint8_t
>(word >> 8);
253 params[4 + i * 4 + 3] =
static_cast<uint8_t
>(word);
256 if (!this->write_command_(LR1121_UPDATER_CMD_WRITE_FLASH_ENCRYPTED, params, 4 + chunk_words * 4,
257 LR1121_UPDATER_BUSY_TIMEOUT_MS))
260 written += chunk_words;
265 on_progress(written, word_count);
270bool Lr1121FirmwareUpdater::read_hash(uint8_t *out,
size_t out_len) {
271 if (out_len < LR1121_UPDATER_HASH_LENGTH)
273 return this->read_command_(LR1121_UPDATER_CMD_GET_HASH,
nullptr, 0, out, LR1121_UPDATER_HASH_LENGTH,
274 LR1121_UPDATER_BUSY_TIMEOUT_MS);
277bool Lr1121FirmwareUpdater::reboot(
bool stay_in_bootloader) {
278 uint8_t
const param = stay_in_bootloader ? 0x03 : 0x00;
279 if (!this->write_command_(LR1121_UPDATER_CMD_REBOOT, ¶m, 1, LR1121_UPDATER_BUSY_TIMEOUT_MS))
287 delay(LR1121_UPDATER_POST_REBOOT_SETTLE_MS);
Interface for SPI bus access.
LR1121 bootloader-mode-*and*-loader-mode SPI transport, standalone from the running RadioDriver.