tan-cli 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tan/__init__.py +0 -0
- tan/__main__.py +120 -0
- tan/cli.py +939 -0
- tan/command_table.py +265 -0
- tan/commands/__init__.py +8 -0
- tan/commands/bootstrap_cmd.py +4856 -0
- tan/commands/bootstrap_patches.py +164 -0
- tan/commands/bootstrap_toolchain_fetch.py +155 -0
- tan/commands/bootstrap_toolchain_pin.py +36 -0
- tan/commands/build/__init__.py +1 -0
- tan/commands/build/configure_inputs.py +277 -0
- tan/commands/build/execute.py +1852 -0
- tan/commands/build/host_python.py +59 -0
- tan/commands/build/link_stale.py +78 -0
- tan/commands/build/manifest.py +428 -0
- tan/commands/build/materialise.py +81 -0
- tan/commands/build/token_substitution.py +381 -0
- tan/commands/build/toolchain.py +482 -0
- tan/commands/build/user_defines_wipe.py +115 -0
- tan/commands/build/workspace_patches.py +65 -0
- tan/commands/build_cmd.py +2236 -0
- tan/commands/build_output.py +331 -0
- tan/commands/clean_cmd.py +1183 -0
- tan/commands/completion_cmd.py +786 -0
- tan/commands/debug_config_cmd.py +2425 -0
- tan/commands/diff_cmd.py +940 -0
- tan/commands/doctor_cmd.py +4767 -0
- tan/commands/examples_cmd.py +644 -0
- tan/commands/explain_cmd.py +1319 -0
- tan/commands/faultdecode_cmd.py +931 -0
- tan/commands/flash_atoc_guard.py +240 -0
- tan/commands/flash_cmd.py +5731 -0
- tan/commands/flash_mram_guard.py +150 -0
- tan/commands/flash_ram.py +578 -0
- tan/commands/flash_raw.py +583 -0
- tan/commands/generate_cmd.py +1456 -0
- tan/commands/image_cmd.py +753 -0
- tan/commands/init_cmd.py +1740 -0
- tan/commands/inspect_cmd.py +377 -0
- tan/commands/kconfig_cmd.py +734 -0
- tan/commands/model_cmd.py +1514 -0
- tan/commands/model_device_cmd.py +351 -0
- tan/commands/model_device_live.py +234 -0
- tan/commands/model_host_cmd.py +430 -0
- tan/commands/model_zoo_cmd.py +363 -0
- tan/commands/monitor_actions.py +125 -0
- tan/commands/monitor_cmd.py +626 -0
- tan/commands/monitor_session.py +505 -0
- tan/commands/new_som_cmd.py +1522 -0
- tan/commands/pinmux_cmd.py +568 -0
- tan/commands/presets_cmd.py +1123 -0
- tan/commands/probe_cmd.py +421 -0
- tan/commands/reset_cmd.py +354 -0
- tan/commands/reset_confirm.py +168 -0
- tan/commands/run_cmd.py +637 -0
- tan/commands/scaffold_cmd.py +490 -0
- tan/commands/sdk_cmd.py +1723 -0
- tan/commands/size_cmd.py +1020 -0
- tan/commands/support_bundle_cmd.py +1073 -0
- tan/commands/trace_cmd.py +341 -0
- tan/commands/validate_cmd.py +2009 -0
- tan/commands/west_forward_cmd.py +736 -0
- tan/commands/workspace_patch_check.py +296 -0
- tan/core/__init__.py +1 -0
- tan/core/alp_conf_pregen.py +100 -0
- tan/core/artifact_provenance.py +240 -0
- tan/core/atoc_guard.py +276 -0
- tan/core/atoc_guard_messages.py +232 -0
- tan/core/atoc_replacement.py +118 -0
- tan/core/atomic_write.py +178 -0
- tan/core/board_context.py +351 -0
- tan/core/board_diagnostic.py +111 -0
- tan/core/board_files.py +221 -0
- tan/core/board_validator.py +542 -0
- tan/core/board_validator_compat.py +196 -0
- tan/core/board_validator_run.py +129 -0
- tan/core/board_validator_schema.py +186 -0
- tan/core/board_validator_skew.py +46 -0
- tan/core/board_yaml_edit.py +295 -0
- tan/core/board_yaml_pos.py +118 -0
- tan/core/bootstrap.py +2572 -0
- tan/core/build_plan.py +625 -0
- tan/core/consent.py +104 -0
- tan/core/console_filter.py +245 -0
- tan/core/debug_launch.py +1803 -0
- tan/core/devicetree_lint.py +168 -0
- tan/core/dir_removal.py +229 -0
- tan/core/doctor_git.py +172 -0
- tan/core/doctor_libraries.py +253 -0
- tan/core/doctor_render.py +185 -0
- tan/core/doctor_scope.py +66 -0
- tan/core/doctor_setools.py +237 -0
- tan/core/doctor_stale.py +180 -0
- tan/core/document_guards.py +723 -0
- tan/core/dp_id.py +97 -0
- tan/core/elf_load.py +63 -0
- tan/core/error_catalog.py +171 -0
- tan/core/example_catalog.py +499 -0
- tan/core/example_facets.py +151 -0
- tan/core/faultdecode.py +521 -0
- tan/core/flash_plan.py +2501 -0
- tan/core/flow_d_report.py +381 -0
- tan/core/flow_d_uptime.py +164 -0
- tan/core/fs_confine.py +130 -0
- tan/core/global_flags.py +230 -0
- tan/core/host_python.py +210 -0
- tan/core/image_bundle.py +247 -0
- tan/core/inert.py +147 -0
- tan/core/jlink_binary.py +128 -0
- tan/core/jlink_probe.py +481 -0
- tan/core/jsonc_splice.py +404 -0
- tan/core/launch_provenance.py +257 -0
- tan/core/link_refusal.py +76 -0
- tan/core/metadata_schema.py +376 -0
- tan/core/model_check.py +227 -0
- tan/core/model_device.py +449 -0
- tan/core/model_doctor.py +198 -0
- tan/core/model_host.py +48 -0
- tan/core/model_list.py +112 -0
- tan/core/model_zoo.py +353 -0
- tan/core/module_template.py +340 -0
- tan/core/mram_link.py +87 -0
- tan/core/new_som_ospi.py +94 -0
- tan/core/os_class.py +159 -0
- tan/core/patch_paths.py +87 -0
- tan/core/pending.py +40 -0
- tan/core/plain_zephyr_plan.py +138 -0
- tan/core/plan_exec.py +373 -0
- tan/core/plan_tokens.py +600 -0
- tan/core/probe.py +155 -0
- tan/core/probe_plan.py +237 -0
- tan/core/proxy.py +168 -0
- tan/core/publish.py +31 -0
- tan/core/python_floor.py +178 -0
- tan/core/ram_run.py +694 -0
- tan/core/ram_watch.py +231 -0
- tan/core/raw_write.py +160 -0
- tan/core/reset_plan.py +56 -0
- tan/core/run.py +161 -0
- tan/core/scaffold.py +2203 -0
- tan/core/scaffold_selftest_identity.py +225 -0
- tan/core/sdk_default_registry.py +565 -0
- tan/core/sdk_discovery.py +996 -0
- tan/core/sdk_removal.py +465 -0
- tan/core/serial_actions.py +175 -0
- tan/core/serial_capture.py +185 -0
- tan/core/serial_url.py +45 -0
- tan/core/setools.py +608 -0
- tan/core/setools_scratch.py +243 -0
- tan/core/shapes.py +194 -0
- tan/core/size.py +610 -0
- tan/core/som_buildability.py +204 -0
- tan/core/som_schema_version.py +62 -0
- tan/core/subprocess_env.py +201 -0
- tan/core/sysbuild_image.py +94 -0
- tan/core/system_manifest.py +827 -0
- tan/core/text_layout.py +73 -0
- tan/core/timestamp.py +182 -0
- tan/core/tool_lookup.py +383 -0
- tan/core/toolchain_pin.py +117 -0
- tan/core/toolchain_provision.py +1224 -0
- tan/core/trusted_path.py +134 -0
- tan/core/uboot_breakin.py +154 -0
- tan/core/uri_reference.py +415 -0
- tan/core/user_defines.py +152 -0
- tan/core/venv.py +332 -0
- tan/core/west_patches.py +143 -0
- tan/core/west_workspace_refusal.py +159 -0
- tan/core/zephyr_env.py +124 -0
- tan/env.py +185 -0
- tan/envelope.py +647 -0
- tan/exit_codes.py +12 -0
- tan/lazy_typer.py +185 -0
- tan/model/__init__.py +2 -0
- tan/model/_gen_fixture.py +132 -0
- tan/model/adapters/__init__.py +116 -0
- tan/model/adapters/cpu.py +26 -0
- tan/model/adapters/deepx.py +94 -0
- tan/model/adapters/drpai.py +242 -0
- tan/model/adapters/ethos_u.py +951 -0
- tan/model/adapters/executorch.py +55 -0
- tan/model/analyze.py +694 -0
- tan/model/build.py +304 -0
- tan/model/check.py +682 -0
- tan/model/manifest.py +625 -0
- tan/model/measure.py +216 -0
- tan/model/npu_ops_validate.py +130 -0
- tan/model/package.py +125 -0
- tan/model/perf.py +635 -0
- tan/model/perf_apply.py +721 -0
- tan/model/prep.py +193 -0
- tan/model/sram_fit.py +502 -0
- tan/model/targets.py +374 -0
- tan/model/tensorio.py +287 -0
- tan/net.py +73 -0
- tan/output_format.py +213 -0
- tan/planner/__init__.py +219 -0
- tan/planner/aperture.py +202 -0
- tan/planner/buildplan.py +1092 -0
- tan/planner/camera_owner.py +192 -0
- tan/planner/cameras.py +132 -0
- tan/planner/carveout.py +755 -0
- tan/planner/cli.py +274 -0
- tan/planner/headers.py +315 -0
- tan/planner/kconfig.py +2435 -0
- tan/planner/kconfig_symbols.py +473 -0
- tan/planner/libraries.py +677 -0
- tan/planner/link_target.py +237 -0
- tan/planner/linux_ownership.py +216 -0
- tan/planner/loader.py +1525 -0
- tan/planner/manifest.py +116 -0
- tan/planner/memory.py +161 -0
- tan/planner/memregion.py +56 -0
- tan/planner/models.py +533 -0
- tan/planner/orchestrator.py +874 -0
- tan/planner/ownership.py +203 -0
- tan/planner/partition.py +1160 -0
- tan/planner/paths.py +32 -0
- tan/planner/plain_slice.py +139 -0
- tan/planner/project_emit/__init__.py +60 -0
- tan/planner/project_emit/bom_netlist.py +375 -0
- tan/planner/project_emit/dts.py +580 -0
- tan/planner/project_emit/hw_info.py +221 -0
- tan/planner/project_emit/native_sim.py +136 -0
- tan/planner/project_emit/west_libs.py +213 -0
- tan/planner/project_loader.py +264 -0
- tan/planner/sdk_capability.py +203 -0
- tan/planner/sdk_compat.py +395 -0
- tan/planner/secure.py +350 -0
- tan/planner/slugs.py +394 -0
- tan/planner/som_metadata.py +325 -0
- tan/planner/strict_loaders.py +131 -0
- tan/planner/template.py +1037 -0
- tan/planner/template_pins.py +535 -0
- tan/planner/template_rewrite.py +714 -0
- tan/planner/topology.py +208 -0
- tan/planner/validate.py +365 -0
- tan/planner/whole_device_alias.py +67 -0
- tan/planner/zephyr_board.py +3510 -0
- tan/planner_cli.py +97 -0
- tan/planner_emit.py +617 -0
- tan/planner_root.py +119 -0
- tan/soc_ref.py +58 -0
- tan/templates/__init__.py +34 -0
- tan/templates/vendored/MANIFEST.md +1862 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/README.md +112 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/board.yaml +38 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.conf +11 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.overlay +29 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/prj.conf +5 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/src/main.c +266 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/testcase.yaml +53 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/README.md +112 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/board.yaml +38 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.conf +11 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.overlay +29 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/prj.conf +5 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/src/main.c +266 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/testcase.yaml +53 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/CMakeLists.txt +10 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/README.md +75 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/board.yaml +38 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/prj.conf +8 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.c +371 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.h +178 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/main.c +373 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/testcase.yaml +62 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/CMakeLists.txt +10 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/README.md +75 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/board.yaml +37 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/prj.conf +8 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.c +371 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.h +178 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/main.c +373 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/testcase.yaml +62 -0
- tan/templates/vendored/iot/E1M-AEN801/CMakeLists.txt +14 -0
- tan/templates/vendored/iot/E1M-AEN801/README.md +103 -0
- tan/templates/vendored/iot/E1M-AEN801/board.yaml +69 -0
- tan/templates/vendored/iot/E1M-AEN801/prj.conf +15 -0
- tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.c +196 -0
- tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.h +173 -0
- tan/templates/vendored/iot/E1M-AEN801/src/main.c +262 -0
- tan/templates/vendored/iot/E1M-AEN801/testcase.yaml +68 -0
- tan/templates/vendored/minimal/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/minimal/E1M-AEN801/README.md +108 -0
- tan/templates/vendored/minimal/E1M-AEN801/board.yaml +32 -0
- tan/templates/vendored/minimal/E1M-AEN801/prj.conf +8 -0
- tan/templates/vendored/minimal/E1M-AEN801/src/main.c +111 -0
- tan/templates/vendored/minimal/E1M-AEN801/testcase.yaml +49 -0
- tan/templates/vendored/minimal/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/minimal/E1M-V2N101/README.md +108 -0
- tan/templates/vendored/minimal/E1M-V2N101/board.yaml +32 -0
- tan/templates/vendored/minimal/E1M-V2N101/prj.conf +8 -0
- tan/templates/vendored/minimal/E1M-V2N101/src/main.c +111 -0
- tan/templates/vendored/minimal/E1M-V2N101/testcase.yaml +49 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/README.md +120 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/board.yaml +57 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/boards/native_sim_native_64.overlay +40 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/CMakeLists.txt +13 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/main.c +171 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/prj.conf +17 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/testcase.yaml +23 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/prj.conf +22 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/src/main.c +185 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/testcase.yaml +26 -0
- tan/templates/vendored/sensor/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/sensor/E1M-AEN801/README.md +112 -0
- tan/templates/vendored/sensor/E1M-AEN801/board.yaml +57 -0
- tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.conf +10 -0
- tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.overlay +28 -0
- tan/templates/vendored/sensor/E1M-AEN801/prj.conf +5 -0
- tan/templates/vendored/sensor/E1M-AEN801/src/main.c +186 -0
- tan/templates/vendored/sensor/E1M-AEN801/testcase.yaml +52 -0
- tan/templates/vendored/sensor/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/sensor/E1M-V2N101/README.md +112 -0
- tan/templates/vendored/sensor/E1M-V2N101/board.yaml +57 -0
- tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.conf +10 -0
- tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.overlay +28 -0
- tan/templates/vendored/sensor/E1M-V2N101/prj.conf +5 -0
- tan/templates/vendored/sensor/E1M-V2N101/src/main.c +186 -0
- tan/templates/vendored/sensor/E1M-V2N101/testcase.yaml +52 -0
- tan/version.py +102 -0
- tan_cli-0.7.0.dist-info/METADATA +125 -0
- tan_cli-0.7.0.dist-info/RECORD +330 -0
- tan_cli-0.7.0.dist-info/WHEEL +5 -0
- tan_cli-0.7.0.dist-info/entry_points.txt +2 -0
- tan_cli-0.7.0.dist-info/top_level.txt +1 -0
tan/planner/cli.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""The planner CLI: argparse + main(), over one mode->text dispatch.
|
|
3
|
+
|
|
4
|
+
Kept in-package (imported by __init__ for the public `main` re-export, and by
|
|
5
|
+
__main__ as the `python -m tan.planner` entry) so nothing has to import
|
|
6
|
+
__main__ -- importing __main__ re-enters the package under runpy and warns.
|
|
7
|
+
|
|
8
|
+
RELOCATED (was alp-sdk `scripts/alp_orchestrate/cli.py`). The mode dispatch was
|
|
9
|
+
lifted out of `main()` into `emit_artefact()` so the in-process caller
|
|
10
|
+
(`tan.planner_root.emit`, which is how `tan build` gets its plan) and this argv
|
|
11
|
+
path render through the SAME branch table. Two copies of an eight-way `--emit`
|
|
12
|
+
switch is how one surface silently starts emitting differently from the other.
|
|
13
|
+
|
|
14
|
+
`--emit` also accepts `alp_project.py`'s OWN modes (`zephyr-conf`,
|
|
15
|
+
`carrier-netlist`, ...), rendered through `tan.planner_emit` -- the same
|
|
16
|
+
in-process engine `tan generate` uses, so a mode still has exactly one renderer
|
|
17
|
+
whichever front door reached it. They print RAW ARTEFACT BYTES, undecorated,
|
|
18
|
+
because alp-sdk's `scripts/check_emit_snapshots.py` diffs this stdout against a
|
|
19
|
+
committed golden; a trailing newline of our own would fail it.
|
|
20
|
+
|
|
21
|
+
`--emit scaffold` is the third family, and the one mode that takes NO board.yaml
|
|
22
|
+
-- it materialises a NEW project, so it is dispatched before `--input` is read,
|
|
23
|
+
the same order `alp_project.main()` dispatches it in. It renders through
|
|
24
|
+
`tan.planner.template` (relocated from `scripts/alp_template.py`) against the
|
|
25
|
+
LIVE catalog of the bound SDK checkout. `tan init` does NOT come this way and
|
|
26
|
+
must not: it serves a customer with no SDK at all, from tan's own vendored
|
|
27
|
+
capture (`tan.core.scaffold`, invariant I-32).
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import sys
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from typing import Iterable, Optional
|
|
35
|
+
|
|
36
|
+
from tan import planner_emit
|
|
37
|
+
|
|
38
|
+
from . import (
|
|
39
|
+
OrchestratorError,
|
|
40
|
+
emit_build_plan,
|
|
41
|
+
emit_kconfig,
|
|
42
|
+
emit_storage_mounts_c,
|
|
43
|
+
emit_system_manifest,
|
|
44
|
+
load_board_yaml,
|
|
45
|
+
)
|
|
46
|
+
from .buildplan import _shared_artefact, _shared_tfm_conf
|
|
47
|
+
from .paths import REPO
|
|
48
|
+
from .template import (
|
|
49
|
+
TemplateError,
|
|
50
|
+
emit_scaffold,
|
|
51
|
+
find_template_by_cores,
|
|
52
|
+
load_catalog,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
if False: # typing-only; keeps the runtime import graph unchanged
|
|
56
|
+
from .models import BoardProject
|
|
57
|
+
|
|
58
|
+
#: The eight modes alp-sdk's `alp_orchestrate` CLI exposed, every one of them
|
|
59
|
+
#: served by `emit_artefact`.
|
|
60
|
+
ORCHESTRATOR_MODES = (
|
|
61
|
+
"system-manifest", "ipc-contract-h", "dts-reservations", "dts-partitions",
|
|
62
|
+
"storage-mounts-c", "tfm-sysbuild-conf", "build-plan", "kconfig",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
#: The rest of `--emit`: `alp_project.py`'s modes, served by `tan.planner_emit`.
|
|
66
|
+
#: DERIVED from `IN_PROCESS_MODES` rather than listed again -- a second list is
|
|
67
|
+
#: how `tan generate` and this entry would drift apart on which modes exist.
|
|
68
|
+
#: `ipc-contract-h` is in both sets and stays with `emit_artefact`; sorted, so
|
|
69
|
+
#: `--help` does not reorder itself between interpreters.
|
|
70
|
+
PROJECT_MODES = tuple(
|
|
71
|
+
sorted(planner_emit.IN_PROCESS_MODES.difference(ORCHESTRATOR_MODES)))
|
|
72
|
+
|
|
73
|
+
#: The modes served by `tan.planner.template`, which take `--template`/`--sku`
|
|
74
|
+
#: instead of a board.yaml. Deliberately NOT folded into `IN_PROCESS_MODES`:
|
|
75
|
+
#: that set is `tan generate`'s target list, and `tan generate --output` writes
|
|
76
|
+
#: ONE artefact, where a scaffold is a whole project's worth of files. The
|
|
77
|
+
#: customer surface is frozen (`tan init` scaffolds); this entry is the gate's.
|
|
78
|
+
TEMPLATE_MODES = ("scaffold",)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def emit_artefact(project: "BoardProject", mode: str, *, board_yaml: Path,
|
|
82
|
+
build_root: Path = Path("build"),
|
|
83
|
+
core: Optional[str] = None) -> str:
|
|
84
|
+
"""Render one `--emit` mode for an already-loaded project.
|
|
85
|
+
|
|
86
|
+
`core` is honoured by `kconfig` alone; every other mode ignores it -- the
|
|
87
|
+
same asymmetry the flag's own help text records.
|
|
88
|
+
"""
|
|
89
|
+
if mode == "system-manifest":
|
|
90
|
+
return emit_system_manifest(project)
|
|
91
|
+
if mode == "ipc-contract-h":
|
|
92
|
+
return _shared_artefact(project, "generated/alp/system_ipc.h")
|
|
93
|
+
if mode == "dts-reservations":
|
|
94
|
+
return _shared_artefact(project, "generated/dts-reservations.dtsi")
|
|
95
|
+
if mode == "dts-partitions":
|
|
96
|
+
return _shared_artefact(project, "generated/dts-partitions.dtsi")
|
|
97
|
+
if mode == "storage-mounts-c":
|
|
98
|
+
# The plan carries the table only when a partition is mountable
|
|
99
|
+
# (alp-sdk#2820); "" here means "none", and the standalone emit has
|
|
100
|
+
# always printed the empty table in that case, so keep it byte-identical.
|
|
101
|
+
return (_shared_artefact(project, "generated/storage_mount_table.c")
|
|
102
|
+
or emit_storage_mounts_c(project))
|
|
103
|
+
if mode == "tfm-sysbuild-conf":
|
|
104
|
+
return _shared_tfm_conf(project)
|
|
105
|
+
if mode == "build-plan":
|
|
106
|
+
return emit_build_plan(project, board_yaml=board_yaml,
|
|
107
|
+
build_root=build_root)
|
|
108
|
+
if mode == "kconfig":
|
|
109
|
+
return emit_kconfig(project, core)
|
|
110
|
+
raise OrchestratorError(f"unknown emit mode '{mode}'")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _parse_cores_arg(raw: str) -> dict[str, str]:
|
|
114
|
+
"""`--cores` (alp-sdk#1652): `core_id:os[,core_id:os...]` -- the
|
|
115
|
+
topology an IDE wizard already knows (which cores it's targeting and
|
|
116
|
+
which OS each runs), NOT a directory. RELOCATED verbatim from
|
|
117
|
+
`alp_project._parse_cores_arg`. `--cores` is a SELECTOR over the
|
|
118
|
+
catalog's existing templates (see `find_template_by_cores`'s
|
|
119
|
+
docstring for why this stops short of an arbitrary core -> app-dir
|
|
120
|
+
renderer): the directory each core lands in is whatever the matched
|
|
121
|
+
template already uses, same as picking that template by `--template`
|
|
122
|
+
would give.
|
|
123
|
+
"""
|
|
124
|
+
cores: dict[str, str] = {}
|
|
125
|
+
for entry in raw.split(","):
|
|
126
|
+
entry = entry.strip()
|
|
127
|
+
if not entry:
|
|
128
|
+
continue
|
|
129
|
+
if ":" not in entry:
|
|
130
|
+
raise ValueError(
|
|
131
|
+
f"--cores entry {entry!r} must be core_id:os (e.g. "
|
|
132
|
+
f"m55_hp:zephyr)")
|
|
133
|
+
core_id, _, os_name = entry.partition(":")
|
|
134
|
+
core_id, os_name = core_id.strip(), os_name.strip()
|
|
135
|
+
if not core_id or not os_name:
|
|
136
|
+
raise ValueError(
|
|
137
|
+
f"--cores entry {entry!r} must be core_id:os (e.g. "
|
|
138
|
+
f"m55_hp:zephyr)")
|
|
139
|
+
if core_id in cores:
|
|
140
|
+
raise ValueError(f"--cores names {core_id!r} more than once")
|
|
141
|
+
cores[core_id] = os_name
|
|
142
|
+
if not cores:
|
|
143
|
+
raise ValueError("--cores must name at least one core_id:os pair")
|
|
144
|
+
return cores
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _emit_scaffold(
|
|
148
|
+
template: Optional[str], sku: Optional[str], cores: Optional[str] = None,
|
|
149
|
+
) -> int:
|
|
150
|
+
"""`--emit scaffold --template <id> --sku <SKU>`, or `--emit scaffold
|
|
151
|
+
--cores <core_id:os,...> --sku <SKU>` (alp-sdk#1652), straight to
|
|
152
|
+
stdout.
|
|
153
|
+
|
|
154
|
+
`--template`/`--cores` are mutually exclusive alternative ways to pick
|
|
155
|
+
the template -- `--cores` resolves to a `template_id` via
|
|
156
|
+
`find_template_by_cores`, then falls into the exact same
|
|
157
|
+
`emit_scaffold()` call `--template` would reach, exactly as
|
|
158
|
+
`alp_project._run_scaffold_emit` refuses/resolves them. `--sku` is
|
|
159
|
+
still required either way and refused ONE AT A TIME, in that order,
|
|
160
|
+
so a caller that omitted both still learns about `--template`/
|
|
161
|
+
`--cores` first. `argparse` cannot express "required only for this
|
|
162
|
+
`--emit`", which is why this is a hand-check.
|
|
163
|
+
"""
|
|
164
|
+
if template and cores:
|
|
165
|
+
print("alp-orchestrate: --emit scaffold takes --template OR "
|
|
166
|
+
"--cores, not both", file=sys.stderr)
|
|
167
|
+
return 1
|
|
168
|
+
if not template and not cores:
|
|
169
|
+
print("alp-orchestrate: --emit scaffold requires --template <id> "
|
|
170
|
+
"or --cores <core_id:os,...>", file=sys.stderr)
|
|
171
|
+
return 1
|
|
172
|
+
if not sku:
|
|
173
|
+
print("alp-orchestrate: --emit scaffold requires --sku <SKU>",
|
|
174
|
+
file=sys.stderr)
|
|
175
|
+
return 1
|
|
176
|
+
if cores:
|
|
177
|
+
try:
|
|
178
|
+
cores_topology = _parse_cores_arg(cores)
|
|
179
|
+
except ValueError as e:
|
|
180
|
+
print(f"alp-orchestrate: {e}", file=sys.stderr)
|
|
181
|
+
return 1
|
|
182
|
+
try:
|
|
183
|
+
record = find_template_by_cores(load_catalog(), cores_topology)
|
|
184
|
+
except TemplateError as e:
|
|
185
|
+
print(f"alp-orchestrate: {e}", file=sys.stderr)
|
|
186
|
+
return 1
|
|
187
|
+
template = record["id"]
|
|
188
|
+
try:
|
|
189
|
+
sys.stdout.write(emit_scaffold(template, sku))
|
|
190
|
+
except TemplateError as e:
|
|
191
|
+
print(f"alp-orchestrate: {e}", file=sys.stderr)
|
|
192
|
+
return 1
|
|
193
|
+
return 0
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def main(argv: Optional[Iterable[str]] = None) -> int:
|
|
197
|
+
import argparse
|
|
198
|
+
parser = argparse.ArgumentParser(
|
|
199
|
+
description="Planner/emit CLI for board.yaml (the executor was "
|
|
200
|
+
"retired -- ADR-0020 Phase 4).")
|
|
201
|
+
parser.add_argument("--input", type=Path, default=Path("board.yaml"),
|
|
202
|
+
help="Path to the project's board.yaml.")
|
|
203
|
+
parser.add_argument("--build-root", type=Path,
|
|
204
|
+
default=Path("build"),
|
|
205
|
+
help="Build root directory (used by --emit build-plan).")
|
|
206
|
+
parser.add_argument("--core", default=None,
|
|
207
|
+
help="Core id to scope a per-core emit mode to "
|
|
208
|
+
"(required by --emit kconfig; every other "
|
|
209
|
+
"mode ignores it).")
|
|
210
|
+
parser.add_argument("--template", default=None,
|
|
211
|
+
help="metadata/templates/catalog-v1.json template id; "
|
|
212
|
+
"required for --emit scaffold (unless --cores is "
|
|
213
|
+
"given instead).")
|
|
214
|
+
parser.add_argument("--cores", default=None,
|
|
215
|
+
help="core_id:os[,core_id:os...] topology (e.g. "
|
|
216
|
+
"'m55_hp:zephyr,m55_he:zephyr'); an alternative "
|
|
217
|
+
"to --template for --emit scaffold -- selects "
|
|
218
|
+
"whichever catalog template's own cores: "
|
|
219
|
+
"topology matches exactly (alp-sdk#1652). "
|
|
220
|
+
"Mutually exclusive with --template.")
|
|
221
|
+
parser.add_argument("--sku", default=None,
|
|
222
|
+
help="Target SoM SKU (e.g. the one a scaffold is "
|
|
223
|
+
"retargeted onto); required for --emit scaffold, "
|
|
224
|
+
"and must be one of the template's declared "
|
|
225
|
+
"supported.som_skus.")
|
|
226
|
+
parser.add_argument("--emit", default=None,
|
|
227
|
+
choices=[*ORCHESTRATOR_MODES, *PROJECT_MODES,
|
|
228
|
+
*TEMPLATE_MODES],
|
|
229
|
+
help="Skip the build; just emit one of the "
|
|
230
|
+
"generated artefacts to stdout.")
|
|
231
|
+
args = parser.parse_args(list(argv) if argv is not None else None)
|
|
232
|
+
|
|
233
|
+
if args.emit in TEMPLATE_MODES:
|
|
234
|
+
# Before `--input` is touched: a scaffold IS the new project, so there
|
|
235
|
+
# is no board.yaml to load yet.
|
|
236
|
+
return _emit_scaffold(args.template, args.sku, args.cores)
|
|
237
|
+
|
|
238
|
+
if args.emit in PROJECT_MODES:
|
|
239
|
+
# Straight to the relocated renderers, deliberately WITHOUT the
|
|
240
|
+
# `load_board_yaml` below: `carrier-netlist` / `composed-route-table`
|
|
241
|
+
# read the raw board.yaml dict (mirroring `alp_project.main()`, which
|
|
242
|
+
# dispatches them before its per-core machinery), so loading here would
|
|
243
|
+
# refuse a board the SDK's own front door serves.
|
|
244
|
+
try:
|
|
245
|
+
sys.stdout.write(planner_emit.render(
|
|
246
|
+
args.emit, sdk_root=REPO, board_yaml=args.input,
|
|
247
|
+
core=args.core))
|
|
248
|
+
except (OrchestratorError, planner_emit.PlannerEmitError) as e:
|
|
249
|
+
print(f"alp-orchestrate: {e}", file=sys.stderr)
|
|
250
|
+
return 1
|
|
251
|
+
return 0
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
project = load_board_yaml(args.input)
|
|
255
|
+
except OrchestratorError as e:
|
|
256
|
+
print(f"alp-orchestrate: {e}", file=sys.stderr)
|
|
257
|
+
return 1
|
|
258
|
+
|
|
259
|
+
if args.emit:
|
|
260
|
+
try:
|
|
261
|
+
sys.stdout.write(emit_artefact(
|
|
262
|
+
project, args.emit, board_yaml=args.input,
|
|
263
|
+
build_root=args.build_root, core=args.core))
|
|
264
|
+
except OrchestratorError as e:
|
|
265
|
+
print(f"alp-orchestrate: {e}", file=sys.stderr)
|
|
266
|
+
return 1
|
|
267
|
+
return 0
|
|
268
|
+
|
|
269
|
+
# ADR-0020 Phase 4 (preview): the SDK-side executor was retired --
|
|
270
|
+
# this module only plans/emits now. Building is an external
|
|
271
|
+
# consumer's job (against `--emit build-plan`'s JSON contract).
|
|
272
|
+
print("alp-orchestrate: no executor -- pass --emit to print a "
|
|
273
|
+
"generated artefact (e.g. --emit build-plan)", file=sys.stderr)
|
|
274
|
+
return 2
|
tan/planner/headers.py
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Header / DTS / mount-table emitters from the resolved model.
|
|
4
|
+
|
|
5
|
+
Pure renderers off the parsed BoardProject + the resolved carve-outs / storage
|
|
6
|
+
partitions: the IPC contract header (ipc-contract-h), the DTS reserved-memory
|
|
7
|
+
overlay (dts-reservations), the DTS fixed-partitions overlay (dts-partitions),
|
|
8
|
+
and the static C mount table (storage-mounts-c). Each is a leaf emit -- it calls
|
|
9
|
+
only the carve-out / partition resolvers, never the loader/validator. Extracted
|
|
10
|
+
as the #285 headers emit seam.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from .carveout import resolve_carve_outs
|
|
16
|
+
from .models import BoardProject, ResolvedPartition
|
|
17
|
+
from .partition import resolve_storage_partitions
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def emit_ipc_contract_h(project: BoardProject) -> str:
|
|
21
|
+
"""Generate alp_system_ipc.h per spec §6.3."""
|
|
22
|
+
carve_outs = resolve_carve_outs(project)
|
|
23
|
+
|
|
24
|
+
lines: list[str] = [
|
|
25
|
+
"/*",
|
|
26
|
+
" * Auto-generated by scripts/alp_orchestrate.py -- do not edit.",
|
|
27
|
+
" * Regenerate after changes to board.yaml `ipc:` or the SoM's",
|
|
28
|
+
" * memory_map / mailbox blocks.",
|
|
29
|
+
" */",
|
|
30
|
+
"",
|
|
31
|
+
"#ifndef ALP_SYSTEM_IPC_H",
|
|
32
|
+
"#define ALP_SYSTEM_IPC_H",
|
|
33
|
+
"",
|
|
34
|
+
f'#define ALP_IPC_SKU "{project.sku}"',
|
|
35
|
+
"",
|
|
36
|
+
]
|
|
37
|
+
if not carve_outs:
|
|
38
|
+
lines += [
|
|
39
|
+
"/* No ipc[] entries declared in board.yaml; nothing to emit. */",
|
|
40
|
+
"",
|
|
41
|
+
"#endif /* ALP_SYSTEM_IPC_H */",
|
|
42
|
+
"",
|
|
43
|
+
]
|
|
44
|
+
return "\n".join(lines)
|
|
45
|
+
|
|
46
|
+
for c in carve_outs:
|
|
47
|
+
upper = c.name.upper()
|
|
48
|
+
lines.append(f"/* {c.kind} channel '{c.name}' -- endpoints "
|
|
49
|
+
f"{', '.join(c.endpoints)} */")
|
|
50
|
+
if c.status == "blocked":
|
|
51
|
+
# Blocked entries still need the SRC_EPT / DST_EPT / MBOX_CH /
|
|
52
|
+
# ADDR / SIZE macros so consumer source compiles: the
|
|
53
|
+
# canonical pattern (see examples/rpmsg-*/m*/src/main.c) is a
|
|
54
|
+
# static struct initialiser that references every field at
|
|
55
|
+
# compile time. Omitting the macros made every rpmsg
|
|
56
|
+
# consumer fail with `<macro> undeclared` long before the
|
|
57
|
+
# NOSUPPORT runtime check could even fire. Emit safe-zero
|
|
58
|
+
# stubs + a #warning so the build is green and the gap is
|
|
59
|
+
# surfaced via the alp_rpc_open() ALP_ERR_NOSUPPORT path
|
|
60
|
+
# the backend already returns when it sees a zero
|
|
61
|
+
# mailbox_channel or empty mailbox controller.
|
|
62
|
+
lines.append(f"/* BLOCKED: {c.reason or 'unknown reason'} */")
|
|
63
|
+
# Surface the gap as a structured comment block rather than
|
|
64
|
+
# a `#warning` (the slice builds under -Werror=cpp and an
|
|
65
|
+
# actual warning would trip it). The same reason text is
|
|
66
|
+
# also written into the build manifest by the orchestrator's
|
|
67
|
+
# fan-out step so reviewers see it.
|
|
68
|
+
lines.append(f"/* IPC channel '{c.name}' is blocked; "
|
|
69
|
+
"fix the SoM metadata before depending on this "
|
|
70
|
+
"channel at runtime. */")
|
|
71
|
+
lines.append(f'#define ALP_IPC_{upper}_NAME "{c.name}"')
|
|
72
|
+
lines.append(f"#define ALP_IPC_{upper}_ADDR 0x0u /* stub: blocked */")
|
|
73
|
+
lines.append(f"#define ALP_IPC_{upper}_SIZE 0x0u /* stub: blocked */")
|
|
74
|
+
lines.append(f"#define ALP_IPC_{upper}_SRC_EPT 0x0u /* stub: blocked */")
|
|
75
|
+
lines.append(f"#define ALP_IPC_{upper}_DST_EPT 0x0u /* stub: blocked */")
|
|
76
|
+
lines.append(f"#define ALP_IPC_{upper}_MBOX_CH 0u /* stub: blocked */")
|
|
77
|
+
lines.append("")
|
|
78
|
+
continue
|
|
79
|
+
lines.append(f'#define ALP_IPC_{upper}_NAME "{c.name}"')
|
|
80
|
+
lines.append(f'#define ALP_IPC_{upper}_ADDR 0x{c.base:08x}u')
|
|
81
|
+
lines.append(f'#define ALP_IPC_{upper}_SIZE 0x{c.size:08x}u')
|
|
82
|
+
lines.append(f'#define ALP_IPC_{upper}_SRC_EPT 0x{c.src_ept:08x}u')
|
|
83
|
+
lines.append(f'#define ALP_IPC_{upper}_DST_EPT 0x{c.dst_ept:08x}u')
|
|
84
|
+
lines.append(f'#define ALP_IPC_{upper}_MBOX_CH {c.mailbox_channel}u')
|
|
85
|
+
lines.append("")
|
|
86
|
+
|
|
87
|
+
lines.append("#endif /* ALP_SYSTEM_IPC_H */")
|
|
88
|
+
lines.append("")
|
|
89
|
+
return "\n".join(lines)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def emit_dts_reservations(project: BoardProject) -> str:
|
|
93
|
+
"""Generate dts-reservations.dtsi per spec §6.2."""
|
|
94
|
+
carve_outs = resolve_carve_outs(project)
|
|
95
|
+
lines: list[str] = [
|
|
96
|
+
"/*",
|
|
97
|
+
" * Auto-generated by scripts/alp_orchestrate.py -- do not edit.",
|
|
98
|
+
" * Regenerate after changes to board.yaml `ipc:` or the SoM's",
|
|
99
|
+
" * memory_map block. #include this file from your kernel /",
|
|
100
|
+
" * Zephyr DT.",
|
|
101
|
+
" */",
|
|
102
|
+
"",
|
|
103
|
+
"/ {",
|
|
104
|
+
" reserved-memory {",
|
|
105
|
+
" #address-cells = <2>;",
|
|
106
|
+
" #size-cells = <2>;",
|
|
107
|
+
"",
|
|
108
|
+
]
|
|
109
|
+
if not carve_outs:
|
|
110
|
+
lines.append(" /* No ipc[] carve-outs declared. */")
|
|
111
|
+
else:
|
|
112
|
+
for c in carve_outs:
|
|
113
|
+
if c.status == "blocked":
|
|
114
|
+
# Blocked carve-outs land as a comment so reviewers see
|
|
115
|
+
# the gap; the slice build trips elsewhere (the C
|
|
116
|
+
# header carries an #error directive).
|
|
117
|
+
lines.append(f" /* BLOCKED: {c.name} -- "
|
|
118
|
+
f"{c.reason or 'unknown reason'} */")
|
|
119
|
+
lines.append("")
|
|
120
|
+
continue
|
|
121
|
+
# Split base / size into two 32-bit halves for the
|
|
122
|
+
# #address-cells = <2>; #size-cells = <2>; addressing.
|
|
123
|
+
base_hi = (c.base >> 32) & 0xFFFFFFFF
|
|
124
|
+
base_lo = c.base & 0xFFFFFFFF
|
|
125
|
+
size_hi = (c.size >> 32) & 0xFFFFFFFF
|
|
126
|
+
size_lo = c.size & 0xFFFFFFFF
|
|
127
|
+
lines.append(
|
|
128
|
+
f" {c.name}: {c.name}@{c.base:x} {{")
|
|
129
|
+
lines.append(
|
|
130
|
+
' compatible = "shared-dma-pool";')
|
|
131
|
+
lines.append(
|
|
132
|
+
f" reg = <0x{base_hi:x} 0x{base_lo:08x} "
|
|
133
|
+
f"0x{size_hi:x} 0x{size_lo:08x}>;")
|
|
134
|
+
lines.append(" no-map;")
|
|
135
|
+
lines.append(f' label = "{c.name}";')
|
|
136
|
+
lines.append(" };")
|
|
137
|
+
lines.append("")
|
|
138
|
+
|
|
139
|
+
lines.append(" };")
|
|
140
|
+
lines.append("};")
|
|
141
|
+
lines.append("")
|
|
142
|
+
return "\n".join(lines)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def emit_dts_partitions(project: BoardProject) -> str:
|
|
146
|
+
"""Generate dts-partitions.dtsi from board.yaml `storage:`.
|
|
147
|
+
|
|
148
|
+
The overlay decorates each referenced flash device with a
|
|
149
|
+
`partitions { ... }` child node carrying every resolved
|
|
150
|
+
partition for that device. Zephyr's `fixed-partitions` binding
|
|
151
|
+
consumes the result; downstream Kconfig (CONFIG_FILE_SYSTEM_LITTLEFS
|
|
152
|
+
etc., emitted by `_slice_alp_conf()`) wires the filesystem driver.
|
|
153
|
+
|
|
154
|
+
Blocked partitions appear as bare comments so reviewers see the
|
|
155
|
+
gap; the slice build trips elsewhere (the per-fs Kconfig will not
|
|
156
|
+
have a backing partition and Zephyr's link-time fs-table assembly
|
|
157
|
+
surfaces the error).
|
|
158
|
+
"""
|
|
159
|
+
partitions = resolve_storage_partitions(project)
|
|
160
|
+
lines: list[str] = [
|
|
161
|
+
"/*",
|
|
162
|
+
" * Auto-generated by scripts/alp_orchestrate.py -- do not edit.",
|
|
163
|
+
" * Regenerate after changes to board.yaml `storage:` or the SoM's",
|
|
164
|
+
" * memory_map / on_module.ospi_memories blocks. #include this file",
|
|
165
|
+
" * from your Zephyr DT.",
|
|
166
|
+
" */",
|
|
167
|
+
"",
|
|
168
|
+
]
|
|
169
|
+
if not partitions:
|
|
170
|
+
lines += [
|
|
171
|
+
"/* No `storage:` entries declared in board.yaml; nothing to emit. */",
|
|
172
|
+
"",
|
|
173
|
+
]
|
|
174
|
+
return "\n".join(lines)
|
|
175
|
+
|
|
176
|
+
# Group resolved partitions by dt_label; blocked entries get a
|
|
177
|
+
# standalone comment block so reviewers see the gap.
|
|
178
|
+
by_label: dict[str, list[ResolvedPartition]] = {}
|
|
179
|
+
blocked: list[ResolvedPartition] = []
|
|
180
|
+
for p in partitions:
|
|
181
|
+
if p.status == "blocked":
|
|
182
|
+
blocked.append(p)
|
|
183
|
+
continue
|
|
184
|
+
by_label.setdefault(p.dt_label, []).append(p)
|
|
185
|
+
|
|
186
|
+
for label in sorted(by_label.keys()):
|
|
187
|
+
lines.append(f"&{label} {{")
|
|
188
|
+
lines.append(" partitions {")
|
|
189
|
+
lines.append(' compatible = "fixed-partitions";')
|
|
190
|
+
lines.append(" #address-cells = <1>;")
|
|
191
|
+
lines.append(" #size-cells = <1>;")
|
|
192
|
+
lines.append("")
|
|
193
|
+
# Sort by base offset for human readability + DT-binding
|
|
194
|
+
# convention (low-address first).
|
|
195
|
+
for p in sorted(by_label[label], key=lambda x: x.base_kib):
|
|
196
|
+
base_bytes = p.base_kib * 1024
|
|
197
|
+
size_bytes = p.size_kib * 1024
|
|
198
|
+
lines.append(
|
|
199
|
+
f" {p.name}_partition: partition@{base_bytes:x} {{")
|
|
200
|
+
lines.append(f' label = "{p.name}";')
|
|
201
|
+
lines.append(
|
|
202
|
+
f" reg = <0x{base_bytes:x} 0x{size_bytes:x}>;")
|
|
203
|
+
lines.append(" };")
|
|
204
|
+
lines.append("")
|
|
205
|
+
lines.append(" };")
|
|
206
|
+
lines.append("};")
|
|
207
|
+
lines.append("")
|
|
208
|
+
|
|
209
|
+
if blocked:
|
|
210
|
+
lines.append(
|
|
211
|
+
"/* Blocked storage entries -- see system-manifest.yaml for details. */")
|
|
212
|
+
for p in blocked:
|
|
213
|
+
lines.append(f"/* BLOCKED: {p.name} -- "
|
|
214
|
+
f"{p.reason or 'unknown reason'} */")
|
|
215
|
+
lines.append("")
|
|
216
|
+
|
|
217
|
+
return "\n".join(lines)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _mountable_partitions(project: BoardProject):
|
|
221
|
+
"""Resolved storage partitions that get a row in the mount table."""
|
|
222
|
+
return [p for p in resolve_storage_partitions(project)
|
|
223
|
+
if p.status == "ok" and p.mount and p.fs != "raw"]
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def has_storage_mounts(project: BoardProject) -> bool:
|
|
227
|
+
"""True when `emit_storage_mounts_c` would emit a non-empty table."""
|
|
228
|
+
return bool(_mountable_partitions(project))
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def emit_storage_mounts_c(project: BoardProject) -> str:
|
|
232
|
+
"""Generate storage_mount_table.c -- a static fs_mount_t[] array.
|
|
233
|
+
|
|
234
|
+
Optional companion to emit_dts_partitions. Apps that want
|
|
235
|
+
deterministic boot-time mounting include this file and call
|
|
236
|
+
`alp_storage_mount_all()` (or iterate the table manually).
|
|
237
|
+
Partitions with no `mount:` declared are omitted from the table.
|
|
238
|
+
"""
|
|
239
|
+
mountable = _mountable_partitions(project)
|
|
240
|
+
|
|
241
|
+
lines: list[str] = [
|
|
242
|
+
"/*",
|
|
243
|
+
" * Auto-generated by scripts/alp_orchestrate.py -- do not edit.",
|
|
244
|
+
" * Regenerate after changes to board.yaml `storage:`.",
|
|
245
|
+
" */",
|
|
246
|
+
"/* clang-format off */",
|
|
247
|
+
"",
|
|
248
|
+
"#include <zephyr/fs/fs.h>",
|
|
249
|
+
"#include <zephyr/storage/flash_map.h>",
|
|
250
|
+
"",
|
|
251
|
+
]
|
|
252
|
+
if not mountable:
|
|
253
|
+
lines += [
|
|
254
|
+
"/* No mountable storage[] entries declared; emitting empty table. */",
|
|
255
|
+
"",
|
|
256
|
+
"const struct fs_mount_t *alp_storage_mounts[] = { 0 };",
|
|
257
|
+
"const size_t alp_storage_mount_count = 0;",
|
|
258
|
+
"/* clang-format on */",
|
|
259
|
+
"",
|
|
260
|
+
]
|
|
261
|
+
return "\n".join(lines)
|
|
262
|
+
|
|
263
|
+
# Per-fs includes + per-partition fs_<name>_data + fs_mount_t.
|
|
264
|
+
fs_seen: set[str] = set()
|
|
265
|
+
for p in mountable:
|
|
266
|
+
if p.fs in fs_seen:
|
|
267
|
+
continue
|
|
268
|
+
fs_seen.add(p.fs)
|
|
269
|
+
if p.fs == "littlefs":
|
|
270
|
+
lines.append("#include <zephyr/fs/littlefs.h>")
|
|
271
|
+
elif p.fs == "fat":
|
|
272
|
+
lines.append("#include <ff.h>")
|
|
273
|
+
elif p.fs == "ext4":
|
|
274
|
+
lines.append("#include <zephyr/fs/ext2.h>")
|
|
275
|
+
lines.append("")
|
|
276
|
+
|
|
277
|
+
for p in mountable:
|
|
278
|
+
upper = p.name.upper()
|
|
279
|
+
if p.fs == "littlefs":
|
|
280
|
+
lines.append(f"FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(alp_lfs_{p.name});")
|
|
281
|
+
lines.append(f"static struct fs_mount_t alp_mnt_{p.name} = {{")
|
|
282
|
+
lines.append(" .type = FS_LITTLEFS,")
|
|
283
|
+
lines.append(f" .fs_data = &alp_lfs_{p.name},")
|
|
284
|
+
lines.append(f" .storage_dev = (void *)FIXED_PARTITION_ID({p.name}_partition),")
|
|
285
|
+
lines.append(f' .mnt_point = "{p.mount}",')
|
|
286
|
+
lines.append("};")
|
|
287
|
+
elif p.fs == "fat":
|
|
288
|
+
lines.append(f"static FATFS alp_fat_{p.name};")
|
|
289
|
+
lines.append(f"static struct fs_mount_t alp_mnt_{p.name} = {{")
|
|
290
|
+
lines.append(" .type = FS_FATFS,")
|
|
291
|
+
lines.append(f" .fs_data = &alp_fat_{p.name},")
|
|
292
|
+
lines.append(f" .storage_dev = (void *)FIXED_PARTITION_ID({p.name}_partition),")
|
|
293
|
+
lines.append(f' .mnt_point = "{p.mount}",')
|
|
294
|
+
lines.append("};")
|
|
295
|
+
elif p.fs == "ext4":
|
|
296
|
+
lines.append(f"static struct fs_mount_t alp_mnt_{p.name} = {{")
|
|
297
|
+
lines.append(" .type = FS_EXT2,")
|
|
298
|
+
lines.append(f" .storage_dev = (void *)FIXED_PARTITION_ID({p.name}_partition),")
|
|
299
|
+
lines.append(f' .mnt_point = "{p.mount}",')
|
|
300
|
+
lines.append("};")
|
|
301
|
+
lines.append("")
|
|
302
|
+
# Silence -Wunused on the per-partition mount when the app
|
|
303
|
+
# iterates only via alp_storage_mounts[]; the explicit symbol
|
|
304
|
+
# lets test fixtures reach a specific mount by name.
|
|
305
|
+
_ = upper
|
|
306
|
+
|
|
307
|
+
lines.append("const struct fs_mount_t *alp_storage_mounts[] = {")
|
|
308
|
+
for p in mountable:
|
|
309
|
+
lines.append(f" &alp_mnt_{p.name},")
|
|
310
|
+
lines.append("};")
|
|
311
|
+
lines.append("const size_t alp_storage_mount_count = "
|
|
312
|
+
f"{len(mountable)};")
|
|
313
|
+
lines.append("/* clang-format on */")
|
|
314
|
+
lines.append("")
|
|
315
|
+
return "\n".join(lines)
|