Arduino core 3.2.1
This commit is contained in:
@@ -110,14 +110,14 @@ env.Append(
|
||||
" ".join(
|
||||
[
|
||||
"riscv32-esp-elf-objcopy"
|
||||
if mcu in ("esp32c2","esp32c3","esp32c6","esp32h2","esp32p4")
|
||||
if mcu in ("esp32c2","esp32c3","esp32c5","esp32c6","esp32h2","esp32p4")
|
||||
else "xtensa-%s-elf-objcopy" % mcu,
|
||||
"--input-target",
|
||||
"binary",
|
||||
"--output-target",
|
||||
"elf32-littleriscv" if mcu in ("esp32c2","esp32c3","esp32c6","esp32h2","esp32p4") else "elf32-xtensa-le",
|
||||
"elf32-littleriscv" if mcu in ("esp32c2","esp32c3","esp32c5","esp32c6","esp32h2","esp32p4") else "elf32-xtensa-le",
|
||||
"--binary-architecture",
|
||||
"riscv" if mcu in ("esp32c2","esp32c3","esp32c6","esp32h2","esp32p4") else "xtensa",
|
||||
"riscv" if mcu in ("esp32c2","esp32c3","esp32c5","esp32c6","esp32h2","esp32p4") else "xtensa",
|
||||
"--rename-section",
|
||||
".data=.rodata.embedded",
|
||||
"$SOURCE",
|
||||
|
||||
+861
-153
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+271
-185
@@ -40,22 +40,22 @@ from SCons.Script import (
|
||||
DefaultEnvironment,
|
||||
)
|
||||
|
||||
from platformio import fs, __version__
|
||||
from platformio import fs
|
||||
from platformio.compat import IS_WINDOWS
|
||||
from platformio.proc import exec_command
|
||||
from platformio.builder.tools.piolib import ProjectAsLibBuilder
|
||||
from platformio.project.config import ProjectConfig
|
||||
from platformio.package.version import get_original_version, pepver_to_semver
|
||||
|
||||
# Added to avoid conflicts between installed Python packages from
|
||||
# the IDF virtual environment and PlatformIO Core
|
||||
# Note: This workaround can be safely deleted when PlatformIO 6.1.7 is released
|
||||
if os.environ.get("PYTHONPATH"):
|
||||
del os.environ["PYTHONPATH"]
|
||||
|
||||
env = DefaultEnvironment()
|
||||
env.SConscript("_embed_files.py", exports="env")
|
||||
|
||||
# remove maybe existing old map file in project root
|
||||
map_file = os.path.join(env.subst("$PROJECT_DIR"), env.subst("$PROGNAME") + ".map")
|
||||
if os.path.exists(map_file):
|
||||
os.remove(map_file)
|
||||
|
||||
def install_standard_python_deps():
|
||||
def _get_installed_standard_pip_packages():
|
||||
result = {}
|
||||
@@ -83,7 +83,10 @@ def install_standard_python_deps():
|
||||
deps = {
|
||||
"wheel": ">=0.35.1",
|
||||
"rich-click": ">=1.8.6",
|
||||
"PyYAML": ">=6.0.2"
|
||||
"PyYAML": ">=6.0.2",
|
||||
"intelhex": ">=2.3.0",
|
||||
"rich": ">=14.0.0",
|
||||
"esp-idf-size": ">=1.6.1"
|
||||
}
|
||||
|
||||
installed_packages = _get_installed_standard_pip_packages()
|
||||
@@ -100,7 +103,7 @@ def install_standard_python_deps():
|
||||
env.Execute(
|
||||
env.VerboseAction(
|
||||
(
|
||||
'"$PYTHONEXE" -m pip install -U '
|
||||
'"$PYTHONEXE" -m pip install -U -q -q -q '
|
||||
+ " ".join(
|
||||
[
|
||||
'"%s%s"' % (p, deps[p])
|
||||
@@ -147,18 +150,20 @@ TOOLCHAIN_DIR = platform.get_package_dir(
|
||||
assert os.path.isdir(FRAMEWORK_DIR)
|
||||
assert os.path.isdir(TOOLCHAIN_DIR)
|
||||
|
||||
if (
|
||||
["espidf"] == env.get("PIOFRAMEWORK")
|
||||
and semantic_version.Version.coerce(__version__)
|
||||
<= semantic_version.Version("6.1.10")
|
||||
and "__debug" in COMMAND_LINE_TARGETS
|
||||
):
|
||||
print("Warning! Debugging an IDF project requires PlatformIO Core >= 6.1.11!")
|
||||
def create_silent_action(action_func):
|
||||
"""Create a silent SCons action that suppresses output"""
|
||||
silent_action = env.Action(action_func)
|
||||
silent_action.strfunction = lambda target, source, env: ''
|
||||
return silent_action
|
||||
|
||||
# Arduino framework as a component is not compatible with ESP-IDF >5.3
|
||||
if "arduino" in env.subst("$PIOFRAMEWORK"):
|
||||
ARDUINO_FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32")
|
||||
ARDUINO_FRMWRK_LIB_DIR = platform.get_package_dir("framework-arduinoespressif32-libs")
|
||||
if mcu == "esp32c2":
|
||||
ARDUINO_FRMWRK_C2_LIB_DIR = join(ARDUINO_FRMWRK_LIB_DIR, mcu)
|
||||
if not os.path.exists(ARDUINO_FRMWRK_C2_LIB_DIR):
|
||||
ARDUINO_C2_DIR = join(platform.get_package_dir("framework-arduino-c2-skeleton-lib"),mcu)
|
||||
shutil.copytree(ARDUINO_C2_DIR, ARDUINO_FRMWRK_C2_LIB_DIR, dirs_exist_ok=True)
|
||||
# Possible package names in 'package@version' format is not compatible with CMake
|
||||
if "@" in os.path.basename(ARDUINO_FRAMEWORK_DIR):
|
||||
new_path = os.path.join(
|
||||
@@ -168,6 +173,7 @@ if "arduino" in env.subst("$PIOFRAMEWORK"):
|
||||
os.rename(ARDUINO_FRAMEWORK_DIR, new_path)
|
||||
ARDUINO_FRAMEWORK_DIR = new_path
|
||||
assert ARDUINO_FRAMEWORK_DIR and os.path.isdir(ARDUINO_FRAMEWORK_DIR)
|
||||
arduino_libs_mcu = join(platform.get_package_dir("framework-arduinoespressif32-libs"),mcu)
|
||||
|
||||
BUILD_DIR = env.subst("$BUILD_DIR")
|
||||
PROJECT_DIR = env.subst("$PROJECT_DIR")
|
||||
@@ -178,6 +184,18 @@ SDKCONFIG_PATH = os.path.expandvars(board.get(
|
||||
os.path.join(PROJECT_DIR, "sdkconfig.%s" % env.subst("$PIOENV")),
|
||||
))
|
||||
|
||||
def contains_path_traversal(url):
|
||||
"""Check for Path Traversal patterns"""
|
||||
dangerous_patterns = [
|
||||
'../', '..\\', # Standard Path Traversal
|
||||
'%2e%2e%2f', '%2e%2e%5c', # URL-encoded
|
||||
'..%2f', '..%5c', # Mixed
|
||||
'%252e%252e%252f', # Double encoded
|
||||
]
|
||||
|
||||
url_lower = url.lower()
|
||||
return any(pattern in url_lower for pattern in dangerous_patterns)
|
||||
|
||||
#
|
||||
# generate modified Arduino IDF sdkconfig, applying settings from "custom_sdkconfig"
|
||||
#
|
||||
@@ -192,180 +210,208 @@ if "espidf.custom_sdkconfig" in board:
|
||||
flag_custom_sdkonfig = True
|
||||
|
||||
def HandleArduinoIDFsettings(env):
|
||||
"""
|
||||
Handles Arduino IDF settings configuration with custom sdkconfig support.
|
||||
"""
|
||||
|
||||
def get_MD5_hash(phrase):
|
||||
"""Generate MD5 hash for checksum validation."""
|
||||
import hashlib
|
||||
return hashlib.md5((phrase).encode('utf-8')).hexdigest()[:16]
|
||||
return hashlib.md5(phrase.encode('utf-8')).hexdigest()[:16]
|
||||
|
||||
def custom_sdkconfig_file(string):
|
||||
if not config.has_option("env:"+env["PIOENV"], "custom_sdkconfig"):
|
||||
def load_custom_sdkconfig_file():
|
||||
"""Load custom sdkconfig from file or URL if specified."""
|
||||
if not config.has_option("env:" + env["PIOENV"], "custom_sdkconfig"):
|
||||
return ""
|
||||
sdkconfig_entrys = env.GetProjectOption("custom_sdkconfig").splitlines()
|
||||
for file in sdkconfig_entrys:
|
||||
if "http" in file and "://" in file:
|
||||
response = requests.get(file.split(" ")[0])
|
||||
if response.ok:
|
||||
target = str(response.content.decode('utf-8'))
|
||||
|
||||
sdkconfig_entries = env.GetProjectOption("custom_sdkconfig").splitlines()
|
||||
|
||||
for file_entry in sdkconfig_entries:
|
||||
# Handle HTTP/HTTPS URLs
|
||||
if "http" in file_entry and "://" in file_entry:
|
||||
url = file_entry.split(" ")[0]
|
||||
# Path Traversal protection
|
||||
if contains_path_traversal(url):
|
||||
print(f"Path Traversal detected: {url} check your URL path")
|
||||
else:
|
||||
print("Failed to download:", file)
|
||||
return ""
|
||||
return target
|
||||
if "file://" in file:
|
||||
file_path = join(PROJECT_DIR,file.lstrip("file://").split(os.path.sep)[-1])
|
||||
try:
|
||||
response = requests.get(file_entry.split(" ")[0], timeout=10)
|
||||
if response.ok:
|
||||
return response.content.decode('utf-8')
|
||||
except requests.RequestException as e:
|
||||
print(f"Error downloading {file_entry}: {e}")
|
||||
except UnicodeDecodeError as e:
|
||||
print(f"Error decoding response from {file_entry}: {e}")
|
||||
return ""
|
||||
|
||||
# Handle local files
|
||||
if "file://" in file_entry:
|
||||
file_ref = file_entry[7:] if file_entry.startswith("file://") else file_entry
|
||||
filename = os.path.basename(file_ref)
|
||||
file_path = join(PROJECT_DIR, filename)
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r') as file:
|
||||
target = file.read()
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
return f.read()
|
||||
except IOError as e:
|
||||
print(f"Error reading file {file_path}: {e}")
|
||||
return ""
|
||||
else:
|
||||
print("File not found:", file_path)
|
||||
print("File not found, check path:", file_path)
|
||||
return ""
|
||||
return target
|
||||
|
||||
return ""
|
||||
|
||||
def extract_flag_name(line):
|
||||
"""Extract flag name from sdkconfig line."""
|
||||
line = line.strip()
|
||||
if line.startswith("#") and "is not set" in line:
|
||||
return line.split(" ")[1]
|
||||
elif not line.startswith("#") and "=" in line:
|
||||
return line.split("=")[0]
|
||||
return None
|
||||
|
||||
custom_sdk_config_flags = ""
|
||||
board_idf_config_flags = ""
|
||||
sdkconfig_file_flags = ""
|
||||
custom_sdkconfig_file_str = ""
|
||||
def build_idf_config_flags():
|
||||
"""Build complete IDF configuration flags from all sources."""
|
||||
flags = []
|
||||
|
||||
# Add board-specific flags first
|
||||
if "espidf.custom_sdkconfig" in board:
|
||||
board_flags = board.get("espidf.custom_sdkconfig", [])
|
||||
if board_flags:
|
||||
flags.extend(board_flags)
|
||||
|
||||
# Add custom sdkconfig file content
|
||||
custom_file_content = load_custom_sdkconfig_file()
|
||||
if custom_file_content:
|
||||
flags.append(custom_file_content)
|
||||
|
||||
# Add project-level custom sdkconfig
|
||||
if config.has_option("env:" + env["PIOENV"], "custom_sdkconfig"):
|
||||
custom_flags = env.GetProjectOption("custom_sdkconfig").rstrip("\n")
|
||||
if custom_flags:
|
||||
flags.append(custom_flags)
|
||||
|
||||
return "\n".join(flags) + "\n" if flags else ""
|
||||
|
||||
if config.has_option("env:"+env["PIOENV"], "custom_sdkconfig"):
|
||||
flag_custom_sdkonfig = True
|
||||
custom_sdk_config_flags = (env.GetProjectOption("custom_sdkconfig").rstrip("\n")) + "\n"
|
||||
custom_sdkconfig_file_str = custom_sdkconfig_file(sdkconfig_file_flags)
|
||||
|
||||
if "espidf.custom_sdkconfig" in board:
|
||||
board_idf_config_flags = ('\n'.join([element for element in board.get("espidf.custom_sdkconfig", "")])).rstrip("\n") + "\n"
|
||||
flag_custom_sdkonfig = True
|
||||
|
||||
if flag_custom_sdkonfig == True: # TDOO duplicated
|
||||
print("*** Add \"custom_sdkconfig\" settings to IDF sdkconfig.defaults ***")
|
||||
idf_config_flags = custom_sdk_config_flags
|
||||
if custom_sdkconfig_file_str != "":
|
||||
sdkconfig_file_flags = custom_sdkconfig_file_str + "\n"
|
||||
idf_config_flags = sdkconfig_file_flags + idf_config_flags
|
||||
idf_config_flags = board_idf_config_flags + idf_config_flags
|
||||
def add_flash_configuration(config_flags):
|
||||
"""Add flash frequency and mode configuration."""
|
||||
if flash_frequency != "80m":
|
||||
idf_config_flags = idf_config_flags + "# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set\n"
|
||||
esptool_flashfreq_y = "CONFIG_ESPTOOLPY_FLASHFREQ_%s=y\n" % flash_frequency.upper()
|
||||
esptool_flashfreq_M = "CONFIG_ESPTOOLPY_FLASHFREQ=\"%s\"\n" % flash_frequency
|
||||
idf_config_flags = idf_config_flags + esptool_flashfreq_y + esptool_flashfreq_M
|
||||
config_flags += "# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set\n"
|
||||
config_flags += f"CONFIG_ESPTOOLPY_FLASHFREQ_{flash_frequency.upper()}=y\n"
|
||||
config_flags += f"CONFIG_ESPTOOLPY_FLASHFREQ=\"{flash_frequency}\"\n"
|
||||
|
||||
if flash_mode != "qio":
|
||||
idf_config_flags = idf_config_flags + "# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set\n"
|
||||
esptool_flashmode = "CONFIG_ESPTOOLPY_FLASHMODE_%s=y\n" % flash_mode.upper()
|
||||
if esptool_flashmode not in idf_config_flags:
|
||||
idf_config_flags = idf_config_flags + esptool_flashmode
|
||||
if mcu in ("esp32") and "CONFIG_FREERTOS_UNICORE=y" in idf_config_flags:
|
||||
idf_config_flags = idf_config_flags + "# CONFIG_SPIRAM is not set\n"
|
||||
config_flags += "# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set\n"
|
||||
|
||||
flash_mode_flag = f"CONFIG_ESPTOOLPY_FLASHMODE_{flash_mode.upper()}=y\n"
|
||||
if flash_mode_flag not in config_flags:
|
||||
config_flags += flash_mode_flag
|
||||
|
||||
# ESP32 specific SPIRAM configuration
|
||||
if mcu == "esp32" and "CONFIG_FREERTOS_UNICORE=y" in config_flags:
|
||||
config_flags += "# CONFIG_SPIRAM is not set\n"
|
||||
|
||||
return config_flags
|
||||
|
||||
idf_config_flags = idf_config_flags.splitlines()
|
||||
sdkconfig_src = join(ARDUINO_FRMWRK_LIB_DIR,mcu,"sdkconfig")
|
||||
|
||||
def get_flag(line):
|
||||
if line.startswith("#") and "is not set" in line:
|
||||
return line.split(" ")[1]
|
||||
elif not line.startswith("#") and len(line.split("=")) > 1:
|
||||
return line.split("=")[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
with open(sdkconfig_src) as src:
|
||||
sdkconfig_dst = os.path.join(PROJECT_DIR, "sdkconfig.defaults")
|
||||
dst = open(sdkconfig_dst,"w")
|
||||
dst.write("# TASMOTA__"+ get_MD5_hash(''.join(custom_sdk_config_flags).strip() + mcu) +"\n")
|
||||
while line := src.readline():
|
||||
flag = get_flag(line)
|
||||
if flag is None:
|
||||
def write_sdkconfig_file(idf_config_flags, checksum_source):
|
||||
if "arduino" not in env.subst("$PIOFRAMEWORK"):
|
||||
print("Error: Arduino framework required for sdkconfig processing")
|
||||
return
|
||||
"""Write the final sdkconfig.defaults file with checksum."""
|
||||
sdkconfig_src = join(arduino_libs_mcu, "sdkconfig")
|
||||
sdkconfig_dst = join(PROJECT_DIR, "sdkconfig.defaults")
|
||||
|
||||
# Generate checksum for validation (maintains original logic)
|
||||
checksum = get_MD5_hash(checksum_source.strip() + mcu)
|
||||
|
||||
with open(sdkconfig_src, 'r', encoding='utf-8') as src, open(sdkconfig_dst, 'w', encoding='utf-8') as dst:
|
||||
# Write checksum header (critical for compilation decision logic)
|
||||
dst.write(f"# TASMOTA__{checksum}\n")
|
||||
|
||||
processed_flags = set()
|
||||
|
||||
# Process each line from source sdkconfig
|
||||
for line in src:
|
||||
flag_name = extract_flag_name(line)
|
||||
|
||||
if flag_name is None:
|
||||
dst.write(line)
|
||||
else:
|
||||
no_match = True
|
||||
for item in idf_config_flags:
|
||||
if flag == get_flag(item.replace("\'", "")):
|
||||
dst.write(item.replace("\'", "")+"\n")
|
||||
no_match = False
|
||||
print("Replace:",line,"with:",item.replace("\'", ""))
|
||||
idf_config_flags.remove(item)
|
||||
if no_match:
|
||||
dst.write(line)
|
||||
for item in idf_config_flags: # are there new flags?
|
||||
print("Add:",item.replace("\'", ""))
|
||||
dst.write(item.replace("\'", "")+"\n")
|
||||
dst.close()
|
||||
return
|
||||
else:
|
||||
continue
|
||||
|
||||
# Check if we have a custom replacement for this flag
|
||||
flag_replaced = False
|
||||
for custom_flag in idf_config_flags[:]: # Create copy for safe removal
|
||||
custom_flag_name = extract_flag_name(custom_flag.replace("'", ""))
|
||||
|
||||
if flag_name == custom_flag_name:
|
||||
cleaned_flag = custom_flag.replace("'", "")
|
||||
dst.write(cleaned_flag + "\n")
|
||||
print(f"Replace: {line.strip()} with: {cleaned_flag}")
|
||||
idf_config_flags.remove(custom_flag)
|
||||
processed_flags.add(custom_flag_name)
|
||||
flag_replaced = True
|
||||
break
|
||||
|
||||
if not flag_replaced:
|
||||
dst.write(line)
|
||||
|
||||
# Add any remaining new flags
|
||||
for remaining_flag in idf_config_flags:
|
||||
cleaned_flag = remaining_flag.replace("'", "")
|
||||
print(f"Add: {cleaned_flag}")
|
||||
dst.write(cleaned_flag + "\n")
|
||||
|
||||
# Main execution logic
|
||||
has_custom_config = (
|
||||
config.has_option("env:" + env["PIOENV"], "custom_sdkconfig") or
|
||||
"espidf.custom_sdkconfig" in board
|
||||
)
|
||||
|
||||
if not has_custom_config:
|
||||
return
|
||||
|
||||
print("*** Add \"custom_sdkconfig\" settings to IDF sdkconfig.defaults ***")
|
||||
|
||||
# Build complete configuration
|
||||
idf_config_flags = build_idf_config_flags()
|
||||
idf_config_flags = add_flash_configuration(idf_config_flags)
|
||||
|
||||
# Convert to list for processing
|
||||
idf_config_list = [line for line in idf_config_flags.splitlines() if line.strip()]
|
||||
|
||||
# Write final configuration file with checksum
|
||||
custom_sdk_config_flags = ""
|
||||
if config.has_option("env:" + env["PIOENV"], "custom_sdkconfig"):
|
||||
custom_sdk_config_flags = env.GetProjectOption("custom_sdkconfig").rstrip("\n") + "\n"
|
||||
|
||||
write_sdkconfig_file(idf_config_list, custom_sdk_config_flags)
|
||||
|
||||
|
||||
|
||||
def HandleCOMPONENTsettings(env):
|
||||
if flag_custom_component_add == True or flag_custom_component_remove == True: # todo remove duplicated
|
||||
import yaml
|
||||
from yaml import SafeLoader
|
||||
print("*** \"custom_component\" is used to select managed idf components ***")
|
||||
if flag_custom_component_remove == True:
|
||||
idf_custom_component_remove = env.GetProjectOption("custom_component_remove").splitlines()
|
||||
else:
|
||||
idf_custom_component_remove = ""
|
||||
if flag_custom_component_add == True:
|
||||
idf_custom_component_add = env.GetProjectOption("custom_component_add").splitlines()
|
||||
else:
|
||||
idf_custom_component_add = ""
|
||||
from component_manager import ComponentManager
|
||||
component_manager = ComponentManager(env)
|
||||
|
||||
# search "idf_component.yml" file
|
||||
try: # 1.st in Arduino framework
|
||||
idf_component_yml_src = os.path.join(ARDUINO_FRAMEWORK_DIR, "idf_component.yml")
|
||||
shutil.copy(join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml"),join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml.orig"))
|
||||
yml_file_dir = idf_component_yml_src
|
||||
except: # 2.nd Project source
|
||||
try:
|
||||
idf_component_yml_src = os.path.join(PROJECT_SRC_DIR, "idf_component.yml")
|
||||
shutil.copy(join(PROJECT_SRC_DIR,"idf_component.yml"),join(PROJECT_SRC_DIR,"idf_component.yml.orig"))
|
||||
yml_file_dir = idf_component_yml_src
|
||||
except: # no idf_component.yml in Project source -> create
|
||||
idf_component_yml_src = os.path.join(PROJECT_SRC_DIR, "idf_component.yml")
|
||||
yml_file_dir = idf_component_yml_src
|
||||
idf_component_yml_str = """
|
||||
dependencies:
|
||||
idf: \">=5.1\"
|
||||
"""
|
||||
idf_component_yml = yaml.safe_load(idf_component_yml_str)
|
||||
with open(idf_component_yml_src, 'w',) as f :
|
||||
yaml.dump(idf_component_yml,f)
|
||||
if flag_custom_component_add or flag_custom_component_remove:
|
||||
actions = [action for flag, action in [
|
||||
(flag_custom_component_add, "select"),
|
||||
(flag_custom_component_remove, "deselect")
|
||||
] if flag]
|
||||
action_text = " and ".join(actions)
|
||||
print(f"*** \"custom_component\" is used to {action_text} managed idf components ***")
|
||||
|
||||
yaml_file=open(idf_component_yml_src,"r")
|
||||
idf_component=yaml.load(yaml_file, Loader=SafeLoader)
|
||||
idf_component_str=json.dumps(idf_component) # convert to json string
|
||||
idf_component_json=json.loads(idf_component_str) # convert string to json dict
|
||||
|
||||
if idf_custom_component_remove != "":
|
||||
for entry in idf_custom_component_remove:
|
||||
# checking if the entry exists before removing
|
||||
if entry in idf_component_json["dependencies"]:
|
||||
print("*** Removing component:",entry)
|
||||
del idf_component_json["dependencies"][entry]
|
||||
|
||||
if idf_custom_component_add != "":
|
||||
for entry in idf_custom_component_add:
|
||||
if len(str(entry)) > 4: # too short or empty entry
|
||||
# add new entrys to json
|
||||
if "@" in entry:
|
||||
idf_comp_entry = str(entry.split("@")[0]).replace(" ", "")
|
||||
idf_comp_vers = str(entry.split("@")[1]).replace(" ", "")
|
||||
else:
|
||||
idf_comp_entry = str(entry).replace(" ", "")
|
||||
idf_comp_vers = "*"
|
||||
if idf_comp_entry not in idf_component_json["dependencies"]:
|
||||
print("*** Adding component:", idf_comp_entry, idf_comp_vers)
|
||||
new_entry = {idf_comp_entry: {"version": idf_comp_vers}}
|
||||
idf_component_json["dependencies"].update(new_entry)
|
||||
|
||||
idf_component_yml_file = open(yml_file_dir,"w")
|
||||
yaml.dump(idf_component_json, idf_component_yml_file)
|
||||
idf_component_yml_file.close()
|
||||
# print("JSON from modified idf_component.yml:")
|
||||
# print(json.dumps(idf_component_json))
|
||||
component_manager.handle_component_settings(
|
||||
add_components=flag_custom_component_add,
|
||||
remove_components=flag_custom_component_remove
|
||||
)
|
||||
return
|
||||
return
|
||||
|
||||
if flag_custom_component_add == True or flag_custom_component_remove == True:
|
||||
if "arduino" in env.subst("$PIOFRAMEWORK"):
|
||||
HandleCOMPONENTsettings(env)
|
||||
|
||||
if flag_custom_sdkonfig == True and "arduino" in env.subst("$PIOFRAMEWORK"):
|
||||
if flag_custom_sdkonfig == True and "arduino" in env.subst("$PIOFRAMEWORK") and "espidf" not in env.subst("$PIOFRAMEWORK"):
|
||||
HandleArduinoIDFsettings(env)
|
||||
LIB_SOURCE = os.path.join(ProjectConfig.get_instance().get("platformio", "platforms_dir"), "espressif32", "builder", "build_lib")
|
||||
if not bool(os.path.exists(os.path.join(PROJECT_DIR, ".dummy"))):
|
||||
@@ -397,7 +443,6 @@ def get_project_lib_includes(env):
|
||||
|
||||
return paths
|
||||
|
||||
|
||||
def is_cmake_reconfigure_required(cmake_api_reply_dir):
|
||||
cmake_cache_file = os.path.join(BUILD_DIR, "CMakeCache.txt")
|
||||
cmake_txt_files = [
|
||||
@@ -536,6 +581,8 @@ def populate_idf_env_vars(idf_env):
|
||||
if "IDF_TOOLS_PATH" in idf_env:
|
||||
del idf_env["IDF_TOOLS_PATH"]
|
||||
|
||||
idf_env["ESP_ROM_ELF_DIR"] = platform.get_package_dir("tool-esp-rom-elfs")
|
||||
|
||||
|
||||
def get_target_config(project_configs, target_index, cmake_api_reply_dir):
|
||||
target_json = project_configs.get("targets")[target_index].get("jsonFile", "")
|
||||
@@ -595,6 +642,8 @@ def extract_defines(compile_group):
|
||||
define_string = define_string.strip()
|
||||
if "=" in define_string:
|
||||
define, value = define_string.split("=", maxsplit=1)
|
||||
if define == "OPENTHREAD_BUILD_DATETIME":
|
||||
return None
|
||||
if any(char in value for char in (' ', '<', '>')):
|
||||
value = f'"{value}"'
|
||||
elif '"' in value and not value.startswith("\\"):
|
||||
@@ -1531,11 +1580,10 @@ def install_python_deps():
|
||||
# https://github.com/platformio/platformio-core/issues/4614
|
||||
"urllib3": "<2",
|
||||
# https://github.com/platformio/platform-espressif32/issues/635
|
||||
"cryptography": "~=41.0.1",
|
||||
"future": ">=0.18.3",
|
||||
"cryptography": "~=44.0.0",
|
||||
"pyparsing": ">=3.1.0,<4",
|
||||
"idf-component-manager": "~=2.0.1",
|
||||
"esp-idf-kconfig": ">=2.5.0"
|
||||
"esp-idf-kconfig": "~=2.5.0"
|
||||
}
|
||||
|
||||
if sys_platform.system() == "Darwin" and "arm" in sys_platform.machine().lower():
|
||||
@@ -1556,7 +1604,7 @@ def install_python_deps():
|
||||
env.Execute(
|
||||
env.VerboseAction(
|
||||
(
|
||||
'"%s" -m pip install -U ' % python_exe_path
|
||||
'"%s" -m pip install -U -q -q -q ' % python_exe_path
|
||||
+ " ".join(['"%s%s"' % (p, deps[p]) for p in packages_to_install])
|
||||
),
|
||||
"Installing ESP-IDF's Python dependencies",
|
||||
@@ -1566,7 +1614,7 @@ def install_python_deps():
|
||||
if IS_WINDOWS and "windows-curses" not in installed_packages:
|
||||
env.Execute(
|
||||
env.VerboseAction(
|
||||
'"%s" -m pip install windows-curses' % python_exe_path,
|
||||
'"%s" -m pip install -q -q -q windows-curses' % python_exe_path,
|
||||
"Installing windows-curses package",
|
||||
)
|
||||
)
|
||||
@@ -1786,18 +1834,36 @@ if "arduino" in env.subst("$PIOFRAMEWORK"):
|
||||
LIBSOURCE_DIRS=[os.path.join(ARDUINO_FRAMEWORK_DIR, "libraries")]
|
||||
)
|
||||
|
||||
# Set ESP-IDF version environment variables (needed for proper Kconfig processing)
|
||||
framework_version = get_framework_version()
|
||||
major_version = framework_version.split('.')[0] + '.' + framework_version.split('.')[1]
|
||||
os.environ["ESP_IDF_VERSION"] = major_version
|
||||
|
||||
# Configure CMake arguments with ESP-IDF version
|
||||
extra_cmake_args = [
|
||||
"-DIDF_TARGET=" + idf_variant,
|
||||
"-DPYTHON_DEPS_CHECKED=1",
|
||||
"-DEXTRA_COMPONENT_DIRS:PATH=" + ";".join(extra_components),
|
||||
"-DPYTHON=" + get_python_exe(),
|
||||
"-DSDKCONFIG=" + SDKCONFIG_PATH,
|
||||
f"-DESP_IDF_VERSION={major_version}",
|
||||
f"-DESP_IDF_VERSION_MAJOR={framework_version.split('.')[0]}",
|
||||
f"-DESP_IDF_VERSION_MINOR={framework_version.split('.')[1]}",
|
||||
]
|
||||
|
||||
# This will add the linker flag for the map file
|
||||
extra_cmake_args.append(
|
||||
f'-DCMAKE_EXE_LINKER_FLAGS=-Wl,-Map={os.path.join(BUILD_DIR, env.subst("$PROGNAME") + ".map")}'
|
||||
)
|
||||
|
||||
# Add any extra args from board config
|
||||
extra_cmake_args += click.parser.split_arg_string(board.get("build.cmake_extra_args", ""))
|
||||
|
||||
print("Reading CMake configuration...")
|
||||
project_codemodel = get_cmake_code_model(
|
||||
PROJECT_DIR,
|
||||
BUILD_DIR,
|
||||
[
|
||||
"-DIDF_TARGET=" + idf_variant,
|
||||
"-DPYTHON_DEPS_CHECKED=1",
|
||||
"-DEXTRA_COMPONENT_DIRS:PATH=" + ";".join(extra_components),
|
||||
"-DPYTHON=" + get_python_exe(),
|
||||
"-DSDKCONFIG=" + SDKCONFIG_PATH,
|
||||
]
|
||||
+ click.parser.split_arg_string(board.get("build.cmake_extra_args", "")),
|
||||
extra_cmake_args
|
||||
)
|
||||
|
||||
# At this point the sdkconfig file should be generated by the underlying build system
|
||||
@@ -1973,7 +2039,7 @@ env.Prepend(
|
||||
(
|
||||
board.get(
|
||||
"upload.bootloader_offset",
|
||||
"0x1000" if mcu in ["esp32", "esp32s2"] else ("0x2000" if mcu in ["esp32p4"] else "0x0"),
|
||||
"0x1000" if mcu in ["esp32", "esp32s2"] else ("0x2000" if mcu in ["esp32c5", "esp32p4"] else "0x0"),
|
||||
),
|
||||
os.path.join("$BUILD_DIR", "bootloader.bin"),
|
||||
),
|
||||
@@ -2063,6 +2129,15 @@ extra_elf2bin_flags = "--elf-sha256-offset 0xb0"
|
||||
# For chips that support configurable MMU page size feature
|
||||
# If page size is configured to values other than the default "64KB" in menuconfig,
|
||||
mmu_page_size = "64KB"
|
||||
if sdk_config.get("MMU_PAGE_SIZE_8KB", False):
|
||||
mmu_page_size = "8KB"
|
||||
elif sdk_config.get("MMU_PAGE_SIZE_16KB", False):
|
||||
mmu_page_size = "16KB"
|
||||
elif sdk_config.get("MMU_PAGE_SIZE_32KB", False):
|
||||
mmu_page_size = "32KB"
|
||||
else:
|
||||
mmu_page_size = "64KB"
|
||||
|
||||
if sdk_config.get("SOC_MMU_PAGE_SIZE_CONFIGURABLE", False):
|
||||
if board_flash_size == "2MB":
|
||||
mmu_page_size = "32KB"
|
||||
@@ -2091,7 +2166,7 @@ if os.path.isdir(ulp_dir) and os.listdir(ulp_dir) and mcu not in ("esp32c2", "es
|
||||
# Compile Arduino IDF sources
|
||||
#
|
||||
|
||||
if "arduino" in env.get("PIOFRAMEWORK") and "espidf" not in env.get("PIOFRAMEWORK"):
|
||||
if ("arduino" in env.subst("$PIOFRAMEWORK")) and ("espidf" not in env.subst("$PIOFRAMEWORK")):
|
||||
def idf_lib_copy(source, target, env):
|
||||
env_build = join(env["PROJECT_BUILD_DIR"],env["PIOENV"])
|
||||
sdkconfig_h_path = join(env_build,"config","sdkconfig.h")
|
||||
@@ -2147,9 +2222,14 @@ if "arduino" in env.get("PIOFRAMEWORK") and "espidf" not in env.get("PIOFRAMEWOR
|
||||
print("*** Original Arduino \"idf_component.yml\" restored ***")
|
||||
except:
|
||||
print("*** Original Arduino \"idf_component.yml\" couldnt be restored ***")
|
||||
env.AddPostAction("checkprogsize", idf_lib_copy)
|
||||
# Restore original pioarduino-build.py
|
||||
from component_manager import ComponentManager
|
||||
component_manager = ComponentManager(env)
|
||||
component_manager.restore_pioarduino_build_py()
|
||||
silent_action = create_silent_action(idf_lib_copy)
|
||||
env.AddPostAction("checkprogsize", silent_action)
|
||||
|
||||
if "espidf" in env.get("PIOFRAMEWORK") and (flag_custom_component_add == True or flag_custom_component_remove == True):
|
||||
if "espidf" in env.subst("$PIOFRAMEWORK") and (flag_custom_component_add == True or flag_custom_component_remove == True):
|
||||
def idf_custom_component(source, target, env):
|
||||
try:
|
||||
shutil.copy(join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml.orig"),join(ARDUINO_FRAMEWORK_DIR,"idf_component.yml"))
|
||||
@@ -2163,8 +2243,14 @@ if "espidf" in env.get("PIOFRAMEWORK") and (flag_custom_component_add == True or
|
||||
os.remove(join(PROJECT_SRC_DIR,"idf_component.yml"))
|
||||
print("*** pioarduino generated \"idf_component.yml\" removed ***")
|
||||
except:
|
||||
print("*** \"idf_component.yml\" couldnt be removed ***")
|
||||
env.AddPostAction("checkprogsize", idf_custom_component)
|
||||
print("*** no custom \"idf_component.yml\" found for removing ***")
|
||||
if "arduino" in env.subst("$PIOFRAMEWORK"):
|
||||
# Restore original pioarduino-build.py, only used with Arduino
|
||||
from component_manager import ComponentManager
|
||||
component_manager = ComponentManager(env)
|
||||
component_manager.restore_pioarduino_build_py()
|
||||
silent_action = create_silent_action(idf_custom_component)
|
||||
env.AddPostAction("checkprogsize", silent_action)
|
||||
#
|
||||
# Process OTA partition and image
|
||||
#
|
||||
@@ -2219,7 +2305,7 @@ def _parse_size(value):
|
||||
partitions_csv = env.subst("$PARTITIONS_TABLE_CSV")
|
||||
result = []
|
||||
next_offset = 0
|
||||
bound = int(board.get("upload.offset_address", "0x10000"), 16) # default 0x10000
|
||||
bound = 0x10000
|
||||
with open(partitions_csv) as fp:
|
||||
for line in fp.readlines():
|
||||
line = line.strip()
|
||||
|
||||
@@ -37,7 +37,7 @@ def prepare_ulp_env_vars(env):
|
||||
|
||||
toolchain_path = platform.get_package_dir(
|
||||
"toolchain-xtensa-esp-elf"
|
||||
if idf_variant not in ("esp32c6", "esp32p4")
|
||||
if idf_variant not in ("esp32c5","esp32c6", "esp32p4")
|
||||
else "toolchain-riscv32-esp"
|
||||
)
|
||||
|
||||
|
||||
+333
-127
@@ -12,31 +12,47 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
from os.path import isfile, join
|
||||
|
||||
from SCons.Script import (
|
||||
ARGUMENTS, COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default,
|
||||
DefaultEnvironment)
|
||||
ARGUMENTS,
|
||||
COMMAND_LINE_TARGETS,
|
||||
AlwaysBuild,
|
||||
Builder,
|
||||
Default,
|
||||
DefaultEnvironment,
|
||||
)
|
||||
|
||||
from platformio.project.helpers import get_project_dir
|
||||
from platformio.util import get_serial_ports
|
||||
|
||||
# Initialize environment and configuration
|
||||
env = DefaultEnvironment()
|
||||
platform = env.PioPlatform()
|
||||
projectconfig = env.GetProjectConfig()
|
||||
terminal_cp = locale.getpreferredencoding().lower()
|
||||
|
||||
#
|
||||
# Helpers
|
||||
#
|
||||
|
||||
# Framework directory path
|
||||
FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32")
|
||||
|
||||
|
||||
def BeforeUpload(target, source, env):
|
||||
"""
|
||||
Prepare the environment before uploading firmware.
|
||||
Handles port detection and special upload configurations.
|
||||
"""
|
||||
upload_options = {}
|
||||
if "BOARD" in env:
|
||||
upload_options = env.BoardConfig().get("upload", {})
|
||||
|
||||
env.AutodetectUploadPort()
|
||||
if not env.subst("$UPLOAD_PORT"):
|
||||
env.AutodetectUploadPort()
|
||||
|
||||
before_ports = get_serial_ports()
|
||||
if upload_options.get("use_1200bps_touch", False):
|
||||
@@ -47,6 +63,10 @@ def BeforeUpload(target, source, env):
|
||||
|
||||
|
||||
def _get_board_memory_type(env):
|
||||
"""
|
||||
Determine the memory type configuration for the board.
|
||||
Returns the appropriate memory type string based on board configuration.
|
||||
"""
|
||||
board_config = env.BoardConfig()
|
||||
default_type = "%s_%s" % (
|
||||
board_config.get("build.flash_mode", "dio"),
|
||||
@@ -62,24 +82,33 @@ def _get_board_memory_type(env):
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _normalize_frequency(frequency):
|
||||
"""
|
||||
Convert frequency value to normalized string format (e.g., "40m").
|
||||
Removes 'L' suffix and converts to MHz format.
|
||||
"""
|
||||
frequency = str(frequency).replace("L", "")
|
||||
return str(int(int(frequency) / 1000000)) + "m"
|
||||
|
||||
|
||||
def _get_board_f_flash(env):
|
||||
"""Get the flash frequency for the board."""
|
||||
frequency = env.subst("$BOARD_F_FLASH")
|
||||
return _normalize_frequency(frequency)
|
||||
|
||||
|
||||
def _get_board_f_image(env):
|
||||
"""Get the image frequency for the board, fallback to flash frequency."""
|
||||
board_config = env.BoardConfig()
|
||||
if "build.f_image" in board_config:
|
||||
return _normalize_frequency(board_config.get("build.f_image"))
|
||||
|
||||
return _get_board_f_flash(env)
|
||||
|
||||
|
||||
def _get_board_f_boot(env):
|
||||
"""Get the boot frequency for the board, fallback to flash frequency."""
|
||||
board_config = env.BoardConfig()
|
||||
if "build.f_boot" in board_config:
|
||||
return _normalize_frequency(board_config.get("build.f_boot"))
|
||||
@@ -88,10 +117,11 @@ def _get_board_f_boot(env):
|
||||
|
||||
|
||||
def _get_board_flash_mode(env):
|
||||
if _get_board_memory_type(env) in (
|
||||
"opi_opi",
|
||||
"opi_qspi",
|
||||
):
|
||||
"""
|
||||
Determine the appropriate flash mode for the board.
|
||||
Handles special cases for OPI memory types.
|
||||
"""
|
||||
if _get_board_memory_type(env) in ("opi_opi", "opi_qspi"):
|
||||
return "dout"
|
||||
|
||||
mode = env.subst("$BOARD_FLASH_MODE")
|
||||
@@ -101,6 +131,10 @@ def _get_board_flash_mode(env):
|
||||
|
||||
|
||||
def _get_board_boot_mode(env):
|
||||
"""
|
||||
Determine the boot mode for the board.
|
||||
Handles special cases for OPI memory types.
|
||||
"""
|
||||
memory_type = env.BoardConfig().get("build.arduino.memory_type", "")
|
||||
build_boot = env.BoardConfig().get("build.boot", "$BOARD_FLASH_MODE")
|
||||
if memory_type in ("opi_opi", "opi_qspi"):
|
||||
@@ -109,6 +143,10 @@ def _get_board_boot_mode(env):
|
||||
|
||||
|
||||
def _parse_size(value):
|
||||
"""
|
||||
Parse size values from various formats (int, hex, K/M suffixes).
|
||||
Returns the size in bytes as an integer.
|
||||
"""
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
elif value.isdigit():
|
||||
@@ -122,16 +160,23 @@ def _parse_size(value):
|
||||
|
||||
|
||||
def _parse_partitions(env):
|
||||
"""
|
||||
Parse the partition table CSV file and return partition information.
|
||||
Also sets the application offset for the environment.
|
||||
"""
|
||||
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)
|
||||
sys.stderr.write(
|
||||
"Could not find the file %s with partitions table.\n"
|
||||
% partitions_csv
|
||||
)
|
||||
env.Exit(1)
|
||||
return
|
||||
|
||||
result = []
|
||||
next_offset = 0
|
||||
app_offset = int(board.get("upload.offset_address", "0x10000"), 16) # default 0x10000
|
||||
app_offset = 0x10000 # Default address for firmware
|
||||
|
||||
with open(partitions_csv) as fp:
|
||||
for line in fp.readlines():
|
||||
line = line.strip()
|
||||
@@ -148,25 +193,34 @@ def _parse_partitions(env):
|
||||
"subtype": tokens[2],
|
||||
"offset": tokens[3] or calculated_offset,
|
||||
"size": tokens[4],
|
||||
"flags": tokens[5] if len(tokens) > 5 else None
|
||||
"flags": tokens[5] if len(tokens) > 5 else None,
|
||||
}
|
||||
result.append(partition)
|
||||
next_offset = _parse_size(partition["offset"])
|
||||
if (partition["subtype"] == "ota_0"):
|
||||
if partition["subtype"] == "ota_0":
|
||||
app_offset = next_offset
|
||||
next_offset = next_offset + _parse_size(partition["size"])
|
||||
|
||||
# Configure application partition offset
|
||||
env.Replace(ESP32_APP_OFFSET=str(hex(app_offset)))
|
||||
# Propagate application offset to debug configurations
|
||||
env["INTEGRATION_EXTRA_DATA"].update({"application_offset": str(hex(app_offset))})
|
||||
env["INTEGRATION_EXTRA_DATA"].update(
|
||||
{"application_offset": str(hex(app_offset))}
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def _update_max_upload_size(env):
|
||||
"""
|
||||
Update the maximum upload size based on partition table configuration.
|
||||
Prioritizes user-specified partition names.
|
||||
"""
|
||||
if not env.get("PARTITIONS_TABLE_CSV"):
|
||||
return
|
||||
|
||||
sizes = {
|
||||
p["subtype"]: _parse_size(p["size"]) for p in _parse_partitions(env)
|
||||
p["subtype"]: _parse_size(p["size"])
|
||||
for p in _parse_partitions(env)
|
||||
if p["type"] in ("0", "app")
|
||||
}
|
||||
|
||||
@@ -177,12 +231,15 @@ def _update_max_upload_size(env):
|
||||
if custom_app_partition_name:
|
||||
selected_partition = partitions.get(custom_app_partition_name, {})
|
||||
if selected_partition:
|
||||
board.update("upload.maximum_size", _parse_size(selected_partition["size"]))
|
||||
board.update(
|
||||
"upload.maximum_size", _parse_size(selected_partition["size"])
|
||||
)
|
||||
return
|
||||
else:
|
||||
print(
|
||||
"Warning! Selected partition `%s` is not available in the partition " \
|
||||
"table! Default partition will be used!" % custom_app_partition_name
|
||||
"Warning! Selected partition `%s` is not available in the "
|
||||
"partition table! Default partition will be used!"
|
||||
% custom_app_partition_name
|
||||
)
|
||||
|
||||
for p in partitions.values():
|
||||
@@ -191,20 +248,23 @@ def _update_max_upload_size(env):
|
||||
break
|
||||
|
||||
|
||||
|
||||
def _to_unix_slashes(path):
|
||||
"""Convert Windows-style backslashes to Unix-style forward slashes."""
|
||||
return path.replace("\\", "/")
|
||||
|
||||
|
||||
#
|
||||
# Filesystem helpers
|
||||
#
|
||||
|
||||
|
||||
def fetch_fs_size(env):
|
||||
"""
|
||||
Extract filesystem size and offset information from partition table.
|
||||
Sets FS_START, FS_SIZE, FS_PAGE, and FS_BLOCK environment variables.
|
||||
"""
|
||||
fs = None
|
||||
for p in _parse_partitions(env):
|
||||
if p["type"] == "data" and p["subtype"] in ("spiffs", "fat", "littlefs"):
|
||||
if p["type"] == "data" and p["subtype"] in (
|
||||
"spiffs",
|
||||
"fat",
|
||||
"littlefs",
|
||||
):
|
||||
fs = p
|
||||
if not fs:
|
||||
sys.stderr.write(
|
||||
@@ -213,6 +273,7 @@ def fetch_fs_size(env):
|
||||
)
|
||||
env.Exit(1)
|
||||
return
|
||||
|
||||
env["FS_START"] = _parse_size(fs["offset"])
|
||||
env["FS_SIZE"] = _parse_size(fs["size"])
|
||||
env["FS_PAGE"] = int("0x100", 16)
|
||||
@@ -226,20 +287,37 @@ def fetch_fs_size(env):
|
||||
|
||||
|
||||
def __fetch_fs_size(target, source, env):
|
||||
"""Wrapper function for fetch_fs_size to be used as SCons emitter."""
|
||||
fetch_fs_size(env)
|
||||
return (target, source)
|
||||
|
||||
|
||||
def check_lib_archive_exists():
|
||||
"""
|
||||
Check if lib_archive is set in platformio.ini configuration.
|
||||
Returns True if found, False otherwise.
|
||||
"""
|
||||
for section in projectconfig.sections():
|
||||
if "lib_archive" in projectconfig.options(section):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# Initialize board configuration and MCU settings
|
||||
board = env.BoardConfig()
|
||||
mcu = board.get("build.mcu", "esp32")
|
||||
toolchain_arch = "xtensa-%s" % mcu
|
||||
filesystem = board.get("build.filesystem", "spiffs")
|
||||
if mcu in ("esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4"):
|
||||
filesystem = board.get("build.filesystem", "littlefs")
|
||||
|
||||
# Set toolchain architecture for RISC-V based ESP32 variants
|
||||
if mcu in ("esp32c2", "esp32c3", "esp32c5", "esp32c6", "esp32h2", "esp32p4"):
|
||||
toolchain_arch = "riscv32-esp"
|
||||
|
||||
# Initialize integration extra data if not present
|
||||
if "INTEGRATION_EXTRA_DATA" not in env:
|
||||
env["INTEGRATION_EXTRA_DATA"] = {}
|
||||
|
||||
# Configure build tools and environment variables
|
||||
env.Replace(
|
||||
__get_board_boot_mode=_get_board_boot_mode,
|
||||
__get_board_f_flash=_get_board_f_flash,
|
||||
@@ -247,7 +325,6 @@ env.Replace(
|
||||
__get_board_f_boot=_get_board_f_boot,
|
||||
__get_board_flash_mode=_get_board_flash_mode,
|
||||
__get_board_memory_type=_get_board_memory_type,
|
||||
|
||||
AR="%s-elf-gcc-ar" % toolchain_arch,
|
||||
AS="%s-elf-as" % toolchain_arch,
|
||||
CC="%s-elf-gcc" % toolchain_arch,
|
||||
@@ -255,7 +332,14 @@ env.Replace(
|
||||
GDB=join(
|
||||
platform.get_package_dir(
|
||||
"tool-riscv32-esp-elf-gdb"
|
||||
if mcu in ("esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4")
|
||||
if mcu in (
|
||||
"esp32c2",
|
||||
"esp32c3",
|
||||
"esp32c5",
|
||||
"esp32c6",
|
||||
"esp32h2",
|
||||
"esp32p4",
|
||||
)
|
||||
else "tool-xtensa-esp-elf-gdb"
|
||||
)
|
||||
or "",
|
||||
@@ -265,20 +349,14 @@ env.Replace(
|
||||
OBJCOPY=join(platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"),
|
||||
RANLIB="%s-elf-gcc-ranlib" % toolchain_arch,
|
||||
SIZETOOL="%s-elf-size" % toolchain_arch,
|
||||
|
||||
ARFLAGS=["rc"],
|
||||
|
||||
SIZEPROGREGEXP=r"^(?:\.iram0\.text|\.iram0\.vectors|\.dram0\.data|\.flash\.text|\.flash\.rodata|)\s+([0-9]+).*",
|
||||
SIZEPROGREGEXP=r"^(?:\.iram0\.text|\.iram0\.vectors|\.dram0\.data|"
|
||||
r"\.flash\.text|\.flash\.rodata|)\s+([0-9]+).*",
|
||||
SIZEDATAREGEXP=r"^(?:\.dram0\.data|\.dram0\.bss|\.noinit)\s+([0-9]+).*",
|
||||
SIZECHECKCMD="$SIZETOOL -A -d $SOURCES",
|
||||
SIZEPRINTCMD="$SIZETOOL -B -d $SOURCES",
|
||||
|
||||
ERASEFLAGS=[
|
||||
"--chip", mcu,
|
||||
"--port", '"$UPLOAD_PORT"'
|
||||
],
|
||||
ERASECMD='"$PYTHONEXE" "$OBJCOPY" $ERASEFLAGS erase_flash',
|
||||
|
||||
ERASEFLAGS=["--chip", mcu, "--port", '"$UPLOAD_PORT"'],
|
||||
ERASECMD='"$PYTHONEXE" "$OBJCOPY" $ERASEFLAGS erase-flash',
|
||||
# mkspiffs package contains two different binaries for IDF and Arduino
|
||||
MKFSTOOL="mk%s" % filesystem
|
||||
+ (
|
||||
@@ -293,46 +371,61 @@ env.Replace(
|
||||
if filesystem == "spiffs"
|
||||
else ""
|
||||
),
|
||||
# Legacy `ESP32_SPIFFS_IMAGE_NAME` is used as the second fallback value for
|
||||
# backward compatibility
|
||||
# Legacy `ESP32_SPIFFS_IMAGE_NAME` is used as the second fallback value
|
||||
# for backward compatibility
|
||||
ESP32_FS_IMAGE_NAME=env.get(
|
||||
"ESP32_FS_IMAGE_NAME", env.get("ESP32_SPIFFS_IMAGE_NAME", filesystem)
|
||||
"ESP32_FS_IMAGE_NAME",
|
||||
env.get("ESP32_SPIFFS_IMAGE_NAME", filesystem),
|
||||
),
|
||||
ESP32_APP_OFFSET=env.get("INTEGRATION_EXTRA_DATA").get(
|
||||
"application_offset"
|
||||
),
|
||||
|
||||
ESP32_APP_OFFSET=env.get("INTEGRATION_EXTRA_DATA").get("application_offset"),
|
||||
ARDUINO_LIB_COMPILE_FLAG="Inactive",
|
||||
|
||||
PROGSUFFIX=".elf"
|
||||
PROGSUFFIX=".elf",
|
||||
)
|
||||
|
||||
# Check if lib_archive is set in platformio.ini and set it to False
|
||||
# if not found. This makes weak defs in framework and libs possible.
|
||||
if not check_lib_archive_exists():
|
||||
env_section = "env:" + env["PIOENV"]
|
||||
projectconfig.set(env_section, "lib_archive", "False")
|
||||
|
||||
# Allow user to override via pre:script
|
||||
if env.get("PROGNAME", "program") == "program":
|
||||
env.Replace(PROGNAME="firmware")
|
||||
|
||||
# Configure build actions and builders
|
||||
env.Append(
|
||||
BUILDERS=dict(
|
||||
ElfToBin=Builder(
|
||||
action=env.VerboseAction(" ".join([
|
||||
'"$PYTHONEXE" "$OBJCOPY"',
|
||||
"--chip", mcu, "elf2image",
|
||||
"--flash_mode", "${__get_board_flash_mode(__env__)}",
|
||||
"--flash_freq", "${__get_board_f_image(__env__)}",
|
||||
"--flash_size", board.get("upload.flash_size", "4MB"),
|
||||
"-o", "$TARGET", "$SOURCES"
|
||||
]), "Building $TARGET"),
|
||||
suffix=".bin"
|
||||
action=env.VerboseAction(
|
||||
" ".join(
|
||||
[
|
||||
'"$PYTHONEXE" "$OBJCOPY"',
|
||||
"--chip",
|
||||
mcu,
|
||||
"elf2image",
|
||||
"--flash-mode",
|
||||
"${__get_board_flash_mode(__env__)}",
|
||||
"--flash-freq",
|
||||
"${__get_board_f_image(__env__)}",
|
||||
"--flash-size",
|
||||
board.get("upload.flash_size", "4MB"),
|
||||
"-o",
|
||||
"$TARGET",
|
||||
"$SOURCES",
|
||||
]
|
||||
),
|
||||
"Building $TARGET",
|
||||
),
|
||||
suffix=".bin",
|
||||
),
|
||||
DataToBin=Builder(
|
||||
action=env.VerboseAction(
|
||||
" ".join(
|
||||
['"$MKFSTOOL"', "-c", "$SOURCES", "-s", "$FS_SIZE"]
|
||||
+ (
|
||||
[
|
||||
"-p",
|
||||
"$FS_PAGE",
|
||||
"-b",
|
||||
"$FS_BLOCK",
|
||||
]
|
||||
["-p", "$FS_PAGE", "-b", "$FS_BLOCK"]
|
||||
if filesystem in ("littlefs", "spiffs")
|
||||
else []
|
||||
)
|
||||
@@ -347,9 +440,76 @@ env.Append(
|
||||
)
|
||||
)
|
||||
|
||||
# Load framework-specific configuration
|
||||
if not env.get("PIOFRAMEWORK"):
|
||||
env.SConscript("frameworks/_bare.py", exports="env")
|
||||
|
||||
def firmware_metrics(target, source, env):
|
||||
"""
|
||||
Custom target to run esp-idf-size with support for command line parameters
|
||||
Usage: pio run -t metrics -- [esp-idf-size arguments]
|
||||
"""
|
||||
if terminal_cp != "utf-8":
|
||||
print("Firmware metrics can not be shown. Set the terminal codepage to \"utf-8\"")
|
||||
return
|
||||
|
||||
map_file = os.path.join(env.subst("$BUILD_DIR"), env.subst("$PROGNAME") + ".map")
|
||||
if not os.path.isfile(map_file):
|
||||
# map file can be in project dir
|
||||
map_file = os.path.join(get_project_dir(), env.subst("$PROGNAME") + ".map")
|
||||
|
||||
if not os.path.isfile(map_file):
|
||||
print(f"Error: Map file not found: {map_file}")
|
||||
print("Make sure the project is built first with 'pio run'")
|
||||
return
|
||||
|
||||
try:
|
||||
import subprocess
|
||||
import sys
|
||||
import shlex
|
||||
|
||||
cmd = [env.subst("$PYTHONEXE"), "-m", "esp_idf_size", "--ng"]
|
||||
|
||||
# Parameters from platformio.ini
|
||||
extra_args = env.GetProjectOption("custom_esp_idf_size_args", "")
|
||||
if extra_args:
|
||||
cmd.extend(shlex.split(extra_args))
|
||||
|
||||
# Command Line Parameter, after --
|
||||
cli_args = []
|
||||
if "--" in sys.argv:
|
||||
dash_index = sys.argv.index("--")
|
||||
if dash_index + 1 < len(sys.argv):
|
||||
cli_args = sys.argv[dash_index + 1:]
|
||||
cmd.extend(cli_args)
|
||||
|
||||
# Add CLI arguments before the map file
|
||||
if cli_args:
|
||||
cmd.extend(cli_args)
|
||||
|
||||
# Map-file as last argument
|
||||
cmd.append(map_file)
|
||||
|
||||
# Debug-Info if wanted
|
||||
if env.GetProjectOption("custom_esp_idf_size_verbose", False):
|
||||
print(f"Running command: {' '.join(cmd)}")
|
||||
|
||||
# Call esp-idf-size
|
||||
result = subprocess.run(cmd, check=False, capture_output=False)
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"Warning: esp-idf-size exited with code {result.returncode}")
|
||||
|
||||
except ImportError:
|
||||
print("Error: esp-idf-size module not found.")
|
||||
print("Install with: pip install esp-idf-size")
|
||||
except FileNotFoundError:
|
||||
print("Error: Python executable not found.")
|
||||
print("Check your Python installation.")
|
||||
except Exception as e:
|
||||
print(f"Error: Failed to run firmware metrics: {e}")
|
||||
print("Make sure esp-idf-size is installed: pip install esp-idf-size")
|
||||
|
||||
#
|
||||
# Target: Build executable and linkable firmware or FS image
|
||||
#
|
||||
@@ -364,6 +524,10 @@ if "nobuild" in COMMAND_LINE_TARGETS:
|
||||
target_firm = join("$BUILD_DIR", "${PROGNAME}.bin")
|
||||
else:
|
||||
target_elf = env.BuildProgram()
|
||||
silent_action = env.Action(firmware_metrics)
|
||||
# Hack to silence scons command output
|
||||
silent_action.strfunction = lambda target, source, env: ""
|
||||
env.AddPostAction(target_elf, silent_action)
|
||||
if set(["buildfs", "uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
|
||||
target_firm = env.DataToBin(
|
||||
join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR"
|
||||
@@ -371,26 +535,27 @@ else:
|
||||
env.NoCache(target_firm)
|
||||
AlwaysBuild(target_firm)
|
||||
else:
|
||||
target_firm = env.ElfToBin(
|
||||
join("$BUILD_DIR", "${PROGNAME}"), target_elf)
|
||||
target_firm = env.ElfToBin(join("$BUILD_DIR", "${PROGNAME}"), target_elf)
|
||||
env.Depends(target_firm, "checkprogsize")
|
||||
|
||||
env.AddPlatformTarget("buildfs", target_firm, target_firm, "Build Filesystem Image")
|
||||
# Configure platform targets
|
||||
env.AddPlatformTarget(
|
||||
"buildfs", target_firm, target_firm, "Build Filesystem Image"
|
||||
)
|
||||
AlwaysBuild(env.Alias("nobuild", target_firm))
|
||||
target_buildprog = env.Alias("buildprog", target_firm, target_firm)
|
||||
|
||||
# update max upload size based on CSV file
|
||||
# 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"))
|
||||
"Retrieving maximum program size $SOURCES",
|
||||
),
|
||||
)
|
||||
|
||||
#
|
||||
# Target: Print binary size
|
||||
#
|
||||
|
||||
target_size = env.AddPlatformTarget(
|
||||
"size",
|
||||
target_elf,
|
||||
@@ -399,25 +564,25 @@ target_size = env.AddPlatformTarget(
|
||||
"Calculate program size",
|
||||
)
|
||||
|
||||
#
|
||||
# Target: Upload firmware or FS image
|
||||
#
|
||||
|
||||
upload_protocol = env.subst("$UPLOAD_PROTOCOL")
|
||||
debug_tools = board.get("debug.tools", {})
|
||||
upload_actions = []
|
||||
|
||||
# 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", ""))):
|
||||
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")
|
||||
"project configuration file.\n"
|
||||
)
|
||||
|
||||
# Configure upload protocol: ESP OTA
|
||||
if upload_protocol == "espota":
|
||||
if not env.subst("$UPLOAD_PORT"):
|
||||
sys.stderr.write(
|
||||
@@ -425,32 +590,45 @@ if upload_protocol == "espota":
|
||||
"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")
|
||||
"espressif32.html#over-the-air-ota-update\n"
|
||||
)
|
||||
env.Replace(
|
||||
UPLOADER=join(FRAMEWORK_DIR,"tools", "espota.py"),
|
||||
UPLOADER=join(FRAMEWORK_DIR, "tools", "espota.py"),
|
||||
UPLOADERFLAGS=["--debug", "--progress", "-i", "$UPLOAD_PORT"],
|
||||
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS -f $SOURCE'
|
||||
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS -f $SOURCE',
|
||||
)
|
||||
if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
|
||||
env.Append(UPLOADERFLAGS=["--spiffs"])
|
||||
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
|
||||
|
||||
# Configure upload protocol: esptool
|
||||
elif upload_protocol == "esptool":
|
||||
env.Replace(
|
||||
UPLOADER=join(
|
||||
platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"),
|
||||
platform.get_package_dir("tool-esptoolpy") or "", "esptool.py"
|
||||
),
|
||||
UPLOADERFLAGS=[
|
||||
"--chip", mcu,
|
||||
"--port", '"$UPLOAD_PORT"',
|
||||
"--baud", "$UPLOAD_SPEED",
|
||||
"--before", board.get("upload.before_reset", "default_reset"),
|
||||
"--after", board.get("upload.after_reset", "hard_reset"),
|
||||
"write_flash", "-z",
|
||||
"--flash_mode", "${__get_board_flash_mode(__env__)}",
|
||||
"--flash_freq", "${__get_board_f_image(__env__)}",
|
||||
"--flash_size", "detect"
|
||||
"--chip",
|
||||
mcu,
|
||||
"--port",
|
||||
'"$UPLOAD_PORT"',
|
||||
"--baud",
|
||||
"$UPLOAD_SPEED",
|
||||
"--before",
|
||||
board.get("upload.before_reset", "default-reset"),
|
||||
"--after",
|
||||
board.get("upload.after_reset", "hard-reset"),
|
||||
"write-flash",
|
||||
"-z",
|
||||
"--flash-mode",
|
||||
"${__get_board_flash_mode(__env__)}",
|
||||
"--flash-freq",
|
||||
"${__get_board_f_image(__env__)}",
|
||||
"--flash-size",
|
||||
"detect",
|
||||
],
|
||||
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS $ESP32_APP_OFFSET $SOURCE'
|
||||
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])])
|
||||
@@ -458,27 +636,36 @@ elif upload_protocol == "esptool":
|
||||
if "uploadfs" in COMMAND_LINE_TARGETS:
|
||||
env.Replace(
|
||||
UPLOADERFLAGS=[
|
||||
"--chip", mcu,
|
||||
"--port", '"$UPLOAD_PORT"',
|
||||
"--baud", "$UPLOAD_SPEED",
|
||||
"--before", board.get("upload.before_reset", "default_reset"),
|
||||
"--after", board.get("upload.after_reset", "hard_reset"),
|
||||
"write_flash", "-z",
|
||||
"--flash_mode", "${__get_board_flash_mode(__env__)}",
|
||||
"--flash_freq", "${__get_board_f_image(__env__)}",
|
||||
"--flash_size", "detect",
|
||||
"$FS_START"
|
||||
"--chip",
|
||||
mcu,
|
||||
"--port",
|
||||
'"$UPLOAD_PORT"',
|
||||
"--baud",
|
||||
"$UPLOAD_SPEED",
|
||||
"--before",
|
||||
board.get("upload.before_reset", "default-reset"),
|
||||
"--after",
|
||||
board.get("upload.after_reset", "hard-reset"),
|
||||
"write-flash",
|
||||
"-z",
|
||||
"--flash-mode",
|
||||
"${__get_board_flash_mode(__env__)}",
|
||||
"--flash-freq",
|
||||
"${__get_board_f_image(__env__)}",
|
||||
"--flash-size",
|
||||
"detect",
|
||||
"$FS_START",
|
||||
],
|
||||
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS $SOURCE',
|
||||
)
|
||||
|
||||
upload_actions = [
|
||||
env.VerboseAction(BeforeUpload, "Looking for upload port..."),
|
||||
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")
|
||||
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE"),
|
||||
]
|
||||
|
||||
# Configure upload protocol: DFU
|
||||
elif upload_protocol == "dfu":
|
||||
|
||||
hwids = board.get("build.hwids", [["0x2341", "0x0070"]])
|
||||
vid = hwids[0][0]
|
||||
pid = hwids[0][1]
|
||||
@@ -493,17 +680,18 @@ elif upload_protocol == "dfu":
|
||||
"-d",
|
||||
",".join(["%s:%s" % (hwid[0], hwid[1]) for hwid in hwids]),
|
||||
"-Q",
|
||||
"-D"
|
||||
"-D",
|
||||
],
|
||||
UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS "$SOURCE"',
|
||||
)
|
||||
|
||||
|
||||
# Configure upload protocol: Debug tools (OpenOCD)
|
||||
elif upload_protocol in debug_tools:
|
||||
_parse_partitions(env)
|
||||
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", []))
|
||||
debug_tools.get(upload_protocol).get("server").get("arguments", [])
|
||||
)
|
||||
openocd_args.extend(
|
||||
[
|
||||
"-c",
|
||||
@@ -531,7 +719,9 @@ elif upload_protocol in debug_tools:
|
||||
f.replace(
|
||||
"$PACKAGE_DIR",
|
||||
_to_unix_slashes(
|
||||
platform.get_package_dir("tool-openocd-esp32") or ""))
|
||||
platform.get_package_dir("tool-openocd-esp32") or ""
|
||||
),
|
||||
)
|
||||
for f in openocd_args
|
||||
]
|
||||
env.Replace(
|
||||
@@ -541,55 +731,71 @@ elif upload_protocol in debug_tools:
|
||||
)
|
||||
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
|
||||
|
||||
# custom upload tool
|
||||
# Configure upload protocol: Custom
|
||||
elif upload_protocol == "custom":
|
||||
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
|
||||
|
||||
else:
|
||||
sys.stderr.write("Warning! Unknown upload protocol %s\n" % upload_protocol)
|
||||
|
||||
# Register upload targets
|
||||
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")
|
||||
"uploadfs", target_firm, upload_actions, "Upload Filesystem Image"
|
||||
)
|
||||
env.AddPlatformTarget(
|
||||
"uploadfsota",
|
||||
target_firm,
|
||||
upload_actions,
|
||||
"Upload Filesystem Image OTA",
|
||||
)
|
||||
|
||||
#
|
||||
# Target: Erase Flash and Upload
|
||||
#
|
||||
|
||||
env.AddPlatformTarget(
|
||||
"erase_upload",
|
||||
target_firm,
|
||||
[
|
||||
env.VerboseAction(BeforeUpload, "Looking for upload port..."),
|
||||
env.VerboseAction("$ERASECMD", "Erasing..."),
|
||||
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")
|
||||
env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE"),
|
||||
],
|
||||
"Erase Flash and Upload",
|
||||
)
|
||||
|
||||
#
|
||||
# Target: Erase Flash
|
||||
#
|
||||
|
||||
env.AddPlatformTarget(
|
||||
"erase",
|
||||
None,
|
||||
[
|
||||
env.VerboseAction(BeforeUpload, "Looking for upload port..."),
|
||||
env.VerboseAction("$ERASECMD", "Erasing...")
|
||||
env.VerboseAction("$ERASECMD", "Erasing..."),
|
||||
],
|
||||
"Erase Flash",
|
||||
)
|
||||
|
||||
#
|
||||
# Override memory inspection behavior
|
||||
#
|
||||
# Register Custom Target for firmware metrics
|
||||
env.AddCustomTarget(
|
||||
name="metrics",
|
||||
dependencies="$BUILD_DIR/${PROGNAME}.elf",
|
||||
actions=firmware_metrics,
|
||||
title="Firmware Size Metrics",
|
||||
description="Analyze firmware size using esp-idf-size "
|
||||
"(supports CLI args after --)",
|
||||
always_build=True,
|
||||
)
|
||||
|
||||
# Additional Target without Build-Dependency when already compiled
|
||||
env.AddCustomTarget(
|
||||
name="metrics-only",
|
||||
dependencies=None,
|
||||
actions=firmware_metrics,
|
||||
title="Firmware Size Metrics (No Build)",
|
||||
description="Analyze firmware size without building first",
|
||||
always_build=True,
|
||||
)
|
||||
|
||||
# Override memory inspection behavior
|
||||
env.SConscript("sizedata.py", exports="env")
|
||||
|
||||
#
|
||||
# Default targets
|
||||
#
|
||||
|
||||
# Set default targets
|
||||
Default([target_buildprog, target_size])
|
||||
|
||||
Reference in New Issue
Block a user