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

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 (191) hide show
  1. package/README.md +22 -35
  2. package/dist/as-built.d.ts +33 -0
  3. package/dist/as-built.js +188 -0
  4. package/dist/async/timer-polyfill.js +1 -1
  5. package/dist/boardgen.d.ts +128 -0
  6. package/dist/boardgen.js +1366 -0
  7. package/dist/chips/board-overrides.d.ts +7 -0
  8. package/dist/chips/board-overrides.js +11 -0
  9. package/dist/chips/controllers.d.ts +28 -8
  10. package/dist/chips/controllers.js +49 -12
  11. package/dist/chips/esp32s3.js +49 -0
  12. package/dist/chips/index.d.ts +6 -12
  13. package/dist/chips/index.js +18 -34
  14. package/dist/chips/resolve.d.ts +16 -2
  15. package/dist/chips/resolve.js +298 -15
  16. package/dist/chips/soc/.d.ts +2 -0
  17. package/dist/chips/soc/.js +129 -0
  18. package/dist/chips/soc/esp32.d.ts +2 -0
  19. package/dist/chips/soc/esp32.js +120 -0
  20. package/dist/chips/soc/esp32c3.d.ts +2 -0
  21. package/dist/chips/soc/esp32c3.js +90 -0
  22. package/dist/chips/soc/esp32c6.d.ts +2 -0
  23. package/dist/chips/soc/esp32c6.js +109 -0
  24. package/dist/chips/soc/esp32s3.d.ts +2 -0
  25. package/dist/chips/soc/esp32s3.js +189 -0
  26. package/dist/chips/soc/index.d.ts +2 -0
  27. package/dist/chips/soc/index.js +23 -0
  28. package/dist/chips/soc/nrf52840.d.ts +2 -0
  29. package/dist/chips/soc/nrf52840.js +130 -0
  30. package/dist/chips/soc/rp2040.d.ts +2 -0
  31. package/dist/chips/soc/rp2040.js +141 -0
  32. package/dist/chips/soc/rp2350a.d.ts +2 -0
  33. package/dist/chips/soc/rp2350a.js +145 -0
  34. package/dist/chips/soc/samd21g18a.d.ts +2 -0
  35. package/dist/chips/soc/samd21g18a.js +143 -0
  36. package/dist/chips/soc/stm32f411xe.d.ts +2 -0
  37. package/dist/chips/soc/stm32f411xe.js +251 -0
  38. package/dist/chips/types.d.ts +382 -12
  39. package/dist/chips/xiao-ble.js +33 -0
  40. package/dist/display/profiles.js +1 -1
  41. package/dist/doctor.js +38 -4
  42. package/dist/dt-config/custom-board.d.ts +23 -0
  43. package/dist/dt-config/custom-board.js +227 -0
  44. package/dist/dt-config/kconfig.d.ts +83 -1
  45. package/dist/dt-config/kconfig.js +116 -27
  46. package/dist/dt-config/overlay.js +623 -18
  47. package/dist/framework.manifest.d.ts +20 -30
  48. package/dist/framework.manifest.js +124 -178
  49. package/dist/index.d.ts +4 -1
  50. package/dist/index.js +8 -2
  51. package/dist/lowering/adc.d.ts +26 -5
  52. package/dist/lowering/adc.js +137 -31
  53. package/dist/lowering/ble.js +31 -28
  54. package/dist/lowering/dac.js +9 -9
  55. package/dist/lowering/fs.js +18 -10
  56. package/dist/lowering/gpio.d.ts +2 -0
  57. package/dist/lowering/gpio.js +90 -10
  58. package/dist/lowering/http.js +39 -14
  59. package/dist/lowering/hwtimer.d.ts +4 -0
  60. package/dist/lowering/hwtimer.js +35 -10
  61. package/dist/lowering/i2c.js +46 -54
  62. package/dist/lowering/index.d.ts +5 -5
  63. package/dist/lowering/index.js +15 -16
  64. package/dist/lowering/interrupts.d.ts +22 -5
  65. package/dist/lowering/interrupts.js +104 -22
  66. package/dist/lowering/mqtt.js +12 -6
  67. package/dist/lowering/power.js +0 -4
  68. package/dist/lowering/preferences.js +49 -77
  69. package/dist/lowering/pulse.js +5 -36
  70. package/dist/lowering/pwm.d.ts +32 -3
  71. package/dist/lowering/pwm.js +105 -17
  72. package/dist/lowering/random.js +3 -3
  73. package/dist/lowering/sensor.d.ts +37 -0
  74. package/dist/lowering/sensor.js +119 -0
  75. package/dist/lowering/spi.d.ts +12 -0
  76. package/dist/lowering/spi.js +65 -40
  77. package/dist/lowering/thread.d.ts +14 -0
  78. package/dist/lowering/thread.js +55 -0
  79. package/dist/lowering/timing.js +20 -46
  80. package/dist/lowering/tone.js +18 -5
  81. package/dist/lowering/uart.d.ts +13 -0
  82. package/dist/lowering/uart.js +72 -51
  83. package/dist/lowering/usb.d.ts +34 -0
  84. package/dist/lowering/usb.js +206 -0
  85. package/dist/lowering/wdt.d.ts +1 -1
  86. package/dist/lowering/wdt.js +17 -7
  87. package/dist/lowering/wifi.d.ts +3 -2
  88. package/dist/lowering/wifi.js +120 -111
  89. package/dist/sdk/board-catalog-sync.d.ts +16 -0
  90. package/dist/sdk/board-catalog-sync.js +41 -0
  91. package/dist/sdk/board-data.generated.d.ts +2 -0
  92. package/dist/sdk/board-data.generated.js +4 -0
  93. package/dist/sdk/catalog-walker.d.ts +90 -0
  94. package/dist/sdk/catalog-walker.js +682 -0
  95. package/dist/sdk/dts-reader.d.ts +83 -0
  96. package/dist/sdk/dts-reader.js +596 -0
  97. package/dist/strategy.d.ts +136 -17
  98. package/dist/strategy.js +881 -212
  99. package/dist/toolchain/bossac-touch.d.ts +18 -0
  100. package/dist/toolchain/bossac-touch.js +88 -0
  101. package/dist/toolchain/compat.d.ts +2 -2
  102. package/dist/toolchain/compat.js +8 -3
  103. package/dist/toolchain/debug-config.d.ts +21 -26
  104. package/dist/toolchain/debug-config.js +212 -72
  105. package/dist/toolchain/env-check.d.ts +4 -4
  106. package/dist/toolchain/env-check.js +5 -5
  107. package/dist/toolchain/index.d.ts +66 -1
  108. package/dist/toolchain/index.js +713 -58
  109. package/dist/toolchain/scaffold.d.ts +9 -0
  110. package/dist/toolchain/scaffold.js +84 -7
  111. package/dist/toolchain/west-discover.d.ts +8 -1
  112. package/dist/toolchain/west-discover.js +19 -6
  113. package/dist/toolchain/west-spawn.js +17 -5
  114. package/installer/CHANGELOG.md +473 -0
  115. package/installer/README.md +328 -0
  116. package/installer/environment.yml +46 -0
  117. package/installer/etc/conda/activate.d/zephyr.bat +7 -0
  118. package/installer/etc/conda/activate.d/zephyr.ps1 +12 -0
  119. package/installer/etc/conda/activate.d/zephyr.sh +20 -0
  120. package/installer/etc/conda/deactivate.d/zephyr.bat +6 -0
  121. package/installer/etc/conda/deactivate.d/zephyr.ps1 +6 -0
  122. package/installer/etc/conda/deactivate.d/zephyr.sh +4 -0
  123. package/installer/install.mjs +580 -0
  124. package/installer/install.ps1 +619 -0
  125. package/installer/install.sh +310 -0
  126. package/installer/lib/detect-platform.sh +62 -0
  127. package/installer/lib/fetch-sdk.sh +304 -0
  128. package/installer/lib/init-workspace.sh +153 -0
  129. package/installer/lib/write-activation.sh +76 -0
  130. package/installer/patches/tfm-c-include-separators.patch +19 -0
  131. package/installer/patches/zephyr-tfm-nordic-zephyr-include.patch +24 -0
  132. package/installer/templates/project/.typecad/activate-zephyr.ps1 +31 -0
  133. package/installer/templates/project/.typecad/activate-zephyr.sh +31 -0
  134. package/installer/templates/project/.vscode/settings.json +30 -0
  135. package/installer/templates/project/README.md +58 -0
  136. package/installer/versions.env +110 -0
  137. package/package.json +16 -16
  138. package/src/as-built.ts +206 -0
  139. package/src/boardgen.ts +1428 -0
  140. package/src/chips/controllers.ts +61 -12
  141. package/src/chips/index.ts +35 -54
  142. package/src/chips/resolve.ts +316 -14
  143. package/src/chips/types.ts +388 -13
  144. package/src/display/profiles.ts +1 -1
  145. package/src/doctor.ts +110 -77
  146. package/src/dt-config/custom-board.ts +325 -0
  147. package/src/dt-config/kconfig.ts +177 -19
  148. package/src/dt-config/overlay.ts +1058 -450
  149. package/src/framework.manifest.ts +125 -178
  150. package/src/index.ts +57 -41
  151. package/src/lowering/adc.ts +222 -102
  152. package/src/lowering/ble.ts +32 -28
  153. package/src/lowering/dac.ts +82 -82
  154. package/src/lowering/fs.ts +18 -10
  155. package/src/lowering/gpio.ts +242 -152
  156. package/src/lowering/http.ts +512 -488
  157. package/src/lowering/hwtimer.ts +139 -101
  158. package/src/lowering/i2c.ts +116 -126
  159. package/src/lowering/index.ts +91 -93
  160. package/src/lowering/interrupts.ts +113 -21
  161. package/src/lowering/mqtt.ts +12 -6
  162. package/src/lowering/preferences.ts +327 -354
  163. package/src/lowering/pwm.ts +167 -74
  164. package/src/lowering/random.ts +3 -3
  165. package/src/lowering/sensor.ts +155 -0
  166. package/src/lowering/spi.ts +164 -124
  167. package/src/lowering/thread.ts +63 -0
  168. package/src/lowering/timing.ts +46 -72
  169. package/src/lowering/uart.ts +73 -51
  170. package/src/lowering/usb.ts +221 -0
  171. package/src/lowering/wdt.ts +95 -84
  172. package/src/lowering/wifi.ts +120 -111
  173. package/src/sdk/board-catalog-sync.ts +62 -0
  174. package/src/strategy.ts +888 -229
  175. package/src/toolchain/bossac-touch.ts +112 -0
  176. package/src/toolchain/compat.ts +8 -3
  177. package/src/toolchain/debug-config.ts +666 -522
  178. package/src/toolchain/env-check.ts +9 -9
  179. package/src/toolchain/index.ts +765 -44
  180. package/src/toolchain/scaffold.ts +81 -7
  181. package/src/toolchain/west-discover.ts +334 -316
  182. package/src/toolchain/west-spawn.ts +17 -5
  183. package/src/async/timer-polyfill.ts +0 -107
  184. package/src/chips/esp32.ts +0 -74
  185. package/src/chips/esp32s3.ts +0 -57
  186. package/src/chips/xiao-ble.ts +0 -70
  187. package/src/lowering/power.ts +0 -70
  188. package/src/lowering/pulse.ts +0 -93
  189. package/src/lowering/tone.ts +0 -60
  190. package/src/lowering/worker-backing.ts +0 -94
  191. package/src/lowering/worker.ts +0 -17
