@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,10 @@
1
+ import type { DisplayAdapterCode } from "@typecad/cuttlefish/api/shared";
2
+ import type { ZephyrDisplayProfile } from "./profiles.js";
3
+ /**
4
+ * Build the display-API UI adapter for a profile. The profile's dtLabel must
5
+ * name a display node an in-tree driver binds (the overlay generates it; the
6
+ * Kconfig layer enables the driver symbol for the profile's controller).
7
+ * Profiles whose dbiHost is 'local-hold-cs' additionally emit an app-local
8
+ * CS-holding mipi-dbi host the panel driver sits on (see mipi-dbi-host.ts).
9
+ */
10
+ export declare function zephyrDisplayApiAdapter(profile: ZephyrDisplayProfile): DisplayAdapterCode;
@@ -0,0 +1,295 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Zephyr UI display adapter — 'zephyr-display' transport.
3
+ //
4
+ // Emits the same display_ / display_target_ / display_canvas_ surface the UI
5
+ // runtime expects (see ui-adapter.ts), but reaches the panel through Zephyr's
6
+ // display API: display_write() with a buffer descriptor on the DT display
7
+ // device (the overlay's display0 node under the mipi-dbi-spi bridge), with
8
+ // display_get_capabilities() consulted for the panel's pixel format. An
9
+ // in-tree panel driver (e.g. ilitek,ili9341 with CONFIG_ILI9341) owns the
10
+ // init sequence, rotation, and wire format — this adapter carries no panel
11
+ // registers at all.
12
+ //
13
+ // Why this transport exists alongside 'direct-spi': the direct path is the
14
+ // escape hatch for panels the in-tree drivers cannot init (clone ST7796S —
15
+ // the generic mipi-dbi-spi bridge deasserts CS between the command byte and
16
+ // its parameters, scrambling those panels). Standard ILI9341-class SPI
17
+ // modules tolerate per-transaction CS (upstream Zephyr boards wire them this
18
+ // way), so they can ride the in-tree driver and drop the per-controller
19
+ // emitted init tables. Choose per profile via ZephyrDisplayProfile.transport;
20
+ // flip a profile here only after hardware verification on a rig.
21
+ //
22
+ // display_write() is a dirty-rect API — the descriptor's x/y/width/height
23
+ // become the controller address window — so the UI engine's
24
+ // setAddrWindow+writePixels pairs map onto it directly. Batching notes:
25
+ // display_write calls are atomic per call (the mipi-dbi layer serializes on a
26
+ // per-device mutex), so startWrite/endWrite are no-ops; solid fills tile a
27
+ // reused block buffer into multi-row display_write chunks, the same
28
+ // fewer/larger-transfers lesson the direct path learned (~40 instead of ~320
29
+ // writes on a full 480x320 clear).
30
+ //
31
+ // EMIT BOUNDARY: emitted bytes land in user firmware. Covered by the TypeCAD
32
+ // Runtime Exception (RUNTIME_EXCEPTION.md at the repo root).
33
+ //
34
+ // AGENTS.md rendering guardrails honored: scratch buffers are static and
35
+ // reused (no per-frame heap allocation); fills are block-buffered.
36
+ // ---------------------------------------------------------------------------
37
+ import { dbiHostFor, displayFactsLine } from "./profiles.js";
38
+ import { localHoldCsDbiHost } from "./mipi-dbi-host.js";
39
+ import { CANVAS_LIFECYCLE_SECTION, TARGET_FORWARDERS_SECTION, profileMarkerLine } from "./ui-adapter-shared.js";
40
+ /**
41
+ * Build the display-API UI adapter for a profile. The profile's dtLabel must
42
+ * name a display node an in-tree driver binds (the overlay generates it; the
43
+ * Kconfig layer enables the driver symbol for the profile's controller).
44
+ * Profiles whose dbiHost is 'local-hold-cs' additionally emit an app-local
45
+ * CS-holding mipi-dbi host the panel driver sits on (see mipi-dbi-host.ts).
46
+ */
47
+ export function zephyrDisplayApiAdapter(profile) {
48
+ const w = profile.width;
49
+ const h = profile.height;
50
+ const maxDim = Math.max(w, h);
51
+ const dtLabel = profile.dtLabel;
52
+ const backlightAlias = profile.backlight;
53
+ const rbSwap = profile.channelSwapRb === true;
54
+ const nativeW = profile.nativeWidth ?? w;
55
+ const nativeH = profile.nativeHeight ?? h;
56
+ const host = dbiHostFor(profile) === 'local-hold-cs' ? localHoldCsDbiHost(profile) : undefined;
57
+ const includes = [
58
+ `// --- Zephyr UI display adapter (${profile.driver}, zephyr-display transport) ---`,
59
+ profileMarkerLine(profile.driver),
60
+ displayFactsLine(profile),
61
+ `// Native CuttlefishGFX path: do NOT #define CuttlefishCanvas16 so the`,
62
+ `// runtime header emits the in-tree CuttlefishGFX/CuttlefishCanvas16 class.`,
63
+ `#define CuttlefishDisplayTarget CuttlefishGFX`,
64
+ `#include <zephyr/kernel.h>`,
65
+ `#include <zephyr/drivers/display.h>`,
66
+ `#include <zephyr/drivers/gpio.h>`,
67
+ ...(host ? host.includes : []),
68
+ ].join("\n");
69
+ const declaration = [
70
+ `// CUTTLEFISH_DISPLAY_BEGIN`,
71
+ `// The panel device: the overlay's display0 node, bound by an in-tree panel`,
72
+ `// driver (CONFIG enabled for the profile's controller). Compile-time`,
73
+ `// constant — DEVICE_DT_GET requires the driver to exist at build time,`,
74
+ `// which the Kconfig layer guarantees for this transport.`,
75
+ `static const struct device* __tc_zd_dev = DEVICE_DT_GET(DT_NODELABEL(${dtLabel}));`,
76
+ `// Panel facts from display_get_capabilities, read once in display_init.`,
77
+ `static struct display_capabilities __tc_zd_caps;`,
78
+ `// Zephyr pixel formats carry byte-order semantics: PIXEL_FORMAT_RGB_565`,
79
+ `// is little-endian (Red in byte 1, Blue in byte 0) — exactly the memory`,
80
+ `// layout of the UI's uint16_t rgb565 words on little-endian targets — and`,
81
+ `// PIXEL_FORMAT_RGB_565X is the byte-swapped variant. Clone panels with`,
82
+ `// crossed 16-bit channel routing (verified ST7796S quirk) additionally`,
83
+ `// need an R/B channel swap. __tc_zd_fix_pixel applies the panel's fixup`,
84
+ `// chain before pixels reach display_write.`,
85
+ `static bool __tc_zd_swap = false;`,
86
+ `static const bool __tc_zd_rb = ${rbSwap};`,
87
+ `// Multi-row block buffer for solid fills AND the byte-swap scratch for`,
88
+ `// 565X pixel streams (8 rows of maxDim px, rgb565 — fillRect and`,
89
+ `// writePixels never interleave mid-call, so one buffer serves both).`,
90
+ `// fillRect tiles it once with the color, then delivers the rect in a`,
91
+ `// few large display_write calls instead of one per row — the same`,
92
+ `// per-call-overhead lesson as the direct transport. Reused, not per-frame`,
93
+ `// (AGENTS.md: no per-frame heap allocation).`,
94
+ `#define __TC_FILL_ROWS 8`,
95
+ `static uint16_t __tc_zd_block[${maxDim} * __TC_FILL_ROWS];`,
96
+ `// Stashed address window from the last setAddrWindow call. The runtime`,
97
+ `// calls setAddrWindow + writePixels as a matched pair, so we stash the rect`,
98
+ `// here and consume it in writePixels.`,
99
+ `static int16_t __tc_aw_x = 0;`,
100
+ `static int16_t __tc_aw_y = 0;`,
101
+ `static int16_t __tc_aw_w = ${w};`,
102
+ `static int16_t __tc_aw_h = ${h};`,
103
+ `// CUTTLEFISH_DISPLAY_END`,
104
+ ].join("\n");
105
+ // Backlight: same DT-alias drive as the direct transport (the overlay emits
106
+ // the gpio-leds node + alias only when a backlight GPIO is configured).
107
+ const blInit = backlightAlias
108
+ ? `#if DT_HAS_ALIAS(${backlightAlias})\n const struct gpio_dt_spec __bl = GPIO_DT_SPEC_GET(DT_ALIAS(${backlightAlias}), gpios);\n if (device_is_ready(__bl.port)) { gpio_pin_configure_dt(&__bl, GPIO_OUTPUT_ACTIVE); }\n#endif`
109
+ : '';
110
+ const functions = `${host ? host.functions : ''}
111
+ // ── display-API transport ───────────────────────────────────────────────
112
+ // Every panel write is one display_write() carrying its own address window
113
+ // (the descriptor's x/y/width/height) — no CASET/RASET bookkeeping here. The
114
+ // in-tree driver beneath the device owns init, rotation, and the wire format.
115
+
116
+ static void __tc_zd_write_rect(int16_t x, int16_t y, int16_t rw, int16_t rows,
117
+ const uint16_t* px) {
118
+ if (rw <= 0 || rows <= 0) return;
119
+ struct display_buffer_descriptor __desc = {};
120
+ __desc.width = static_cast<uint16_t>(rw);
121
+ __desc.height = static_cast<uint16_t>(rows);
122
+ __desc.pitch = static_cast<uint16_t>(rw);
123
+ __desc.buf_size = static_cast<size_t>(rw) * static_cast<size_t>(rows) * 2U;
124
+ (void)display_write(__tc_zd_dev, static_cast<uint16_t>(x), static_cast<uint16_t>(y),
125
+ &__desc, px);
126
+ }
127
+
128
+ // The panel's pack-time pixel fixup chain: R/B channel swap (clone panels
129
+ // whose 16-bit routing is crossed — lossless, verified equivalent to the
130
+ // direct transport's 18-bit mode), then byte swap when the panel reports
131
+ // RGB565X. No-op for well-behaved panels on little-endian targets.
132
+ static inline uint16_t __tc_zd_fix_pixel(uint16_t c) {
133
+ if (__tc_zd_rb) {
134
+ c = static_cast<uint16_t>(((c & 0x1Fu) << 11) | ((c >> 11) & 0x1Fu) | (c & 0x07E0u));
135
+ }
136
+ if (__tc_zd_swap) {
137
+ c = static_cast<uint16_t>((c >> 8) | ((c & 0xFFu) << 8));
138
+ }
139
+ return c;
140
+ }
141
+
142
+ // Fix a pixel run into the block scratch (passthrough when the panel needs
143
+ // no fixup — the common case). count ≤ maxDim*__TC_FILL_ROWS — the largest
144
+ // call is a full writePixels batch.
145
+ static const uint16_t* __tc_zd_fixup_run(const uint16_t* px, uint32_t count) {
146
+ if (!__tc_zd_rb && !__tc_zd_swap) return px;
147
+ for (uint32_t i = 0; i < count; i++) {
148
+ __tc_zd_block[i] = __tc_zd_fix_pixel(px[i]);
149
+ }
150
+ return __tc_zd_block;
151
+ }
152
+
153
+ // ── Panel-ops consumed by CuttlefishGFX ─────────────────────────────────
154
+ // startWrite/endWrite are no-ops: display_write is atomic per call (the
155
+ // mipi-dbi layer serializes on a per-device mutex), so there is no CS batch
156
+ // to bracket. The depth-counter concept from the direct transport does not
157
+ // apply.
158
+ static void __tc_op_startWrite(void* /*ctx*/) { }
159
+ static void __tc_op_endWrite(void* /*ctx*/) { }
160
+
161
+ // Stash the target rect. The runtime always follows this with writePixels
162
+ // delivering (w*h) pixels for this rect, OR fillRect/writePixel which ignore
163
+ // the stash.
164
+ static void __tc_op_setAddrWindow(void* /*ctx*/, int16_t x, int16_t y, int16_t winW, int16_t winH) {
165
+ __tc_aw_x = x; __tc_aw_y = y; __tc_aw_w = winW; __tc_aw_h = winH;
166
+ }
167
+
168
+ // Push the stashed rect's worth of rgb565 pixels, delivered in multi-row
169
+ // display_write chunks (≤ __TC_FILL_ROWS rows per call) so a canvas push
170
+ // stays a handful of calls instead of one per row. A trailing partial row
171
+ // (count not a multiple of the window width) goes out as its own 1-row rect.
172
+ static void __tc_op_writePixels(void* /*ctx*/, const uint16_t* px, uint32_t n) {
173
+ if (n == 0U || __tc_aw_w <= 0) return;
174
+ const uint32_t __full = static_cast<uint32_t>(__tc_aw_w);
175
+ uint32_t __rows = n / __full;
176
+ int16_t __row = 0;
177
+ const uint16_t* __p = px;
178
+ while (__rows > 0U) {
179
+ uint32_t __batch = (__rows > static_cast<uint32_t>(__TC_FILL_ROWS))
180
+ ? static_cast<uint32_t>(__TC_FILL_ROWS) : __rows;
181
+ __tc_zd_write_rect(__tc_aw_x, static_cast<int16_t>(__tc_aw_y + __row), __tc_aw_w,
182
+ static_cast<int16_t>(__batch),
183
+ __tc_zd_fixup_run(__p, __full * __batch));
184
+ __p += __full * __batch;
185
+ __rows -= __batch;
186
+ __row = static_cast<int16_t>(__row + __batch);
187
+ }
188
+ const uint32_t __rem = n % __full;
189
+ if (__rem > 0U) {
190
+ __tc_zd_write_rect(__tc_aw_x, static_cast<int16_t>(__tc_aw_y + __row),
191
+ static_cast<int16_t>(__rem), 1, __tc_zd_fixup_run(__p, __rem));
192
+ }
193
+ }
194
+
195
+ // Single pixel: one 1x1 write.
196
+ static void __tc_op_writePixel(void* /*ctx*/, int16_t x, int16_t y, uint16_t c) {
197
+ uint16_t __buf[1];
198
+ __buf[0] = __tc_zd_fix_pixel(c);
199
+ __tc_zd_write_rect(x, y, 1, 1, __buf);
200
+ }
201
+
202
+ // Fill a rect with a solid color: tile the block buffer with the color, then
203
+ // deliver the rect in multi-row display_write chunks.
204
+ static void __tc_op_fillRect(void* /*ctx*/, int16_t x, int16_t y, int16_t rw, int16_t rh, uint16_t c) {
205
+ if (rw <= 0 || rh <= 0) return;
206
+ const uint16_t __word = __tc_zd_fix_pixel(c);
207
+ for (int16_t r = 0; r < __TC_FILL_ROWS; r++) {
208
+ for (int16_t i = 0; i < rw; i++) {
209
+ __tc_zd_block[static_cast<uint32_t>(r) * static_cast<uint32_t>(rw) + static_cast<uint32_t>(i)] = __word;
210
+ }
211
+ }
212
+ int16_t remaining = rh;
213
+ int16_t yy = y;
214
+ while (remaining > 0) {
215
+ int16_t chunk = (remaining > __TC_FILL_ROWS) ? __TC_FILL_ROWS : remaining;
216
+ __tc_zd_write_rect(x, yy, rw, chunk, __tc_zd_block);
217
+ remaining -= chunk;
218
+ yy = static_cast<int16_t>(yy + chunk);
219
+ }
220
+ }
221
+
222
+ // Width/height are the profile's compile-time effective dimensions — the
223
+ // CuttlefishGFX global below is constructed before main() runs, so it cannot
224
+ // wait for display_get_capabilities. display_init cross-checks the caps
225
+ // against these and reports a mismatch (a wiring/binding problem worth
226
+ // surfacing, not silently rendering at the wrong resolution).
227
+ static int16_t __tc_op_width(void* /*ctx*/) { return ${w}; }
228
+ static int16_t __tc_op_height(void* /*ctx*/) { return ${h}; }
229
+
230
+ // flush is nullptr — immediate-mode panel (TFT); the dirty loop's writes are
231
+ // already on the glass.
232
+ struct CuttlefishPanelOps;
233
+ extern const CuttlefishPanelOps __tc_display_ops;
234
+
235
+ const CuttlefishPanelOps __tc_display_ops = {
236
+ __tc_op_startWrite,
237
+ __tc_op_endWrite,
238
+ __tc_op_setAddrWindow,
239
+ __tc_op_writePixels,
240
+ __tc_op_writePixel,
241
+ __tc_op_fillRect,
242
+ __tc_op_width,
243
+ __tc_op_height,
244
+ nullptr, // flush — immediate-mode panel
245
+ };
246
+
247
+ // The live display target: a CuttlefishGFX driven by the panel-ops vtable.
248
+ CuttlefishGFX __tc_display(&__tc_display_ops, nullptr);
249
+
250
+ // ── display_init (called from setup) ────────────────────────────────────
251
+
252
+ static inline void display_init() {
253
+ printk("TC_DISPLAY: display-API transport (${dtLabel})\\n");
254
+ ${blInit}
255
+ if (!device_is_ready(__tc_zd_dev)) {
256
+ printk("TC_DISPLAY: device not ready — is the panel driver enabled?\\n");
257
+ return;
258
+ }
259
+ display_get_capabilities(__tc_zd_dev, &__tc_zd_caps);
260
+ __tc_zd_swap = (__tc_zd_caps.current_pixel_format == PIXEL_FORMAT_RGB_565X);
261
+ if (__tc_zd_caps.current_pixel_format != PIXEL_FORMAT_RGB_565
262
+ && __tc_zd_caps.current_pixel_format != PIXEL_FORMAT_RGB_565X) {
263
+ printk("TC_DISPLAY: unexpected pixel format %u (expected RGB565) — rendering best-effort\\n",
264
+ static_cast<unsigned int>(__tc_zd_caps.current_pixel_format));
265
+ }
266
+ if (__tc_zd_caps.x_resolution != static_cast<uint16_t>(${nativeW})
267
+ || __tc_zd_caps.y_resolution != static_cast<uint16_t>(${nativeH})) {
268
+ printk("TC_DISPLAY: panel reports %ux%u, DT node carries ${nativeW}x${nativeH} — check the display node geometry\\n",
269
+ static_cast<unsigned int>(__tc_zd_caps.x_resolution),
270
+ static_cast<unsigned int>(__tc_zd_caps.y_resolution));
271
+ }
272
+ (void)display_blanking_off(__tc_zd_dev);
273
+ __tc_op_fillRect(nullptr, 0, 0, ${w}, ${h}, 0x0000);
274
+ printk("TC_DISPLAY: display-API init done (RGB565, black fill)\\n");
275
+ }
276
+
277
+ static inline void display_fillScreen(UI_COLOR_T color) {
278
+ __tc_op_fillRect(nullptr, 0, 0, ${w}, ${h}, static_cast<uint16_t>(color));
279
+ }
280
+ static inline CuttlefishDisplayTarget* display_defaultTarget() { return &__tc_display; }
281
+ static inline int16_t display_width() { return ${w}; }
282
+ static inline int16_t display_height() { return ${h}; }
283
+
284
+ static inline void display_startWrite() { }
285
+ static inline void display_endWrite() { }
286
+ static inline void display_setAddrWindow(int16_t x, int16_t y, int16_t winW, int16_t winH) {
287
+ __tc_op_setAddrWindow(nullptr, x, y, winW, winH);
288
+ }
289
+ static inline void display_writePixels(const UI_COLOR_T* pixels, uint32_t count) {
290
+ uint16_t* px = const_cast<uint16_t*>(static_cast<const uint16_t*>(pixels));
291
+ __tc_op_writePixels(nullptr, px, count);
292
+ }
293
+ ${CANVAS_LIFECYCLE_SECTION}${TARGET_FORWARDERS_SECTION}`;
294
+ return { includes, declaration, functions };
295
+ }
@@ -0,0 +1,11 @@
1
+ /** Offscreen canvas lifecycle + accessors (malloc + placement-new; PSRAM via
2
+ * Zephyr's shared multi-heap when BOARD_HAS_PSRAM). */
3
+ export declare const CANVAS_LIFECYCLE_SECTION = "\n// \u2500\u2500 Canvas lifecycle + accessors (offscreen rgb565 compositing) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Allocate the canvas object via malloc + placement-new (not operator new).\n// Under CONFIG_REQUIRES_FULL_LIBCPP without CONFIG_CPP_EXCEPTIONS, operator new\n// throws std::bad_alloc on OOM and the nothrow wrapper's internal catch cannot\n// unwind (no EH runtime) \u2192 std::terminate \u2192 abort. malloc returns NULL on\n// failure with no exception path; placement-new then constructs the object in\n// place (vtable included). display_deleteCanvas mirrors with an explicit dtor\n// + free. The runtime's callers already null-check the return, so an OOM\n// degrades gracefully instead of aborting.\nstatic inline CuttlefishCanvas16* display_createCanvas(int16_t cw, int16_t ch) {\n void* mem = malloc(sizeof(CuttlefishCanvas16));\n if (!mem) return nullptr;\n return new (mem) CuttlefishCanvas16(cw, ch);\n}\n// psramFound() shim: the Arduino ESP32 core provides this, but Zephyr does not.\n// Under BOARD_HAS_PSRAM the ESP heap serves PSRAM, so report it as present. The\n// runtime's ui_create_canvas_best calls this under #if defined(BOARD_HAS_PSRAM).\n#if defined(BOARD_HAS_PSRAM) && !defined(psramFound)\n#include <zephyr/multi_heap/shared_multi_heap.h>\nstatic inline bool psramFound() {\n // Compile-time truth: if BOARD_HAS_PSRAM is defined, the build targets a\n // PSRAM board with CONFIG_ESP_SPIRAM enabled (the framework emits both).\n return true;\n}\n// Allocate from PSRAM via Zephyr's shared multi-heap (the ESP32 SoC code\n// registers PSRAM as an SMH_REG_ATTR_EXTERNAL region at boot).\nstatic inline void* ui_psram_malloc(size_t bytes) {\n return shared_multi_heap_alloc(SMH_REG_ATTR_EXTERNAL, bytes);\n}\n#endif\nstatic inline CuttlefishCanvas16* display_createCanvasPsram(int16_t cw, int16_t ch) {\n // Allocate the pixel buffer in PSRAM (large: w*h*2 bytes) and the small\n // canvas object in SRAM. The canvas takes ownership of the PSRAM buffer and\n // frees it via free() in its dtor (the SMH allocator's free is compatible\n // with the standard k_free/free path). Returns nullptr if PSRAM isn't\n // available or the allocation fails \u2014 ui_create_canvas_best falls back.\n#if defined(BOARD_HAS_PSRAM)\n if ((cw > 0) && (ch > 0)) {\n size_t bytes = static_cast<size_t>(cw) * static_cast<size_t>(ch) * sizeof(uint16_t);\n uint16_t* psramBuf = static_cast<uint16_t*>(ui_psram_malloc(bytes));\n if (psramBuf) {\n void* mem = malloc(sizeof(CuttlefishCanvas16));\n if (mem) {\n return new (mem) CuttlefishCanvas16(cw, ch, psramBuf, 1);\n }\n free(psramBuf);\n }\n }\n#else\n (void)cw; (void)ch;\n#endif\n return nullptr;\n}\nstatic inline void display_deleteCanvas(CuttlefishCanvas16* canvas) {\n if (!canvas) return;\n canvas->~CuttlefishCanvas16();\n free(canvas);\n}\nstatic inline int16_t display_canvasWidth(CuttlefishCanvas16* c) { return c->width(); }\nstatic inline int16_t display_canvasHeight(CuttlefishCanvas16* c) { return c->height(); }\n// Canvas buffers are addressed in UI_COLOR_T units by every runtime caller;\n// the underlying CuttlefishCanvas16 storage is 16-bit (the 565/mono world the\n// canvas machinery was built for). Gray8/full-frame targets never allocate\n// canvases, so the reinterpret never dereferences on those builds.\nstatic inline UI_COLOR_T* display_canvasBuffer(CuttlefishCanvas16* c) {\n return reinterpret_cast<UI_COLOR_T*>(c->getBuffer());\n}\nstatic inline uint16_t display_canvasGetPixel(CuttlefishCanvas16* c, int16_t x, int16_t y) { return c->getPixel(x, y); }\nstatic inline void display_canvasFillScreen(CuttlefishCanvas16* c, UI_COLOR_T color) { c->fillScreen(static_cast<uint16_t>(color)); }\nstatic inline void display_canvasFillRect(CuttlefishCanvas16* c, int16_t x, int16_t y, int16_t cw, int16_t ch, UI_COLOR_T color) {\n c->fillRect(x, y, cw, ch, static_cast<uint16_t>(color));\n}\n";
4
+ /** Target-polymorphic draw passthroughs (panel or canvas via
5
+ * CuttlefishDisplayTarget*). Pure virtual dispatch on the target object. */
6
+ export declare const TARGET_FORWARDERS_SECTION = "\n// \u2500\u2500 Target-polymorphic draw (panel or canvas via CuttlefishDisplayTarget*) \u2500\nstatic inline void display_targetDrawPixel(CuttlefishDisplayTarget* t, int16_t x, int16_t y, UI_COLOR_T color) { t->drawPixel(x, y, static_cast<uint16_t>(color)); }\nstatic inline int16_t display_targetWidth(CuttlefishDisplayTarget* t) { return t->width(); }\nstatic inline int16_t display_targetHeight(CuttlefishDisplayTarget* t) { return t->height(); }\nstatic inline void display_targetDrawRGBBitmap(CuttlefishDisplayTarget* t, int16_t x, int16_t y, const UI_COLOR_T* bitmap, int16_t bw, int16_t bh) {\n t->drawRGBBitmap(x, y, reinterpret_cast<const uint16_t*>(bitmap), bw, bh);\n}\nstatic inline void display_targetFillRect(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, int16_t bh, UI_COLOR_T color) { t->fillRect(x, y, bw, bh, static_cast<uint16_t>(color)); }\nstatic inline void display_targetDrawFastHLine(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, UI_COLOR_T color) { t->drawFastHLine(x, y, bw, static_cast<uint16_t>(color)); }\nstatic inline void display_targetDrawFastVLine(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bh, UI_COLOR_T color) { t->drawFastVLine(x, y, bh, static_cast<uint16_t>(color)); }\nstatic inline void display_targetFillRoundRect(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, int16_t bh, int16_t r, UI_COLOR_T color) { t->fillRoundRect(x, y, bw, bh, r, static_cast<uint16_t>(color)); }\nstatic inline void display_targetDrawRect(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, int16_t bh, UI_COLOR_T color) { t->drawRect(x, y, bw, bh, static_cast<uint16_t>(color)); }\nstatic inline void display_targetDrawRoundRect(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, int16_t bh, int16_t r, UI_COLOR_T color) { t->drawRoundRect(x, y, bw, bh, r, static_cast<uint16_t>(color)); }\nstatic inline void display_targetDrawLine(CuttlefishDisplayTarget* t, int16_t x0, int16_t y0, int16_t x1, int16_t y1, UI_COLOR_T color) { t->drawLine(x0, y0, x1, y1, static_cast<uint16_t>(color)); }\nstatic inline void display_targetFillCircle(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t r, UI_COLOR_T color) { t->fillCircle(x, y, r, static_cast<uint16_t>(color)); }\nstatic inline void display_targetDrawCircle(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t r, UI_COLOR_T color) { t->drawCircle(x, y, r, static_cast<uint16_t>(color)); }\nstatic inline void display_targetSetCursor(CuttlefishDisplayTarget* t, int16_t x, int16_t y) { t->setCursor(x, y); }\nstatic inline void display_targetSetTextColor(CuttlefishDisplayTarget* t, UI_COLOR_T fg) { t->setTextColor(static_cast<uint16_t>(fg)); }\nstatic inline void display_targetSetTextColorBg(CuttlefishDisplayTarget* t, UI_COLOR_T fg, UI_COLOR_T bg) { t->setTextColor(static_cast<uint16_t>(fg), static_cast<uint16_t>(bg)); }\nstatic inline void display_targetSetTextSize(CuttlefishDisplayTarget* t, uint8_t s) { t->setTextSize(s); }\nstatic inline void display_targetSetTextWrap(CuttlefishDisplayTarget* t, bool wp) { t->setTextWrap(wp); }\nstatic inline void display_targetPrint(CuttlefishDisplayTarget* t, const char* s) { t->print(s); }\n";
7
+ /** The marker line every adapter stamps into its includes so the toolchain
8
+ * can recover the emitting profile. Pairs with displayFactsLine() from
9
+ * profiles.ts, which adapters emit alongside it (the facts line carries
10
+ * synthesized, compatible-driven profiles too). */
11
+ export declare function profileMarkerLine(driver: string): string;
@@ -0,0 +1,122 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Shared C++ sections for the Zephyr UI display adapters.
3
+ //
4
+ // The canvas lifecycle + target-polymorphic sections of the emitted adapter
5
+ // are transport-independent (they operate on CuttlefishCanvas16 /
6
+ // CuttlefishDisplayTarget and never touch the panel), so both transports
7
+ // (direct-spi in ui-adapter.ts, zephyr-display in ui-adapter-native.ts)
8
+ // emit them verbatim from this module. Keeping one copy prevents the two
9
+ // transports from drifting apart.
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
+ /** Offscreen canvas lifecycle + accessors (malloc + placement-new; PSRAM via
15
+ * Zephyr's shared multi-heap when BOARD_HAS_PSRAM). */
16
+ export const CANVAS_LIFECYCLE_SECTION = `
17
+ // ── Canvas lifecycle + accessors (offscreen rgb565 compositing) ──────────
18
+ // Allocate the canvas object via malloc + placement-new (not operator new).
19
+ // Under CONFIG_REQUIRES_FULL_LIBCPP without CONFIG_CPP_EXCEPTIONS, operator new
20
+ // throws std::bad_alloc on OOM and the nothrow wrapper's internal catch cannot
21
+ // unwind (no EH runtime) → std::terminate → abort. malloc returns NULL on
22
+ // failure with no exception path; placement-new then constructs the object in
23
+ // place (vtable included). display_deleteCanvas mirrors with an explicit dtor
24
+ // + free. The runtime's callers already null-check the return, so an OOM
25
+ // degrades gracefully instead of aborting.
26
+ static inline CuttlefishCanvas16* display_createCanvas(int16_t cw, int16_t ch) {
27
+ void* mem = malloc(sizeof(CuttlefishCanvas16));
28
+ if (!mem) return nullptr;
29
+ return new (mem) CuttlefishCanvas16(cw, ch);
30
+ }
31
+ // psramFound() shim: the Arduino ESP32 core provides this, but Zephyr does not.
32
+ // Under BOARD_HAS_PSRAM the ESP heap serves PSRAM, so report it as present. The
33
+ // runtime's ui_create_canvas_best calls this under #if defined(BOARD_HAS_PSRAM).
34
+ #if defined(BOARD_HAS_PSRAM) && !defined(psramFound)
35
+ #include <zephyr/multi_heap/shared_multi_heap.h>
36
+ static inline bool psramFound() {
37
+ // Compile-time truth: if BOARD_HAS_PSRAM is defined, the build targets a
38
+ // PSRAM board with CONFIG_ESP_SPIRAM enabled (the framework emits both).
39
+ return true;
40
+ }
41
+ // Allocate from PSRAM via Zephyr's shared multi-heap (the ESP32 SoC code
42
+ // registers PSRAM as an SMH_REG_ATTR_EXTERNAL region at boot).
43
+ static inline void* ui_psram_malloc(size_t bytes) {
44
+ return shared_multi_heap_alloc(SMH_REG_ATTR_EXTERNAL, bytes);
45
+ }
46
+ #endif
47
+ static inline CuttlefishCanvas16* display_createCanvasPsram(int16_t cw, int16_t ch) {
48
+ // Allocate the pixel buffer in PSRAM (large: w*h*2 bytes) and the small
49
+ // canvas object in SRAM. The canvas takes ownership of the PSRAM buffer and
50
+ // frees it via free() in its dtor (the SMH allocator's free is compatible
51
+ // with the standard k_free/free path). Returns nullptr if PSRAM isn't
52
+ // available or the allocation fails — ui_create_canvas_best falls back.
53
+ #if defined(BOARD_HAS_PSRAM)
54
+ if ((cw > 0) && (ch > 0)) {
55
+ size_t bytes = static_cast<size_t>(cw) * static_cast<size_t>(ch) * sizeof(uint16_t);
56
+ uint16_t* psramBuf = static_cast<uint16_t*>(ui_psram_malloc(bytes));
57
+ if (psramBuf) {
58
+ void* mem = malloc(sizeof(CuttlefishCanvas16));
59
+ if (mem) {
60
+ return new (mem) CuttlefishCanvas16(cw, ch, psramBuf, 1);
61
+ }
62
+ free(psramBuf);
63
+ }
64
+ }
65
+ #else
66
+ (void)cw; (void)ch;
67
+ #endif
68
+ return nullptr;
69
+ }
70
+ static inline void display_deleteCanvas(CuttlefishCanvas16* canvas) {
71
+ if (!canvas) return;
72
+ canvas->~CuttlefishCanvas16();
73
+ free(canvas);
74
+ }
75
+ static inline int16_t display_canvasWidth(CuttlefishCanvas16* c) { return c->width(); }
76
+ static inline int16_t display_canvasHeight(CuttlefishCanvas16* c) { return c->height(); }
77
+ // Canvas buffers are addressed in UI_COLOR_T units by every runtime caller;
78
+ // the underlying CuttlefishCanvas16 storage is 16-bit (the 565/mono world the
79
+ // canvas machinery was built for). Gray8/full-frame targets never allocate
80
+ // canvases, so the reinterpret never dereferences on those builds.
81
+ static inline UI_COLOR_T* display_canvasBuffer(CuttlefishCanvas16* c) {
82
+ return reinterpret_cast<UI_COLOR_T*>(c->getBuffer());
83
+ }
84
+ static inline uint16_t display_canvasGetPixel(CuttlefishCanvas16* c, int16_t x, int16_t y) { return c->getPixel(x, y); }
85
+ static inline void display_canvasFillScreen(CuttlefishCanvas16* c, UI_COLOR_T color) { c->fillScreen(static_cast<uint16_t>(color)); }
86
+ static inline void display_canvasFillRect(CuttlefishCanvas16* c, int16_t x, int16_t y, int16_t cw, int16_t ch, UI_COLOR_T color) {
87
+ c->fillRect(x, y, cw, ch, static_cast<uint16_t>(color));
88
+ }
89
+ `;
90
+ /** Target-polymorphic draw passthroughs (panel or canvas via
91
+ * CuttlefishDisplayTarget*). Pure virtual dispatch on the target object. */
92
+ export const TARGET_FORWARDERS_SECTION = `
93
+ // ── Target-polymorphic draw (panel or canvas via CuttlefishDisplayTarget*) ─
94
+ static inline void display_targetDrawPixel(CuttlefishDisplayTarget* t, int16_t x, int16_t y, UI_COLOR_T color) { t->drawPixel(x, y, static_cast<uint16_t>(color)); }
95
+ static inline int16_t display_targetWidth(CuttlefishDisplayTarget* t) { return t->width(); }
96
+ static inline int16_t display_targetHeight(CuttlefishDisplayTarget* t) { return t->height(); }
97
+ static inline void display_targetDrawRGBBitmap(CuttlefishDisplayTarget* t, int16_t x, int16_t y, const UI_COLOR_T* bitmap, int16_t bw, int16_t bh) {
98
+ t->drawRGBBitmap(x, y, reinterpret_cast<const uint16_t*>(bitmap), bw, bh);
99
+ }
100
+ static inline void display_targetFillRect(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, int16_t bh, UI_COLOR_T color) { t->fillRect(x, y, bw, bh, static_cast<uint16_t>(color)); }
101
+ static inline void display_targetDrawFastHLine(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, UI_COLOR_T color) { t->drawFastHLine(x, y, bw, static_cast<uint16_t>(color)); }
102
+ static inline void display_targetDrawFastVLine(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bh, UI_COLOR_T color) { t->drawFastVLine(x, y, bh, static_cast<uint16_t>(color)); }
103
+ static inline void display_targetFillRoundRect(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, int16_t bh, int16_t r, UI_COLOR_T color) { t->fillRoundRect(x, y, bw, bh, r, static_cast<uint16_t>(color)); }
104
+ static inline void display_targetDrawRect(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, int16_t bh, UI_COLOR_T color) { t->drawRect(x, y, bw, bh, static_cast<uint16_t>(color)); }
105
+ static inline void display_targetDrawRoundRect(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t bw, int16_t bh, int16_t r, UI_COLOR_T color) { t->drawRoundRect(x, y, bw, bh, r, static_cast<uint16_t>(color)); }
106
+ static inline void display_targetDrawLine(CuttlefishDisplayTarget* t, int16_t x0, int16_t y0, int16_t x1, int16_t y1, UI_COLOR_T color) { t->drawLine(x0, y0, x1, y1, static_cast<uint16_t>(color)); }
107
+ static inline void display_targetFillCircle(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t r, UI_COLOR_T color) { t->fillCircle(x, y, r, static_cast<uint16_t>(color)); }
108
+ static inline void display_targetDrawCircle(CuttlefishDisplayTarget* t, int16_t x, int16_t y, int16_t r, UI_COLOR_T color) { t->drawCircle(x, y, r, static_cast<uint16_t>(color)); }
109
+ static inline void display_targetSetCursor(CuttlefishDisplayTarget* t, int16_t x, int16_t y) { t->setCursor(x, y); }
110
+ static inline void display_targetSetTextColor(CuttlefishDisplayTarget* t, UI_COLOR_T fg) { t->setTextColor(static_cast<uint16_t>(fg)); }
111
+ static inline void display_targetSetTextColorBg(CuttlefishDisplayTarget* t, UI_COLOR_T fg, UI_COLOR_T bg) { t->setTextColor(static_cast<uint16_t>(fg), static_cast<uint16_t>(bg)); }
112
+ static inline void display_targetSetTextSize(CuttlefishDisplayTarget* t, uint8_t s) { t->setTextSize(s); }
113
+ static inline void display_targetSetTextWrap(CuttlefishDisplayTarget* t, bool wp) { t->setTextWrap(wp); }
114
+ static inline void display_targetPrint(CuttlefishDisplayTarget* t, const char* s) { t->print(s); }
115
+ `;
116
+ /** The marker line every adapter stamps into its includes so the toolchain
117
+ * can recover the emitting profile. Pairs with displayFactsLine() from
118
+ * profiles.ts, which adapters emit alongside it (the facts line carries
119
+ * synthesized, compatible-driven profiles too). */
120
+ export function profileMarkerLine(driver) {
121
+ return `// typecad-display-profile: ${driver}`;
122
+ }