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,373 @@
1
+ /*
2
+ * Copyright 2026 Alp Lab AB
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ *
5
+ * cold-chain-monitor
6
+ * ==================
7
+ *
8
+ * Pharma/food cold-chain integrity monitor. Pipeline:
9
+ *
10
+ * BME280 (I2C) --read_raw + compensate--> T(C) / RH(%) / P(Pa)
11
+ * --sliding window--> cold_chain (mean/min/max, MKT, dewpoint, excursion)
12
+ * -> cc_classify (OK / TEMP_EXCURSION / MKT_EXCEEDED / CONDENSATION_RISK)
13
+ * + <alp/inference.h> anomaly score (deterministic fallback)
14
+ * --> one CC record per report window.
15
+ *
16
+ * Honest scope: a reference cold-chain logger. MKT, dewpoint, and excursion
17
+ * time are the real metrics; thresholds are configurable per product. This is
18
+ * NOT a certified GxP / 21-CFR-Part-11 data logger (no validated audit trail,
19
+ * no calibration traceability, no tamper-proof storage). The model is a stub
20
+ * (see https://github.com/alplabai/alp-sdk/blob/v0.17.0/examples/ai/cold-chain-monitor/models/README.md); with no model the
21
+ * deterministic classifier + anomaly fallback run.
22
+ *
23
+ *
24
+ * ── Why the BME280 ────────────────────────────────────────────────────────
25
+ *
26
+ * The Bosch BME280 is a combined temperature / humidity / barometric pressure
27
+ * sensor well suited to cold-chain loggers:
28
+ * - Temperature range -40..+85 C, accuracy ±1.0 C RMS, sufficient for
29
+ * the ±0.5 C inter-unit spread allowed by GxP-adjacent monitoring.
30
+ * - Humidity ±3% RH at 25 C enables dewpoint estimation (condensation /
31
+ * mould risk on packaging and metal surfaces).
32
+ * - Pressure is logged but not classified by this demo; it's useful for
33
+ * altitude compensation and for detecting seal-break events in insulated
34
+ * shippers where a damaged seal opens to ambient.
35
+ * - I2C single-chip integration keeps the BOM to a minimum; SPI arrives
36
+ * in the v0.3 driver.
37
+ * - Normal-mode continuous sampling at a user-selected standby interval
38
+ * eliminates the MCU-driven trigger polling needed in Forced mode.
39
+ *
40
+ *
41
+ * ── Measurement cadence and window sizing ─────────────────────────────────
42
+ *
43
+ * CC_WINDOW_N (256 samples) * CC_SAMPLE_MIN (1.0 min/sample) = 256 minutes
44
+ * = ~4.3 hours per report window. That matches a common GDP-compliant
45
+ * logging interval (log every 5..15 min over a 24 h transit) while keeping
46
+ * the window SRAM footprint under 4 kB (256 × 12 B = 3072 B).
47
+ *
48
+ * In this demo the "1 minute" cadence is simulated: all 256 synthetic samples
49
+ * are pushed immediately so the pipeline exercises the framing path without
50
+ * sleeping. On real hardware a k_timer drives one bme280_read_raw() call per
51
+ * real minute (or whatever the product's logging period is).
52
+ *
53
+ *
54
+ * ── Cold-chain standards ──────────────────────────────────────────────────
55
+ *
56
+ * MKT (Mean Kinetic Temperature, ICH Q1A / USP <1079>):
57
+ * The single equivalent temperature that delivers the same cumulative
58
+ * Arrhenius thermal stress as the fluctuating temperature profile.
59
+ * A brief hot excursion contributes more than an equal-duration cool dip,
60
+ * so MKT >= arithmetic mean. The regulatory limit for most vaccines is
61
+ * MKT <= 8 C (the same as the storage upper bound), so a distribution that
62
+ * averaged 6 C but had a 12 C spike for 30 min would still breach.
63
+ * ΔH/R = 10 000 K is the ICH default (ΔH = 83.144 kJ/mol for pharma).
64
+ *
65
+ * Dewpoint (Magnus formula):
66
+ * When ambient temperature approaches the dewpoint, water condenses on
67
+ * cold surfaces -- packaging labels detach, metal contacts corrode,
68
+ * biological samples degrade. The dewpoint_margin_c config knob controls
69
+ * how close the reading must be to the dewpoint before CONDENSATION_RISK
70
+ * is raised.
71
+ *
72
+ *
73
+ * ── Classifier priority ordering ──────────────────────────────────────────
74
+ *
75
+ * The 4-state classifier (implemented in cold_chain.c) reports the HIGHEST
76
+ * severity condition present:
77
+ * CC_TEMP_EXCURSION -- product is currently out of the safe band, or
78
+ * the cumulative out-of-band time exceeds the limit.
79
+ * ACUTE: operator must act immediately.
80
+ * CC_MKT_EXCEEDED -- the equivalent thermal stress has crossed the
81
+ * regulatory limit even if the product is currently
82
+ * in-band. CUMULATIVE: product may be degraded.
83
+ * CC_CONDENSATION_RISK -- high humidity or temperature near the dewpoint;
84
+ * packaging and surface integrity may be compromised.
85
+ * CC_OK -- all metrics within limits.
86
+ *
87
+ *
88
+ * ── AI anomaly score ──────────────────────────────────────────────────────
89
+ *
90
+ * The threshold-based classifier catches known bad states. The AI score
91
+ * catches SUBTLE DRIFT that no single threshold catches: a slowly degrading
92
+ * compressor that nudges the mean temperature up by 0.3 C per week, or a
93
+ * door-seal micro-leak that correlates the humidity rise with the warming
94
+ * slope. The fallback (cc_anomaly_fallback) implements the same idea
95
+ * deterministically: it returns max(excursion depth, MKT overshoot),
96
+ * saturating at 1.0. A trained autoencoder running via <alp/inference.h>
97
+ * replaces this with a learned reconstruction error.
98
+ *
99
+ *
100
+ * ── native_sim / no-sensor fallback ──────────────────────────────────────
101
+ *
102
+ * On native_sim the I2C emul controller answers open() / ioctl() but has no
103
+ * BME280 target attached, so bme280_init() fails the CHIP_ID check. main()
104
+ * detects this and fills every window with synthetic environment data via
105
+ * synth_sample(), covering the three interesting states:
106
+ * window 0: stable in-band cold -> CC_OK
107
+ * window 1: warming ramp -> CC_TEMP_EXCURSION
108
+ * window 2: near-saturated air -> CC_CONDENSATION_RISK
109
+ * On real silicon fill the window from bme280_read_raw() instead.
110
+ */
111
+ #include <string.h>
112
+ #include <zephyr/kernel.h>
113
+ #include <zephyr/logging/log.h>
114
+
115
+ /* Board-portable alias for the sensor I2C bus: BOARD_I2C_SENSORS resolves to
116
+ * the correct on-board I2C controller for whatever EVK is targeted via the
117
+ * CONFIG_COMPILER_OPT="-DALP_BOARD_E1M_EVK" build flag. */
118
+ #include "alp/board.h"
119
+ /* AI inference dispatch: AUTO routes to Ethos-U55 on AEN, DEEPX DX-M1 on V2N,
120
+ * and the reference TFLM CPU kernels on native_sim. */
121
+ #include "alp/inference.h"
122
+ /* Portable I2C open/close/read/write primitives (no vendor names). */
123
+ #include "alp/peripheral.h"
124
+ /* BME280 combined T/RH/P chip driver (I2C v0.2, paper-correct). */
125
+ #include "alp/chips/bme280.h"
126
+
127
+ /* Pure-C cold-chain metrics, classifier, and anomaly fallback (arch-neutral,
128
+ * no Zephyr deps -- identical source compiles for native_sim and the M55). */
129
+ #include "cold_chain.h"
130
+
131
+ LOG_MODULE_REGISTER(cc, LOG_LEVEL_INF);
132
+
133
+ /* BME280 I2C address: SDO-tied-low = 0x76 on the EVK (0x77 if SDO is high).
134
+ * Override at compile time if your carrier boards SDO differently. */
135
+ #define BME280_ADDR 0x76u
136
+ /* Number of report windows in the bounded demo run (3 covers OK / EXCURSION /
137
+ * CONDENSATION in the synthetic scenario; a real logger runs indefinitely). */
138
+ #define N_REPORTS 3
139
+
140
+ /* Vaccine-fridge thresholds (2..8 C, USP <1079> Annex 1 cold chain).
141
+ * A real deployment loads the limits for the specific product (frozen at
142
+ * -20 C, ambient-stable at +25 C, etc.) from NVS or a compile-time overlay. */
143
+ static const struct cc_config CFG = {
144
+ .t_lo = 2.0f, /* safe-band lower edge, Celsius */
145
+ .t_hi = 8.0f, /* safe-band upper edge, Celsius */
146
+ .mkt_limit_c = 8.0f, /* MKT above this -> cumulative damage */
147
+ .excursion_min_limit = 30.0f, /* out-of-band minutes before EXCURSION */
148
+ .dewpoint_margin_c = 2.0f, /* T within this of dewpoint -> CONDENSATION */
149
+ };
150
+
151
+ /* 1-byte stub so alp_inference_open's non-NULL model-data contract is met.
152
+ * An unusable tensor (wrong shape from the stub backend) causes every
153
+ * alp_inference_invoke() to return no usable output, which anomaly_score()
154
+ * detects and routes to cc_anomaly_fallback(). See
155
+ * https://github.com/alplabai/alp-sdk/blob/v0.17.0/examples/ai/cold-chain-monitor/models/README.md for the autoencoder
156
+ * training recipe to replace this stub. */
157
+ static const uint8_t s_model[] = { 0x00 };
158
+
159
+ /*
160
+ * synth_sample() -- synthetic environment data for native_sim / no sensor.
161
+ *
162
+ * Generates a deterministic (T, RH, P) triple for sample @p i of report
163
+ * window @p report. Three scenarios are exercised across the N_REPORTS
164
+ * windows so the classifier produces a meaningful state spread:
165
+ *
166
+ * report 0: steady in-band cold storage (5 C, 50 % RH) -> CC_OK
167
+ * report 1: warming ramp (5..12 C linear) -> CC_TEMP_EXCURSION
168
+ * report 2: cold but near-saturated air (5 C, 95 % RH) -> CC_CONDENSATION_RISK
169
+ *
170
+ * Pressure is fixed at 101325 Pa (sea-level standard) for all windows;
171
+ * it does not affect classification in this demo.
172
+ */
173
+ static struct cc_sample synth_sample(int report, int i)
174
+ {
175
+ /* Baseline: stable cold storage in the 2..8 C vaccine fridge band. */
176
+ struct cc_sample s = { .temp_c = 5.0f, .rh_pct = 50.0f, .pressure_pa = 101325.0f };
177
+ switch (report) {
178
+ case 0:
179
+ break; /* stable cold -- all defaults are fine */
180
+ case 1:
181
+ /* Linear warming ramp from 5 C to 12 C across the window.
182
+ * This drives the mean above t_hi and the excursion counter
183
+ * past the limit, triggering CC_TEMP_EXCURSION. */
184
+ s.temp_c = 5.0f + 7.0f * (float)i / (float)(CC_WINDOW_N - 1);
185
+ s.rh_pct = 55.0f;
186
+ break;
187
+ default:
188
+ /* Near-saturated cold air: temperature stays in-band but RH
189
+ * is high enough that the Magnus dewpoint is within
190
+ * dewpoint_margin_c of the ambient temperature, raising
191
+ * CC_CONDENSATION_RISK. */
192
+ s.rh_pct = 95.0f;
193
+ break;
194
+ }
195
+ return s;
196
+ }
197
+
198
+ /*
199
+ * anomaly_score() -- AI model if available, else the deterministic fallback.
200
+ *
201
+ * Packs the cc_features vector, invokes the loaded model, and reads the
202
+ * first float output as a 0..1 anomaly score. Falls back to
203
+ * cc_anomaly_fallback() when:
204
+ * - @p inf is NULL (inference handle failed to open),
205
+ * - the stub model returns an empty / wrongly-typed output tensor, or
206
+ * - alp_inference_invoke() returns a non-OK status.
207
+ * This "try model, fall back cleanly" pattern matches the sibling examples
208
+ * and means the demo always produces a meaningful score offline.
209
+ */
210
+ static float anomaly_score(alp_inference_t *inf, const struct cc_features *f)
211
+ {
212
+ if (inf != NULL) {
213
+ /* Pack the 8 metrics into the flat float vector the model expects. */
214
+ float vec[CC_FEATURE_DIM];
215
+ (void)cc_feat_pack(f, vec, CC_FEATURE_DIM);
216
+ alp_inference_tensor_t in = { 0 };
217
+ /* Copy into the model's input tensor only if the shape matches. */
218
+ if (alp_inference_get_input(inf, 0, &in) == ALP_OK && in.dtype == ALP_INFERENCE_DTYPE_F32 &&
219
+ in.data != NULL && in.size_bytes >= sizeof(vec)) {
220
+ memcpy(in.data, vec, sizeof(vec));
221
+ if (alp_inference_invoke(inf) == ALP_OK) {
222
+ alp_inference_tensor_t out = { 0 };
223
+ /* Read the scalar anomaly score from the output tensor. */
224
+ if (alp_inference_get_output(inf, 0, &out) == ALP_OK &&
225
+ out.dtype == ALP_INFERENCE_DTYPE_F32 && out.data != NULL &&
226
+ out.size_bytes >= sizeof(float)) {
227
+ return ((const float *)out.data)[0];
228
+ }
229
+ }
230
+ }
231
+ }
232
+ /* Deterministic fallback: max(excursion depth, MKT overshoot), clamped
233
+ * to 1.0. Transparent, always correct, gives the demo a meaningful
234
+ * score without any trained model. */
235
+ return cc_anomaly_fallback(f, &CFG);
236
+ }
237
+
238
+ int main(void)
239
+ {
240
+ /* Driver context and window state are static so they do not consume
241
+ * stack on the Zephyr M55 thread (the BME280 calib struct is 26 bytes;
242
+ * the window is 256 × 12 B = 3072 B). */
243
+ static bme280_t dev;
244
+ static struct cc_window_state win;
245
+ bool sensor_ok = false;
246
+
247
+ /* ── Sensor bring-up ─────────────────────────────────────────────────
248
+ * Open the shared sensor I2C bus (BOARD_I2C_SENSORS resolves to the
249
+ * correct on-board controller for the target EVK) and initialise the
250
+ * BME280. bme280_init() reads CHIP_ID and loads the per-die calibration
251
+ * coefficients; it returns ALP_ERR_IO if no BME280 responds.
252
+ * On native_sim the emul controller has no target attached, so init
253
+ * fails cleanly and we fall back to synth_sample(). */
254
+ alp_i2c_t *bus =
255
+ alp_i2c_open(&(alp_i2c_config_t){ .bus_id = BOARD_I2C_SENSORS, .bitrate_hz = 400000 });
256
+ if (bus != NULL && bme280_init(&dev, bus, BME280_ADDR) == ALP_OK) {
257
+ /* bme280_init() leaves the oversampling / mode registers untouched.
258
+ * Configure continuous-conversion (NORMAL) mode with X1 oversampling
259
+ * on all three channels (T, P, H), a 1 s standby period between
260
+ * measurements, and no IIR filter. bme280_read_raw() will then
261
+ * return a fresh reading without needing to poll the status register.
262
+ * For a cold-chain logger the 1 s cadence is already faster than the
263
+ * CC_SAMPLE_MIN (1 min) window rate, so X1/1 s is well matched. */
264
+ (void)bme280_set_sampling(&dev,
265
+ BME280_OVERSAMPLING_X1, /* temperature channel */
266
+ BME280_OVERSAMPLING_X1, /* pressure channel */
267
+ BME280_OVERSAMPLING_X1, /* humidity channel */
268
+ BME280_MODE_NORMAL, /* continuous conversion */
269
+ BME280_STANDBY_1000_MS, /* 1 s between measurements */
270
+ BME280_FILTER_OFF); /* no IIR smoothing */
271
+ sensor_ok = true;
272
+ } else {
273
+ LOG_WRN("BME280 unavailable; using synthetic environment data");
274
+ }
275
+
276
+ /* ── Inference bring-up ──────────────────────────────────────────────
277
+ * Open the inference handle. BACKEND_AUTO selects Ethos-U on AEN,
278
+ * DEEPX DX-M1 on V2N, or the TFLM CPU kernels on native_sim.
279
+ * The 1-byte stub model causes every invoke() to return an unusable
280
+ * output, so anomaly_score() falls back to the deterministic path. */
281
+ alp_inference_t *inf = alp_inference_open(&(alp_inference_config_t){
282
+ .backend = ALP_INFERENCE_BACKEND_AUTO,
283
+ .format = ALP_INFERENCE_MODEL_TFLITE,
284
+ .model_data = s_model,
285
+ .model_size = sizeof(s_model),
286
+ });
287
+
288
+ /* CSV header: one line per report window. Field order matches the
289
+ * documented output schema and the README example. */
290
+ printk("# CC,t_s,state,temp_c,rh_pct,dewpoint_c,mkt_c,excursion_min\n");
291
+
292
+ /* ── Report loop ─────────────────────────────────────────────────────
293
+ * Each iteration resets the window, fills it (real or synthetic), then
294
+ * reduces it to metrics and emits one CC record. N_REPORTS = 3 covers
295
+ * the OK / EXCURSION / CONDENSATION states in the synthetic scenario. */
296
+ for (int r = 0; r < N_REPORTS; r++) {
297
+ /* Reset the window for this report period. */
298
+ cc_window_reset(&win);
299
+
300
+ /* Fill one window of readings (real sensor or synthetic). */
301
+ for (int i = 0; i < CC_WINDOW_N; i++) {
302
+ struct cc_sample s;
303
+ if (sensor_ok) {
304
+ /* Real sensor path: burst-read the raw 20/20/16-bit
305
+ * conversion result, then compensate with the per-die
306
+ * calibration loaded at init. The BME280 is running
307
+ * continuously (NORMAL mode), so the result is fresh
308
+ * within the 1 s standby period. */
309
+ bme280_raw_t raw;
310
+ bme280_compensated_t c;
311
+ if (bme280_read_raw(&dev, &raw) == ALP_OK &&
312
+ bme280_compensate(&dev, &raw, &c) == ALP_OK) {
313
+ /* Convert from fixed-point to float physical units:
314
+ * temperature_c100 is degrees × 100 -> C
315
+ * humidity_milli_pct is %RH × 1024 -> %
316
+ * pressure_pa is already pascals. */
317
+ s.temp_c = (float)c.temperature_c100 / 100.0f;
318
+ s.rh_pct = (float)c.humidity_milli_pct / 1024.0f;
319
+ s.pressure_pa = (float)c.pressure_pa;
320
+ } else {
321
+ /* I/O error mid-window: fall back to synth for
322
+ * this sample so the window stays complete. */
323
+ s = synth_sample(r, i);
324
+ }
325
+ } else {
326
+ /* No sensor: generate deterministic synthetic data. */
327
+ s = synth_sample(r, i);
328
+ }
329
+ cc_window_push(&win, s);
330
+ }
331
+
332
+ /* Reduce the window to metrics, classify, score the anomaly, emit. */
333
+ struct cc_features f;
334
+ cc_feat_extract(&win, &CFG, &f);
335
+ cc_state_t st = cc_classify(&f, &CFG);
336
+ /* Compute the anomaly score (model or deterministic fallback).
337
+ * In a real gateway deployment `an` is forwarded via MQTT / OPC-UA
338
+ * alongside the classifier state; here we suppress the unused-var
339
+ * warning with (void) since this demo only emits the state string. */
340
+ float an = anomaly_score(inf, &f);
341
+ (void)an;
342
+
343
+ /* Emit one CSV record. t_s = elapsed monitoring time in minutes
344
+ * = samples-completed × CC_SAMPLE_MIN (1.0 min/sample). */
345
+ printk("CC,%.1f,%s,%.1f,%.1f,%.1f,%.1f,%.1f\n",
346
+ (double)((r + 1) * CC_WINDOW_N * CC_SAMPLE_MIN),
347
+ cc_state_name(st),
348
+ (double)f.mean_temp_c,
349
+ (double)f.mean_rh_pct,
350
+ (double)f.dewpoint_c,
351
+ (double)f.mkt_c,
352
+ (double)f.excursion_min);
353
+ }
354
+
355
+ /* ── Lifecycle teardown ──────────────────────────────────────────────
356
+ * Release in reverse acquisition order: model, sensor, bus.
357
+ * bme280_soft_reset() writes 0xB6 to the RESET register so the chip
358
+ * returns to its power-on state; the bus is then safe to release. */
359
+ if (inf != NULL) {
360
+ alp_inference_close(inf);
361
+ }
362
+ if (sensor_ok) {
363
+ /* Soft-reset the chip before releasing the bus so it stops
364
+ * converting and returns to sleep (lowest power state). */
365
+ bme280_soft_reset(&dev);
366
+ bme280_deinit(&dev); /* Release the driver context (no chip power-down). */
367
+ }
368
+ if (bus != NULL) {
369
+ alp_i2c_close(bus);
370
+ }
371
+ printk("[cc] done\n");
372
+ return 0;
373
+ }
@@ -0,0 +1,62 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ sample:
4
+ name: cold-chain-monitor
5
+ description: |
6
+ Cold-chain integrity monitor: BME280 T/RH/P -> sliding-window metrics
7
+ (MKT / dewpoint / excursion time) -> 4-state classifier (OK / TEMP_EXCURSION
8
+ / MKT_EXCEEDED / CONDENSATION_RISK) + AI anomaly score (deterministic
9
+ fallback). native_sim runs synthetic environment data covering the states.
10
+ common:
11
+ tags: ai inference industrial environmental cold-chain marketing showcase
12
+ tests:
13
+ alp_sdk.example.cold_chain_monitor.e1m_evk:
14
+ extra_args: EXTRA_CONF_FILE=generated/alp.conf
15
+ extra_configs:
16
+ - 'CONFIG_COMPILER_OPT="-DALP_BOARD_E1M_EVK"'
17
+ platform_allow:
18
+ - native_sim/native/64
19
+ integration_platforms:
20
+ - native_sim/native/64
21
+ tags:
22
+ - alp-sdk
23
+ - example
24
+ - ai
25
+ - environmental
26
+ harness: console
27
+ harness_config:
28
+ type: one_line
29
+ regex:
30
+ - "\\[cc\\] done"
31
+
32
+ alp_sdk.example.cold_chain_monitor.e1m_x_evk:
33
+ extra_args: EXTRA_CONF_FILE=generated/alp.conf
34
+ extra_configs:
35
+ - 'CONFIG_COMPILER_OPT="-DALP_BOARD_E1M_X_EVK"'
36
+ platform_allow:
37
+ - native_sim/native/64
38
+ integration_platforms:
39
+ - native_sim/native/64
40
+ tags:
41
+ - alp-sdk
42
+ - example
43
+ - ai
44
+ - environmental
45
+ harness: console
46
+ harness_config:
47
+ type: one_line
48
+ regex:
49
+ - "\\[cc\\] done"
50
+
51
+ alp_sdk.example.cold_chain_monitor.aen_build:
52
+ extra_args: EXTRA_CONF_FILE=generated/alp.conf
53
+ extra_configs:
54
+ - 'CONFIG_COMPILER_OPT="-DALP_BOARD_E1M_EVK"'
55
+ platform_allow:
56
+ - alp_e1m_aen801_m55_hp/ae822fa0e5597ls0/rtss_hp
57
+ build_only: true
58
+ tags:
59
+ - alp-sdk
60
+ - example
61
+ - ai
62
+ - environmental
@@ -0,0 +1,14 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ cmake_minimum_required(VERSION 3.20)
4
+
5
+ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6
+ project(mqtt_telemetry LANGUAGES C)
7
+
8
+ target_sources(app PRIVATE src/main.c)
9
+ # Reusable SoM bring-up helper (cc3501e_bridge_bringup): the one-call CC3501E
10
+ # bridge init this app uses so alp_wifi_open() can bind to a ready bridge on
11
+ # E1M-AEN801 (#2112). Copyable template, same file as examples/aen/aen-cc3501e-*
12
+ # -- see src/cc3501e_bridge.h. Built unconditionally; alp_gpio_open()/alp_spi_open()
13
+ # fail fast (NULL, no matching backend) on native_sim, so this is a no-op there.
14
+ target_sources(app PRIVATE src/cc3501e_bridge.c)
@@ -0,0 +1,103 @@
1
+ # mqtt-telemetry
2
+
3
+ The **connected device** starting point: bring up Wi-Fi, open an
4
+ `mqtts://` (TLS) MQTT client, and publish a telemetry reading on a
5
+ cadence -- the whole path on the portable [`<alp/iot.h>`](https://github.com/alplabai/alp-sdk/blob/v0.17.0/include/alp/iot.h)
6
+ surface.
7
+
8
+ ```
9
+ alp_wifi_open() -> alp_wifi_connect() # Wi-Fi station up
10
+ alp_mqtt_open(mqtts://... , CA pinned) # TLS MQTT client
11
+ alp_mqtt_connect() -> alp_mqtt_publish() x N # publish telemetry
12
+ alp_mqtt_close() # clean disconnect
13
+ ```
14
+
15
+ ## Supported hardware -- AEN only
16
+
17
+ This template ships for **E1M-AEN801 only**. Its transport is the
18
+ **CC3501E Wi-Fi6+BLE coprocessor bridge**
19
+ ([`docs/cc3501e-bridge.md`](https://github.com/alplabai/alp-sdk/blob/v0.17.0/docs/cc3501e-bridge.md)),
20
+ silicon-validated 2026-06-24. The app never names the bridge -- the
21
+ AEN board emit wires it as the `<alp/iot.h>` Wi-Fi backend from
22
+ `iot.wifi: true` in `board.yaml`.
23
+
24
+ The **E1M-V2N101 is deliberately not supported**: its Murata Wi-Fi
25
+ (`murata_lbee5hy2fy`) is `hil_silicon: untested` and its Linux-side
26
+ data path is an unmerged design, so there is no working Wi-Fi
27
+ transport for that family yet. Do not add it to a scaffold of this
28
+ template until that port lands.
29
+
30
+ ## TLS status -- preview
31
+
32
+ The `mqtts://` path is configured through the portable API (broker URI + a
33
+ pinned CA) and **mbedTLS is now built in on every target**, native_sim
34
+ included. It used to be held off: with mbedTLS' PSA core disabled the pinned
35
+ library's own `ssl_misc.h` does not compile (`unknown type name
36
+ 'mbedtls_error_pair_t'`), so the app turned mbedTLS off rather than fail. The
37
+ SDK now turns that PSA core on wherever it builds mbedTLS without TF-M
38
+ (`ALP_SDK_MBEDTLS_PSA_CRYPTO`, issue #2173), so this app carries no mbedTLS
39
+ knobs at all any more (see [`prj.conf`](https://github.com/alplabai/alp-sdk/blob/v0.17.0/examples/connectivity/mqtt-telemetry/prj.conf), which is
40
+ empty by design) and the `native_sim.conf` that used to hold the workaround is
41
+ deleted.
42
+
43
+ AEN hardware builds seed the PSA core from the Secure Enclave TRNG entropy
44
+ driver (`alif,se-trng`, bench-proven on both M55 cores, issue #2192), which
45
+ every AEN board chooses as `zephyr,entropy` by default, so the AEN Twister
46
+ scenario needs no weak-RNG opt-in. Only the native_sim scenario, which has no
47
+ real entropy source, still sets `CONFIG_ALP_SDK_ALLOW_TEST_ENTROPY=y`.
48
+
49
+ ## The "sensor reading"
50
+
51
+ To keep the focus on the transport, this template publishes a
52
+ **synthetic metric** (device uptime). Swap
53
+ `read_telemetry_value()` for a real sensor read -- e.g. compose it
54
+ with the [`sensor` template](https://github.com/alplabai/alp-sdk/tree/v0.17.0/examples/peripheral-io/i2c-master) (BMP581
55
+ over `<alp/chips/bmp581.h>`) -- and the publish path is unchanged.
56
+
57
+ ## Build
58
+
59
+ ```bash
60
+ # Standalone, native_sim (no radio, so the app prints the framing it
61
+ # would publish; mbedTLS is built in):
62
+ # writes ./generated/alp.conf, which west reads below (#866)
63
+ tan generate --target zephyr-conf --core m55_hp --sdk-root "$ALP_SDK_ROOT" --output generated/alp.conf
64
+ west build -b native_sim/native/64 . \
65
+ -- -DEXTRA_CONF_FILE=generated/alp.conf -DEXTRA_ZEPHYR_MODULES=$ALP_SDK_ROOT
66
+ west build -t run
67
+
68
+ # On real silicon (E1M-AEN801):
69
+ west build -b alp_e1m_aen801_m55_hp/ae822fa0e5597ls0/rtss_hp . -- -DEXTRA_CONF_FILE=generated/alp.conf
70
+ west flash
71
+ ```
72
+
73
+ ## Expected output
74
+
75
+ native_sim (no Wi-Fi/MQTT backend; framing only):
76
+
77
+ ```
78
+ [mqtt] alp-sdk mqtt-telemetry demo (publish over MQTT/TLS)
79
+ [mqtt] transport: CC3501E Wi-Fi bridge (E1M-AEN801)
80
+ [mqtt] wifi: opening station
81
+ [mqtt] wifi: alp_wifi_open -> NULL (ALP_ERR_NOT_READY)
82
+ [mqtt] no transport on this build -- printing framing only
83
+ [mqtt] would publish to alp/telemetry/e1m-aen801: {"device":"e1m-aen801-demo","metric":"uptime_s","value":0}
84
+ [mqtt] would publish to alp/telemetry/e1m-aen801: {"device":"e1m-aen801-demo","metric":"uptime_s","value":5}
85
+ [mqtt] would publish to alp/telemetry/e1m-aen801: {"device":"e1m-aen801-demo","metric":"uptime_s","value":10}
86
+ [mqtt] done
87
+ ```
88
+
89
+ Real hardware (E1M-AEN801, associated + broker reachable):
90
+
91
+ ```
92
+ [mqtt] wifi: associated to "alp-demo-ap"
93
+ [mqtt] broker: connected
94
+ [mqtt] publish 0 -> ALP_OK: {"device":"e1m-aen801-demo","metric":"uptime_s","value":0}
95
+ ...
96
+ [mqtt] done
97
+ ```
98
+
99
+ ## Reference
100
+
101
+ - [`<alp/iot.h>`](https://github.com/alplabai/alp-sdk/blob/v0.17.0/include/alp/iot.h) -- Wi-Fi station + MQTT client surface.
102
+ - [`docs/cc3501e-bridge.md`](https://github.com/alplabai/alp-sdk/blob/v0.17.0/docs/cc3501e-bridge.md) -- the AEN Wi-Fi transport.
103
+ - [`examples/peripheral-io/i2c-master/`](https://github.com/alplabai/alp-sdk/tree/v0.17.0/examples/peripheral-io/i2c-master) -- the `sensor` template, for a real reading to publish.
@@ -0,0 +1,69 @@
1
+ # board.yaml -- per-app project configuration for the
2
+ # mqtt-telemetry example (publish a sensor reading over MQTT/TLS).
3
+ #
4
+ # The "connected device" starting point: bring up the Wi-Fi
5
+ # station, open an `mqtts://` (TLS) MQTT client via the portable
6
+ # <alp/iot.h> surface, and publish a telemetry reading on a
7
+ # cadence. All app code stays on <alp/iot.h> -- the transport
8
+ # underneath is the CC3501E Wi-Fi6+BLE coprocessor bridge on the
9
+ # E1M-AEN801 (see https://github.com/alplabai/alp-sdk/blob/v0.17.0/docs/cc3501e-bridge.md), selected automatically
10
+ # by the AEN board emit; no app change is needed to target it.
11
+ #
12
+ # AEN-only by design: the E1M-V2N101's Murata Wi-Fi
13
+ # (murata_lbee5hy2fy) is `hil_silicon: untested` and its Linux-side
14
+ # data path is an unmerged design, so there is no working Wi-Fi
15
+ # transport for that family yet. Shipping this template for the one
16
+ # family whose transport is silicon-proven (AEN, validated
17
+ # 2026-06-24) is deliberate -- see the catalog record's `preview`
18
+ # note. Do not add E1M-V2N101 to a scaffold of this template until
19
+ # that port lands.
20
+ #
21
+ # Customer workflow: `tan init --from-example connectivity/mqtt-telemetry`,
22
+ # set your SSID/PSK + broker URI in src/main.c (or wire them from
23
+ # provisioning), and `tan build` for the AEN board target.
24
+ libraries:
25
+ # mbedtls backs the `mqtts://` TLS path. The v0.6 board.yaml
26
+ # cross-field validator requires `mbedtls` (or `bearssl`) in
27
+ # `libraries:` whenever any core sets `iot.tls: true`.
28
+ - name: mbedtls
29
+ cores: [m55_hp]
30
+
31
+ som:
32
+ sku: E1M-AEN801 # Alif Ensemble E8 + on-module CC3501E
33
+ # Wi-Fi6+BLE bridge (the transport).
34
+
35
+ preset: e1m-evk
36
+
37
+ cores:
38
+ m55_hp:
39
+ app: ./src
40
+ # IoT toggles. wifi:true wires the CC3501E bridge as the
41
+ # <alp/iot.h> Wi-Fi backend on this AEN board; tls:true selects
42
+ # the mqtts:// (TLS) MQTT path. CONFIG_MBEDTLS is no longer held
43
+ # off: the ssl_misc.h break that forced that is fixed at its root
44
+ # (ALP_SDK_MBEDTLS_PSA_CRYPTO, #2173), so every target builds the
45
+ # TLS-enabled configuration. The remaining limit is the RNG, not
46
+ # the library -- see the README's TLS status section and #2192.
47
+ iot:
48
+ wifi: true
49
+ tls: true
50
+ # Portable peripheral subsystems this app opens to bring the CC3501E
51
+ # bridge up (cc3501e_bridge_bringup(), #2112): SPI1 (inter-chip link)
52
+ # + the WIFI_EN/nRESET LP-GPIO control pins. Same as the
53
+ # https://github.com/alplabai/alp-sdk/tree/v0.17.0/examples/aen/aen-cc3501e-* board.yaml. The loader translates these
54
+ # to CONFIG_SPI=y / CONFIG_GPIO=y in alp.conf.
55
+ peripherals:
56
+ - spi
57
+ - gpio
58
+
59
+ # The bridge helper this app now carries (src/cc3501e_bridge.h, #2112)
60
+ # includes <alp/chips/cc3501e.h> directly, so the chip has to be declared
61
+ # here for check_example_portability.py's family-compatibility check and
62
+ # the portability ring to account for it -- same as
63
+ # https://github.com/alplabai/alp-sdk/blob/v0.17.0/examples/aen/aen-cc3501e-bringup/board.yaml. Wi-Fi itself still reaches
64
+ # the app through the portable <alp/iot.h> surface, not this entry.
65
+ chips:
66
+ - cc3501e
67
+
68
+ diagnostics:
69
+ log_level: info
@@ -0,0 +1,15 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Empty-by-design Kconfig. The effective build config is the
4
+ # overlay alp.conf emitted from board.yaml by `tan build`
5
+ # at build time (see README.md: `tan generate --target zephyr-conf`) -- it turns the
6
+ # `iot: {wifi, tls}` toggles + `libraries: [mbedtls]` into the
7
+ # CONFIG_* the app needs (Wi-Fi, the MQTT client, mbedtls).
8
+ #
9
+ # mbedtls used to be forced OFF here and in a native_sim.conf, because
10
+ # the pinned mbedtls' ssl_misc.h uses `mbedtls_error_pair_t` with PSA
11
+ # crypto off and does not compile. That is fixed at its root -- the SDK
12
+ # now turns mbedtls' PSA core on with mbedtls itself, see
13
+ # ALP_SDK_MBEDTLS_PSA_CRYPTO in zephyr/Kconfig.alp-libraries (#2173) --
14
+ # so every target, native_sim included, builds the same TLS-enabled
15
+ # configuration the SoM does.