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.
Files changed (330) hide show
  1. tan/__init__.py +0 -0
  2. tan/__main__.py +120 -0
  3. tan/cli.py +939 -0
  4. tan/command_table.py +265 -0
  5. tan/commands/__init__.py +8 -0
  6. tan/commands/bootstrap_cmd.py +4856 -0
  7. tan/commands/bootstrap_patches.py +164 -0
  8. tan/commands/bootstrap_toolchain_fetch.py +155 -0
  9. tan/commands/bootstrap_toolchain_pin.py +36 -0
  10. tan/commands/build/__init__.py +1 -0
  11. tan/commands/build/configure_inputs.py +277 -0
  12. tan/commands/build/execute.py +1852 -0
  13. tan/commands/build/host_python.py +59 -0
  14. tan/commands/build/link_stale.py +78 -0
  15. tan/commands/build/manifest.py +428 -0
  16. tan/commands/build/materialise.py +81 -0
  17. tan/commands/build/token_substitution.py +381 -0
  18. tan/commands/build/toolchain.py +482 -0
  19. tan/commands/build/user_defines_wipe.py +115 -0
  20. tan/commands/build/workspace_patches.py +65 -0
  21. tan/commands/build_cmd.py +2236 -0
  22. tan/commands/build_output.py +331 -0
  23. tan/commands/clean_cmd.py +1183 -0
  24. tan/commands/completion_cmd.py +786 -0
  25. tan/commands/debug_config_cmd.py +2425 -0
  26. tan/commands/diff_cmd.py +940 -0
  27. tan/commands/doctor_cmd.py +4767 -0
  28. tan/commands/examples_cmd.py +644 -0
  29. tan/commands/explain_cmd.py +1319 -0
  30. tan/commands/faultdecode_cmd.py +931 -0
  31. tan/commands/flash_atoc_guard.py +240 -0
  32. tan/commands/flash_cmd.py +5731 -0
  33. tan/commands/flash_mram_guard.py +150 -0
  34. tan/commands/flash_ram.py +578 -0
  35. tan/commands/flash_raw.py +583 -0
  36. tan/commands/generate_cmd.py +1456 -0
  37. tan/commands/image_cmd.py +753 -0
  38. tan/commands/init_cmd.py +1740 -0
  39. tan/commands/inspect_cmd.py +377 -0
  40. tan/commands/kconfig_cmd.py +734 -0
  41. tan/commands/model_cmd.py +1514 -0
  42. tan/commands/model_device_cmd.py +351 -0
  43. tan/commands/model_device_live.py +234 -0
  44. tan/commands/model_host_cmd.py +430 -0
  45. tan/commands/model_zoo_cmd.py +363 -0
  46. tan/commands/monitor_actions.py +125 -0
  47. tan/commands/monitor_cmd.py +626 -0
  48. tan/commands/monitor_session.py +505 -0
  49. tan/commands/new_som_cmd.py +1522 -0
  50. tan/commands/pinmux_cmd.py +568 -0
  51. tan/commands/presets_cmd.py +1123 -0
  52. tan/commands/probe_cmd.py +421 -0
  53. tan/commands/reset_cmd.py +354 -0
  54. tan/commands/reset_confirm.py +168 -0
  55. tan/commands/run_cmd.py +637 -0
  56. tan/commands/scaffold_cmd.py +490 -0
  57. tan/commands/sdk_cmd.py +1723 -0
  58. tan/commands/size_cmd.py +1020 -0
  59. tan/commands/support_bundle_cmd.py +1073 -0
  60. tan/commands/trace_cmd.py +341 -0
  61. tan/commands/validate_cmd.py +2009 -0
  62. tan/commands/west_forward_cmd.py +736 -0
  63. tan/commands/workspace_patch_check.py +296 -0
  64. tan/core/__init__.py +1 -0
  65. tan/core/alp_conf_pregen.py +100 -0
  66. tan/core/artifact_provenance.py +240 -0
  67. tan/core/atoc_guard.py +276 -0
  68. tan/core/atoc_guard_messages.py +232 -0
  69. tan/core/atoc_replacement.py +118 -0
  70. tan/core/atomic_write.py +178 -0
  71. tan/core/board_context.py +351 -0
  72. tan/core/board_diagnostic.py +111 -0
  73. tan/core/board_files.py +221 -0
  74. tan/core/board_validator.py +542 -0
  75. tan/core/board_validator_compat.py +196 -0
  76. tan/core/board_validator_run.py +129 -0
  77. tan/core/board_validator_schema.py +186 -0
  78. tan/core/board_validator_skew.py +46 -0
  79. tan/core/board_yaml_edit.py +295 -0
  80. tan/core/board_yaml_pos.py +118 -0
  81. tan/core/bootstrap.py +2572 -0
  82. tan/core/build_plan.py +625 -0
  83. tan/core/consent.py +104 -0
  84. tan/core/console_filter.py +245 -0
  85. tan/core/debug_launch.py +1803 -0
  86. tan/core/devicetree_lint.py +168 -0
  87. tan/core/dir_removal.py +229 -0
  88. tan/core/doctor_git.py +172 -0
  89. tan/core/doctor_libraries.py +253 -0
  90. tan/core/doctor_render.py +185 -0
  91. tan/core/doctor_scope.py +66 -0
  92. tan/core/doctor_setools.py +237 -0
  93. tan/core/doctor_stale.py +180 -0
  94. tan/core/document_guards.py +723 -0
  95. tan/core/dp_id.py +97 -0
  96. tan/core/elf_load.py +63 -0
  97. tan/core/error_catalog.py +171 -0
  98. tan/core/example_catalog.py +499 -0
  99. tan/core/example_facets.py +151 -0
  100. tan/core/faultdecode.py +521 -0
  101. tan/core/flash_plan.py +2501 -0
  102. tan/core/flow_d_report.py +381 -0
  103. tan/core/flow_d_uptime.py +164 -0
  104. tan/core/fs_confine.py +130 -0
  105. tan/core/global_flags.py +230 -0
  106. tan/core/host_python.py +210 -0
  107. tan/core/image_bundle.py +247 -0
  108. tan/core/inert.py +147 -0
  109. tan/core/jlink_binary.py +128 -0
  110. tan/core/jlink_probe.py +481 -0
  111. tan/core/jsonc_splice.py +404 -0
  112. tan/core/launch_provenance.py +257 -0
  113. tan/core/link_refusal.py +76 -0
  114. tan/core/metadata_schema.py +376 -0
  115. tan/core/model_check.py +227 -0
  116. tan/core/model_device.py +449 -0
  117. tan/core/model_doctor.py +198 -0
  118. tan/core/model_host.py +48 -0
  119. tan/core/model_list.py +112 -0
  120. tan/core/model_zoo.py +353 -0
  121. tan/core/module_template.py +340 -0
  122. tan/core/mram_link.py +87 -0
  123. tan/core/new_som_ospi.py +94 -0
  124. tan/core/os_class.py +159 -0
  125. tan/core/patch_paths.py +87 -0
  126. tan/core/pending.py +40 -0
  127. tan/core/plain_zephyr_plan.py +138 -0
  128. tan/core/plan_exec.py +373 -0
  129. tan/core/plan_tokens.py +600 -0
  130. tan/core/probe.py +155 -0
  131. tan/core/probe_plan.py +237 -0
  132. tan/core/proxy.py +168 -0
  133. tan/core/publish.py +31 -0
  134. tan/core/python_floor.py +178 -0
  135. tan/core/ram_run.py +694 -0
  136. tan/core/ram_watch.py +231 -0
  137. tan/core/raw_write.py +160 -0
  138. tan/core/reset_plan.py +56 -0
  139. tan/core/run.py +161 -0
  140. tan/core/scaffold.py +2203 -0
  141. tan/core/scaffold_selftest_identity.py +225 -0
  142. tan/core/sdk_default_registry.py +565 -0
  143. tan/core/sdk_discovery.py +996 -0
  144. tan/core/sdk_removal.py +465 -0
  145. tan/core/serial_actions.py +175 -0
  146. tan/core/serial_capture.py +185 -0
  147. tan/core/serial_url.py +45 -0
  148. tan/core/setools.py +608 -0
  149. tan/core/setools_scratch.py +243 -0
  150. tan/core/shapes.py +194 -0
  151. tan/core/size.py +610 -0
  152. tan/core/som_buildability.py +204 -0
  153. tan/core/som_schema_version.py +62 -0
  154. tan/core/subprocess_env.py +201 -0
  155. tan/core/sysbuild_image.py +94 -0
  156. tan/core/system_manifest.py +827 -0
  157. tan/core/text_layout.py +73 -0
  158. tan/core/timestamp.py +182 -0
  159. tan/core/tool_lookup.py +383 -0
  160. tan/core/toolchain_pin.py +117 -0
  161. tan/core/toolchain_provision.py +1224 -0
  162. tan/core/trusted_path.py +134 -0
  163. tan/core/uboot_breakin.py +154 -0
  164. tan/core/uri_reference.py +415 -0
  165. tan/core/user_defines.py +152 -0
  166. tan/core/venv.py +332 -0
  167. tan/core/west_patches.py +143 -0
  168. tan/core/west_workspace_refusal.py +159 -0
  169. tan/core/zephyr_env.py +124 -0
  170. tan/env.py +185 -0
  171. tan/envelope.py +647 -0
  172. tan/exit_codes.py +12 -0
  173. tan/lazy_typer.py +185 -0
  174. tan/model/__init__.py +2 -0
  175. tan/model/_gen_fixture.py +132 -0
  176. tan/model/adapters/__init__.py +116 -0
  177. tan/model/adapters/cpu.py +26 -0
  178. tan/model/adapters/deepx.py +94 -0
  179. tan/model/adapters/drpai.py +242 -0
  180. tan/model/adapters/ethos_u.py +951 -0
  181. tan/model/adapters/executorch.py +55 -0
  182. tan/model/analyze.py +694 -0
  183. tan/model/build.py +304 -0
  184. tan/model/check.py +682 -0
  185. tan/model/manifest.py +625 -0
  186. tan/model/measure.py +216 -0
  187. tan/model/npu_ops_validate.py +130 -0
  188. tan/model/package.py +125 -0
  189. tan/model/perf.py +635 -0
  190. tan/model/perf_apply.py +721 -0
  191. tan/model/prep.py +193 -0
  192. tan/model/sram_fit.py +502 -0
  193. tan/model/targets.py +374 -0
  194. tan/model/tensorio.py +287 -0
  195. tan/net.py +73 -0
  196. tan/output_format.py +213 -0
  197. tan/planner/__init__.py +219 -0
  198. tan/planner/aperture.py +202 -0
  199. tan/planner/buildplan.py +1092 -0
  200. tan/planner/camera_owner.py +192 -0
  201. tan/planner/cameras.py +132 -0
  202. tan/planner/carveout.py +755 -0
  203. tan/planner/cli.py +274 -0
  204. tan/planner/headers.py +315 -0
  205. tan/planner/kconfig.py +2435 -0
  206. tan/planner/kconfig_symbols.py +473 -0
  207. tan/planner/libraries.py +677 -0
  208. tan/planner/link_target.py +237 -0
  209. tan/planner/linux_ownership.py +216 -0
  210. tan/planner/loader.py +1525 -0
  211. tan/planner/manifest.py +116 -0
  212. tan/planner/memory.py +161 -0
  213. tan/planner/memregion.py +56 -0
  214. tan/planner/models.py +533 -0
  215. tan/planner/orchestrator.py +874 -0
  216. tan/planner/ownership.py +203 -0
  217. tan/planner/partition.py +1160 -0
  218. tan/planner/paths.py +32 -0
  219. tan/planner/plain_slice.py +139 -0
  220. tan/planner/project_emit/__init__.py +60 -0
  221. tan/planner/project_emit/bom_netlist.py +375 -0
  222. tan/planner/project_emit/dts.py +580 -0
  223. tan/planner/project_emit/hw_info.py +221 -0
  224. tan/planner/project_emit/native_sim.py +136 -0
  225. tan/planner/project_emit/west_libs.py +213 -0
  226. tan/planner/project_loader.py +264 -0
  227. tan/planner/sdk_capability.py +203 -0
  228. tan/planner/sdk_compat.py +395 -0
  229. tan/planner/secure.py +350 -0
  230. tan/planner/slugs.py +394 -0
  231. tan/planner/som_metadata.py +325 -0
  232. tan/planner/strict_loaders.py +131 -0
  233. tan/planner/template.py +1037 -0
  234. tan/planner/template_pins.py +535 -0
  235. tan/planner/template_rewrite.py +714 -0
  236. tan/planner/topology.py +208 -0
  237. tan/planner/validate.py +365 -0
  238. tan/planner/whole_device_alias.py +67 -0
  239. tan/planner/zephyr_board.py +3510 -0
  240. tan/planner_cli.py +97 -0
  241. tan/planner_emit.py +617 -0
  242. tan/planner_root.py +119 -0
  243. tan/soc_ref.py +58 -0
  244. tan/templates/__init__.py +34 -0
  245. tan/templates/vendored/MANIFEST.md +1862 -0
  246. tan/templates/vendored/diagnostics/E1M-AEN801/CMakeLists.txt +8 -0
  247. tan/templates/vendored/diagnostics/E1M-AEN801/README.md +112 -0
  248. tan/templates/vendored/diagnostics/E1M-AEN801/board.yaml +38 -0
  249. tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.conf +11 -0
  250. tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.overlay +29 -0
  251. tan/templates/vendored/diagnostics/E1M-AEN801/prj.conf +5 -0
  252. tan/templates/vendored/diagnostics/E1M-AEN801/src/main.c +266 -0
  253. tan/templates/vendored/diagnostics/E1M-AEN801/testcase.yaml +53 -0
  254. tan/templates/vendored/diagnostics/E1M-V2N101/CMakeLists.txt +8 -0
  255. tan/templates/vendored/diagnostics/E1M-V2N101/README.md +112 -0
  256. tan/templates/vendored/diagnostics/E1M-V2N101/board.yaml +38 -0
  257. tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.conf +11 -0
  258. tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.overlay +29 -0
  259. tan/templates/vendored/diagnostics/E1M-V2N101/prj.conf +5 -0
  260. tan/templates/vendored/diagnostics/E1M-V2N101/src/main.c +266 -0
  261. tan/templates/vendored/diagnostics/E1M-V2N101/testcase.yaml +53 -0
  262. tan/templates/vendored/edge-ai/E1M-AEN801/CMakeLists.txt +10 -0
  263. tan/templates/vendored/edge-ai/E1M-AEN801/README.md +75 -0
  264. tan/templates/vendored/edge-ai/E1M-AEN801/board.yaml +38 -0
  265. tan/templates/vendored/edge-ai/E1M-AEN801/prj.conf +8 -0
  266. tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.c +371 -0
  267. tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.h +178 -0
  268. tan/templates/vendored/edge-ai/E1M-AEN801/src/main.c +373 -0
  269. tan/templates/vendored/edge-ai/E1M-AEN801/testcase.yaml +62 -0
  270. tan/templates/vendored/edge-ai/E1M-V2N101/CMakeLists.txt +10 -0
  271. tan/templates/vendored/edge-ai/E1M-V2N101/README.md +75 -0
  272. tan/templates/vendored/edge-ai/E1M-V2N101/board.yaml +37 -0
  273. tan/templates/vendored/edge-ai/E1M-V2N101/prj.conf +8 -0
  274. tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.c +371 -0
  275. tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.h +178 -0
  276. tan/templates/vendored/edge-ai/E1M-V2N101/src/main.c +373 -0
  277. tan/templates/vendored/edge-ai/E1M-V2N101/testcase.yaml +62 -0
  278. tan/templates/vendored/iot/E1M-AEN801/CMakeLists.txt +14 -0
  279. tan/templates/vendored/iot/E1M-AEN801/README.md +103 -0
  280. tan/templates/vendored/iot/E1M-AEN801/board.yaml +69 -0
  281. tan/templates/vendored/iot/E1M-AEN801/prj.conf +15 -0
  282. tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.c +196 -0
  283. tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.h +173 -0
  284. tan/templates/vendored/iot/E1M-AEN801/src/main.c +262 -0
  285. tan/templates/vendored/iot/E1M-AEN801/testcase.yaml +68 -0
  286. tan/templates/vendored/minimal/E1M-AEN801/CMakeLists.txt +8 -0
  287. tan/templates/vendored/minimal/E1M-AEN801/README.md +108 -0
  288. tan/templates/vendored/minimal/E1M-AEN801/board.yaml +32 -0
  289. tan/templates/vendored/minimal/E1M-AEN801/prj.conf +8 -0
  290. tan/templates/vendored/minimal/E1M-AEN801/src/main.c +111 -0
  291. tan/templates/vendored/minimal/E1M-AEN801/testcase.yaml +49 -0
  292. tan/templates/vendored/minimal/E1M-V2N101/CMakeLists.txt +8 -0
  293. tan/templates/vendored/minimal/E1M-V2N101/README.md +108 -0
  294. tan/templates/vendored/minimal/E1M-V2N101/board.yaml +32 -0
  295. tan/templates/vendored/minimal/E1M-V2N101/prj.conf +8 -0
  296. tan/templates/vendored/minimal/E1M-V2N101/src/main.c +111 -0
  297. tan/templates/vendored/minimal/E1M-V2N101/testcase.yaml +49 -0
  298. tan/templates/vendored/multicore-mailbox/E1M-AEN801/CMakeLists.txt +8 -0
  299. tan/templates/vendored/multicore-mailbox/E1M-AEN801/README.md +120 -0
  300. tan/templates/vendored/multicore-mailbox/E1M-AEN801/board.yaml +57 -0
  301. tan/templates/vendored/multicore-mailbox/E1M-AEN801/boards/native_sim_native_64.overlay +40 -0
  302. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/CMakeLists.txt +13 -0
  303. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/main.c +171 -0
  304. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/prj.conf +17 -0
  305. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/testcase.yaml +23 -0
  306. tan/templates/vendored/multicore-mailbox/E1M-AEN801/prj.conf +22 -0
  307. tan/templates/vendored/multicore-mailbox/E1M-AEN801/src/main.c +185 -0
  308. tan/templates/vendored/multicore-mailbox/E1M-AEN801/testcase.yaml +26 -0
  309. tan/templates/vendored/sensor/E1M-AEN801/CMakeLists.txt +8 -0
  310. tan/templates/vendored/sensor/E1M-AEN801/README.md +112 -0
  311. tan/templates/vendored/sensor/E1M-AEN801/board.yaml +57 -0
  312. tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.conf +10 -0
  313. tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.overlay +28 -0
  314. tan/templates/vendored/sensor/E1M-AEN801/prj.conf +5 -0
  315. tan/templates/vendored/sensor/E1M-AEN801/src/main.c +186 -0
  316. tan/templates/vendored/sensor/E1M-AEN801/testcase.yaml +52 -0
  317. tan/templates/vendored/sensor/E1M-V2N101/CMakeLists.txt +8 -0
  318. tan/templates/vendored/sensor/E1M-V2N101/README.md +112 -0
  319. tan/templates/vendored/sensor/E1M-V2N101/board.yaml +57 -0
  320. tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.conf +10 -0
  321. tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.overlay +28 -0
  322. tan/templates/vendored/sensor/E1M-V2N101/prj.conf +5 -0
  323. tan/templates/vendored/sensor/E1M-V2N101/src/main.c +186 -0
  324. tan/templates/vendored/sensor/E1M-V2N101/testcase.yaml +52 -0
  325. tan/version.py +102 -0
  326. tan_cli-0.7.0.dist-info/METADATA +125 -0
  327. tan_cli-0.7.0.dist-info/RECORD +330 -0
  328. tan_cli-0.7.0.dist-info/WHEEL +5 -0
  329. tan_cli-0.7.0.dist-info/entry_points.txt +2 -0
  330. tan_cli-0.7.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,221 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """C header emission for `<alp/hw_info.h>` (`--emit hw-info-h`).
3
+
4
+ RELOCATED (was alp-sdk `scripts/alp_project_emit/hw_info.py`) -- see this
5
+ package's `__init__.py` for the move's contract.
6
+
7
+ alp-sdk#1964 (tan-cli#1156 hand-port) made this emitter a second reader of
8
+ `hw-revisions.yaml`, through `board_designator()`: `ALP_HW_BUILD_SOM_HW_REV`
9
+ now carries the COMPOSED `<board_datecode>-<hw_rev>` form (`"2626-r2"`), not
10
+ the bare revision key, matching what `scripts/program_eeprom.py` writes into
11
+ the manifest and what the boot banner compares the live EEPROM read
12
+ against. The bare key is untouched everywhere it is a LOOKUP key
13
+ (board.yaml, `family_revision_known()`, `pad_route_overrides`) -- only this
14
+ identity/compare surface composes. A family that declares no
15
+ `board_datecode:` is unaffected (`board_designator` returns the bare key).
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from pathlib import Path
21
+ from typing import Any
22
+
23
+ from ..sdk_compat import board_designator, load_family_table
24
+ from ..som_metadata import _sku_family
25
+
26
+
27
+ # ---------------------------------------------------------------------
28
+ # C header emission (build-time identifiers for <alp/hw_info.h>)
29
+ # ---------------------------------------------------------------------
30
+ #
31
+ # Produces the auto-generated `<alp_hw_info_build.h>` companion to
32
+ # `<alp/hw_info.h>` -- a small header that bakes the customer's
33
+ # board.yaml identifiers in as `ALP_HW_BUILD_*` string macros so the
34
+ # runtime check has something to compare the EEPROM read against:
35
+ #
36
+ # #include "alp/hw_info.h"
37
+ # #include "alp_hw_info_build.h" // generated
38
+ #
39
+ # alp_hw_info_t info;
40
+ # alp_hw_info_read(&info);
41
+ # alp_hw_info_assert_matches_build(&info,
42
+ # ALP_HW_BUILD_SOM_SKU,
43
+ # ALP_HW_BUILD_SOM_HW_REV);
44
+ #
45
+ # A CMakeLists.txt consuming it writes the header to
46
+ # `${CMAKE_BINARY_DIR}/generated/` and adds that path to the include search.
47
+
48
+
49
+ def _pick_primary_core_os(cores: dict[str, str]) -> tuple[str, str]:
50
+ """Pick the "primary" core for the `ALP_HW_BUILD_OS` macro.
51
+
52
+ `cores` maps core id -> os string ("zephyr" / "yocto" / "baremetal" /
53
+ "off"). The selection rule:
54
+
55
+ 1. First M-class core (alphabetical by id), with os != off, if any.
56
+ 2. Else first A-class core (alphabetical by id), with os != off, if any.
57
+ 3. Else first non-off core (alphabetical by id), if any.
58
+ 4. Else returns ("", "off").
59
+
60
+ Returns (core_id, os).
61
+ """
62
+ active = {cid: os_ for cid, os_ in cores.items() if os_ != "off"}
63
+ if not active:
64
+ return ("", "off")
65
+ m_class = sorted(cid for cid in active if cid.startswith("m"))
66
+ if m_class:
67
+ cid = m_class[0]
68
+ return (cid, active[cid])
69
+ a_class = sorted(cid for cid in active if cid.startswith("a"))
70
+ if a_class:
71
+ cid = a_class[0]
72
+ return (cid, active[cid])
73
+ cid = sorted(active.keys())[0]
74
+ return (cid, active[cid])
75
+
76
+
77
+ def _emit_hw_info_h(
78
+ project: dict[str, Any],
79
+ sku_preset: dict[str, Any],
80
+ board_preset: dict[str, Any] | None,
81
+ *,
82
+ v2_cores: dict[str, str] | None = None,
83
+ v2_selected_core: str | None = None,
84
+ metadata_root: Path,
85
+ ) -> str:
86
+ """Emit <alp_hw_info_build.h> -- build-time identifier companion to
87
+ <alp/hw_info.h>.
88
+
89
+ v1 path (`v2_cores is None`): the `ALP_HW_BUILD_OS` macro comes from
90
+ `project.os` (the v1 schema's single top-level OS).
91
+
92
+ v2 path: derive `ALP_HW_BUILD_OS` from the cores: block. If
93
+ `v2_selected_core` is set (i.e. the caller passed `--core <id>`),
94
+ use that core's OS. Else pick a "primary" core via
95
+ `_pick_primary_core_os`: first M-class core alphabetically, falling
96
+ back to first A-class core, falling back to any non-off core.
97
+
98
+ The v2 path also emits `ALP_HW_BUILD_CORES` (comma-separated list of
99
+ every non-off core id) and one `ALP_HW_BUILD_HAS_<id>` macro per
100
+ non-off core so consumers can `#ifdef` on the topology.
101
+
102
+ `metadata_root` (alp-sdk#1964) resolves this SKU's family
103
+ `hw-revisions.yaml` (via `load_family_table`) so `ALP_HW_BUILD_SOM_HW_REV`
104
+ can be composed through `board_designator` -- see the module docstring.
105
+ """
106
+ sku = project["som"]["sku"]
107
+ som_hw_rev = (project["som"].get("hw_rev")
108
+ or sku_preset.get("default_hw_rev")
109
+ or "unknown")
110
+ family = _sku_family(sku)
111
+ som_hw_rev = board_designator(
112
+ load_family_table(metadata_root, family), som_hw_rev)
113
+
114
+ board_block = project.get("board") or {}
115
+ board_name = board_block.get("name") or ""
116
+ board_hw_rev = ""
117
+ if board_name and board_preset is not None:
118
+ board_hw_rev = (board_block.get("hw_rev")
119
+ or board_preset.get("default_hw_rev")
120
+ or "")
121
+
122
+ # Resolve the OS string.
123
+ primary_core_id = ""
124
+ primary_core_os = ""
125
+ if v2_cores is not None:
126
+ if v2_selected_core is not None and v2_selected_core in v2_cores:
127
+ primary_core_id = v2_selected_core
128
+ primary_core_os = v2_cores[v2_selected_core]
129
+ else:
130
+ primary_core_id, primary_core_os = _pick_primary_core_os(v2_cores)
131
+ os_choice = primary_core_os
132
+ else:
133
+ os_choice = project.get("os") or ""
134
+
135
+ lines: list[str] = [
136
+ "/*",
137
+ " * Auto-generated by scripts/alp_project.py -- do not edit by hand.",
138
+ " * Regenerate after changes to board.yaml.",
139
+ " *",
140
+ " * Build-time identifier companion to <alp/hw_info.h>. Apps include",
141
+ " * this header alongside <alp/hw_info.h> and pass the ALP_HW_BUILD_*",
142
+ " * string macros to alp_hw_info_assert_matches_build() so the runtime",
143
+ " * EEPROM read can be checked against what the firmware was built for.",
144
+ " */",
145
+ "",
146
+ "#ifndef ALP_HW_INFO_BUILD_H",
147
+ "#define ALP_HW_INFO_BUILD_H",
148
+ "",
149
+ f'#define ALP_HW_BUILD_SOM_SKU "{sku}"',
150
+ f'#define ALP_HW_BUILD_SOM_FAMILY "{family}"',
151
+ f'#define ALP_HW_BUILD_SOM_HW_REV "{som_hw_rev}"',
152
+ ]
153
+ if board_name:
154
+ lines.append(f'#define ALP_HW_BUILD_BOARD_NAME "{board_name}"')
155
+ if board_hw_rev:
156
+ lines.append(f'#define ALP_HW_BUILD_BOARD_HW_REV "{board_hw_rev}"')
157
+ if os_choice:
158
+ lines.append(f'#define ALP_HW_BUILD_OS "{os_choice}"')
159
+ if v2_cores is not None:
160
+ # `active` and the loop below range over every non-off core in the
161
+ # PROJECT, not the compiling slice, so this block's output --
162
+ # `CORES` and the `HAS_<id>` macros -- is identical in every
163
+ # slice's copy of the header. `PRIMARY_CORE` is the one
164
+ # exception: it tracks --core when the caller passes one.
165
+ # Primary-core selection rule (used when --core is not given):
166
+ # 1. First M-class core (alphabetical by id), if any non-off.
167
+ # 2. Else first A-class core (alphabetical by id), if any non-off.
168
+ # 3. Else first non-off core (alphabetical by id).
169
+ active = sorted(cid for cid, os_ in v2_cores.items() if os_ != "off")
170
+ if active:
171
+ lines.append("")
172
+ lines.append(
173
+ f'#define ALP_HW_BUILD_CORES "{",".join(active)}"'
174
+ )
175
+ if primary_core_id:
176
+ lines.append(
177
+ f'#define ALP_HW_BUILD_PRIMARY_CORE "{primary_core_id}"'
178
+ )
179
+ lines.append("")
180
+ lines.append("/* Per-core presence flags: `ALP_HW_BUILD_HAS_<id>` means "
181
+ "core <id> exists in")
182
+ lines.append(" * the project; its value is that core's OS string. Defined "
183
+ "for EVERY active")
184
+ lines.append(" * core in EVERY slice -- it cannot say which core is "
185
+ "compiling.")
186
+ lines.append(" *")
187
+ lines.append(" * `ALP_HW_BUILD_PRIMARY_CORE` names the compiling slice ONLY "
188
+ "when this header")
189
+ lines.append(" * was emitted --core-scoped (the per-slice build path). "
190
+ "Emitted without")
191
+ lines.append(" * --core -- as the project-wide recipe in "
192
+ "docs/board-config-emit.md does -- it")
193
+ lines.append(" * names the project's primary core (first M-class core "
194
+ "alphabetically),")
195
+ lines.append(" * which on a multi-core project is not necessarily the one "
196
+ "you are")
197
+ lines.append(" * building.")
198
+ lines.append(" *")
199
+ lines.append(" * Zephyr's own CONFIG_BOARD and CONFIG_BOARD_TARGET differ "
200
+ "per slice too --")
201
+ lines.append(" * the board name and the board/soc/cpucluster target "
202
+ "passed to `west build")
203
+ lines.append(" * -b` -- and do so no matter how this header was emitted. "
204
+ "E.g. on E1M-AEN801,")
205
+ lines.append(" * the HE slice's CONFIG_BOARD is "
206
+ "\"alp_e1m_aen801_m55_he\" and its")
207
+ lines.append(" * CONFIG_BOARD_TARGET ends \".../rtss_he\"; the HP "
208
+ "slice's end \"_hp\" and")
209
+ lines.append(" * \".../rtss_hp\". Prefer them over PRIMARY_CORE where "
210
+ "that portability")
211
+ lines.append(" * matters. */")
212
+ for cid in active:
213
+ lines.append(
214
+ f'#define ALP_HW_BUILD_HAS_{cid.upper():<12} "{v2_cores[cid]}"'
215
+ )
216
+ lines += [
217
+ "",
218
+ "#endif /* ALP_HW_INFO_BUILD_H */",
219
+ "",
220
+ ]
221
+ return "\n".join(lines)
@@ -0,0 +1,136 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """native_sim board overlay emission (`--emit native-sim-overlay`).
3
+
4
+ RELOCATED (was alp-sdk `scripts/alp_project_emit/native_sim.py`) -- see this
5
+ package's `__init__.py` for the move's contract.
6
+
7
+ One change beyond the import repoint: the three form-factor STRINGS are derived
8
+ from `_sku_form_factor`'s own return value instead of written out per branch.
9
+ alp-sdk spelled `form_factor = "E1M-X"` literally, which inside `tan` is a
10
+ hardware fact and fails `tests/gates/test_no_new_hardware_facts.py` -- correctly,
11
+ since naming the connector family is metadata's job, not tan's. `e1m-x` ->
12
+ `E1M-X` / `e1m_x_pinout.h` / `ALP_E1M_X_GPIO` is a pure re-spelling of the token
13
+ the loader already resolved, so the emitted bytes do not move;
14
+ `test_the_in_process_engine_matches_alp_project_for_every_mode` proves that over
15
+ every `board.yaml` in the SDK's `examples/`.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from typing import Any
21
+
22
+ from ..project_loader import _sku_form_factor
23
+
24
+ from . import _e1m_gpio_canonical, _e1m_x_gpio_canonical
25
+
26
+
27
+ # ---------------------------------------------------------------------
28
+ # native_sim overlay emission (canonical alp,pin-array on gpio-emul)
29
+ # ---------------------------------------------------------------------
30
+ #
31
+ # Studio + `alp init` want a native_sim board overlay so a scaffolded GPIO
32
+ # app links + runs on `native_sim/native/64` (host emulation, emulated CI)
33
+ # with no silicon. Unlike `--emit dts-overlay` -- which stubs every
34
+ # pin-array triplet at <&gpio0 0> pending the upstream SoM board file --
35
+ # gpio-emul IS the backing controller under native_sim, so this overlay is
36
+ # complete and directly buildable. Keeping it here (not hand-rolled in a
37
+ # downstream scaffolder) means the E1M/E1M-X pad ABI lives in exactly one
38
+ # place: the canonical helpers above.
39
+
40
+ # zephyr,gpio-emul controllers cap at 32 pins.
41
+ _GPIO_EMUL_MAX_PINS = 32
42
+
43
+
44
+ def _emit_native_sim_overlay(project: dict[str, Any]) -> str:
45
+ """Emit a native_sim board overlay: the canonical alp,pin-array mapped
46
+ onto zephyr,gpio-emul controllers.
47
+
48
+ The pin-array is the full positional map in the form-factor pinout header's
49
+ canonical order, so alp_z_gpio_resolve(pin_id) is a direct index for
50
+ any pad (the GPIO backend derives ALP_PIN_COUNT from this node's gpios
51
+ length). gpio-emul caps at 32 pins, so the pads span as many
52
+ controllers as the active form factor needs. Every pad defaults to
53
+ GPIO_ACTIVE_HIGH; an app that needs a
54
+ different polarity (e.g. an active-low button) overrides its own pad.
55
+
56
+ GPIO only: non-GPIO peripherals (display, sensors) have no universal
57
+ native_sim emulation, so an app that needs them adds its own emulated
58
+ nodes (e.g. a zephyr,dummy-dc display), exactly as the curated examples
59
+ do.
60
+ """
61
+ sku = project["som"]["sku"]
62
+ # `e1m-x` / `e1m` -> the three spellings the overlay's prose uses. Derived,
63
+ # not written out: the connector-family name is a hardware fact (I-26).
64
+ ff = _sku_form_factor(sku)
65
+ form_factor = ff.upper()
66
+ pinout_header = f"{ff.replace('-', '_')}_pinout.h"
67
+ gpio_macro_prefix = f"ALP_{form_factor.replace('-', '_')}_GPIO"
68
+ if ff == "e1m-x":
69
+ canonical = _e1m_x_gpio_canonical()
70
+ index_summary = [
71
+ " * 0..35 IO0..IO35 36..43 PWM0..PWM7",
72
+ " * 44..51 ENC0_X..ENC3_Y 52..59 ADC0..ADC7 60..61 DAC0..DAC1",
73
+ " * 62..72 I2C2/3 + SPI2 + CAN1",
74
+ " * 73..98 LCD_B0..LCD_B23 + LCD_HSYNC/LCD_VSYNC */",
75
+ ]
76
+ else:
77
+ canonical = _e1m_gpio_canonical()
78
+ index_summary = [
79
+ " * 0..25 IO0..IO25 26..33 PWM0..PWM7",
80
+ " * 34..41 ENC0_X..ENC3_Y 42..49 ADC0..ADC7 50..51 DAC0..DAC1 */",
81
+ ]
82
+ n = len(canonical)
83
+ n_ctrl = (n + _GPIO_EMUL_MAX_PINS - 1) // _GPIO_EMUL_MAX_PINS
84
+
85
+ lines: list[str] = []
86
+ lines.append("/*")
87
+ lines.append(" * Auto-generated by scripts/alp_project.py "
88
+ "--emit native-sim-overlay -- do not edit by hand.")
89
+ lines.append(f" * Regenerate after changes to the {pinout_header} GPIO order.")
90
+ lines.append(" *")
91
+ lines.append(f" * native_sim GPIO emulation for SoM SKU {sku}: the canonical")
92
+ lines.append(" * alp,pin-array mapped onto zephyr,gpio-emul so alp_gpio_open(pin_id)")
93
+ lines.append(f" * resolves under `west build -b native_sim/native/64`. All {n} {form_factor} pads")
94
+ lines.append(" * are present so any pin_id resolves; pads default to GPIO_ACTIVE_HIGH")
95
+ lines.append(" * -- override per pad in your app for a different polarity. GPIO only:")
96
+ lines.append(" * add your own emulated nodes for non-GPIO peripherals (display, etc.).")
97
+ lines.append(" */")
98
+ lines.append("")
99
+ lines.append("#include <zephyr/dt-bindings/gpio/gpio.h>")
100
+ lines.append("")
101
+ lines.append("/ {")
102
+
103
+ # gpio-emul controllers -- one per 32-pad span.
104
+ for c in range(n_ctrl):
105
+ base = c * _GPIO_EMUL_MAX_PINS
106
+ count = min(_GPIO_EMUL_MAX_PINS, n - base)
107
+ lines.append(f" gpio_emul{c}: gpio_emul{c} {{")
108
+ lines.append(' compatible = "zephyr,gpio-emul";')
109
+ lines.append(' status = "okay";')
110
+ lines.append(" gpio-controller;")
111
+ lines.append(" rising-edge;")
112
+ lines.append(" falling-edge;")
113
+ lines.append(" #gpio-cells = <2>;")
114
+ lines.append(f" ngpios = <{count}>;")
115
+ lines.append(" };")
116
+ lines.append("")
117
+
118
+ # alp,pin-array -- the full positional map spanning the controllers.
119
+ lines.append(" alp_pins: alp-pins {")
120
+ lines.append(' compatible = "alp,pin-array";')
121
+ lines.append(f" /* {n} entries in {form_factor} canonical order ({pinout_header}). Indices:")
122
+ for line in index_summary:
123
+ lines.append(line)
124
+ lines.append(" gpios =")
125
+ for i, suffix in enumerate(canonical):
126
+ ctrl = i // _GPIO_EMUL_MAX_PINS
127
+ local = i % _GPIO_EMUL_MAX_PINS
128
+ terminator = ";" if i == n - 1 else ","
129
+ lines.append(
130
+ f" <&gpio_emul{ctrl} {local:2d} GPIO_ACTIVE_HIGH>{terminator}"
131
+ f" /* [{i:2d}] {gpio_macro_prefix}_{suffix} */"
132
+ )
133
+ lines.append(" };")
134
+ lines.append("};")
135
+
136
+ return "\n".join(lines) + "\n"
@@ -0,0 +1,213 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """west.yml fragment emission (`--emit west-libraries`).
3
+
4
+ RELOCATED (was alp-sdk `scripts/alp_project_emit/west_libs.py`) -- see this
5
+ package's `__init__.py` for the move's contract.
6
+
7
+ Only the west.yml half came across. That file's other half --
8
+ `_emit_library_hw_backends` + `_SOC_FAMILY_TOKEN`, the per-library
9
+ HW-accelerator Kconfig matcher -- is NOT reached by `--emit west-libraries` at
10
+ all (`_slice_alp_conf` calls it, and that is the `zephyr-conf` path), and it
11
+ already relocated with the rest of the Kconfig emitter into
12
+ `tan/planner/libraries.py`. A second copy here would be a second source of truth
13
+ for which accelerator a SKU gets. `_library_alias_table` is imported for the
14
+ same reason -- from `tan/planner/loader.py`, its one definition since
15
+ tan-cli#868 (`libraries.py` carried a twin of it until then, and the two had
16
+ already drifted by a docstring clause).
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from pathlib import Path
22
+ from typing import Any
23
+
24
+ import yaml
25
+
26
+ from ..loader import _library_alias_table
27
+
28
+ # ---------------------------------------------------------------------
29
+ # west.yml fragment emission (libraries -> Zephyr-module name-allowlist)
30
+ # ---------------------------------------------------------------------
31
+ #
32
+ # Closes the second v0.4 gap docs/board-config.md flagged: customers
33
+ # whose board.yaml declares `libraries: [lvgl, mbedtls]` should not
34
+ # also have to hand-add those modules to their app's west.yml
35
+ # `name-allowlist:`. The emitter produces a paste-ready fragment
36
+ # they import via a self-referencing `import:` block.
37
+
38
+
39
+ # Canonical library name -> Zephyr module name the workspace's west.yml must
40
+ # import. Keyed by the CANONICAL manifest name (metadata/libraries/<name>.yaml)
41
+ # because the v2 `libraries:` resolution feeds canonical names here; the
42
+ # conservative allowlist stays four upstream Zephyr modules (the vendored /
43
+ # header-only libraries deliberately do NOT get a west entry -- `west update`
44
+ # would reject a name it can't resolve). Mirrors zephyr/modules.git; LittleFS
45
+ # ships as `fs/littlefs` while the rest match their names 1:1.
46
+ _LIBRARY_WEST_MODULES: dict[str, str] = {
47
+ "lvgl": "lvgl",
48
+ "mbedtls": "mbedtls",
49
+ "cmsis-dsp": "cmsis-dsp",
50
+ "littlefs": "fs/littlefs",
51
+ # The four header-only C++ libraries (etl / fmt / nlohmann_json /
52
+ # doctest) are not Zephyr modules today -- they land in v0.4 via
53
+ # the per-library profile + include-path hook in the loader, not
54
+ # via west.yml. Listing them here would emit an entry that
55
+ # `west update` rejects.
56
+ }
57
+
58
+
59
+ # OTA provider -> Zephyr module name the workspace's west.yml must
60
+ # import. Hawkbit and MCUmgr ship in Zephyr upstream so no entry --
61
+ # only out-of-tree clients need a west.yml line. See ADR 0009.
62
+ _OTA_PROVIDER_WEST_MODULES: dict[str, str] = {
63
+ "mender": "mender-mcu-client",
64
+ # hawkbit -- in Zephyr upstream
65
+ # mcumgr -- in Zephyr upstream
66
+ }
67
+
68
+
69
+ def _load_curated_library_manifest(
70
+ lib: str, metadata_root: Path) -> dict[str, Any] | None:
71
+ """Load a top-level ADR 0018 library manifest if one exists.
72
+
73
+ `metadata_root` is required, not defaulted -- see `_library_alias_table`
74
+ (alp-sdk#1485).
75
+ """
76
+ path = metadata_root / "libraries" / f"{lib}.yaml"
77
+ if not path.is_file():
78
+ return None
79
+ doc = yaml.safe_load(path.read_text(encoding="utf-8"))
80
+ return doc if isinstance(doc, dict) else None
81
+
82
+
83
+ def _emit_west_libraries(
84
+ project: dict[str, Any],
85
+ sku_preset: dict[str, Any],
86
+ board_preset: dict[str, Any] | None,
87
+ *,
88
+ v2_libraries: list[str] | None = None,
89
+ v2_project_libraries: list[str] | None = None,
90
+ metadata_root: Path,
91
+ ) -> str:
92
+ """Emit a west.yml fragment that the customer's manifest can
93
+ import to pin the Zephyr modules board.yaml's `libraries:` array
94
+ requires. Idempotent: emitting an empty `libraries:` array gives
95
+ an empty (but well-formed) name-allowlist.
96
+
97
+ v1 path (`v2_libraries is None`): reads project-level `libraries:`.
98
+ v2 path: callers compute the union across the Zephyr-runtime cores
99
+ (or pick one when `--core <id>` is supplied) and pass it in via
100
+ `v2_libraries`. `v2_project_libraries` carries the top-level ADR 0018
101
+ curated library manifests; these may either import a Zephyr-owned module
102
+ by name or emit a standalone west project pin from the manifest's
103
+ `integration.zephyr.west` block.
104
+
105
+ `metadata_root` is required, not defaulted -- pass the project's
106
+ `effective_metadata_root()` so the alias table and every curated library
107
+ manifest read below resolve against the SAME tree
108
+ `load_board_yaml(..., metadata_root=...)` validated the project against,
109
+ instead of an omitted argument silently falling back to the bound SDK's
110
+ own in-tree `metadata/` (alp-sdk#1485).
111
+ """
112
+ del sku_preset, board_preset # unused -- libraries are SoM-agnostic
113
+ if v2_libraries is not None:
114
+ libs = list(v2_libraries)
115
+ else:
116
+ libs = project.get("libraries") or []
117
+ project_libs = list(v2_project_libraries
118
+ if v2_project_libraries is not None
119
+ else [])
120
+ modules: list[tuple[str, str]] = [] # (library, Zephyr-owned west module)
121
+ west_projects: list[tuple[str, dict[str, Any]]] = []
122
+ unsupported: list[str] = []
123
+ seen_modules: set[str] = set()
124
+ seen_projects: set[str] = set()
125
+
126
+ def add_module(lib: str, mod: str) -> None:
127
+ if mod not in seen_modules:
128
+ modules.append((lib, mod))
129
+ seen_modules.add(mod)
130
+
131
+ def add_west_project(lib: str, west: dict[str, Any]) -> None:
132
+ name = str(west.get("name") or "")
133
+ if name and name not in seen_projects:
134
+ west_projects.append((lib, west))
135
+ seen_projects.add(name)
136
+
137
+ # Normalise legacy per-core tokens (schemaVersion 1) to their canonical
138
+ # manifest name so the west-module lookup resolves regardless of which
139
+ # spelling the caller passed (v2 resolution already yields canonical).
140
+ alias = _library_alias_table(metadata_root)
141
+ for lib in libs:
142
+ mod = _LIBRARY_WEST_MODULES.get(alias.get(lib, lib))
143
+ if mod is None:
144
+ unsupported.append(lib)
145
+ else:
146
+ add_module(lib, mod)
147
+
148
+ for lib in project_libs:
149
+ manifest = _load_curated_library_manifest(lib, metadata_root)
150
+ zephyr = ((manifest or {}).get("integration") or {}).get("zephyr") or {}
151
+ if not zephyr:
152
+ continue
153
+ west = zephyr.get("west")
154
+ if isinstance(west, dict):
155
+ add_west_project(lib, west)
156
+ continue
157
+ mod = zephyr.get("module")
158
+ if isinstance(mod, str) and mod:
159
+ add_module(lib, mod)
160
+ else:
161
+ unsupported.append(lib)
162
+
163
+ # OTA provider-driven dispatch (ADR 0009 follow-up): out-of-tree
164
+ # Zephyr OTA clients need their own west.yml entry. Mender-MCU-client
165
+ # is the only one today; hawkbit and mcumgr ship in Zephyr upstream.
166
+ ota = project.get("ota") or {}
167
+ if isinstance(ota, dict):
168
+ ota_provider = (ota.get("provider") or "").lower()
169
+ ota_mod = _OTA_PROVIDER_WEST_MODULES.get(ota_provider)
170
+ if ota_mod is not None:
171
+ modules.append((f"ota:{ota_provider}", ota_mod))
172
+
173
+ lines: list[str] = []
174
+ lines.append("# SPDX-License-Identifier: Apache-2.0")
175
+ lines.append("#")
176
+ lines.append("# Auto-generated by scripts/alp_project.py -- "
177
+ "do not edit by hand.")
178
+ lines.append("# Regenerate after changes to board.yaml's `libraries:` array.")
179
+ lines.append("#")
180
+ lines.append("# Import into your application's west.yml so `west update`")
181
+ lines.append("# pulls only the Zephyr modules the libraries you enabled")
182
+ lines.append("# actually need. Drop alongside your west.yml and reference")
183
+ lines.append("# from the `import:` field of the alp-sdk project entry.")
184
+ lines.append("")
185
+ lines.append("manifest:")
186
+ lines.append(" projects:")
187
+ lines.append(" - name: zephyr")
188
+ lines.append(" import:")
189
+ lines.append(" name-allowlist:")
190
+ if modules:
191
+ for lib, mod in modules:
192
+ lines.append(f" - {mod} # board.yaml libraries: '{lib}'")
193
+ else:
194
+ lines.append(" # no selected Zephyr-owned modules -- nothing to allowlist.")
195
+ lines.append(" []")
196
+
197
+ if west_projects:
198
+ lines.append("")
199
+ lines.append(" # ADR 0018 libraries not imported by Zephyr's own west.yml.")
200
+ for lib, west in west_projects:
201
+ lines.append(f" - name: {west['name']}")
202
+ lines.append(f" url: {west['url']}")
203
+ lines.append(f" revision: {west['revision']}")
204
+ lines.append(f" path: {west['path']} # board.yaml libraries: '{lib}'")
205
+
206
+ if unsupported:
207
+ lines.append("")
208
+ lines.append("# The following libraries have no Zephyr west project entry today")
209
+ lines.append("# (header-only/profile libraries ride the loader's include path;")
210
+ lines.append("# Yocto-only or in-tree Zephyr subsystems do not need a project pin):")
211
+ for lib in unsupported:
212
+ lines.append(f"# - {lib}")
213
+ return "\n".join(lines) + "\n"