[core] Migrate to UF2 OTA format version 2

This commit is contained in:
Kuba Szczodrzyński
2023-03-09 11:46:40 +01:00
parent 046f7df7d1
commit 65cf460691
5 changed files with 94 additions and 74 deletions

View File

@@ -533,31 +533,19 @@ env.Append(
)
# Main firmware outputs and actions
image_app_crc = "${BUILD_DIR}/image_${MCULC}_app.${FLASH_APP_OFFSET}.crc"
image_app_rblh = "${BUILD_DIR}/image_${MCULC}_app.${FLASH_RBL_OFFSET}.rblh"
image_ota_rbl = "${BUILD_DIR}/image_${MCULC}_app.ota.rbl"
env.Replace(
# linker command (encryption + packaging)
LINK="${LTCHIPTOOL} link2bin ${VARIANT} '' ''",
# UF2OTA input list
UF2OTA=[
# app binary image (enc+crc), OTA1 (uploader) only
(
"app",
"${BUILD_DIR}/${MCULC}_app_${FLASH_APP_OFFSET}.crc",
"",
"",
),
# app RBL header (crc), OTA1 (uploader) only
(
f"app+{rbl_offs}",
"${BUILD_DIR}/${MCULC}_app_${FLASH_RBL_OFFSET}.rblh",
"", # not used for OTA2
"",
),
# OTA RBL package, OTA2 (uf2ota lib) only
(
"", # not used for OTA1
"",
"download",
"${BUILD_DIR}/${MCULC}_app.ota.rbl",
),
# app binary image (enc+crc) for flasher
f"{image_app_crc}=flasher:app",
# app RBL header (with crc) for flasher
f"{image_app_rblh}+{rbl_offs}=flasher:app",
# OTA RBL package for device only
f"{image_ota_rbl}=device:download",
],
)

View File

@@ -274,18 +274,14 @@ env.Prepend(LIBS=[target_boot])
queue.BuildLibraries()
# Main firmware outputs and actions
image_ota1 = "${BUILD_DIR}/image_ota1.${FLASH_OTA1_OFFSET}.bin"
image_ota2 = "${BUILD_DIR}/image_ota2.${FLASH_OTA2_OFFSET}.bin"
env.Replace(
# linker command (dual .bin outputs)
LINK="${LTCHIPTOOL} link2bin ${VARIANT} xip1 xip2",
# default output .bin name
IMG_FW="image_${FLASH_OTA1_OFFSET}.ota1.bin",
# UF2OTA input list
UF2OTA=[
(
"ota1",
"${BUILD_DIR}/image_${FLASH_OTA1_OFFSET}.ota1.bin",
"ota2",
"${BUILD_DIR}/image_${FLASH_OTA2_OFFSET}.ota2.bin",
),
# same OTA images for flasher and device
f"{image_ota1},{image_ota2}=device:ota1,ota2;flasher:ota1,ota2",
],
)

View File

@@ -1,10 +1,17 @@
# Copyright (c) Kuba Szczodrzyński 2022-04-20.
import sys
from os.path import join
from platformio.platform.base import PlatformBase
from platformio.platform.board import PlatformBoardConfig
from SCons.Script import Default, DefaultEnvironment, Environment
from SCons.Script import (
COMMAND_LINE_TARGETS,
AlwaysBuild,
Default,
DefaultEnvironment,
Environment,
)
env: Environment = DefaultEnvironment()
platform: PlatformBase = env.PioPlatform()
@@ -21,7 +28,7 @@ env.SConscript("utils/ltchiptool.py", exports="env")
# Firmware name
if env.get("PROGNAME", "program") == "program":
env.Replace(PROGNAME="firmware")
env.Replace(PROGNAME="raw_firmware")
env.Replace(PROGSUFFIX=".elf")
# Configure the toolchain
@@ -62,19 +69,62 @@ env.AddFlashLayout(board)
# - # Main firmware outputs and actions
# Framework builder (base.py/arduino.py) is executed in BuildProgram()
target_elf = env.BuildProgram()
targets = [target_elf]
# Force including the base framework in case no other is specified
if not env.get("PIOFRAMEWORK"):
env.SConscript("frameworks/base.py")
if "UF2OTA" in env:
target_uf2 = env.BuildUF2OTA(target_elf)
targets.append(target_uf2)
env.AddFlashWriter(target_uf2)
elif "IMG_FW" in env:
target_fw = env.subst("$IMG_FW")
env.AddPlatformTarget("upload", target_fw, env["UPLOAD_ACTIONS"], "Upload")
#
# Target: Build executable and linkable firmware
#
target_uf2 = join("${BUILD_DIR}", "firmware.uf2")
if "nobuild" in COMMAND_LINE_TARGETS:
target_elf = join("${BUILD_DIR}", "${PROGNAME}.elf")
env["UF2OTA"] = "dummy" # forcefully allow uploading using ltchiptool
else:
sys.stderr.write(
"Warning! Firmware outputs not specified. Uploading is not possible.\n"
)
target_elf = env.BuildProgram()
target_uf2 = env.BuildUF2OTA(target_uf2, target_elf)
env.Depends(target_uf2, "checkprogsize")
Default(targets)
AlwaysBuild(env.Alias("nobuild", target_uf2))
target_buildprog = env.Alias("buildprog", target_uf2, target_uf2)
#
# Target: Print binary size
#
target_size = env.Alias(
"size",
target_elf,
env.VerboseAction("${SIZEPRINTCMD}", "Calculating size ${SOURCE}"),
)
AlwaysBuild(target_size)
#
# Target: Upload firmware
#
upload_protocol = env.subst("${UPLOAD_PROTOCOL}") or "uart"
upload_actions = []
upload_source = target_uf2
ltchiptool_flags = "UF2OTA" in env and env.GetLtchiptoolWriteFlags()
if ltchiptool_flags:
# use ltchiptool for flashing, if available
env.Replace(
LTCHIPTOOL_FLAGS=ltchiptool_flags,
UPLOADER="${LTCHIPTOOL} flash write",
UPLOADCMD="${UPLOADER} ${LTCHIPTOOL_FLAGS} ${UPLOADERFLAGS} ${SOURCE}",
)
upload_actions = [
env.VerboseAction(env.AutodetectUploadPort, "Looking for upload port..."),
env.VerboseAction("${UPLOADCMD}", "Uploading ${SOURCE}"),
]
elif upload_protocol == "custom":
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
else:
sys.stderr.write("Warning! Unknown upload protocol %s\n" % upload_protocol)
AlwaysBuild(env.Alias("upload", upload_source, upload_actions))
#
# Default targets
#
Default([target_buildprog, target_size])

