@typecad/framework-zephyr 1.0.0-alpha.16 → 1.0.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/LICENSE +202 -21
  2. package/README.md +49 -87
  3. package/dist/as-built.d.ts +2 -2
  4. package/dist/as-built.js +2 -2
  5. package/dist/audit.d.ts +111 -0
  6. package/dist/audit.js +416 -0
  7. package/dist/boardgen.d.ts +1 -9
  8. package/dist/boardgen.js +288 -47
  9. package/dist/chips/resolve.js +20 -0
  10. package/dist/chips/types.d.ts +22 -1
  11. package/dist/debug-codegen.js +1 -1
  12. package/dist/display/bindings.d.ts +55 -0
  13. package/dist/display/bindings.js +316 -0
  14. package/dist/display/gfx.d.ts +2 -3
  15. package/dist/display/gfx.js +166 -154
  16. package/dist/display/index.js +20 -1
  17. package/dist/display/mipi-dbi-host.d.ts +9 -0
  18. package/dist/display/mipi-dbi-host.js +174 -0
  19. package/dist/display/profiles.d.ts +109 -4
  20. package/dist/display/profiles.js +270 -7
  21. package/dist/display/touch-adapter.js +119 -49
  22. package/dist/display/ui-adapter-eink.d.ts +2 -0
  23. package/dist/display/ui-adapter-eink.js +4 -0
  24. package/dist/display/ui-adapter-gray.d.ts +8 -0
  25. package/dist/display/ui-adapter-gray.js +170 -0
  26. package/dist/display/ui-adapter-mono.d.ts +13 -0
  27. package/dist/display/ui-adapter-mono.js +230 -0
  28. package/dist/display/ui-adapter-native.d.ts +10 -0
  29. package/dist/display/ui-adapter-native.js +295 -0
  30. package/dist/display/ui-adapter-shared.d.ts +11 -0
  31. package/dist/display/ui-adapter-shared.js +122 -0
  32. package/dist/display/ui-adapter.js +510 -558
  33. package/dist/doctor.js +4 -4
  34. package/dist/dt-config/custom-board.js +2 -2
  35. package/dist/dt-config/kconfig.d.ts +62 -1
  36. package/dist/dt-config/kconfig.js +141 -38
  37. package/dist/dt-config/overlay.d.ts +15 -2
  38. package/dist/dt-config/overlay.js +433 -18
  39. package/dist/framework.manifest.d.ts +10 -4
  40. package/dist/framework.manifest.js +133 -17
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.js +14 -6
  43. package/dist/licenses.d.ts +2 -2
  44. package/dist/licenses.js +13 -92
  45. package/dist/lowering/can.d.ts +25 -0
  46. package/dist/lowering/can.js +97 -0
  47. package/dist/lowering/clock.d.ts +17 -0
  48. package/dist/lowering/clock.js +58 -0
  49. package/dist/lowering/fs.js +1 -1
  50. package/dist/lowering/gpio.js +0 -32
  51. package/dist/lowering/hid.d.ts +27 -0
  52. package/dist/lowering/hid.js +244 -0
  53. package/dist/lowering/http.js +264 -32
  54. package/dist/lowering/i2c.d.ts +8 -0
  55. package/dist/lowering/i2c.js +137 -5
  56. package/dist/lowering/i2s.d.ts +27 -0
  57. package/dist/lowering/i2s.js +98 -0
  58. package/dist/lowering/index.d.ts +9 -1
  59. package/dist/lowering/index.js +25 -1
  60. package/dist/lowering/interrupts.js +6 -0
  61. package/dist/lowering/matrix.d.ts +15 -0
  62. package/dist/lowering/matrix.js +63 -0
  63. package/dist/lowering/mqtt.js +110 -8
  64. package/dist/lowering/power.d.ts +3 -2
  65. package/dist/lowering/power.js +20 -45
  66. package/dist/lowering/pwm.js +25 -0
  67. package/dist/lowering/sensor.d.ts +2 -2
  68. package/dist/lowering/sensor.js +8 -4
  69. package/dist/lowering/strip.d.ts +16 -0
  70. package/dist/lowering/strip.js +70 -0
  71. package/dist/lowering/thread.js +5 -1
  72. package/dist/lowering/trace.d.ts +44 -0
  73. package/dist/lowering/trace.js +239 -0
  74. package/dist/lowering/uart.js +6 -1
  75. package/dist/lowering/usb.d.ts +3 -1
  76. package/dist/lowering/usb.js +16 -13
  77. package/dist/lowering/wdt.js +2 -29
  78. package/dist/sbom.d.ts +181 -0
  79. package/dist/sbom.js +901 -0
  80. package/dist/sdk/board-catalog-sync.d.ts +1 -3
  81. package/dist/sdk/board-catalog-sync.js +4 -10
  82. package/dist/strategy.d.ts +82 -46
  83. package/dist/strategy.js +639 -182
  84. package/dist/tmp-probe.d.ts +2 -0
  85. package/dist/tmp-probe.js +9 -0
  86. package/dist/toolchain/debug-config.d.ts +50 -90
  87. package/dist/toolchain/debug-config.js +239 -510
  88. package/dist/toolchain/env-check.d.ts +1 -3
  89. package/dist/toolchain/env-check.js +2 -7
  90. package/dist/toolchain/index.d.ts +28 -3
  91. package/dist/toolchain/index.js +498 -62
  92. package/dist/toolchain/runners.d.ts +16 -0
  93. package/dist/toolchain/runners.js +75 -0
  94. package/dist/toolchain/scaffold.d.ts +5 -2
  95. package/dist/toolchain/scaffold.js +79 -15
  96. package/dist/toolchain/west-discover.d.ts +6 -0
  97. package/dist/toolchain/west-discover.js +36 -13
  98. package/dist/toolchain/west-spawn.js +8 -2
  99. package/dist/west-inventory.d.ts +25 -0
  100. package/dist/west-inventory.js +97 -0
  101. package/installer/README.md +328 -328
  102. package/installer/install.sh +2 -2
  103. package/installer/templates/project/.typecad/activate-zephyr.ps1 +1 -1
  104. package/installer/templates/project/.typecad/activate-zephyr.sh +1 -1
  105. package/installer/templates/project/.vscode/settings.json +1 -1
  106. package/installer/templates/project/README.md +2 -2
  107. package/package.json +5 -5
  108. package/src/as-built.ts +206 -206
  109. package/src/audit.ts +529 -0
  110. package/src/boardgen.ts +265 -50
  111. package/src/chips/resolve.ts +21 -0
  112. package/src/chips/types.ts +10 -1
  113. package/src/display/bindings.ts +347 -0
  114. package/src/display/gfx.ts +318 -306
  115. package/src/display/index.ts +87 -70
  116. package/src/display/mipi-dbi-host.ts +183 -0
  117. package/src/display/profiles.ts +458 -139
  118. package/src/display/touch-adapter.ts +119 -49
  119. package/src/display/ui-adapter-eink.ts +13 -0
  120. package/src/display/ui-adapter-gray.ts +178 -0
  121. package/src/display/ui-adapter-mono.ts +238 -0
  122. package/src/display/ui-adapter-native.ts +304 -0
  123. package/src/display/ui-adapter-shared.ts +125 -0
  124. package/src/display/ui-adapter.ts +732 -781
  125. package/src/doctor.ts +4 -4
  126. package/src/dt-config/custom-board.ts +2 -2
  127. package/src/dt-config/kconfig.ts +647 -505
  128. package/src/dt-config/overlay.ts +1475 -1058
  129. package/src/framework.manifest.ts +659 -535
  130. package/src/index.ts +16 -6
  131. package/src/licenses.ts +346 -425
  132. package/src/lowering/can.ts +140 -0
  133. package/src/lowering/clock.ts +91 -0
  134. package/src/lowering/fs.ts +135 -135
  135. package/src/lowering/gpio.ts +0 -33
  136. package/src/lowering/hid.ts +261 -0
  137. package/src/lowering/http.ts +264 -32
  138. package/src/lowering/i2c.ts +142 -5
  139. package/src/lowering/i2s.ts +143 -0
  140. package/src/lowering/index.ts +18 -1
  141. package/src/lowering/interrupts.ts +6 -0
  142. package/src/lowering/matrix.ts +70 -0
  143. package/src/lowering/mqtt.ts +109 -8
  144. package/src/lowering/power.ts +41 -0
  145. package/src/lowering/pwm.ts +192 -167
  146. package/src/lowering/sensor.ts +159 -155
  147. package/src/lowering/strip.ts +81 -0
  148. package/src/lowering/thread.ts +5 -1
  149. package/src/lowering/trace.ts +270 -0
  150. package/src/lowering/uart.ts +6 -1
  151. package/src/lowering/usb.ts +16 -13
  152. package/src/lowering/wdt.ts +2 -25
  153. package/src/sbom.ts +1117 -0
  154. package/src/sdk/board-catalog-sync.ts +4 -25
  155. package/src/strategy.ts +2680 -2309
  156. package/src/toolchain/debug-config.ts +262 -522
  157. package/src/toolchain/env-check.ts +279 -285
  158. package/src/toolchain/index.ts +1792 -1359
  159. package/src/toolchain/runners.ts +80 -0
  160. package/src/toolchain/scaffold.ts +355 -296
  161. package/src/toolchain/west-discover.ts +35 -13
  162. package/src/toolchain/west-spawn.ts +174 -168
  163. package/src/west-inventory.ts +102 -0
  164. package/dist/async/timer-polyfill.d.ts +0 -10
  165. package/dist/async/timer-polyfill.js +0 -95
  166. package/dist/chips/board-overrides.d.ts +0 -7
  167. package/dist/chips/board-overrides.js +0 -11
  168. package/dist/chips/esp32.d.ts +0 -2
  169. package/dist/chips/esp32.js +0 -71
  170. package/dist/chips/esp32s3.d.ts +0 -2
  171. package/dist/chips/esp32s3.js +0 -103
  172. package/dist/chips/soc/.d.ts +0 -2
  173. package/dist/chips/soc/.js +0 -129
  174. package/dist/chips/soc/esp32.d.ts +0 -2
  175. package/dist/chips/soc/esp32.js +0 -120
  176. package/dist/chips/soc/esp32c3.d.ts +0 -2
  177. package/dist/chips/soc/esp32c3.js +0 -90
  178. package/dist/chips/soc/esp32c6.d.ts +0 -2
  179. package/dist/chips/soc/esp32c6.js +0 -109
  180. package/dist/chips/soc/esp32s3.d.ts +0 -2
  181. package/dist/chips/soc/esp32s3.js +0 -189
  182. package/dist/chips/soc/index.d.ts +0 -2
  183. package/dist/chips/soc/index.js +0 -23
  184. package/dist/chips/soc/nrf52840.d.ts +0 -2
  185. package/dist/chips/soc/nrf52840.js +0 -130
  186. package/dist/chips/soc/rp2040.d.ts +0 -2
  187. package/dist/chips/soc/rp2040.js +0 -141
  188. package/dist/chips/soc/rp2350a.d.ts +0 -2
  189. package/dist/chips/soc/rp2350a.js +0 -145
  190. package/dist/chips/soc/samd21g18a.d.ts +0 -2
  191. package/dist/chips/soc/samd21g18a.js +0 -143
  192. package/dist/chips/soc/stm32f411xe.d.ts +0 -2
  193. package/dist/chips/soc/stm32f411xe.js +0 -251
  194. package/dist/chips/xiao-ble.d.ts +0 -2
  195. package/dist/chips/xiao-ble.js +0 -100
  196. package/dist/lowering/pulse.d.ts +0 -7
  197. package/dist/lowering/pulse.js +0 -51
  198. package/dist/lowering/tone.d.ts +0 -10
  199. package/dist/lowering/tone.js +0 -63
  200. package/dist/lowering/worker-backing.d.ts +0 -14
  201. package/dist/lowering/worker-backing.js +0 -79
  202. package/dist/lowering/worker.d.ts +0 -6
  203. package/dist/lowering/worker.js +0 -14
  204. package/dist/sdk/board-data.generated.d.ts +0 -2
  205. package/dist/sdk/board-data.generated.js +0 -4
  206. package/dist/sdk/catalog-walker.d.ts +0 -90
  207. package/dist/sdk/catalog-walker.js +0 -682
  208. package/dist/sdk/dts-reader.d.ts +0 -83
  209. package/dist/sdk/dts-reader.js +0 -596
  210. package/src/debug-codegen.ts +0 -207
