@typecad/framework-zephyr 1.0.0-alpha.15 → 1.0.0-alpha.18

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 (132) 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/boardgen.d.ts +1 -9
  6. package/dist/boardgen.js +228 -45
  7. package/dist/chips/types.d.ts +1 -1
  8. package/dist/debug-codegen.js +1 -1
  9. package/dist/display/touch-adapter.js +1 -1
  10. package/dist/display/ui-adapter.js +549 -549
  11. package/dist/doctor.js +4 -4
  12. package/dist/dt-config/custom-board.js +2 -2
  13. package/dist/dt-config/kconfig.js +18 -12
  14. package/dist/dt-config/overlay.d.ts +2 -2
  15. package/dist/dt-config/overlay.js +2 -2
  16. package/dist/framework.manifest.d.ts +3 -3
  17. package/dist/framework.manifest.js +10 -7
  18. package/dist/index.js +5 -5
  19. package/dist/licenses.d.ts +2 -2
  20. package/dist/licenses.js +8 -8
  21. package/dist/lowering/fs.js +1 -1
  22. package/dist/lowering/gpio.js +0 -32
  23. package/dist/lowering/http.js +264 -32
  24. package/dist/lowering/i2c.js +0 -8
  25. package/dist/lowering/interrupts.js +6 -0
  26. package/dist/lowering/mqtt.js +110 -8
  27. package/dist/lowering/usb.js +11 -11
  28. package/dist/lowering/wdt.js +2 -29
  29. package/dist/sdk/board-catalog-sync.d.ts +1 -3
  30. package/dist/sdk/board-catalog-sync.js +4 -10
  31. package/dist/strategy.d.ts +22 -44
  32. package/dist/strategy.js +152 -155
  33. package/dist/tmp-probe.d.ts +2 -0
  34. package/dist/tmp-probe.js +9 -0
  35. package/dist/toolchain/debug-config.d.ts +50 -90
  36. package/dist/toolchain/debug-config.js +241 -502
  37. package/dist/toolchain/env-check.d.ts +1 -3
  38. package/dist/toolchain/env-check.js +2 -7
  39. package/dist/toolchain/index.d.ts +65 -2
  40. package/dist/toolchain/index.js +432 -55
  41. package/dist/toolchain/runners.d.ts +16 -0
  42. package/dist/toolchain/runners.js +75 -0
  43. package/dist/toolchain/scaffold.d.ts +1 -1
  44. package/dist/toolchain/scaffold.js +12 -12
  45. package/dist/toolchain/west-discover.d.ts +6 -0
  46. package/dist/toolchain/west-discover.js +36 -13
  47. package/dist/toolchain/west-spawn.js +8 -2
  48. package/installer/README.md +328 -328
  49. package/installer/install.sh +2 -2
  50. package/installer/templates/project/.typecad/activate-zephyr.ps1 +1 -1
  51. package/installer/templates/project/.typecad/activate-zephyr.sh +1 -1
  52. package/installer/templates/project/.vscode/settings.json +1 -1
  53. package/installer/templates/project/README.md +2 -2
  54. package/package.json +5 -5
  55. package/src/as-built.ts +206 -206
  56. package/src/boardgen.ts +214 -48
  57. package/src/chips/types.ts +567 -567
  58. package/src/display/touch-adapter.ts +204 -204
  59. package/src/display/ui-adapter.ts +781 -781
  60. package/src/doctor.ts +4 -4
  61. package/src/dt-config/custom-board.ts +2 -2
  62. package/src/dt-config/kconfig.ts +18 -12
  63. package/src/dt-config/overlay.ts +1058 -1058
  64. package/src/framework.manifest.ts +538 -535
  65. package/src/index.ts +5 -5
  66. package/src/licenses.ts +425 -425
  67. package/src/lowering/fs.ts +135 -135
  68. package/src/lowering/gpio.ts +0 -33
  69. package/src/lowering/http.ts +264 -32
  70. package/src/lowering/i2c.ts +0 -9
  71. package/src/lowering/interrupts.ts +6 -0
  72. package/src/lowering/mqtt.ts +109 -8
  73. package/src/lowering/usb.ts +221 -221
  74. package/src/lowering/wdt.ts +2 -25
  75. package/src/sdk/board-catalog-sync.ts +4 -25
  76. package/src/strategy.ts +2265 -2309
  77. package/src/toolchain/debug-config.ts +264 -514
  78. package/src/toolchain/env-check.ts +279 -285
  79. package/src/toolchain/index.ts +1703 -1286
  80. package/src/toolchain/runners.ts +80 -0
  81. package/src/toolchain/scaffold.ts +296 -296
  82. package/src/toolchain/west-discover.ts +35 -13
  83. package/src/toolchain/west-spawn.ts +174 -168
  84. package/dist/async/timer-polyfill.d.ts +0 -10
  85. package/dist/async/timer-polyfill.js +0 -95
  86. package/dist/chips/board-overrides.d.ts +0 -7
  87. package/dist/chips/board-overrides.js +0 -11
  88. package/dist/chips/esp32.d.ts +0 -2
  89. package/dist/chips/esp32.js +0 -71
  90. package/dist/chips/esp32s3.d.ts +0 -2
  91. package/dist/chips/esp32s3.js +0 -103
  92. package/dist/chips/soc/.d.ts +0 -2
  93. package/dist/chips/soc/.js +0 -129
  94. package/dist/chips/soc/esp32.d.ts +0 -2
  95. package/dist/chips/soc/esp32.js +0 -120
  96. package/dist/chips/soc/esp32c3.d.ts +0 -2
  97. package/dist/chips/soc/esp32c3.js +0 -90
  98. package/dist/chips/soc/esp32c6.d.ts +0 -2
  99. package/dist/chips/soc/esp32c6.js +0 -109
  100. package/dist/chips/soc/esp32s3.d.ts +0 -2
  101. package/dist/chips/soc/esp32s3.js +0 -189
  102. package/dist/chips/soc/index.d.ts +0 -2
  103. package/dist/chips/soc/index.js +0 -23
  104. package/dist/chips/soc/nrf52840.d.ts +0 -2
  105. package/dist/chips/soc/nrf52840.js +0 -130
  106. package/dist/chips/soc/rp2040.d.ts +0 -2
  107. package/dist/chips/soc/rp2040.js +0 -141
  108. package/dist/chips/soc/rp2350a.d.ts +0 -2
  109. package/dist/chips/soc/rp2350a.js +0 -145
  110. package/dist/chips/soc/samd21g18a.d.ts +0 -2
  111. package/dist/chips/soc/samd21g18a.js +0 -143
  112. package/dist/chips/soc/stm32f411xe.d.ts +0 -2
  113. package/dist/chips/soc/stm32f411xe.js +0 -251
  114. package/dist/chips/xiao-ble.d.ts +0 -2
  115. package/dist/chips/xiao-ble.js +0 -100
  116. package/dist/lowering/power.d.ts +0 -9
  117. package/dist/lowering/power.js +0 -60
  118. package/dist/lowering/pulse.d.ts +0 -7
  119. package/dist/lowering/pulse.js +0 -51
  120. package/dist/lowering/tone.d.ts +0 -10
  121. package/dist/lowering/tone.js +0 -63
  122. package/dist/lowering/worker-backing.d.ts +0 -14
  123. package/dist/lowering/worker-backing.js +0 -79
  124. package/dist/lowering/worker.d.ts +0 -6
  125. package/dist/lowering/worker.js +0 -14
  126. package/dist/sdk/board-data.generated.d.ts +0 -2
  127. package/dist/sdk/board-data.generated.js +0 -4
  128. package/dist/sdk/catalog-walker.d.ts +0 -90
  129. package/dist/sdk/catalog-walker.js +0 -682
  130. package/dist/sdk/dts-reader.d.ts +0 -83
  131. package/dist/sdk/dts-reader.js +0 -596
  132. package/src/debug-codegen.ts +0 -207
