Files
platform-espressif32/builder/main.py
T

447 lines
14 KiB
Python
Raw Normal View History

2016-10-22 02:20:57 +03:00
# Copyright 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
2019-05-11 22:13:26 +03:00
import re
import sys
from os.path import isfile, join
2016-10-24 20:23:25 +03:00
2019-05-28 14:09:26 +03:00
from SCons.Script import (
ARGUMENTS, COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default,
DefaultEnvironment)
2016-10-24 20:23:25 +03:00
2018-05-26 01:13:54 +03:00
#
# Helpers
#
2016-10-24 20:23:25 +03:00
def _get_board_f_flash(env):
frequency = env.subst("$BOARD_F_FLASH")
frequency = str(frequency).replace("L", "")
return str(int(int(frequency) / 1000000)) + "m"
def _get_board_flash_mode(env):
mode = env.subst("$BOARD_FLASH_MODE")
if mode == "qio":
return "dio"
elif mode == "qout":
return "dout"
return mode
2018-05-26 01:13:54 +03:00
def _parse_size(value):
if isinstance(value, int):
return value
elif value.isdigit():
2018-05-26 01:13:54 +03:00
return int(value)
elif value.startswith("0x"):
return int(value, 16)
2018-06-15 21:35:03 +03:00
elif value[-1].upper() in ("K", "M"):
base = 1024 if value[-1].upper() == "K" else 1024 * 1024
2018-05-26 01:13:54 +03:00
return int(value[:-1]) * base
return value
def _parse_partitions(env):
partitions_csv = env.subst("$PARTITIONS_TABLE_CSV")
if not isfile(partitions_csv):
sys.stderr.write("Could not find the file %s with partitions "
"table.\n" % partitions_csv)
env.Exit(1)
2018-05-30 00:25:12 +03:00
return
2018-05-26 01:13:54 +03:00
result = []
next_offset = 0
2018-05-26 01:13:54 +03:00
with open(partitions_csv) as fp:
for line in fp.readlines():
line = line.strip()
if not line or line.startswith("#"):
continue
tokens = [t.strip() for t in line.split(",")]
2018-05-26 01:13:54 +03:00
if len(tokens) < 5:
continue
partition = {
2018-05-26 01:13:54 +03:00
"name": tokens[0],
"type": tokens[1],
"subtype": tokens[2],
"offset": tokens[3] or next_offset,
2018-05-26 01:13:54 +03:00
"size": tokens[4],
"flags": tokens[5] if len(tokens) > 5 else None
}
result.append(partition)
2021-11-05 14:45:37 +02:00
next_offset = _parse_size(partition["offset"]) + _parse_size(
partition["size"]
)
bound = 0x10000 if partition["type"] in ("0", "app") else 4
next_offset = (next_offset + bound - 1) & ~(bound - 1)
2018-05-26 01:13:54 +03:00
return result
def _update_max_upload_size(env):
if not env.get("PARTITIONS_TABLE_CSV"):
return
sizes = [
_parse_size(p['size']) for p in _parse_partitions(env)
if p['type'] in ("0", "app")
]
if sizes:
board.update("upload.maximum_size", max(sizes))
2018-05-26 01:13:54 +03:00
2018-12-26 02:07:03 +02:00
def _to_unix_slashes(path):
return path.replace('\\', '/')
#
# SPIFFS helpers
#
def fetch_spiffs_size(env):
2018-05-26 01:13:54 +03:00
spiffs = None
for p in _parse_partitions(env):
if p['type'] == "data" and p['subtype'] == "spiffs":
spiffs = p
if not spiffs:
sys.stderr.write(
"Could not find the `spiffs` section in the partitions "
"table %s\n" % env.subst("$PARTITIONS_TABLE_CSV")
)
2018-05-30 00:25:12 +03:00
env.Exit(1)
return
2018-05-26 01:13:54 +03:00
env["SPIFFS_START"] = _parse_size(spiffs['offset'])
env["SPIFFS_SIZE"] = _parse_size(spiffs['size'])
env["SPIFFS_PAGE"] = int("0x100", 16)
env["SPIFFS_BLOCK"] = int("0x1000", 16)
def __fetch_spiffs_size(target, source, env):
fetch_spiffs_size(env)
return (target, source)
2016-10-24 20:23:25 +03:00
env = DefaultEnvironment()
2020-06-10 17:16:17 +03:00
env.SConscript("compat.py", exports="env")
2016-10-24 20:23:25 +03:00
platform = env.PioPlatform()
board = env.BoardConfig()
2020-05-11 21:17:48 +03:00
mcu = board.get("build.mcu", "esp32")
2021-06-23 12:32:55 +03:00
toolchain_arch = "xtensa-%s" % mcu
if mcu == "esp32c3":
toolchain_arch = "riscv32-esp"
2016-10-24 20:23:25 +03:00
env.Replace(
__get_board_f_flash=_get_board_f_flash,
__get_board_flash_mode=_get_board_flash_mode,
2018-06-02 15:58:00 +03:00
2021-06-23 12:32:55 +03:00
AR="%s-elf-ar" % toolchain_arch,
AS="%s-elf-as" % toolchain_arch,
CC="%s-elf-gcc" % toolchain_arch,
CXX="%s-elf-g++" % toolchain_arch,
GDB="%s-elf-gdb" % toolchain_arch,
2016-10-29 19:31:23 +03:00
OBJCOPY=join(
platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"),
2021-06-23 12:32:55 +03:00
RANLIB="%s-elf-ranlib" % toolchain_arch,
SIZETOOL="%s-elf-size" % toolchain_arch,
2018-06-02 15:58:00 +03:00
ARFLAGS=["rc"],
2018-06-09 01:00:20 +03:00
2018-07-02 15:33:43 +03:00
SIZEPROGREGEXP=r"^(?:\.iram0\.text|\.iram0\.vectors|\.dram0\.data|\.flash\.text|\.flash\.rodata|)\s+([0-9]+).*",
SIZEDATAREGEXP=r"^(?:\.dram0\.data|\.dram0\.bss|\.noinit)\s+([0-9]+).*",
2018-06-02 15:58:00 +03:00
SIZECHECKCMD="$SIZETOOL -A -d $SOURCES",
SIZEPRINTCMD="$SIZETOOL -B -d $SOURCES",
2018-11-24 15:29:21 +02:00
ERASEFLAGS=[
2020-05-11 21:17:48 +03:00
"--chip", mcu,
2018-11-24 15:29:21 +02:00
"--port", '"$UPLOAD_PORT"'
],
ERASECMD='"$PYTHONEXE" "$OBJCOPY" $ERASEFLAGS erase_flash',
MKSPIFFSTOOL="mkspiffs_${PIOPLATFORM}_" + ("espidf" if "espidf" in env.subst(
"$PIOFRAMEWORK") else "${PIOFRAMEWORK}"),
ESP32_SPIFFS_IMAGE_NAME=env.get("ESP32_SPIFFS_IMAGE_NAME", "spiffs"),
ESP32_APP_OFFSET="0x10000",
2018-06-02 15:58:00 +03:00
PROGSUFFIX=".elf"
)
2016-10-24 20:23:25 +03:00
2018-01-03 18:23:00 +02:00
# Allow user to override via pre:script
if env.get("PROGNAME", "program") == "program":
env.Replace(PROGNAME="firmware")
2016-10-24 20:23:25 +03:00
env.Append(
# copy CCFLAGS to ASFLAGS (-x assembler-with-cpp mode)
ASFLAGS=env.get("CCFLAGS", [])[:],
2016-10-24 20:23:25 +03:00
BUILDERS=dict(
ElfToBin=Builder(
action=env.VerboseAction(" ".join([
2018-06-09 01:00:20 +03:00
'"$PYTHONEXE" "$OBJCOPY"',
2020-05-11 21:17:48 +03:00
"--chip", mcu,
2018-06-09 01:00:20 +03:00
"elf2image",
"--flash_mode", "$BOARD_FLASH_MODE",
"--flash_freq", "${__get_board_f_flash(__env__)}",
"--flash_size", board.get("upload.flash_size", "detect"),
2018-06-09 01:00:20 +03:00
"-o", "$TARGET", "$SOURCES"
2016-10-24 20:23:25 +03:00
]), "Building $TARGET"),
suffix=".bin"
),
DataToBin=Builder(
action=env.VerboseAction(" ".join([
2018-06-09 01:00:20 +03:00
'"$MKSPIFFSTOOL"',
"-c", "$SOURCES",
"-p", "$SPIFFS_PAGE",
"-b", "$SPIFFS_BLOCK",
"-s", "$SPIFFS_SIZE",
"$TARGET"
]), "Building SPIFFS image from '$SOURCES' directory to $TARGET"),
emitter=__fetch_spiffs_size,
source_factory=env.Dir,
suffix=".bin"
)
)
)
if not env.get("PIOFRAMEWORK"):
env.SConscript("frameworks/_bare.py", exports="env")
2017-04-28 11:51:04 +03:00
2016-10-24 20:23:25 +03:00
#
# Target: Build executable and linkable firmware or SPIFFS image
#
target_elf = None
2018-01-03 18:23:00 +02:00
if "nobuild" in COMMAND_LINE_TARGETS:
2019-06-12 23:09:40 +03:00
target_elf = join("$BUILD_DIR", "${PROGNAME}.elf")
if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
fetch_spiffs_size(env)
target_firm = join("$BUILD_DIR", "${ESP32_SPIFFS_IMAGE_NAME}.bin")
else:
target_firm = join("$BUILD_DIR", "${PROGNAME}.bin")
2018-01-03 18:23:00 +02:00
else:
target_elf = env.BuildProgram()
if set(["buildfs", "uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
target_firm = env.DataToBin(
2021-12-02 22:08:28 +02:00
join("$BUILD_DIR", "${ESP32_SPIFFS_IMAGE_NAME}"), "$PROJECT_DATA_DIR")
2020-09-07 12:56:44 +03:00
env.NoCache(target_firm)
AlwaysBuild(target_firm)
else:
target_firm = env.ElfToBin(
join("$BUILD_DIR", "${PROGNAME}"), target_elf)
env.Depends(target_firm, "checkprogsize")
2016-10-24 20:23:25 +03:00
env.AddPlatformTarget("buildfs", target_firm, target_firm, "Build Filesystem Image")
2018-01-03 18:23:00 +02:00
AlwaysBuild(env.Alias("nobuild", target_firm))
2016-11-13 21:42:12 +02:00
target_buildprog = env.Alias("buildprog", target_firm, target_firm)
2016-10-24 20:23:25 +03:00
2018-05-26 01:13:54 +03:00
# update max upload size based on CSV file
if env.get("PIOMAINPROG"):
env.AddPreAction(
"checkprogsize",
env.VerboseAction(
lambda source, target, env: _update_max_upload_size(env),
"Retrieving maximum program size $SOURCES"))
# remove after PIO Core 3.6 release
elif set(["checkprogsize", "upload"]) & set(COMMAND_LINE_TARGETS):
2018-05-26 01:13:54 +03:00
_update_max_upload_size(env)
#
# Target: Print binary size
#
2020-06-10 17:16:17 +03:00
target_size = env.AddPlatformTarget(
"size",
target_elf,
env.VerboseAction("$SIZEPRINTCMD", "Calculating size $SOURCE"),
"Program Size",
"Calculate program size",
)
#
# Target: Upload firmware or SPIFFS image
#
upload_protocol = env.subst("$UPLOAD_PROTOCOL")
debug_tools = board.get("debug.tools", {})
upload_actions = []
2019-05-11 22:13:26 +03:00
# Compatibility with old OTA configurations
if (upload_protocol != "espota"
and re.match(r"\"?((([0-9]{1,3}\.){3}[0-9]{1,3})|[^\\/]+\.local)\"?$",
env.get("UPLOAD_PORT", ""))):
upload_protocol = "espota"
sys.stderr.write(
"Warning! We have just detected `upload_port` as IP address or host "
"name of ESP device. `upload_protocol` is switched to `espota`.\n"
"Please specify `upload_protocol = espota` in `platformio.ini` "
"project configuration file.\n")
if upload_protocol == "espota":
if not env.subst("$UPLOAD_PORT"):
sys.stderr.write(
"Error: Please specify IP address or host name of ESP device "
"using `upload_port` for build environment or use "
"global `--upload-port` option.\n"
"See https://docs.platformio.org/page/platforms/"
"espressif32.html#over-the-air-ota-update\n")
env.Replace(
UPLOADER=join(
2019-05-14 00:23:48 +03:00
platform.get_package_dir("framework-arduinoespressif32") or "",
"tools", "espota.py"),
2019-05-11 22:13:26 +03:00
UPLOADERFLAGS=["--debug", "--progress", "-i", "$UPLOAD_PORT"],
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS -f $SOURCE'
)
if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
env.Append(UPLOADERFLAGS=["--spiffs"])
2019-05-11 22:13:26 +03:00
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
elif upload_protocol == "esptool":
env.Replace(
UPLOADER=join(
platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"),
UPLOADERFLAGS=[
2020-05-11 21:17:48 +03:00
"--chip", mcu,
2018-06-09 01:00:20 +03:00
"--port", '"$UPLOAD_PORT"',
"--baud", "$UPLOAD_SPEED",
"--before", "default_reset",
"--after", "hard_reset",
"write_flash", "-z",
"--flash_mode", "${__get_board_flash_mode(__env__)}",
2018-06-09 01:00:20 +03:00
"--flash_freq", "${__get_board_f_flash(__env__)}",
"--flash_size", "detect"
],
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS $ESP32_APP_OFFSET $SOURCE'
)
for image in env.get("FLASH_EXTRA_IMAGES", []):
env.Append(UPLOADERFLAGS=[image[0], env.subst(image[1])])
if "uploadfs" in COMMAND_LINE_TARGETS:
env.Replace(
UPLOADERFLAGS=[
2020-05-11 21:17:48 +03:00
"--chip", mcu,
2018-06-09 01:00:20 +03:00
"--port", '"$UPLOAD_PORT"',
"--baud", "$UPLOAD_SPEED",
"--before", "default_reset",
"--after", "hard_reset",
"write_flash", "-z",
"--flash_mode", "$BOARD_FLASH_MODE",
"--flash_size", "detect",
"$SPIFFS_START"
],
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS $SOURCE',
)
2018-07-02 16:03:11 +03:00
upload_actions = [
env.VerboseAction(env.AutodetectUploadPort,
"Looking for upload port..."),
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")
]
2020-03-17 10:51:38 +00:00
elif upload_protocol == "mbctool":
env.Replace(
UPLOADER=join(
platform.get_package_dir("tool-mbctool") or "", "bin", "mbctool"),
UPLOADERFLAGS=[
"--device", "esp",
"--speed", "$UPLOAD_SPEED",
"--port", '"$UPLOAD_PORT"',
2020-03-17 10:51:38 +00:00
"--upload",
"0x1000", join(
platform.get_package_dir("framework-arduino-mbcwb"),
2020-03-17 10:51:38 +00:00
"tools", "sdk", "bin", "bootloader_qio_80m.bin"),
"0x8000", join("$BUILD_DIR", "partitions.bin"),
"0xe000", join(
platform.get_package_dir("framework-arduino-mbcwb"),
2020-03-17 10:51:38 +00:00
"tools", "partitions", "boot_app0.bin"),
"0x10000", join("$BUILD_DIR", "${PROGNAME}.bin"),
],
UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS'
2020-03-17 10:51:38 +00:00
)
upload_actions = [
env.VerboseAction(env.AutodetectUploadPort,
"Looking for upload port..."),
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")
]
elif upload_protocol in debug_tools:
openocd_args = ["-d%d" % (2 if int(ARGUMENTS.get("PIOVERBOSE", 0)) else 1)]
openocd_args.extend(
debug_tools.get(upload_protocol).get("server").get("arguments", []))
openocd_args.extend([
"-c", "adapter_khz %s" % env.GetProjectOption("debug_speed", "5000"),
"-c",
2020-10-26 22:19:01 +02:00
"program_esp {{$SOURCE}} %s verify" %
board.get("upload.offset_address", "$ESP32_APP_OFFSET"),
])
for image in env.get("FLASH_EXTRA_IMAGES", []):
openocd_args.extend([
"-c",
2020-10-26 22:19:01 +02:00
'program_esp {{%s}} %s verify' %
(_to_unix_slashes(image[1]), image[0])
])
openocd_args.extend(["-c", "reset run; shutdown"])
openocd_args = [
f.replace(
"$PACKAGE_DIR",
_to_unix_slashes(
platform.get_package_dir("tool-openocd-esp32") or ""))
for f in openocd_args
]
env.Replace(UPLOADER="openocd",
UPLOADERFLAGS=openocd_args,
UPLOADCMD="$UPLOADER $UPLOADERFLAGS")
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
2016-10-24 20:23:25 +03:00
# custom upload tool
elif upload_protocol == "custom":
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
2016-10-24 20:23:25 +03:00
else:
sys.stderr.write("Warning! Unknown upload protocol %s\n" % upload_protocol)
2016-10-24 20:23:25 +03:00
2020-06-10 17:16:17 +03:00
env.AddPlatformTarget("upload", target_firm, upload_actions, "Upload")
env.AddPlatformTarget("uploadfs", target_firm, upload_actions, "Upload Filesystem Image")
env.AddPlatformTarget(
"uploadfsota", target_firm, upload_actions, "Upload Filesystem Image OTA")
2016-10-24 20:23:25 +03:00
2018-11-24 15:29:21 +02:00
#
# Target: Erase Flash
#
2020-06-10 17:16:17 +03:00
env.AddPlatformTarget(
"erase",
None,
[
env.VerboseAction(env.AutodetectUploadPort, "Looking for serial port..."),
2019-05-11 22:13:26 +03:00
env.VerboseAction("$ERASECMD", "Erasing...")
2020-06-10 17:16:17 +03:00
],
"Erase Flash",
)
2018-11-24 15:29:21 +02:00
2020-01-29 15:38:58 +02:00
#
# Information about obsolete method of specifying linker scripts
#
if any("-Wl,-T" in f for f in env.get("LINKFLAGS", [])):
print("Warning! '-Wl,-T' option for specifying linker scripts is deprecated. "
"Please use 'board_build.ldscript' option in your 'platformio.ini' file.")
2016-10-24 20:23:25 +03:00
#
# Default targets
#
Default([target_buildprog, target_size])