From 9040873526aaecaa3db57a01405299c540d03abe Mon Sep 17 00:00:00 2001 From: pelgraine <140762863+pelgraine@users.noreply.github.com> Date: Fri, 13 Mar 2026 00:10:03 +1100 Subject: [PATCH] script to create merged firmware automatically --- examples/companion_radio/MyMesh.h | 2 +- merge_firmware.py | 65 +++++++++++++++++++ .../lilygo_t5s3_epaper_pro/platformio.ini | 1 + variants/lilygo_tdeck_pro/platformio.ini | 1 + 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 merge_firmware.py diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 2c2b2a67..da9f7595 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -8,7 +8,7 @@ #define FIRMWARE_VER_CODE 10 #ifndef FIRMWARE_BUILD_DATE -#define FIRMWARE_BUILD_DATE "11 March 2026" +#define FIRMWARE_BUILD_DATE "12 March 2026" #endif #ifndef FIRMWARE_VERSION diff --git a/merge_firmware.py b/merge_firmware.py new file mode 100644 index 00000000..752995f6 --- /dev/null +++ b/merge_firmware.py @@ -0,0 +1,65 @@ +""" +PlatformIO post-build script: merge bootloader + partitions + firmware +into a single flashable binary. + +Output: .pio/build//firmware_merged.bin +Flash: esptool.py --chip esp32s3 write_flash 0x0 firmware_merged.bin + +Place this file in the project root alongside platformio.ini. +Add to each environment (or the base section): + extra_scripts = post:merge_firmware.py +""" + +Import("env") + +def merge_bin(source, target, env): + import subprocess, os + + build_dir = env.subst("$BUILD_DIR") + env_name = env.subst("$PIOENV") + + bootloader = os.path.join(build_dir, "bootloader.bin") + partitions = os.path.join(build_dir, "partitions.bin") + firmware = os.path.join(build_dir, "firmware.bin") + output = os.path.join(build_dir, "firmware_merged.bin") + + # Verify all inputs exist + for f in [bootloader, partitions, firmware]: + if not os.path.isfile(f): + print(f"[merge] WARNING: {f} not found, skipping merge") + return + + # Read flash settings from board config + flash_mode = env.BoardConfig().get("build.flash_mode", "qio") + flash_freq = env.BoardConfig().get("build.f_flash", "80000000L").rstrip("L") + flash_size = env.BoardConfig().get("upload.flash_size", "16MB") + mcu = env.BoardConfig().get("build.mcu", "esp32s3") + + # Convert numeric frequency to esptool format + freq_map = {"80000000": "80m", "40000000": "40m", "26000000": "26m", "20000000": "20m"} + flash_freq_str = freq_map.get(flash_freq, "80m") + + cmd = [ + env.subst("$PYTHONEXE"), "-m", "esptool", + "--chip", mcu, + "merge_bin", + "-o", output, + "--flash_mode", flash_mode, + "--flash_freq", flash_freq_str, + "--flash_size", flash_size, + "0x0", bootloader, + "0x8000", partitions, + "0x10000", firmware, + ] + + print(f"\n[merge] Creating merged firmware for {env_name}...") + print(f"[merge] {' '.join(cmd[-6:])}") + + result = subprocess.run(cmd, capture_output=True, text=True) + if result.returncode == 0: + size_kb = os.path.getsize(output) / 1024 + print(f"[merge] OK: {output} ({size_kb:.0f} KB)") + else: + print(f"[merge] FAILED: {result.stderr}") + +env.AddPostAction("$BUILD_DIR/firmware.bin", merge_bin) \ No newline at end of file diff --git a/variants/lilygo_t5s3_epaper_pro/platformio.ini b/variants/lilygo_t5s3_epaper_pro/platformio.ini index a36efe85..6e6f2bf5 100644 --- a/variants/lilygo_t5s3_epaper_pro/platformio.ini +++ b/variants/lilygo_t5s3_epaper_pro/platformio.ini @@ -10,6 +10,7 @@ [LilyGo_T5S3_EPaper_Pro] extends = esp32_base +extra_scripts = post:merge_firmware.py board = t5s3-epaper-pro board_build.flash_mode = qio board_build.f_flash = 80000000L diff --git a/variants/lilygo_tdeck_pro/platformio.ini b/variants/lilygo_tdeck_pro/platformio.ini index 4abf3390..f52cc172 100644 --- a/variants/lilygo_tdeck_pro/platformio.ini +++ b/variants/lilygo_tdeck_pro/platformio.ini @@ -1,5 +1,6 @@ [LilyGo_TDeck_Pro] extends = esp32_base +extra_scripts = post:merge_firmware.py board = t-deck_pro board_build.flash_mode = qio board_build.f_flash = 80000000L