Use a bounded uzlib-derived block encoder with the existing strict tinf decoder, qualify infrastructure roles, budget temporary RAM, and cache running-image metadata. Add self-serve CLI and policy, USB host-loss sleep grace, hardware test harnesses, regression tests, and CI coverage.
95 lines
4.0 KiB
Python
95 lines
4.0 KiB
Python
"""Enable bounded on-device OTA encoding only for qualified infrastructure.
|
|
|
|
Inspect the EFFECTIVE ordered source filter, never the environment name. This
|
|
pre-script contributes one shared compiler definition, so the C encoder and all
|
|
C++ OTA translation units agree. A custom recipe that omits this hook keeps
|
|
OtaDeflateConfig.h's fail-closed default. Companions keep host-precompressed OTA.
|
|
"""
|
|
|
|
import importlib.util
|
|
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(
|
|
"ota_device_deflate_source_policy", SCRIPT_DIR / "nrf52_flash_trim.py")
|
|
SOURCE_POLICY = importlib.util.module_from_spec(SPEC)
|
|
SPEC.loader.exec_module(SOURCE_POLICY)
|
|
|
|
DEFINITION = "MESHCORE_OTA_DEVICE_DEFLATE"
|
|
ROLE_SOURCES = (
|
|
"../examples/simple_repeater/main.cpp",
|
|
"../examples/simple_room_server/main.cpp",
|
|
"../examples/simple_sensor/main.cpp",
|
|
)
|
|
EXCLUDED_SOURCES = (
|
|
"../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",
|
|
)
|
|
|
|
|
|
def enabled(values, name):
|
|
value = values.get(name)
|
|
return value is not None and str(value).strip("\"'() ") not in ("", "0")
|
|
|
|
|
|
def bool_override(value):
|
|
# -U leaves the header's default zero and is an explicit opt-out as well.
|
|
if value is None:
|
|
return 0
|
|
text = str(value).strip("\"'() ")
|
|
if text not in ("0", "1"):
|
|
raise ValueError(DEFINITION + " override must be 0 or 1")
|
|
return int(text)
|
|
|
|
|
|
def role_policy(platform, mcu, src_filter, flags=(), cppdefines=()):
|
|
"""Return a common define or reject an unsafe explicit enable override."""
|
|
values = SOURCE_POLICY.flag_defines(flags, cppdefines)
|
|
selected = SOURCE_POLICY.source_selected
|
|
known_roles = sum(selected(src_filter, source) for source in ROLE_SOURCES)
|
|
excluded = any(selected(src_filter, source) for source in EXCLUDED_SOURCES)
|
|
seeder = values.get("OTA_SEEDER_ONLY") is not None
|
|
companion = any(enabled(values, name) for name in values
|
|
if name.startswith("COMPANION_"))
|
|
ota_enabled = enabled(values, "ENABLE_OTA") and not enabled(values, "DISABLE_LORA_OTA")
|
|
esp32 = (platform == "espressif32" and str(mcu).lower().startswith("esp32")
|
|
and enabled(values, "ESP32_PLATFORM"))
|
|
nrf52 = (platform == "nordicnrf52" and str(mcu).lower().startswith("nrf52")
|
|
and enabled(values, "NRF52_PLATFORM")
|
|
and any(enabled(values, store)
|
|
for store in ("OTA_QSPI_STORE", "OTA_SD_STORE", "OTA_RAK_AUTO_STORE")))
|
|
qualified = (known_roles == 1 and not excluded and not seeder and not companion
|
|
and ota_enabled and (esp32 or nrf52))
|
|
if DEFINITION in values:
|
|
override = bool_override(values[DEFINITION])
|
|
if override and not qualified:
|
|
raise ValueError(DEFINITION + "=1 requires an OTA infrastructure source role "
|
|
"and eligible ESP32/external-nRF52 storage")
|
|
return {} # Preserve an explicit valid definition/opt-out without duplicates.
|
|
return {DEFINITION: 1} if qualified else {}
|
|
|
|
|
|
def install(build_env):
|
|
platform = build_env.PioPlatform().name
|
|
mcu = build_env.BoardConfig().get("build.mcu", "")
|
|
src_filter = build_env.get("SRC_FILTER")
|
|
if src_filter is None:
|
|
src_filter = build_env.GetProjectOption("build_src_filter", "")
|
|
definitions = role_policy(platform, mcu, src_filter,
|
|
build_env.get("BUILD_FLAGS", ()),
|
|
build_env.get("CPPDEFINES", ()))
|
|
if definitions:
|
|
build_env.AppendUnique(CPPDEFINES=list(definitions.items()))
|
|
print("Device OTA DEFLATE: qualified infrastructure role; bounded per-block encoder")
|
|
|
|
|
|
if "Import" in globals():
|
|
Import("env")
|
|
install(env)
|