@@ -0,0 +1,270 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Trace heartbeat — the runtime-stats sampler behind `typecad-hal trace`
3
+ //
4
+ // Emits a self-starting sampler into the ENTRY translation unit only (the
5
+ // block compiles under CUTTLEFISH_ENTRY_TU, which the emitter defines once
6
+ // per program — a copy in a split-file TU would register the SYS_INIT hook
7
+ // twice and double every heartbeat). A k_work_delayable on the system work
8
+ // queue samples, every intervalMs:
9
+ //
10
+ // - per-thread execution cycles (CONFIG_THREAD_RUNTIME_STATS)
11
+ // - per-thread stack unused/size (CONFIG_INIT_STACKS / THREAD_STACK_INFO)
12
+ // - the system-wide cycle counter (k_thread_runtime_stats_all_get — the
13
+ // CPU-time denominator; per-thread CPU% is computed HOST-side as
14
+ // delta_thread_exec / delta_sys_exec, so no cycle/Hz units leak onto
15
+ // the wire and idle shows up as its own thread)
16
+ //
17
+ // and prints `[TR:` lines on the console (printf → STDOUT_CONSOLE, the same
18
+ // channel the test-runner protocol uses). Sampling, not event tracing: the
19
+ // device cost is O(live threads) arithmetic per interval — no context-switch
20
+ // hook, no ring buffer, no per-frame work — so the probe effect on the
21
+ // measured system is one short work-queue visit per interval.
22
+ //
23
+ // Heap usage is deliberately NOT sampled: engine-emitted C++ is no-malloc by
24
+ // construction (AUTOSAR rule set), so a heap series would be a constant line.
25
+ //
26
+ // The whole block also gates on CONFIG_THREAD_MONITOR + CONFIG_THREAD_RUNTIME
27
+ // _STATS: the scaffold enables both when zephyr.trace.enabled is set, but a
28
+ // user override in zephyr.kconfig compiles the sampler out instead of
29
+ // failing the link (k_thread_foreach lives in kernel/thread_monitor.c and
30
+ // only builds under THREAD_MONITOR).
31
+ // ---------------------------------------------------------------------------
32
+
33
+ import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
34
+
35
+ /**
36
+ * Resolve a HAL trace.* op to Zephyr C++. The device helpers
37
+ * (__tc_trace_mark / __tc_trace_event) are emitted unconditionally by
38
+ * shimLines — they are two printf calls, and a Trace.mark() call site must
39
+ * never fail to link because tracing was disabled (the lines simply have no
40
+ * capture listening).
41
+ */
42
+ export function lowerTrace(op: HALOpIR): { code?: string; expression?: string } {
43
+ const o = op as { operation: string; name?: string; value?: string | number };
44
+
45
+ switch (op.operation) {
46
+ case 'trace.mark':
47
+ return { code: `__tc_trace_mark(${o.name ?? '""'});` };
48
+ case 'trace.event':
49
+ // The value may be a runtime expression (variable, ternary) — the
50
+ // plugin resolved it as text; interpolate inside static_cast so any
51
+ // numeric C++ expression is valid here.
52
+ return { code: `__tc_trace_event(${o.name ?? '""'}, static_cast<double>(${o.value ?? 0}));` };
53
+ default:
54
+ throw new Error(
55
+ `framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
56
+ `Open an issue or use rawCpp() to emit it manually.`,
57
+ );
58
+ }
59
+ }
60
+
61
+ /** Default heartbeat interval (ms) when zephyr.trace.intervalMs is absent. */
62
+ export const TRACE_HB_DEFAULT_INTERVAL_MS = 1000;
63
+
64
+ /** Clamp for zephyr.trace.intervalMs — faster than 50 ms floods the console
65
+ * and skews the measured CPU load; slower than a minute adds nothing. */
66
+ export function clampTraceIntervalMs(intervalMs: number | undefined): number {
67
+ if (typeof intervalMs !== 'number' || !Number.isFinite(intervalMs)) {
68
+ return TRACE_HB_DEFAULT_INTERVAL_MS;
69
+ }
70
+ return Math.min(60_000, Math.max(50, Math.round(intervalMs)));
71
+ }
72
+
73
+ /**
74
+ * UI frame-time trace block — emitted UNCONDITIONALLY for UI-mounted
75
+ * programs (the call site the emitter stamps after ui_tick must never fail
76
+ * to link), but every body compiles away unless the heartbeat block defined
77
+ * CUTTLEFISH_TRACE_UI (zephyr.trace enabled). Wall-time stats only: frame
78
+ * count / total / max ms per heartbeat interval — the per-phase breakdown
79
+ * inside ui_tick stays a ui-engine change for a later stage.
80
+ */
81
+ /**
82
+ * On-device alarm thresholds (zephyr.trace.alarms) — the sampler prints
83
+ * [TR:ALARM:<seq>:<code>:<detail>] the moment one is breached, so an
84
+ * untethered device still DETECTS the degradation; reading it only needs a
85
+ * capture (or a serial console) after the fact.
86
+ */
87
+ export interface TraceAlarmThresholds {
88
+ /** Alarm when a thread's unused stack falls below this (bytes). */
89
+ stackMinBytes?: number;
90
+ /** Alarm when an interval's worst UI frame exceeds this (ms). */
91
+ frameMaxMs?: number;
92
+ }
93
+
94
+ export function uiFrameTraceLines(frameAlarmMs?: number): string[] {
95
+ const alarmDefine = frameAlarmMs !== undefined ? [`#define __TC_TRACE_ALARM_FRAME ${frameAlarmMs}U`] : [];
96
+ const frameAlarm = frameAlarmMs !== undefined
97
+ ? [
98
+ ' // Continual monitoring: the worst frame breaching the ceiling is an',
99
+ ' // alarm, not a statistic — printed the moment it happens.',
100
+ ' if (__tc_trace_ui_max_ms > __TC_TRACE_ALARM_FRAME) {',
101
+ ' printf("[TR:ALARM:%u:frame:%u\\n", static_cast<unsigned int>(seq),',
102
+ ' static_cast<unsigned int>(__tc_trace_ui_max_ms));',
103
+ ' }',
104
+ ]
105
+ : [];
106
+ return [
107
+ '// CUTTLEFISH_TRACE_UI_BEGIN',
108
+ '#if defined(CUTTLEFISH_TRACE_UI)',
109
+ ...alarmDefine,
110
+ 'static uint32_t __tc_trace_ui_frames = 0U;',
111
+ 'static uint32_t __tc_trace_ui_total_ms = 0U;',
112
+ 'static uint32_t __tc_trace_ui_max_ms = 0U;',
113
+ 'static uint64_t __tc_trace_ui_phase[5];',
114
+ '#endif',
115
+ 'static inline void __tc_trace_ui_frame(uint32_t frame_delta_ms) {',
116
+ '#if defined(CUTTLEFISH_TRACE_UI)',
117
+ ' __tc_trace_ui_frames += 1U;',
118
+ ' __tc_trace_ui_total_ms += frame_delta_ms;',
119
+ ' if (frame_delta_ms > __tc_trace_ui_max_ms) { __tc_trace_ui_max_ms = frame_delta_ms; }',
120
+ '#else',
121
+ ' (void)frame_delta_ms;',
122
+ '#endif',
123
+ '}',
124
+ // Called from the seams the ui-engine's emitTick interleaves between its
125
+ // five phase slices (bindings / transitions / draw / scroll / flush).
126
+ // Cycles are accumulated raw; the report converts to µs once per
127
+ // heartbeat via sys_clock_hw_cycles_per_sec().
128
+ 'static inline void __tc_trace_ui_phase_add(uint8_t idx, uint64_t cycles) {',
129
+ '#if defined(CUTTLEFISH_TRACE_UI)',
130
+ ' if (idx < 5U) { __tc_trace_ui_phase[idx] += cycles; }',
131
+ '#else',
132
+ ' (void)idx; (void)cycles;',
133
+ '#endif',
134
+ '}',
135
+ 'static inline void __tc_trace_ui_report(uint32_t seq) {',
136
+ '#if defined(CUTTLEFISH_TRACE_UI)',
137
+ ' if (__tc_trace_ui_frames > 0U) {',
138
+ ' const uint32_t avg_x10 = (__tc_trace_ui_total_ms * 10U) / __tc_trace_ui_frames;',
139
+ ' printf("[TR:UI:%u:%u:%u:%u\\n", static_cast<unsigned int>(seq),',
140
+ ' static_cast<unsigned int>(__tc_trace_ui_frames),',
141
+ ' static_cast<unsigned int>(avg_x10),',
142
+ ' static_cast<unsigned int>(__tc_trace_ui_max_ms));',
143
+ ' printf("[TR:UP:%u:%llu:%llu:%llu:%llu:%llu\\n", static_cast<unsigned int>(seq),',
144
+ ' static_cast<unsigned long long>((__tc_trace_ui_phase[0] * 1000000ULL) / sys_clock_hw_cycles_per_sec()),',
145
+ ' static_cast<unsigned long long>((__tc_trace_ui_phase[1] * 1000000ULL) / sys_clock_hw_cycles_per_sec()),',
146
+ ' static_cast<unsigned long long>((__tc_trace_ui_phase[2] * 1000000ULL) / sys_clock_hw_cycles_per_sec()),',
147
+ ' static_cast<unsigned long long>((__tc_trace_ui_phase[3] * 1000000ULL) / sys_clock_hw_cycles_per_sec()),',
148
+ ' static_cast<unsigned long long>((__tc_trace_ui_phase[4] * 1000000ULL) / sys_clock_hw_cycles_per_sec()));',
149
+ ...frameAlarm,
150
+ ' }',
151
+ '#else',
152
+ ' (void)seq;',
153
+ '#endif',
154
+ '}',
155
+ 'static inline void __tc_trace_ui_reset(void) {',
156
+ '#if defined(CUTTLEFISH_TRACE_UI)',
157
+ ' __tc_trace_ui_frames = 0U;',
158
+ ' __tc_trace_ui_total_ms = 0U;',
159
+ ' __tc_trace_ui_max_ms = 0U;',
160
+ ' for (uint8_t i = 0U; i < 5U; i++) { __tc_trace_ui_phase[i] = 0ULL; }',
161
+ '#endif',
162
+ '}',
163
+ '// CUTTLEFISH_TRACE_UI_END',
164
+ ];
165
+ }
166
+
167
+ /**
168
+ * The heartbeat shim lines (definitions + SYS_INIT self-start). Emitted by
169
+ * shimLines when the platform context carries zephyr.trace.enabled.
170
+ * `withUi` adds the [TR:UI: frame-stats line (UI-mounted programs).
171
+ */
172
+ export function traceHeartbeatLines(intervalMs: number, withUi: boolean, alarms?: TraceAlarmThresholds): string[] {
173
+ const ms = clampTraceIntervalMs(intervalMs);
174
+ const stackAlarmDefine = alarms?.stackMinBytes !== undefined
175
+ ? [`#define __TC_TRACE_ALARM_STACK ${alarms.stackMinBytes}U`]
176
+ : [];
177
+ const stackAlarm = alarms?.stackMinBytes !== undefined
178
+ ? [
179
+ ' // Continual monitoring: headroom under the floor is an alarm, printed',
180
+ ' // the moment the sampler sees it (once per interval while held).',
181
+ '#ifdef __TC_TRACE_ALARM_STACK',
182
+ ' if (stack_ok && unused < __TC_TRACE_ALARM_STACK) {',
183
+ ' printf("[TR:ALARM:%u:stack:%s:%u\\n", static_cast<unsigned int>(seq), name,',
184
+ ' static_cast<unsigned int>(unused));',
185
+ ' }',
186
+ '#endif',
187
+ ]
188
+ : [];
189
+ return [
190
+ '// CUTTLEFISH_TRACE_BEGIN',
191
+ '#if defined(CUTTLEFISH_ENTRY_TU) && defined(CONFIG_THREAD_MONITOR) && defined(CONFIG_THREAD_RUNTIME_STATS)',
192
+ `#define __TC_TRACE_HB_MS ${ms}U`,
193
+ ...stackAlarmDefine,
194
+ 'static uint32_t __tc_trace_seq = 0U;',
195
+ // One [TR:TH:<seq>:<name>:<exec>:<unused>:<size>] line per live thread.
196
+ // Stack fields print -1 when the platform cannot inspect that thread
197
+ // (ARC-style NO_UNUSED_STACK_INSPECTION faults) — the host reads the
198
+ // sentinel as "unknown", not zero.
199
+ 'static void __tc_trace_thread_line(const struct k_thread* cthread, void* user_data) {',
200
+ ' (void)user_data;',
201
+ ' // The foreach callback hands out a const thread; the stats/name',
202
+ ' // syscalls take k_tid_t (non-const) — the same const_cast Zephyr\'s',
203
+ ' // own thread_analyzer performs at this exact boundary.',
204
+ ' struct k_thread* thread = const_cast<struct k_thread*>(cthread);',
205
+ ' const uint32_t seq = __tc_trace_seq;',
206
+ ' k_thread_runtime_stats_t stats;',
207
+ ' uint64_t exec = 0U;',
208
+ ' if (k_thread_runtime_stats_get(thread, &stats) == 0) {',
209
+ ' exec = stats.execution_cycles;',
210
+ ' }',
211
+ ' size_t unused = 0U;',
212
+ ' const bool stack_ok = k_thread_stack_space_get(thread, &unused) == 0;',
213
+ '#ifdef CONFIG_THREAD_STACK_INFO',
214
+ ' const size_t size = thread->stack_info.size;',
215
+ '#else',
216
+ ' const size_t size = 0U;',
217
+ '#endif',
218
+ ' char name[24];',
219
+ ' const char* thread_name = k_thread_name_get(thread);',
220
+ ' uint32_t n = 0U;',
221
+ ' if (thread_name != nullptr) {',
222
+ ' for (; thread_name[n] != \'\\0\' && n < (sizeof(name) - 1U); n++) {',
223
+ ' const char c = thread_name[n];',
224
+ ' const bool plain = (c >= \'a\' && c <= \'z\') || (c >= \'A\' && c <= \'Z\')',
225
+ ' || (c >= \'0\' && c <= \'9\') || c == \'_\' || c == \'-\' || c == \'.\';',
226
+ ' name[n] = plain ? c : \'_\';',
227
+ ' }',
228
+ ' }',
229
+ ' name[n] = \'\\0\';',
230
+ ' if (n == 0U) { name[0] = \'u\'; name[1] = \'n\'; name[2] = \'\\0\'; }',
231
+ ' printf("[TR:TH:%u:%s:%llu:%lld:%u\\n",',
232
+ ' static_cast<unsigned int>(seq), name,',
233
+ ' static_cast<unsigned long long>(exec),',
234
+ ' stack_ok ? static_cast<long long>(unused) : -1LL,',
235
+ ' static_cast<unsigned int>(size));',
236
+ ...stackAlarm,
237
+ '}',
238
+ 'static void __tc_trace_hb_work(struct k_work* work);',
239
+ 'static K_WORK_DELAYABLE_DEFINE(__tc_trace_hb_dwork, __tc_trace_hb_work);',
240
+ 'static void __tc_trace_hb_work(struct k_work* work) {',
241
+ ' (void)work;',
242
+ ' k_thread_runtime_stats_t all;',
243
+ ' uint64_t sys_exec = 0U;',
244
+ ' if (k_thread_runtime_stats_all_get(&all) == 0) {',
245
+ ' sys_exec = all.execution_cycles;',
246
+ ' }',
247
+ ' __tc_trace_seq += 1U;',
248
+ ' printf("[TR:HB:%u:%u:%llu\\n",',
249
+ ' static_cast<unsigned int>(__tc_trace_seq),',
250
+ ' static_cast<unsigned int>(k_uptime_get_32()),',
251
+ ' static_cast<unsigned long long>(sys_exec));',
252
+ ...(withUi
253
+ ? [
254
+ ' __tc_trace_ui_report(__tc_trace_seq);',
255
+ ' __tc_trace_ui_reset();',
256
+ ]
257
+ : []),
258
+ ' k_thread_foreach(__tc_trace_thread_line, nullptr);',
259
+ ' k_work_reschedule(&__tc_trace_hb_dwork, K_MSEC(__TC_TRACE_HB_MS));',
260
+ '}',
261
+ 'static int __tc_trace_hb_boot(void) {',
262
+ ` printf("[TR:CFG:1:${ms}]\\n");`,
263
+ ' k_work_schedule(&__tc_trace_hb_dwork, K_MSEC(__TC_TRACE_HB_MS));',
264
+ ' return 0;',
265
+ '}',
266
+ 'SYS_INIT(__tc_trace_hb_boot, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);',
267
+ '#endif // CUTTLEFISH_ENTRY_TU && THREAD_MONITOR && THREAD_RUNTIME_STATS',
268
+ '// CUTTLEFISH_TRACE_END',
269
+ ];
270
+ }
@@ -30,7 +30,12 @@ export function uartInitLines(chip: ZephyrChipDescriptor, controllerIndex: numbe
30
30
  '// CUTTLEFISH_UART_BEGIN',
31
31
  `static const struct device* ${p}_dev = DEVICE_DT_GET(DT_NODELABEL(${ctrl.nodeLabel}));`,
32
32
  `static void ${p}_init(uint32_t baud) {`,
33
- ` const struct uart_config cfg = { .baudrate = (baud ? baud : 115200), .parity = UART_CFG_PARITY_NONE, .stop_bits = UART_CFG_STOP_BITS_1, .data_bits = UART_CFG_DATA_BITS_8, .flow_ctrl = UART_CFG_FLOW_CTRL_NONE };`,
33
+ // 115200 8N1 is the console default — reconfiguring an already-matching
34
+ // port RESETS the ESP32 UART's TX path and silently eats the FIRST write
35
+ // that follows (poll_out completes into a reconfiguring FIFO). Only a
36
+ // genuinely different rate reconfigures.
37
+ ` if (baud == 0U || baud == 115200U) { return; }`,
38
+ ` const struct uart_config cfg = { .baudrate = baud, .parity = UART_CFG_PARITY_NONE, .stop_bits = UART_CFG_STOP_BITS_1, .data_bits = UART_CFG_DATA_BITS_8, .flow_ctrl = UART_CFG_FLOW_CTRL_NONE };`,
34
39
  ` uart_configure(${p}_dev, &cfg);`,
35
40
  `}`,
36
41
  '// CUTTLEFISH_UART_END',
@@ -51,10 +51,10 @@ function nodeLabel(idx: number): string {
51
51
  * subsys/usb/device_next/Kconfig, include/zephyr/usb/usbd.h, and
52
52
  * samples/subsys/usb/common/sample_usbd_init.c.
53
53
  */
54
- export function usbdDeviceLines(chip: ZephyrChipDescriptor): string[] {
54
+ export function usbdDeviceLines(chip: ZephyrChipDescriptor, opts?: { hid?: boolean }): string[] {
55
55
  if (!chip.usb) return [];
56
56
  const vid = chip.usb.vid ?? '0x2fe3';
57
- const pid = chip.usb.pid ?? '0x0001';
57
+ const pid = chip.usb.pid ?? (opts?.hid ? '0x0008' : '0x0001');
58
58
  // 1200-baud touch-to-reset (BOSSA-bootloader boards): a usbd message
59
59
  // callback that reboots into the bootloader when the host sets the CDC
60
60
  // baud rate to 1200. Zephyr's CDC-ACM class publishes
@@ -93,13 +93,13 @@ export function usbdDeviceLines(chip: ZephyrChipDescriptor): string[] {
93
93
  ` ${vid}, ${pid});`,
94
94
  'USBD_DESC_LANG_DEFINE(__tc_usbd_lang);',
95
95
  'USBD_DESC_MANUFACTURER_DEFINE(__tc_usbd_mfr, "typecad");',
96
- 'USBD_DESC_PRODUCT_DEFINE(__tc_usbd_product, "cuttlefish app");',
96
+ 'USBD_DESC_PRODUCT_DEFINE(__tc_usbd_product, "typecad-hal app");',
97
97
  // Serial number from hwinfo: Windows keys USB devnodes without a serial
98
98
  // on the physical port, so flash-cycle re-enumerations reuse stale
99
99
  // port-keyed nodes (the "access denied" open wedge). Identity-based
100
100
  // instance paths are stable across ports and never hit that pool.
101
101
  'USBD_DESC_SERIAL_NUMBER_DEFINE(__tc_usbd_sn);',
102
- 'USBD_DESC_CONFIG_DEFINE(__tc_usbd_cfg_desc, "cuttlefish");',
102
+ 'USBD_DESC_CONFIG_DEFINE(__tc_usbd_cfg_desc, "typecad-hal");',
103
103
  'USBD_CONFIGURATION_DEFINE(__tc_usbd_cfg, 0, 250, &__tc_usbd_cfg_desc);',
104
104
  'static bool __tc_usbd_started = false;',
105
105
  ...touchLines,
@@ -107,17 +107,17 @@ export function usbdDeviceLines(chip: ZephyrChipDescriptor): string[] {
107
107
  ' if (__tc_usbd_started) { return; }',
108
108
  ' __tc_usbd_started = true;',
109
109
  ' int err = usbd_add_descriptor(&__tc_usbd, &__tc_usbd_lang);',
110
- ' if (err != 0) { printk("cuttlefish usb: lang descriptor failed: %d\\n", err); return; }',
110
+ ' if (err != 0) { printk("typecad-hal usb: lang descriptor failed: %d\\n", err); return; }',
111
111
  ' err = usbd_add_descriptor(&__tc_usbd, &__tc_usbd_sn);',
112
- ' if (err != 0) { printk("cuttlefish usb: serial descriptor failed: %d\\n", err); return; }',
112
+ ' if (err != 0) { printk("typecad-hal usb: serial descriptor failed: %d\\n", err); return; }',
113
113
  ' err = usbd_add_descriptor(&__tc_usbd, &__tc_usbd_mfr);',
114
- ' if (err != 0) { printk("cuttlefish usb: manufacturer descriptor failed: %d\\n", err); return; }',
114
+ ' if (err != 0) { printk("typecad-hal usb: manufacturer descriptor failed: %d\\n", err); return; }',
115
115
  ' err = usbd_add_descriptor(&__tc_usbd, &__tc_usbd_product);',
116
- ' if (err != 0) { printk("cuttlefish usb: product descriptor failed: %d\\n", err); return; }',
116
+ ' if (err != 0) { printk("typecad-hal usb: product descriptor failed: %d\\n", err); return; }',
117
117
  ' err = usbd_add_configuration(&__tc_usbd, USBD_SPEED_FS, &__tc_usbd_cfg);',
118
- ' if (err != 0) { printk("cuttlefish usb: add configuration failed: %d\\n", err); return; }',
118
+ ' if (err != 0) { printk("typecad-hal usb: add configuration failed: %d\\n", err); return; }',
119
119
  ' err = usbd_register_all_classes(&__tc_usbd, USBD_SPEED_FS, 1, NULL);',
120
- ' if (err != 0) { printk("cuttlefish usb: register classes failed: %d\\n", err); return; }',
120
+ ' if (err != 0) { printk("typecad-hal usb: register classes failed: %d\\n", err); return; }',
121
121
  // Registered before usbd_init so no line-coding event can be missed.
122
122
  ...touchRegister,
123
123
  // usbd_init builds the descriptor tables from the registered
@@ -125,14 +125,17 @@ export function usbdDeviceLines(chip: ZephyrChipDescriptor): string[] {
125
125
  // refuses with -EPERM ("not initialized") without it (sample_usbd_init.c
126
126
  // calls it between setup and enable).
127
127
  ' err = usbd_init(&__tc_usbd);',
128
- ' if (err != 0) { printk("cuttlefish usb: init failed: %d\\n", err); return; }',
128
+ ' if (err != 0) { printk("typecad-hal usb: init failed: %d\\n", err); return; }',
129
129
  // Boards with VBUS detection start on the VBUS event in the Zephyr
130
130
  // sample, via a message callback we do not register; enabling
131
131
  // unconditionally (and reporting the error) is the sample's own path
132
132
  // for boards without detection (STM32 OTG_FS).
133
133
  ' err = usbd_enable(&__tc_usbd);',
134
- ' if (err != 0) { printk("cuttlefish usb: enable failed: %d\\n", err); return; }',
135
- ' printk("cuttlefish usb: device enabled\\n");',
134
+ ' if (err != 0) { printk("typecad-hal usb: enable failed: %d\\n", err); return; }',
135
+ // No success printk: the message interleaves with the hardware-test
136
+ // protocol on the shared uart console (a [TC:EXPECT] line corrupted
137
+ // mid-suite when the HID tests first brought the device up). Failures
138
+ // still print — a broken USB is worth the noise.
136
139
  '}',
137
140
  '// CUTTLEFISH_USBD_END',
138
141
  ];
@@ -6,36 +6,13 @@
6
6
  // wdt_install_timeout in a static var so wdt.reset can feed it.
7
7
  //
8
8
  // enable(timeout): wdt_install_timeout + wdt_setup. Zephyr expects the timeout
9
- // in milliseconds (wdt_window.max). The HAL passes a "250ms" string or WDTO_*
10
- // constant or a number; we parse to ms in the lowering.
9
+ // in milliseconds (wdt_window.max); the thin Watchdog (hal/watchdog.ts)
10
+ // construction already carries a plain timeoutMs number.
11
11
  // ---------------------------------------------------------------------------
12
12
 
13
13
  import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
14
14
  import type { ZephyrChipDescriptor } from '../chips/types.js';
15
15
 
16
- /** Parse a HAL wdt timeout ("250ms", WDTO_2S, or a bare number) to ms.
17
- * Tolerates undefined (the manifest validator's probe sends a minimal op)
18
- * and quote-wrapped strings (resolveSemanticArg can hand the literal's
19
- * quoted source text through). */
20
- function timeoutToMs(timeout: string | number | undefined): number {
21
- if (typeof timeout === 'number') return timeout;
22
- if (!timeout) return 1000; // default 1s when absent (e.g. the validator probe)
23
- timeout = timeout.replace(/^['"]|['"]$/g, '');
24
- // Arduino WDTO_* constants.
25
- const wdto: Record<string, number> = {
26
- WDTO_15MS: 15, WDTO_30MS: 30, WDTO_60MS: 60, WDTO_120MS: 120,
27
- WDTO_250MS: 250, WDTO_500MS: 500, WDTO_1S: 1000, WDTO_2S: 2000,
28
- WDTO_4S: 4000, WDTO_8S: 8000,
29
- };
30
- if (wdto[timeout]) return wdto[timeout];
31
- const m = timeout.match(/^(\d+)\s*ms$/i);
32
- if (m) return parseInt(m[1], 10);
33
- const s = timeout.match(/^(\d+)\s*s$/i);
34
- if (s) return parseInt(s[1], 10) * 1000;
35
- const n = parseInt(timeout, 10);
36
- return isNaN(n) ? 1000 : n;
37
- }
38
-
39
16
  /**
40
17
  * Emit the WDT device + channel state. Called from shimLines when the program
41
18
  * uses the watchdog.