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

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