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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/LICENSE +202 -21
  2. package/README.md +49 -87
  3. package/dist/as-built.d.ts +2 -2
  4. package/dist/as-built.js +2 -2
  5. package/dist/audit.d.ts +111 -0
  6. package/dist/audit.js +416 -0
  7. package/dist/boardgen.d.ts +1 -9
  8. package/dist/boardgen.js +288 -47
  9. package/dist/chips/resolve.js +20 -0
  10. package/dist/chips/types.d.ts +22 -1
  11. package/dist/debug-codegen.js +1 -1
  12. package/dist/display/bindings.d.ts +55 -0
  13. package/dist/display/bindings.js +316 -0
  14. package/dist/display/gfx.d.ts +2 -3
  15. package/dist/display/gfx.js +166 -154
  16. package/dist/display/index.js +20 -1
  17. package/dist/display/mipi-dbi-host.d.ts +9 -0
  18. package/dist/display/mipi-dbi-host.js +174 -0
  19. package/dist/display/profiles.d.ts +109 -4
  20. package/dist/display/profiles.js +270 -7
  21. package/dist/display/touch-adapter.js +119 -49
  22. package/dist/display/ui-adapter-eink.d.ts +2 -0
  23. package/dist/display/ui-adapter-eink.js +4 -0
  24. package/dist/display/ui-adapter-gray.d.ts +8 -0
  25. package/dist/display/ui-adapter-gray.js +170 -0
  26. package/dist/display/ui-adapter-mono.d.ts +13 -0
  27. package/dist/display/ui-adapter-mono.js +230 -0
  28. package/dist/display/ui-adapter-native.d.ts +10 -0
  29. package/dist/display/ui-adapter-native.js +295 -0
  30. package/dist/display/ui-adapter-shared.d.ts +11 -0
  31. package/dist/display/ui-adapter-shared.js +122 -0
  32. package/dist/display/ui-adapter.js +510 -558
  33. package/dist/doctor.js +4 -4
  34. package/dist/dt-config/custom-board.js +2 -2
  35. package/dist/dt-config/kconfig.d.ts +62 -1
  36. package/dist/dt-config/kconfig.js +141 -38
  37. package/dist/dt-config/overlay.d.ts +15 -2
  38. package/dist/dt-config/overlay.js +433 -18
  39. package/dist/framework.manifest.d.ts +10 -4
  40. package/dist/framework.manifest.js +133 -17
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.js +14 -6
  43. package/dist/licenses.d.ts +2 -2
  44. package/dist/licenses.js +13 -92
  45. package/dist/lowering/can.d.ts +25 -0
  46. package/dist/lowering/can.js +97 -0
  47. package/dist/lowering/clock.d.ts +17 -0
  48. package/dist/lowering/clock.js +58 -0
  49. package/dist/lowering/fs.js +1 -1
  50. package/dist/lowering/gpio.js +0 -32
  51. package/dist/lowering/hid.d.ts +27 -0
  52. package/dist/lowering/hid.js +244 -0
  53. package/dist/lowering/http.js +264 -32
  54. package/dist/lowering/i2c.d.ts +8 -0
  55. package/dist/lowering/i2c.js +137 -5
  56. package/dist/lowering/i2s.d.ts +27 -0
  57. package/dist/lowering/i2s.js +98 -0
  58. package/dist/lowering/index.d.ts +9 -1
  59. package/dist/lowering/index.js +25 -1
  60. package/dist/lowering/interrupts.js +6 -0
  61. package/dist/lowering/matrix.d.ts +15 -0
  62. package/dist/lowering/matrix.js +63 -0
  63. package/dist/lowering/mqtt.js +110 -8
  64. package/dist/lowering/power.d.ts +3 -2
  65. package/dist/lowering/power.js +20 -45
  66. package/dist/lowering/pwm.js +25 -0
  67. package/dist/lowering/sensor.d.ts +2 -2
  68. package/dist/lowering/sensor.js +8 -4
  69. package/dist/lowering/strip.d.ts +16 -0
  70. package/dist/lowering/strip.js +70 -0
  71. package/dist/lowering/thread.js +5 -1
  72. package/dist/lowering/trace.d.ts +44 -0
  73. package/dist/lowering/trace.js +239 -0
  74. package/dist/lowering/uart.js +6 -1
  75. package/dist/lowering/usb.d.ts +3 -1
  76. package/dist/lowering/usb.js +16 -13
  77. package/dist/lowering/wdt.js +2 -29
  78. package/dist/sbom.d.ts +181 -0
  79. package/dist/sbom.js +901 -0
  80. package/dist/sdk/board-catalog-sync.d.ts +1 -3
  81. package/dist/sdk/board-catalog-sync.js +4 -10
  82. package/dist/strategy.d.ts +82 -46
  83. package/dist/strategy.js +639 -182
  84. package/dist/tmp-probe.d.ts +2 -0
  85. package/dist/tmp-probe.js +9 -0
  86. package/dist/toolchain/debug-config.d.ts +50 -90
  87. package/dist/toolchain/debug-config.js +239 -510
  88. package/dist/toolchain/env-check.d.ts +1 -3
  89. package/dist/toolchain/env-check.js +2 -7
  90. package/dist/toolchain/index.d.ts +28 -3
  91. package/dist/toolchain/index.js +498 -62
  92. package/dist/toolchain/runners.d.ts +16 -0
  93. package/dist/toolchain/runners.js +75 -0
  94. package/dist/toolchain/scaffold.d.ts +5 -2
  95. package/dist/toolchain/scaffold.js +79 -15
  96. package/dist/toolchain/west-discover.d.ts +6 -0
  97. package/dist/toolchain/west-discover.js +36 -13
  98. package/dist/toolchain/west-spawn.js +8 -2
  99. package/dist/west-inventory.d.ts +25 -0
  100. package/dist/west-inventory.js +97 -0
  101. package/installer/README.md +328 -328
  102. package/installer/install.sh +2 -2
  103. package/installer/templates/project/.typecad/activate-zephyr.ps1 +1 -1
  104. package/installer/templates/project/.typecad/activate-zephyr.sh +1 -1
  105. package/installer/templates/project/.vscode/settings.json +1 -1
  106. package/installer/templates/project/README.md +2 -2
  107. package/package.json +5 -5
  108. package/src/as-built.ts +206 -206
  109. package/src/audit.ts +529 -0
  110. package/src/boardgen.ts +265 -50
  111. package/src/chips/resolve.ts +21 -0
  112. package/src/chips/types.ts +10 -1
  113. package/src/display/bindings.ts +347 -0
  114. package/src/display/gfx.ts +318 -306
  115. package/src/display/index.ts +87 -70
  116. package/src/display/mipi-dbi-host.ts +183 -0
  117. package/src/display/profiles.ts +458 -139
  118. package/src/display/touch-adapter.ts +119 -49
  119. package/src/display/ui-adapter-eink.ts +13 -0
  120. package/src/display/ui-adapter-gray.ts +178 -0
  121. package/src/display/ui-adapter-mono.ts +238 -0
  122. package/src/display/ui-adapter-native.ts +304 -0
  123. package/src/display/ui-adapter-shared.ts +125 -0
  124. package/src/display/ui-adapter.ts +732 -781
  125. package/src/doctor.ts +4 -4
  126. package/src/dt-config/custom-board.ts +2 -2
  127. package/src/dt-config/kconfig.ts +647 -505
  128. package/src/dt-config/overlay.ts +1475 -1058
  129. package/src/framework.manifest.ts +659 -535
  130. package/src/index.ts +16 -6
  131. package/src/licenses.ts +346 -425
  132. package/src/lowering/can.ts +140 -0
  133. package/src/lowering/clock.ts +91 -0
  134. package/src/lowering/fs.ts +135 -135
  135. package/src/lowering/gpio.ts +0 -33
  136. package/src/lowering/hid.ts +261 -0
  137. package/src/lowering/http.ts +264 -32
  138. package/src/lowering/i2c.ts +142 -5
  139. package/src/lowering/i2s.ts +143 -0
  140. package/src/lowering/index.ts +18 -1
  141. package/src/lowering/interrupts.ts +6 -0
  142. package/src/lowering/matrix.ts +70 -0
  143. package/src/lowering/mqtt.ts +109 -8
  144. package/src/lowering/power.ts +41 -0
  145. package/src/lowering/pwm.ts +192 -167
  146. package/src/lowering/sensor.ts +159 -155
  147. package/src/lowering/strip.ts +81 -0
  148. package/src/lowering/thread.ts +5 -1
  149. package/src/lowering/trace.ts +270 -0
  150. package/src/lowering/uart.ts +6 -1
  151. package/src/lowering/usb.ts +16 -13
  152. package/src/lowering/wdt.ts +2 -25
  153. package/src/sbom.ts +1117 -0
  154. package/src/sdk/board-catalog-sync.ts +4 -25
  155. package/src/strategy.ts +2680 -2309
  156. package/src/toolchain/debug-config.ts +262 -522
  157. package/src/toolchain/env-check.ts +279 -285
  158. package/src/toolchain/index.ts +1792 -1359
  159. package/src/toolchain/runners.ts +80 -0
  160. package/src/toolchain/scaffold.ts +355 -296
  161. package/src/toolchain/west-discover.ts +35 -13
  162. package/src/toolchain/west-spawn.ts +174 -168
  163. package/src/west-inventory.ts +102 -0
  164. package/dist/async/timer-polyfill.d.ts +0 -10
  165. package/dist/async/timer-polyfill.js +0 -95
  166. package/dist/chips/board-overrides.d.ts +0 -7
  167. package/dist/chips/board-overrides.js +0 -11
  168. package/dist/chips/esp32.d.ts +0 -2
  169. package/dist/chips/esp32.js +0 -71
  170. package/dist/chips/esp32s3.d.ts +0 -2
  171. package/dist/chips/esp32s3.js +0 -103
  172. package/dist/chips/soc/.d.ts +0 -2
  173. package/dist/chips/soc/.js +0 -129
  174. package/dist/chips/soc/esp32.d.ts +0 -2
  175. package/dist/chips/soc/esp32.js +0 -120
  176. package/dist/chips/soc/esp32c3.d.ts +0 -2
  177. package/dist/chips/soc/esp32c3.js +0 -90
  178. package/dist/chips/soc/esp32c6.d.ts +0 -2
  179. package/dist/chips/soc/esp32c6.js +0 -109
  180. package/dist/chips/soc/esp32s3.d.ts +0 -2
  181. package/dist/chips/soc/esp32s3.js +0 -189
  182. package/dist/chips/soc/index.d.ts +0 -2
  183. package/dist/chips/soc/index.js +0 -23
  184. package/dist/chips/soc/nrf52840.d.ts +0 -2
  185. package/dist/chips/soc/nrf52840.js +0 -130
  186. package/dist/chips/soc/rp2040.d.ts +0 -2
  187. package/dist/chips/soc/rp2040.js +0 -141
  188. package/dist/chips/soc/rp2350a.d.ts +0 -2
  189. package/dist/chips/soc/rp2350a.js +0 -145
  190. package/dist/chips/soc/samd21g18a.d.ts +0 -2
  191. package/dist/chips/soc/samd21g18a.js +0 -143
  192. package/dist/chips/soc/stm32f411xe.d.ts +0 -2
  193. package/dist/chips/soc/stm32f411xe.js +0 -251
  194. package/dist/chips/xiao-ble.d.ts +0 -2
  195. package/dist/chips/xiao-ble.js +0 -100
  196. package/dist/lowering/pulse.d.ts +0 -7
  197. package/dist/lowering/pulse.js +0 -51
  198. package/dist/lowering/tone.d.ts +0 -10
  199. package/dist/lowering/tone.js +0 -63
  200. package/dist/lowering/worker-backing.d.ts +0 -14
  201. package/dist/lowering/worker-backing.js +0 -79
  202. package/dist/lowering/worker.d.ts +0 -6
  203. package/dist/lowering/worker.js +0 -14
  204. package/dist/sdk/board-data.generated.d.ts +0 -2
  205. package/dist/sdk/board-data.generated.js +0 -4
  206. package/dist/sdk/catalog-walker.d.ts +0 -90
  207. package/dist/sdk/catalog-walker.js +0 -682
  208. package/dist/sdk/dts-reader.d.ts +0 -83
  209. package/dist/sdk/dts-reader.js +0 -596
  210. package/src/debug-codegen.ts +0 -207
