@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.
- package/LICENSE +202 -21
- package/README.md +49 -87
- package/dist/as-built.d.ts +2 -2
- package/dist/as-built.js +2 -2
- package/dist/audit.d.ts +111 -0
- package/dist/audit.js +416 -0
- package/dist/boardgen.d.ts +1 -9
- package/dist/boardgen.js +288 -47
- package/dist/chips/resolve.js +20 -0
- package/dist/chips/types.d.ts +22 -1
- package/dist/debug-codegen.js +1 -1
- package/dist/display/bindings.d.ts +55 -0
- package/dist/display/bindings.js +316 -0
- package/dist/display/gfx.d.ts +2 -3
- package/dist/display/gfx.js +166 -154
- package/dist/display/index.js +20 -1
- package/dist/display/mipi-dbi-host.d.ts +9 -0
- package/dist/display/mipi-dbi-host.js +174 -0
- package/dist/display/profiles.d.ts +109 -4
- package/dist/display/profiles.js +270 -7
- package/dist/display/touch-adapter.js +119 -49
- package/dist/display/ui-adapter-eink.d.ts +2 -0
- package/dist/display/ui-adapter-eink.js +4 -0
- package/dist/display/ui-adapter-gray.d.ts +8 -0
- package/dist/display/ui-adapter-gray.js +170 -0
- package/dist/display/ui-adapter-mono.d.ts +13 -0
- package/dist/display/ui-adapter-mono.js +230 -0
- package/dist/display/ui-adapter-native.d.ts +10 -0
- package/dist/display/ui-adapter-native.js +295 -0
- package/dist/display/ui-adapter-shared.d.ts +11 -0
- package/dist/display/ui-adapter-shared.js +122 -0
- package/dist/display/ui-adapter.js +510 -558
- package/dist/doctor.js +4 -4
- package/dist/dt-config/custom-board.js +2 -2
- package/dist/dt-config/kconfig.d.ts +62 -1
- package/dist/dt-config/kconfig.js +141 -38
- package/dist/dt-config/overlay.d.ts +15 -2
- package/dist/dt-config/overlay.js +433 -18
- package/dist/framework.manifest.d.ts +10 -4
- package/dist/framework.manifest.js +133 -17
- package/dist/index.d.ts +2 -0
- package/dist/index.js +14 -6
- package/dist/licenses.d.ts +2 -2
- package/dist/licenses.js +13 -92
- package/dist/lowering/can.d.ts +25 -0
- package/dist/lowering/can.js +97 -0
- package/dist/lowering/clock.d.ts +17 -0
- package/dist/lowering/clock.js +58 -0
- package/dist/lowering/fs.js +1 -1
- package/dist/lowering/gpio.js +0 -32
- package/dist/lowering/hid.d.ts +27 -0
- package/dist/lowering/hid.js +244 -0
- package/dist/lowering/http.js +264 -32
- package/dist/lowering/i2c.d.ts +8 -0
- package/dist/lowering/i2c.js +137 -5
- package/dist/lowering/i2s.d.ts +27 -0
- package/dist/lowering/i2s.js +98 -0
- package/dist/lowering/index.d.ts +9 -1
- package/dist/lowering/index.js +25 -1
- package/dist/lowering/interrupts.js +6 -0
- package/dist/lowering/matrix.d.ts +15 -0
- package/dist/lowering/matrix.js +63 -0
- package/dist/lowering/mqtt.js +110 -8
- package/dist/lowering/power.d.ts +3 -2
- package/dist/lowering/power.js +20 -45
- package/dist/lowering/pwm.js +25 -0
- package/dist/lowering/sensor.d.ts +2 -2
- package/dist/lowering/sensor.js +8 -4
- package/dist/lowering/strip.d.ts +16 -0
- package/dist/lowering/strip.js +70 -0
- package/dist/lowering/thread.js +5 -1
- package/dist/lowering/trace.d.ts +44 -0
- package/dist/lowering/trace.js +239 -0
- package/dist/lowering/uart.js +6 -1
- package/dist/lowering/usb.d.ts +3 -1
- package/dist/lowering/usb.js +16 -13
- package/dist/lowering/wdt.js +2 -29
- package/dist/sbom.d.ts +181 -0
- package/dist/sbom.js +901 -0
- package/dist/sdk/board-catalog-sync.d.ts +1 -3
- package/dist/sdk/board-catalog-sync.js +4 -10
- package/dist/strategy.d.ts +82 -46
- package/dist/strategy.js +639 -182
- package/dist/tmp-probe.d.ts +2 -0
- package/dist/tmp-probe.js +9 -0
- package/dist/toolchain/debug-config.d.ts +50 -90
- package/dist/toolchain/debug-config.js +239 -510
- package/dist/toolchain/env-check.d.ts +1 -3
- package/dist/toolchain/env-check.js +2 -7
- package/dist/toolchain/index.d.ts +28 -3
- package/dist/toolchain/index.js +498 -62
- package/dist/toolchain/runners.d.ts +16 -0
- package/dist/toolchain/runners.js +75 -0
- package/dist/toolchain/scaffold.d.ts +5 -2
- package/dist/toolchain/scaffold.js +79 -15
- package/dist/toolchain/west-discover.d.ts +6 -0
- package/dist/toolchain/west-discover.js +36 -13
- package/dist/toolchain/west-spawn.js +8 -2
- package/dist/west-inventory.d.ts +25 -0
- package/dist/west-inventory.js +97 -0
- package/installer/README.md +328 -328
- package/installer/install.sh +2 -2
- package/installer/templates/project/.typecad/activate-zephyr.ps1 +1 -1
- package/installer/templates/project/.typecad/activate-zephyr.sh +1 -1
- package/installer/templates/project/.vscode/settings.json +1 -1
- package/installer/templates/project/README.md +2 -2
- package/package.json +5 -5
- package/src/as-built.ts +206 -206
- package/src/audit.ts +529 -0
- package/src/boardgen.ts +265 -50
- package/src/chips/resolve.ts +21 -0
- package/src/chips/types.ts +10 -1
- package/src/display/bindings.ts +347 -0
- package/src/display/gfx.ts +318 -306
- package/src/display/index.ts +87 -70
- package/src/display/mipi-dbi-host.ts +183 -0
- package/src/display/profiles.ts +458 -139
- package/src/display/touch-adapter.ts +119 -49
- package/src/display/ui-adapter-eink.ts +13 -0
- package/src/display/ui-adapter-gray.ts +178 -0
- package/src/display/ui-adapter-mono.ts +238 -0
- package/src/display/ui-adapter-native.ts +304 -0
- package/src/display/ui-adapter-shared.ts +125 -0
- package/src/display/ui-adapter.ts +732 -781
- package/src/doctor.ts +4 -4
- package/src/dt-config/custom-board.ts +2 -2
- package/src/dt-config/kconfig.ts +647 -505
- package/src/dt-config/overlay.ts +1475 -1058
- package/src/framework.manifest.ts +659 -535
- package/src/index.ts +16 -6
- package/src/licenses.ts +346 -425
- package/src/lowering/can.ts +140 -0
- package/src/lowering/clock.ts +91 -0
- package/src/lowering/fs.ts +135 -135
- package/src/lowering/gpio.ts +0 -33
- package/src/lowering/hid.ts +261 -0
- package/src/lowering/http.ts +264 -32
- package/src/lowering/i2c.ts +142 -5
- package/src/lowering/i2s.ts +143 -0
- package/src/lowering/index.ts +18 -1
- package/src/lowering/interrupts.ts +6 -0
- package/src/lowering/matrix.ts +70 -0
- package/src/lowering/mqtt.ts +109 -8
- package/src/lowering/power.ts +41 -0
- package/src/lowering/pwm.ts +192 -167
- package/src/lowering/sensor.ts +159 -155
- package/src/lowering/strip.ts +81 -0
- package/src/lowering/thread.ts +5 -1
- package/src/lowering/trace.ts +270 -0
- package/src/lowering/uart.ts +6 -1
- package/src/lowering/usb.ts +16 -13
- package/src/lowering/wdt.ts +2 -25
- package/src/sbom.ts +1117 -0
- package/src/sdk/board-catalog-sync.ts +4 -25
- package/src/strategy.ts +2680 -2309
- package/src/toolchain/debug-config.ts +262 -522
- package/src/toolchain/env-check.ts +279 -285
- package/src/toolchain/index.ts +1792 -1359
- package/src/toolchain/runners.ts +80 -0
- package/src/toolchain/scaffold.ts +355 -296
- package/src/toolchain/west-discover.ts +35 -13
- package/src/toolchain/west-spawn.ts +174 -168
- package/src/west-inventory.ts +102 -0
- package/dist/async/timer-polyfill.d.ts +0 -10
- package/dist/async/timer-polyfill.js +0 -95
- package/dist/chips/board-overrides.d.ts +0 -7
- package/dist/chips/board-overrides.js +0 -11
- package/dist/chips/esp32.d.ts +0 -2
- package/dist/chips/esp32.js +0 -71
- package/dist/chips/esp32s3.d.ts +0 -2
- package/dist/chips/esp32s3.js +0 -103
- package/dist/chips/soc/.d.ts +0 -2
- package/dist/chips/soc/.js +0 -129
- package/dist/chips/soc/esp32.d.ts +0 -2
- package/dist/chips/soc/esp32.js +0 -120
- package/dist/chips/soc/esp32c3.d.ts +0 -2
- package/dist/chips/soc/esp32c3.js +0 -90
- package/dist/chips/soc/esp32c6.d.ts +0 -2
- package/dist/chips/soc/esp32c6.js +0 -109
- package/dist/chips/soc/esp32s3.d.ts +0 -2
- package/dist/chips/soc/esp32s3.js +0 -189
- package/dist/chips/soc/index.d.ts +0 -2
- package/dist/chips/soc/index.js +0 -23
- package/dist/chips/soc/nrf52840.d.ts +0 -2
- package/dist/chips/soc/nrf52840.js +0 -130
- package/dist/chips/soc/rp2040.d.ts +0 -2
- package/dist/chips/soc/rp2040.js +0 -141
- package/dist/chips/soc/rp2350a.d.ts +0 -2
- package/dist/chips/soc/rp2350a.js +0 -145
- package/dist/chips/soc/samd21g18a.d.ts +0 -2
- package/dist/chips/soc/samd21g18a.js +0 -143
- package/dist/chips/soc/stm32f411xe.d.ts +0 -2
- package/dist/chips/soc/stm32f411xe.js +0 -251
- package/dist/chips/xiao-ble.d.ts +0 -2
- package/dist/chips/xiao-ble.js +0 -100
- package/dist/lowering/pulse.d.ts +0 -7
- package/dist/lowering/pulse.js +0 -51
- package/dist/lowering/tone.d.ts +0 -10
- package/dist/lowering/tone.js +0 -63
- package/dist/lowering/worker-backing.d.ts +0 -14
- package/dist/lowering/worker-backing.js +0 -79
- package/dist/lowering/worker.d.ts +0 -6
- package/dist/lowering/worker.js +0 -14
- package/dist/sdk/board-data.generated.d.ts +0 -2
- package/dist/sdk/board-data.generated.js +0 -4
- package/dist/sdk/catalog-walker.d.ts +0 -90
- package/dist/sdk/catalog-walker.js +0 -682
- package/dist/sdk/dts-reader.d.ts +0 -83
- package/dist/sdk/dts-reader.js +0 -596
- 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
|
+
}
|