mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-30 03:52:28 +00:00
Resolve Serial macro and ESP-NOW wrapper compilation errors. Preserve queue, neighbor, advert-history and Room post capacities while using qualified RTC, PSRAM and word-only IRAM storage on constrained ESP32 targets. Reduce Full infrastructure flash through lossless Room web compression, compact crypto and unused exception metadata removal. Add focused native regressions for storage ownership, exact protocol output, OTA proofs and build policy. Keep physical flash sizes, OTA slots and RAM guard formulas unchanged.
129 lines
5.1 KiB
Python
129 lines
5.1 KiB
Python
"""Keep complete ESP32 infrastructure firmware inside physical dual-OTA slots.
|
|
|
|
No source-built MeshCore/framework/dependency code uses C++ exception handlers.
|
|
Arduino otherwise forces unwinding metadata into each linked function. Apply
|
|
this policy after framework flags are populated, including library clones.
|
|
Constrained 4 MiB infrastructure images also share the already-qualified
|
|
compact Ed25519 arithmetic/hash and lossless OTA target-name table.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import os
|
|
from pathlib import Path
|
|
|
|
SCRIPT_DIR = Path(__file__).resolve().parent if "__file__" in globals() else Path("scripts").resolve()
|
|
SPEC = importlib.util.spec_from_file_location(
|
|
"esp32_full_size_source_policy", SCRIPT_DIR / "nrf52_flash_trim.py")
|
|
SOURCE_POLICY = importlib.util.module_from_spec(SPEC)
|
|
SPEC.loader.exec_module(SOURCE_POLICY)
|
|
|
|
ROLES = (
|
|
"../examples/simple_repeater/main.cpp",
|
|
"../examples/simple_room_server/main.cpp",
|
|
"../examples/simple_sensor/main.cpp",
|
|
)
|
|
EXCLUDED_ROLES = (
|
|
"../examples/companion_radio/main.cpp",
|
|
"../examples/companion_radio/MyMesh.cpp",
|
|
"../examples/simple_secure_chat/main.cpp",
|
|
"../examples/kiss_modem/main.cpp",
|
|
"../examples/partition_expander/main.cpp",
|
|
"../examples/esp32_partition_migrator/main.cpp",
|
|
"../examples/esp32_partition_legacy_seed/main.cpp",
|
|
)
|
|
COMPACT_DEFINES = {
|
|
# SMALL_BASE uses the existing 960-byte table, not a RAM-built table.
|
|
"ED25519_SMALL_BASE": 1,
|
|
"ED25519_COMPACT_SCALAR": 1,
|
|
"ED25519_COMPACT_FIELD": 1,
|
|
"ED25519_USE_CRYPTO_SHA512": 1,
|
|
"OTA_TARGET_NAME_FRONT_CODED": 1,
|
|
}
|
|
POSITIVE_FLAGS = {"-fexceptions", "-funwind-tables", "-fasynchronous-unwind-tables"}
|
|
UNWIND_FLAGS = ["-fno-unwind-tables", "-fno-asynchronous-unwind-tables"]
|
|
|
|
|
|
def infrastructure_policy(platform, mcu, src_filter, *, full=False, companion=False):
|
|
selected = SOURCE_POLICY.source_selected
|
|
return bool(
|
|
full and not companion and platform == "espressif32"
|
|
and str(mcu).lower().startswith("esp32")
|
|
and sum(selected(src_filter, source) for source in ROLES) == 1
|
|
and not any(selected(src_filter, source) for source in EXCLUDED_ROLES)
|
|
)
|
|
|
|
|
|
def compact_definitions(flash_bytes, flags=(), cppdefines=()):
|
|
if flash_bytes > 4 * 1024 * 1024:
|
|
return {}
|
|
values = SOURCE_POLICY.flag_defines(flags, cppdefines)
|
|
definitions = {name: value for name, value in COMPACT_DEFINES.items() if name not in values}
|
|
# An explicitly chosen base implementation remains authoritative.
|
|
if "ED25519_COMPACT_BASE" in values:
|
|
definitions.pop("ED25519_SMALL_BASE", None)
|
|
return definitions
|
|
|
|
|
|
def flag_values(values):
|
|
return values.split() if isinstance(values, str) else list(values)
|
|
|
|
|
|
def apply_final_flags(build_env):
|
|
"""Runs per object after SDK defaults and library-clone flags exist."""
|
|
updates = {}
|
|
for name in ("CCFLAGS", "CFLAGS", "CXXFLAGS", "LINKFLAGS"):
|
|
values = [value for value in flag_values(build_env.get(name, []))
|
|
if value not in POSITIVE_FLAGS]
|
|
additions = UNWIND_FLAGS + (["-fno-exceptions"] if name in ("CXXFLAGS", "LINKFLAGS") else [])
|
|
updates[name] = values + [flag for flag in additions if flag not in values]
|
|
build_env.Replace(**updates)
|
|
|
|
|
|
def prepare_source(build_env, node):
|
|
# Earlier middleware may already have substituted a private patched source.
|
|
# Change flags in the actual clone, preserving that substituted node.
|
|
apply_final_flags(build_env)
|
|
return node
|
|
|
|
|
|
def flash_size_bytes(value):
|
|
text = str(value).strip().upper()
|
|
for suffix, multiplier in (("MB", 1024 * 1024), ("KB", 1024)):
|
|
if text.endswith(suffix):
|
|
return int(text[:-len(suffix)]) * multiplier
|
|
return int(text, 0)
|
|
|
|
|
|
def install(build_env, process_environment=None):
|
|
settings = os.environ if process_environment is None else process_environment
|
|
board = build_env.BoardConfig()
|
|
source_filter = build_env.get("SRC_FILTER")
|
|
if source_filter is None:
|
|
source_filter = build_env.GetProjectOption("build_src_filter", "")
|
|
if not infrastructure_policy(
|
|
build_env.PioPlatform().name, board.get("build.mcu", ""), source_filter,
|
|
full=settings.get("MESHCORE_ESP32_FULL_BUILD") == "1",
|
|
companion=settings.get("MESHCORE_COMPANION_RADIO_FULL") == "1",
|
|
):
|
|
return False
|
|
definitions = compact_definitions(
|
|
flash_size_bytes(board.get("upload.flash_size", "4MB")),
|
|
build_env.get("BUILD_FLAGS", ()), build_env.get("CPPDEFINES", ()),
|
|
)
|
|
if definitions:
|
|
build_env.AppendUnique(CPPDEFINES=list(definitions.items()))
|
|
# Pre-script flags may be followed by SDK -fexceptions. Middleware sees
|
|
# the populated environment for each framework/library/application object.
|
|
build_env.AddBuildMiddleware(prepare_source)
|
|
# LINKFLAGS belong to this final application environment, not lib clones.
|
|
# This also covers objects emitted by a custom builder with no source hook.
|
|
apply_final_flags(build_env)
|
|
print("ESP32 Full infrastructure: no exception/unwind metadata; capacities and dual OTA retained")
|
|
return True
|
|
|
|
|
|
if "Import" in globals():
|
|
Import("env")
|
|
install(env)
|