@typecad/framework-zephyr 1.0.0-alpha.18 → 1.0.0-alpha.20
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/dist/audit.d.ts +111 -0
- package/dist/audit.js +416 -0
- package/dist/boardgen.js +63 -5
- package/dist/chips/resolve.js +20 -0
- package/dist/chips/types.d.ts +21 -0
- 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 +118 -48
- 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 +53 -101
- package/dist/dt-config/kconfig.d.ts +62 -1
- package/dist/dt-config/kconfig.js +123 -26
- package/dist/dt-config/overlay.d.ts +13 -0
- package/dist/dt-config/overlay.js +431 -16
- package/dist/framework.manifest.d.ts +9 -3
- package/dist/framework.manifest.js +123 -10
- package/dist/index.d.ts +2 -0
- package/dist/index.js +9 -1
- package/dist/licenses.js +5 -84
- 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/hid.d.ts +27 -0
- package/dist/lowering/hid.js +244 -0
- package/dist/lowering/i2c.d.ts +8 -0
- package/dist/lowering/i2c.js +140 -0
- 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/matrix.d.ts +15 -0
- package/dist/lowering/matrix.js +63 -0
- package/dist/lowering/power.d.ts +10 -0
- package/dist/lowering/power.js +35 -0
- 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 +6 -3
- package/dist/sbom.d.ts +181 -0
- package/dist/sbom.js +901 -0
- package/dist/strategy.d.ts +60 -2
- package/dist/strategy.js +485 -25
- package/dist/toolchain/index.d.ts +12 -1
- package/dist/toolchain/index.js +115 -27
- package/dist/toolchain/scaffold.d.ts +4 -1
- package/dist/toolchain/scaffold.js +67 -3
- package/dist/west-inventory.d.ts +25 -0
- package/dist/west-inventory.js +97 -0
- package/package.json +6 -6
- package/src/audit.ts +529 -0
- package/src/boardgen.ts +54 -5
- package/src/chips/resolve.ts +21 -0
- package/src/chips/types.ts +576 -567
- 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 +274 -204
- 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 +51 -100
- package/src/dt-config/kconfig.ts +647 -511
- package/src/dt-config/overlay.ts +433 -16
- package/src/framework.manifest.ts +131 -10
- package/src/index.ts +11 -1
- package/src/licenses.ts +5 -84
- package/src/lowering/can.ts +140 -0
- package/src/lowering/clock.ts +91 -0
- package/src/lowering/hid.ts +261 -0
- package/src/lowering/i2c.ts +146 -0
- package/src/lowering/i2s.ts +143 -0
- package/src/lowering/index.ts +18 -1
- package/src/lowering/matrix.ts +70 -0
- 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 +224 -221
- package/src/sbom.ts +1117 -0
- package/src/strategy.ts +440 -25
- package/src/toolchain/index.ts +117 -28
- package/src/toolchain/scaffold.ts +62 -3
- package/src/west-inventory.ts +102 -0
|
@@ -10,8 +10,74 @@
|
|
|
10
10
|
// that brings external capabilities into a build. (Arduino does it by parsing
|
|
11
11
|
// library headers into .d.ts; Zephyr does it by enabling DT nodes + Kconfig.)
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
|
-
import {
|
|
13
|
+
import { controllerNodelabelForPin, controllerRawPinForPin } from '../chips/controllers.js';
|
|
14
|
+
import { PANEL_CONTROLLER_DEFAULTS, panelControllerFor, transportFor, isDtCompatible } from '../display/profiles.js';
|
|
15
|
+
import { readDisplayBinding } from '../display/bindings.js';
|
|
16
|
+
import { isEinkDisplay } from '../display/profiles.js';
|
|
17
|
+
/** Standard values for the mono-OLED family's default-free required props
|
|
18
|
+
* (segment/page/display offsets, multiplex ratio, precharge period) — the
|
|
19
|
+
* values upstream board overlays ship; tune per panel from here. */
|
|
20
|
+
function monoPropFallback(prop, info, nativeHeight) {
|
|
21
|
+
if (prop === 'width' || prop === 'height' || prop === 'reg' || prop === 'compatible')
|
|
22
|
+
return undefined;
|
|
23
|
+
const def = info?.default;
|
|
24
|
+
if (def?.kind === 'int')
|
|
25
|
+
return `${prop} = <${def.value}>`;
|
|
26
|
+
if (prop === 'multiplex-ratio')
|
|
27
|
+
return `multiplex-ratio = <${nativeHeight - 1}>`;
|
|
28
|
+
if (prop === 'prechargep')
|
|
29
|
+
return 'prechargep = <0x22>';
|
|
30
|
+
if (prop === 'segment-offset' || prop === 'page-offset' || prop === 'display-offset')
|
|
31
|
+
return `${prop} = <0>`;
|
|
32
|
+
// SSD1327-class (Stage 3 gray): required by solomon,ssd1327_5-common.yaml
|
|
33
|
+
// with no binding default. Panel-tunable — these are the datasheet/common-
|
|
34
|
+
// module starting points (scanline artifacts: raise oscillator-freq toward
|
|
35
|
+
// 0x70; striping: add 0x40 to remap-value per the binding's bit table).
|
|
36
|
+
if (prop === 'oscillator-freq')
|
|
37
|
+
return 'oscillator-freq = <0x00>';
|
|
38
|
+
if (prop === 'start-line')
|
|
39
|
+
return 'start-line = <0>';
|
|
40
|
+
if (prop === 'remap-value')
|
|
41
|
+
return 'remap-value = <0x51>';
|
|
42
|
+
if (prop === 'phase-length')
|
|
43
|
+
return 'phase-length = <0x1f>';
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/** Format one binding-required property with its harvested default. Binding
|
|
47
|
+
* props that are deliberately default-free ("panel specific" — e.g. the
|
|
48
|
+
* sitronix gamma arrays) fall back to the rig-validated tuning the curated
|
|
49
|
+
* profiles ship, so the generated node is always DT-valid. */
|
|
50
|
+
function emitBindingProp(lines, prop, info) {
|
|
51
|
+
const def = info?.default;
|
|
52
|
+
if (def?.kind === 'bytes' && def.value.length > 0) {
|
|
53
|
+
lines.push(` ${prop} = [${def.value.map((b) => b.toString(16).padStart(2, '0')).join(' ')}];`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (def?.kind === 'bool' && def.value) {
|
|
57
|
+
lines.push(` ${prop};`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (def?.kind === 'string') {
|
|
61
|
+
lines.push(` ${prop} = "${def.value}";`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (info?.type === 'uint8-array') {
|
|
65
|
+
// No binding default (panel-specific): emit the rig-validated gamma
|
|
66
|
+
// tuning the curated st7796 profile carries. Tune per panel from here.
|
|
67
|
+
lines.push(` ${prop} = [f0 09 0b 06 04 2e 46 46 39 13 15 12 15 12];`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const v = def?.kind === 'int' ? def.value : 0;
|
|
71
|
+
lines.push(` ${prop} = <${v}>;`);
|
|
72
|
+
}
|
|
14
73
|
import { SENSOR_PART_INFO } from '@typecad/hal';
|
|
74
|
+
/** 1-Wire family codes (the high byte of the 64-bit ROM ID) for the parts
|
|
75
|
+
* the catalog carries on the w1 bus — vendor silicon data, like the ESP32
|
|
76
|
+
* DAC pin table. Unknown compatibles default to the DS18B20's 0x28. */
|
|
77
|
+
const W1_FAMILY_CODES = {
|
|
78
|
+
'maxim,ds18b20': 0x28,
|
|
79
|
+
'maxim,ds18s20': 0x10,
|
|
80
|
+
};
|
|
15
81
|
/** Display panel CS default — shared by the display block and the SPI-sensor
|
|
16
82
|
* cs-gpios merge so both sites write the same entry. */
|
|
17
83
|
const DEFAULT_DISPLAY_CS = 5;
|
|
@@ -128,6 +194,36 @@ export function generateOverlay(chip, usage, display, wiring, touch, diagnostics
|
|
|
128
194
|
lines.push('};');
|
|
129
195
|
lines.push('');
|
|
130
196
|
}
|
|
197
|
+
// One w1-gpio master + sensor child per constructed 1-Wire sensor. The
|
|
198
|
+
// master bit-bangs the data pin (open-drain, internal pull-up enabled —
|
|
199
|
+
// the binding recommends an external 4.7 kΩ, the internal one is weak);
|
|
200
|
+
// the child's family-code comes from the vendor table below (part of the
|
|
201
|
+
// 64-bit ROM ID), resolution from the construction opts. The nodelabels
|
|
202
|
+
// match lowering/sensor.ts sensorNames — the tc-pwm discipline.
|
|
203
|
+
for (const sp of sensorParts.filter((s) => s.busKind === 'w1')) {
|
|
204
|
+
const info = SENSOR_PART_INFO[sp.part.replace(/^SENSOR\./, '')];
|
|
205
|
+
const family = W1_FAMILY_CODES[info?.compatible ?? ''] ?? 0x28;
|
|
206
|
+
if (!info)
|
|
207
|
+
continue; // the lowering already threw on unknown parts
|
|
208
|
+
const pinCtrl = controllerNodelabelForPin(chip, sp.port);
|
|
209
|
+
const pinBit = controllerRawPinForPin(chip, sp.port);
|
|
210
|
+
const nodeName = info.compatible.split(',')[1] ?? sp.part;
|
|
211
|
+
const stem = `${sp.part.replace(/^SENSOR\./, '')}_w1_p${sp.port}`;
|
|
212
|
+
lines.push('/ {');
|
|
213
|
+
lines.push(` tc_w1_p${sp.port}: tc-w1-p${sp.port} {`);
|
|
214
|
+
lines.push(' compatible = "zephyr,w1-gpio";');
|
|
215
|
+
lines.push(` gpios = <&${pinCtrl} ${pinBit} (GPIO_OPEN_DRAIN | GPIO_PULL_UP)>;`);
|
|
216
|
+
lines.push(' status = "okay";');
|
|
217
|
+
lines.push(` tc_${stem}: ${nodeName} {`);
|
|
218
|
+
lines.push(` compatible = "${info.compatible}";`);
|
|
219
|
+
lines.push(` family-code = <0x${family.toString(16)}>;`);
|
|
220
|
+
lines.push(` resolution = <${sp.resolution}>;`);
|
|
221
|
+
lines.push(' status = "okay";');
|
|
222
|
+
lines.push(' };');
|
|
223
|
+
lines.push(' };');
|
|
224
|
+
lines.push('};');
|
|
225
|
+
lines.push('');
|
|
226
|
+
}
|
|
131
227
|
if (usage.usesSpi && chip.spi) {
|
|
132
228
|
for (const [i, c] of chip.spi.controllers.entries()) {
|
|
133
229
|
if (usage.spiUsedInstances && !usage.spiUsedInstances.includes(i))
|
|
@@ -226,6 +322,178 @@ export function generateOverlay(chip, usage, display, wiring, touch, diagnostics
|
|
|
226
322
|
}
|
|
227
323
|
}
|
|
228
324
|
}
|
|
325
|
+
// LED strips: one ws2812-spi child per driven SPI controller. The frame
|
|
326
|
+
// tuning (6.4 MHz, one=0xf0 / zero=0xc0 — 625 ns bit halves) is the
|
|
327
|
+
// Zephyr led_strip sample's canonical SPI encoding; the color-mapping
|
|
328
|
+
// matches the WS2812's native GRB order (the driver reorders). The
|
|
329
|
+
// controller is enabled here too — a strip-only program emits no spi_*
|
|
330
|
+
// calls, so the bus enable cannot ride the generic SPI usage path.
|
|
331
|
+
// `line-idle-low` keeps MOSI low between frames, the WS2812 reset level.
|
|
332
|
+
if (usage.usesStrip && usage.strips && usage.strips.length > 0) {
|
|
333
|
+
lines.splice(2, 0, '#include <zephyr/dt-bindings/led/led.h>', '');
|
|
334
|
+
for (const s of usage.strips) {
|
|
335
|
+
const ctrl = chip.spi?.controllers[s.index];
|
|
336
|
+
if (!ctrl)
|
|
337
|
+
continue;
|
|
338
|
+
lines.push(`&${ctrl.nodeLabel} {`);
|
|
339
|
+
lines.push(' status = "okay";');
|
|
340
|
+
lines.push(' line-idle-low;');
|
|
341
|
+
lines.push(` tc_strip${s.index}: ws2812@0 {`);
|
|
342
|
+
lines.push(' compatible = "worldsemi,ws2812-spi";');
|
|
343
|
+
lines.push(' reg = <0>;');
|
|
344
|
+
lines.push(' spi-max-frequency = <6400000>;');
|
|
345
|
+
lines.push(` chain-length = <${s.count}>;`);
|
|
346
|
+
lines.push(' spi-cpha;');
|
|
347
|
+
lines.push(' spi-one-frame = <0xf0>;');
|
|
348
|
+
lines.push(' spi-zero-frame = <0xc0>;');
|
|
349
|
+
lines.push(' color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;');
|
|
350
|
+
lines.push(' };');
|
|
351
|
+
lines.push('};');
|
|
352
|
+
lines.push('');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// I2S: enable the board's own i2s@ controllers — their pinctrl groups
|
|
356
|
+
// are board-authored (the devkitC wires i2s0_default/i2s1_default), so
|
|
357
|
+
// status is the only synthesis needed. The GDMA the ESP32 I2S driver
|
|
358
|
+
// DMA-runs through also ships disabled — enable it alongside.
|
|
359
|
+
// Full-duplex: the RX side's I_BCK/I_WS inputs must be routed in the
|
|
360
|
+
// GPIO matrix to the same pads the TX outputs drive (input-enable on
|
|
361
|
+
// the TX clock pads — the same-pad GPIO matrix trick the CAN loopback
|
|
362
|
+
// uses; the devkitC's i2s0 clock pads are WS=36, BCK=37).
|
|
363
|
+
if (usage.usesI2s && chip.i2s) {
|
|
364
|
+
lines.push('&dma {');
|
|
365
|
+
lines.push(' status = "okay";');
|
|
366
|
+
lines.push('};');
|
|
367
|
+
lines.push('');
|
|
368
|
+
for (const c of chip.i2s.controllers) {
|
|
369
|
+
const n = c.nodeLabel.replace(/[^0-9]/g, '') || '0';
|
|
370
|
+
lines.push(`&${c.nodeLabel} {`);
|
|
371
|
+
lines.push(' status = "okay";');
|
|
372
|
+
lines.push('};');
|
|
373
|
+
lines.push('');
|
|
374
|
+
lines.push('&pinctrl {');
|
|
375
|
+
lines.push(' tc_i2s_clock_loop: tc-i2s-clock-loop {');
|
|
376
|
+
lines.push(' group1 {');
|
|
377
|
+
lines.push(` pinmux = <I2S${n}_I_BCK_GPIO37>,`);
|
|
378
|
+
lines.push(` <I2S${n}_I_WS_GPIO36>;`);
|
|
379
|
+
lines.push(' };');
|
|
380
|
+
lines.push(' };');
|
|
381
|
+
lines.push('};');
|
|
382
|
+
lines.push(`&${c.nodeLabel} {`);
|
|
383
|
+
lines.push(` pinctrl-0 = <&${c.nodeLabel}_default>, <&tc_i2s_clock_loop>;`);
|
|
384
|
+
lines.push(' pinctrl-names = "default";');
|
|
385
|
+
lines.push('};');
|
|
386
|
+
lines.push('');
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// CAN: enable the board's own can@ controller (the harvested node —
|
|
390
|
+
// boards that ship pinctrl groups keep them; the bitrate is the begin()
|
|
391
|
+
// default, overridden at runtime by can_set_bitrate). Classic CAN only.
|
|
392
|
+
// LOOPBACK: the SJA1000 self-test transmits on the TX pad and receives
|
|
393
|
+
// on the RX pad — with no transceiver the overlay routes BOTH TWAI
|
|
394
|
+
// functions onto the TX pad (the Zephyr test suite's own
|
|
395
|
+
// twai-enable.overlay shape: output-enable on the RX mux, input-enable
|
|
396
|
+
// on the TX mux, one shared pad).
|
|
397
|
+
if (usage.usesCan && chip.can) {
|
|
398
|
+
for (const c of chip.can.controllers) {
|
|
399
|
+
lines.push(`&${c.nodeLabel} {`);
|
|
400
|
+
lines.push(' status = "okay";');
|
|
401
|
+
lines.push(' bitrate = <500000>;');
|
|
402
|
+
lines.push('};');
|
|
403
|
+
lines.push('');
|
|
404
|
+
if (usage.canLoopback && c.txPad !== undefined) {
|
|
405
|
+
lines.push('&pinctrl {');
|
|
406
|
+
lines.push(' tc_can_loopback: tc-can-loopback {');
|
|
407
|
+
lines.push(' group1 {');
|
|
408
|
+
lines.push(` pinmux = <TWAI_RX_GPIO${c.txPad}>;`);
|
|
409
|
+
lines.push(' output-enable;');
|
|
410
|
+
lines.push(' };');
|
|
411
|
+
lines.push(' group2 {');
|
|
412
|
+
lines.push(` pinmux = <TWAI_TX_GPIO${c.txPad}>;`);
|
|
413
|
+
lines.push(' input-enable;');
|
|
414
|
+
lines.push(' };');
|
|
415
|
+
lines.push(' };');
|
|
416
|
+
lines.push('};');
|
|
417
|
+
lines.push(`&${c.nodeLabel} { pinctrl-0 = <&tc_can_loopback>; pinctrl-names = "default"; };`);
|
|
418
|
+
lines.push('');
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
// Wall-clock shim: a zephyr,rtc-counter child on the board's first free
|
|
423
|
+
// counter node + the `rtc` alias (Zephyr's own discovery convention —
|
|
424
|
+
// the api tests filter on dt_alias_exists("rtc")). The shim is a CHILD:
|
|
425
|
+
// the counter driver keeps the parent node, so Counter and Clock
|
|
426
|
+
// coexist. V1 always synthesizes the shim (uniform semantics, no driver
|
|
427
|
+
// conflicts); preferring a board's own hardware-calendar alias — and the
|
|
428
|
+
// backup-domain persistence it buys — is the follow-up.
|
|
429
|
+
if (usage.usesClock && usage.clockShimCounter) {
|
|
430
|
+
const c = usage.clockShimCounter;
|
|
431
|
+
if (c.parent) {
|
|
432
|
+
// Child-form counters (ESP32 timerN children): the shim's parent
|
|
433
|
+
// must be the counter DEVICE, so it nests INSIDE the counter child —
|
|
434
|
+
// DT_INST_PARENT in the shim driver resolves to the counter, not the
|
|
435
|
+
// timer (which carries no device of its own).
|
|
436
|
+
lines.push(`&${c.parent} {`);
|
|
437
|
+
lines.push(' status = "okay";');
|
|
438
|
+
lines.push(` ${c.label}: counter {`);
|
|
439
|
+
lines.push(' status = "okay";');
|
|
440
|
+
lines.push(' tc_rtc: tc-rtc {');
|
|
441
|
+
lines.push(' compatible = "zephyr,rtc-counter";');
|
|
442
|
+
lines.push(' };');
|
|
443
|
+
lines.push(' };');
|
|
444
|
+
lines.push('};');
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
lines.push(`&${c.label} {`);
|
|
448
|
+
lines.push(' tc_rtc: tc-rtc {');
|
|
449
|
+
lines.push(' compatible = "zephyr,rtc-counter";');
|
|
450
|
+
lines.push(' };');
|
|
451
|
+
lines.push('};');
|
|
452
|
+
}
|
|
453
|
+
lines.push('/ {');
|
|
454
|
+
lines.push(' aliases {');
|
|
455
|
+
lines.push(' rtc = &tc_rtc;');
|
|
456
|
+
lines.push(' };');
|
|
457
|
+
lines.push('};');
|
|
458
|
+
lines.push('');
|
|
459
|
+
}
|
|
460
|
+
// USB HID: one zephyr,hid-device interface per program (the v1 ceiling —
|
|
461
|
+
// Keyboard OR Mouse, not both). protocol-code stays "none": the boot
|
|
462
|
+
// subclass/protocol codes (keyboard/mouse) made Windows bind the
|
|
463
|
+
// collections but silently discard every input report on this stack,
|
|
464
|
+
// while "none" (pure report-protocol device, like Zephyr's own samples)
|
|
465
|
+
// delivers input normally. The report descriptor carries the real
|
|
466
|
+
// keyboard/mouse semantics either way.
|
|
467
|
+
if (usage.usesHid) {
|
|
468
|
+
lines.push('/ {');
|
|
469
|
+
lines.push(' tc_hid: tc-hid {');
|
|
470
|
+
lines.push(' compatible = "zephyr,hid-device";');
|
|
471
|
+
lines.push(' protocol-code = "none";');
|
|
472
|
+
lines.push(' in-report-size = <8>;');
|
|
473
|
+
lines.push(' in-polling-period-us = <1000>;');
|
|
474
|
+
lines.push(' };');
|
|
475
|
+
lines.push('};');
|
|
476
|
+
lines.push('');
|
|
477
|
+
}
|
|
478
|
+
// Key matrix: the gpio-kbd-matrix node from the construction pad lists.
|
|
479
|
+
// Rows are pull-up inputs (active-low); columns are driven one at a time.
|
|
480
|
+
// Pin → controller/bit via the same mapping the gpio lowering uses.
|
|
481
|
+
if (usage.usesMatrix && usage.matrix && usage.matrix.rows.length > 0) {
|
|
482
|
+
// Same mapping the gpio lowering uses — the canonical controller
|
|
483
|
+
// resolution (single-controller fallback included). The port-relative
|
|
484
|
+
// bit comes from controllerRawPinForPin (split-SoC offsets).
|
|
485
|
+
const gpioRef = (pin) => {
|
|
486
|
+
return `&${controllerNodelabelForPin(chip, pin)} ${controllerRawPinForPin(chip, pin)} (GPIO_PULL_UP | GPIO_ACTIVE_LOW)`;
|
|
487
|
+
};
|
|
488
|
+
lines.push('/ {');
|
|
489
|
+
lines.push(' tc_matrix: matrix {');
|
|
490
|
+
lines.push(' compatible = "gpio-kbd-matrix";');
|
|
491
|
+
lines.push(` row-gpios = ${usage.matrix.rows.map((pin) => `<${gpioRef(pin)}>`).join(', ')};`);
|
|
492
|
+
lines.push(` col-gpios = ${usage.matrix.cols.map((pin) => `<${gpioRef(pin)}>`).join(', ')};`);
|
|
493
|
+
lines.push(' };');
|
|
494
|
+
lines.push('};');
|
|
495
|
+
lines.push('');
|
|
496
|
+
}
|
|
229
497
|
if (display) {
|
|
230
498
|
// Emit a full display DT node definition. Boards like the ESP32 devkit
|
|
231
499
|
// have no display node in their base DT, so a bare `&display0 { status }`
|
|
@@ -726,11 +994,87 @@ function emitAlert(lines, chip, alertPin, supported, indent) {
|
|
|
726
994
|
function emitDisplayNode(lines, display, wiring, spiTouchCs) {
|
|
727
995
|
const bus = display.busLabel ?? 'spi2';
|
|
728
996
|
const controller = panelControllerFor(display);
|
|
729
|
-
|
|
997
|
+
// Board-provided displays (native_sim's built-in sdl_dc): the board's own
|
|
998
|
+
// devicetree wires the panel — nothing to emit here.
|
|
999
|
+
if (display.boardProvidesDisplay) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
// I2C-family panels (mono OLEDs, ssd1306-class): a plain &i2cN child node —
|
|
1003
|
+
// no mipi-dbi bridge, no SPI bus block, no DMA. Bus pins come from the
|
|
1004
|
+
// touch wiring's remux (shared bus) or the board's default I2C pins.
|
|
1005
|
+
if (readDisplayBinding(display.dtCompatible ?? (isDtCompatible(display.driver) ? display.driver : ''))?.busFamily === 'i2c') {
|
|
1006
|
+
const addr = wiring?.address ?? 0x3c;
|
|
1007
|
+
// Optional I2C pin remux — mirrors the touch path's remux (the board's
|
|
1008
|
+
// default I2C pins rarely match a breakout's wiring). Named macros from
|
|
1009
|
+
// the SoC pinctrl header; the group lives under &pinctrl and overrides
|
|
1010
|
+
// i2c0's default group via pinctrl-0.
|
|
1011
|
+
const sda = wiring?.sda;
|
|
1012
|
+
const scl = wiring?.scl;
|
|
1013
|
+
if (sda !== undefined && scl !== undefined) {
|
|
1014
|
+
lines.push('&pinctrl {');
|
|
1015
|
+
lines.push(' i2c0_display: i2c0_display {');
|
|
1016
|
+
lines.push(' group1 {');
|
|
1017
|
+
lines.push(` pinmux = <I2C0_SDA_GPIO${sda}>, <I2C0_SCL_GPIO${scl}>;`);
|
|
1018
|
+
lines.push(' bias-pull-up;');
|
|
1019
|
+
lines.push(' drive-open-drain;');
|
|
1020
|
+
lines.push(' };');
|
|
1021
|
+
lines.push(' };');
|
|
1022
|
+
lines.push('};');
|
|
1023
|
+
lines.push('');
|
|
1024
|
+
}
|
|
1025
|
+
// Node name from the compatible's panel segment (ssd1306/ssd1309/sh1106);
|
|
1026
|
+
// DT node names are labels, not compatibles — but matching the panel
|
|
1027
|
+
// keeps the built zephyr.dts readable.
|
|
1028
|
+
const panel = (display.dtCompatible ?? display.driver).split(',')[1] ?? 'ssd1306';
|
|
1029
|
+
lines.push('&i2c0 {');
|
|
1030
|
+
lines.push(' status = "okay";');
|
|
1031
|
+
// Fast mode: the full-frame mono push is bandwidth-bound (a 128x64 frame
|
|
1032
|
+
// is 1KB — ~25ms at the 100kHz default, ~7ms at 400kHz), so animations
|
|
1033
|
+
// step without it. OLED modules and the esp32s3/nRF i2c controllers all
|
|
1034
|
+
// handle 400kHz; declare it whenever we own the bus node generation.
|
|
1035
|
+
lines.push(' clock-frequency = <400000>;');
|
|
1036
|
+
if (sda !== undefined && scl !== undefined) {
|
|
1037
|
+
lines.push(' pinctrl-0 = <&i2c0_display>;');
|
|
1038
|
+
lines.push(' pinctrl-names = "default";');
|
|
1039
|
+
}
|
|
1040
|
+
lines.push(` ${display.dtLabel}: ${panel}@${addr.toString(16)} {`);
|
|
1041
|
+
lines.push(` compatible = "${display.dtCompatible ?? display.driver}";`);
|
|
1042
|
+
lines.push(` reg = <0x${addr.toString(16)}>;`);
|
|
1043
|
+
lines.push(` width = <${display.nativeWidth ?? display.width}>;`);
|
|
1044
|
+
lines.push(` height = <${display.nativeHeight ?? display.height}>;`);
|
|
1045
|
+
const binding = readDisplayBinding(display.dtCompatible ?? display.driver);
|
|
1046
|
+
if (binding) {
|
|
1047
|
+
for (const [prop, info] of binding.required) {
|
|
1048
|
+
const v = monoPropFallback(prop, info, display.nativeHeight ?? display.height);
|
|
1049
|
+
if (v !== undefined)
|
|
1050
|
+
lines.push(` ${v};`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
lines.push(' };');
|
|
1054
|
+
lines.push('};');
|
|
1055
|
+
lines.push('');
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
// Compatible resolution: explicit override → the registry controllers →
|
|
1059
|
+
// the drop-in path (driver IS a compatible string) → a safe default.
|
|
1060
|
+
// Drop-in drivers (DT-compatible shape) ARE the compatible — they win over
|
|
1061
|
+
// the controller-default table (which only serves registry driver ids whose
|
|
1062
|
+
// id isn't itself a compatible; the e-ink family entries exist for the
|
|
1063
|
+
// Kconfig layer, not for node naming).
|
|
1064
|
+
const compatible = display.dtCompatible
|
|
1065
|
+
?? (isDtCompatible(display.driver)
|
|
1066
|
+
? display.driver
|
|
1067
|
+
: (controller !== undefined
|
|
1068
|
+
? PANEL_CONTROLLER_DEFAULTS[controller].dtCompatible
|
|
1069
|
+
: PANEL_CONTROLLER_DEFAULTS.ili9341.dtCompatible));
|
|
730
1070
|
const dc = wiring?.dc ?? 17;
|
|
731
1071
|
const rst = wiring?.rst ?? 16;
|
|
732
1072
|
const cs = wiring?.cs ?? DEFAULT_DISPLAY_CS;
|
|
733
|
-
|
|
1073
|
+
// E-ink SPI tops out far below TFTs (the reel board runs ssd1673 at 4MHz;
|
|
1074
|
+
// the controllers' shift registers clock 4-10MHz). Cap the default for the
|
|
1075
|
+
// e-ink families; explicit spiFrequency always wins.
|
|
1076
|
+
const einkFamily = isEinkDisplay({ driver: display.driver, displayClass: display.displayClass });
|
|
1077
|
+
const freq = wiring?.spiFrequency ?? (einkFamily ? 4000000 : 80000000);
|
|
734
1078
|
// DT node describes the NATIVE panel geometry; the effective (rotated)
|
|
735
1079
|
// dimensions live in the display profile.
|
|
736
1080
|
const nativeW = display.nativeWidth ?? display.width;
|
|
@@ -793,19 +1137,25 @@ function emitDisplayNode(lines, display, wiring, spiTouchCs) {
|
|
|
793
1137
|
lines.push(` ${display.dtLabel}: display@0 {`);
|
|
794
1138
|
lines.push(` compatible = "${compatible}";`);
|
|
795
1139
|
lines.push(' reg = <0>;');
|
|
796
|
-
if (wiring?.tearingEffectPin !== undefined) {
|
|
1140
|
+
if (wiring?.tearingEffectPin !== undefined && transportFor(display) === 'direct-spi') {
|
|
797
1141
|
const tePin = wiring.tearingEffectPin;
|
|
798
1142
|
// Tearing-effect input on the display node: GPIO_DT_SPEC_GET(
|
|
799
|
-
// DT_NODELABEL(display0), te_gpios) in the adapter.
|
|
800
|
-
// most modules don't break the TE pad out.
|
|
1143
|
+
// DT_NODELABEL(display0), te_gpios) in the direct-spi adapter.
|
|
1144
|
+
// Opt-in — most modules don't break the TE pad out. NOT emitted
|
|
1145
|
+
// on the zephyr-display transport: te-gpios makes the bound
|
|
1146
|
+
// in-tree driver allocate the TE GPIO interrupt (the ESP32
|
|
1147
|
+
// VECDESC_FL_SHARED conflict path) — the driver's TE handling
|
|
1148
|
+
// needs re-verification before it can be wired there.
|
|
801
1149
|
lines.push(` te-gpios = <&${gpioController(tePin)} ${tePin} GPIO_ACTIVE_HIGH>;`);
|
|
802
1150
|
}
|
|
803
1151
|
lines.push(` mipi-max-frequency = <${freq}>;`);
|
|
804
1152
|
lines.push(' mipi-mode = "MIPI_DBI_MODE_SPI_4WIRE";');
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1153
|
+
if (wiring?.busyPin !== undefined) {
|
|
1154
|
+
// E-ink BUSY line — required by the ssd16xx/uc81xx bindings
|
|
1155
|
+
// (the drivers block on it through the flash cycle). Active
|
|
1156
|
+
// level fixed per family: ssd16xx BUSY is active-high.
|
|
1157
|
+
lines.push(` busy-gpios = <&${gpioController(wiring.busyPin)} ${wiring.busyPin} GPIO_ACTIVE_HIGH>;`);
|
|
1158
|
+
}
|
|
809
1159
|
lines.push(` width = <${nativeW}>;`);
|
|
810
1160
|
lines.push(` height = <${nativeH}>;`);
|
|
811
1161
|
if (controller === 'st7796s') {
|
|
@@ -815,12 +1165,72 @@ function emitDisplayNode(lines, display, wiring, spiTouchCs) {
|
|
|
815
1165
|
lines.push(' madctl = <0x28>;');
|
|
816
1166
|
lines.push(' pgc = [f0 09 0b 06 04 2e 46 46 39 13 15 12 15 12];');
|
|
817
1167
|
lines.push(' ngc = [f0 09 0b 06 04 2e 46 46 39 13 15 12 15 12];');
|
|
1168
|
+
// rgb-is-inverted flips the format the driver REPORTS (565 <-> 565X).
|
|
1169
|
+
// Zephyr RGB_565 is little-endian storage, but an 8-bit SPI panel clocks
|
|
1170
|
+
// the LOW byte first — each pixel arrives byte-swapped, which mixes the
|
|
1171
|
+
// green channel into red/blue (white text reads purple, dark backgrounds
|
|
1172
|
+
// read green — verified on the rig). With the flag, the driver reports
|
|
1173
|
+
// 565X and the adapter byte-swaps at pack time, restoring wire order.
|
|
1174
|
+
// (The binding documents the prop for "buggy modules that display RGB as
|
|
1175
|
+
// BGR" — same mechanism, byte order.)
|
|
1176
|
+
lines.push(' rgb-is-inverted;');
|
|
818
1177
|
}
|
|
819
|
-
else {
|
|
1178
|
+
else if (controller === 'ili9341') {
|
|
820
1179
|
// ILI9341: the ilitek,ili9341 binding carries defaults for every register
|
|
821
1180
|
// (gamma, power, porch) and expresses orientation via `rotation` (degrees)
|
|
822
1181
|
// instead of a raw MADCTL — no panel-specific props are required.
|
|
823
1182
|
lines.push(` rotation = <${display.rotation ?? 0}>;`);
|
|
1183
|
+
// pixel-format is REQUIRED by the lcd-controller binding the ilitek
|
|
1184
|
+
// ili9xxx family includes: 0 = RGB565 (dt-bindings/display/panel.h),
|
|
1185
|
+
// matching upstream ILI9341 boards (esp_wrover_kit) and the C++ runtime.
|
|
1186
|
+
// The sitronix,st7796s binding does NOT declare pixel-format (its branch
|
|
1187
|
+
// omits the property — emitting it there is a DTC error, caught the hard
|
|
1188
|
+
// way once the overlay stopped carrying the wrong ilitek compatible).
|
|
1189
|
+
lines.push(' pixel-format = <0>;');
|
|
1190
|
+
}
|
|
1191
|
+
else {
|
|
1192
|
+
// Generic (drop-in) path: required properties come from the panel's own
|
|
1193
|
+
// binding in the user's Zephyr tree — the harvest is the single source
|
|
1194
|
+
// of truth, so the node is valid for ANY bound panel by construction.
|
|
1195
|
+
// Geometry/frequency props above are already emitted; pixel-format is
|
|
1196
|
+
// special (required by the lcd-controller family, value fixed to RGB565).
|
|
1197
|
+
const binding = readDisplayBinding(compatible);
|
|
1198
|
+
if (binding?.requiresPixelFormat) {
|
|
1199
|
+
lines.push(' pixel-format = <0>;');
|
|
1200
|
+
}
|
|
1201
|
+
if (binding) {
|
|
1202
|
+
for (const [prop, def] of binding.required) {
|
|
1203
|
+
// Skip structural properties the generator emits itself.
|
|
1204
|
+
if (prop === 'width' || prop === 'height' || prop === 'mipi-max-frequency'
|
|
1205
|
+
|| prop === 'pixel-format' || prop === 'reg' || prop === 'compatible'
|
|
1206
|
+
|| prop === 'status' || prop === 'mipi-mode'
|
|
1207
|
+
// phandle-array props are structural (GPIO routing) — the
|
|
1208
|
+
// generator emits them from config wiring (busy-gpios above),
|
|
1209
|
+
// never from a numeric fallback.
|
|
1210
|
+
|| prop === 'busy-gpios' || prop === 'reset-gpios' || prop === 'dc-gpios') {
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
emitBindingProp(lines, prop, def);
|
|
1214
|
+
}
|
|
1215
|
+
// Rotation on madctl-style panels (st7796s family): the binding ships
|
|
1216
|
+
// a neutral portrait default and the driver writes MADCTL verbatim, so
|
|
1217
|
+
// the config's rotation MUST reach the node or the UI's landscape
|
|
1218
|
+
// writes fall outside the portrait address window — half the screen
|
|
1219
|
+
// scrambled, half fine (verified on the rig). Table = ST77xx rotation
|
|
1220
|
+
// bits with BGR set (the verified clone convention; an R/B-swapped
|
|
1221
|
+
// panel flips to the config's channelSwapRb flag instead).
|
|
1222
|
+
// Byte-order quirk flag (clone panels): flips the format the driver
|
|
1223
|
+
// reports so the adapter byte-swaps at pack time. Only bindings that
|
|
1224
|
+
// declare the prop accept it — the DTC rejects it elsewhere, honestly.
|
|
1225
|
+
if (display.rgbInverted === true) {
|
|
1226
|
+
lines.push(' rgb-is-inverted;');
|
|
1227
|
+
}
|
|
1228
|
+
if (binding.props.has('madctl') && display.rotation !== undefined) {
|
|
1229
|
+
const MADCTL_ROTATION = [0x08, 0x28, 0x48, 0xE8];
|
|
1230
|
+
const r = ((display.rotation % 4) + 4) % 4;
|
|
1231
|
+
lines.push(` madctl = <0x${MADCTL_ROTATION[r].toString(16)}>;`);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
824
1234
|
}
|
|
825
1235
|
lines.push(' };');
|
|
826
1236
|
lines.push(' };');
|
|
@@ -909,11 +1319,16 @@ function emitFt6336uNode(lines, touch) {
|
|
|
909
1319
|
lines.push(' ft6336u: ft6336u@38 {');
|
|
910
1320
|
lines.push(' compatible = "focaltech,ft5336";');
|
|
911
1321
|
lines.push(' reg = <0x38>;');
|
|
912
|
-
// NOTE: int-gpios is intentionally omitted. The
|
|
913
|
-
// registers a GPIO
|
|
914
|
-
//
|
|
915
|
-
//
|
|
916
|
-
//
|
|
1322
|
+
// NOTE: int-gpios is intentionally omitted. The driver's interrupt mode
|
|
1323
|
+
// registers a GPIO IRQ (the ESP32 VECDESC_FL_SHARED crash); with no
|
|
1324
|
+
// int-gpios the in-tree driver falls back to polling mode
|
|
1325
|
+
// (CONFIG_INPUT_FT5336_PERIOD, default 10ms) — no IRQ is registered and
|
|
1326
|
+
// the touch adapter consumes the driver's input events.
|
|
1327
|
+
// swapped-x-y: the driver reports pos(col, row) — the Y-register value
|
|
1328
|
+
// first. The swap makes its ABS_X/ABS_Y events carry the controller's
|
|
1329
|
+
// X/Y registers verbatim, which is the raw coordinate space the runtime's
|
|
1330
|
+
// calibration + rotation math (ui_poll_touch) expects from touch_readRaw.
|
|
1331
|
+
lines.push(' swapped-x-y;');
|
|
917
1332
|
if (resetPin !== undefined) {
|
|
918
1333
|
lines.push(` reset-gpios = <&${gpioController(resetPin)} ${resetPin} GPIO_ACTIVE_LOW>;`);
|
|
919
1334
|
}
|
|
@@ -9,7 +9,7 @@ declare const _default: {
|
|
|
9
9
|
entrypoint: {
|
|
10
10
|
entrypointFunctionName: string;
|
|
11
11
|
requiresLoopFunction: boolean;
|
|
12
|
-
sourceExtension: "
|
|
12
|
+
sourceExtension: "h" | "cpp" | "ino" | "cc";
|
|
13
13
|
generateHeaderFile: boolean;
|
|
14
14
|
overrideBaseName?: string | undefined;
|
|
15
15
|
outputSubdirectory?: string | undefined;
|
|
@@ -22,7 +22,7 @@ declare const _default: {
|
|
|
22
22
|
};
|
|
23
23
|
hal: Record<string, {
|
|
24
24
|
supported: boolean;
|
|
25
|
-
ops: Record<string, "
|
|
25
|
+
ops: Record<string, "supported" | "unsupported" | "stub" | "polyfill" | "probe-inconclusive">;
|
|
26
26
|
partialCoverage: boolean;
|
|
27
27
|
unsupportedReason?: string | undefined;
|
|
28
28
|
}>;
|
|
@@ -62,7 +62,7 @@ declare const _default: {
|
|
|
62
62
|
hasExceptions: boolean;
|
|
63
63
|
hasRTTI: boolean;
|
|
64
64
|
recommendedArrayImpl: "static_array" | "std_vector";
|
|
65
|
-
recommendedStringImpl: "
|
|
65
|
+
recommendedStringImpl: "std_string" | "static_string";
|
|
66
66
|
};
|
|
67
67
|
};
|
|
68
68
|
ambientTypes: string[];
|
|
@@ -85,6 +85,12 @@ declare const _default: {
|
|
|
85
85
|
licenses?: {
|
|
86
86
|
available: boolean;
|
|
87
87
|
} | undefined;
|
|
88
|
+
sbom?: {
|
|
89
|
+
available: boolean;
|
|
90
|
+
} | undefined;
|
|
91
|
+
audit?: {
|
|
92
|
+
available: boolean;
|
|
93
|
+
} | undefined;
|
|
88
94
|
compat?: {
|
|
89
95
|
zephyr?: string | undefined;
|
|
90
96
|
} | undefined;
|