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
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
* Copyright 2026 Alp Lab AB
|
|
4
|
+
*
|
|
5
|
+
* E1M-AEN SoM CC3501E bridge bring-up helper -- see cc3501e_bridge.h.
|
|
6
|
+
*
|
|
7
|
+
* The final reset is warm-aware. cc3501e_reset() drops WIFI_EN for 50 ms, a
|
|
8
|
+
* supply cold cycle; on a CC3501E that is already running (an activated unit with
|
|
9
|
+
* vendor_sbl_container_enable=1 may then never relaunch) that must not happen on a
|
|
10
|
+
* mere re-run or warm reset of the application. So when WIFI_EN already reads high
|
|
11
|
+
* AND the chip answers a PING the bring-up resets through nRESET only
|
|
12
|
+
* (cc3501e_hard_reset()), and uses cc3501e_reset() only from WIFI_EN low or, as a
|
|
13
|
+
* last resort, from a chip that stays silent through an nRESET-only reset. WIFI_EN
|
|
14
|
+
* reading high alone is not trusted: a pull-up would make every power-on look warm
|
|
15
|
+
* (whether the module has one is an open question, issue #2797).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include "cc3501e_bridge.h"
|
|
19
|
+
|
|
20
|
+
#include <stdio.h>
|
|
21
|
+
|
|
22
|
+
#if defined(CONFIG_SOC_AE822FA0E5597LS0_RTSS_HE) || defined(CONFIG_SOC_AE822FA0E5597LS0_RTSS_HP)
|
|
23
|
+
#include <zephyr/arch/cpu.h>
|
|
24
|
+
#include <zephyr/devicetree.h>
|
|
25
|
+
#include <zephyr/sys/sys_io.h>
|
|
26
|
+
/*
|
|
27
|
+
* AEN LP-pad mux (Alif Ensemble E8, both M55-HE and M55-HP cores). WIFI_EN
|
|
28
|
+
* (P15_5) and nRESET (P15_1) are on the Alif LP-GPIO island, bound by the
|
|
29
|
+
* generic snps,designware-gpio driver which does NOT apply Alif pinctrl --
|
|
30
|
+
* so the LP pads stay un-muxed and their output drivers OFF (confirmed on
|
|
31
|
+
* silicon on M55-HE: WIFI_EN never powers the CC3501E until these regs are
|
|
32
|
+
* set). 0x23 = the Alif GPIO-output pad config (driver + read-enable +
|
|
33
|
+
* drive strength). TODO: drop this raw poke once the Alif GPIO backend
|
|
34
|
+
* muxes the LP island via pinctrl.
|
|
35
|
+
*
|
|
36
|
+
* ALIF_LPGPIO_PADCTRL_BASE (0x42007000) is not an M55-HE-local address: the
|
|
37
|
+
* shared upstream `pin-controller@1a603000` node (ensemble_common.dtsi,
|
|
38
|
+
* included by both cores' SoC dtsi) declares this exact window as its
|
|
39
|
+
* second `reg` range, and `alp_e1m_aen801_m55_hp-pinctrl.dtsi` already
|
|
40
|
+
* muxes a different LP-GPIO pad (P15_0, RTC_ALARM) from the M55-HP pinctrl
|
|
41
|
+
* driver through it, so the poke below is equally applicable on M55-HP.
|
|
42
|
+
* Running it on M55-HP is NOT bench-proven -- only running it on M55-HE has
|
|
43
|
+
* been confirmed on silicon.
|
|
44
|
+
*/
|
|
45
|
+
#define ALIF_LPGPIO_PADCTRL_BASE 0x42007000u
|
|
46
|
+
#define ALIF_PAD_GPIO_OUTPUT 0x23u
|
|
47
|
+
/* Latch WIFI_EN (P15_5) HIGH in the port's data register while the pad is still an
|
|
48
|
+
* INPUT. Switching the direction afterwards then drives the already-high level; the
|
|
49
|
+
* other order (direction first, value second -- what gpio_dw's configure does even
|
|
50
|
+
* with an init flag) drives whatever DR holds, and with DR bit 5 = 0 that glitches
|
|
51
|
+
* the supply of a running chip low. DR is written directly (read-modify-write, the
|
|
52
|
+
* same access gpio_dw's port_set_bits_raw makes) so this template stays on the
|
|
53
|
+
* portable <alp/...> headers: SWPORTA_DR is offset 0x00 of the DesignWare GPIO block
|
|
54
|
+
* (zephyr drivers/gpio/gpio_dw_registers.h), the block base is the `lpgpio` node's
|
|
55
|
+
* reg, and the LP-GPIO clock is already on because alp_gpio_open() opened the pin. */
|
|
56
|
+
#define DW_GPIO_SWPORTA_DR 0x00u
|
|
57
|
+
static void aen_wifi_en_latch_high(void)
|
|
58
|
+
{
|
|
59
|
+
const mem_addr_t dr = DT_REG_ADDR(DT_NODELABEL(lpgpio)) + DW_GPIO_SWPORTA_DR;
|
|
60
|
+
|
|
61
|
+
sys_write32(sys_read32(dr) | (1u << 5), dr);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static void aen_lp_pads_enable_output(void)
|
|
65
|
+
{
|
|
66
|
+
sys_write32(ALIF_PAD_GPIO_OUTPUT, ALIF_LPGPIO_PADCTRL_BASE + 5u * 4u); /* P15_5 WIFI_EN */
|
|
67
|
+
sys_write32(ALIF_PAD_GPIO_OUTPUT, ALIF_LPGPIO_PADCTRL_BASE + 1u * 4u); /* P15_1 nRESET */
|
|
68
|
+
}
|
|
69
|
+
#else
|
|
70
|
+
static inline void aen_lp_pads_enable_output(void)
|
|
71
|
+
{
|
|
72
|
+
}
|
|
73
|
+
static inline void aen_wifi_en_latch_high(void)
|
|
74
|
+
{
|
|
75
|
+
}
|
|
76
|
+
#endif
|
|
77
|
+
|
|
78
|
+
alp_status_t cc3501e_bridge_bringup(cc3501e_t *fw)
|
|
79
|
+
{
|
|
80
|
+
if (fw == NULL) {
|
|
81
|
+
return ALP_ERR_INVAL;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* 1. Control pins: WIFI_EN (supply gate) + nRESET. These are Alif LP-GPIO
|
|
85
|
+
* pads, not E1M edge pads -- the SoM owns them. */
|
|
86
|
+
alp_gpio_t *wifi_en = alp_gpio_open(CC3501E_BRIDGE_PIN_WIFI_EN);
|
|
87
|
+
alp_gpio_t *nrst = alp_gpio_open(CC3501E_BRIDGE_PIN_NRST);
|
|
88
|
+
if (wifi_en == NULL || nrst == NULL) {
|
|
89
|
+
if (wifi_en != NULL) {
|
|
90
|
+
alp_gpio_close(wifi_en);
|
|
91
|
+
}
|
|
92
|
+
if (nrst != NULL) {
|
|
93
|
+
alp_gpio_close(nrst);
|
|
94
|
+
}
|
|
95
|
+
return ALP_ERR_NOT_PRESENT_ON_THIS_SOC;
|
|
96
|
+
}
|
|
97
|
+
aen_lp_pads_enable_output();
|
|
98
|
+
/* Sample the supply gate BEFORE touching its direction. High is only a HINT
|
|
99
|
+
* that the chip may be powered -- an external pull-up on WIFI_EN would make every
|
|
100
|
+
* power-on read high (whether the module has one is an OPEN QUESTION; the
|
|
101
|
+
* netlist has not been checked), so the decision below also needs a PING. */
|
|
102
|
+
bool wifi_was_high = false;
|
|
103
|
+
/* A failed read leaves the level unknown: never take the supply-cycling cold path
|
|
104
|
+
* on that alone -- go through the PING path below, which still ends in
|
|
105
|
+
* cc3501e_reset() if the chip turns out to be silent. */
|
|
106
|
+
const bool wifi_unknown = alp_gpio_read(wifi_en, &wifi_was_high) != ALP_OK;
|
|
107
|
+
if (wifi_was_high) {
|
|
108
|
+
/* Latch the level in DR first so the direction change cannot glitch it low. */
|
|
109
|
+
aen_wifi_en_latch_high();
|
|
110
|
+
}
|
|
111
|
+
(void)alp_gpio_configure(wifi_en, ALP_GPIO_OUTPUT, ALP_GPIO_PULL_NONE);
|
|
112
|
+
(void)alp_gpio_configure(nrst, ALP_GPIO_OUTPUT, ALP_GPIO_PULL_NONE);
|
|
113
|
+
|
|
114
|
+
/* 2. Inter-chip SPI (Alif = master). CS is the dwc-ssi hardware SS0
|
|
115
|
+
* muxed on P14_7; the app passes ALP_SPI_NO_CS so no software GPIO CS
|
|
116
|
+
* is installed and the SPI controller drives SS0 per transfer. Mode 0
|
|
117
|
+
* matches the CC3501E vendor image frameFormat. */
|
|
118
|
+
alp_spi_t *spi = alp_spi_open(&(alp_spi_config_t){
|
|
119
|
+
.bus_id = CC3501E_BRIDGE_SPI_BUS_ID,
|
|
120
|
+
.freq_hz = CC3501E_BRIDGE_SPI_FREQ_HZ,
|
|
121
|
+
.mode = ALP_SPI_MODE_0,
|
|
122
|
+
.bits_per_word = 8u,
|
|
123
|
+
.cs_pin_id = ALP_SPI_NO_CS,
|
|
124
|
+
});
|
|
125
|
+
if (spi == NULL) {
|
|
126
|
+
alp_gpio_close(wifi_en);
|
|
127
|
+
alp_gpio_close(nrst);
|
|
128
|
+
return ALP_ERR_NOT_PRESENT_ON_THIS_SOC;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#if CC3501E_BRIDGE_RX_SAMPLE_DLY > 0
|
|
132
|
+
/* Raise the SCLK past 1 MHz: the DW SSI RX_SAMPLE_DLY register (0xf0) delays
|
|
133
|
+
* the MISO capture point by N ssi_clk cycles to cover the on-SoM trace + crossed
|
|
134
|
+
* data round-trip. Zephyr spi_dw never writes it (leaves 0), so without this
|
|
135
|
+
* >1 MHz mis-samples MISO (cold reqhdr_rx=0xFFFFFFFF). Written with SSI disabled
|
|
136
|
+
* (SSIENR=0); persists across the driver's per-transfer configure. Value is
|
|
137
|
+
* silicon-tuned -- sweep CC3501E_BRIDGE_RX_SAMPLE_DLY at the target SCLK.
|
|
138
|
+
*
|
|
139
|
+
* SWEEP TRAP -- read before setting the constant to 0: the `#if > 0` above
|
|
140
|
+
* compiles this block out, so 0 does not mean "no delay", it means the SPI
|
|
141
|
+
* node's `rx-delay` devicetree value is left in place. aen-cc3501e-bringup
|
|
142
|
+
* and aen-evk-demo declare rx-delay = <2>, so a naive N=0 sweep point on
|
|
143
|
+
* those two silently measures 2. Read 0x481040F0 back to see what the link
|
|
144
|
+
* is actually running at. */
|
|
145
|
+
{
|
|
146
|
+
volatile uint32_t *ssienr =
|
|
147
|
+
(volatile uint32_t *)(uintptr_t)(CC3501E_BRIDGE_SPI1_BASE + 0x08u);
|
|
148
|
+
volatile uint32_t *rsd = (volatile uint32_t *)(uintptr_t)(CC3501E_BRIDGE_SPI1_BASE + 0xf0u);
|
|
149
|
+
uint32_t en = *ssienr;
|
|
150
|
+
*ssienr = 0u;
|
|
151
|
+
*rsd = (uint32_t)CC3501E_BRIDGE_RX_SAMPLE_DLY;
|
|
152
|
+
*ssienr = en;
|
|
153
|
+
}
|
|
154
|
+
#endif
|
|
155
|
+
|
|
156
|
+
/* 3. Bind the bus + control pins; attach the GPIO proxy (proxied E1M IOs then
|
|
157
|
+
* route over the bridge); run the power + reset sequence (TI SWRU626 + the
|
|
158
|
+
* Puya cold-boot hard-reset workaround). Leaves WIFI_EN HIGH. */
|
|
159
|
+
(void)cc3501e_init(fw, spi);
|
|
160
|
+
fw->enable_pin = wifi_en;
|
|
161
|
+
fw->reset_pin = nrst;
|
|
162
|
+
/* READY (CC35 GPIO17) is NOT wired here by default on this R2 module --
|
|
163
|
+
* see chips/cc3501e/cc3501e_core.c's cc3501e_reply_gate() comment for the
|
|
164
|
+
* pin-routing fact, the bench evidence, and how a board that genuinely
|
|
165
|
+
* wires it can opt back in via fw->ready_pin. */
|
|
166
|
+
#ifdef CONFIG_ALP_SDK_GPIO_CC3501E_PROXY
|
|
167
|
+
(void)alp_gpio_cc3501e_attach(fw);
|
|
168
|
+
#endif
|
|
169
|
+
#ifdef CONFIG_ALP_SDK_WIFI_CC3501E
|
|
170
|
+
(void)alp_wifi_cc3501e_attach(fw);
|
|
171
|
+
#endif
|
|
172
|
+
#ifdef CONFIG_ALP_SDK_BLE_CC3501E
|
|
173
|
+
(void)alp_ble_cc3501e_attach(fw);
|
|
174
|
+
#endif
|
|
175
|
+
/* One line naming the path taken, so a log shows whether the supply was cycled. */
|
|
176
|
+
if (!wifi_was_high && !wifi_unknown) {
|
|
177
|
+
printf("[cc3501e_bridge] WIFI_EN low: cold power-up (cc3501e_reset)\n");
|
|
178
|
+
return cc3501e_reset(fw); /* supply low: the full cold-boot sequence */
|
|
179
|
+
}
|
|
180
|
+
/* WIFI_EN reads high. Warm = the chip ANSWERS a PING; a pull-up alone proves
|
|
181
|
+
* nothing. Warm: nRESET only, never a WIFI_EN toggle. */
|
|
182
|
+
if (cc3501e_ping(fw) == ALP_OK) {
|
|
183
|
+
printf("[cc3501e_bridge] WIFI_EN high, PING ok: warm, nRESET only\n");
|
|
184
|
+
return cc3501e_hard_reset(fw);
|
|
185
|
+
}
|
|
186
|
+
/* High but silent: powered-and-hung, or unpowered behind a pull-up. Try the
|
|
187
|
+
* nRESET-only reset first (safe for a powered chip); only if the chip still does
|
|
188
|
+
* not answer is the supply cycled -- the last resort, taken from a chip that is
|
|
189
|
+
* already unresponsive. */
|
|
190
|
+
if (cc3501e_hard_reset(fw) == ALP_OK && cc3501e_ping(fw) == ALP_OK) {
|
|
191
|
+
printf("[cc3501e_bridge] WIFI_EN high, silent: recovered by nRESET only\n");
|
|
192
|
+
return ALP_OK;
|
|
193
|
+
}
|
|
194
|
+
printf("[cc3501e_bridge] WIFI_EN high, silent after nRESET: supply cycle (cc3501e_reset)\n");
|
|
195
|
+
return cc3501e_reset(fw);
|
|
196
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
* Copyright 2026 Alp Lab AB
|
|
4
|
+
*
|
|
5
|
+
* One-call bring-up of the E1M-AEN SoM's CC3501E Wi-Fi 6 / BLE coprocessor over the
|
|
6
|
+
* inter-chip SPI bridge -- the SoM bring-up TEMPLATE for applications.
|
|
7
|
+
*
|
|
8
|
+
* The CC3501E is part of the SoM (module U4 = BDE-BW35N): the application does NOT
|
|
9
|
+
* touch the raw SPI bus or the WIFI_EN / nRESET control pins. It calls
|
|
10
|
+
* cc3501e_bridge_bringup() once, gets a ready @ref cc3501e_t, and from there uses the
|
|
11
|
+
* portable surfaces:
|
|
12
|
+
* - cc3501e_* (chips/cc3501e) -- MAC / Wi-Fi / BLE / GPIO-proxy / OTA
|
|
13
|
+
* - alp_gpio_open(ALP_E1M_GPIO_IOxx) -- proxied E1M IOs (when the proxy is built)
|
|
14
|
+
*
|
|
15
|
+
* To reuse in your own AEN application: copy this pair (cc3501e_bridge.{c,h}) into your
|
|
16
|
+
* app, or call cc3501e_bridge_bringup() directly. The bus / pins / clock are the
|
|
17
|
+
* E1M-AEN SoM defaults below; a board variant overrides only those macros -- the SoM
|
|
18
|
+
* stays swappable without touching application code.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
#ifndef CC3501E_BRIDGE_H
|
|
22
|
+
#define CC3501E_BRIDGE_H
|
|
23
|
+
|
|
24
|
+
#include <alp/peripheral.h> /* alp_status_t */
|
|
25
|
+
#include <alp/chips/cc3501e.h> /* cc3501e_t */
|
|
26
|
+
|
|
27
|
+
/* ---- E1M-AEN SoM bridge defaults (override per board variant) ---------------- */
|
|
28
|
+
|
|
29
|
+
/* Inter-chip SPI: Alif = master, CC3501E = slave. P14_7 is muxed as the
|
|
30
|
+
* dwc-ssi hardware SS0 chip-select; ALP_SPI_NO_CS means "no software GPIO CS"
|
|
31
|
+
* here, so the controller frames each protocol phase. Mode 0 matches the
|
|
32
|
+
* CC3501E vendor image frameFormat. */
|
|
33
|
+
#ifndef CC3501E_BRIDGE_SPI_BUS_ID
|
|
34
|
+
#define CC3501E_BRIDGE_SPI_BUS_ID 1u
|
|
35
|
+
#endif
|
|
36
|
+
#ifndef CC3501E_BRIDGE_SPI_FREQ_HZ
|
|
37
|
+
/* 25 MHz = 200 MHz SSI functional clock / 8.
|
|
38
|
+
*
|
|
39
|
+
* The CC3501E peripheral-mode maximum is 30 MHz, NOT the 15 MHz this comment
|
|
40
|
+
* claimed for most of the bring-up: datasheet SWRS343A section 6.14.2.3.3,
|
|
41
|
+
* `fsclk SPI clock frequency, Peripheral Mode, MAX 30 MHz` (Controller Mode is
|
|
42
|
+
* 40 MHz). Every earlier ceiling argument here was built on the wrong number.
|
|
43
|
+
*
|
|
44
|
+
* 25 MHz is the fastest LEGAL step available: the DW SSI BAUDR divisor must be
|
|
45
|
+
* EVEN, so from 200 MHz the neighbours are /8 = 25 MHz and /6 = 33.3 MHz, and
|
|
46
|
+
* 33.3 is 11% over the part's maximum. Reaching exactly 30 MHz would require
|
|
47
|
+
* retargeting the SSI functional clock itself (AE822 HWRM section 8.3.5) --
|
|
48
|
+
* ALIF_SPI_CLK is a frequency-only dummy in the dtsi with no divider control,
|
|
49
|
+
* so there is no software knob for it here.
|
|
50
|
+
*
|
|
51
|
+
* REQUIRES an RX sample delay: at a 40 ns bit period the MISO capture does not
|
|
52
|
+
* land on its own. That delay comes from CC3501E_BRIDGE_RX_SAMPLE_DLY below --
|
|
53
|
+
* NOT from the SPI node's `rx-delay` property, which the poke in
|
|
54
|
+
* cc3501e_bridge.c overwrites. The measured working span is in that constant's
|
|
55
|
+
* comment.
|
|
56
|
+
*
|
|
57
|
+
* It does not raise throughput -- silicon-measured
|
|
58
|
+
* 2026-08-24: 682 kB/s at 25 MHz vs 678 kB/s at 14.29 MHz on PIO, 704 vs 701 on
|
|
59
|
+
* DMA, because wire time is only ~554 us of a ~2459 us transaction and the rest
|
|
60
|
+
* is per-frame protocol cost on both ends. It is worth taking anyway: each
|
|
61
|
+
* transfer occupies the bus for ~44% less time, which is CPU and bus budget
|
|
62
|
+
* handed back to everything else on the SoM.
|
|
63
|
+
*
|
|
64
|
+
* The 14.29 MHz predecessor was scope-confirmed at 14.20-14.26 MHz, which is
|
|
65
|
+
* what validates the 200 MHz functional-clock figure the divider assumes. A
|
|
66
|
+
* board with longer traces should re-check MISO capture before adopting 25 MHz.
|
|
67
|
+
*
|
|
68
|
+
* SEPARATE, PRE-EXISTING DEFECT (do not blame this clock for it): a bulk read
|
|
69
|
+
* intermittently desyncs partway through -- roughly 1 run in 2-3, at anywhere
|
|
70
|
+
* from 61 kB to 212 kB in -- and then never recovers for the caller's whole
|
|
71
|
+
* retry budget. It reproduces at 14.29 MHz TOO, so it is not a clock artifact.
|
|
72
|
+
* Signature (host-side, request-header phase of CMD_SOCK_RECV 0x23): the
|
|
73
|
+
* slave's in-band idle marker reads [02 00 00 00] once and then [00 00 00 00]
|
|
74
|
+
* forever instead of A5 A5 A5 A5 -- i.e. the slave is stuck mid-reply on a
|
|
75
|
+
* transfer it armed earlier and never completed. With
|
|
76
|
+
* SPI_TRANSFER_RETURN_PARTIAL deliberately off, a CS deassert does not complete
|
|
77
|
+
* it, and NEITHER slave self-heal fires (g_resync_count does not move -- the
|
|
78
|
+
* slave is not misframing; g_arm_fail_count does not move -- the arm succeeded).
|
|
79
|
+
* Clocking a full idle frame from the host to satisfy the outstanding count was
|
|
80
|
+
* tried and did NOT recover it. The fix likely belongs on the slave: a
|
|
81
|
+
* stall watchdog that calls bridge_transport_spi_hw_reinit() when an armed
|
|
82
|
+
* transfer has not completed for N ms. */
|
|
83
|
+
#define CC3501E_BRIDGE_SPI_FREQ_HZ 25000000u
|
|
84
|
+
#endif
|
|
85
|
+
|
|
86
|
+
/* CC3501E control pins on the Alif LP-GPIO island (NOT E1M edge pads):
|
|
87
|
+
* WIFI_EN = supply gate (P15_5), nRESET = reset (P15_1_FLEX). */
|
|
88
|
+
#ifndef CC3501E_BRIDGE_PIN_WIFI_EN
|
|
89
|
+
#define CC3501E_BRIDGE_PIN_WIFI_EN 0u
|
|
90
|
+
#endif
|
|
91
|
+
#ifndef CC3501E_BRIDGE_PIN_NRST
|
|
92
|
+
#define CC3501E_BRIDGE_PIN_NRST 1u
|
|
93
|
+
#endif
|
|
94
|
+
/* OPTIONAL host-IRQ/READY input. ready_pin has no fixed index or macro
|
|
95
|
+
* here on purpose: on a board where the CC3501E's GPIO17 READY net is
|
|
96
|
+
* actually routed to the host, set fw->ready_pin (in
|
|
97
|
+
* cc3501e_bridge_bringup() below) to whatever Alif pin that board wires it
|
|
98
|
+
* to. When set, cc3501e_reply_gate() (chips/cc3501e/cc3501e_core.c) can
|
|
99
|
+
* only ever ADD delay to a reply phase, never remove it, so opting in on a
|
|
100
|
+
* board where the wiring is wrong costs up to 3 x 250 ms of busy-wait per
|
|
101
|
+
* latch cycle before the driver's own (recoverable) stuck-LOW latch gives up
|
|
102
|
+
* on it -- longer thresholds apply after each re-latch if the line flaps
|
|
103
|
+
* instead of staying cleanly stuck (chips/cc3501e/cc3501e_core.c's
|
|
104
|
+
* g_ready_stuck_low_threshold) -- it is always safe to try FOR LINK TIMING.
|
|
105
|
+
* It is not free, though: this
|
|
106
|
+
* wait runs while cc3501e_request() holds its internal transport lock, so
|
|
107
|
+
* a wrong or slow ready_pin can make another caller on the same ctx see
|
|
108
|
+
* ALP_ERR_BUSY after CONFIG_ALP_SDK_CC3501E_REQUEST_LOCK_TIMEOUT_MS -- see
|
|
109
|
+
* <alp/chips/cc3501e/core.h>'s ready_pin doc.
|
|
110
|
+
*
|
|
111
|
+
* NOT Alif P2_6 on an R2 AEN EVK bench module: P2_6 there is E1M pad AH7 /
|
|
112
|
+
* I2S1_SCLK (the EVK's Arduino CK_RST, metadata/boards/e1m-evk.yaml), and
|
|
113
|
+
* the CC3501E GPIO17 READY net lands on E1M pad G3 / IO16 instead
|
|
114
|
+
* (metadata/e1m_modules/aen/from-cc3501e.tsv). cc3501e_bridge_bringup()
|
|
115
|
+
* below leaves ready_pin NULL by default on that module -- see
|
|
116
|
+
* cc3501e_reply_gate()'s own doc comment for the bench evidence. */
|
|
117
|
+
|
|
118
|
+
/* DW SSI SPI1 base (0x48104000) + RX_SAMPLE_DLY to run the bridge SCLK above
|
|
119
|
+
* 1 MHz. spi_dw_configure never writes RX_SAMPLE_DLY (0xf0), so without the
|
|
120
|
+
* poke in cc3501e_bridge.c the master samples MISO at the SCLK edge, before the
|
|
121
|
+
* on-SoM trace + crossed-data round-trip returns the CC35's bit, and anything
|
|
122
|
+
* above 1 MHz mis-samples. Setting it delays the capture by N ssi_clk
|
|
123
|
+
* (200 MHz) cycles -- 5 ns per step.
|
|
124
|
+
*
|
|
125
|
+
* 4 is silicon-measured at the 25 MHz working point (40 ns bit period) on
|
|
126
|
+
* E1M-AEN803 serial 2026W36-0002. N was swept 0..10 with 0x481040F0 read back
|
|
127
|
+
* each time to confirm the value took, using aen-evk-demo phase 8 as the
|
|
128
|
+
* workload:
|
|
129
|
+
*
|
|
130
|
+
* N = 0..7 PASS, 2-3 runs each: bring-up 0, PING on attempt 1 of 25,
|
|
131
|
+
* byte-exact MAC, scan 0, BLE 0.
|
|
132
|
+
* N = 8 FAIL, 3 runs of 3: bring-up still returns 0, but the link never
|
|
133
|
+
* answers -- PING -> -5 after all 25 attempts.
|
|
134
|
+
* N = 9 PASS, 2 runs of 2.
|
|
135
|
+
* N = 10 PASS, 3 runs of 3, but one run returned a MAC with a single bit
|
|
136
|
+
* flipped in byte 0.
|
|
137
|
+
*
|
|
138
|
+
* 4 is the centre of the measured-good 0..7 span: +4 steps (20 ns, half a bit
|
|
139
|
+
* period) below the failure, and the low side is not a cliff at all since 0
|
|
140
|
+
* itself is clean. Do NOT read 8/9/10 as a monotone upper boundary -- 8
|
|
141
|
+
* hard-fails while 9 and 10 pass, which this sweep did not explain. Treat
|
|
142
|
+
* everything above 7 as unqualified, not as graded margin.
|
|
143
|
+
*
|
|
144
|
+
* The "4..8 all clean cold+warm" window this comment used to claim was taken on
|
|
145
|
+
* an earlier bench run at ~14.3 MHz -- a different board at roughly half the clock,
|
|
146
|
+
* so it is not comparable and is not evidence for 25 MHz on this one.
|
|
147
|
+
*
|
|
148
|
+
* 0 does NOT mean "no delay": it compiles the poke out, leaving whatever the
|
|
149
|
+
* SPI node's `rx-delay` property put there (see cc3501e_bridge.c). Re-sweep if
|
|
150
|
+
* the SoM trace lengths or the SCLK change. */
|
|
151
|
+
#ifndef CC3501E_BRIDGE_SPI1_BASE
|
|
152
|
+
#define CC3501E_BRIDGE_SPI1_BASE 0x48104000u
|
|
153
|
+
#endif
|
|
154
|
+
#ifndef CC3501E_BRIDGE_RX_SAMPLE_DLY
|
|
155
|
+
#define CC3501E_BRIDGE_RX_SAMPLE_DLY 4u
|
|
156
|
+
#endif
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @brief Bring up the SoM's CC3501E coprocessor over the inter-chip bridge.
|
|
160
|
+
*
|
|
161
|
+
* Opens the hardware-SS0 bridge SPI + the WIFI_EN / nRESET control pins, binds
|
|
162
|
+
* them to @p fw, attaches the GPIO proxy (when CONFIG_ALP_SDK_GPIO_CC3501E_PROXY is
|
|
163
|
+
* built), and runs the power + reset sequence (TI SWRU626 + the Puya cold-boot
|
|
164
|
+
* hard-reset workaround). Blocks ~900 ms for the boot budget; leaves WIFI_EN HIGH.
|
|
165
|
+
*
|
|
166
|
+
* @param fw Caller-owned handle, populated on success. Use it with cc3501e_*.
|
|
167
|
+
* @return ALP_OK with @p fw ready; ALP_ERR_NOT_PRESENT_ON_THIS_SOC if the SPI bus /
|
|
168
|
+
* control pins are absent (check the board overlay); otherwise the reset
|
|
169
|
+
* sequence status. On any failure @p fw is left un-bound (do not use it).
|
|
170
|
+
*/
|
|
171
|
+
alp_status_t cc3501e_bridge_bringup(cc3501e_t *fw);
|
|
172
|
+
|
|
173
|
+
#endif /* CC3501E_BRIDGE_H */
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Alp Lab AB
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*
|
|
5
|
+
* mqtt-telemetry -- publish a sensor reading over MQTT/TLS.
|
|
6
|
+
*
|
|
7
|
+
* The "connected device" starting point. It shows the whole
|
|
8
|
+
* telemetry path a field device runs, all on the portable
|
|
9
|
+
* <alp/iot.h> surface:
|
|
10
|
+
*
|
|
11
|
+
* 1. Bring the Wi-Fi station up + associate. (alp_wifi_*)
|
|
12
|
+
* 2. Open an mqtts:// (TLS) MQTT client. (alp_mqtt_open)
|
|
13
|
+
* 3. Connect to the broker. (alp_mqtt_connect)
|
|
14
|
+
* 4. Publish a telemetry reading on a cadence. (alp_mqtt_publish)
|
|
15
|
+
* 5. Disconnect cleanly. (alp_mqtt_close)
|
|
16
|
+
*
|
|
17
|
+
* Transport (E1M-AEN801): the CC3501E Wi-Fi6+BLE coprocessor bridge
|
|
18
|
+
* (https://github.com/alplabai/alp-sdk/blob/v0.17.0/docs/cc3501e-bridge.md), selected automatically by the AEN board
|
|
19
|
+
* emit from `iot.wifi: true` -- the app never names it, it just
|
|
20
|
+
* calls <alp/iot.h>. The bridge is silicon-validated (2026-06-24);
|
|
21
|
+
* this is a real transport, not a stub.
|
|
22
|
+
*
|
|
23
|
+
* Bridge bring-up (#2112): alp_wifi_open() only resolves to the CC3501E
|
|
24
|
+
* backend once an application has attached a live bridge handle --
|
|
25
|
+
* cc3501e_bridge_bringup() (src/cc3501e_bridge.c, the same copyable
|
|
26
|
+
* template every https://github.com/alplabai/alp-sdk/tree/v0.17.0/examples/aen/aen-cc3501e-* app uses) does exactly that
|
|
27
|
+
* before this app calls alp_wifi_open() below. On native_sim the bring-up
|
|
28
|
+
* fails fast (ALP_ERR_NOT_PRESENT_ON_THIS_SOC -- no SPI/GPIO backend
|
|
29
|
+
* matches that SoC ref) and this app falls through to the same
|
|
30
|
+
* NULL-with-NOT_READY framing path as before.
|
|
31
|
+
*
|
|
32
|
+
* The "sensor reading": to keep the focus on the transport, this
|
|
33
|
+
* template publishes a synthetic metric (device uptime). Swap
|
|
34
|
+
* read_telemetry_value() for a real sensor read -- e.g. compose it
|
|
35
|
+
* with the `sensor` template (https://github.com/alplabai/alp-sdk/tree/v0.17.0/examples/peripheral-io/i2c-master,
|
|
36
|
+
* TMP112 over <alp/chips/tmp112.h>) -- and the publish path here is
|
|
37
|
+
* unchanged.
|
|
38
|
+
*
|
|
39
|
+
* TLS status (preview): the mqtts:// path is configured through the
|
|
40
|
+
* portable API (broker URI + pinned CA), but CONFIG_MBEDTLS is held
|
|
41
|
+
* OFF in the build today -- Zephyr v4.4's mbedtls 3.6 has an
|
|
42
|
+
* ssl_misc.h include-order bug; full tf-psa-crypto wiring is a v0.6
|
|
43
|
+
* work item (see prj.conf / native_sim.conf). Real AEN silicon
|
|
44
|
+
* uses the TF-M stack. This is why the catalog record is `preview`.
|
|
45
|
+
*
|
|
46
|
+
* What runs under native_sim (CI lane): there is no radio and no
|
|
47
|
+
* MQTT-capable net stack, so alp_wifi_open()/alp_mqtt_open() return
|
|
48
|
+
* NULL -- ALP_ERR_NOT_READY when a backend registered but its device
|
|
49
|
+
* isn't up, or ALP_ERR_NOSUPPORT when no backend is linked at all;
|
|
50
|
+
* both are the documented <alp/iot.h> NULL contract. The app
|
|
51
|
+
* detects that, prints the telemetry payloads it WOULD publish (so
|
|
52
|
+
* the framing is CI-observable), and exits on the `[mqtt] done`
|
|
53
|
+
* marker.
|
|
54
|
+
*
|
|
55
|
+
* What runs on AEN HiL: real association through the CC3501E, real
|
|
56
|
+
* MQTT publish to the broker; the same source, no #ifdef in the
|
|
57
|
+
* telemetry logic.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
#include <stdint.h>
|
|
61
|
+
#include <stdio.h>
|
|
62
|
+
#include <string.h>
|
|
63
|
+
|
|
64
|
+
#include "alp/iot.h"
|
|
65
|
+
#include "cc3501e_bridge.h" /* cc3501e_bridge_bringup() -- the SoM bring-up template, #2112 */
|
|
66
|
+
|
|
67
|
+
/* Broker + topic identity. In a real fleet these come from the
|
|
68
|
+
* device's provisioning step; hardcoded here as documentation.
|
|
69
|
+
* mqtts:// selects the TLS path (see the TLS config below). */
|
|
70
|
+
#define MQTT_BROKER_URI "mqtts://broker.example.alplab.ai:8883"
|
|
71
|
+
#define MQTT_CLIENT_ID "e1m-aen801-demo"
|
|
72
|
+
#define MQTT_TOPIC "alp/telemetry/e1m-aen801"
|
|
73
|
+
|
|
74
|
+
/* Pin the broker's CA bundle. NULL would fall back to the OS
|
|
75
|
+
* default trust store; a real deployment should pin a known-good
|
|
76
|
+
* CA, so we name the path a customer would provision. */
|
|
77
|
+
#define MQTT_CA_FILE "/etc/ssl/certs/alp-broker-ca.pem"
|
|
78
|
+
|
|
79
|
+
/* Wi-Fi credentials. On real silicon these come from the EEPROM
|
|
80
|
+
* factory manifest or a provisioning blob so one binary serves a
|
|
81
|
+
* whole fleet; hardcoded for the demo. */
|
|
82
|
+
#define WIFI_SSID "alp-demo-ap"
|
|
83
|
+
#define WIFI_PSK "changeme-in-provisioning"
|
|
84
|
+
|
|
85
|
+
/* Publish a bounded number of readings so the native_sim run
|
|
86
|
+
* terminates and the twister harness latches. Real firmware would
|
|
87
|
+
* publish forever on a timer. */
|
|
88
|
+
#define PUBLISH_COUNT 3u
|
|
89
|
+
#define PUBLISH_PERIOD_S 5u
|
|
90
|
+
|
|
91
|
+
/* Handshake budgets.
|
|
92
|
+
*
|
|
93
|
+
* WIFI_CONNECT_TIMEOUT_MS: on E1M-AEN801 with the CC3501E bridge attached,
|
|
94
|
+
* alp_wifi_connect() routes to the CC3501E backend
|
|
95
|
+
* (src/backends/wifi/cc3501e.c), and the bridge's own worst case for one STA
|
|
96
|
+
* connect is 10s Wlan_RoleUp + 30s L2 association + a 30s DHCP-lease poll
|
|
97
|
+
* (hal/ti/cc3501e_hw_ti_wifi.c) = 70s. On other Wi-Fi backends this value is
|
|
98
|
+
* only an upper bound, not a derived worst case. */
|
|
99
|
+
#define WIFI_CONNECT_TIMEOUT_MS 75000u
|
|
100
|
+
#define MQTT_CONNECT_TIMEOUT_MS 10000u
|
|
101
|
+
|
|
102
|
+
/* Read one telemetry value.
|
|
103
|
+
*
|
|
104
|
+
* PLACEHOLDER: returns a synthetic uptime-seconds counter so the
|
|
105
|
+
* template stays chip-free and focused on the transport. On real
|
|
106
|
+
* hardware, replace the body with a sensor read -- e.g. a TMP112
|
|
107
|
+
* temperature via <alp/chips/tmp112.h> (see the `sensor` template)
|
|
108
|
+
* -- and return that value. The publish path below does not change. */
|
|
109
|
+
static uint32_t read_telemetry_value(uint32_t sample_index)
|
|
110
|
+
{
|
|
111
|
+
/* Synthetic: seconds of "uptime" at this sample's cadence.
|
|
112
|
+
* Deterministic so the native_sim framing output is stable. */
|
|
113
|
+
return sample_index * PUBLISH_PERIOD_S;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Format a telemetry sample as a compact JSON payload. Returns the
|
|
117
|
+
* byte length written (excluding the NUL), or 0 on truncation. */
|
|
118
|
+
static size_t build_payload(char *buf, size_t cap, uint32_t value)
|
|
119
|
+
{
|
|
120
|
+
int n = snprintf(buf,
|
|
121
|
+
cap,
|
|
122
|
+
"{\"device\":\"%s\",\"metric\":\"uptime_s\",\"value\":%u}",
|
|
123
|
+
MQTT_CLIENT_ID,
|
|
124
|
+
value);
|
|
125
|
+
if (n < 0 || (size_t)n >= cap) {
|
|
126
|
+
return 0u; /* truncated -- caller skips the publish */
|
|
127
|
+
}
|
|
128
|
+
return (size_t)n;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* Bring the Wi-Fi station up + associate. Returns an open handle
|
|
132
|
+
* on success, or NULL (with the reason logged) when there is no
|
|
133
|
+
* Wi-Fi backend on this build -- the native_sim / sw_fallback path. */
|
|
134
|
+
static alp_wifi_t *telemetry_wifi_up(void)
|
|
135
|
+
{
|
|
136
|
+
/* STATIC, not a local -- cc3501e_t embeds several
|
|
137
|
+
* ALP_CC3501E_MAX_PAYLOAD scratch buffers; see cc3501e_bridge.h. */
|
|
138
|
+
static cc3501e_t bridge = { 0 };
|
|
139
|
+
|
|
140
|
+
printf("[mqtt] wifi: bridge bring-up\n");
|
|
141
|
+
alp_status_t bridge_rc = cc3501e_bridge_bringup(&bridge);
|
|
142
|
+
printf("[mqtt] wifi: cc3501e_bridge_bringup -> %s\n", alp_status_name(bridge_rc));
|
|
143
|
+
|
|
144
|
+
printf("[mqtt] wifi: opening station\n");
|
|
145
|
+
alp_wifi_t *w = alp_wifi_open();
|
|
146
|
+
if (w == NULL) {
|
|
147
|
+
/* NOT_READY on native_sim (a Wi-Fi backend registered but no
|
|
148
|
+
* device is up) or NOSUPPORT when no Wi-Fi backend is linked;
|
|
149
|
+
* on HiL, NOT_READY before the CC3501E bridge has probed. */
|
|
150
|
+
printf("[mqtt] wifi: alp_wifi_open -> NULL (%s)\n", alp_status_name(alp_last_error()));
|
|
151
|
+
return NULL;
|
|
152
|
+
}
|
|
153
|
+
const alp_wifi_credentials_t creds = {
|
|
154
|
+
.ssid = WIFI_SSID,
|
|
155
|
+
.psk = WIFI_PSK,
|
|
156
|
+
};
|
|
157
|
+
alp_status_t s = alp_wifi_connect(w, &creds, WIFI_CONNECT_TIMEOUT_MS);
|
|
158
|
+
if (s != ALP_OK) {
|
|
159
|
+
printf("[mqtt] wifi: connect -> %s\n", alp_status_name(s));
|
|
160
|
+
alp_wifi_close(w);
|
|
161
|
+
return NULL;
|
|
162
|
+
}
|
|
163
|
+
printf("[mqtt] wifi: associated to \"%s\"\n", WIFI_SSID);
|
|
164
|
+
return w;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* Open + connect the TLS MQTT client. Returns an open handle, or
|
|
168
|
+
* NULL when there is no MQTT backend on this build. */
|
|
169
|
+
static alp_mqtt_t *telemetry_mqtt_up(void)
|
|
170
|
+
{
|
|
171
|
+
printf("[mqtt] broker: opening %s (TLS, CA pinned)\n", MQTT_BROKER_URI);
|
|
172
|
+
|
|
173
|
+
/* Pin the broker CA for the mqtts:// handshake. insecure
|
|
174
|
+
* stays false -- a starter must not teach cert-skipping. */
|
|
175
|
+
static const alp_mqtt_tls_config_t tls = {
|
|
176
|
+
.ca_file = MQTT_CA_FILE,
|
|
177
|
+
.insecure = false,
|
|
178
|
+
};
|
|
179
|
+
alp_mqtt_config_t cfg = ALP_MQTT_CONFIG_DEFAULT(MQTT_BROKER_URI);
|
|
180
|
+
cfg.client_id = MQTT_CLIENT_ID;
|
|
181
|
+
cfg.tls = &tls;
|
|
182
|
+
|
|
183
|
+
alp_mqtt_t *m = alp_mqtt_open(&cfg);
|
|
184
|
+
if (m == NULL) {
|
|
185
|
+
printf("[mqtt] broker: alp_mqtt_open -> NULL (%s)\n", alp_status_name(alp_last_error()));
|
|
186
|
+
return NULL;
|
|
187
|
+
}
|
|
188
|
+
alp_status_t s = alp_mqtt_connect(m, MQTT_CONNECT_TIMEOUT_MS);
|
|
189
|
+
if (s != ALP_OK) {
|
|
190
|
+
printf("[mqtt] broker: connect -> %s\n", alp_status_name(s));
|
|
191
|
+
alp_mqtt_close(m);
|
|
192
|
+
return NULL;
|
|
193
|
+
}
|
|
194
|
+
printf("[mqtt] broker: connected\n");
|
|
195
|
+
return m;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Publish PUBLISH_COUNT readings on the live client. */
|
|
199
|
+
static void telemetry_publish_loop(alp_mqtt_t *m)
|
|
200
|
+
{
|
|
201
|
+
for (uint32_t i = 0; i < PUBLISH_COUNT; i++) {
|
|
202
|
+
char payload[96];
|
|
203
|
+
size_t len = build_payload(payload, sizeof(payload), read_telemetry_value(i));
|
|
204
|
+
if (len == 0u) {
|
|
205
|
+
printf("[mqtt] publish %u: payload truncated -- skipped\n", i);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
alp_status_t s =
|
|
209
|
+
alp_mqtt_publish(m, MQTT_TOPIC, (const uint8_t *)payload, len, ALP_MQTT_QOS_1, false);
|
|
210
|
+
printf("[mqtt] publish %u -> %s: %s\n", i, alp_status_name(s), payload);
|
|
211
|
+
|
|
212
|
+
/* Pace the publishes -- a real telemetry device sends on a
|
|
213
|
+
* timer, not in a tight loop. alp_delay_ms is portable
|
|
214
|
+
* (<alp/peripheral.h>, reached via <alp/iot.h>). */
|
|
215
|
+
if (i + 1u < PUBLISH_COUNT) {
|
|
216
|
+
alp_delay_ms(PUBLISH_PERIOD_S * 1000u);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* native_sim / no-backend path: there's no live client, but print
|
|
222
|
+
* the payloads the app WOULD publish so the framing is observable
|
|
223
|
+
* in CI (and so a customer sees the message shape without a broker). */
|
|
224
|
+
static void telemetry_print_framing(void)
|
|
225
|
+
{
|
|
226
|
+
printf("[mqtt] no transport on this build -- printing framing only\n");
|
|
227
|
+
for (uint32_t i = 0; i < PUBLISH_COUNT; i++) {
|
|
228
|
+
char payload[96];
|
|
229
|
+
size_t len = build_payload(payload, sizeof(payload), read_telemetry_value(i));
|
|
230
|
+
if (len == 0u) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
printf("[mqtt] would publish to %s: %s\n", MQTT_TOPIC, payload);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
int main(void)
|
|
238
|
+
{
|
|
239
|
+
/* Bring up the SDK runtime before anything else. */
|
|
240
|
+
(void)alp_init();
|
|
241
|
+
|
|
242
|
+
printf("[mqtt] alp-sdk mqtt-telemetry demo (publish over MQTT/TLS)\n");
|
|
243
|
+
printf("[mqtt] transport: CC3501E Wi-Fi bridge (E1M-AEN801)\n");
|
|
244
|
+
|
|
245
|
+
alp_wifi_t *w = telemetry_wifi_up();
|
|
246
|
+
if (w != NULL) {
|
|
247
|
+
alp_mqtt_t *m = telemetry_mqtt_up();
|
|
248
|
+
if (m != NULL) {
|
|
249
|
+
telemetry_publish_loop(m);
|
|
250
|
+
alp_mqtt_close(m);
|
|
251
|
+
}
|
|
252
|
+
alp_wifi_disconnect(w);
|
|
253
|
+
alp_wifi_close(w);
|
|
254
|
+
} else {
|
|
255
|
+
/* No Wi-Fi backend (native_sim): show the framing so the
|
|
256
|
+
* run is still meaningful + the harness has a marker. */
|
|
257
|
+
telemetry_print_framing();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
printf("[mqtt] done\n");
|
|
261
|
+
return 0;
|
|
262
|
+
}
|