@polderlabs/bizar 6.2.4 → 6.3.0
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.
- package/.claude/CLAUDE.md +15 -0
- package/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
- package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
- package/.claude/agents/_shared/SKILLS.md +109 -0
- package/.claude/agents/agent-browser.md +80 -0
- package/.claude/agents/baldr.md +49 -0
- package/.claude/agents/forseti.md +51 -0
- package/.claude/agents/frigg.md +42 -0
- package/.claude/agents/heimdall.md +33 -0
- package/.claude/agents/hermod.md +53 -0
- package/.claude/agents/mimir.md +49 -0
- package/.claude/agents/odin.md +287 -0
- package/.claude/agents/quick.md +34 -0
- package/.claude/agents/semble-search.md +50 -0
- package/.claude/agents/thor.md +53 -0
- package/.claude/agents/tyr.md +56 -0
- package/.claude/agents/vidarr.md +54 -0
- package/.claude/agents/vor.md +53 -0
- package/.claude/commands/audit.md +25 -0
- package/.claude/commands/bizar.md +22 -0
- package/.claude/commands/explain.md +17 -0
- package/.claude/commands/init.md +29 -0
- package/.claude/commands/learn.md +44 -0
- package/.claude/commands/plan.md +35 -0
- package/.claude/commands/plow-through.md +50 -0
- package/.claude/commands/pr-review.md +49 -0
- package/.claude/commands/setup-provider.md +96 -0
- package/.claude/commands/tailscale-serve.md +100 -0
- package/.claude/commands/team.md +132 -0
- package/.claude/commands/test.md +62 -0
- package/.claude/commands/validate.md +68 -0
- package/.claude/commands/visual-plan.md +24 -0
- package/.claude/hooks/README.md +92 -0
- package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
- package/.claude/hooks/pretooluse-bash.mjs +81 -0
- package/.claude/hooks/pretooluse-editwrite.mjs +139 -0
- package/.claude/hooks/sessionend-recall.mjs +74 -0
- package/.claude/hooks/sessionstart-prime.mjs +80 -0
- package/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
- package/.claude/settings.json +116 -0
- package/.claude/skills/9router/SKILL.md +80 -0
- package/.claude/skills/9router-chat/SKILL.md +73 -0
- package/.claude/skills/9router-embeddings/SKILL.md +69 -0
- package/.claude/skills/9router-image/SKILL.md +86 -0
- package/.claude/skills/9router-stt/SKILL.md +79 -0
- package/.claude/skills/9router-tts/SKILL.md +80 -0
- package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
- package/.claude/skills/9router-web-search/SKILL.md +91 -0
- package/.claude/skills/bizar/README.md +9 -0
- package/.claude/skills/bizar/SKILL.md +450 -0
- package/.claude/skills/cpp-coding-standards/README.md +28 -0
- package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
- package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
- package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
- package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
- package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
- package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
- package/.claude/skills/cpp-testing/README.md +28 -0
- package/.claude/skills/cpp-testing/SKILL.md +304 -0
- package/.claude/skills/cpp-testing/references/coverage.md +370 -0
- package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
- package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
- package/.claude/skills/cpp-testing/references/mocking.md +364 -0
- package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
- package/.claude/skills/cubesandbox/SKILL.md +148 -0
- package/.claude/skills/embedded-esp-idf/README.md +41 -0
- package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
- package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
- package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
- package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
- package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
- package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
- package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
- package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
- package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
- package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
- package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
- package/.claude/skills/glyph/SKILL.md +163 -0
- package/.claude/skills/harness-engineering/SKILL.md +143 -0
- package/.claude/skills/lightrag/SKILL.md +81 -0
- package/.claude/skills/memory-protocol/SKILL.md +105 -0
- package/.claude/skills/obsidian/SKILL.md +306 -0
- package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
- package/.claude/skills/self-improvement/SKILL.md +64 -0
- package/README.md +87 -59
- package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-B58aiJiE.js} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-B58aiJiE.js.map} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js → MobileChat-BJrqwVDd.js} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-BJrqwVDd.js.map} +1 -1
- package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js → MobileSettings-CEQNJNLJ.js} +1 -1
- package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-CEQNJNLJ.js.map} +1 -1
- package/bizar-dash/dist/assets/{main-DYiZqMrn.js → main-IvfQAOfy.js} +1 -1
- package/bizar-dash/dist/assets/{main-DYiZqMrn.js.map → main-IvfQAOfy.js.map} +1 -1
- package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js → markdown-tOLaD6nm.js} +1 -1
- package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-tOLaD6nm.js.map} +1 -1
- package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js → mobile-DYCHcUpq.js} +1 -1
- package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DYCHcUpq.js.map} +1 -1
- package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js → mobile-layout-CBHjpwsb.js} +2 -2
- package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js.map → mobile-layout-CBHjpwsb.js.map} +1 -1
- package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js → useSlashCommands-Bd7_FA6U.js} +2 -2
- package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js.map → useSlashCommands-Bd7_FA6U.js.map} +1 -1
- package/bizar-dash/dist/assets/{vendor-CeHGtduv.js → vendor-C843201K.js} +12 -12
- package/bizar-dash/dist/assets/vendor-C843201K.js.map +1 -0
- package/bizar-dash/dist/index.html +6 -6
- package/bizar-dash/dist/mobile.html +2 -2
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/api.mjs +4 -4
- package/bizar-dash/src/server/background-store.mjs +15 -16
- package/bizar-dash/src/server/bg-poller.mjs +25 -35
- package/bizar-dash/src/server/bg-retry.mjs +66 -194
- package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
- package/bizar-dash/src/server/claude-info.mjs +412 -0
- package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
- package/bizar-dash/src/server/claude-sdk.mjs +191 -0
- package/bizar-dash/src/server/providers-store.mjs +22 -49
- package/bizar-dash/src/server/routes/background.mjs +24 -20
- package/bizar-dash/src/server/routes/chat.mjs +223 -326
- package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
- package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
- package/bizar-dash/src/server/routes/tasks.mjs +20 -28
- package/bizar-dash/src/server/task-delegator.mjs +76 -77
- package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
- package/bizar-dash/src/web/views/Chat.tsx +8 -8
- package/cli/bin.mjs +31 -18
- package/cli/commands/claude-cmd.mjs +348 -0
- package/cli/commands/install.mjs +12 -11
- package/cli/commands/sandbox.mjs +220 -0
- package/cli/commands/validate.mjs +252 -288
- package/cli/dev-link.test.mjs +11 -11
- package/cli/doctor.mjs +131 -213
- package/cli/install.mjs +33 -37
- package/cli/install.test.mjs +9 -9
- package/cli/provision-claude.mjs +893 -0
- package/cli/provision.mjs +330 -226
- package/cli/provision.test.mjs +102 -0
- package/cli/utils.mjs +72 -58
- package/config/AGENTS.md +28 -28
- package/config/agents/_shared/AGENT_BASELINE.md +104 -684
- package/config/skills/bizar/SKILL.md +197 -0
- package/config/skills/cubesandbox/SKILL.md +148 -0
- package/config/skills/harness-engineering/SKILL.md +142 -0
- package/install.sh +66 -44
- package/package.json +19 -11
- package/packages/sdk/ARCHITECTURE.md +40 -36
- package/packages/sdk/package-lock.json +32 -0
- package/packages/sdk/package.json +15 -5
- package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
- package/packages/sdk/src/fingerprint.ts +0 -0
- package/packages/sdk/src/index.ts +38 -73
- package/packages/sdk/src/mcp/bin.ts +51 -0
- package/packages/sdk/src/mcp/server.ts +498 -0
- package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
- package/packages/sdk/tests/sdk.test.mjs +148 -0
- package/packages/sdk/vitest.config.ts +1 -1
- package/scripts/bh-full-e2e.mjs +166 -363
- package/scripts/check-deps.mjs +28 -46
- package/scripts/mirror-claude-md.sh +78 -0
- package/scripts/test-in-container.sh +157 -0
- package/templates/clean-state-checklist.md +3 -3
- package/templates/sprint-contract.md +2 -2
- package/bizar-dash/.bizar/activity.log +0 -3
- package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
- package/bizar-dash/.omx/state/session.json +0 -10
- package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
- package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
- package/bizar-dash/bizar-design/canvas.html +0 -281
- package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/components.css +0 -1665
- package/bizar-dash/bizar-design/components.html +0 -557
- package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/agents.html +0 -74
- package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/memory.html +0 -75
- package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
- package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/overview.html +0 -95
- package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/settings.html +0 -70
- package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/icons.svg +0 -44
- package/bizar-dash/bizar-design/index.html +0 -192
- package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/agents.html +0 -29
- package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/memory.html +0 -28
- package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
- package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/overview.html +0 -33
- package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/settings.html +0 -28
- package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/prototype.js +0 -114
- package/bizar-dash/bizar-design/tokens.css +0 -106
- package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
- package/bizar-dash/node_modules/.package-lock.json +0 -6
- package/bizar-dash/package-lock.json +0 -6
- package/bizar-dash/src/server/cline-sdk.mjs +0 -132
- package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
- package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
- package/cli/commands/cline-cmd.mjs +0 -289
- package/cli/commands/validate.test.mjs +0 -344
- package/cli/doctor.test.mjs +0 -350
- package/config/cline.json.template +0 -342
- package/packages/sdk/src/client.ts +0 -188
- package/packages/sdk/src/cline-events.ts +0 -134
- package/packages/sdk/src/cline-types.ts +0 -66
- package/packages/sdk/src/cline.ts +0 -339
- package/packages/sdk/src/errors.ts +0 -129
- package/packages/sdk/src/events.ts +0 -153
- package/packages/sdk/src/types.ts +0 -176
- package/packages/sdk/tests/client.test.ts +0 -217
- package/packages/sdk/tests/errors.test.ts +0 -108
- package/packages/sdk/tests/events.test.ts +0 -139
- package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
- package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
- package/plugins/bizar/ARCHITECTURE.md +0 -142
- package/plugins/bizar/CONSTRAINTS.md +0 -67
- package/plugins/bizar/LICENSE +0 -21
- package/plugins/bizar/README.md +0 -448
- package/plugins/bizar/index.ts +0 -872
- package/plugins/bizar/package.json +0 -39
- package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
- package/plugins/bizar/src/background-state.ts +0 -641
- package/plugins/bizar/src/background.ts +0 -1806
- package/plugins/bizar/src/cline-runner.ts +0 -203
- package/plugins/bizar/src/clineruntime.ts +0 -227
- package/plugins/bizar/src/commands-impl.ts +0 -151
- package/plugins/bizar/src/commands.ts +0 -1799
- package/plugins/bizar/src/compaction.d.mts +0 -48
- package/plugins/bizar/src/compaction.mjs +0 -192
- package/plugins/bizar/src/dashboard-client.ts +0 -233
- package/plugins/bizar/src/event-stream.ts +0 -606
- package/plugins/bizar/src/fingerprint.ts +0 -120
- package/plugins/bizar/src/handoff.ts +0 -79
- package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
- package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
- package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
- package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
- package/plugins/bizar/src/http-client.ts +0 -467
- package/plugins/bizar/src/key-rotation.ts +0 -218
- package/plugins/bizar/src/logger.ts +0 -144
- package/plugins/bizar/src/loop-engineering.ts +0 -241
- package/plugins/bizar/src/loop.ts +0 -176
- package/plugins/bizar/src/mistake-recovery.ts +0 -98
- package/plugins/bizar/src/odin.ts +0 -227
- package/plugins/bizar/src/options.ts +0 -470
- package/plugins/bizar/src/plan-fs.ts +0 -323
- package/plugins/bizar/src/reasoning-clean.ts +0 -454
- package/plugins/bizar/src/report.ts +0 -178
- package/plugins/bizar/src/research-prompt.ts +0 -35
- package/plugins/bizar/src/serve-info.ts +0 -228
- package/plugins/bizar/src/serve.ts +0 -496
- package/plugins/bizar/src/settings.ts +0 -349
- package/plugins/bizar/src/state.ts +0 -298
- package/plugins/bizar/src/tool-discipline.ts +0 -105
- package/plugins/bizar/src/tools/agent-browser.ts +0 -315
- package/plugins/bizar/src/tools/bg-collect.ts +0 -131
- package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
- package/plugins/bizar/src/tools/bg-kill.ts +0 -116
- package/plugins/bizar/src/tools/bg-pause.ts +0 -99
- package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
- package/plugins/bizar/src/tools/bg-resume.ts +0 -94
- package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
- package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
- package/plugins/bizar/src/tools/bg-status.ts +0 -130
- package/plugins/bizar/src/tools/graph-query.ts +0 -278
- package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
- package/plugins/bizar/src/tools/memory-list.ts +0 -43
- package/plugins/bizar/src/tools/memory-read.ts +0 -69
- package/plugins/bizar/src/tools/memory-search.ts +0 -47
- package/plugins/bizar/src/tools/memory-write.ts +0 -54
- package/plugins/bizar/src/tools/open-kb.ts +0 -198
- package/plugins/bizar/src/tools/plan-action.ts +0 -785
- package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
- package/plugins/bizar/src/tools/team-spawn.ts +0 -73
- package/plugins/bizar/src/tools/team-status.ts +0 -76
- package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
- package/plugins/bizar/src/trajectory.ts +0 -104
- package/plugins/bizar/tests/README.md +0 -99
- package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
- package/plugins/bizar/tests/background-state.test.ts +0 -277
- package/plugins/bizar/tests/background.test.ts +0 -402
- package/plugins/bizar/tests/block.test.ts +0 -195
- package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
- package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
- package/plugins/bizar/tests/commands-impl.test.ts +0 -316
- package/plugins/bizar/tests/commands.test.ts +0 -584
- package/plugins/bizar/tests/compaction.test.ts +0 -264
- package/plugins/bizar/tests/config.test.ts +0 -128
- package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
- package/plugins/bizar/tests/dispose.test.ts +0 -336
- package/plugins/bizar/tests/event-stream.test.ts +0 -409
- package/plugins/bizar/tests/event.test.ts +0 -262
- package/plugins/bizar/tests/fingerprint.test.ts +0 -162
- package/plugins/bizar/tests/http-client.test.ts +0 -404
- package/plugins/bizar/tests/init-helpers.test.ts +0 -203
- package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
- package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
- package/plugins/bizar/tests/key-rotation.test.ts +0 -396
- package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
- package/plugins/bizar/tests/loop.test.ts +0 -397
- package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
- package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
- package/plugins/bizar/tests/odin.test.ts +0 -125
- package/plugins/bizar/tests/options.test.ts +0 -329
- package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
- package/plugins/bizar/tests/safety.test.ts +0 -256
- package/plugins/bizar/tests/serve.test.ts +0 -339
- package/plugins/bizar/tests/settings.test.ts +0 -351
- package/plugins/bizar/tests/stall-think.test.ts +0 -750
- package/plugins/bizar/tests/state.test.ts +0 -276
- package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
- package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
- package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
- package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
- package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
- package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
- package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
- package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
- package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
- package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
- package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
- package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
- package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
- package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
- package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
- package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
- package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
- package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
- package/plugins/bizar/tsconfig.json +0 -29
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# FreeRTOS patterns
|
|
2
|
+
|
|
3
|
+
ESP-IDF v5 uses FreeRTOS. Most of these patterns are the same as FreeRTOS elsewhere; the ESP32-specific bits are task pinning, ISR rules (no blocking), and `portTICK_PERIOD_MS`.
|
|
4
|
+
|
|
5
|
+
## Task lifecycle
|
|
6
|
+
|
|
7
|
+
Create, run, delete:
|
|
8
|
+
|
|
9
|
+
```cpp
|
|
10
|
+
void acquisition_task(void *arg) {
|
|
11
|
+
while (true) {
|
|
12
|
+
// ... do work, sleep, wait on a queue ...
|
|
13
|
+
}
|
|
14
|
+
vTaskDelete(nullptr); // never reached in a normal acquisition loop
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
void start() {
|
|
18
|
+
xTaskCreatePinnedToCore(
|
|
19
|
+
acquisition_task, // task function
|
|
20
|
+
"acq", // name (shown in runtime stats)
|
|
21
|
+
4096, // stack depth in WORDS (not bytes) on ESP32
|
|
22
|
+
nullptr, // arg
|
|
23
|
+
20, // priority (0 = idle, higher = more preemptive)
|
|
24
|
+
nullptr, // optional task handle
|
|
25
|
+
1 // core ID (0 = APP CPU on classic ESP32, 1 = PRO CPU)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Notes:
|
|
31
|
+
|
|
32
|
+
- Stack depth is in **words**, not bytes. On ESP32 (32-bit) `4096` = 16 KB. Allocate generously for tasks with deep call chains; oversized stack wastes DRAM but undersized stack corrupts memory silently.
|
|
33
|
+
- Pass `nullptr` if you do not need the handle. Use the handle later for `vTaskSuspend` / `vTaskResume` / `vTaskDelete`.
|
|
34
|
+
- Pinning is mandatory for acquisition paths — non-pinned tasks can bounce between cores and lose cache locality.
|
|
35
|
+
|
|
36
|
+
`(AMS7)` AMS7 acquisition tasks run at priority 20+, pinned to core 0 (APP CPU). The PRO CPU (core 1) handles BLE/Wi-Fi by default.
|
|
37
|
+
|
|
38
|
+
## Priorities
|
|
39
|
+
|
|
40
|
+
| Range | Use for |
|
|
41
|
+
|--------|------------------------------------------------------------|
|
|
42
|
+
| 0 | Idle task only — do not use |
|
|
43
|
+
| 1–4 | Normal app tasks, command handling, BLE host |
|
|
44
|
+
| 5–19 | Latency-sensitive but not real-time (rate control, queues) |
|
|
45
|
+
| 20–24 | Real-time acquisition, time-critical ISRs |
|
|
46
|
+
|
|
47
|
+
Do not stack many tasks at priority 20+ — round-robin between them defeats the point.
|
|
48
|
+
|
|
49
|
+
## Pinning to cores
|
|
50
|
+
|
|
51
|
+
ESP32 dual-core (Xtensa LX6):
|
|
52
|
+
|
|
53
|
+
- **Core 0 (APP CPU)** — protocol stacks (Wi-Fi, BLE), low-level drivers.
|
|
54
|
+
- **Core 1 (PRO CPU)** — `app_main` runs here by default.
|
|
55
|
+
|
|
56
|
+
Pick a split that puts time-critical work on the under-used core. `xTaskCreatePinnedToCore(handle, name, stack, arg, prio, handle_out, core_id)`.
|
|
57
|
+
|
|
58
|
+
ESP32-S3 / C3 / H2 are single-core: pinning is a no-op but the API still works.
|
|
59
|
+
|
|
60
|
+
## Queues
|
|
61
|
+
|
|
62
|
+
Producer/consumer with bounded queues. Decouples ISR rate from task rate.
|
|
63
|
+
|
|
64
|
+
```cpp
|
|
65
|
+
QueueHandle_t evt_q = xQueueCreate(16, sizeof(uint32_t));
|
|
66
|
+
|
|
67
|
+
// Producer (task context)
|
|
68
|
+
uint32_t pin = read_pin();
|
|
69
|
+
xQueueSend(evt_q, &pin, pdMS_TO_TICKS(10));
|
|
70
|
+
|
|
71
|
+
// Consumer
|
|
72
|
+
uint32_t pin;
|
|
73
|
+
if (xQueueReceive(evt_q, &pin, portMAX_DELAY) == pdTRUE) {
|
|
74
|
+
handle(pin);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Use `portMAX_DELAY` only when the consumer must never return. Use `pdMS_TO_TICKS(N)` when the consumer should time out (e.g., to check a "stop" flag).
|
|
79
|
+
|
|
80
|
+
## ISR → task handoff
|
|
81
|
+
|
|
82
|
+
ISRs must not block. The standard handoff uses `xQueueSendFromISR` and the higher-priority-task-woken flag:
|
|
83
|
+
|
|
84
|
+
```cpp
|
|
85
|
+
static QueueHandle_t gpio_evt_q;
|
|
86
|
+
|
|
87
|
+
void IRAM_ATTR gpio_isr(void *arg) {
|
|
88
|
+
uint32_t pin = (uint32_t)arg;
|
|
89
|
+
BaseType_t hpw = pdFALSE;
|
|
90
|
+
xQueueSendFromISR(gpio_evt_q, &pin, &hpw);
|
|
91
|
+
if (hpw == pdTRUE) portYIELD_FROM_ISR();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
void consumer_task(void *arg) {
|
|
95
|
+
uint32_t pin;
|
|
96
|
+
while (true) {
|
|
97
|
+
if (xQueueReceive(gpio_evt_q, &pin, portMAX_DELAY) == pdTRUE) {
|
|
98
|
+
// process pin (NOT in ISR context — can block here)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Alternatives:
|
|
105
|
+
|
|
106
|
+
- `xTaskNotifyFromISR` / `xTaskNotifyWait` — single-task notifications, very fast.
|
|
107
|
+
- `xTimerPendFunctionCallFromISR` — defer a callback into the timer service task (useful for one-shot IRAM work).
|
|
108
|
+
- Direct event bits with `xEventGroupSetBitsFromISR` — broadcast to multiple waiters.
|
|
109
|
+
|
|
110
|
+
## Stream and ring buffers
|
|
111
|
+
|
|
112
|
+
For variable-length byte streams (e.g., SPI DMA into a parser):
|
|
113
|
+
|
|
114
|
+
```cpp
|
|
115
|
+
StreamBufferHandle_t sb = xStreamBufferCreate(2048, 256); // total, trigger
|
|
116
|
+
// Producer (DMA ISR)
|
|
117
|
+
xStreamBufferSendFromISR(sb, data, len, &hpw);
|
|
118
|
+
// Consumer task
|
|
119
|
+
uint8_t buf[256];
|
|
120
|
+
size_t got = xStreamBufferReceive(sb, buf, sizeof(buf), pdMS_TO_TICKS(100));
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`xRingbufferCreate` (IDF) is the lock-free variant — better for high-rate ISR streams where the producer must never wait.
|
|
124
|
+
|
|
125
|
+
## Semaphores and mutexes
|
|
126
|
+
|
|
127
|
+
```cpp
|
|
128
|
+
SemaphoreHandle_t ready = xSemaphoreCreateBinary();
|
|
129
|
+
xSemaphoreGive(ready);
|
|
130
|
+
xSemaphoreTake(ready, portMAX_DELAY);
|
|
131
|
+
|
|
132
|
+
SemaphoreHandle_t in_flight = xSemaphoreCreateCounting(4, 0); // max 4, starts empty
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Mutexes for shared resources:
|
|
136
|
+
|
|
137
|
+
```cpp
|
|
138
|
+
SemaphoreHandle_t cfg_lock = xSemaphoreCreateMutex();
|
|
139
|
+
if (xSemaphoreTake(cfg_lock, pdMS_TO_TICKS(100)) == pdTRUE) {
|
|
140
|
+
// ... access shared resource ...
|
|
141
|
+
xSemaphoreGive(cfg_lock);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Recursive mutexes** (`xSemaphoreCreateRecursiveMutex`) for code that may take the same lock twice in a call chain.
|
|
146
|
+
|
|
147
|
+
## Timers
|
|
148
|
+
|
|
149
|
+
```cpp
|
|
150
|
+
TimerHandle_t t = xTimerCreate("rate", pdMS_TO_TICKS(1000), pdTRUE, nullptr, [](TimerHandle_t x) {
|
|
151
|
+
// fired every 1000 ms; called in the timer service task (NOT ISR context)
|
|
152
|
+
});
|
|
153
|
+
xTimerStart(t, 0);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
One-shot for delayed work:
|
|
157
|
+
|
|
158
|
+
```cpp
|
|
159
|
+
TimerHandle_t oneshot = xTimerCreate("once", pdMS_TO_TICKS(50), pdFALSE, nullptr, cb);
|
|
160
|
+
xTimerStart(oneshot, 0);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Event groups
|
|
164
|
+
|
|
165
|
+
Useful when a task must wait for several subsystems to be ready before proceeding:
|
|
166
|
+
|
|
167
|
+
```cpp
|
|
168
|
+
EventGroupHandle_t eg = xEventGroupCreate();
|
|
169
|
+
xEventGroupSetBits(eg, BIT_SD_READY | BIT_BLE_READY | BIT_ACQ_READY);
|
|
170
|
+
|
|
171
|
+
EventBits_t bits = xEventGroupWaitBits(
|
|
172
|
+
eg,
|
|
173
|
+
BIT_SD_READY | BIT_BLE_READY | BIT_ACQ_READY,
|
|
174
|
+
pdFALSE, // don't clear on exit
|
|
175
|
+
pdTRUE, // wait for ALL bits
|
|
176
|
+
portMAX_DELAY
|
|
177
|
+
);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Watchdog
|
|
181
|
+
|
|
182
|
+
The IDF task watchdog resets the system if a task does not feed it within a window. Always feed:
|
|
183
|
+
|
|
184
|
+
```cpp
|
|
185
|
+
void heavy_task(void *arg) {
|
|
186
|
+
while (true) {
|
|
187
|
+
// chunk of work
|
|
188
|
+
vTaskDelay(pdMS_TO_TICKS(10)); // yields — watchdog is fed by idle
|
|
189
|
+
// OR if you spin:
|
|
190
|
+
// vTaskDelay(1); // minimum yield
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
If a task really must spin for >1 second (rare), subscribe it to the watchdog and call `esp_task_wdt_reset()` periodically. Long ISR-disabled windows also trip the watchdog — keep them < one tick (`portTICK_PERIOD_MS` = 10 ms by default).
|
|
196
|
+
|
|
197
|
+
## portTICK_PERIOD_MS
|
|
198
|
+
|
|
199
|
+
Always convert via `pdMS_TO_TICKS(ms)`:
|
|
200
|
+
|
|
201
|
+
```cpp
|
|
202
|
+
vTaskDelay(pdMS_TO_TICKS(100)); // 100 ms regardless of tick rate
|
|
203
|
+
xQueueReceive(q, &x, pdMS_TO_TICKS(50));
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Never multiply by hand (`ms * portTICK_PERIOD_MS`) — it lies when the tick rate changes.
|
|
207
|
+
|
|
208
|
+
## Common pitfalls
|
|
209
|
+
|
|
210
|
+
- **Blocking in an ISR.** Symptom: hard fault or watchdog reset. Fix: defer to a task via `xQueueSendFromISR` / `xTaskNotifyFromISR`.
|
|
211
|
+
- **Stack too small.** Symptom: random crashes after a few minutes, often deep in call chains. Fix: bump stack depth, or enable `CONFIG_COMPILER_STACK_CHECK_MODE_NORM` to catch overflows at runtime.
|
|
212
|
+
- **Priority inversion.** Symptom: low-priority task holds a mutex, blocks a high-priority task. Fix: `xSemaphoreCreateRecursiveMutex` and keep critical sections short.
|
|
213
|
+
- **Forgetting `portYIELD_FROM_ISR`.** Symptom: producer wakes the consumer but the consumer doesn't run until the next tick. Fix: check the `xHigherPriorityTaskWoken` returned from `*FromISR` and yield.
|
|
214
|
+
- **Non-pinned tasks bouncing cores.** Symptom: jittery timing, occasional cache misses. Fix: pin acquisition and protocol tasks explicitly.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Host-side tests
|
|
2
|
+
|
|
3
|
+
ESP-IDF firmware that depends on FreeRTOS, drivers, and NVS cannot run on the host. But policy modules, payload encoders/decoders, pure-C++ algorithms, and protocol parsers can — and should — be unit-tested on the host with a normal C++ toolchain.
|
|
4
|
+
|
|
5
|
+
`(AMS7)` AMS7's host tests are deliberately lightweight: one `.cpp` test file + one `run_*_test.sh` shell wrapper. No CMake host build, no fakes library, no GoogleTest. The whole test is `g++ -std=c++17 ... && ./a.out`.
|
|
6
|
+
|
|
7
|
+
For larger projects with GoogleTest / Catch2 / fakes, see the **`cpp-testing`** skill.
|
|
8
|
+
|
|
9
|
+
## AMS7 pattern (test + run script)
|
|
10
|
+
|
|
11
|
+
A typical test file in `tests/connectivity/`:
|
|
12
|
+
|
|
13
|
+
```cpp
|
|
14
|
+
// tests/connectivity/espnow_imu_frame_test.cpp
|
|
15
|
+
#include <cassert>
|
|
16
|
+
#include <cstdio>
|
|
17
|
+
|
|
18
|
+
#include "espnow_imu_frame.hpp"
|
|
19
|
+
|
|
20
|
+
int main() {
|
|
21
|
+
core_espnow_imu_frame_v1_t frame = {};
|
|
22
|
+
espnow_imu_frame_init(&frame, 0x1234U, 9U, 55U,
|
|
23
|
+
1, -2, 3, -4, 5, -6);
|
|
24
|
+
|
|
25
|
+
assert(frame.magic == CORE_ESPNOW_IMU_MAGIC);
|
|
26
|
+
assert(frame.version == CORE_ESPNOW_IMU_VERSION);
|
|
27
|
+
assert(frame.frame_type == CORE_ESPNOW_FRAME_IMU_RAW);
|
|
28
|
+
assert(frame.id == 0x1234U);
|
|
29
|
+
assert(frame.seq == 9U);
|
|
30
|
+
assert(frame.age_ms == 55U);
|
|
31
|
+
assert(frame.accel_x == 1);
|
|
32
|
+
assert(frame.accel_y == -2);
|
|
33
|
+
assert(frame.accel_z == 3);
|
|
34
|
+
assert(frame.gyro_x == -4);
|
|
35
|
+
assert(frame.gyro_y == 5);
|
|
36
|
+
assert(frame.gyro_z == -6);
|
|
37
|
+
|
|
38
|
+
std::puts("espnow_imu_frame_test: ok");
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
And the wrapper `tests/connectivity/run_espnow_imu_frame_test.sh`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
#!/usr/bin/env bash
|
|
47
|
+
set -euo pipefail
|
|
48
|
+
|
|
49
|
+
g++ -std=c++17 \
|
|
50
|
+
tests/connectivity/espnow_imu_frame_test.cpp \
|
|
51
|
+
main/connectivity/espnow_imu_frame.cpp \
|
|
52
|
+
-I main/connectivity \
|
|
53
|
+
-o /tmp/espnow_imu_frame_test
|
|
54
|
+
|
|
55
|
+
/tmp/espnow_imu_frame_test
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Run it:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bash tests/connectivity/run_espnow_imu_frame_test.sh
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The wrapper does three things: compile, link, run. Add `g++` flags (`-Wall -Wextra -Werror`) for stricter checking.
|
|
65
|
+
|
|
66
|
+
## What can be host-tested
|
|
67
|
+
|
|
68
|
+
- **Packed structs and frame encoders** — `espnow_*_frame_*`, `gateway_command_*`, `marker_*`. Pure data marshalling.
|
|
69
|
+
- **Policy modules** — `connectivity_mode_policy`, `electrode_detach_gate`, `acquisition_command_policy`. Pure decision logic.
|
|
70
|
+
- **Pure algorithms** — `hr_fused`, `resp_fallback`, `summary_metrics`. Make sure they don't `malloc` or call FreeRTOS and they're trivially host-testable.
|
|
71
|
+
- **State machines** — anything that's a transition table plus a few event handlers.
|
|
72
|
+
|
|
73
|
+
## What must NOT be host-tested
|
|
74
|
+
|
|
75
|
+
- Anything that includes `<freertos/FreeRTOS.h>`.
|
|
76
|
+
- Anything that includes `esp_log.h` (unless you fake it).
|
|
77
|
+
- Anything that includes driver headers (`driver/spi_master.h`, `driver/i2c.h`).
|
|
78
|
+
- Anything that pulls in NVS, BLE, Wi-Fi, ESP-NOW stacks.
|
|
79
|
+
|
|
80
|
+
If a header you want to test transitively includes one of these, factor the pure logic out into a separate translation unit. The split is usually: `policy.hpp/cpp` for pure logic, `policy_runtime.cpp` for the FreeRTOS-aware glue.
|
|
81
|
+
|
|
82
|
+
## Fakes for FreeRTOS (when you need them)
|
|
83
|
+
|
|
84
|
+
If you have a real CMake host project (not the AMS7 minimal pattern) and want to test code that touches FreeRTOS, use the **`cpp-testing`** skill's fakes recipe. The minimum useful fakes:
|
|
85
|
+
|
|
86
|
+
- `fake_freertos.h` — declares the FreeRTOS API surface used by the code under test, with hooks (`xQueueCreate` returns a recorded handle, etc.).
|
|
87
|
+
- `fake_log.h` — empty `ESP_LOG*` macros or a recorded message list.
|
|
88
|
+
|
|
89
|
+
Keep fakes local to the test, not in `main/`. Use `BUILD_ONLY_FAKES` or a separate `tests/host/` CMake target.
|
|
90
|
+
|
|
91
|
+
## CMake host project (alternative to per-test shell scripts)
|
|
92
|
+
|
|
93
|
+
For larger suites:
|
|
94
|
+
|
|
95
|
+
```cmake
|
|
96
|
+
# tests/host/CMakeLists.txt
|
|
97
|
+
cmake_minimum_required(VERSION 3.16)
|
|
98
|
+
project(ams7_host_tests CXX)
|
|
99
|
+
|
|
100
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
101
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
102
|
+
|
|
103
|
+
add_executable(test_espnow_imu
|
|
104
|
+
../../main/connectivity/espnow_imu_frame.cpp
|
|
105
|
+
espnow_imu_frame_test.cpp
|
|
106
|
+
)
|
|
107
|
+
target_include_directories(test_espnow_imu PRIVATE
|
|
108
|
+
${CMAKE_SOURCE_DIR}/../../main/connectivity
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
cmake -S tests/host -B tests/host/build
|
|
114
|
+
cmake --build tests/host/build
|
|
115
|
+
./tests/host/build/test_espnow_imu
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Tradeoffs vs the AMS7 minimal pattern:
|
|
119
|
+
|
|
120
|
+
| Aspect | AMS7 shell wrapper | CMake host project |
|
|
121
|
+
|------------------|---------------------------------|---------------------------|
|
|
122
|
+
| Setup cost | Zero — one shell script per test| One CMakeLists to maintain |
|
|
123
|
+
| Linking firmware | Direct `g++ ... file.cpp` | Same, via CMake rules |
|
|
124
|
+
| Adding fakes | None | Add a `fake/` directory |
|
|
125
|
+
| Test discovery | Manual | `ctest` |
|
|
126
|
+
| CI integration | `find tests -name run_*.sh` | `ctest --output-on-failure` |
|
|
127
|
+
| Build parallelism| Sequential | Parallel via `cmake --build` |
|
|
128
|
+
|
|
129
|
+
Both are valid. AMS7 picks the shell wrapper because every test is one file and one assertion set — `ctest` overhead is not worth it.
|
|
130
|
+
|
|
131
|
+
## Tests vs fixtures
|
|
132
|
+
|
|
133
|
+
AMS7 has `tests/fixtures/` for replay inputs (recorded sensor traces used to drive host tests):
|
|
134
|
+
|
|
135
|
+
```cpp
|
|
136
|
+
// tests/fixtures/replay/ecg_2024-09-12.bin — raw bytes recorded from a real run
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Load fixtures in tests via `std::ifstream` rather than copy-pasting bytes into the test source.
|
|
140
|
+
|
|
141
|
+
## Common pitfalls
|
|
142
|
+
|
|
143
|
+
- **Including `<esp_log.h>` from a header that's host-tested.** Fix: forward-declare the log macros in the header, include the real one only in `.cpp`. Or include the AMS7 fake `tests/support/host_include/esp_log.h` if one exists.
|
|
144
|
+
- **`malloc` in pure logic.** Symptom: host test runs fine but firmware crashes from fragmentation. Fix: allocate in the wrapper, pass a buffer in.
|
|
145
|
+
- **Globals with static initialization.** Symptom: works on host, fails on target because init order is different. Fix: prefer explicit `init()` calls.
|
|
146
|
+
- **Asserting on floating-point equality.** Use a tolerance: `assert(std::abs(a - b) < 1e-3)`.
|
|
147
|
+
- **Forgetting `-Werror` in CI.** Compile-only warnings become ship-time bugs. The AMS7 host tests are silent on warnings by default; consider adding `-Wall -Wextra` to your shell wrappers.
|
|
148
|
+
- **Test passes on host, fails on firmware.** The two are usually equivalent for pure logic, but always cross-check with a firmware-side integration test (a debug print, a recorded trace, or an ESP-NOW roundtrip).
|
|
149
|
+
|
|
150
|
+
## When to grow beyond the minimal pattern
|
|
151
|
+
|
|
152
|
+
Stay with the shell wrapper while:
|
|
153
|
+
|
|
154
|
+
- Test count is < ~30.
|
|
155
|
+
- Each test is one `.cpp` plus one shell script.
|
|
156
|
+
- No fakes needed.
|
|
157
|
+
- CI just iterates `tests/ -name run_*.sh`.
|
|
158
|
+
|
|
159
|
+
Migrate to a CMake host project when:
|
|
160
|
+
|
|
161
|
+
- You need `ctest` for CI parallelism and reporting.
|
|
162
|
+
- You need fakes (FreeRTOS, log, drivers).
|
|
163
|
+
- A test needs to link multiple firmware modules together.
|
|
164
|
+
- You want fixtures automatically discovered.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# idf.py commands
|
|
2
|
+
|
|
3
|
+
`idf.py` is the single entry point to ESP-IDF v5. All commands assume the IDF environment is sourced:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
source esp/esp-idf/export.sh
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
If `idf.py` is not on PATH, `scripts/idf_env.sh` will print the source line and tell you whether the env is healthy.
|
|
10
|
+
|
|
11
|
+
## Core workflow
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
idf.py build # compile (incremental)
|
|
15
|
+
idf.py -p /dev/ttyUSB0 flash # write image to board
|
|
16
|
+
idf.py -p /dev/ttyUSB0 monitor # serial console (Ctrl-] to exit)
|
|
17
|
+
idf.py -p /dev/ttyUSB0 flash monitor # flash then monitor in one shot
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`-p` is the serial port. Linux: `/dev/ttyUSB0` or `/dev/ttyACM0`. macOS: `/dev/cu.usbserial-*`. Windows: `COM3`.
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
idf.py menuconfig # TUI Kconfig editor
|
|
26
|
+
idf.py menuconfig --no-target # don't ask to set target
|
|
27
|
+
idf.py save-defconfig # write minimal defconfig from current settings
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`menuconfig` writes the result to `sdkconfig`. To apply a layered profile:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
idf.py -B build_espnow_flow -C . \
|
|
34
|
+
--sdkconfig sdkconfig.espnow_flow \
|
|
35
|
+
build flash
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The `-B build_<name>` puts the build output in `build_<name>/`, leaving the default `build/` clean.
|
|
39
|
+
|
|
40
|
+
## Build inspection
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
idf.py size # text: app partition + IRAM + DRAM
|
|
44
|
+
idf.py size --format json # machine-readable for tooling
|
|
45
|
+
idf.py size --format csv # spreadsheet-friendly
|
|
46
|
+
idf.py size --output-file size.json
|
|
47
|
+
idf.py size-components # per-component breakdown
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`idf.py size` exit code is 0 on success regardless of size; size policy lives in project-specific tools.
|
|
51
|
+
|
|
52
|
+
## Cleaning
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
idf.py clean # remove build artifacts but keep config
|
|
56
|
+
idf.py fullclean # remove build/ AND sdkconfig (then menuconfig again)
|
|
57
|
+
idf.py -B build_espnow_flow clean # clean a specific build dir
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`fullclean` is destructive — it deletes your local `sdkconfig` overrides. Commit your `sdkconfig` and any profile files first.
|
|
61
|
+
|
|
62
|
+
## Target and project
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
idf.py set-target esp32 # esp32 / esp32s2 / esp32s3 / esp32c3 / esp32h2
|
|
66
|
+
idf.py create-project foo # scaffold a new project from a template
|
|
67
|
+
idf.py add-dependency "owner/repo^1.2.3" # pull into managed_components/
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
After `set-target`, ESP-IDF regenerates component configs — clean build artifacts:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
idf.py set-target esp32s3 && idf.py build
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Partition table
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
idf.py partition-table # regenerate partition_table/*.bin from partitions.csv
|
|
80
|
+
idf.py erase-flash # erase entire flash (use with care)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`partitions.csv` is at the project root; `idf.py menuconfig → Partition Table` selects which CSV to use. Common layouts:
|
|
84
|
+
|
|
85
|
+
- `partitions_singleapp.csv` — single OTA-less app partition
|
|
86
|
+
- `partitions_two_ota.csv` — A/B OTA slots (default for OTA-enabled projects)
|
|
87
|
+
- A custom CSV — declare `app`, `data`, `nvs`, `phy_init`, `storage` partitions with explicit sizes
|
|
88
|
+
|
|
89
|
+
`(AMS7)` The AMS7 partition table reserves a large `storage` partition for SD-aware OTA staging.
|
|
90
|
+
|
|
91
|
+
## Monitor filters
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
idf.py -p /dev/ttyUSB0 monitor --print-filter="*:I" # only INFO and above
|
|
95
|
+
idf.py monitor --print-filter="ams7driver:I espnow_summary:W" # per-tag levels
|
|
96
|
+
idf.py monitor --elf <elf_path> # decode panic backtraces
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`-d` disables line-ending conversion (binary output). `-t` adds a timestamp prefix.
|
|
100
|
+
|
|
101
|
+
Inside the monitor, useful key bindings:
|
|
102
|
+
|
|
103
|
+
- `Ctrl-]` — exit
|
|
104
|
+
- `Ctrl-T` — toggle menu (send break, change filter, etc.)
|
|
105
|
+
|
|
106
|
+
## Build flags
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
idf.py -DCMAKE_BUILD_TYPE=Debug build # Debug / Release / RelWithDebInfo / MinSizeRel
|
|
110
|
+
idf.py -DCONFIG_COMPILER_OPTIMIZATION_PERF=y build # enable IDF performance optimizations
|
|
111
|
+
idf.py -DSDKCONFIG_DEFAULTS=sdkconfig.espnow_flow build
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`-DSDKCONFIG_DEFAULTS` is equivalent to the `--sdkconfig` CLI flag and is useful for CI.
|
|
115
|
+
|
|
116
|
+
## OpenOCD / debugging
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
idf.py openocd # start OpenOCD for JTAG debugging
|
|
120
|
+
idf.py gdb # start xtensa-esp32-elf-gdb
|
|
121
|
+
idf.py gdbgui # GDB with a frontend
|
|
122
|
+
idf.py app-flash # flash only the app partition
|
|
123
|
+
idf.py bootloader-flash # flash only the bootloader
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
GDB requires an `openocd` server on the default port (3333).
|
|
127
|
+
|
|
128
|
+
## OTA
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
idf.py app # build the app, ready for OTA push
|
|
132
|
+
idf.py ota # ... or `idf.py app` then push via HTTP
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
For SD-card OTA staging: copy `build/<project>.bin` to the SD card under the OTA path your bootloader expects, then reboot.
|
|
136
|
+
|
|
137
|
+
## Useful exit-code patterns
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# CI: build, then size check
|
|
141
|
+
idf.py build && idf.py size
|
|
142
|
+
|
|
143
|
+
# AMS7: full CI gate
|
|
144
|
+
source esp/esp-idf/export.sh
|
|
145
|
+
idf.py build
|
|
146
|
+
tools/check_idf_size_budget.py
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`scripts/size_check.sh` wraps the AMS7-specific size policy and falls back to `idf.py size` when run in a non-AMS7 project.
|
|
150
|
+
|
|
151
|
+
## Common pitfalls
|
|
152
|
+
|
|
153
|
+
- **Forgot to source the env.** Symptom: `idf.py: command not found`. Fix: `source esp/esp-idf/export.sh` per shell session.
|
|
154
|
+
- **Wrong target.** Symptom: linker errors about `esp_image_header_t` size mismatches or missing `esp_hw_support`. Fix: `idf.py set-target esp32` then rebuild.
|
|
155
|
+
- **`sdkconfig` drift.** Symptom: subtle behavior changes after a `git pull`. Fix: `idf.py menuconfig` to re-resolve, or `git checkout sdkconfig` and re-apply.
|
|
156
|
+
- **`-B build_<flow>` left stale.** Symptom: build picks up old sources. Fix: `idf.py -B build_<flow> fullclean`.
|
|
157
|
+
- **Monitor hangs on macOS.** Use `/dev/cu.usbserial-*` not `/dev/tty.usbserial-*` (the `tty.` node blocks open while the driver holds it).
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Kconfig
|
|
2
|
+
|
|
3
|
+
Kconfig is the build-time configuration system ESP-IDF inherits from the Linux kernel. Options live in `Kconfig` files, are presented through `idf.py menuconfig`, and resolve to `CONFIG_*` macros visible in C/C++.
|
|
4
|
+
|
|
5
|
+
## Where Kconfig files live
|
|
6
|
+
|
|
7
|
+
ESP-IDF automatically sources a `Kconfig` file from every registered component. The top-level `Kconfig.projbuild` is required and seeds the project menu. Conventions:
|
|
8
|
+
|
|
9
|
+
- `main/Kconfig` — app-level options. Always include `main "AMS7 Project Options"` style menus.
|
|
10
|
+
- `components/<name>/Kconfig` — component-private options; only visible if the component is included in the build.
|
|
11
|
+
- `Kconfig.projbuild` — root-level options that gate top-of-tree decisions.
|
|
12
|
+
|
|
13
|
+
`(AMS7)` AMS7 puts its entire menu under `main/Kconfig` (single file, ~430 lines), with the menu title `"AMS7 Project Options"`. Every project-defined option uses the `AMS7_*` prefix.
|
|
14
|
+
|
|
15
|
+
## Adding a simple bool option
|
|
16
|
+
|
|
17
|
+
```kconfig
|
|
18
|
+
menu "Connectivity Workflow"
|
|
19
|
+
|
|
20
|
+
config AMS7_SUMMARY_ENABLE
|
|
21
|
+
bool "Enable ESP-NOW summary workflow"
|
|
22
|
+
default n
|
|
23
|
+
help
|
|
24
|
+
Master switch for the recording workflow that starts with BLE
|
|
25
|
+
control and then switches to ESP-NOW summary mode after
|
|
26
|
+
acquisition begins. Keep disabled to preserve the BLE-only
|
|
27
|
+
workflow.
|
|
28
|
+
|
|
29
|
+
endmenu
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The `CONFIG_AMS7_SUMMARY_ENABLE` macro is then visible everywhere in C/C++:
|
|
33
|
+
|
|
34
|
+
```cpp
|
|
35
|
+
#if CONFIG_AMS7_SUMMARY_ENABLE
|
|
36
|
+
init_espnow_summary();
|
|
37
|
+
#endif
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Types
|
|
41
|
+
|
|
42
|
+
| Type | C macro | Notes |
|
|
43
|
+
|-------------|--------------------------------------|----------------------------------------|
|
|
44
|
+
| `bool` | `CONFIG_FOO` (1 or undefined) | `default y` or `default n` |
|
|
45
|
+
| `int` | `CONFIG_FOO` (int literal) | `range MIN MAX` is recommended |
|
|
46
|
+
| `hex` | `CONFIG_FOO` (hex literal) | Useful for bitmasks and addresses |
|
|
47
|
+
| `string` | `CONFIG_FOO` (string literal) | `default "literal"` |
|
|
48
|
+
| `choice` | selects one of several values | Use for mutually-exclusive options |
|
|
49
|
+
|
|
50
|
+
```kconfig
|
|
51
|
+
config AMS7_HR_HOLD_MS
|
|
52
|
+
int "Hold time for fused HR before fallback (ms)"
|
|
53
|
+
depends on AMS7_VITALS_ENABLE
|
|
54
|
+
range 0 60000
|
|
55
|
+
default 10000
|
|
56
|
+
help
|
|
57
|
+
How long to keep reporting fused HR after the fused pipeline
|
|
58
|
+
reports a confident beat, before falling back to the simple
|
|
59
|
+
backend. 0 disables the hold.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
In code:
|
|
63
|
+
|
|
64
|
+
```cpp
|
|
65
|
+
#if CONFIG_AMS7_HR_HOLD_MS > 0
|
|
66
|
+
const TickType_t kHoldTicks = pdMS_TO_TICKS(CONFIG_AMS7_HR_HOLD_MS);
|
|
67
|
+
#endif
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`menuconfig` values are stored in `sdkconfig` as `CONFIG_<NAME>=<value>` lines. `idf.py menuconfig` is the editor.
|
|
71
|
+
|
|
72
|
+
## Dependencies and implications
|
|
73
|
+
|
|
74
|
+
```kconfig
|
|
75
|
+
config AMS7_BLE_VITALS_ENABLE
|
|
76
|
+
bool "Enable custom BLE vitals characteristic"
|
|
77
|
+
depends on AMS7_VITALS_ENABLE
|
|
78
|
+
default y
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- `depends on AMS7_VITALS_ENABLE` — option is **invisible** unless `AMS7_VITALS_ENABLE=y`. Selecting it auto-selects the dep.
|
|
82
|
+
- `select AMS7_ESPNOW_ENABLE` — when **this** option is enabled, force `AMS7_ESPNOW_ENABLE=y`.
|
|
83
|
+
- `imply AMS7_ESPNOW_LIVE_ECG_ENABLE` — when **this** option is enabled, set `AMS7_ESPNOW_LIVE_ECG_ENABLE=y` unless the user explicitly disabled it (softer than `select`).
|
|
84
|
+
|
|
85
|
+
`select` chains can cause cycles if used carelessly — prefer `depends on` for prerequisites.
|
|
86
|
+
|
|
87
|
+
## Ranges
|
|
88
|
+
|
|
89
|
+
```kconfig
|
|
90
|
+
config AMS7_ESPNOW_WIFI_CHANNEL
|
|
91
|
+
int "ESP-NOW Wi-Fi channel"
|
|
92
|
+
range 1 13
|
|
93
|
+
default 6
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The value is validated by menuconfig; `range` rejects out-of-range entries.
|
|
97
|
+
|
|
98
|
+
## Choices
|
|
99
|
+
|
|
100
|
+
```kconfig
|
|
101
|
+
choice AMS7_HR_BACKEND
|
|
102
|
+
prompt "Heart-rate backend"
|
|
103
|
+
default AMS7_HR_BACKEND_FUSED
|
|
104
|
+
depends on AMS7_VITALS_ENABLE
|
|
105
|
+
|
|
106
|
+
config AMS7_HR_BACKEND_SIMPLE
|
|
107
|
+
bool "Simple R-peak detector"
|
|
108
|
+
|
|
109
|
+
config AMS7_HR_BACKEND_FUSED
|
|
110
|
+
bool "Fused multi-source pipeline"
|
|
111
|
+
|
|
112
|
+
endchoice
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Only one of the listed `config`s can be `y` at a time. Use `# CONFIG_AMS7_HR_BACKEND_FUSED is not set` to switch.
|
|
116
|
+
|
|
117
|
+
## Sourcing custom Kconfig files
|
|
118
|
+
|
|
119
|
+
In a component's top-level `Kconfig` (sourced automatically), include sub-files:
|
|
120
|
+
|
|
121
|
+
```kconfig
|
|
122
|
+
mainmenu "My Component"
|
|
123
|
+
|
|
124
|
+
menu "Sensor Options"
|
|
125
|
+
source "Kconfig.sensor"
|
|
126
|
+
endmenu
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Or in `CMakeLists.txt`, register the file as part of the component:
|
|
130
|
+
|
|
131
|
+
```cmake
|
|
132
|
+
idf_component_register(
|
|
133
|
+
...
|
|
134
|
+
KCONFIG
|
|
135
|
+
"Kconfig"
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
For project-wide overlays, create `sdkconfig.espnow_flow` (or similar) and pass `--sdkconfig` to `idf.py`. Layers are applied in order: defaults, then `sdkconfig`, then any `--sdkconfig` files.
|
|
140
|
+
|
|
141
|
+
## Help text
|
|
142
|
+
|
|
143
|
+
Always include a `help` block. menuconfig shows it on the option's help line; the project documentation pulls it from `Kconfig` when generating reference. Keep it under ~10 lines.
|
|
144
|
+
|
|
145
|
+
## AMS7 conventions (project-specific)
|
|
146
|
+
|
|
147
|
+
- Prefix every project-defined option with `AMS7_`. Never use `CONFIG_FOO` for an AMS7-introduced symbol.
|
|
148
|
+
- Group options by feature in `menu "..."` blocks. AMS7 groups: Connectivity Workflow, Vitals, ESP-NOW, Logging, etc.
|
|
149
|
+
- Default to `n` for any feature that increases IRAM/flash — acquisition builds are size-sensitive.
|
|
150
|
+
- For "trial debug" toggles, name them `*_TRIAL_DEBUG_LOG_ENABLE` and gate `ESP_LOG*` calls behind them — never compile trial-debug logs into release by default.
|
|
151
|
+
- Add a `help` block on every option. AMS7 reviewers check for missing help text.
|
|
152
|
+
|
|
153
|
+
## Common pitfalls
|
|
154
|
+
|
|
155
|
+
- **Forgetting `default`.** menuconfig prompts for a value on first use; this is annoying. Always set a sensible default.
|
|
156
|
+
- **`select` cycle.** `A select B; B select A` causes menuconfig to error. Use `depends on` instead.
|
|
157
|
+
- **Component Kconfig included in disabled component.** If a component's Kconfig has options, that component must be discoverable. Check `EXTRA_COMPONENT_DIRS` in `CMakeLists.txt`.
|
|
158
|
+
- **Renaming an option without a migration.** Renaming `AMS7_X` to `AMS7_Y` leaves `sdkconfig` referring to the old name. `menuconfig` will silently drop the new option. Fix: add a `config AMS7_Y` with `default AMS7_X` then remove `AMS7_X`.
|
|
159
|
+
- **`range` on a `bool`.** Doesn't make sense — Kconfig will refuse. Use a `choice` instead.
|