@@ -1,567 +1,567 @@
1
- // ---------------------------------------------------------------------------
2
- // Zephyr chip descriptor — pure-data model
3
- //
4
- // Mirrors the per-framework chip-descriptor pattern established by
5
- // framework-esp32 (Esp32ChipDescriptor) and framework-avr (AVRChipDescriptor):
6
- // the framework owns its own device-tree-derived descriptor, keyed off the
7
- // Zephyr board target string in frameworkData.buildTarget. The board/MCU
8
- // packages are deliberately NOT read at emit time (see the framework-package
9
- // data-flow split); this descriptor is the source the lowering reads.
10
- //
11
- // No behavior — the lowering code in src/lowering/*.ts reads getActiveChip()
12
- // to resolve pins to devicetree specs and raw-controller fallbacks.
13
- // ---------------------------------------------------------------------------
14
-
15
- /**
16
- * A GPIO pin described as a devicetree spec.
17
- *
18
- * Zephyr addresses GPIO via `struct gpio_dt_spec` resolved from devicetree
19
- * aliases/labels (e.g. DT_ALIAS(led0)). The dtSpec form is preferred because
20
- * `gpio_pin_set_dt()` honors the node's polarity flags — so an active-low LED
21
- * (logical 1 = LED on) is handled by the DT `GPIO_ACTIVE_LOW` flag, not by the
22
- * generated C++.
23
- */
24
- export interface ZephyrGpioDtSpec {
25
- /** GPIO number — matches the HAL op `pin` field (P0.X → X, P1.X → 32+X). */
26
- readonly pin: number;
27
- /**
28
- * Devicetree alias/nodelabel macro, e.g. `led0`, `sw0`, `led1`.
29
- * Emitted as `GPIO_DT_SPEC_GET(DT_ALIAS(<dtSpec>), gpios)`.
30
- */
31
- readonly dtSpec: string;
32
- }
33
-
34
- /**
35
- * A GPIO controller devicetree node, and the HAL pin-number range it owns.
36
- *
37
- * Most SoCs expose a single GPIO controller (nRF52840: `gpio0` owns every
38
- * pin). SoCs that split GPIO across multiple devicetree nodes — e.g. the
39
- * ESP32-S3 (`gpio0`: pins 0–31, `gpio1`: pins 32–48) — list one entry per
40
- * controller so the lowering can route a HAL pin to the owning controller at
41
- * runtime. Pin numbers match the HAL op `pin` field.
42
- */
43
- export interface ZephyrGpioController {
44
- /** Devicetree nodelabel, e.g. 'gpio0', 'gpio1'. */
45
- readonly nodelabel: string;
46
- /** First HAL pin number owned by this controller (inclusive). */
47
- readonly minPin: number;
48
- /** Last HAL pin number owned by this controller (inclusive). */
49
- readonly maxPin: number;
50
- }
51
-
52
- /**
53
- * A bus controller (I2C / SPI / UART) described by its devicetree nodelabel.
54
- *
55
- * Zephyr resolves the `const struct device*` at compile time via
56
- * `DEVICE_DT_GET(DT_NODELABEL(<nodeLabel>))`, so unlike ESP-IDF there is no
57
- * lazy handle resolution — the lowering emits the macro directly.
58
- */
59
- export interface ZephyrBusController {
60
- /** Devicetree nodelabel, e.g. 'i2c1', 'spi2', 'uart0'. */
61
- readonly nodeLabel: string;
62
- /**
63
- * Counter child form only: the labeled TIMER PARENT's nodelabel (ESP32
64
- * timer0-3). The counter device is an unlabeled `counter {}` child; the
65
- * nodeLabel above is a label the generated overlay defines on that child,
66
- * and this field tells the overlay which parent to attach it to.
67
- */
68
- readonly counterParent?: string;
69
- /**
70
- * Synthesized pinctrl group, for controllers whose board DT ships no
71
- * default group (e.g. uart1 on rpi_pico/rpi_pico2 — the mainline board DT
72
- * only pins uart0). When present, the overlay generator emits the group
73
- * under `&pinctrl` and wires `pinctrl-0`/`pinctrl-names` onto the
74
- * controller when enabling it. RP2xxx pinmux is fully muxable per pad, so
75
- * the group is pure data: which pads carry the signals.
76
- */
77
- readonly pinctrl?: {
78
- /** Pinmux header to #include (token definitions). */
79
- readonly include: string;
80
- /** Output-signal pinmux tokens (emitted as group1). */
81
- readonly pinmux: readonly string[];
82
- /** Input-signal pinmux tokens (emitted as group2 with input-enable). */
83
- readonly inputPinmux?: readonly string[];
84
- /**
85
- * `#define` lines emitted (ifndef-guarded) BEFORE the include — for
86
- * upstream header bugs where a token's macro body references an
87
- * undefined helper (e.g. RP2_PINCTRL_GPIO_FUNC_UART_ALT in Zephyr's
88
- * rp2350 pinctrl headers, unreferenced by mainline so never noticed).
89
- */
90
- readonly defines?: readonly string[];
91
- };
92
- /**
93
- * Reference an EXISTING pinctrl group (defined in the board's pinctrl
94
- * dtsi but not attached to the node) instead of synthesizing one — e.g.
95
- * uart1_default on esp32s3_devkitc. The overlay wires
96
- * `pinctrl-0 = <&<group>>` when enabling the controller.
97
- */
98
- readonly pinctrlRef?: string;
99
- /**
100
- * Raw devicetree property lines emitted inside the enable block — for
101
- * bindings with required properties the board DTS only sets on its own
102
- * wired-up nodes (e.g. `current-speed` on the Picos' PL011 UARTs).
103
- */
104
- readonly props?: readonly string[];
105
- }
106
-
107
- /**
108
- * A PWM channel described as a devicetree spec.
109
- *
110
- * Two forms, mutually exclusive:
111
- * - **Board-shipped alias:** `dtSpec` names a DT alias the board's own DTS
112
- * already defines (e.g. the XIAO's `pwm-led0`). Emitted as
113
- * `PWM_DT_SPEC_GET(DT_ALIAS(<dtSpec>))`.
114
- * - **Synthesized** (controller + channel): the board DTS enables a PWM
115
- * controller node (e.g. `pwm4`) but defines no alias for it. The overlay
116
- * generator synthesizes a `pwm-leds` consumer node + a `tc-pwm<pin>` alias
117
- * in `<board>.overlay`; the lowering emits
118
- * `PWM_DT_SPEC_GET(DT_ALIAS(tc-pwm<pin>))`. Both sides derive the alias
119
- * name from the pin, so they always agree.
120
- *
121
- * `pwm_set_pulse_dt(&spec, pulse_ns)` honors the spec's period/polarity.
122
- */
123
- export interface ZephyrPwmSpec {
124
- /** GPIO number (matches the HAL op `pin` field). */
125
- readonly pin: number;
126
- /** Board-shipped DT alias, e.g. 'pwm-led0'. Omit when using the
127
- * synthesized form (controller + channel). */
128
- readonly dtSpec?: string;
129
- /** Synthesized form: PWM controller DT nodelabel, e.g. 'pwm4' (the STM32
130
- * timer's pwm child node). The overlay's pwm-leds node consumes it. */
131
- readonly controller?: string;
132
- /** Synthesized form: channel index within the controller (1-based timer
133
- * channel, matching the `pwms` binding's channel cell). */
134
- readonly channel?: number;
135
- /** Synthesized form: period in nanoseconds, baked into the DT spec. The
136
- * lowering scales duty against `spec.period`. Default 20 000 000 (20 ms /
137
- * 50 Hz — the servo convention; harmless for LED dimming). */
138
- readonly periodNs?: number;
139
- /** Synthesized form: PWM polarity flag. Default PWM_POLARITY_NORMAL. */
140
- readonly polarity?: string;
141
- /**
142
- * SoC pinctrl dtsi token muxing this channel's pin to the timer (e.g.
143
- * 'tim4_ch1_pb6' on STM32). Required on custom boards — the st,stm32-pwm
144
- * binding demands pinctrl-0 on an enabled node and only a board DTS (or
145
- * the custom-board generator, fed by this token) can provide it. Also
146
- * gates the generated board's `pwmN: pwm { }` label declaration: the
147
- * overlay references `&<controller>`, a label that otherwise exists only
148
- * when a board DTS defines it.
149
- */
150
- readonly pinctrl?: string;
151
- }
152
-
153
- /**
154
- * A "PWM matrix" controller: any listed pin can carry any channel, routed by
155
- * the SoC's GPIO matrix rather than a fixed timer-channel↔pad map.
156
- *
157
- * ESP32 LEDC is the shape (espressif,esp32-ledc): 8 channels, each routable
158
- * to (almost) any pad via a pinctrl pinmux token (`LEDC_CH<ch>_GPIO<pin>`).
159
- * A static `specs` list cannot express this — two arbitrary pins would
160
- * collide on a statically assigned channel — so the channel assignment is
161
- * made at build time: the pins the program actually drives are assigned
162
- * channels 0..N-1 (ascending pin order, capped at `channelCount`), and the
163
- * overlay generator emits the pinctrl group + per-channel child nodes the
164
- * espressif,esp32-ledc binding requires. The emitted C++ is channel-blind:
165
- * it addresses each pin via the same `DT_ALIAS(tc-pwm<pin>)` the synthesized
166
- * static form uses, so the two paths share the lowering.
167
- */
168
- export interface ZephyrPwmMatrix {
169
- /** PWM controller DT nodelabel, e.g. 'ledc0'. */
170
- readonly controller: string;
171
- /** Channels the controller exposes (ESP32-S3 LEDC: 8). */
172
- readonly channelCount: number;
173
- /**
174
- * HAL pins usable as PWM outputs. This is the safety filter as much as the
175
- * capability list — on the ESP32-S3 it excludes the boot-strap pin, the
176
- * USB D+/D− pads, the flash/PSRAM pins (GPIO 26–32), the octal-PSRAM pins
177
- * (GPIO 33–37), and the console UART pads (GPIO 43/44).
178
- */
179
- readonly pins: readonly number[];
180
- }
181
-
182
- /**
183
- * A GPIO pin usable as an interrupt source.
184
- *
185
- * Emitted as `struct gpio_dt_spec __tc_int<N> = GPIO_DT_SPEC_GET(DT_ALIAS(<dtSpec>), gpios)`
186
- * + a `struct gpio_callback` registered via `gpio_add_callback`.
187
- */
188
- export interface ZephyrInterruptPin {
189
- /** GPIO number (matches the HAL op `pin` field). */
190
- readonly pin: number;
191
- /** Devicetree alias, e.g. 'sw0', or a nodelabel. */
192
- readonly dtSpec: string;
193
- }
194
-
195
- /**
196
- * An ADC channel: which ADC input a given HAL pin maps to.
197
- *
198
- * The XIAO nRF52840 has no pre-declared ADC channel nodes in devicetree, so the
199
- * lowering emits `adc_channel_setup` against `DEVICE_DT_GET(DT_NODELABEL(adc))`
200
- * using the `channel` index here (SAADC AIN0–AIN7).
201
- */
202
- export interface ZephyrAdcChannel {
203
- /** GPIO number (matches the HAL op `pin` field). */
204
- readonly pin: number;
205
- /** ADC channel index (nRF SAADC AIN0–AIN7; STM32 ADC1_IN0–IN9). */
206
- readonly channel: number;
207
- /**
208
- * ADC device node label that OWNS this channel when the SoC has more than
209
- * one ADC controller (STM32 adc1/adc2, ESP32 units), e.g. 'adc2'. Omitted
210
- * for channels on the descriptor's primary controller (`adc.nodeLabel`) —
211
- * a single-controller manifest is unchanged. Channel indices are unique
212
- * only WITHIN a controller; the pair (controller, channel) is the key.
213
- */
214
- readonly controller?: string;
215
- /**
216
- * Pinctrl node label that muxes this pin to analog mode, e.g.
217
- * 'adc1_in0_pa0' (STM32). When present, the overlay generator rewrites the
218
- * ADC node's pinctrl-0 to the channels the program actually reads — SoCs
219
- * like STM32 leave the pad in GPIO mode otherwise and reads float.
220
- * Omit on SoCs whose ADC needs no pad muxing (nRF SAADC, RP2040).
221
- */
222
- readonly pinctrl?: string;
223
- }
224
-
225
- /**
226
- * A DAC channel: which DAC output a given HAL pin maps to. The lowering emits
227
- * `dac_channel_setup` + `dac_write_value` against the DAC device node.
228
- */
229
- export interface ZephyrDacChannel {
230
- /** GPIO number (matches the HAL op `pin` field). */
231
- readonly pin: number;
232
- /** DAC channel index (ESP32: GPIO25 → 1, GPIO26 → 2). */
233
- readonly channel: number;
234
- /** DAC resolution in bits (ESP32 DAC is 8-bit). */
235
- readonly resolution: number;
236
- /** Pinctrl node name routing the channel to its pad (STM32 harvest). */
237
- readonly pinctrl?: string;
238
- }
239
-
240
- /**
241
- * Pure-data descriptor for a Zephyr board + its SoC's peripheral layout.
242
- */
243
- export interface ZephyrChipDescriptor {
244
- /** Zephyr board target (the `west build -b <id>` argument), e.g. 'xiao_ble'. */
245
- readonly id: string;
246
- /** SoC family, e.g. 'nrf52840'. */
247
- readonly soc: string;
248
- /**
249
- * How confident the framework is in this descriptor's facts.
250
- * - 'validated' — the soc is part of the hardware-tested set; every field
251
- * was verified against the pinned Zephyr tree and real hardware.
252
- * - 'derived' — reconstructed from data (board/MCU packages, DTS reading)
253
- * but never hardware-verified; capability errors may be less precise.
254
- */
255
- readonly tier?: 'validated' | 'derived';
256
- /**
257
- * Datasheet pin-naming convention — how a controller/pin pair becomes the
258
- * schematic-facing name the generated board module exports (the
259
- * `Pin.fromPort()` identity). One of:
260
- * - 'esp32-gpio' — flat numbering, `GPION` (esp32, esp32s3, esp32c*)
261
- * - 'stm32-port' — one controller per port, `P<port><bit>` (PA5, PB12)
262
- * - 'nrf-port' — P0.28 / P1.11 style (`P<port>.<bit>`)
263
- * - 'rp-gpio' — `GP<n>` flat numbering
264
- * - 'samd-port' — PA/PB ports like stm32-port
265
- * Absent on tier-3 socs with no known convention (the generated board
266
- * exposes only connector/alias pins + LED/BUTTON).
267
- */
268
- readonly pinNaming?: 'esp32-gpio' | 'stm32-port' | 'nrf-port' | 'rp-gpio' | 'samd-port';
269
- /**
270
- * Pins that exist in the controller ranges but must NOT be exported as
271
- * usable GPIOs — strapping pads, flash/PSRAM, USB D+/-. The generated
272
- * board module's pin list subtracts these.
273
- */
274
- readonly excludedPins?: readonly number[];
275
- /**
276
- * Default GPIO controller nodelabel for the raw-pin fallback. Pins not in
277
- * `gpio.dtSpecs` are addressed via
278
- * `DEVICE_DT_GET(DT_NODELABEL(<gpioController>))` + gpio_pin_*_raw().
279
- *
280
- * For SoCs that split GPIO across multiple devicetree nodes, `gpioControllers`
281
- * overrides this per pin range; this field is then only the out-of-range
282
- * fallback (so a single-controller board is unaffected by it).
283
- */
284
- readonly gpioController: string;
285
- /**
286
- * Per-range GPIO controllers for SoCs that split GPIO across multiple
287
- * devicetree nodes (ESP32-S3: `gpio0` 0–31, `gpio1` 32–48; STM32: one
288
- * controller per port — `gpioa` 0–15, `gpiob` 16–31, `gpioc` 32–47).
289
- * When present, the lowering routes a HAL pin to its owning controller at
290
- * runtime via the emitted `__tc_gpio_dev(pin)` dispatcher; `gpioController`
291
- * is the fallback. Omit on single-controller SoCs (RP2040, …) — every pin
292
- * is on the one controller described by `gpioController`.
293
- *
294
- * NUMBERING RULE (load-bearing): `minPin` must equal the controller's port
295
- * base so the port-relative raw index is `pin - minPin` (STM32 PB12 = pin
296
- * 28 → raw 12 — the Zephyr raw API addresses the index WITHIN the
297
- * controller). Number pins by port blocks and never contiguously across
298
- * unbonded pins.
299
- */
300
- readonly gpioControllers?: readonly ZephyrGpioController[];
301
- /** GPIO pins with devicetree specs (LEDs, buttons, board-defined pins). */
302
- readonly gpio: {
303
- readonly dtSpecs: readonly ZephyrGpioDtSpec[];
304
- /** Interrupt-capable pins with DT specs (buttons etc.). */
305
- readonly interruptPins?: readonly ZephyrInterruptPin[];
306
- };
307
- /** I2C controllers (board-wired). Index 0 = the primary bus. */
308
- readonly i2c?: { readonly controllers: readonly ZephyrBusController[] };
309
- /** SPI controllers (board-wired). Index 0 = the primary bus. */
310
- readonly spi?: { readonly controllers: readonly ZephyrBusController[] };
311
- /** UART controllers (board-wired). Index 0 = the primary port. */
312
- readonly uart?: { readonly controllers: readonly ZephyrBusController[] };
313
- /**
314
- * USB device (CDC-ACM serial) capability. Zephyr "next" USB device stack:
315
- * the UDC controller node (uniformly `zephyr_udc0` on every USB-capable
316
- * board) plus `cdcInstances` CDC-ACM class child nodes, both composed in
317
- * the generated overlay. The lowering addresses instance N as
318
- * DT_NODELABEL(cdc_acm_uart<N>) — a UART-class device driven with the
319
- * plain uart_* API. Boards without USB device support omit this field;
320
- * usb.* HAL ops then fail with a clear "board does not expose USB" error.
321
- */
322
- readonly usb?: {
323
- /** UDC controller nodelabel (convention: 'zephyr_udc0'). */
324
- readonly controller: string;
325
- /** How many CDC-ACM serial instances to compose (≥1). */
326
- readonly cdcInstances: number;
327
- /** USB vendor ID for the device descriptor ('0x2fe3' Zephyr-test default). */
328
- readonly vid?: string;
329
- /** USB product ID for the device descriptor ('0x0001' default). */
330
- readonly pid?: string;
331
- /**
332
- * 1200-baud touch-to-reset (BOSSA-bootloader boards, e.g. SAM D21).
333
- *
334
- * Present = two things happen automatically:
335
- * - Device side: the emitted USB shim registers a usbd message callback;
336
- * when the host sets the CDC baud rate to 1200, the shim writes the
337
- * bootloader's "stay resident" magic to the flag address and reboots —
338
- * the board lands in the bootloader with no button press.
339
- * - Host side: the bossac upload path opens the app's console port at
340
- * 1200 baud to trigger the above, waits for the bootloader's USB
341
- * identity, and points bossac at that port.
342
- * Omit on boards without a cooperative bootloader (probe- or
343
- * UF2-flashed boards don't need it).
344
- */
345
- readonly touchReset?: {
346
- /** RAM address of the bootloader's stay-resident flag word
347
- * (SAMD21G18A: 0x20007FFC — the last word of the 32 KB SRAM). */
348
- readonly flagAddress: number;
349
- /** Magic word the bootloader checks there (Arduino SAMD: 0x07738135). */
350
- readonly magic: number;
351
- /** Bootloader USB vendor id, hex string ('0x2341') — host-side watch. */
352
- readonly bootloaderVid?: string;
353
- /** Bootloader USB product id, hex string ('0x0057') — host-side watch. */
354
- readonly bootloaderPid?: string;
355
- };
356
- };
357
- /** PWM channels with DT specs. */
358
- readonly pwm?: {
359
- readonly specs: readonly ZephyrPwmSpec[];
360
- /**
361
- * Matrix PWM capability (ESP32 LEDC) — channels assigned to the driven
362
- * pins at build time instead of enumerated statically. `specs` may be
363
- * empty when only the matrix is declared.
364
- */
365
- readonly matrix?: ZephyrPwmMatrix;
366
- /**
367
- * Timer input clock (Hz) for the synthesized specs' controllers — the
368
- * number the 16-bit overflow check divides by (STM32: APB clock × the
369
- * timer multiplier; blackpill TIM4 = 96 MHz). When set, the overlay
370
- * generator derives an `st,prescaler` for the timers node so slow
371
- * periods (servo 20 ms) fit the 16-bit ARR — without it pwm_stm32
372
- * rejects the channel ("period cycles exceeds 16-bit timer limit").
373
- */
374
- readonly clockHz?: number;
375
- };
376
- /** ADC: the ADC device node label + the pin→channel map. */
377
- readonly adc?: {
378
- readonly nodeLabel: string;
379
- readonly channels: readonly ZephyrAdcChannel[];
380
- /** Reference voltage in millivolts (nRF internal = 3000 for VDD/4 + gain 1/4… use 3000). */
381
- readonly vrefMv: number;
382
- /** ADC resolution in bits. */
383
- readonly resolution: number;
384
- /**
385
- * Zephyr `enum adc_gain` macro for the channel setup, e.g.
386
- * 'ADC_GAIN_1_4' (nRF SAADC default) or 'ADC_GAIN_1' (STM32 driver
387
- * requires exactly this). Defaults to 'ADC_GAIN_1_4'.
388
- */
389
- readonly gain?: string;
390
- /**
391
- * Zephyr `enum adc_reference` macro, e.g. 'ADC_REF_INTERNAL'. Defaults to
392
- * 'ADC_REF_INTERNAL' — on nRF that is the 0.6 V internal ref measured
393
- * through the gain divider; the STM32 driver ALSO requires
394
- * ADC_REF_INTERNAL (Zephyr maps it to the VREF+ pad) with vrefMv = VDDA.
395
- */
396
- readonly reference?: string;
397
- };
398
- /**
399
- * DAC: the DAC device node label + the pin→channel map. Present only on chips
400
- * with a DAC (ESP32 has 2 channels on GPIO25/26; ESP32-S3 and nRF52840 have
401
- * none). Read by profileDiagnostics to flag dac.* usage on chips without it.
402
- */
403
- readonly dac?: {
404
- readonly device: string;
405
- readonly channels: readonly ZephyrDacChannel[];
406
- };
407
- /** Watchdog node label, e.g. 'wdt0'. */
408
- readonly wdt?: { readonly nodeLabel: string };
409
- /**
410
- * Storage partition to synthesize when the board DTS ships none. Boards
411
- * with an MCUboot-style partition map (most STM32s) define boot/slot
412
- * partitions but no `storage_partition`, which the Preferences/FS backends
413
- * (ZMS/littlefs) require. Present = "the overlay generator must declare
414
- * this partition under &flash0"; boards whose DTS already carries one
415
- * (ESP32 devkits) omit it — the overlay only adds the /chosen pointer.
416
- * The region must cover ≥2 flash pages (ZMS minimum) and stay clear of
417
- * the linked application image.
418
- */
419
- readonly storage?: {
420
- /** Partition start offset in flash, page-aligned. */
421
- readonly offset: number;
422
- /** Partition size in bytes, a multiple of the flash page size. */
423
- readonly size: number;
424
- /** True when the board's own DTS already declares this partition — the
425
- * overlay must only point /chosen at it, never redeclare the node. */
426
- readonly preexisting?: boolean;
427
- };
428
- /**
429
- * Hardware timers exposed as Zephyr counter devices. `instance` (the HAL
430
- * hwtimer.* op's instance index) maps to `controllers[instance].nodeLabel`.
431
- * Omit on chips whose counter nodes are kernel-owned or unavailable; the
432
- * lowering then lowers to a comment and profileDiagnostics flags usage.
433
- */
434
- readonly hwtimer?: { readonly controllers: readonly ZephyrBusController[] };
435
- /**
436
- * WiFi capability marker. Present only on chips with a WiFi radio (ESP32-S3).
437
- * Read by profileDiagnostics to flag wifi.* usage on chips without a radio.
438
- * Omit on radioless chips (nRF52840) — its absence is the "no WiFi" signal.
439
- */
440
- readonly wifi?: { readonly supported: true };
441
- /**
442
- * Probe methods the board supports, in user-facing terms. Each entry maps a
443
- * friendly id (`stlink`, `dfu`, `jlink`, …) to the west runner it drives
444
- * plus any args the method always needs — the hardware quirks (e.g. openocd
445
- * needing `reset_config none` when the SRST line is unwired) live here,
446
- * verified with the board, instead of in user configs. One probe method
447
- * serves BOTH flashing and debugging (the same attach session); entries
448
- * that cannot debug (bootloaders) set `debug: false`. Users select one via
449
- * `zephyr.probe` in cuttlefish.config.ts or `--probe` on the CLI;
450
- * `zephyr.runner`/`runnerArgs` remain the raw escape hatch underneath.
451
- */
452
- readonly probeMethods?: readonly ZephyrProbeMethod[];
453
- /**
454
- * Silicon-level inputs for the custom-board generator — present when the
455
- * chip was resolved from an MCU package's `zephyr` block (an MCU-only
456
- * config with no board package). The generator emits an out-of-tree Zephyr
457
- * board (`boards/typecad/<name>/` in the project) from exactly this data:
458
- * SoC name, devicetree includes, the default console mux, and the default
459
- * clock plan. Absent on board-resolved chips (their board already exists).
460
- */
461
- readonly customBoard?: ZephyrCustomBoardData;
462
- }
463
-
464
- /**
465
- * Everything the custom-board generator needs from the silicon to emit a
466
- * minimal, buildable out-of-tree board for a chip with no board package.
467
- */
468
- export interface ZephyrCustomBoardData {
469
- /** Zephyr SoC name(s) for board.yml + the Kconfig SOC_* selection. */
470
- readonly socs: readonly string[];
471
- /** Devicetree includes for the generated board DTS root (SoC + pinctrl). */
472
- readonly dtsIncludes: readonly string[];
473
- /** The default console the generated board enables. */
474
- readonly console: {
475
- /** Controller nodelabel, e.g. 'usart1'. */
476
- readonly nodeLabel: string;
477
- /** TX pinctrl token from the SoC's pinctrl dtsi, e.g. 'usart1_tx_pa9'. */
478
- readonly tx: string;
479
- /** RX pinctrl token, e.g. 'usart1_rx_pa10'. */
480
- readonly rx: string;
481
- /** Baud rate (the DT `current-speed`). */
482
- readonly speed: number;
483
- };
484
- /**
485
- * Default clock plan — the numbers the generated DTS writes into the SoC's
486
- * clock nodes (HSE crystal frequency, PLL dividers, bus prescalers). A
487
- * board package overrides with its own crystal/plan; a custom board uses
488
- * this silicon default.
489
- */
490
- readonly clocks: {
491
- /** HSE crystal frequency in MHz. */
492
- readonly hseMHz: number;
493
- /** PLL divider/multiplier plan. */
494
- readonly pll: {
495
- readonly divM: number;
496
- readonly mulN: number;
497
- readonly divP: number;
498
- readonly divQ: number;
499
- };
500
- /** System clock frequency in MHz (the &rcc clock-frequency). */
501
- readonly sysMHz: number;
502
- readonly ahbPrescaler: number;
503
- readonly apb1Prescaler: number;
504
- readonly apb2Prescaler: number;
505
- };
506
- /**
507
- * Silicon USB node to alias as `usb.controller` in the generated DTS
508
- * (e.g. 'usbotg_fs' aliased as 'zephyr_udc0'). Omit when usb is absent.
509
- */
510
- readonly usbNode?: string;
511
- /**
512
- * Pinctrl tokens muxing the USB node's pins (e.g.
513
- * 'usb_otg_fs_dm_pa11'/'usb_otg_fs_dp_pa12'). The st,stm32-otgfs binding
514
- * requires pinctrl-0 on an enabled node, so the generated board pre-enables
515
- * the USB node with exactly these (the blackpill shape). Omit when the
516
- * SoC's USB needs no board-side muxing.
517
- */
518
- readonly usbPinctrl?: readonly string[];
519
- /**
520
- * ADC node the generated board must pre-enable with the SoC driver's
521
- * required properties — e.g. the STM32 F4 binding rejects an enabled adc
522
- * node without `st,adc-clock-source`/`st,adc-prescaler` (upstream boards
523
- * set them in their DTS; a custom board has none, so the generator emits
524
- * them from this data). The baseline pinctrl satisfies the binding's
525
- * pinctrl-0 requirement; the usage-driven overlay rewrites it to the
526
- * channels the program actually reads. Omit on SoCs whose ADC needs no
527
- * board-side enabling.
528
- */
529
- readonly adcNode?: {
530
- readonly nodeLabel: string;
531
- /** The binding's clock-source property value (e.g. 'SYNC'). */
532
- readonly clockSource: string;
533
- /** The binding's prescaler property value (e.g. 2). */
534
- readonly prescaler: number;
535
- /** Baseline pinctrl token (e.g. 'adc1_in1_pa1'). */
536
- readonly pinctrl: string;
537
- };
538
- }
539
-
540
- /**
541
- * A named way to attach a probe to a board — what the user picks, and what
542
- * flashing/debugging lower to.
543
- */
544
- export interface ZephyrProbeMethod {
545
- /** User-facing id, stable per board (`stlink`, `dfu`, `jlink`, `uf2`, …). */
546
- readonly id: string;
547
- /** The west runner this method drives (flash and debug). */
548
- readonly runner: string;
549
- /** Args always passed with this method (before any user runnerArgs). */
550
- readonly args?: readonly string[];
551
- /** One-line human description for the wizard, doctor, and error messages. */
552
- readonly description?: string;
553
- /** Whether this method can debug (default true — SWD/JTAG probes can,
554
- * bootloaders cannot and set this false explicitly). */
555
- readonly debug?: boolean;
556
- /** cortex-debug: the wire protocol (default 'swd'; esp_usb_jtag is 'jtag'). */
557
- readonly debugInterface?: 'swd' | 'jtag';
558
- /** cortex-debug servertype=jlink: the J-Link device name (e.g. 'STM32F411CE'). */
559
- readonly debugDevice?: string;
560
- /** Raw OpenOCD cfg lines for the debug server config (e.g. 'reset_config
561
- * none') — the cfg-file form of the quirks `args` carry for west. */
562
- readonly debugCfg?: readonly string[];
563
- /** OpenOCD cfg `source [find …]` lines for the debug server (interface +
564
- * target configs). Omitted entries fall back to the framework default. */
565
- readonly debugCfgSource?: readonly string[];
566
- }
567
-
1
+ // ---------------------------------------------------------------------------
2
+ // Zephyr chip descriptor — pure-data model
3
+ //
4
+ // Mirrors the per-framework chip-descriptor pattern established by
5
+ // framework-esp32 (Esp32ChipDescriptor) and framework-avr (AVRChipDescriptor):
6
+ // the framework owns its own device-tree-derived descriptor, keyed off the
7
+ // Zephyr board target string in frameworkData.buildTarget. The board/MCU
8
+ // packages are deliberately NOT read at emit time (see the framework-package
9
+ // data-flow split); this descriptor is the source the lowering reads.
10
+ //
11
+ // No behavior — the lowering code in src/lowering/*.ts reads getActiveChip()
12
+ // to resolve pins to devicetree specs and raw-controller fallbacks.
13
+ // ---------------------------------------------------------------------------
14
+
15
+ /**
16
+ * A GPIO pin described as a devicetree spec.
17
+ *
18
+ * Zephyr addresses GPIO via `struct gpio_dt_spec` resolved from devicetree
19
+ * aliases/labels (e.g. DT_ALIAS(led0)). The dtSpec form is preferred because
20
+ * `gpio_pin_set_dt()` honors the node's polarity flags — so an active-low LED
21
+ * (logical 1 = LED on) is handled by the DT `GPIO_ACTIVE_LOW` flag, not by the
22
+ * generated C++.
23
+ */
24
+ export interface ZephyrGpioDtSpec {
25
+ /** GPIO number — matches the HAL op `pin` field (P0.X → X, P1.X → 32+X). */
26
+ readonly pin: number;
27
+ /**
28
+ * Devicetree alias/nodelabel macro, e.g. `led0`, `sw0`, `led1`.
29
+ * Emitted as `GPIO_DT_SPEC_GET(DT_ALIAS(<dtSpec>), gpios)`.
30
+ */
31
+ readonly dtSpec: string;
32
+ }
33
+
34
+ /**
35
+ * A GPIO controller devicetree node, and the HAL pin-number range it owns.
36
+ *
37
+ * Most SoCs expose a single GPIO controller (nRF52840: `gpio0` owns every
38
+ * pin). SoCs that split GPIO across multiple devicetree nodes — e.g. the
39
+ * ESP32-S3 (`gpio0`: pins 0–31, `gpio1`: pins 32–48) — list one entry per
40
+ * controller so the lowering can route a HAL pin to the owning controller at
41
+ * runtime. Pin numbers match the HAL op `pin` field.
42
+ */
43
+ export interface ZephyrGpioController {
44
+ /** Devicetree nodelabel, e.g. 'gpio0', 'gpio1'. */
45
+ readonly nodelabel: string;
46
+ /** First HAL pin number owned by this controller (inclusive). */
47
+ readonly minPin: number;
48
+ /** Last HAL pin number owned by this controller (inclusive). */
49
+ readonly maxPin: number;
50
+ }
51
+
52
+ /**
53
+ * A bus controller (I2C / SPI / UART) described by its devicetree nodelabel.
54
+ *
55
+ * Zephyr resolves the `const struct device*` at compile time via
56
+ * `DEVICE_DT_GET(DT_NODELABEL(<nodeLabel>))`, so unlike ESP-IDF there is no
57
+ * lazy handle resolution — the lowering emits the macro directly.
58
+ */
59
+ export interface ZephyrBusController {
60
+ /** Devicetree nodelabel, e.g. 'i2c1', 'spi2', 'uart0'. */
61
+ readonly nodeLabel: string;
62
+ /**
63
+ * Counter child form only: the labeled TIMER PARENT's nodelabel (ESP32
64
+ * timer0-3). The counter device is an unlabeled `counter {}` child; the
65
+ * nodeLabel above is a label the generated overlay defines on that child,
66
+ * and this field tells the overlay which parent to attach it to.
67
+ */
68
+ readonly counterParent?: string;
69
+ /**
70
+ * Synthesized pinctrl group, for controllers whose board DT ships no
71
+ * default group (e.g. uart1 on rpi_pico/rpi_pico2 — the mainline board DT
72
+ * only pins uart0). When present, the overlay generator emits the group
73
+ * under `&pinctrl` and wires `pinctrl-0`/`pinctrl-names` onto the
74
+ * controller when enabling it. RP2xxx pinmux is fully muxable per pad, so
75
+ * the group is pure data: which pads carry the signals.
76
+ */
77
+ readonly pinctrl?: {
78
+ /** Pinmux header to #include (token definitions). */
79
+ readonly include: string;
80
+ /** Output-signal pinmux tokens (emitted as group1). */
81
+ readonly pinmux: readonly string[];
82
+ /** Input-signal pinmux tokens (emitted as group2 with input-enable). */
83
+ readonly inputPinmux?: readonly string[];
84
+ /**
85
+ * `#define` lines emitted (ifndef-guarded) BEFORE the include — for
86
+ * upstream header bugs where a token's macro body references an
87
+ * undefined helper (e.g. RP2_PINCTRL_GPIO_FUNC_UART_ALT in Zephyr's
88
+ * rp2350 pinctrl headers, unreferenced by mainline so never noticed).
89
+ */
90
+ readonly defines?: readonly string[];
91
+ };
92
+ /**
93
+ * Reference an EXISTING pinctrl group (defined in the board's pinctrl
94
+ * dtsi but not attached to the node) instead of synthesizing one — e.g.
95
+ * uart1_default on esp32s3_devkitc. The overlay wires
96
+ * `pinctrl-0 = <&<group>>` when enabling the controller.
97
+ */
98
+ readonly pinctrlRef?: string;
99
+ /**
100
+ * Raw devicetree property lines emitted inside the enable block — for
101
+ * bindings with required properties the board DTS only sets on its own
102
+ * wired-up nodes (e.g. `current-speed` on the Picos' PL011 UARTs).
103
+ */
104
+ readonly props?: readonly string[];
105
+ }
106
+
107
+ /**
108
+ * A PWM channel described as a devicetree spec.
109
+ *
110
+ * Two forms, mutually exclusive:
111
+ * - **Board-shipped alias:** `dtSpec` names a DT alias the board's own DTS
112
+ * already defines (e.g. the XIAO's `pwm-led0`). Emitted as
113
+ * `PWM_DT_SPEC_GET(DT_ALIAS(<dtSpec>))`.
114
+ * - **Synthesized** (controller + channel): the board DTS enables a PWM
115
+ * controller node (e.g. `pwm4`) but defines no alias for it. The overlay
116
+ * generator synthesizes a `pwm-leds` consumer node + a `tc-pwm<pin>` alias
117
+ * in `<board>.overlay`; the lowering emits
118
+ * `PWM_DT_SPEC_GET(DT_ALIAS(tc-pwm<pin>))`. Both sides derive the alias
119
+ * name from the pin, so they always agree.
120
+ *
121
+ * `pwm_set_pulse_dt(&spec, pulse_ns)` honors the spec's period/polarity.
122
+ */
123
+ export interface ZephyrPwmSpec {
124
+ /** GPIO number (matches the HAL op `pin` field). */
125
+ readonly pin: number;
126
+ /** Board-shipped DT alias, e.g. 'pwm-led0'. Omit when using the
127
+ * synthesized form (controller + channel). */
128
+ readonly dtSpec?: string;
129
+ /** Synthesized form: PWM controller DT nodelabel, e.g. 'pwm4' (the STM32
130
+ * timer's pwm child node). The overlay's pwm-leds node consumes it. */
131
+ readonly controller?: string;
132
+ /** Synthesized form: channel index within the controller (1-based timer
133
+ * channel, matching the `pwms` binding's channel cell). */
134
+ readonly channel?: number;
135
+ /** Synthesized form: period in nanoseconds, baked into the DT spec. The
136
+ * lowering scales duty against `spec.period`. Default 20 000 000 (20 ms /
137
+ * 50 Hz — the servo convention; harmless for LED dimming). */
138
+ readonly periodNs?: number;
139
+ /** Synthesized form: PWM polarity flag. Default PWM_POLARITY_NORMAL. */
140
+ readonly polarity?: string;
141
+ /**
142
+ * SoC pinctrl dtsi token muxing this channel's pin to the timer (e.g.
143
+ * 'tim4_ch1_pb6' on STM32). Required on custom boards — the st,stm32-pwm
144
+ * binding demands pinctrl-0 on an enabled node and only a board DTS (or
145
+ * the custom-board generator, fed by this token) can provide it. Also
146
+ * gates the generated board's `pwmN: pwm { }` label declaration: the
147
+ * overlay references `&<controller>`, a label that otherwise exists only
148
+ * when a board DTS defines it.
149
+ */
150
+ readonly pinctrl?: string;
151
+ }
152
+
153
+ /**
154
+ * A "PWM matrix" controller: any listed pin can carry any channel, routed by
155
+ * the SoC's GPIO matrix rather than a fixed timer-channel↔pad map.
156
+ *
157
+ * ESP32 LEDC is the shape (espressif,esp32-ledc): 8 channels, each routable
158
+ * to (almost) any pad via a pinctrl pinmux token (`LEDC_CH<ch>_GPIO<pin>`).
159
+ * A static `specs` list cannot express this — two arbitrary pins would
160
+ * collide on a statically assigned channel — so the channel assignment is
161
+ * made at build time: the pins the program actually drives are assigned
162
+ * channels 0..N-1 (ascending pin order, capped at `channelCount`), and the
163
+ * overlay generator emits the pinctrl group + per-channel child nodes the
164
+ * espressif,esp32-ledc binding requires. The emitted C++ is channel-blind:
165
+ * it addresses each pin via the same `DT_ALIAS(tc-pwm<pin>)` the synthesized
166
+ * static form uses, so the two paths share the lowering.
167
+ */
168
+ export interface ZephyrPwmMatrix {
169
+ /** PWM controller DT nodelabel, e.g. 'ledc0'. */
170
+ readonly controller: string;
171
+ /** Channels the controller exposes (ESP32-S3 LEDC: 8). */
172
+ readonly channelCount: number;
173
+ /**
174
+ * HAL pins usable as PWM outputs. This is the safety filter as much as the
175
+ * capability list — on the ESP32-S3 it excludes the boot-strap pin, the
176
+ * USB D+/D− pads, the flash/PSRAM pins (GPIO 26–32), the octal-PSRAM pins
177
+ * (GPIO 33–37), and the console UART pads (GPIO 43/44).
178
+ */
179
+ readonly pins: readonly number[];
180
+ }
181
+
182
+ /**
183
+ * A GPIO pin usable as an interrupt source.
184
+ *
185
+ * Emitted as `struct gpio_dt_spec __tc_int<N> = GPIO_DT_SPEC_GET(DT_ALIAS(<dtSpec>), gpios)`
186
+ * + a `struct gpio_callback` registered via `gpio_add_callback`.
187
+ */
188
+ export interface ZephyrInterruptPin {
189
+ /** GPIO number (matches the HAL op `pin` field). */
190
+ readonly pin: number;
191
+ /** Devicetree alias, e.g. 'sw0', or a nodelabel. */
192
+ readonly dtSpec: string;
193
+ }
194
+
195
+ /**
196
+ * An ADC channel: which ADC input a given HAL pin maps to.
197
+ *
198
+ * The XIAO nRF52840 has no pre-declared ADC channel nodes in devicetree, so the
199
+ * lowering emits `adc_channel_setup` against `DEVICE_DT_GET(DT_NODELABEL(adc))`
200
+ * using the `channel` index here (SAADC AIN0–AIN7).
201
+ */
202
+ export interface ZephyrAdcChannel {
203
+ /** GPIO number (matches the HAL op `pin` field). */
204
+ readonly pin: number;
205
+ /** ADC channel index (nRF SAADC AIN0–AIN7; STM32 ADC1_IN0–IN9). */
206
+ readonly channel: number;
207
+ /**
208
+ * ADC device node label that OWNS this channel when the SoC has more than
209
+ * one ADC controller (STM32 adc1/adc2, ESP32 units), e.g. 'adc2'. Omitted
210
+ * for channels on the descriptor's primary controller (`adc.nodeLabel`) —
211
+ * a single-controller manifest is unchanged. Channel indices are unique
212
+ * only WITHIN a controller; the pair (controller, channel) is the key.
213
+ */
214
+ readonly controller?: string;
215
+ /**
216
+ * Pinctrl node label that muxes this pin to analog mode, e.g.
217
+ * 'adc1_in0_pa0' (STM32). When present, the overlay generator rewrites the
218
+ * ADC node's pinctrl-0 to the channels the program actually reads — SoCs
219
+ * like STM32 leave the pad in GPIO mode otherwise and reads float.
220
+ * Omit on SoCs whose ADC needs no pad muxing (nRF SAADC, RP2040).
221
+ */
222
+ readonly pinctrl?: string;
223
+ }
224
+
225
+ /**
226
+ * A DAC channel: which DAC output a given HAL pin maps to. The lowering emits
227
+ * `dac_channel_setup` + `dac_write_value` against the DAC device node.
228
+ */
229
+ export interface ZephyrDacChannel {
230
+ /** GPIO number (matches the HAL op `pin` field). */
231
+ readonly pin: number;
232
+ /** DAC channel index (ESP32: GPIO25 → 1, GPIO26 → 2). */
233
+ readonly channel: number;
234
+ /** DAC resolution in bits (ESP32 DAC is 8-bit). */
235
+ readonly resolution: number;
236
+ /** Pinctrl node name routing the channel to its pad (STM32 harvest). */
237
+ readonly pinctrl?: string;
238
+ }
239
+
240
+ /**
241
+ * Pure-data descriptor for a Zephyr board + its SoC's peripheral layout.
242
+ */
243
+ export interface ZephyrChipDescriptor {
244
+ /** Zephyr board target (the `west build -b <id>` argument), e.g. 'xiao_ble'. */
245
+ readonly id: string;
246
+ /** SoC family, e.g. 'nrf52840'. */
247
+ readonly soc: string;
248
+ /**
249
+ * How confident the framework is in this descriptor's facts.
250
+ * - 'validated' — the soc is part of the hardware-tested set; every field
251
+ * was verified against the pinned Zephyr tree and real hardware.
252
+ * - 'derived' — reconstructed from data (board/MCU packages, DTS reading)
253
+ * but never hardware-verified; capability errors may be less precise.
254
+ */
255
+ readonly tier?: 'validated' | 'derived';
256
+ /**
257
+ * Datasheet pin-naming convention — how a controller/pin pair becomes the
258
+ * schematic-facing name the generated board module exports (the
259
+ * `Pin.fromPort()` identity). One of:
260
+ * - 'esp32-gpio' — flat numbering, `GPION` (esp32, esp32s3, esp32c*)
261
+ * - 'stm32-port' — one controller per port, `P<port><bit>` (PA5, PB12)
262
+ * - 'nrf-port' — P0.28 / P1.11 style (`P<port>.<bit>`)
263
+ * - 'rp-gpio' — `GP<n>` flat numbering
264
+ * - 'samd-port' — PA/PB ports like stm32-port
265
+ * Absent on tier-3 socs with no known convention (the generated board
266
+ * exposes only connector/alias pins + LED/BUTTON).
267
+ */
268
+ readonly pinNaming?: 'esp32-gpio' | 'stm32-port' | 'nrf-port' | 'rp-gpio' | 'samd-port';
269
+ /**
270
+ * Pins that exist in the controller ranges but must NOT be exported as
271
+ * usable GPIOs — strapping pads, flash/PSRAM, USB D+/-. The generated
272
+ * board module's pin list subtracts these.
273
+ */
274
+ readonly excludedPins?: readonly number[];
275
+ /**
276
+ * Default GPIO controller nodelabel for the raw-pin fallback. Pins not in
277
+ * `gpio.dtSpecs` are addressed via
278
+ * `DEVICE_DT_GET(DT_NODELABEL(<gpioController>))` + gpio_pin_*_raw().
279
+ *
280
+ * For SoCs that split GPIO across multiple devicetree nodes, `gpioControllers`
281
+ * overrides this per pin range; this field is then only the out-of-range
282
+ * fallback (so a single-controller board is unaffected by it).
283
+ */
284
+ readonly gpioController: string;
285
+ /**
286
+ * Per-range GPIO controllers for SoCs that split GPIO across multiple
287
+ * devicetree nodes (ESP32-S3: `gpio0` 0–31, `gpio1` 32–48; STM32: one
288
+ * controller per port — `gpioa` 0–15, `gpiob` 16–31, `gpioc` 32–47).
289
+ * When present, the lowering routes a HAL pin to its owning controller at
290
+ * runtime via the emitted `__tc_gpio_dev(pin)` dispatcher; `gpioController`
291
+ * is the fallback. Omit on single-controller SoCs (RP2040, …) — every pin
292
+ * is on the one controller described by `gpioController`.
293
+ *
294
+ * NUMBERING RULE (load-bearing): `minPin` must equal the controller's port
295
+ * base so the port-relative raw index is `pin - minPin` (STM32 PB12 = pin
296
+ * 28 → raw 12 — the Zephyr raw API addresses the index WITHIN the
297
+ * controller). Number pins by port blocks and never contiguously across
298
+ * unbonded pins.
299
+ */
300
+ readonly gpioControllers?: readonly ZephyrGpioController[];
301
+ /** GPIO pins with devicetree specs (LEDs, buttons, board-defined pins). */
302
+ readonly gpio: {
303
+ readonly dtSpecs: readonly ZephyrGpioDtSpec[];
304
+ /** Interrupt-capable pins with DT specs (buttons etc.). */
305
+ readonly interruptPins?: readonly ZephyrInterruptPin[];
306
+ };
307
+ /** I2C controllers (board-wired). Index 0 = the primary bus. */
308
+ readonly i2c?: { readonly controllers: readonly ZephyrBusController[] };
309
+ /** SPI controllers (board-wired). Index 0 = the primary bus. */
310
+ readonly spi?: { readonly controllers: readonly ZephyrBusController[] };
311
+ /** UART controllers (board-wired). Index 0 = the primary port. */
312
+ readonly uart?: { readonly controllers: readonly ZephyrBusController[] };
313
+ /**
314
+ * USB device (CDC-ACM serial) capability. Zephyr "next" USB device stack:
315
+ * the UDC controller node (uniformly `zephyr_udc0` on every USB-capable
316
+ * board) plus `cdcInstances` CDC-ACM class child nodes, both composed in
317
+ * the generated overlay. The lowering addresses instance N as
318
+ * DT_NODELABEL(cdc_acm_uart<N>) — a UART-class device driven with the
319
+ * plain uart_* API. Boards without USB device support omit this field;
320
+ * usb.* HAL ops then fail with a clear "board does not expose USB" error.
321
+ */
322
+ readonly usb?: {
323
+ /** UDC controller nodelabel (convention: 'zephyr_udc0'). */
324
+ readonly controller: string;
325
+ /** How many CDC-ACM serial instances to compose (≥1). */
326
+ readonly cdcInstances: number;
327
+ /** USB vendor ID for the device descriptor ('0x2fe3' Zephyr-test default). */
328
+ readonly vid?: string;
329
+ /** USB product ID for the device descriptor ('0x0001' default). */
330
+ readonly pid?: string;
331
+ /**
332
+ * 1200-baud touch-to-reset (BOSSA-bootloader boards, e.g. SAM D21).
333
+ *
334
+ * Present = two things happen automatically:
335
+ * - Device side: the emitted USB shim registers a usbd message callback;
336
+ * when the host sets the CDC baud rate to 1200, the shim writes the
337
+ * bootloader's "stay resident" magic to the flag address and reboots —
338
+ * the board lands in the bootloader with no button press.
339
+ * - Host side: the bossac upload path opens the app's console port at
340
+ * 1200 baud to trigger the above, waits for the bootloader's USB
341
+ * identity, and points bossac at that port.
342
+ * Omit on boards without a cooperative bootloader (probe- or
343
+ * UF2-flashed boards don't need it).
344
+ */
345
+ readonly touchReset?: {
346
+ /** RAM address of the bootloader's stay-resident flag word
347
+ * (SAMD21G18A: 0x20007FFC — the last word of the 32 KB SRAM). */
348
+ readonly flagAddress: number;
349
+ /** Magic word the bootloader checks there (Arduino SAMD: 0x07738135). */
350
+ readonly magic: number;
351
+ /** Bootloader USB vendor id, hex string ('0x2341') — host-side watch. */
352
+ readonly bootloaderVid?: string;
353
+ /** Bootloader USB product id, hex string ('0x0057') — host-side watch. */
354
+ readonly bootloaderPid?: string;
355
+ };
356
+ };
357
+ /** PWM channels with DT specs. */
358
+ readonly pwm?: {
359
+ readonly specs: readonly ZephyrPwmSpec[];
360
+ /**
361
+ * Matrix PWM capability (ESP32 LEDC) — channels assigned to the driven
362
+ * pins at build time instead of enumerated statically. `specs` may be
363
+ * empty when only the matrix is declared.
364
+ */
365
+ readonly matrix?: ZephyrPwmMatrix;
366
+ /**
367
+ * Timer input clock (Hz) for the synthesized specs' controllers — the
368
+ * number the 16-bit overflow check divides by (STM32: APB clock × the
369
+ * timer multiplier; blackpill TIM4 = 96 MHz). When set, the overlay
370
+ * generator derives an `st,prescaler` for the timers node so slow
371
+ * periods (servo 20 ms) fit the 16-bit ARR — without it pwm_stm32
372
+ * rejects the channel ("period cycles exceeds 16-bit timer limit").
373
+ */
374
+ readonly clockHz?: number;
375
+ };
376
+ /** ADC: the ADC device node label + the pin→channel map. */
377
+ readonly adc?: {
378
+ readonly nodeLabel: string;
379
+ readonly channels: readonly ZephyrAdcChannel[];
380
+ /** Reference voltage in millivolts (nRF internal = 3000 for VDD/4 + gain 1/4… use 3000). */
381
+ readonly vrefMv: number;
382
+ /** ADC resolution in bits. */
383
+ readonly resolution: number;
384
+ /**
385
+ * Zephyr `enum adc_gain` macro for the channel setup, e.g.
386
+ * 'ADC_GAIN_1_4' (nRF SAADC default) or 'ADC_GAIN_1' (STM32 driver
387
+ * requires exactly this). Defaults to 'ADC_GAIN_1_4'.
388
+ */
389
+ readonly gain?: string;
390
+ /**
391
+ * Zephyr `enum adc_reference` macro, e.g. 'ADC_REF_INTERNAL'. Defaults to
392
+ * 'ADC_REF_INTERNAL' — on nRF that is the 0.6 V internal ref measured
393
+ * through the gain divider; the STM32 driver ALSO requires
394
+ * ADC_REF_INTERNAL (Zephyr maps it to the VREF+ pad) with vrefMv = VDDA.
395
+ */
396
+ readonly reference?: string;
397
+ };
398
+ /**
399
+ * DAC: the DAC device node label + the pin→channel map. Present only on chips
400
+ * with a DAC (ESP32 has 2 channels on GPIO25/26; ESP32-S3 and nRF52840 have
401
+ * none). Read by profileDiagnostics to flag dac.* usage on chips without it.
402
+ */
403
+ readonly dac?: {
404
+ readonly device: string;
405
+ readonly channels: readonly ZephyrDacChannel[];
406
+ };
407
+ /** Watchdog node label, e.g. 'wdt0'. */
408
+ readonly wdt?: { readonly nodeLabel: string };
409
+ /**
410
+ * Storage partition to synthesize when the board DTS ships none. Boards
411
+ * with an MCUboot-style partition map (most STM32s) define boot/slot
412
+ * partitions but no `storage_partition`, which the Preferences/FS backends
413
+ * (ZMS/littlefs) require. Present = "the overlay generator must declare
414
+ * this partition under &flash0"; boards whose DTS already carries one
415
+ * (ESP32 devkits) omit it — the overlay only adds the /chosen pointer.
416
+ * The region must cover ≥2 flash pages (ZMS minimum) and stay clear of
417
+ * the linked application image.
418
+ */
419
+ readonly storage?: {
420
+ /** Partition start offset in flash, page-aligned. */
421
+ readonly offset: number;
422
+ /** Partition size in bytes, a multiple of the flash page size. */
423
+ readonly size: number;
424
+ /** True when the board's own DTS already declares this partition — the
425
+ * overlay must only point /chosen at it, never redeclare the node. */
426
+ readonly preexisting?: boolean;
427
+ };
428
+ /**
429
+ * Hardware timers exposed as Zephyr counter devices. `instance` (the HAL
430
+ * hwtimer.* op's instance index) maps to `controllers[instance].nodeLabel`.
431
+ * Omit on chips whose counter nodes are kernel-owned or unavailable; the
432
+ * lowering then lowers to a comment and profileDiagnostics flags usage.
433
+ */
434
+ readonly hwtimer?: { readonly controllers: readonly ZephyrBusController[] };
435
+ /**
436
+ * WiFi capability marker. Present only on chips with a WiFi radio (ESP32-S3).
437
+ * Read by profileDiagnostics to flag wifi.* usage on chips without a radio.
438
+ * Omit on radioless chips (nRF52840) — its absence is the "no WiFi" signal.
439
+ */
440
+ readonly wifi?: { readonly supported: true };
441
+ /**
442
+ * Probe methods the board supports, in user-facing terms. Each entry maps a
443
+ * friendly id (`stlink`, `dfu`, `jlink`, …) to the west runner it drives
444
+ * plus any args the method always needs — the hardware quirks (e.g. openocd
445
+ * needing `reset_config none` when the SRST line is unwired) live here,
446
+ * verified with the board, instead of in user configs. One probe method
447
+ * serves BOTH flashing and debugging (the same attach session); entries
448
+ * that cannot debug (bootloaders) set `debug: false`. Users select one via
449
+ * `zephyr.probe` in typecad-hal.config.ts or `--probe` on the CLI;
450
+ * `zephyr.runner`/`runnerArgs` remain the raw escape hatch underneath.
451
+ */
452
+ readonly probeMethods?: readonly ZephyrProbeMethod[];
453
+ /**
454
+ * Silicon-level inputs for the custom-board generator — present when the
455
+ * chip was resolved from an MCU package's `zephyr` block (an MCU-only
456
+ * config with no board package). The generator emits an out-of-tree Zephyr
457
+ * board (`boards/typecad/<name>/` in the project) from exactly this data:
458
+ * SoC name, devicetree includes, the default console mux, and the default
459
+ * clock plan. Absent on board-resolved chips (their board already exists).
460
+ */
461
+ readonly customBoard?: ZephyrCustomBoardData;
462
+ }
463
+
464
+ /**
465
+ * Everything the custom-board generator needs from the silicon to emit a
466
+ * minimal, buildable out-of-tree board for a chip with no board package.
467
+ */
468
+ export interface ZephyrCustomBoardData {
469
+ /** Zephyr SoC name(s) for board.yml + the Kconfig SOC_* selection. */
470
+ readonly socs: readonly string[];
471
+ /** Devicetree includes for the generated board DTS root (SoC + pinctrl). */
472
+ readonly dtsIncludes: readonly string[];
473
+ /** The default console the generated board enables. */
474
+ readonly console: {
475
+ /** Controller nodelabel, e.g. 'usart1'. */
476
+ readonly nodeLabel: string;
477
+ /** TX pinctrl token from the SoC's pinctrl dtsi, e.g. 'usart1_tx_pa9'. */
478
+ readonly tx: string;
479
+ /** RX pinctrl token, e.g. 'usart1_rx_pa10'. */
480
+ readonly rx: string;
481
+ /** Baud rate (the DT `current-speed`). */
482
+ readonly speed: number;
483
+ };
484
+ /**
485
+ * Default clock plan — the numbers the generated DTS writes into the SoC's
486
+ * clock nodes (HSE crystal frequency, PLL dividers, bus prescalers). A
487
+ * board package overrides with its own crystal/plan; a custom board uses
488
+ * this silicon default.
489
+ */
490
+ readonly clocks: {
491
+ /** HSE crystal frequency in MHz. */
492
+ readonly hseMHz: number;
493
+ /** PLL divider/multiplier plan. */
494
+ readonly pll: {
495
+ readonly divM: number;
496
+ readonly mulN: number;
497
+ readonly divP: number;
498
+ readonly divQ: number;
499
+ };
500
+ /** System clock frequency in MHz (the &rcc clock-frequency). */
501
+ readonly sysMHz: number;
502
+ readonly ahbPrescaler: number;
503
+ readonly apb1Prescaler: number;
504
+ readonly apb2Prescaler: number;
505
+ };
506
+ /**
507
+ * Silicon USB node to alias as `usb.controller` in the generated DTS
508
+ * (e.g. 'usbotg_fs' aliased as 'zephyr_udc0'). Omit when usb is absent.
509
+ */
510
+ readonly usbNode?: string;
511
+ /**
512
+ * Pinctrl tokens muxing the USB node's pins (e.g.
513
+ * 'usb_otg_fs_dm_pa11'/'usb_otg_fs_dp_pa12'). The st,stm32-otgfs binding
514
+ * requires pinctrl-0 on an enabled node, so the generated board pre-enables
515
+ * the USB node with exactly these (the blackpill shape). Omit when the
516
+ * SoC's USB needs no board-side muxing.
517
+ */
518
+ readonly usbPinctrl?: readonly string[];
519
+ /**
520
+ * ADC node the generated board must pre-enable with the SoC driver's
521
+ * required properties — e.g. the STM32 F4 binding rejects an enabled adc
522
+ * node without `st,adc-clock-source`/`st,adc-prescaler` (upstream boards
523
+ * set them in their DTS; a custom board has none, so the generator emits
524
+ * them from this data). The baseline pinctrl satisfies the binding's
525
+ * pinctrl-0 requirement; the usage-driven overlay rewrites it to the
526
+ * channels the program actually reads. Omit on SoCs whose ADC needs no
527
+ * board-side enabling.
528
+ */
529
+ readonly adcNode?: {
530
+ readonly nodeLabel: string;
531
+ /** The binding's clock-source property value (e.g. 'SYNC'). */
532
+ readonly clockSource: string;
533
+ /** The binding's prescaler property value (e.g. 2). */
534
+ readonly prescaler: number;
535
+ /** Baseline pinctrl token (e.g. 'adc1_in1_pa1'). */
536
+ readonly pinctrl: string;
537
+ };
538
+ }
539
+
540
+ /**
541
+ * A named way to attach a probe to a board — what the user picks, and what
542
+ * flashing/debugging lower to.
543
+ */
544
+ export interface ZephyrProbeMethod {
545
+ /** User-facing id, stable per board (`stlink`, `dfu`, `jlink`, `uf2`, …). */
546
+ readonly id: string;
547
+ /** The west runner this method drives (flash and debug). */
548
+ readonly runner: string;
549
+ /** Args always passed with this method (before any user runnerArgs). */
550
+ readonly args?: readonly string[];
551
+ /** One-line human description for the wizard, doctor, and error messages. */
552
+ readonly description?: string;
553
+ /** Whether this method can debug (default true — SWD/JTAG probes can,
554
+ * bootloaders cannot and set this false explicitly). */
555
+ readonly debug?: boolean;
556
+ /** cortex-debug: the wire protocol (default 'swd'; esp_usb_jtag is 'jtag'). */
557
+ readonly debugInterface?: 'swd' | 'jtag';
558
+ /** cortex-debug servertype=jlink: the J-Link device name (e.g. 'STM32F411CE'). */
559
+ readonly debugDevice?: string;
560
+ /** Raw OpenOCD cfg lines for the debug server config (e.g. 'reset_config
561
+ * none') — the cfg-file form of the quirks `args` carry for west. */
562
+ readonly debugCfg?: readonly string[];
563
+ /** OpenOCD cfg `source [find …]` lines for the debug server (interface +
564
+ * target configs). Omitted entries fall back to the framework default. */
565
+ readonly debugCfgSource?: readonly string[];
566
+ }
567
+