From a906432febfa01bf5574858426bad4ff77a7dead Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 10 Mar 2026 17:42:18 +0100 Subject: [PATCH] basic support for firmware metadata (upstream 0.15 backport) --- platformio.ini | 1 + wled00/e131.cpp | 2 +- wled00/ota_update.cpp | 2 +- wled00/ota_update.h | 3 +- wled00/wled.h | 7 +++-- wled00/wled_metadata.cpp | 6 ++-- wled00/wled_metadata.h | 62 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 wled00/wled_metadata.h diff --git a/platformio.ini b/platformio.ini index 8c19addb..1e3a59e9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -241,6 +241,7 @@ ldscript_16m14m = eagle.flash.16m14m.ld extra_scripts = pre:pio-scripts/set_version.py pre:pio-scripts/set_nightly_version.py + pre:pio-scripts/set_metadata.py pre:pio-scripts/build_ui.py pre:pio-scripts/conditional_usb_mode.py pre:pio-scripts/set_repo.py diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 6587c6e6..a6486ee3 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -469,7 +469,7 @@ void prepareArtnetPollReply(ArtPollReply *reply) { reply->reply_port = ARTNET_DEFAULT_PORT; - char * numberEnd = versionString; + char * numberEnd = (char*) versionString; // strtol promises not to try to edit this. reply->reply_version_h = (uint8_t)strtol(numberEnd, &numberEnd, 10); numberEnd++; reply->reply_version_l = (uint8_t)strtol(numberEnd, &numberEnd, 10); diff --git a/wled00/ota_update.cpp b/wled00/ota_update.cpp index eb70e72e..a0bf31d3 100644 --- a/wled00/ota_update.cpp +++ b/wled00/ota_update.cpp @@ -22,7 +22,7 @@ constexpr size_t METADATA_OFFSET = 256; // ESP32: metadata appears afte // Bootloader is at fixed offset 0x1000 (4KB), 0x0000 (0KB), or 0x2000 (8KB), and is typically 32KB // Bootloader offsets for different MCUs => see https://github.com/wled/WLED/issues/5064 -#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) +#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) constexpr size_t BOOTLOADER_OFFSET = 0x0000; // esp32-S3, esp32-C3 and (future support) esp32-c6 constexpr size_t BOOTLOADER_SIZE = 0x8000; // 32KB, typical bootloader size #define BOOTLOADER_OTA_UNSUPPORTED // still needs validation on these platforms. diff --git a/wled00/ota_update.h b/wled00/ota_update.h index e2239ebd..9b36429a 100644 --- a/wled00/ota_update.h +++ b/wled00/ota_update.h @@ -9,8 +9,6 @@ #pragma once -#if 0 // WLEDMM not needed - we only want getBootloaderSHA256Hex(); - // Platform-specific metadata locations #ifdef ESP32 #define BUILD_METADATA_SECTION ".rodata_custom_desc" @@ -18,6 +16,7 @@ #define BUILD_METADATA_SECTION ".ver_number" #endif +#if 0 // WLEDMM not needed - we only want getBootloaderSHA256Hex(); class AsyncWebServerRequest; diff --git a/wled00/wled.h b/wled00/wled.h index 871c340d..36572b24 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -230,6 +230,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #include "pin_manager.h" #include "bus_manager.h" #include "FX.h" +#include "wled_metadata.h" #ifndef CLIENT_SSID #define CLIENT_SSID DEFAULT_CLIENT_SSID @@ -314,9 +315,9 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #endif // Global Variable definitions -WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION)); -WLED_GLOBAL char releaseString[] _INIT_PROGMEM(TOSTRING(WLED_RELEASE_NAME)); //WLEDMM: to show on update page // somehow this will not work if using "const char releaseString[] -WLED_GLOBAL char repoString[] _INIT(WLED_REPO); +//WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION)); +//WLED_GLOBAL char releaseString[] _INIT_PROGMEM(TOSTRING(WLED_RELEASE_NAME)); //WLEDMM: to show on update page // somehow this will not work if using "const char releaseString[] +extern const __FlashStringHelper* repoString; // Github repository (if available) #define WLED_CODENAME "Hoshi" // AP and OTA default passwords (for maximum security change them!) diff --git a/wled00/wled_metadata.cpp b/wled00/wled_metadata.cpp index 6ab9fe50..80e26a6a 100644 --- a/wled00/wled_metadata.cpp +++ b/wled00/wled_metadata.cpp @@ -19,7 +19,7 @@ constexpr uint32_t WLED_CUSTOM_DESC_MAGIC = 0x57535453; // "WSTS" (WLED System constexpr uint32_t WLED_CUSTOM_DESC_VERSION = 2; // v1 - original PR; v2 - "safe to update from" version // Compile-time validation that release name doesn't exceed maximum length -static_assert(sizeof(WLED_RELEASE_NAME) <= WLED_RELEASE_NAME_MAX_LEN, +static_assert(sizeof(TOSTRING(WLED_RELEASE_NAME)) <= WLED_RELEASE_NAME_MAX_LEN, "WLED_RELEASE_NAME exceeds maximum length of WLED_RELEASE_NAME_MAX_LEN characters"); @@ -57,8 +57,8 @@ const wled_metadata_t __attribute__((section(BUILD_METADATA_SECTION))) WLED_BUIL WLED_CUSTOM_DESC_MAGIC, // magic WLED_CUSTOM_DESC_VERSION, // version TOSTRING(WLED_VERSION), - WLED_RELEASE_NAME, // release_name - std::integral_constant::value, // hash - computed at compile time; integral_constant enforces this + TOSTRING(WLED_RELEASE_NAME), // release_name + std::integral_constant::value, // hash - computed at compile time; integral_constant enforces this { 0, 0, 0 }, // All other platforms can update safely }; diff --git a/wled00/wled_metadata.h b/wled00/wled_metadata.h new file mode 100644 index 00000000..8c1dc0bb --- /dev/null +++ b/wled00/wled_metadata.h @@ -0,0 +1,62 @@ +/* + WLED build metadata + + Manages and exports information about the current WLED build. +*/ + + +#pragma once + +#include +#include +#include + +#define WLED_VERSION_MAX_LEN 48 +#define WLED_RELEASE_NAME_MAX_LEN 48 + +/** + * WLED Custom Description Structure + * This structure is embedded in platform-specific sections at an approximately + * fixed offset in ESP32/ESP8266 binaries, where it can be found and validated + * by the OTA process. + */ +typedef struct { + uint32_t magic; // Magic number to identify WLED custom description + uint32_t desc_version; // Structure version for future compatibility + char wled_version[WLED_VERSION_MAX_LEN]; + char release_name[WLED_RELEASE_NAME_MAX_LEN]; // Release name (null-terminated) + uint32_t hash; // Structure sanity check + uint8_t safe_update_version[3]; // Indicates version it's known to be safe to install this update from: major, minor, patch +} __attribute__((packed)) wled_metadata_t; + + +// Global build description +extern const wled_metadata_t WLED_BUILD_DESCRIPTION; + +// Convenient metdata pointers +#define versionString (WLED_BUILD_DESCRIPTION.wled_version) // Build version, WLED_VERSION +#define releaseString (WLED_BUILD_DESCRIPTION.release_name) // Release name, WLED_RELEASE_NAME +extern const __FlashStringHelper* repoString; // Github repository (if available) +extern const __FlashStringHelper* productString; // Product, WLED_PRODUCT_NAME -- deprecated, use WLED_RELEASE_NAME +extern const __FlashStringHelper* brandString ; // Brand + + +// Metadata analysis functions + +/** + * Extract WLED custom description structure from binary data + * @param binaryData Pointer to binary file data + * @param dataSize Size of binary data in bytes + * @param extractedDesc Buffer to store extracted custom description structure + * @return true if structure was found and extracted, false otherwise + */ +bool findWledMetadata(const uint8_t* binaryData, size_t dataSize, wled_metadata_t* extractedDesc); + +/** + * Check if OTA should be allowed based on release compatibility + * @param firmwareDescription Pointer to firmware description + * @param errorMessage Buffer to store error message if validation fails + * @param errorMessageLen Maximum length of error message buffer + * @return true if OTA should proceed, false if it should be blocked + */ +bool shouldAllowOTA(const wled_metadata_t& firmwareDescription, char* errorMessage, size_t errorMessageLen);