diff --git a/merge-bin.py b/merge-bin.py new file mode 100644 index 0000000..6837b00 --- /dev/null +++ b/merge-bin.py @@ -0,0 +1,110 @@ +#!/usr/bin/python3 + +# Post-link: copy app .bin to out/.bin and a timestamped copy; optional merge_bin target for merged flash image. + +import os +import shutil +import subprocess +from datetime import datetime + +Import("env", "projenv") + +board_config = env.BoardConfig() +firmware_bin = "${BUILD_DIR}/${PROGNAME}.bin" +merged_bin = os.environ.get("MERGED_BIN_PATH", "${BUILD_DIR}/${PROGNAME}-merged.bin") + + +def _git_short_sha(project_dir): + try: + r = subprocess.run( + ["git", "-C", project_dir, "rev-parse", "--short", "HEAD"], + capture_output=True, + text=True, + timeout=8, + ) + sha = (r.stdout or "").strip() + if r.returncode != 0 or not sha: + return "nogit" + dirty = subprocess.run( + ["git", "-C", project_dir, "diff", "--quiet"], + timeout=8, + capture_output=True, + ) + return sha + ("-dirty" if dirty.returncode != 0 else "") + except (OSError, subprocess.TimeoutExpired): + return "nogit" + + +def _copy_one(src_path, dst_path): + shutil.copy2(src_path, dst_path) + print("Copied %s -> %s" % (src_path, dst_path)) + + +def _copy_to_out(env, src_path, out_suffix): + if not src_path or not os.path.isfile(src_path): + return + pioenv = env["PIOENV"] + project_dir = env["PROJECT_DIR"] + stamp = datetime.now().strftime("%Y%m%d_%H%M%S") + sha = _git_short_sha(project_dir) + stable_name = pioenv + out_suffix + ".bin" + stamped_name = "%s%s-%s-%s.bin" % (pioenv, out_suffix, stamp, sha) + + out_dir = os.path.join(project_dir, "out") + os.makedirs(out_dir, exist_ok=True) + _copy_one(src_path, os.path.join(out_dir, stable_name)) + _copy_one(src_path, os.path.join(out_dir, stamped_name)) + + # When the project lives in a subfolder (e.g. HeltecV4/MeshCore), also copy to /out + parent_out = os.path.normpath(os.path.join(project_dir, "..", "out")) + if parent_out != os.path.normpath(out_dir): + try: + os.makedirs(parent_out, exist_ok=True) + _copy_one(src_path, os.path.join(parent_out, stable_name)) + _copy_one(src_path, os.path.join(parent_out, stamped_name)) + except OSError as exc: + print("Note: could not mirror to parent out/: %s" % exc) + + +def copy_app_bin_to_out(target, source, env): + bin_path = os.path.join(env.subst("$BUILD_DIR"), env.subst("${PROGNAME}") + ".bin") + _copy_to_out(env, bin_path, "") + + +def merge_bin_action(source, target, env): + flash_images = [ + *env.Flatten(env.get("FLASH_EXTRA_IMAGES", [])), + "$ESP32_APP_OFFSET", + source[0].get_abspath(), + ] + merge_cmd = " ".join( + [ + '"$PYTHONEXE"', + '"$OBJCOPY"', + "--chip", + board_config.get("build.mcu", "esp32"), + "merge_bin", + "-o", + merged_bin, + "--flash_mode", + board_config.get("build.flash_mode", "dio"), + "--flash_freq", + "${__get_board_f_flash(__env__)}", + "--flash_size", + board_config.get("upload.flash_size", "4MB"), + *flash_images, + ] + ) + env.Execute(merge_cmd) + + +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", copy_app_bin_to_out) + +env.AddCustomTarget( + name="mergebin", + dependencies=firmware_bin, + actions=merge_bin_action, + title="Merge binary", + description="Build combined image", + always_build=True, +) \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 5f0496e..87143f4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,7 +14,7 @@ framework = arduino board = heltec_v4 monitor_speed = 115200 board_build.partitions = partitions_tft_touch.csv -extra_scripts = pre:scripts/inject_wifi_env.py +extra_scripts = pre:scripts/inject_wifi_env.py, merge-bin.py build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1 @@ -206,7 +206,7 @@ framework = arduino board = t-deck monitor_speed = 115200 board_build.partitions = variants/lilygo_tdeck/partitions_tdeck_touch.csv -extra_scripts = pre:scripts/inject_wifi_env.py +extra_scripts = pre:scripts/inject_wifi_env.py, merge-bin.py build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1