102 lines
3.1 KiB
Python
102 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import json
|
|
import re
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
|
|
BUILD_ARTIFACTS = (
|
|
"bootloader.bin",
|
|
"partitions.bin",
|
|
"firmware.bin",
|
|
"firmware.elf",
|
|
"firmware.map",
|
|
)
|
|
|
|
MANIFEST_PARTS = (
|
|
{"path": "bootloader.bin", "offset": 4096},
|
|
{"path": "partitions.bin", "offset": 32768},
|
|
{"path": "boot_app0.bin", "offset": 57344},
|
|
{"path": "firmware.bin", "offset": 65536},
|
|
)
|
|
|
|
VERSION_PATTERN = re.compile(r'Eggduino-Firmware V([^"\\]+)')
|
|
|
|
|
|
def extract_firmware_version(header_text: str) -> str:
|
|
match = VERSION_PATTERN.search(header_text)
|
|
if not match:
|
|
raise ValueError("Could not extract firmware version from include/EggDuino.h")
|
|
return match.group(1).strip()
|
|
|
|
|
|
def build_manifest(version: str) -> dict:
|
|
return {
|
|
"name": "EggDuino ESP32 Firmware",
|
|
"version": version,
|
|
"new_install_prompt_erase": True,
|
|
"builds": [
|
|
{
|
|
"chipFamily": "ESP32",
|
|
"parts": list(MANIFEST_PARTS),
|
|
}
|
|
],
|
|
}
|
|
|
|
|
|
def package_bundle(build_dir: Path, boot_app0_path: Path, header_path: Path, output_dir: Path) -> None:
|
|
build_dir = Path(build_dir)
|
|
boot_app0_path = Path(boot_app0_path)
|
|
header_path = Path(header_path)
|
|
output_dir = Path(output_dir)
|
|
|
|
if output_dir.exists():
|
|
shutil.rmtree(output_dir)
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
for artifact_name in BUILD_ARTIFACTS:
|
|
artifact_path = build_dir / artifact_name
|
|
if not artifact_path.is_file():
|
|
raise FileNotFoundError(f"Missing build artifact: {artifact_path}")
|
|
shutil.copy2(artifact_path, output_dir / artifact_name)
|
|
|
|
if not boot_app0_path.is_file():
|
|
raise FileNotFoundError(f"Missing boot_app0.bin: {boot_app0_path}")
|
|
shutil.copy2(boot_app0_path, output_dir / "boot_app0.bin")
|
|
|
|
version = extract_firmware_version(header_path.read_text(encoding="utf-8"))
|
|
manifest_path = output_dir / "manifest.json"
|
|
manifest_path.write_text(
|
|
json.dumps(build_manifest(version), indent=4) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
|
|
def _get_boot_app0_path(env) -> Path:
|
|
framework_dir = env.PioPlatform().get_package_dir("framework-arduinoespressif32")
|
|
if not framework_dir:
|
|
raise FileNotFoundError("PlatformIO framework-arduinoespressif32 package is not installed")
|
|
|
|
boot_app0_path = Path(framework_dir) / "tools" / "partitions" / "boot_app0.bin"
|
|
if not boot_app0_path.is_file():
|
|
raise FileNotFoundError(f"Could not find boot_app0.bin in {boot_app0_path.parent}")
|
|
return boot_app0_path
|
|
|
|
|
|
def _package_platformio_bundle(target, source, env) -> None:
|
|
del target, source
|
|
project_dir = Path(env.subst("$PROJECT_DIR"))
|
|
package_bundle(
|
|
build_dir=Path(env.subst("$BUILD_DIR")),
|
|
boot_app0_path=_get_boot_app0_path(env),
|
|
header_path=project_dir / "include" / "EggDuino.h",
|
|
output_dir=project_dir / "firmware",
|
|
)
|
|
print(f"Packaged firmware bundle to {project_dir / 'firmware'}")
|
|
|
|
|
|
if "Import" in globals():
|
|
Import("env")
|
|
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", _package_platformio_bundle)
|