View File

@@ -1,6 +1,5 @@
# Copyright (c) Kuba Szczodrzyński 2022-06-02.
import sys
from datetime import datetime
from os.path import basename, join, normpath
@@ -23,7 +22,6 @@ def env_uf2ota(env: Environment, *args, **kwargs):
if platform.custom("fw_version"):
project_version = platform.custom("fw_version")
inputs = " ".join(f'"{";".join(input)}"' for input in env["UF2OTA"])
output = [
project_name,
project_version,
@@ -34,57 +32,46 @@ def env_uf2ota(env: Environment, *args, **kwargs):
output = "_".join(output) + ".uf2"
if platform.custom("fw_output"):
output = platform.custom("fw_output")
output = join("${BUILD_DIR}", output)
output_copy_1 = join("${BUILD_DIR}", "firmware.uf2")
output_copy_2 = join("${BUILD_DIR}", "firmware.bin")
env["UF2OUT"] = output
env["UF2OUT_BASE"] = basename(output)
cmd = [
"@${LTCHIPTOOL} uf2 write",
f'--output "{output}"',
f'--output-copy "{output_copy_1}"',
f'--output-copy "{output_copy_2}"',
"--family ${FAMILY}",
"--board ${VARIANT}",
f"--version {lt_version}",
f"--lt-version {lt_version}",
f'--fw "{project_name}:{project_version}"',
f"--date {int(now.timestamp())}",
inputs,
*env["UF2OTA"],
]
print(f"|-- {basename(env.subst(output))}")
env.Execute(" ".join(cmd))
print(f"|-- {basename(env.subst(output_copy_1))}")
print(f"|-- {basename(env.subst(output_copy_2))}")
def env_flash_write(env: Environment, target):
def env_flash_write(env: Environment):
protocol = env.subst("${UPLOAD_PROTOCOL}")
actions = []
# from platform-espressif32/builder/main.py
if protocol == "uart":
# upload via UART
env["UPLOADERFLAGS_UF2"] = [
"${UF2OUT}",
return [
"-d",
"${UPLOAD_PORT}",
"-b",
"${UPLOAD_SPEED}",
]
actions = [
env.VerboseAction(env.AutodetectUploadPort, "Looking for upload port..."),
]
elif protocol == "custom":
actions = [
env.VerboseAction("${UPLOADCMD}", "Uploading firmware"),
]
else:
sys.stderr.write("Warning! Unknown upload protocol %s\n" % protocol)
return
# add main upload target
env.Replace(
UPLOADER="${LTCHIPTOOL} flash write",
UPLOADCMD="${UPLOADER} ${UPLOADERFLAGS_UF2} ${UPLOADERFLAGS}",
)
actions.append(env.VerboseAction("${UPLOADCMD}", "Uploading ${UF2OUT_BASE}"))
env.AddPlatformTarget("upload", target, actions, "Upload")
# can't upload via ltchiptool
return []
env.Append(
@@ -94,4 +81,4 @@ env.Append(
)
)
)
env.AddMethod(env_flash_write, "AddFlashWriter")
env.AddMethod(env_flash_write, "GetLtchiptoolWriteFlags")