@@ -16,7 +16,8 @@
16
16
  // ---------------------------------------------------------------------------
17
17
 
18
18
  import type { SpawnSyncOptions } from 'node:child_process';
19
- import { dirname } from 'node:path';
19
+ import { dirname, join } from 'node:path';
20
+ import { existsSync } from 'node:fs';
20
21
  import { type WestInstall, discoverWest } from './west-discover.js';
21
22
 
22
23
  export interface WestInvocation {
@@ -57,8 +58,19 @@ export function buildEnv(install: WestInstall): NodeJS.ProcessEnv {
57
58
  if (install.zephyrBase && !env.ZEPHYR_BASE) {
58
59
  env.ZEPHYR_BASE = install.zephyrBase;
59
60
  }
60
- const bin = venvBinDir(install);
61
- if (bin) {
61
+ // SWD flashing (`zephyr.runner: 'openocd'`): west's openocd runner resolves
62
+ // a bare `openocd` from PATH. The Zephyr SDK ships it under
63
+ // hosttools/openocd/bin (the SDK's own setup.cmd puts that dir on PATH for
64
+ // activated terminals) — do the same for spawned west processes so ST-Link
65
+ // flashing works without activation. $ZEPHYR_SDK_INSTALL_DIR (set by an
66
+ // activated env) wins over the discovered install dir.
67
+ const sdkRoot = env.ZEPHYR_SDK_INSTALL_DIR || install.sdkInstallDir;
68
+ const openocdBin = sdkRoot ? join(sdkRoot, 'hosttools', 'openocd', 'bin') : undefined;
69
+ const prepend = [
70
+ openocdBin !== undefined && existsSync(openocdBin) ? openocdBin : undefined,
71
+ venvBinDir(install),
72
+ ].filter((d): d is string => d !== undefined);
73
+ if (prepend.length > 0) {
62
74
  const sep = process.platform === 'win32' ? ';' : ':';
63
75
  // On Windows the PATH environment variable may be cased as `Path` (the
64
76
  // registry-native form, the only one populated when node is launched from
@@ -66,9 +78,9 @@ export function buildEnv(install: WestInstall): NodeJS.ProcessEnv {
66
78
  // casing can leave the other stale/empty, which under PowerShell would drop
67
79
  // the user's real PATH (cmake, ninja, …) — breaking `west` configure. Read
68
80
  // whichever casing is populated and write that same casing back, preserving
69
- // the full existing value with the venv dir prepended.
81
+ // the full existing value with the discovered dirs prepended.
70
82
  const existing = env.Path ?? env.PATH ?? '';
71
- const updated = bin + sep + existing;
83
+ const updated = prepend.join(sep) + sep + existing;
72
84
  if (env.Path !== undefined || (env.PATH === undefined && process.platform === 'win32')) {
73
85
  env.Path = updated;
74
86
  } else {
@@ -1,107 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Timer methods polyfill — Zephyr k_timer + k_work (heap-free)
3
- //
4
- // setInterval / setTimeout / clearInterval / clearTimeout backed by a fixed
5
- // pool of k_timer + k_work pairs. The timer's expiry function (ISR context)
6
- // submits a k_work item to the system workqueue; the work handler runs the
7
- // user callback in thread context. This split keeps the ISR cheap and lets the
8
- // callback run on a real thread (so it can do real work — but must not block,
9
- // since the system workqueue is shared).
10
- //
11
- // EMIT BOUNDARY: emitted bytes land in user firmware. Covered by the TypeCAD
12
- // Runtime Exception (RUNTIME_EXCEPTION.md at the repo root).
13
- // ---------------------------------------------------------------------------
14
-
15
- import type { RuntimePolyfillIR } from '@typecad/cuttlefish/api/shared';
16
-
17
- const MIN_TIMERS = 1;
18
- const MAX_TIMERS_CAP = 16;
19
-
20
- export interface TimerPolyfillIR extends RuntimePolyfillIR {
21
- /** The clamped pool size the C++ was generated with. */
22
- maxTimers: number;
23
- }
24
-
25
- /**
26
- * Build the timer_methods polyfill IR. `requestedTimers` is sized from
27
- * ctx.analysis.timerCallCount; it is clamped to [1, 16].
28
- */
29
- export function buildTimerPolyfill(requestedTimers: number): TimerPolyfillIR {
30
- const maxTimers = Math.min(MAX_TIMERS_CAP, Math.max(MIN_TIMERS, requestedTimers));
31
-
32
- const helperStructs = [`
33
- // cuttlefish timer runtime — k_timer + k_work pool (heap-free).
34
- struct __tc_TimerSlot {
35
- struct k_timer timer;
36
- struct k_work work;
37
- void (*callback)(void);
38
- bool active;
39
- };
40
-
41
- static struct __tc_TimerSlot __tc_timer_slots[${maxTimers}];
42
-
43
- static void __tc_timer_work_handler(struct k_work* w) {
44
- // Runs on the system workqueue thread (NOT ISR). Find the owning slot by
45
- // address and invoke the callback. Must not block.
46
- for (int32_t i = 0; i < ${maxTimers}; i++) {
47
- if (&__tc_timer_slots[i].work == w) {
48
- if (__tc_timer_slots[i].callback != nullptr) { __tc_timer_slots[i].callback(); }
49
- return;
50
- }
51
- }
52
- }
53
-
54
- static void __tc_timer_expiry_fn(struct k_timer* t) {
55
- // ISR context: submit the work item, do NOT run the callback here.
56
- for (int32_t i = 0; i < ${maxTimers}; i++) {
57
- if (&__tc_timer_slots[i].timer == t) {
58
- (void)k_work_submit(&__tc_timer_slots[i].work);
59
- return;
60
- }
61
- }
62
- }
63
-
64
- static int32_t __tc_timer_add(void (*cb)(void), int32_t ms, bool repeat) {
65
- for (int32_t i = 0; i < ${maxTimers}; i++) {
66
- if (!__tc_timer_slots[i].active) {
67
- __tc_timer_slots[i].callback = cb;
68
- __tc_timer_slots[i].active = true;
69
- k_timer_init(&__tc_timer_slots[i].timer, __tc_timer_expiry_fn, nullptr);
70
- k_work_init(&__tc_timer_slots[i].work, __tc_timer_work_handler);
71
- k_timer_start(&__tc_timer_slots[i].timer, K_MSEC(ms), repeat ? K_MSEC(ms) : K_FOREVER);
72
- return i + 1; // 1-based id (Arduino parity)
73
- }
74
- }
75
- return 0; // pool full
76
- }
77
-
78
- static void __tc_timer_clear(int32_t id) {
79
- if (id > 0 && id <= ${maxTimers}) {
80
- int32_t i = id - 1;
81
- k_timer_stop(&__tc_timer_slots[i].timer);
82
- __tc_timer_slots[i].active = false;
83
- __tc_timer_slots[i].callback = nullptr;
84
- }
85
- }
86
- `];
87
-
88
- const helperFunctions = [`
89
- int32_t __tc_setInterval(void (*cb)(), int32_t ms) { return __tc_timer_add(cb, ms, true); }
90
- int32_t __tc_setTimeout(void (*cb)(), int32_t ms) { return __tc_timer_add(cb, ms, false); }
91
- void __tc_clearInterval(int32_t id) { __tc_timer_clear(id); }
92
- void __tc_clearTimeout(int32_t id) { __tc_timer_clear(id); }
93
- `];
94
-
95
- return {
96
- kind: 'polyfill',
97
- id: 'timer_methods',
98
- domain: 'embedded',
99
- requiredIncludes: [],
100
- forwardDeclarations: [],
101
- helperStructs,
102
- helperFunctions,
103
- shimMacros: [],
104
- dependencies: [],
105
- maxTimers,
106
- };
107
- }
@@ -1,74 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Espressif ESP32 (esp32_devkitc) — Zephyr board descriptor
3
- //
4
- // Board target: `esp32_devkitc` (mainline Zephyr,
5
- // boards/espressif/esp32_devkitc). Programmed over USB via the esptool runner
6
- // (see toolchain/index.ts), the same flash path as the ESP32-S3.
7
- //
8
- // GPIO is split across TWO devicetree controllers — `gpio0` (pins 0–31) and
9
- // `gpio1` (pins 32–39) — so this descriptor lists both in `gpioControllers`.
10
- // The lowering routes each HAL pin to its owning controller at runtime; see
11
- // chips/controllers.ts. (Same shape as the S3, but the ESP32's highest GPIO is
12
- // 39, not 48 — `gpio1` has ngpios=8, not 17.)
13
- //
14
- // Minimal-by-design: the only DT facts carried here are the ones a compile-time
15
- // DT macro cannot reach — the runtime pin→controller split, plus the `sw0`
16
- // alias for the BOOT button (used by the devicetree-spec GPIO path). Every other
17
- // DT fact (UART/I2C/SPI/`wdt` nodelabels) is resolved by Zephyr's own
18
- // devicetree via emitted DT_NODELABEL macros, not hand-copied here.
19
- //
20
- // Verified against the Zephyr board DTS:
21
- // boards/espressif/esp32_devkitc/esp32_devkitc_procpu.dts
22
- // aliases { sw0 = &button0; } → button_0: pin 0 on gpio0, active-low + pull-up
23
- // &gpio0/&gpio1 { status = "okay" } (esp32_devkitc_procpu.dts:64-70)
24
- // &wifi { status = "okay" } (esp32_devkitc_procpu.dts:143-145)
25
- // GPIO controller coverage:
26
- // dts/xtensa/espressif/esp32/esp32_common.dtsi:314-337
27
- // gpio0: ngpios = <32> (pins 0–31)
28
- // gpio1: ngpios = <8> (pins 32–39)
29
- //
30
- // Note: GPIO 34–39 are input-only pads on ESP32 silicon (not modeled here —
31
- // the DT does not encode output restrictions per pin; an output config on those
32
- // pins fails at runtime against the raw controller, which is the expected
33
- // silicon-accurate behavior).
34
- // ---------------------------------------------------------------------------
35
-
36
- import type { ZephyrChipDescriptor } from './types.js';
37
-
38
- export const ESP32_DEVKITC: ZephyrChipDescriptor = {
39
- id: 'esp32_devkitc',
40
- soc: 'esp32',
41
- gpioController: 'gpio0',
42
- gpioControllers: [
43
- { nodelabel: 'gpio0', minPin: 0, maxPin: 31 },
44
- { nodelabel: 'gpio1', minPin: 32, maxPin: 39 },
45
- ],
46
- gpio: {
47
- // The BOOT button (GPIO0) is the board's only DT-aliased GPIO. Listed so a
48
- // program reading/interrupting pin 0 goes through the polarity-correct
49
- // devicetree-spec path (GPIO_ACTIVE_LOW honored by the DT flags).
50
- dtSpecs: [
51
- { pin: 0, dtSpec: 'sw0' }, // BOOT button (GPIO0)
52
- ],
53
- interruptPins: [
54
- { pin: 0, dtSpec: 'sw0' }, // BOOT button (GPIO0)
55
- ],
56
- },
57
- // WiFi: the ESP32 has a 2.4GHz radio; conn_mgr + the esp32 wifi driver
58
- // (CONFIG_WIFI_ESP32) provide connectivity. WIFI_ESP32 depends on !SMP, and
59
- // the ESP32 is AMP (dual-image procpu/appcpu), not SMP, by default — so the
60
- // dependency is satisfied. Omitted on radioless targets.
61
- wifi: { supported: true },
62
- // DAC: the ESP32 has two 8-bit DAC channels on GPIO25 (channel 1) and GPIO26
63
- // (channel 2). The Zephyr esp32 DAC driver (drivers/dac/dac_esp32.c) exposes
64
- // them via the `dac0` node; the lowering emits dac_channel_setup +
65
- // dac_write_value against DEVICE_DT_GET(DT_NODELABEL(dac0)). The overlay
66
- // enables the node when the program uses dac.*. ESP32-S3 has no DAC.
67
- dac: {
68
- device: 'dac0',
69
- channels: [
70
- { pin: 25, channel: 1, resolution: 8 },
71
- { pin: 26, channel: 2, resolution: 8 },
72
- ],
73
- },
74
- };
@@ -1,57 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Espressif ESP32-S3 (esp32s3_devkitc) — Zephyr board descriptor
3
- //
4
- // Board target: `esp32s3_devkitc` (mainline Zephyr,
5
- // boards/espressif/esp32s3_devkitc). Programmed over USB via the esptool
6
- // runner (see toolchain/index.ts), unlike the J-Link/nrfjprog path used for
7
- // the XIAO nRF52840.
8
- //
9
- // GPIO is split across TWO devicetree controllers — `gpio0` (pins 0–31) and
10
- // `gpio1` (pins 32–48) — so this descriptor lists both in `gpioControllers`.
11
- // The lowering routes each HAL pin to its owning controller at runtime; see
12
- // chips/controllers.ts.
13
- //
14
- // Minimal-by-design: the only DT facts carried here are the ones a
15
- // compile-time DT macro cannot reach — the runtime pin→controller split, plus
16
- // the `sw0` alias for the BOOT button (used by the devicetree-spec GPIO path).
17
- // Every other DT fact (UART/I2C/SPI/`wdt` nodelabels) is resolved by Zephyr's
18
- // own devicetree via emitted DT_NODELABEL macros, not hand-copied here.
19
- //
20
- // Verified against the Zephyr board DTS:
21
- // boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts
22
- // aliases { sw0 = &button0; } → button_0: pin 0 on gpio0, active-low + pull-up
23
- // (the DevKitC board DTS defines no led0 alias — the onboard RGB is a WS2812
24
- // on GPIO38, not a plain GPIO LED, so it is intentionally NOT listed here.)
25
- // ---------------------------------------------------------------------------
26
-
27
- import type { ZephyrChipDescriptor } from './types.js';
28
-
29
- export const ESP32S3_DEVKITC: ZephyrChipDescriptor = {
30
- id: 'esp32s3_devkitc',
31
- soc: 'esp32s3',
32
- gpioController: 'gpio0',
33
- gpioControllers: [
34
- { nodelabel: 'gpio0', minPin: 0, maxPin: 31 },
35
- { nodelabel: 'gpio1', minPin: 32, maxPin: 48 },
36
- ],
37
- gpio: {
38
- // The BOOT button (GPIO0) is the board's only DT-aliased GPIO. Listed so a
39
- // program reading/interrupting pin 0 goes through the polarity-correct
40
- // devicetree-spec path (GPIO_ACTIVE_LOW honored by the DT flags). Every
41
- // other GPIO pin uses the raw-controller path against its owning controller.
42
- dtSpecs: [
43
- { pin: 0, dtSpec: 'sw0' }, // BOOT button (GPIO0)
44
- ],
45
- interruptPins: [
46
- { pin: 0, dtSpec: 'sw0' }, // BOOT button (GPIO0)
47
- ],
48
- },
49
- // UART/I2C/SPI/`wdt` are intentionally omitted: their devicetree nodelabels
50
- // (uart0/uart1/uart2, i2c0/i2c1, spi2/spi3, wdt0) are resolved by Zephyr's
51
- // devicetree at compile time and don't need to be carried as data here. ADC is
52
- // omitted as well — added when a demo needs analog reads, with the verified
53
- // ESP32-S3 ADC1/ADC2 pin→channel map.
54
- // WiFi: the ESP32-S3 has a 2.4GHz radio; conn_mgr + the esp32 wifi driver
55
- // (CONFIG_WIFI_ESP32) provide connectivity. Omitted on radioless targets.
56
- wifi: { supported: true },
57
- };
@@ -1,70 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Seeed Studio XIAO nRF52840 — Zephyr board descriptor
3
- //
4
- // Board target: `xiao_ble` (mainline Zephyr, boards/seeed/xiao_ble).
5
- // The onboard user LED is active-low and exposed as the DT alias `led0`.
6
- // ---------------------------------------------------------------------------
7
-
8
- import type { ZephyrChipDescriptor } from './types.js';
9
-
10
- export const XIAO_BLE: ZephyrChipDescriptor = {
11
- id: 'xiao_ble',
12
- soc: 'nrf52840',
13
- gpioController: 'gpio0',
14
- gpio: {
15
- dtSpecs: [
16
- // Onboard RGB LEDs — active-low (GPIO_ACTIVE_LOW in xiao_ble_common.dtsi).
17
- // Verified against the board's `aliases { led0 = &led0; led1 = &led1; led2 = &led2; }`.
18
- { pin: 26, dtSpec: 'led0' }, // Red (P0.26)
19
- { pin: 30, dtSpec: 'led1' }, // Green (P0.30)
20
- { pin: 6, dtSpec: 'led2' }, // Blue (P0.06)
21
- ],
22
- // The XIAO nRF52840 has a user button on P0.04, but mainline Zephyr's
23
- // xiao_ble board (verified against Zephyr 4.3.99) does NOT expose it as a
24
- // DT `sw0` alias — there is no gpio-keys node in xiao_ble.dts. Emitting
25
- // GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios) therefore fails to compile
26
- // ('DT_N_ALIAS_sw0_... was not declared'). Until a button node + alias is
27
- // added (via an overlay or an upstream board update), interruptPins stays
28
- // empty: attachInterrupt on this board lowers to the no-DT-spec comment
29
- // fallback rather than a hard compile error.
30
- interruptPins: [],
31
- },
32
- // The XIAO connector wiring (from seeed_xiao_connector.dtsi + xiao_ble-pinctrl.dtsi):
33
- // xiao_i2c → i2c1 (SDA P0.04/D4, SCL P0.05/D5)
34
- // xiao_spi → spi2 (SCK P1.13/D8, MOSI P1.15/D10, MISO P1.14/D9)
35
- // xiao_serial → uart0 (TX P1.11/D6, RX P1.12/D7)
36
- // The board DTS leaves i2c0/spi0/spi1 disabled (shared instances).
37
- i2c: {
38
- controllers: [{ nodeLabel: 'i2c1' }],
39
- },
40
- spi: {
41
- controllers: [{ nodeLabel: 'spi2' }],
42
- },
43
- uart: {
44
- controllers: [{ nodeLabel: 'uart0' }],
45
- },
46
- pwm: {
47
- // pwm-led0 drives the board PWM LED (PWM_OUT0 on P0.17, inverted).
48
- specs: [{ pin: 17, dtSpec: 'pwm-led0' }],
49
- },
50
- adc: {
51
- // SAADC node is `adc`; no pre-declared channels. XIAO D0–D3 = AIN0–AIN3
52
- // (P0.02/P0.03/P0.28/P0.29). Internal VREF ~0.6V with VDD/4 gain ⇒ 3000mV.
53
- nodeLabel: 'adc',
54
- resolution: 12,
55
- vrefMv: 3000,
56
- channels: [
57
- { pin: 2, channel: 0 }, // P0.02 / D0 / AIN0
58
- { pin: 3, channel: 1 }, // P0.03 / D1 / AIN1
59
- { pin: 28, channel: 2 }, // P0.28 / D2 / AIN2
60
- { pin: 29, channel: 3 }, // P0.29 / D3 / AIN3
61
- ],
62
- },
63
- wdt: { nodeLabel: 'wdt0' },
64
- // Hardware timer: nRF RTC1 is the free counter (RTC0 is kernel-owned by the
65
- // softdevice/clock driver). The hwtimer lowering drives it as a Zephyr
66
- // counter device (counter_start/stop + a top-value alarm for set_frequency).
67
- // Verified against the nRF52840 SoC dtsi (rtc0/rtc1 nodes). The kernel uses
68
- // RTC0 for the system tick; RTC1 is available for application use.
69
- hwtimer: { controllers: [{ nodeLabel: 'rtc1' }] },
70
- };
@@ -1,70 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Power lowering — Zephyr power management
3
- //
4
- // Zephyr enters low-power states from the idle thread per policy. The app-facing
5
- // controls are pm_state_force (override policy to force a state on next idle)
6
- // and k_sleep (block the calling thread, allowing the system to idle into a
7
- // low-power state). "Deep sleep" maps to k_sleep (the SoC picks its deepest
8
- // allowed state); "light sleep" best-effort forces SUSPEND_TO_IDLE.
9
- //
10
- // deep_sleep_pin configures the wake GPIO as an interrupt source then k_sleeps
11
- // (the interrupt wakes the SoC). CPU frequency is SoC-specific (nRF52 has a
12
- // fixed 64 MHz HFXO with no portable dynamic scaling) and stays a documented
13
- // no-op. deep_sleep_pin targets gpio0 (single-controller nRF52840 case);
14
- // multi-controller SoC routing is a documented follow-on.
15
- // ---------------------------------------------------------------------------
16
-
17
- import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
18
-
19
- /**
20
- * Resolve a HAL power.* op to Zephyr C++.
21
- * Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
22
- */
23
- export function lowerPower(op: HALOpIR): { code?: string; expression?: string } {
24
- const o = op as any;
25
-
26
- switch (op.operation) {
27
- case 'power.deep_sleep':
28
- // Block for the requested duration; the idle thread + PM policy will enter
29
- // the deepest state the SoC allows during the sleep.
30
- return { code: `k_sleep(K_MSEC(${o.ms}));` };
31
- case 'power.light_sleep':
32
- // Best-effort: force a shallow suspend on the next idle. pm_state_force
33
- // requires a pm_state_info; SUSPEND_TO_IDLE is a common shallow state.
34
- return { code: `pm_state_force(0, &(const struct pm_state_info){ .state = PM_STATE_SUSPEND_TO_IDLE, .substate_id = 0 });` };
35
- case 'power.set_cpu_frequency':
36
- // nRF52 has a fixed 64 MHz HFXO; no portable dynamic scaling from C++.
37
- // Documented no-op (best-effort), matching Arduino's approach.
38
- return { code: `/* power.set_cpu_frequency(${o.mhz}): nRF52 fixed 64 MHz HFXO — no portable scaling */` };
39
- case 'power.deep_sleep_pin': {
40
- // Configure the pin as a GPIO wake source (level interrupt), then k_sleep
41
- // until the interrupt fires. A static gpio_callback + a no-op handler (the
42
- // wake just needs the interrupt enabled; the handler does nothing). level:
43
- // 1=high, 0=low. Targets gpio0 (single-controller nRF52840); multi-
44
- // controller SoC routing is a documented follow-on.
45
- const pin = o.pin;
46
- const level = o.level;
47
- const flags = level ? 'GPIO_INT_LEVEL_HIGH' : 'GPIO_INT_LEVEL_LOW';
48
- return {
49
- code: [
50
- '{',
51
- ` static struct gpio_callback __tc_wake_cb;`,
52
- ` const struct device* __dev = DEVICE_DT_GET(DT_NODELABEL(gpio0));`,
53
- ` gpio_pin_configure(__dev, ${pin}, GPIO_INPUT);`,
54
- ` gpio_init_callback(&__tc_wake_cb, [](const struct device*, struct gpio_callback*, gpio_port_pins_t) { (void)0; }, BIT(${pin}));`,
55
- ` gpio_add_callback(__dev, &__tc_wake_cb);`,
56
- ` gpio_pin_interrupt_configure(__dev, ${pin}, ${flags});`,
57
- ` k_sleep(K_FOREVER);`,
58
- ` gpio_pin_interrupt_configure(__dev, ${pin}, GPIO_INT_DISABLE);`,
59
- ` gpio_remove_callback(__dev, &__tc_wake_cb);`,
60
- '}',
61
- ].join(' '),
62
- };
63
- }
64
- default:
65
- throw new Error(
66
- `framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
67
- `Open an issue or use rawCpp() to emit it manually.`,
68
- );
69
- }
70
- }
@@ -1,93 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Pulse + shift lowering — bit-bang via GPIO + timing
3
- //
4
- // pulse.in measures the duration of a pulse (HIGH or LOW) on a GPIO pin by
5
- // edge-polling with k_uptime_get. shift.out/in bit-bang a byte through a data
6
- // + clock pin pair using gpio_pin_set + k_busy_wait. These are software
7
- // implementations (no hardware pulse capture on nRF for the HAL surface); they
8
- // are correct but not high-precision.
9
- // ---------------------------------------------------------------------------
10
-
11
- import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
12
- import type { ZephyrChipDescriptor } from '../chips/types.js';
13
- import { controllerNodelabelForPin } from '../chips/controllers.js';
14
-
15
- /** `DEVICE_DT_GET(DT_NODELABEL(<owning-controller>))` for a HAL pin. */
16
- function devForPin(chip: ZephyrChipDescriptor, pin: number): string {
17
- return `DEVICE_DT_GET(DT_NODELABEL(${controllerNodelabelForPin(chip, pin)}))`;
18
- }
19
-
20
- /** Resolve a HAL pulse.* or shift.* op to Zephyr C++ (bit-bang). */
21
- export function lowerPulseOrShift(
22
- op: HALOpIR,
23
- chip: ZephyrChipDescriptor,
24
- ): { code?: string; expression?: string } {
25
- const o = op as any;
26
-
27
- switch (op.operation) {
28
- case 'pulse.in': {
29
- // Wait for the pin to reach `value`, then measure until it changes.
30
- // Edge-poll with k_uptime_get() (ms granularity — coarse but correct,
31
- // and 64-bit so it cannot wrap mid-measurement over ~49 days). The wait
32
- // for the start edge is bounded by the timeout; the measurement of the
33
- // pulse itself is intentionally unbounded (that IS the pulse length).
34
- // Returns -1 (0) if the start edge never arrives within the timeout.
35
- const pin = o.pin;
36
- const want = o.value;
37
- const dev = devForPin(chip, pin);
38
- const timeout = o.timeout ?? 1_000_000; // default 1s in us
39
- return {
40
- expression: `({ int64_t __max = static_cast<int64_t>(${timeout} / 1000); int64_t __t0 = k_uptime_get(); bool __ok = true; while (gpio_pin_get_raw(${dev}, ${pin}) != ${want}) { if ((k_uptime_get() - __t0) > __max) { __ok = false; break; } } int32_t __ret = 0; if (__ok) { int64_t __start = k_uptime_get(); while (gpio_pin_get_raw(${dev}, ${pin}) == ${want}) { } __ret = static_cast<int32_t>((k_uptime_get() - __start) * 1000); } __ret; })`,
41
- };
42
- }
43
- case 'pulse.in_long': {
44
- // Same as pulse.in but for long pulses. Previously this spun forever
45
- // with NO timeout (the comment claimed "no overflow concern" but the
46
- // real risk was hanging the thread on a stuck pin). Apply the same
47
- // timeout-bounded start-edge wait as pulse.in (bug Q5).
48
- const pin = o.pin;
49
- const want = o.value;
50
- const dev = devForPin(chip, pin);
51
- const timeout = o.timeout ?? 3_000_000; // default 3s in us (long pulses)
52
- return {
53
- expression: `({ int64_t __max = static_cast<int64_t>(${timeout} / 1000); int64_t __t0 = k_uptime_get(); bool __ok = true; while (gpio_pin_get_raw(${dev}, ${pin}) != ${want}) { if ((k_uptime_get() - __t0) > __max) { __ok = false; break; } } int32_t __ret = 0; if (__ok) { int64_t __start = k_uptime_get(); while (gpio_pin_get_raw(${dev}, ${pin}) == ${want}) { } __ret = static_cast<int32_t>((k_uptime_get() - __start) * 1000); } __ret; })`,
54
- };
55
- }
56
- case 'shift.out': {
57
- // Bit-bang `value` (MSB or LSB first) via dataPin + clockPin. The two
58
- // pins may sit on different GPIO controllers on multi-controller SoCs
59
- // (ESP32-S3), so each is resolved to its own owning controller.
60
- const dataPin = o.dataPin;
61
- const clockPin = o.clockPin;
62
- const dataDev = devForPin(chip, dataPin);
63
- const clockDev = devForPin(chip, clockPin);
64
- const msbFirst = o.bitOrder === 'msb';
65
- const init = msbFirst ? '7' : '0';
66
- const test = msbFirst ? '(__i >= 0)' : '(__i < 8)';
67
- const step = msbFirst ? '__i--' : '__i++';
68
- return {
69
- code: `for (int __i = ${init}; ${test}; ${step}) { gpio_pin_set_raw(${dataDev}, ${dataPin}, (${o.value} >> __i) & 1); gpio_pin_set_raw(${clockDev}, ${clockPin}, 1); k_busy_wait(1); gpio_pin_set_raw(${clockDev}, ${clockPin}, 0); }`,
70
- };
71
- }
72
- case 'shift.in': {
73
- // Read 8 bits (MSB or LSB first) from dataPin, clocking on clockPin.
74
- const dataPin = o.dataPin;
75
- const clockPin = o.clockPin;
76
- const dataDev = devForPin(chip, dataPin);
77
- const clockDev = devForPin(chip, clockPin);
78
- const msbFirst = o.bitOrder === 'msb';
79
- const init = msbFirst ? '7' : '0';
80
- const test = msbFirst ? '(__i >= 0)' : '(__i < 8)';
81
- const step = msbFirst ? '__i--' : '__i++';
82
- const accum = msbFirst ? '__v = (__v << 1)' : '__v |= (bit << __i)';
83
- return {
84
- expression: `({ uint8_t __v = 0; for (int __i = ${init}; ${test}; ${step}) { gpio_pin_set_raw(${clockDev}, ${clockPin}, 1); k_busy_wait(1); int bit = gpio_pin_get_raw(${dataDev}, ${dataPin}); gpio_pin_set_raw(${clockDev}, ${clockPin}, 0); ${accum}; } __v; })`,
85
- };
86
- }
87
- default:
88
- throw new Error(
89
- `framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
90
- `Open an issue or use rawCpp() to emit it manually.`,
91
- );
92
- }
93
- }
@@ -1,60 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Tone lowering — PWM-based square-wave generation
3
- //
4
- // tone is a convenience wrapper around PWM: a square wave at `frequency` Hz with
5
- // a 50% duty cycle. The lowering maps frequency → period (ns) and sets the PWM
6
- // channel to a 50% pulse. stop turns the output off (0% duty). The PWM spec is
7
- // resolved from the chip descriptor (pwm-led0 on the XIAO).
8
- //
9
- // An optional duration is honored by scheduling a stop via k_sleep in a detached
10
- // fashion — but the simple lowering is blocking (k_msleep(duration) then stop),
11
- // matching the synchronous Arduino tone() semantics. For non-blocking tone,
12
- // a workqueue would be needed (deferred).
13
- // ---------------------------------------------------------------------------
14
-
15
- import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
16
- import type { ZephyrChipDescriptor } from '../chips/types.js';
17
- import { lowerPwm } from './pwm.js';
18
-
19
- /**
20
- * Resolve a HAL tone.* op to Zephyr C++ via PWM.
21
- * Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
22
- */
23
- export function lowerTone(
24
- op: HALOpIR,
25
- chip: ZephyrChipDescriptor,
26
- ): { code?: string; expression?: string } {
27
- const o = op as any;
28
-
29
- switch (op.operation) {
30
- case 'tone.play': {
31
- // period_ns = 1e9 / freq; pulse_ns = period / 2 (50% duty).
32
- // Build a fake pwm.write would need the spec var directly; emit the
33
- // pwm_set_dt call against the same spec var the PWM lowering uses.
34
- const spec = chip.pwm?.specs[0];
35
- if (!spec) {
36
- return { code: `/* tone.play(${o.frequency}): no PWM spec in chip descriptor */` };
37
- }
38
- const v = `__tc_pwm_${spec.dtSpec.replace(/-/g, '_')}`;
39
- const freq = o.frequency;
40
- const duration = o.duration;
41
- const setTone = `uint32_t __period = (${freq} > 0) ? (1000000000ULL / static_cast<uint64_t>(${freq})) : 0; pwm_set_dt(&${v}, __period, __period / 2);`;
42
- if (duration !== undefined) {
43
- // Blocking tone for the requested duration, then stop.
44
- return { code: `${setTone} k_msleep(${duration}); pwm_set_pulse_dt(&${v}, 0);` };
45
- }
46
- return { code: setTone };
47
- }
48
- case 'tone.stop': {
49
- const spec = chip.pwm?.specs[0];
50
- if (!spec) return { code: `/* tone.stop: no PWM spec */` };
51
- const v = `__tc_pwm_${spec.dtSpec.replace(/-/g, '_')}`;
52
- return { code: `pwm_set_pulse_dt(&${v}, 0);` };
53
- }
54
- default:
55
- throw new Error(
56
- `framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
57
- `Open an issue or use rawCpp() to emit it manually.`,
58
- );
59
- }
60
- }