From c304871e73978ab2b97317420ca80cc288eb4fba Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 13 Oct 2026 10:27:10 -1000 Subject: [PATCH] Read the device table in place with word-only fields instead of copying an entry --- .../shelly_dimmer/shelly_dimmer.cpp | 2 +- .../components/shelly_dimmer/stm32flash.cpp | 37 +++++++------------ esphome/components/shelly_dimmer/stm32flash.h | 18 +++++---- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.cpp b/esphome/components/shelly_dimmer/shelly_dimmer.cpp index 9ff913f46f4..eedf7ff7ce2 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.cpp +++ b/esphome/components/shelly_dimmer/shelly_dimmer.cpp @@ -176,7 +176,7 @@ bool ShellyDimmer::upgrade_firmware_() { uint8_t buffer[BUFFER_SIZE]; const uint8_t *p = STM_FIRMWARE; uint32_t offset = 0; - uint32_t addr = stm32->dev.fl_start; + uint32_t addr = stm32->dev->fl_start; const uint32_t end = addr + STM_FIRMWARE_SIZE_IN_BYTES; while (addr < end && offset < STM_FIRMWARE_SIZE_IN_BYTES) { diff --git a/esphome/components/shelly_dimmer/stm32flash.cpp b/esphome/components/shelly_dimmer/stm32flash.cpp index 0dab7b75f9c..c33876e4943 100644 --- a/esphome/components/shelly_dimmer/stm32flash.cpp +++ b/esphome/components/shelly_dimmer/stm32flash.cpp @@ -116,25 +116,18 @@ namespace esphome::shelly_dimmer { namespace { -uint32_t read_page_size(const uint32_t *psize) { - uint32_t size; - progmem_memcpy(&size, psize, sizeof(size)); - return size; -} - int flash_addr_to_page_ceil(const stm32_unique_ptr &stm, uint32_t addr) { - if (!(addr >= stm->dev.fl_start && addr <= stm->dev.fl_end)) + if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end)) return 0; int page = 0; - addr -= stm->dev.fl_start; - const auto *psize = stm->dev.fl_ps; + addr -= stm->dev->fl_start; + const auto *psize = stm->dev->fl_ps; - uint32_t size; - while (addr >= (size = read_page_size(psize))) { - addr -= size; + while (addr >= psize[0]) { + addr -= psize[0]; page++; - if (read_page_size(psize + 1)) + if (psize[1]) psize++; } @@ -644,16 +637,14 @@ stm32_unique_ptr stm32_init(uart::UARTDevice *stream, const uint8_t flags, const return make_stm32_with_deletor(nullptr); } - const stm32_dev_t *dev = DEVICES; - uint16_t id; - while ((id = progmem_read_uint16(&dev->id)) != 0x00 && id != stm->pid) - ++dev; + stm->dev = DEVICES; + while (stm->dev->id != 0x00 && stm->dev->id != stm->pid) + ++stm->dev; - if (!id) { + if (!stm->dev->id) { ESP_LOGD(TAG, "Unknown/unsupported device (Device ID: 0x%03x)", stm->pid); return make_stm32_with_deletor(nullptr); } - progmem_memcpy(&stm->dev, dev, sizeof(stm->dev)); return stm; } @@ -830,10 +821,10 @@ stm32_err_t stm32_erase_memory(const stm32_unique_ptr &stm, uint32_t spage, uint * a tentative of intrusion and will hang. * Erasing the flash page-by-page is the safer way to go. */ - if (!(stm->dev.flags & F_NO_ME)) + if (!(stm->dev->flags & F_NO_ME)) return stm32_mass_erase(stm); - pages = flash_addr_to_page_ceil(stm, stm->dev.fl_end); + pages = flash_addr_to_page_ceil(stm, stm->dev->fl_end); } /* @@ -922,9 +913,9 @@ stm32_err_t stm32_go(const stm32_unique_ptr &stm, const uint32_t address) { } stm32_err_t stm32_reset_device(const stm32_unique_ptr &stm) { - const auto target_address = stm->dev.ram_start; + const auto target_address = stm->dev->ram_start; - if (stm->dev.flags & F_OBLL) { + if (stm->dev->flags & F_OBLL) { /* set the OBL_LAUNCH bit to reset device (see RM0360, 2.5) */ return stm32_run_raw_code(stm, target_address, STM_OBL_LAUNCH_CODE, STM_OBL_LAUNCH_CODE_SIZE); } else { diff --git a/esphome/components/shelly_dimmer/stm32flash.h b/esphome/components/shelly_dimmer/stm32flash.h index 1c14d3790b2..9aa2e470808 100644 --- a/esphome/components/shelly_dimmer/stm32flash.h +++ b/esphome/components/shelly_dimmer/stm32flash.h @@ -72,16 +72,18 @@ using stm32_cmd_t = struct Stm32Cmd { uint8_t crc; }; +// Word-only fields: the table is in PROGMEM and aligned 32-bit loads from flash are safe on ESP8266 using stm32_dev_t = struct Stm32Dev { // NOLINT - uint16_t id; - uint32_t ram_start, ram_end; - uint32_t fl_start, fl_end; - uint16_t fl_pps; // pages per sector + const uint32_t id; + const uint32_t ram_start, ram_end; + const uint32_t fl_start, fl_end; + const uint32_t fl_pps; // pages per sector const uint32_t *fl_ps; // page size - uint32_t opt_start, opt_end; - uint32_t mem_start, mem_end; - uint32_t flags; + const uint32_t opt_start, opt_end; + const uint32_t mem_start, mem_end; + const uint32_t flags; }; +static_assert(sizeof(stm32_dev_t) == 12 * sizeof(uint32_t), "stm32_dev_t must stay word-only for flash reads"); using stm32_t = struct Stm32 { uart::UARTDevice *stream; @@ -92,7 +94,7 @@ using stm32_t = struct Stm32 { uint8_t option1, option2; uint16_t pid; stm32_cmd_t *cmd; - stm32_dev_t dev; // RAM copy of the PROGMEM DEVICES entry + const stm32_dev_t *dev; }; /*