@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
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// Zephyr touch adapters for the
|
|
2
|
+
// Zephyr touch adapters for the TypeCAD UI rendering pipeline.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
4
|
+
// - FT6336U capacitive: through Zephyr's INPUT subsystem — the in-tree
|
|
5
|
+
// focaltech,ft5336 driver owns the controller (polling mode: the node
|
|
6
|
+
// carries no int-gpios, so the driver samples on a k_timer/work cycle
|
|
7
|
+
// and no GPIO IRQ is registered — sidestepping the ESP32
|
|
8
|
+
// VECDESC_FL_SHARED crash the direct-IRQ path hit). The adapter listens
|
|
9
|
+
// for the device's INPUT events and serves the runtime's
|
|
10
|
+
// touch_init/isTouched/readRaw contract from the latest event state.
|
|
11
|
+
// Hardware-verified on the demo rig (ESP32-S3 + FT6336U, SDA8/SCL9).
|
|
12
|
+
// - XPT2046 resistive: raw SPI polling (spi_transceive_dt) — the Zephyr
|
|
13
|
+
// analog of Arduino's XPT2046_Touchscreen adapter. NOT yet on the input
|
|
14
|
+
// subsystem: the in-tree xpt2046 driver scales coordinates through its
|
|
15
|
+
// DT min-x/max-x props, which would double-apply the runtime's
|
|
16
|
+
// calibration math (touch_readRaw must stay in raw controller units for
|
|
17
|
+
// ui_poll_touch's calibration + rotation). Converting needs the DT
|
|
18
|
+
// scaling reconciled with the config calibration — and hardware to
|
|
19
|
+
// verify it on. CONFIG_INPUT stays off for xpt2046-only builds.
|
|
10
20
|
//
|
|
11
21
|
// The adapters emit touch_init / touch_isTouched / touch_readRaw — the three
|
|
12
|
-
// symbols the runtime's ui_poll_touch body calls.
|
|
22
|
+
// symbols the runtime's ui_poll_touch body calls. For FT6336U the raw
|
|
23
|
+
// coordinate space is unchanged (X/Y controller registers, native portrait
|
|
24
|
+
// panel units): the overlay's swapped-xy property makes the driver's ABS_X/
|
|
25
|
+
// ABS_Y events carry the register values verbatim, so ui_poll_touch's
|
|
26
|
+
// calibration + rotation math applies as before.
|
|
13
27
|
//
|
|
14
28
|
// EMIT BOUNDARY: emitted bytes land in user firmware. Covered by the TypeCAD
|
|
15
29
|
// Runtime Exception (RUNTIME_EXCEPTION.md at the repo root).
|
|
@@ -135,69 +149,125 @@ function xpt2046Adapter(touch: TouchProfile): TouchAdapterCodegen {
|
|
|
135
149
|
function ft6336uAdapter(_touch: TouchProfile): TouchAdapterCodegen {
|
|
136
150
|
return {
|
|
137
151
|
includes: [
|
|
152
|
+
`#include <zephyr/kernel.h>`,
|
|
153
|
+
`#include <zephyr/input/input.h>`,
|
|
154
|
+
// TEMPORARY DIAGNOSTIC (with __tc_touch_diag above).
|
|
138
155
|
`#include <zephyr/drivers/i2c.h>`,
|
|
139
156
|
],
|
|
140
157
|
declaration: [
|
|
141
|
-
`// Zephyr FT6336U touch —
|
|
142
|
-
`//
|
|
143
|
-
|
|
158
|
+
`// Zephyr FT6336U touch — INPUT subsystem listener. The in-tree`,
|
|
159
|
+
`// focaltech,ft5336 driver (CONFIG_INPUT_FT5336, polling mode — no`,
|
|
160
|
+
`// int-gpios on the node) owns the controller and reports events; this`,
|
|
161
|
+
`// adapter keeps the latest state and serves the runtime's per-frame`,
|
|
162
|
+
`// touch_isTouched/touch_readRaw poll. The overlay's swapped-xy DT prop`,
|
|
163
|
+
`// makes the driver's ABS_X/ABS_Y carry the controller's X/Y registers`,
|
|
164
|
+
`// verbatim — the same raw space the register-polling adapter reported,`,
|
|
165
|
+
`// so the runtime's calibration + rotation math is unchanged.`,
|
|
144
166
|
`static int16_t __tc_touch_cached_x = 0;`,
|
|
145
167
|
`static int16_t __tc_touch_cached_y = 0;`,
|
|
146
|
-
`static
|
|
147
|
-
`static uint8_t __tc_touch_cached_valid = 0;`,
|
|
168
|
+
`static volatile bool __tc_touch_down = false;`,
|
|
148
169
|
].join("\n"),
|
|
149
170
|
functions: [
|
|
150
|
-
`//
|
|
151
|
-
`//
|
|
152
|
-
`//
|
|
153
|
-
`// frame
|
|
154
|
-
`//
|
|
155
|
-
|
|
156
|
-
`
|
|
157
|
-
`
|
|
158
|
-
`
|
|
171
|
+
`// Input listener: runs in the driver's work-handler context (poll mode`,
|
|
172
|
+
`// samples every CONFIG_INPUT_FT5336_PERIOD ms). Latest-value semantics —`,
|
|
173
|
+
`// plain int16 stores with no locking; the UI loop reads them once per`,
|
|
174
|
+
`// frame and a torn mid-write read only ever costs one sample of one axis.`,
|
|
175
|
+
`// The first events are logged once — a diagnostic that costs ten lines`,
|
|
176
|
+
`// ever and immediately answers "are events arriving, and in which space".`,
|
|
177
|
+
`static uint8_t __tc_touch_evt_logged = 0U;`,
|
|
178
|
+
`static void __tc_touch_input_cb(struct input_event* evt, void* /*user_data*/) {`,
|
|
179
|
+
` if (__tc_touch_evt_logged < 10U) {`,
|
|
180
|
+
` __tc_touch_evt_logged++;`,
|
|
181
|
+
` printk("TC_TOUCH: evt type=%u code=%u value=%d sync=%u\\n",`,
|
|
182
|
+
` static_cast<unsigned int>(evt->type),`,
|
|
183
|
+
` static_cast<unsigned int>(evt->code),`,
|
|
184
|
+
` static_cast<int>(evt->value),`,
|
|
185
|
+
` static_cast<unsigned int>(evt->sync));`,
|
|
186
|
+
` }`,
|
|
187
|
+
` if (evt->type == INPUT_EV_ABS) {`,
|
|
188
|
+
` if (evt->code == INPUT_ABS_X) {`,
|
|
189
|
+
` __tc_touch_cached_x = static_cast<int16_t>(evt->value);`,
|
|
190
|
+
` } else if (evt->code == INPUT_ABS_Y) {`,
|
|
191
|
+
` __tc_touch_cached_y = static_cast<int16_t>(evt->value);`,
|
|
192
|
+
` }`,
|
|
193
|
+
` } else if ((evt->type == INPUT_EV_KEY) && (evt->code == INPUT_BTN_TOUCH)) {`,
|
|
194
|
+
` __tc_touch_down = (evt->value != 0);`,
|
|
195
|
+
` }`,
|
|
159
196
|
`}`,
|
|
160
197
|
``,
|
|
198
|
+
`// Registered for the ft6336u device's events only (the _dev filter) —`,
|
|
199
|
+
`// other input devices on the system never reach the UI touch state.`,
|
|
200
|
+
`INPUT_CALLBACK_DEFINE(DEVICE_DT_GET(DT_NODELABEL(ft6336u)), __tc_touch_input_cb, NULL);`,
|
|
201
|
+
``,
|
|
161
202
|
`static inline void touch_init() {`,
|
|
162
|
-
` //
|
|
163
|
-
` //
|
|
203
|
+
` // Power/reset enable — rig-verified sequence, matching the Arduino`,
|
|
204
|
+
` // pin order this module needs (GPIO driven LOW 10ms, then HIGH, then`,
|
|
205
|
+
` // 500ms settle before the controller answers). Without the drive the`,
|
|
206
|
+
` // enable floats: the controller half-powers, ACKs briefly, then`,
|
|
207
|
+
` // browns out — the 0xFF-then-NAK bus death reproduced identically on`,
|
|
208
|
+
` // every firmware variant until this was wired. The in-tree driver`,
|
|
209
|
+
` // pulses its own (shorter) reset at init; this re-drive with the`,
|
|
210
|
+
` // verified timing runs from main before the UI starts polling.`,
|
|
164
211
|
`#if DT_NODE_HAS_STATUS(DT_NODELABEL(ft6336u), okay) && DT_NODE_HAS_PROP(DT_NODELABEL(ft6336u), reset_gpios)`,
|
|
165
|
-
` static const struct gpio_dt_spec
|
|
166
|
-
` if (device_is_ready(
|
|
167
|
-
` gpio_pin_configure_dt(&
|
|
212
|
+
` static const struct gpio_dt_spec __tc_touch_en = GPIO_DT_SPEC_GET(DT_NODELABEL(ft6336u), reset_gpios);`,
|
|
213
|
+
` if (device_is_ready(__tc_touch_en.port)) {`,
|
|
214
|
+
` gpio_pin_configure_dt(&__tc_touch_en, GPIO_OUTPUT_ACTIVE); // drive LOW (active-low spec)`,
|
|
168
215
|
` k_msleep(10);`,
|
|
169
|
-
` gpio_pin_set_dt(&
|
|
170
|
-
` k_msleep(
|
|
216
|
+
` gpio_pin_set_dt(&__tc_touch_en, 0); // drive HIGH`,
|
|
217
|
+
` k_msleep(500);`,
|
|
171
218
|
` }`,
|
|
172
219
|
`#endif`,
|
|
173
|
-
` (
|
|
220
|
+
` const struct device* __tc_touch_dev = DEVICE_DT_GET(DT_NODELABEL(ft6336u));`,
|
|
221
|
+
` if (!device_is_ready(__tc_touch_dev)) {`,
|
|
222
|
+
` printk("TC_TOUCH: ft6336u device not ready\\n");`,
|
|
223
|
+
` return;`,
|
|
224
|
+
` }`,
|
|
225
|
+
` // Self-test: dispatch one synthetic release event through the input`,
|
|
226
|
+
` // core. If the listener is registered and dispatch works, the event`,
|
|
227
|
+
` // logger above prints it; rc=-EAGAIN means the input queue is full`,
|
|
228
|
+
` // (input thread wedged). K_NO_WAIT so a dead queue can never block`,
|
|
229
|
+
` // boot.`,
|
|
230
|
+
` int __rc = input_report_key(__tc_touch_dev, INPUT_BTN_TOUCH, 0, true, K_NO_WAIT);`,
|
|
231
|
+
` printk("TC_TOUCH: ft6336u ready, self-test report rc=%d\\n", __rc);`,
|
|
232
|
+
`}`,
|
|
233
|
+
``,
|
|
234
|
+
`// Boot-time bus diagnostic (self-limiting): reads TD_STATUS directly`,
|
|
235
|
+
`// over I2C — the register path the raw adapter proved on this rig —`,
|
|
236
|
+
`// dense (300ms) for the first 5s, sparse (3s) until 60s, then silent.`,
|
|
237
|
+
`// On the demo rig this caught a failing touch module: the controller`,
|
|
238
|
+
`// ACKs for the first ~700ms after every reset, returns 0xFF once, then`,
|
|
239
|
+
`// NAKs permanently — a power/connection fault, independent of firmware`,
|
|
240
|
+
`// (reproduced identically on the committed pre-migration build).`,
|
|
241
|
+
`static const struct i2c_dt_spec __tc_touch_probe = I2C_DT_SPEC_GET(DT_NODELABEL(ft6336u));`,
|
|
242
|
+
`static int32_t __tc_touch_probe_next = 0;`,
|
|
243
|
+
`static void __tc_touch_diag() {`,
|
|
244
|
+
` int32_t __now = static_cast<int32_t>(k_uptime_get_32());`,
|
|
245
|
+
` if (__now >= 60000) return;`,
|
|
246
|
+
` int32_t __gap = (__now < 5000) ? 300 : 3000;`,
|
|
247
|
+
` if (__now < __tc_touch_probe_next) return;`,
|
|
248
|
+
` __tc_touch_probe_next = __now + __gap;`,
|
|
249
|
+
` uint8_t __td = 0U;`,
|
|
250
|
+
` uint8_t __reg = 0x02U;`,
|
|
251
|
+
` int __rc = i2c_write_read_dt(&__tc_touch_probe, &__reg, 1U, &__td, 1U);`,
|
|
252
|
+
` if ((__rc != 0) || (__td != 0U)) {`,
|
|
253
|
+
` printk("TC_TOUCH: diag td_status=0x%02x rc=%d down=%d\\n",`,
|
|
254
|
+
` static_cast<unsigned int>(__td), __rc,`,
|
|
255
|
+
` __tc_touch_down ? 1 : 0);`,
|
|
256
|
+
` }`,
|
|
174
257
|
`}`,
|
|
175
258
|
``,
|
|
176
259
|
`static inline bool touch_isTouched() {`,
|
|
177
|
-
`
|
|
178
|
-
`
|
|
179
|
-
` // Read TD_STATUS (0x02) + P1_XH/XL/YH/YL — 5 bytes in one transaction.`,
|
|
180
|
-
` uint8_t buf[5] = {0, 0, 0, 0, 0};`,
|
|
181
|
-
` if (!__tc_touch_read_block(0x02, buf, 5U)) return false;`,
|
|
182
|
-
` uint8_t count = buf[0] & 0x0F;`,
|
|
183
|
-
` if (count == 0U) return false;`,
|
|
184
|
-
` __tc_touch_cached_x = static_cast<int16_t>((static_cast<uint16_t>(buf[1] & 0x0F) << 8) | buf[2]);`,
|
|
185
|
-
` __tc_touch_cached_y = static_cast<int16_t>((static_cast<uint16_t>(buf[3] & 0x0F) << 8) | buf[4]);`,
|
|
186
|
-
` __tc_touch_cached_z = 255;`,
|
|
187
|
-
` __tc_touch_cached_valid = 1;`,
|
|
188
|
-
` return true;`,
|
|
260
|
+
` __tc_touch_diag();`,
|
|
261
|
+
` return __tc_touch_down;`,
|
|
189
262
|
`}`,
|
|
190
263
|
``,
|
|
191
264
|
`static inline void touch_readRaw(int16_t* x, int16_t* y, int16_t* z) {`,
|
|
192
|
-
` //
|
|
193
|
-
` //
|
|
194
|
-
`
|
|
195
|
-
` (void)touch_isTouched();`,
|
|
196
|
-
` }`,
|
|
265
|
+
` // Latest reported position in controller register units (native panel`,
|
|
266
|
+
` // space); the runtime applies calibration + rotation. z is saturation`,
|
|
267
|
+
` // for capacitive (the driver reports press/release, not pressure).`,
|
|
197
268
|
` if (x) *x = __tc_touch_cached_x;`,
|
|
198
269
|
` if (y) *y = __tc_touch_cached_y;`,
|
|
199
|
-
` if (z) *z =
|
|
200
|
-
` __tc_touch_cached_valid = 0;`,
|
|
270
|
+
` if (z) *z = 255;`,
|
|
201
271
|
`}`,
|
|
202
272
|
].join("\n"),
|
|
203
273
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// E-ink UI adapter (Stage 4) — the refresh-model proof. Same 1bpp format as
|
|
2
|
+
// mono (the parameterized mono adapter: vtiled MONO01 backing store, always-
|
|
3
|
+
// complemented MONO10 pushes — the ssd16xx/uc81xx families accept nothing
|
|
4
|
+
// else); the NEW axis is the refresh model: the runtime's UI_REFRESH_DEFERRED
|
|
5
|
+
// accumulator flushes on change, the adapter rate-limits pushes to the panel's
|
|
6
|
+
// flash-cycle economics (TC_EINK_MIN_REFRESH_MS), and the panel sleeps between
|
|
7
|
+
// flashes (the driver blocks through BUSY inside display_write).
|
|
8
|
+
import type { ZephyrDisplayProfile } from "./profiles.js";
|
|
9
|
+
import { zephyrMonoDisplayAdapter } from "./ui-adapter-mono.js";
|
|
10
|
+
|
|
11
|
+
export function zephyrEinkDisplayAdapter(profile: ZephyrDisplayProfile) {
|
|
12
|
+
return zephyrMonoDisplayAdapter(profile, { eink: true });
|
|
13
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Zephyr gray UI display adapter — Stage 3's gray8 lowering target.
|
|
3
|
+
//
|
|
4
|
+
// The panel accepts PIXEL_FORMAT_L_8 (8-bit luminance; the solomon,ssd1327
|
|
5
|
+
// driver nibble-reduces to its 16 display levels). The adapter keeps a
|
|
6
|
+
// row-major L_8 backing store (one byte per pixel — 4KB at 128x64) and
|
|
7
|
+
// pushes the whole frame with ONE display_write, mirroring the mono
|
|
8
|
+
// adapter's full-frame semantic at gray fidelity. UI_COLOR_T is uint8_t and
|
|
9
|
+
// node values are luminance bytes, so every draw is a store.
|
|
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
|
+
// AGENTS.md rendering guardrails honored: one static framebuffer, no
|
|
15
|
+
// per-frame allocation, one atomic push per frame.
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
import type { DisplayAdapterCode } from "@typecad/cuttlefish/api/shared";
|
|
19
|
+
import type { ZephyrDisplayProfile } from "./profiles.js";
|
|
20
|
+
import { displayFactsLine } from "./profiles.js";
|
|
21
|
+
import { CANVAS_LIFECYCLE_SECTION, TARGET_FORWARDERS_SECTION, profileMarkerLine } from "./ui-adapter-shared.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Build the gray8 UI adapter for a profile. The profile's dtLabel must name
|
|
25
|
+
* a display node bound by an L_8-capable driver (solomon,ssd1327-class —
|
|
26
|
+
* the overlay generates the node; the driver self-builds from it).
|
|
27
|
+
*/
|
|
28
|
+
export function zephyrGrayDisplayAdapter(profile: ZephyrDisplayProfile): DisplayAdapterCode {
|
|
29
|
+
const w = profile.width;
|
|
30
|
+
const h = profile.height;
|
|
31
|
+
const dtLabel = profile.dtLabel;
|
|
32
|
+
|
|
33
|
+
const includes = [
|
|
34
|
+
`// --- Zephyr gray UI display adapter (${profile.driver}, full-frame L_8) ---`,
|
|
35
|
+
profileMarkerLine(profile.driver),
|
|
36
|
+
displayFactsLine(profile),
|
|
37
|
+
`// Gray target: the adapter's ZephyrGrayTarget (a CuttlefishGFX writing an`,
|
|
38
|
+
`// L_8 backing store — one luminance byte per pixel; the driver reduces`,
|
|
39
|
+
`// to the panel's 16 display levels).`,
|
|
40
|
+
`#define CuttlefishDisplayTarget ZephyrGrayTarget`,
|
|
41
|
+
`#include <zephyr/kernel.h>`,
|
|
42
|
+
`#include <zephyr/drivers/display.h>`,
|
|
43
|
+
`#include <zephyr/drivers/gpio.h>`,
|
|
44
|
+
].join("\n");
|
|
45
|
+
|
|
46
|
+
const declaration = [
|
|
47
|
+
`// CUTTLEFISH_DISPLAY_BEGIN`,
|
|
48
|
+
`// The panel device: the overlay's display0 node, bound by an L_8-capable`,
|
|
49
|
+
`// driver. Compile-time constant — DEVICE_DT_GET requires the driver to`,
|
|
50
|
+
`// exist at build time, which the Kconfig layer guarantees.`,
|
|
51
|
+
`static const struct device* __tc_zd_dev = DEVICE_DT_GET(DT_NODELABEL(${dtLabel}));`,
|
|
52
|
+
`static struct display_capabilities __tc_zd_caps;`,
|
|
53
|
+
`// Full-frame backing store, row-major L_8: one luminance byte per pixel`,
|
|
54
|
+
`// (${w}*${h} = ${w * h} bytes).`,
|
|
55
|
+
`static uint8_t __tc_gray_fb[${w} * ${h}];`,
|
|
56
|
+
`// Rig diagnostics: frames pushed since boot (see display_partial_refresh).`,
|
|
57
|
+
`static uint32_t __tc_gray_frames = 0;`,
|
|
58
|
+
`// Gray target clip (w <= 0 ⇒ no clip). Enforced in ZephyrGrayTarget's`,
|
|
59
|
+
`// drawPixel/fillRect so EVERY pixel — including ones emitted inside`,
|
|
60
|
+
`// CuttlefishGFX geometry algorithms — respects it.`,
|
|
61
|
+
`static int16_t __tc_mono_clip_x = 0;`,
|
|
62
|
+
`static int16_t __tc_mono_clip_y = 0;`,
|
|
63
|
+
`static int16_t __tc_mono_clip_w = 0;`,
|
|
64
|
+
`static int16_t __tc_mono_clip_h = 0;`,
|
|
65
|
+
`// CUTTLEFISH_DISPLAY_END`,
|
|
66
|
+
].join("\n");
|
|
67
|
+
|
|
68
|
+
const functions = `
|
|
69
|
+
// ── Gray target ───────────────────────────────────────────────────────────
|
|
70
|
+
// A CuttlefishGFX whose pixels are backing-store bytes. All geometry/text
|
|
71
|
+
// primitives the runtime draws funnel through these two overrides.
|
|
72
|
+
class ZephyrGrayTarget final : public CuttlefishGFX {
|
|
73
|
+
public:
|
|
74
|
+
ZephyrGrayTarget() : CuttlefishGFX(nullptr, nullptr) {}
|
|
75
|
+
int16_t width() const { return ${w}; }
|
|
76
|
+
int16_t height() const { return ${h}; }
|
|
77
|
+
void drawPixel(int16_t x, int16_t y, uint16_t color) {
|
|
78
|
+
if (x < 0 || y < 0 || x >= ${w} || y >= ${h}) return;
|
|
79
|
+
if (__tc_mono_clip_w > 0 &&
|
|
80
|
+
(x < __tc_mono_clip_x || y < __tc_mono_clip_y ||
|
|
81
|
+
x >= __tc_mono_clip_x + __tc_mono_clip_w ||
|
|
82
|
+
y >= __tc_mono_clip_y + __tc_mono_clip_h)) return;
|
|
83
|
+
__tc_gray_fb[static_cast<uint32_t>(y) * ${w}u + static_cast<uint32_t>(x)] =
|
|
84
|
+
static_cast<uint8_t>(color);
|
|
85
|
+
}
|
|
86
|
+
void fillRect(int16_t x, int16_t y, int16_t rw, int16_t rh, uint16_t color) {
|
|
87
|
+
if (rw <= 0 || rh <= 0) return;
|
|
88
|
+
for (int16_t j = 0; j < rh; j++) {
|
|
89
|
+
for (int16_t i = 0; i < rw; i++) {
|
|
90
|
+
drawPixel(static_cast<int16_t>(x + i), static_cast<int16_t>(y + j), color);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
static ZephyrGrayTarget __tc_display;
|
|
96
|
+
|
|
97
|
+
// ── Gray clip (the runtime's full-frame scroll clipping) ──────────────────
|
|
98
|
+
static inline void display_mono_set_clip(int16_t x, int16_t y, int16_t rw, int16_t rh) {
|
|
99
|
+
__tc_mono_clip_x = x;
|
|
100
|
+
__tc_mono_clip_y = y;
|
|
101
|
+
__tc_mono_clip_w = rw;
|
|
102
|
+
__tc_mono_clip_h = rh;
|
|
103
|
+
}
|
|
104
|
+
static inline void display_mono_clear_clip() {
|
|
105
|
+
__tc_mono_clip_w = 0;
|
|
106
|
+
__tc_mono_clip_h = 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ── Frame push ─────────────────────────────────────────────────────────────
|
|
110
|
+
// Full-frame redraw, ALWAYS (Stage 3): the ${w * h}-byte L_8 frame is one
|
|
111
|
+
// display_write. The dirty-rect args are accepted and ignored — at
|
|
112
|
+
// ~50-100ms a frame (I2C fast mode), incremental compositing has nothing
|
|
113
|
+
// to optimize.
|
|
114
|
+
static inline void display_partial_refresh(int16_t x, int16_t y, int16_t rw, int16_t rh) {
|
|
115
|
+
(void)x; (void)y; (void)rw; (void)rh;
|
|
116
|
+
struct display_buffer_descriptor __desc = {};
|
|
117
|
+
__desc.width = ${w}u;
|
|
118
|
+
__desc.height = ${h}u;
|
|
119
|
+
__desc.pitch = ${w}u;
|
|
120
|
+
__desc.buf_size = sizeof(__tc_gray_fb);
|
|
121
|
+
__desc.frame_incomplete = false;
|
|
122
|
+
int __ret = display_write(__tc_zd_dev, 0, 0, &__desc, __tc_gray_fb);
|
|
123
|
+
__tc_gray_frames++;
|
|
124
|
+
if (__ret != 0) {
|
|
125
|
+
printk("TC_DISPLAY: display_write failed: %d\\n", __ret);
|
|
126
|
+
} else if ((__tc_gray_frames & 0x0Fu) == 1u) {
|
|
127
|
+
printk("TC_DISPLAY: gray frame #%u pushed\\n", static_cast<unsigned int>(__tc_gray_frames));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ── display_init (called from setup) ───────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
static inline void display_init() {
|
|
134
|
+
printk("TC_DISPLAY: gray full-frame transport (${dtLabel}, ${w}x${h}, L_8)\\n");
|
|
135
|
+
if (!device_is_ready(__tc_zd_dev)) {
|
|
136
|
+
printk("TC_DISPLAY: device not ready — is the panel driver enabled?\\n");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
display_get_capabilities(__tc_zd_dev, &__tc_zd_caps);
|
|
140
|
+
printk("TC_DISPLAY: panel reports %ux%u fmt=%u screen_info=%u\\n",
|
|
141
|
+
static_cast<unsigned int>(__tc_zd_caps.x_resolution),
|
|
142
|
+
static_cast<unsigned int>(__tc_zd_caps.y_resolution),
|
|
143
|
+
static_cast<unsigned int>(__tc_zd_caps.current_pixel_format),
|
|
144
|
+
static_cast<unsigned int>(__tc_zd_caps.screen_info));
|
|
145
|
+
// L_8 is the driver's native format (it nibble-reduces to the panel's 16
|
|
146
|
+
// levels); request it in case the driver boots in something else.
|
|
147
|
+
if (__tc_zd_caps.current_pixel_format != PIXEL_FORMAT_L_8) {
|
|
148
|
+
if (display_set_pixel_format(__tc_zd_dev, PIXEL_FORMAT_L_8) != 0) {
|
|
149
|
+
printk("TC_DISPLAY: panel refused L_8 — check the driver\\n");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
for (size_t i = 0; i < sizeof(__tc_gray_fb); i++) __tc_gray_fb[i] = 0u;
|
|
153
|
+
(void)display_blanking_off(__tc_zd_dev);
|
|
154
|
+
display_partial_refresh(0, 0, ${w}, ${h});
|
|
155
|
+
printk("TC_DISPLAY: gray init done (L_8 full-frame)\\n");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static inline void display_fillScreen(UI_COLOR_T color) {
|
|
159
|
+
for (size_t i = 0; i < sizeof(__tc_gray_fb); i++) __tc_gray_fb[i] = static_cast<uint8_t>(color);
|
|
160
|
+
}
|
|
161
|
+
static inline CuttlefishDisplayTarget* display_defaultTarget() { return &__tc_display; }
|
|
162
|
+
static inline int16_t display_width() { return ${w}; }
|
|
163
|
+
static inline int16_t display_height() { return ${h}; }
|
|
164
|
+
|
|
165
|
+
// Immediate-push no-ops: all drawing targets the backing store; the frame
|
|
166
|
+
// publishes atomically in display_partial_refresh.
|
|
167
|
+
static inline void display_startWrite() { }
|
|
168
|
+
static inline void display_endWrite() { }
|
|
169
|
+
static inline void display_setAddrWindow(int16_t x, int16_t y, int16_t winW, int16_t winH) {
|
|
170
|
+
(void)x; (void)y; (void)winW; (void)winH;
|
|
171
|
+
}
|
|
172
|
+
static inline void display_writePixels(const UI_COLOR_T* pixels, uint32_t count) {
|
|
173
|
+
(void)pixels; (void)count;
|
|
174
|
+
}
|
|
175
|
+
${CANVAS_LIFECYCLE_SECTION}${TARGET_FORWARDERS_SECTION}`;
|
|
176
|
+
|
|
177
|
+
return { includes, declaration, functions };
|
|
178
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Zephyr mono UI display adapter — Stage 2's 1bpp lowering target.
|
|
3
|
+
//
|
|
4
|
+
// The mono panel IS a backing store: the adapter keeps a full-frame vtiled
|
|
5
|
+
// MONO01 framebuffer (byte = 8 vertical pixels, buf[(y>>3)*W + x], bit
|
|
6
|
+
// 1<<(y&7) — the layout Zephyr's ssd1306-class drivers expect from
|
|
7
|
+
// display_write: pitch == width, y and height multiples of 8). Every UI draw
|
|
8
|
+
// lands in RAM through a CuttlefishGFX subclass; ui_refresh_flush pushes the
|
|
9
|
+
// whole frame with ONE display_write call (full-frame redraw, always — a
|
|
10
|
+
// 128×64 frame is 1KB, ~25ms over I²C; incremental compositing has nothing
|
|
11
|
+
// to optimize).
|
|
12
|
+
//
|
|
13
|
+
// The runtime's scroll-canvas/band machinery is bypassed under
|
|
14
|
+
// UI_FULL_FRAME_REDRAW (see the engine's runtime header); scroll clipping
|
|
15
|
+
// rides this adapter's mono clip rect (display_mono_set_clip), which every
|
|
16
|
+
// draw primitive enforces — including pixels emitted inside the CuttlefishGFX
|
|
17
|
+
// geometry algorithms, which is why the clip lives here and not in the shim.
|
|
18
|
+
//
|
|
19
|
+
// EMIT BOUNDARY: emitted bytes land in user firmware. Covered by the TypeCAD
|
|
20
|
+
// Runtime Exception (RUNTIME_EXCEPTION.md at the repo root).
|
|
21
|
+
//
|
|
22
|
+
// AGENTS.md rendering guardrails honored: one static framebuffer, no per-frame
|
|
23
|
+
// allocation, one atomic push per frame.
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
import type { DisplayAdapterCode } from "@typecad/cuttlefish/api/shared";
|
|
27
|
+
import type { ZephyrDisplayProfile } from "./profiles.js";
|
|
28
|
+
import { displayFactsLine } from "./profiles.js";
|
|
29
|
+
import { CANVAS_LIFECYCLE_SECTION, TARGET_FORWARDERS_SECTION, profileMarkerLine } from "./ui-adapter-shared.js";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Build the mono (1bpp) UI adapter for a profile. The profile's dtLabel must
|
|
33
|
+
* name a display node an in-tree mono driver binds (ssd1306-class over I²C —
|
|
34
|
+
* the overlay generates the node; the driver self-builds from it).
|
|
35
|
+
* `opts.eink` retunes it for the e-ink refresh model (Stage 4): skip the
|
|
36
|
+
* MONO01 negotiation (ssd16xx/uc81xx are MONO10-only) and throttle pushes
|
|
37
|
+
* to the panel's flash-cycle economics.
|
|
38
|
+
*/
|
|
39
|
+
export function zephyrMonoDisplayAdapter(profile: ZephyrDisplayProfile, opts?: { eink?: boolean }): DisplayAdapterCode {
|
|
40
|
+
const eink = opts?.eink === true;
|
|
41
|
+
const w = profile.width;
|
|
42
|
+
const h = profile.height;
|
|
43
|
+
const dtLabel = profile.dtLabel;
|
|
44
|
+
const nativeW = profile.nativeWidth ?? w;
|
|
45
|
+
const nativeH = profile.nativeHeight ?? h;
|
|
46
|
+
|
|
47
|
+
const includes = [
|
|
48
|
+
`// --- Zephyr mono UI display adapter (${profile.driver}, full-frame 1bpp) ---`,
|
|
49
|
+
profileMarkerLine(profile.driver),
|
|
50
|
+
displayFactsLine(profile),
|
|
51
|
+
`// Mono target: the adapter's ZephyrMonoTarget (a CuttlefishGFX writing a`,
|
|
52
|
+
`// vtiled MONO01 backing store), NOT the rgb565 panel-ops path.`,
|
|
53
|
+
`#define CuttlefishDisplayTarget ZephyrMonoTarget`,
|
|
54
|
+
`#include <zephyr/kernel.h>`,
|
|
55
|
+
`#include <zephyr/drivers/display.h>`,
|
|
56
|
+
`#include <zephyr/drivers/gpio.h>`,
|
|
57
|
+
].join("\n");
|
|
58
|
+
|
|
59
|
+
const declaration = [
|
|
60
|
+
`// CUTTLEFISH_DISPLAY_BEGIN`,
|
|
61
|
+
`// The panel device: the overlay's display0 node, bound by an in-tree mono`,
|
|
62
|
+
`// driver (ssd1306-class). Compile-time constant — DEVICE_DT_GET requires`,
|
|
63
|
+
`// the driver to exist at build time, which the Kconfig layer guarantees.`,
|
|
64
|
+
`static const struct device* __tc_zd_dev = DEVICE_DT_GET(DT_NODELABEL(${dtLabel}));`,
|
|
65
|
+
`static struct display_capabilities __tc_zd_caps;`,
|
|
66
|
+
`// Full-frame backing store, vtiled MONO01: byte = 8 vertical pixels,`,
|
|
67
|
+
`// buf[(y>>3)*${w} + x], bit = 1<<(y&7). One bit per pixel ⇒ ${w}*${h}/8 = ${(w * h) / 8} bytes.`,
|
|
68
|
+
`static uint8_t __tc_mono_fb[(${w} * ${h} + 7) / 8];`,
|
|
69
|
+
`// Push scratch for panels that insist on MONO10 (1=black): the frame is`,
|
|
70
|
+
`// complemented here, never in the backing store itself.`,
|
|
71
|
+
`static uint8_t __tc_mono_inv[(${w} * ${h} + 7) / 8];`,
|
|
72
|
+
`// Rig diagnostics: frames pushed since boot (see display_partial_refresh).`,
|
|
73
|
+
`static uint32_t __tc_mono_frames = 0;`,
|
|
74
|
+
`// E-ink flush floor: one flash per push at most this often (the drivers
|
|
75
|
+
// block through BUSY inside display_write — an unthrottled binding tick
|
|
76
|
+
// would stall the app loop for seconds).
|
|
77
|
+
#define TC_EINK_MIN_REFRESH_MS 2000u
|
|
78
|
+
// Set when the panel insists on MONO10 (1=black): pushes invert the frame.`,
|
|
79
|
+
`static bool __tc_mono_invert = false;`,
|
|
80
|
+
`// Scroll-viewport clip in display coords (w <= 0 ⇒ no clip). Enforced in`,
|
|
81
|
+
`// ZephyrMonoTarget's drawPixel/fillRect so EVERY pixel — including ones`,
|
|
82
|
+
`// emitted inside CuttlefishGFX geometry algorithms — respects it.`,
|
|
83
|
+
`static int16_t __tc_mono_clip_x = 0;`,
|
|
84
|
+
`static int16_t __tc_mono_clip_y = 0;`,
|
|
85
|
+
`static int16_t __tc_mono_clip_w = 0;`,
|
|
86
|
+
`static int16_t __tc_mono_clip_h = 0;`,
|
|
87
|
+
`// CUTTLEFISH_DISPLAY_END`,
|
|
88
|
+
].join("\n");
|
|
89
|
+
|
|
90
|
+
const functions = `
|
|
91
|
+
// ── Mono target ───────────────────────────────────────────────────────────
|
|
92
|
+
// A CuttlefishGFX whose pixels are backing-store bits. All geometry/text
|
|
93
|
+
// primitives the runtime draws funnel through these two overrides.
|
|
94
|
+
class ZephyrMonoTarget final : public CuttlefishGFX {
|
|
95
|
+
public:
|
|
96
|
+
ZephyrMonoTarget() : CuttlefishGFX(nullptr, nullptr) {}
|
|
97
|
+
int16_t width() const { return ${w}; }
|
|
98
|
+
int16_t height() const { return ${h}; }
|
|
99
|
+
void drawPixel(int16_t x, int16_t y, uint16_t color) {
|
|
100
|
+
if (x < 0 || y < 0 || x >= ${w} || y >= ${h}) return;
|
|
101
|
+
if (__tc_mono_clip_w > 0 &&
|
|
102
|
+
(x < __tc_mono_clip_x || y < __tc_mono_clip_y ||
|
|
103
|
+
x >= __tc_mono_clip_x + __tc_mono_clip_w ||
|
|
104
|
+
y >= __tc_mono_clip_y + __tc_mono_clip_h)) return;
|
|
105
|
+
uint8_t mask = static_cast<uint8_t>(1u << (y & 7));
|
|
106
|
+
uint8_t* b = &__tc_mono_fb[(static_cast<uint32_t>(y) >> 3) * ${w}u + static_cast<uint32_t>(x)];
|
|
107
|
+
if (color) *b = static_cast<uint8_t>(*b | mask);
|
|
108
|
+
else *b = static_cast<uint8_t>(*b & static_cast<uint8_t>(~mask));
|
|
109
|
+
}
|
|
110
|
+
void fillRect(int16_t x, int16_t y, int16_t rw, int16_t rh, uint16_t color) {
|
|
111
|
+
if (rw <= 0 || rh <= 0) return;
|
|
112
|
+
for (int16_t j = 0; j < rh; j++) {
|
|
113
|
+
for (int16_t i = 0; i < rw; i++) {
|
|
114
|
+
drawPixel(static_cast<int16_t>(x + i), static_cast<int16_t>(y + j), color);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
static ZephyrMonoTarget __tc_display;
|
|
120
|
+
|
|
121
|
+
// ── Mono clip (the runtime's full-frame scroll clipping) ──────────────────
|
|
122
|
+
static inline void display_mono_set_clip(int16_t x, int16_t y, int16_t rw, int16_t rh) {
|
|
123
|
+
__tc_mono_clip_x = x;
|
|
124
|
+
__tc_mono_clip_y = y;
|
|
125
|
+
__tc_mono_clip_w = rw;
|
|
126
|
+
__tc_mono_clip_h = rh;
|
|
127
|
+
}
|
|
128
|
+
static inline void display_mono_clear_clip() {
|
|
129
|
+
__tc_mono_clip_w = 0;
|
|
130
|
+
__tc_mono_clip_h = 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ── Frame push ─────────────────────────────────────────────────────────────
|
|
134
|
+
// Full-frame redraw, ALWAYS (Stage 2): the 1KB frame is one display_write.
|
|
135
|
+
// The ssd1306-class drivers require pitch == width and (y, height) multiples
|
|
136
|
+
// of 8 — the full frame satisfies both by construction. The dirty-rect args
|
|
137
|
+
// are accepted and ignored: at ~25ms a frame, partial compositing has nothing
|
|
138
|
+
// to optimize.
|
|
139
|
+
static inline void display_partial_refresh(int16_t x, int16_t y, int16_t rw, int16_t rh) {
|
|
140
|
+
(void)x; (void)y; (void)rw; (void)rh;
|
|
141
|
+
${eink ? ` // E-ink deferred flush: the flash cycle blocks inside display_write for
|
|
142
|
+
// 1-4s — rate-limit pushes, keep the newest frame pending in between.
|
|
143
|
+
static uint32_t last_push_ms = 0;
|
|
144
|
+
static bool pending = false;
|
|
145
|
+
const uint32_t now_ms = k_uptime_get_32();
|
|
146
|
+
if (pending && (now_ms - last_push_ms) < TC_EINK_MIN_REFRESH_MS) return;
|
|
147
|
+
pending = true;
|
|
148
|
+
last_push_ms = now_ms;` : ""}
|
|
149
|
+
struct display_buffer_descriptor __desc = {};
|
|
150
|
+
__desc.width = ${w}u;
|
|
151
|
+
__desc.height = ${h}u;
|
|
152
|
+
__desc.pitch = ${w}u;
|
|
153
|
+
__desc.buf_size = sizeof(__tc_mono_fb);
|
|
154
|
+
__desc.frame_incomplete = false;
|
|
155
|
+
const uint8_t* src = __tc_mono_fb;
|
|
156
|
+
if (__tc_mono_invert) {
|
|
157
|
+
// Panel insists on MONO10 (1=black): push the complement of the frame.
|
|
158
|
+
for (size_t i = 0; i < sizeof(__tc_mono_fb); i++) {
|
|
159
|
+
__tc_mono_inv[i] = static_cast<uint8_t>(~__tc_mono_fb[i]);
|
|
160
|
+
}
|
|
161
|
+
src = __tc_mono_inv;
|
|
162
|
+
}
|
|
163
|
+
int __ret = display_write(__tc_zd_dev, 0, 0, &__desc, src);
|
|
164
|
+
// Rig diagnostics: the first frame + every 64th reports liveness, and any
|
|
165
|
+
// write failure prints once-per-second-class errno (EIO = I2C NACK —
|
|
166
|
+
// address/wiring; ENODEV = device never initialized). A blank panel with
|
|
167
|
+
// these lines green means the failure is panel-side (power/quirks).
|
|
168
|
+
__tc_mono_frames++;
|
|
169
|
+
if (__ret != 0) {
|
|
170
|
+
printk("TC_DISPLAY: display_write failed: %d\\n", __ret);
|
|
171
|
+
} else if ((__tc_mono_frames & 0x3Fu) == 1u) {
|
|
172
|
+
printk("TC_DISPLAY: mono frame #%u pushed\\n", static_cast<unsigned int>(__tc_mono_frames));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ── display_init (called from setup) ───────────────────────────────────────
|
|
177
|
+
|
|
178
|
+
static inline void display_init() {
|
|
179
|
+
printk("TC_DISPLAY: ${eink ? 'e-ink deferred' : 'mono full-frame'} transport (${dtLabel}, ${w}x${h})\\n");
|
|
180
|
+
if (!device_is_ready(__tc_zd_dev)) {
|
|
181
|
+
printk("TC_DISPLAY: device not ready — is the panel driver enabled?\\n");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
display_get_capabilities(__tc_zd_dev, &__tc_zd_caps);
|
|
185
|
+
// Rig diagnostics: what the driver reports — geometry/format mismatches
|
|
186
|
+
// print here before anything reaches the panel.
|
|
187
|
+
printk("TC_DISPLAY: panel reports %ux%u fmt=%u screen_info=%u\\n",
|
|
188
|
+
static_cast<unsigned int>(__tc_zd_caps.x_resolution),
|
|
189
|
+
static_cast<unsigned int>(__tc_zd_caps.y_resolution),
|
|
190
|
+
static_cast<unsigned int>(__tc_zd_caps.current_pixel_format),
|
|
191
|
+
static_cast<unsigned int>(__tc_zd_caps.screen_info));
|
|
192
|
+
// MONO01 (0=black, 1=white) matches our packing. A MONO10 panel gets asked
|
|
193
|
+
// to switch once; if it refuses, frames push bit-inverted (still correct).
|
|
194
|
+
if (${!eink} && __tc_zd_caps.current_pixel_format == PIXEL_FORMAT_MONO10) {
|
|
195
|
+
if (display_set_pixel_format(__tc_zd_dev, PIXEL_FORMAT_MONO01) == 0) {
|
|
196
|
+
display_get_capabilities(__tc_zd_dev, &__tc_zd_caps);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (__tc_zd_caps.current_pixel_format == PIXEL_FORMAT_MONO10) {
|
|
200
|
+
__tc_mono_invert = true;
|
|
201
|
+
} else if (${!eink} && __tc_zd_caps.current_pixel_format != PIXEL_FORMAT_MONO01) {
|
|
202
|
+
printk("TC_DISPLAY: unexpected pixel format %u (expected MONO01) — rendering best-effort\\n",
|
|
203
|
+
static_cast<unsigned int>(__tc_zd_caps.current_pixel_format));
|
|
204
|
+
}
|
|
205
|
+
if (__tc_zd_caps.x_resolution != static_cast<uint16_t>(${nativeW})
|
|
206
|
+
|| __tc_zd_caps.y_resolution != static_cast<uint16_t>(${nativeH})) {
|
|
207
|
+
printk("TC_DISPLAY: panel reports %ux%u, DT node carries ${nativeW}x${nativeH} — check the display node geometry\\n",
|
|
208
|
+
static_cast<unsigned int>(__tc_zd_caps.x_resolution),
|
|
209
|
+
static_cast<unsigned int>(__tc_zd_caps.y_resolution));
|
|
210
|
+
}
|
|
211
|
+
for (size_t i = 0; i < sizeof(__tc_mono_fb); i++) __tc_mono_fb[i] = 0u;
|
|
212
|
+
(void)display_blanking_off(__tc_zd_dev);
|
|
213
|
+
display_partial_refresh(0, 0, ${w}, ${h});
|
|
214
|
+
printk("TC_DISPLAY: ${eink ? 'e-ink init done (1bpp deferred, min 2s/flash)' : 'mono init done (1bpp full-frame)'}\\n");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static inline void display_fillScreen(UI_COLOR_T color) {
|
|
218
|
+
const uint8_t fill = color ? 0xFFu : 0x00u;
|
|
219
|
+
for (size_t i = 0; i < sizeof(__tc_mono_fb); i++) __tc_mono_fb[i] = fill;
|
|
220
|
+
}
|
|
221
|
+
static inline CuttlefishDisplayTarget* display_defaultTarget() { return &__tc_display; }
|
|
222
|
+
static inline int16_t display_width() { return ${w}; }
|
|
223
|
+
static inline int16_t display_height() { return ${h}; }
|
|
224
|
+
|
|
225
|
+
// Immediate-push no-ops: all drawing targets the backing store; the frame
|
|
226
|
+
// publishes atomically in display_partial_refresh.
|
|
227
|
+
static inline void display_startWrite() { }
|
|
228
|
+
static inline void display_endWrite() { }
|
|
229
|
+
static inline void display_setAddrWindow(int16_t x, int16_t y, int16_t winW, int16_t winH) {
|
|
230
|
+
(void)x; (void)y; (void)winW; (void)winH;
|
|
231
|
+
}
|
|
232
|
+
static inline void display_writePixels(const UI_COLOR_T* pixels, uint32_t count) {
|
|
233
|
+
(void)pixels; (void)count;
|
|
234
|
+
}
|
|
235
|
+
${CANVAS_LIFECYCLE_SECTION}${TARGET_FORWARDERS_SECTION}`;
|
|
236
|
+
|
|
237
|
+
return { includes, declaration, functions };
|
|
238
|
+
}
|