@@ -51,7 +51,7 @@ export function fsInitLines() {
51
51
  ' __tc_fs_mounted = true;',
52
52
  ' } else {',
53
53
  ' char __tc_fs_err[48];',
54
- ' (void)snprintf(__tc_fs_err, sizeof(__tc_fs_err), "cuttlefish-fs: mount failed rc=%d", rc);',
54
+ ' (void)snprintf(__tc_fs_err, sizeof(__tc_fs_err), "typecad-hal-fs: mount failed rc=%d", rc);',
55
55
  ' __tc_println(__tc_fs_err);',
56
56
  ' }',
57
57
  '}',
@@ -24,38 +24,6 @@ export function dtSpecVarName(dtSpec) {
24
24
  function findDtSpec(chip, pin) {
25
25
  return chip.gpio.dtSpecs.find((s) => s.pin === pin);
26
26
  }
27
- // HAL passes UPPERCASE modes ("OUTPUT") while docs say lowercase ("output").
28
- // The *_pullup / *_pulldown modes map to GPIO_INPUT (Zephyr does not have
29
- // separate input+pull mode flags) and OR in a GPIO_PULL_UP / GPIO_PULL_DOWN
30
- // bit via `dtFlagsForMode` — without that bit the pin floats, so INPUT_PULLUP
31
- // was a silent no-op (bug B1). Mirrors the gpio_pullup_en/gpio_pulldown_en
32
- // extras framework-esp32 emits for the same modes.
33
- const MODE_MAP = {
34
- output: 'GPIO_OUTPUT',
35
- OUTPUT: 'GPIO_OUTPUT',
36
- input: 'GPIO_INPUT',
37
- INPUT: 'GPIO_INPUT',
38
- input_pullup: 'GPIO_INPUT',
39
- INPUT_PULLUP: 'GPIO_INPUT',
40
- input_pulldown: 'GPIO_INPUT',
41
- INPUT_PULLDOWN: 'GPIO_INPUT',
42
- };
43
- /** Additional DT flag bits for a HAL mode, OR'd into the configure flags.
44
- * Returns '' for modes with no extra bits so the join leaves the mode alone. */
45
- function dtFlagsForMode(mode) {
46
- const m = (mode ?? '').toLowerCase();
47
- if (m === 'input_pullup')
48
- return ' | GPIO_PULL_UP';
49
- if (m === 'input_pulldown')
50
- return ' | GPIO_PULL_DOWN';
51
- return '';
52
- }
53
- /** Combined mode + pull flags for a HAL mode string, e.g.
54
- * 'INPUT_PULLUP' → 'GPIO_INPUT | GPIO_PULL_UP'. */
55
- function flagsForMode(mode) {
56
- const base = MODE_MAP[mode] ?? 'GPIO_INPUT';
57
- return base + dtFlagsForMode(mode);
58
- }
59
27
  // ── Thin GPIO (hal/gpio-pin.ts) — flag tokens ─────────────────────────────
60
28
  //
61
29
  // "GPIO.OUTPUT | GPIO.PULL_UP" token text maps name-for-name onto the GPIO_*
@@ -0,0 +1,27 @@
1
+ import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
2
+ import type { ZephyrChipDescriptor } from '../chips/types.js';
3
+ /** Modifier tokens — a separate bitmask enum in Zephyr (usage codes start
4
+ * at 4, which collides with modifier bits, so the two kinds CANNOT share
5
+ * one runtime branch: the lowering emits different code per kind).
6
+ * Exported for the hid.h drift-guard test (every mapped macro must exist
7
+ * in Zephyr's header). */
8
+ export declare const KEY_MODIFIER_TOKENS: Record<string, string>;
9
+ /** Is this KEY.* token a modifier (bitmask) rather than a usage code? */
10
+ export declare function isHidModifierToken(token: string): boolean;
11
+ /** Map a KEY or MOUSE token (or pass a runtime expression through) to C. */
12
+ export declare function hidTokenToMacro(token: string, kind: 'key' | 'button'): string;
13
+ /**
14
+ * Emit the HID interface state for one protocol. Called from shimLines when
15
+ * the program uses hid.* — one device handle, one report buffer, the boot
16
+ * report descriptor, and the guarded register helper that also starts the
17
+ * shared usbd context (the same one CDC rides).
18
+ */
19
+ export declare function hidInitLines(protocol: 'keyboard' | 'mouse'): string[];
20
+ /**
21
+ * Resolve a HAL hid.* op to Zephyr C++.
22
+ * Returns `{ code }` for statement ops.
23
+ */
24
+ export declare function lowerHid(op: HALOpIR, chip: ZephyrChipDescriptor): {
25
+ code?: string;
26
+ expression?: string;
27
+ };
@@ -0,0 +1,244 @@
1
+ // ---------------------------------------------------------------------------
2
+ // HID lowering — USB keyboard/mouse over the Zephyr "next" device stack
3
+ //
4
+ // One HID interface per program (Zephyr's zephyr,hid-device node — a v1
5
+ // ceiling like the nRF PWM matrix: Keyboard OR Mouse, not both). The shim
6
+ // block declares the interface device + the boot report buffer + the report
7
+ // descriptor macro; the overlay generator synthesizes the DT node with the
8
+ // protocol the program uses (key verbs → keyboard, mouse verbs → mouse).
9
+ // Key/button arguments arrive as KEY.*/MOUSE.* token text (or runtime
10
+ // expressions) — the token map below translates name-for-name onto Zephyr's
11
+ // HID_KEY_* / button macros, with a build error naming the valid spellings.
12
+ // ----------------------------------------------------------------------------
13
+ /** KEY.* token → Zephyr usage macro. Digits and the four modifiers are the
14
+ * spellings that differ; everything else maps name-for-name. */
15
+ const KEY_TOKENS = {
16
+ A: 'HID_KEY_A', B: 'HID_KEY_B', C: 'HID_KEY_C', D: 'HID_KEY_D', E: 'HID_KEY_E',
17
+ F: 'HID_KEY_F', G: 'HID_KEY_G', H: 'HID_KEY_H', I: 'HID_KEY_I', J: 'HID_KEY_J',
18
+ K: 'HID_KEY_K', L: 'HID_KEY_L', M: 'HID_KEY_M', N: 'HID_KEY_N', O: 'HID_KEY_O',
19
+ P: 'HID_KEY_P', Q: 'HID_KEY_Q', R: 'HID_KEY_R', S: 'HID_KEY_S', T: 'HID_KEY_T',
20
+ U: 'HID_KEY_U', V: 'HID_KEY_V', W: 'HID_KEY_W', X: 'HID_KEY_X', Y: 'HID_KEY_Y',
21
+ Z: 'HID_KEY_Z',
22
+ N1: 'HID_KEY_1', N2: 'HID_KEY_2', N3: 'HID_KEY_3', N4: 'HID_KEY_4', N5: 'HID_KEY_5',
23
+ N6: 'HID_KEY_6', N7: 'HID_KEY_7', N8: 'HID_KEY_8', N9: 'HID_KEY_9', N0: 'HID_KEY_0',
24
+ ENTER: 'HID_KEY_ENTER', ESC: 'HID_KEY_ESC', BACKSPACE: 'HID_KEY_BACKSPACE',
25
+ TAB: 'HID_KEY_TAB', SPACE: 'HID_KEY_SPACE',
26
+ MINUS: 'HID_KEY_MINUS', EQUAL: 'HID_KEY_EQUAL',
27
+ LEFTBRACE: 'HID_KEY_LEFTBRACE', RIGHTBRACE: 'HID_KEY_RIGHTBRACE',
28
+ BACKSLASH: 'HID_KEY_BACKSLASH', SEMICOLON: 'HID_KEY_SEMICOLON',
29
+ APOSTROPHE: 'HID_KEY_APOSTROPHE', GRAVE: 'HID_KEY_GRAVE',
30
+ COMMA: 'HID_KEY_COMMA', DOT: 'HID_KEY_DOT', SLASH: 'HID_KEY_SLASH',
31
+ CAPSLOCK: 'HID_KEY_CAPSLOCK',
32
+ F1: 'HID_KEY_F1', F2: 'HID_KEY_F2', F3: 'HID_KEY_F3', F4: 'HID_KEY_F4',
33
+ F5: 'HID_KEY_F5', F6: 'HID_KEY_F6', F7: 'HID_KEY_F7', F8: 'HID_KEY_F8',
34
+ F9: 'HID_KEY_F9', F10: 'HID_KEY_F10', F11: 'HID_KEY_F11', F12: 'HID_KEY_F12',
35
+ // Zephyr names usage 70 HID_KEY_SYSRQ (the /* PRINTSCREEN */ comment is
36
+ // its only mention of the name) — the HAL token keeps the datasheet word.
37
+ PRINTSCREEN: 'HID_KEY_SYSRQ', SCROLLLOCK: 'HID_KEY_SCROLLLOCK',
38
+ PAUSE: 'HID_KEY_PAUSE', INSERT: 'HID_KEY_INSERT', HOME: 'HID_KEY_HOME',
39
+ PAGEUP: 'HID_KEY_PAGEUP', DEL: 'HID_KEY_DELETE', END: 'HID_KEY_END',
40
+ PAGEDOWN: 'HID_KEY_PAGEDOWN', RIGHT: 'HID_KEY_RIGHT', LEFT: 'HID_KEY_LEFT',
41
+ DOWN: 'HID_KEY_DOWN', UP: 'HID_KEY_UP',
42
+ };
43
+ /** Modifier tokens — a separate bitmask enum in Zephyr (usage codes start
44
+ * at 4, which collides with modifier bits, so the two kinds CANNOT share
45
+ * one runtime branch: the lowering emits different code per kind).
46
+ * Exported for the hid.h drift-guard test (every mapped macro must exist
47
+ * in Zephyr's header). */
48
+ export const KEY_MODIFIER_TOKENS = {
49
+ CTRL: 'HID_KBD_MODIFIER_LEFT_CTRL',
50
+ SHIFT: 'HID_KBD_MODIFIER_LEFT_SHIFT',
51
+ ALT: 'HID_KBD_MODIFIER_LEFT_ALT',
52
+ // HID usage tables call the Windows/Apple/GUI key "UI" — Zephyr follows.
53
+ GUI: 'HID_KBD_MODIFIER_LEFT_UI',
54
+ };
55
+ /** Is this KEY.* token a modifier (bitmask) rather than a usage code? */
56
+ export function isHidModifierToken(token) {
57
+ return token.startsWith('KEY.') && KEY_MODIFIER_TOKENS[token.slice(4)] !== undefined;
58
+ }
59
+ /** Map a modifier token to its Zephyr bitmask macro. */
60
+ function hidModifierMacro(token) {
61
+ return KEY_MODIFIER_TOKENS[token.slice(4)];
62
+ }
63
+ const MOUSE_TOKENS = {
64
+ LEFT: 'BIT(0)', RIGHT: 'BIT(1)', MIDDLE: 'BIT(2)',
65
+ };
66
+ /** Map a KEY or MOUSE token (or pass a runtime expression through) to C. */
67
+ export function hidTokenToMacro(token, kind) {
68
+ const prefix = kind === 'key' ? 'KEY.' : 'MOUSE.';
69
+ if (!token.startsWith(prefix))
70
+ return token; // runtime expression
71
+ const name = token.slice(prefix.length);
72
+ const table = kind === 'key' ? KEY_TOKENS : MOUSE_TOKENS;
73
+ const mapped = table[name];
74
+ if (!mapped) {
75
+ const valid = Object.keys(table).map((k) => prefix + k).join(', ');
76
+ throw new Error(`Unknown ${kind} token '${token}'. Valid spellings: ${valid} (or a runtime number expression).`);
77
+ }
78
+ return mapped;
79
+ }
80
+ /**
81
+ * Emit the HID interface state for one protocol. Called from shimLines when
82
+ * the program uses hid.* — one device handle, one report buffer, the boot
83
+ * report descriptor, and the guarded register helper that also starts the
84
+ * shared usbd context (the same one CDC rides).
85
+ */
86
+ export function hidInitLines(protocol) {
87
+ // The boot descriptors: keyboard takes no args; mouse takes its button
88
+ // count (3 — the MOUSE.LEFT/RIGHT/MIDDLE surface).
89
+ const desc = protocol === 'keyboard' ? 'HID_KEYBOARD_REPORT_DESC()' : 'HID_MOUSE_REPORT_DESC(3)';
90
+ // Driver-contract buffers: USB_STATIC_BUF_DEFINE gives pointer alignment
91
+ // (the DWC2 driver rejects unaligned IN buffers with "Buffer not aligned"
92
+ // and the completion still fires — every submit silently failed before
93
+ // this) and the nocache section on builds that require it.
94
+ const buf = protocol === 'keyboard'
95
+ ? 'USB_STATIC_BUF_DEFINE(__tc_kb_report, 8);'
96
+ : 'USB_STATIC_BUF_DEFINE(__tc_mouse_report, 4);';
97
+ const pragmaWrap = protocol === 'mouse'
98
+ ? [
99
+ '#pragma GCC diagnostic push',
100
+ '#pragma GCC diagnostic ignored "-Wnarrowing"',
101
+ ]
102
+ : [];
103
+ const pragmaUnwrap = protocol === 'mouse' ? ['#pragma GCC diagnostic pop'] : [];
104
+ return [
105
+ '// CUTTLEFISH_HID_BEGIN',
106
+ 'static const struct device* __tc_hid_dev = DEVICE_DT_GET_ONE(zephyr_hid_device);',
107
+ ...pragmaWrap,
108
+ `static const uint8_t __tc_hid_desc[] = ${desc};`,
109
+ ...pragmaUnwrap,
110
+ buf,
111
+ 'static bool __tc_hid_registered = false;',
112
+ // The API contract: get_report is required for every HID device type
113
+ // (hid_dev_register rejects NULL ops with -EINVAL), set_protocol is
114
+ // required for boot-subclass devices (both descriptors here), and
115
+ // set_report when an output report is declared. Minimal stubs — the
116
+ // verbs never read host->device state in v1.
117
+ 'static int __tc_hid_get_report(const struct device* dev, const uint8_t type, const uint8_t id, const uint16_t len, uint8_t* const buf) {',
118
+ ' (void)dev; (void)type; (void)id; (void)len; (void)buf;',
119
+ ' return -ENOTSUP;',
120
+ '}',
121
+ 'static int __tc_hid_set_report(const struct device* dev, const uint8_t type, const uint8_t id, const uint16_t len, const uint8_t* const buf) {',
122
+ ' (void)dev; (void)type; (void)id; (void)len; (void)buf;',
123
+ ' return 0;',
124
+ '}',
125
+ 'static void __tc_hid_set_protocol(const struct device* dev, const uint8_t protocol) {',
126
+ ' (void)dev; (void)protocol;',
127
+ '}',
128
+ 'static bool __tc_hid_ready = false;',
129
+ 'static void __tc_hid_iface_ready(const struct device* dev, const bool ready) {',
130
+ ' (void)dev;',
131
+ ' __tc_hid_ready = ready;',
132
+ '}',
133
+ 'static uint32_t __tc_hid_idle = 0;',
134
+ 'static void __tc_hid_set_idle(const struct device* dev, const uint8_t id, const uint32_t duration) {',
135
+ ' (void)dev; (void)id;',
136
+ ' __tc_hid_idle = duration;',
137
+ '}',
138
+ 'static uint32_t __tc_hid_get_idle(const struct device* dev, const uint8_t id) {',
139
+ ' (void)dev; (void)id;',
140
+ ' return __tc_hid_idle;',
141
+ '}',
142
+ 'static void __tc_hid_output_report(const struct device* dev, const uint16_t len, const uint8_t* const buf) {',
143
+ ' (void)dev; (void)len; (void)buf;',
144
+ '}',
145
+ 'static const struct hid_device_ops __tc_hid_ops = {',
146
+ ' .iface_ready = __tc_hid_iface_ready,',
147
+ ' .get_report = __tc_hid_get_report,',
148
+ ' .set_report = __tc_hid_set_report,',
149
+ ' .set_idle = __tc_hid_set_idle,',
150
+ ' .get_idle = __tc_hid_get_idle,',
151
+ ' .set_protocol = __tc_hid_set_protocol,',
152
+ ' .output_report = __tc_hid_output_report,',
153
+ '};',
154
+ 'static void __tc_hid_register(void) {',
155
+ ' if (__tc_hid_registered) { return; }',
156
+ ' __tc_hid_registered = true;',
157
+ ' int err = hid_device_register(__tc_hid_dev, __tc_hid_desc, sizeof(__tc_hid_desc), &__tc_hid_ops);',
158
+ ' if (err != 0) { printk("typecad-hal hid: register failed: %d\\n", err); return; }',
159
+ ' __tc_usbd_start();',
160
+ '}',
161
+ 'static void __tc_hid_submit(const uint8_t* rep, uint16_t len) {',
162
+ ' int err = hid_device_submit_report(__tc_hid_dev, len, rep);',
163
+ ' // -EACCES is the normal pre-enumeration race (submit before the',
164
+ ' // host configures the interface) — not worth a printk; every other',
165
+ ' // errno (e.g. the alignment error that silently ate reports once)',
166
+ ' // deserves to be loud.',
167
+ ' if (err != 0 && err != -EACCES) { printk("typecad-hal hid: submit failed: %d\\n", err); }',
168
+ '}',
169
+ '// CUTTLEFISH_HID_END',
170
+ ];
171
+ }
172
+ /**
173
+ * Resolve a HAL hid.* op to Zephyr C++.
174
+ * Returns `{ code }` for statement ops.
175
+ */
176
+ export function lowerHid(op, chip) {
177
+ if (!chip.usb) {
178
+ throw new Error(`framework-zephyr: \`${op.operation}\` needs a USB device stack, but this board's chip data declares no \`zephyr.usb\` ` +
179
+ `(controller + cdcInstances). Boards whose Zephyr DTS has no enabled UDC controller node ` +
180
+ `(zephyr_udc0) cannot provide USB HID.`);
181
+ }
182
+ const o = op;
183
+ switch (op.operation) {
184
+ case 'hid.kb_begin':
185
+ return { code: '__tc_hid_register();' };
186
+ case 'hid.kb_press': {
187
+ // Modifier tokens are compile-time bitmasks — a different emit than
188
+ // the usage-code slot logic (runtime expressions take the key path).
189
+ if (isHidModifierToken(String(o.key))) {
190
+ const mod = hidModifierMacro(String(o.key));
191
+ return {
192
+ code: `{ __tc_hid_register(); __tc_kb_report[0] = static_cast<uint8_t>(__tc_kb_report[0] | ${mod}); __tc_hid_submit(__tc_kb_report, 8U); }`,
193
+ };
194
+ }
195
+ const key = hidTokenToMacro(String(o.key), 'key');
196
+ return {
197
+ code: `{ __tc_hid_register(); uint8_t __tc_k = static_cast<uint8_t>(${key}); for (uint32_t __tc_slot = 2U; __tc_slot < 8U; ++__tc_slot) { if (__tc_kb_report[__tc_slot] == 0U) { __tc_kb_report[__tc_slot] = __tc_k; break; } } __tc_hid_submit(__tc_kb_report, 8U); }`,
198
+ };
199
+ }
200
+ case 'hid.kb_release': {
201
+ if (isHidModifierToken(String(o.key))) {
202
+ const mod = hidModifierMacro(String(o.key));
203
+ return {
204
+ code: `{ __tc_hid_register(); __tc_kb_report[0] = static_cast<uint8_t>(__tc_kb_report[0] & static_cast<uint8_t>(~${mod})); __tc_hid_submit(__tc_kb_report, 8U); }`,
205
+ };
206
+ }
207
+ const key = hidTokenToMacro(String(o.key), 'key');
208
+ return {
209
+ code: `{ __tc_hid_register(); uint8_t __tc_k = static_cast<uint8_t>(${key}); for (uint32_t __tc_slot = 2U; __tc_slot < 8U; ++__tc_slot) { if (__tc_kb_report[__tc_slot] == __tc_k) { __tc_kb_report[__tc_slot] = 0U; } } __tc_hid_submit(__tc_kb_report, 8U); }`,
210
+ };
211
+ }
212
+ case 'hid.kb_release_all':
213
+ return {
214
+ code: `{ __tc_hid_register(); for (uint32_t __tc_slot = 0U; __tc_slot < 8U; ++__tc_slot) { __tc_kb_report[__tc_slot] = 0U; } __tc_hid_submit(__tc_kb_report, 8U); }`,
215
+ };
216
+ case 'hid.mouse_begin':
217
+ return { code: '__tc_hid_register();' };
218
+ case 'hid.mouse_move': {
219
+ return {
220
+ code: `{ __tc_hid_register(); int32_t __tc_mx = static_cast<int32_t>(${o.dx}); int32_t __tc_my = static_cast<int32_t>(${o.dy}); int32_t __tc_mw = static_cast<int32_t>(${o.wheel}); if (__tc_mx > 127) { __tc_mx = 127; } if (__tc_mx < -127) { __tc_mx = -127; } if (__tc_my > 127) { __tc_my = 127; } if (__tc_my < -127) { __tc_my = -127; } if (__tc_mw > 127) { __tc_mw = 127; } if (__tc_mw < -127) { __tc_mw = -127; } __tc_mouse_report[1] = static_cast<uint8_t>(__tc_mx); __tc_mouse_report[2] = static_cast<uint8_t>(__tc_my); __tc_mouse_report[3] = static_cast<uint8_t>(__tc_mw); __tc_hid_submit(__tc_mouse_report, 4U); }`,
221
+ };
222
+ }
223
+ case 'hid.mouse_press':
224
+ case 'hid.mouse_release': {
225
+ const btn = hidTokenToMacro(String(o.button), 'button');
226
+ const opText = op.operation === 'hid.mouse_press' ? '|' : '&';
227
+ const mask = op.operation === 'hid.mouse_press'
228
+ ? btn
229
+ : `static_cast<uint8_t>(~${btn})`;
230
+ return {
231
+ code: `{ __tc_hid_register(); __tc_mouse_report[0] = static_cast<uint8_t>(__tc_mouse_report[0] ${opText} ${mask}); __tc_hid_submit(__tc_mouse_report, 4U); }`,
232
+ };
233
+ }
234
+ case 'hid.mouse_click': {
235
+ const btn = hidTokenToMacro(String(o.button), 'button');
236
+ return {
237
+ code: `{ __tc_hid_register(); __tc_mouse_report[0] = static_cast<uint8_t>(__tc_mouse_report[0] | ${btn}); __tc_hid_submit(__tc_mouse_report, 4U); __tc_mouse_report[0] = static_cast<uint8_t>(__tc_mouse_report[0] & static_cast<uint8_t>(~${btn})); __tc_hid_submit(__tc_mouse_report, 4U); }`,
238
+ };
239
+ }
240
+ default:
241
+ throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
242
+ `Open an issue or use rawCpp() to emit it manually.`);
243
+ }
244
+ }