@typecad/framework-zephyr 1.0.0-alpha.10 → 1.0.0-alpha.12
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/chips/esp32.js +12 -0
- package/dist/chips/types.d.ts +30 -0
- package/dist/chips/xiao-ble.js +6 -0
- package/dist/display/gfx.d.ts +12 -3
- package/dist/display/gfx.js +130 -17
- package/dist/display/profiles.d.ts +25 -0
- package/dist/display/profiles.js +30 -0
- package/dist/display/touch-adapter.d.ts +3 -4
- package/dist/display/touch-adapter.js +119 -16
- package/dist/display/ui-adapter.js +308 -139
- package/dist/doctor.d.ts +3 -3
- package/dist/doctor.js +56 -29
- package/dist/dt-config/kconfig.d.ts +8 -1
- package/dist/dt-config/kconfig.js +40 -5
- package/dist/dt-config/overlay.d.ts +18 -1
- package/dist/dt-config/overlay.js +124 -26
- package/dist/framework.manifest.d.ts +29 -28
- package/dist/framework.manifest.js +46 -17
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/licenses.d.ts +59 -0
- package/dist/licenses.js +347 -0
- package/dist/lowering/ble.js +3 -1
- package/dist/lowering/dac.d.ts +15 -0
- package/dist/lowering/dac.js +69 -0
- package/dist/lowering/fs.d.ts +16 -0
- package/dist/lowering/fs.js +121 -0
- package/dist/lowering/hwtimer.d.ts +15 -0
- package/dist/lowering/hwtimer.js +84 -0
- package/dist/lowering/index.d.ts +4 -1
- package/dist/lowering/index.js +12 -3
- package/dist/strategy.d.ts +4 -0
- package/dist/strategy.js +275 -35
- package/dist/toolchain/compat.js +10 -1
- package/dist/toolchain/env-check.d.ts +93 -0
- package/dist/toolchain/env-check.js +190 -0
- package/dist/toolchain/index.js +39 -9
- package/dist/toolchain/scaffold.js +7 -2
- package/dist/toolchain/west-discover.d.ts +11 -3
- package/dist/toolchain/west-discover.js +84 -7
- package/dist/toolchain/west-spawn.js +15 -0
- package/package.json +4 -4
- package/src/chips/esp32.ts +12 -0
- package/src/chips/types.ts +29 -0
- package/src/chips/xiao-ble.ts +6 -0
- package/src/display/gfx.ts +135 -19
- package/src/display/profiles.ts +53 -0
- package/src/display/touch-adapter.ts +119 -15
- package/src/display/ui-adapter.ts +311 -139
- package/src/doctor.ts +77 -56
- package/src/dt-config/kconfig.ts +45 -6
- package/src/dt-config/overlay.ts +159 -29
- package/src/framework.manifest.ts +47 -17
- package/src/index.ts +6 -0
- package/src/licenses.ts +425 -0
- package/src/lowering/ble.ts +3 -1
- package/src/lowering/dac.ts +82 -0
- package/src/lowering/fs.ts +127 -0
- package/src/lowering/hwtimer.ts +101 -0
- package/src/lowering/index.ts +9 -2
- package/src/strategy.ts +271 -35
- package/src/toolchain/compat.ts +154 -145
- package/src/toolchain/env-check.ts +285 -0
- package/src/toolchain/index.ts +40 -9
- package/src/toolchain/scaffold.ts +7 -2
- package/src/toolchain/west-discover.ts +92 -9
- package/src/toolchain/west-spawn.ts +15 -0
package/src/doctor.ts
CHANGED
|
@@ -1,56 +1,77 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// @typecad/framework-zephyr — Zephyr environment doctor
|
|
3
|
-
//
|
|
4
|
-
// `cuttlefish doctor` (Zephyr framework) — verify the
|
|
5
|
-
//
|
|
6
|
-
// the configured board target
|
|
7
|
-
// environment is OK, non-zero otherwise. Mirrors framework-arduino's
|
|
8
|
-
// shape (dispatched via the framework's `doctor` export)
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
ui.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @typecad/framework-zephyr — Zephyr environment doctor
|
|
3
|
+
//
|
|
4
|
+
// `cuttlefish doctor` (Zephyr framework) — verify west (the Zephyr build tool)
|
|
5
|
+
// is installed + responsive, the Zephyr RTOS is inside the framework's declared
|
|
6
|
+
// compat range, and the configured board target exists in the checkout. Exits 0
|
|
7
|
+
// if the environment is OK, non-zero otherwise. Mirrors framework-arduino's
|
|
8
|
+
// doctor shape (dispatched via the framework's `doctor` export) and reuses
|
|
9
|
+
// checkZephyrEnv so the detection logic can be shared with the build/test gates.
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
import * as ui from '@typecad/cuttlefish/utils/ui';
|
|
13
|
+
import { loadCuttlefishConfig } from '@typecad/cuttlefish/config-loader';
|
|
14
|
+
import { checkZephyrEnv } from './toolchain/env-check.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Verify west is installed + responsive, the Zephyr RTOS is inside the supported
|
|
18
|
+
* range, and the configured board target exists in the checkout. Sets
|
|
19
|
+
* process.exitCode = 1 on failure. Thin presenter over checkZephyrEnv.
|
|
20
|
+
*/
|
|
21
|
+
export function runDoctor(): void {
|
|
22
|
+
ui.printHeader();
|
|
23
|
+
ui.printStep('Checking Zephyr environment...');
|
|
24
|
+
|
|
25
|
+
const config = loadCuttlefishConfig(process.cwd());
|
|
26
|
+
const buildTarget = config?.buildTarget;
|
|
27
|
+
|
|
28
|
+
const result = checkZephyrEnv(buildTarget);
|
|
29
|
+
const c = result.check;
|
|
30
|
+
|
|
31
|
+
// west (the Zephyr build tool) — the analog of arduino-cli presence.
|
|
32
|
+
if (c.westFound) {
|
|
33
|
+
const ver = c.westVersion ?? 'found';
|
|
34
|
+
const src = c.westSource ? ` (${c.westSource})` : '';
|
|
35
|
+
ui.printInfo(`west ............. ${ver} ✓${src}`);
|
|
36
|
+
} else {
|
|
37
|
+
ui.printError('west ............. NOT FOUND');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Zephyr RTOS version + declared compat range.
|
|
41
|
+
ui.printInfo(`ZEPHYR_BASE ...... ${c.zephyrBase ?? '(not set)'}`);
|
|
42
|
+
ui.printInfo(`Zephyr version .. ${c.zephyrVersion ?? 'unknown (could not read ZEPHYR_BASE/VERSION)'}`);
|
|
43
|
+
ui.printInfo(`Supported range . ${c.compatRange ?? '(none declared)'}`);
|
|
44
|
+
|
|
45
|
+
if (c.compatStatus === 'out-of-range') {
|
|
46
|
+
ui.printError(`Zephyr ${c.zephyrVersion} is OUTSIDE the supported range (${c.compatRange}).`);
|
|
47
|
+
} else if (c.compatStatus === 'undetectable') {
|
|
48
|
+
ui.printWarning('Could not detect the Zephyr version (is ZEPHYR_BASE set?) — compat check skipped.');
|
|
49
|
+
} else {
|
|
50
|
+
ui.printInfo('Zephyr compat ... OK');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Board target — the analog of the Arduino core presence check.
|
|
54
|
+
if (buildTarget) {
|
|
55
|
+
const resolved = c.resolvedBoardTarget ?? buildTarget;
|
|
56
|
+
const arrow = resolved === buildTarget ? '' : ` → ${resolved}`;
|
|
57
|
+
if (c.boardTargetSupported === false) {
|
|
58
|
+
ui.printError(`Board target .... ${buildTarget}${arrow} NOT found in this Zephyr checkout`);
|
|
59
|
+
ui.printInfo(' → check the board id, or run: west boards');
|
|
60
|
+
} else if (c.boardTargetSupported === undefined) {
|
|
61
|
+
ui.printInfo(`Board target .... ${buildTarget}${arrow}`);
|
|
62
|
+
ui.printInfo('(could not verify board presence — no ZEPHYR_BASE boards/ tree found)');
|
|
63
|
+
} else {
|
|
64
|
+
ui.printInfo(`Board target .... ${buildTarget}${arrow}`);
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
ui.printInfo('(no buildTarget in cuttlefish.config.ts — skipping board check)');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Exit code — mirrors framework-arduino's doctor.
|
|
71
|
+
if (result.ok) {
|
|
72
|
+
ui.printSuccess('Environment OK');
|
|
73
|
+
return; // exitCode stays unset => 0
|
|
74
|
+
}
|
|
75
|
+
for (const line of result.messages) ui.printInfo(line);
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
}
|
package/src/dt-config/kconfig.ts
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
export interface KconfigUsage {
|
|
12
12
|
usesAdc?: boolean;
|
|
13
13
|
usesPwm?: boolean;
|
|
14
|
+
usesDac?: boolean;
|
|
15
|
+
usesFS?: boolean;
|
|
16
|
+
usesHwtimer?: boolean;
|
|
14
17
|
usesI2c?: boolean;
|
|
15
18
|
usesSpi?: boolean;
|
|
16
19
|
usesUart?: boolean;
|
|
@@ -23,8 +26,12 @@ export interface KconfigUsage {
|
|
|
23
26
|
usesMqtt?: boolean;
|
|
24
27
|
usesPreferences?: boolean;
|
|
25
28
|
usesRandom?: boolean;
|
|
26
|
-
/** Touch controller referenced (UI touch adapter emits DT_NODELABEL(ft6336u)
|
|
29
|
+
/** Touch controller referenced (UI touch adapter emits DT_NODELABEL(ft6336u)
|
|
30
|
+
* or DT_NODELABEL(xpt2046)). Selects the bus driver the node needs. */
|
|
27
31
|
usesTouch?: boolean;
|
|
32
|
+
/** Which touch controller the program uses — FT6336U rides I2C, XPT2046
|
|
33
|
+
* rides the display's SPI bus. Only meaningful with usesTouch. */
|
|
34
|
+
touchController?: 'ft6336u' | 'xpt2046';
|
|
28
35
|
/** PSRAM type ('opi' | 'quad') when the target board has PSRAM. Emits the
|
|
29
36
|
* CONFIG_SPIRAM symbols so the ESP heap serves PSRAM for canvas allocations. */
|
|
30
37
|
psram?: 'opi' | 'quad';
|
|
@@ -49,9 +56,12 @@ export function resolveKconfigFragments(
|
|
|
49
56
|
|
|
50
57
|
if (usage.usesAdc) m.set('CONFIG_ADC', 'y');
|
|
51
58
|
if (usage.usesPwm) m.set('CONFIG_PWM', 'y');
|
|
59
|
+
if (usage.usesDac) m.set('CONFIG_DAC', 'y');
|
|
52
60
|
if (usage.usesI2c) m.set('CONFIG_I2C', 'y');
|
|
53
61
|
if (usage.usesSpi) m.set('CONFIG_SPI', 'y');
|
|
54
62
|
if (usage.usesWdt) m.set('CONFIG_WATCHDOG', 'y');
|
|
63
|
+
// Hardware timers via the counter driver.
|
|
64
|
+
if (usage.usesHwtimer) m.set('CONFIG_COUNTER', 'y');
|
|
55
65
|
if (usage.usesDisplay) {
|
|
56
66
|
m.set('CONFIG_DISPLAY', 'y');
|
|
57
67
|
m.set('CONFIG_SPI', 'y');
|
|
@@ -62,15 +72,31 @@ export function resolveKconfigFragments(
|
|
|
62
72
|
// configured SPI clock (~80MHz) and drops into the low tens of ms. The
|
|
63
73
|
// display overlay pairs this with dma-enabled + dmas on the spi2 node.
|
|
64
74
|
m.set('CONFIG_DMA', 'y');
|
|
65
|
-
// Disable the MIPI DBI SPI bridge +
|
|
66
|
-
// drives the panel directly via spi_write.
|
|
67
|
-
// allocate a tearing-effect GPIO interrupt
|
|
68
|
-
//
|
|
75
|
+
// Disable the MIPI DBI SPI bridge + in-tree panel drivers (ILI9341,
|
|
76
|
+
// ST7796S). The display adapter drives the panel directly via spi_write.
|
|
77
|
+
// Binding these drivers would allocate a tearing-effect GPIO interrupt
|
|
78
|
+
// that conflicts with the SPI/I2C driver interrupts — the
|
|
79
|
+
// VECDESC_FL_SHARED assertion crashes on touch. ILI9341 matters as much
|
|
80
|
+
// as the bridge: the driver auto-defaults on from the overlay's
|
|
81
|
+
// ilitek,ili9341 node and references the (disabled) mipi-dbi-spi
|
|
82
|
+
// controller's device struct, failing at link time with
|
|
83
|
+
// "undefined reference to __device_dts_ord_N". (Assign the prompted
|
|
84
|
+
// ILI9341, not the hidden ILI9XXX — promptless symbols reject prj.conf
|
|
85
|
+
// assignments.)
|
|
69
86
|
m.set('CONFIG_MIPI_DBI_SPI', 'n');
|
|
87
|
+
m.set('CONFIG_ILI9341', 'n');
|
|
70
88
|
m.set('CONFIG_ST7796S', 'n');
|
|
71
89
|
}
|
|
72
90
|
if (usage.usesTouch) {
|
|
73
|
-
|
|
91
|
+
// FT6336U touch is on I2C; the XPT2046 shares the display's SPI bus.
|
|
92
|
+
// CONFIG_INPUT stays off either way: the adapters drive the controllers
|
|
93
|
+
// directly, and enabling it would build the in-tree input drivers
|
|
94
|
+
// (ft5336 / xpt2046) against nodes these adapters already own.
|
|
95
|
+
if (usage.touchController === 'xpt2046') {
|
|
96
|
+
m.set('CONFIG_SPI', 'y');
|
|
97
|
+
} else {
|
|
98
|
+
m.set('CONFIG_I2C', 'y');
|
|
99
|
+
}
|
|
74
100
|
}
|
|
75
101
|
// PSRAM: enable the ESP SPIRAM driver + route malloc/heap to external RAM so
|
|
76
102
|
// large canvas allocations (scroll viewports, lists) can use PSRAM instead of
|
|
@@ -257,6 +283,19 @@ export function resolveKconfigFragments(
|
|
|
257
283
|
m.set('CONFIG_SETTINGS', 'y');
|
|
258
284
|
m.set('CONFIG_SETTINGS_ZMS', 'y');
|
|
259
285
|
}
|
|
286
|
+
// Filesystem: littlefs on the storage partition. CONFIG_FILE_SYSTEM_LITTLEFS
|
|
287
|
+
// selects the littlefs backend but NOT FLASH/FLASH_MAP (the partition lookup
|
|
288
|
+
// needs them), so all three are set explicitly — same shape as the
|
|
289
|
+
// preferences/ZMS block. The overlay points the storage_partition at the FS
|
|
290
|
+
// (see dt-config/overlay.ts). NOTE: a program using BOTH fs.* and
|
|
291
|
+
// preferences.* shares the one storage_partition between littlefs and ZMS —
|
|
292
|
+
// dedicate separate partitions if both are needed (the manifest flags this).
|
|
293
|
+
if (usage.usesFS) {
|
|
294
|
+
m.set('CONFIG_FLASH', 'y');
|
|
295
|
+
m.set('CONFIG_FLASH_MAP', 'y');
|
|
296
|
+
m.set('CONFIG_FILE_SYSTEM', 'y');
|
|
297
|
+
m.set('CONFIG_FILE_SYSTEM_LITTLEFS', 'y');
|
|
298
|
+
}
|
|
260
299
|
// usesUart: the board enables the console UART by default; the overlay (not
|
|
261
300
|
// Kconfig) is where a UART node would be enabled, so no symbol here.
|
|
262
301
|
// Random: <zephyr/random/random.h> sys_rand_get is backed by the random
|
package/src/dt-config/overlay.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
15
15
|
import type { ZephyrDisplayProfile } from '../display/profiles.js';
|
|
16
|
+
import { PANEL_CONTROLLER_DEFAULTS, panelControllerFor } from '../display/profiles.js';
|
|
16
17
|
import type { KconfigUsage } from './kconfig.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -40,12 +41,24 @@ export interface DisplayWiring {
|
|
|
40
41
|
backlightPin?: number;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
/** Touch wiring from cuttlefish.config.ts (irq/resetPin/sda/scl
|
|
44
|
+
/** Touch wiring from cuttlefish.config.ts (irq/resetPin/sda/scl; cs for SPI
|
|
45
|
+
* resistive controllers, calibration for the XPT2046 DT binding). */
|
|
44
46
|
export interface TouchWiring {
|
|
47
|
+
/** Touch controller kind — selects the DT node shape (FT6336U node on I2C0
|
|
48
|
+
* vs XPT2046 node on the display's SPI bus). Default 'ft6336u'. */
|
|
49
|
+
controller?: 'ft6336u' | 'xpt2046';
|
|
45
50
|
irq?: number;
|
|
46
51
|
resetPin?: number;
|
|
47
52
|
sda?: number;
|
|
48
53
|
scl?: number;
|
|
54
|
+
/** XPT2046 only: SPI CS pin (second cs-gpios entry on the panel's bus). */
|
|
55
|
+
cs?: number;
|
|
56
|
+
/** XPT2046 only: raw ADC calibration — feeds the binding's min-x/max-x/
|
|
57
|
+
* min-y/max-y (required props). Defaults span the full 12-bit range. */
|
|
58
|
+
calibration?: { xMin: number; xMax: number; yMin: number; yMax: number };
|
|
59
|
+
/** XPT2046 only: pen-detect Z1 threshold (binding's z-threshold). Resistive
|
|
60
|
+
* panels need a few hundred 12-bit counts; default 400. */
|
|
61
|
+
minPressure?: number;
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
export function generateOverlay(
|
|
@@ -84,6 +97,11 @@ export function generateOverlay(
|
|
|
84
97
|
if (usage.usesUart && chip.uart) {
|
|
85
98
|
for (const c of chip.uart.controllers) block(c.nodeLabel);
|
|
86
99
|
}
|
|
100
|
+
// DAC: enable the chip's DAC device node when the program uses dac.*. The
|
|
101
|
+
// lowering references DEVICE_DT_GET(DT_NODELABEL(<dac.device>)).
|
|
102
|
+
if (usage.usesDac && chip.dac) {
|
|
103
|
+
block(chip.dac.device);
|
|
104
|
+
}
|
|
87
105
|
if (display) {
|
|
88
106
|
// Emit a full display DT node definition. Boards like the ESP32 devkit
|
|
89
107
|
// have no display node in their base DT, so a bare `&display0 { status }`
|
|
@@ -91,14 +109,23 @@ export function generateOverlay(
|
|
|
91
109
|
// controller with the panel's compatible string + dimensions. The pin
|
|
92
110
|
// wiring (cs/dc/rst) uses ESP32 GPIO defaults from the demo config; a
|
|
93
111
|
// real board overlay would carry its own binding.
|
|
94
|
-
|
|
112
|
+
// An XPT2046 on the same bus needs its CS as the second cs-gpios entry,
|
|
113
|
+
// so thread it into the display block (DT assignment replaces the whole
|
|
114
|
+
// property — both entries must be written together).
|
|
115
|
+
emitDisplayNode(
|
|
116
|
+
lines,
|
|
117
|
+
display,
|
|
118
|
+
wiring,
|
|
119
|
+
touch?.controller === 'xpt2046' ? (touch?.cs ?? DEFAULT_XPT2046_CS) : undefined,
|
|
120
|
+
);
|
|
95
121
|
}
|
|
96
|
-
// FT6336U
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
//
|
|
122
|
+
// Touch — FT6336U capacitive on I2C (references DT_NODELABEL(ft6336u)) or
|
|
123
|
+
// XPT2046 resistive on the display's SPI bus (references
|
|
124
|
+
// DT_NODELABEL(xpt2046)). Same rationale as the display node: the bare
|
|
125
|
+
// devkit has no such node. Gated on usesTouch (not usesI2c/chip.i2c) so it
|
|
126
|
+
// emits even when the chip descriptor doesn't declare bus controllers.
|
|
100
127
|
if (usage.usesTouch) {
|
|
101
|
-
emitTouchNode(lines, touch);
|
|
128
|
+
emitTouchNode(lines, touch, display);
|
|
102
129
|
}
|
|
103
130
|
|
|
104
131
|
// Preferences (ZMS settings backend): point the settings subsystem at the
|
|
@@ -133,11 +160,26 @@ export function generateOverlay(
|
|
|
133
160
|
}
|
|
134
161
|
|
|
135
162
|
/**
|
|
136
|
-
* Emit a display DT node definition. The node is attached to
|
|
137
|
-
* first user SPI controller) via a MIPI
|
|
138
|
-
* the display config (cs/dc/rst);
|
|
163
|
+
* Emit a display DT node definition. The node is attached to the profile's SPI
|
|
164
|
+
* controller (default spi2, the ESP32's first user SPI controller) via a MIPI
|
|
165
|
+
* DBI SPI bridge. Pin wiring comes from the display config (cs/dc/rst);
|
|
166
|
+
* defaults match the demo-st wiring if absent. The compatible string + node
|
|
167
|
+
* props come from the profile's panel controller (st7796s carries the required
|
|
168
|
+
* pgc/ngc gamma + madctl; ili9341's binding defaults everything else).
|
|
169
|
+
*
|
|
170
|
+
* spiTouchCs: when an XPT2046 SPI touch controller shares the bus, its CS is
|
|
171
|
+
* appended as the second cs-gpios entry (the touch node uses reg = <1>) — DT
|
|
172
|
+
* property assignment replaces, so both entries must be written together.
|
|
139
173
|
*/
|
|
140
|
-
function emitDisplayNode(
|
|
174
|
+
function emitDisplayNode(
|
|
175
|
+
lines: string[],
|
|
176
|
+
display: ZephyrDisplayProfile,
|
|
177
|
+
wiring?: DisplayWiring,
|
|
178
|
+
spiTouchCs?: number,
|
|
179
|
+
): void {
|
|
180
|
+
const bus = display.busLabel ?? 'spi2';
|
|
181
|
+
const controller = panelControllerFor(display);
|
|
182
|
+
const compatible = display.dtCompatible ?? PANEL_CONTROLLER_DEFAULTS[controller].dtCompatible;
|
|
141
183
|
const dc = wiring?.dc ?? 17;
|
|
142
184
|
const rst = wiring?.rst ?? 16;
|
|
143
185
|
const cs = wiring?.cs ?? 5;
|
|
@@ -158,7 +200,9 @@ function emitDisplayNode(lines: string[], display: ZephyrDisplayProfile, wiring?
|
|
|
158
200
|
// macros are used instead of the named SPIM2_*_GPIOxx tokens because the
|
|
159
201
|
// bindings header omits GPIOs 22-25 from those lists.
|
|
160
202
|
if (sck !== undefined && mosi !== undefined) {
|
|
161
|
-
|
|
203
|
+
// 'spi2' → pinctrl group 'spim2_default' (ESP32 SPI-master naming).
|
|
204
|
+
const pinctrlGroup = bus.replace(/^spi(\d)$/, 'spim$1') + '_default';
|
|
205
|
+
lines.push(`&${pinctrlGroup} {`);
|
|
162
206
|
lines.push(' group1 {');
|
|
163
207
|
lines.push(` pinmux = <ESP32_PINMUX(${miso ?? 19}, ESP_FSPIQ_IN, ESP_NOSIG)>,`);
|
|
164
208
|
lines.push(` <ESP32_PINMUX(${sck}, ESP_NOSIG, ESP_FSPICLK_OUT)>,`);
|
|
@@ -175,9 +219,9 @@ function emitDisplayNode(lines: string[], display: ZephyrDisplayProfile, wiring?
|
|
|
175
219
|
lines.push(' status = "okay";');
|
|
176
220
|
lines.push('};');
|
|
177
221
|
lines.push('');
|
|
178
|
-
lines.push(
|
|
222
|
+
lines.push(`&${bus} {`);
|
|
179
223
|
lines.push(' status = "okay";');
|
|
180
|
-
lines.push(` cs-gpios = <&${gpioController(cs)} ${cs} GPIO_ACTIVE_LOW
|
|
224
|
+
lines.push(` cs-gpios = <&${gpioController(cs)} ${cs} GPIO_ACTIVE_LOW>${spiTouchCs !== undefined ? `, <&${gpioController(spiTouchCs)} ${spiTouchCs} GPIO_ACTIVE_LOW>` : ''};`);
|
|
181
225
|
// Enable GDMA for the SPI2 host. The ESP32 SPI driver uses DMA only when
|
|
182
226
|
// dma-enabled is set AND dmas wires tx/rx channels to the GDMA controller;
|
|
183
227
|
// without it, transfers run PIO through the 64-byte FIFO (~4MHz effective at
|
|
@@ -193,25 +237,36 @@ function emitDisplayNode(lines: string[], display: ZephyrDisplayProfile, wiring?
|
|
|
193
237
|
lines.push('/ {');
|
|
194
238
|
lines.push(' mipi_dbi: mipi-dbi {');
|
|
195
239
|
lines.push(' compatible = "zephyr,mipi-dbi-spi";');
|
|
196
|
-
lines.push(
|
|
240
|
+
lines.push(` spi-dev = <&${bus}>;`);
|
|
197
241
|
lines.push(` dc-gpios = <&${gpioController(dc)} ${dc} GPIO_ACTIVE_HIGH>;`);
|
|
198
242
|
lines.push(` reset-gpios = <&${gpioController(rst)} ${rst} GPIO_ACTIVE_LOW>;`);
|
|
199
243
|
lines.push(' write-only;');
|
|
200
244
|
lines.push(' #address-cells = <1>;');
|
|
201
245
|
lines.push(' #size-cells = <0>;');
|
|
202
246
|
lines.push(` ${display.dtLabel}: display@0 {`);
|
|
203
|
-
lines.push(
|
|
247
|
+
lines.push(` compatible = "${compatible}";`);
|
|
204
248
|
lines.push(' reg = <0>;');
|
|
205
|
-
|
|
206
|
-
|
|
249
|
+
lines.push(` mipi-max-frequency = <${freq}>;`);
|
|
250
|
+
lines.push(' mipi-mode = "MIPI_DBI_MODE_SPI_4WIRE";');
|
|
251
|
+
// Required by the lcd-controller binding (Zephyr 4.x): 0 = RGB565,
|
|
252
|
+
// matching upstream ILI9341 boards (esp_wrover_kit) and the C++
|
|
253
|
+
// runtime, which drives these SPI TFTs as RGB565.
|
|
254
|
+
lines.push(' pixel-format = <0>;');
|
|
207
255
|
lines.push(` width = <${nativeW}>;`);
|
|
208
256
|
lines.push(` height = <${nativeH}>;`);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
257
|
+
if (controller === 'st7796s') {
|
|
258
|
+
// MADCTL: rotation 1 (landscape, MV=1) + BGR bit, matching the adapter's
|
|
259
|
+
// direct-drive init (0x28). The DT copy keeps the stock driver's init
|
|
260
|
+
// consistent if it is ever exercised.
|
|
261
|
+
lines.push(' madctl = <0x28>;');
|
|
262
|
+
lines.push(' pgc = [f0 09 0b 06 04 2e 46 46 39 13 15 12 15 12];');
|
|
263
|
+
lines.push(' ngc = [f0 09 0b 06 04 2e 46 46 39 13 15 12 15 12];');
|
|
264
|
+
} else {
|
|
265
|
+
// ILI9341: the ilitek,ili9341 binding carries defaults for every register
|
|
266
|
+
// (gamma, power, porch) and expresses orientation via `rotation` (degrees)
|
|
267
|
+
// instead of a raw MADCTL — no panel-specific props are required.
|
|
268
|
+
lines.push(` rotation = <${display.rotation ?? 0}>;`);
|
|
269
|
+
}
|
|
215
270
|
lines.push(' };');
|
|
216
271
|
lines.push(' };');
|
|
217
272
|
lines.push('};');
|
|
@@ -238,13 +293,39 @@ function emitDisplayNode(lines: string[], display: ZephyrDisplayProfile, wiring?
|
|
|
238
293
|
}
|
|
239
294
|
}
|
|
240
295
|
|
|
296
|
+
/** Default XPT2046 CS/IRQ pins (ESP32-S3 GPIOs clear of the demo-st display
|
|
297
|
+
* wiring: 5/17/16/15 and the remuxed SPI pins). Config values override. */
|
|
298
|
+
const DEFAULT_XPT2046_CS = 6;
|
|
299
|
+
const DEFAULT_XPT2046_IRQ = 7;
|
|
300
|
+
|
|
241
301
|
/**
|
|
242
|
-
* Emit
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
302
|
+
* Emit the touch DT node for the configured controller.
|
|
303
|
+
*
|
|
304
|
+
* FT6336U (capacitive, I2C): node on i2c0 at the FT6336U default address
|
|
305
|
+
* (0x38); the C++ touch adapter reads it via i2c_write_read_dt.
|
|
306
|
+
*
|
|
307
|
+
* XPT2046 (resistive, SPI): node on the display's SPI bus as CS index 1. The
|
|
308
|
+
* in-tree xptek,xpt2046 binding (drivers/input) is register-matched for the
|
|
309
|
+
* raw SPI access — CONFIG_INPUT stays off, so the in-tree input driver does
|
|
310
|
+
* not build and the adapter owns the chip (same pattern as FT6336U reusing
|
|
311
|
+
* the ft5336 binding). The binding requires int-gpios, touchscreen-size-*,
|
|
312
|
+
* and min/max calibration props, so defaults are filled for anything the
|
|
313
|
+
* config omits.
|
|
246
314
|
*/
|
|
247
|
-
function emitTouchNode(
|
|
315
|
+
function emitTouchNode(
|
|
316
|
+
lines: string[],
|
|
317
|
+
touch: TouchWiring | undefined,
|
|
318
|
+
display: ZephyrDisplayProfile | undefined,
|
|
319
|
+
): void {
|
|
320
|
+
if (touch?.controller === 'xpt2046') {
|
|
321
|
+
emitXpt2046Node(lines, touch, display);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
emitFt6336uNode(lines, touch);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** FT6336U capacitive touch node on the first I2C controller. */
|
|
328
|
+
function emitFt6336uNode(lines: string[], touch?: TouchWiring): void {
|
|
248
329
|
const irq = touch?.irq ?? 15;
|
|
249
330
|
const resetPin = touch?.resetPin;
|
|
250
331
|
const sda = touch?.sda;
|
|
@@ -291,3 +372,52 @@ function emitTouchNode(lines: string[], touch?: TouchWiring): void {
|
|
|
291
372
|
lines.push('};');
|
|
292
373
|
lines.push('');
|
|
293
374
|
}
|
|
375
|
+
|
|
376
|
+
/** XPT2046 resistive touch node on the display's SPI bus (CS index 1). */
|
|
377
|
+
function emitXpt2046Node(
|
|
378
|
+
lines: string[],
|
|
379
|
+
touch: TouchWiring,
|
|
380
|
+
display: ZephyrDisplayProfile | undefined,
|
|
381
|
+
): void {
|
|
382
|
+
const bus = display?.busLabel ?? 'spi2';
|
|
383
|
+
const cs = touch.cs ?? DEFAULT_XPT2046_CS;
|
|
384
|
+
const irq = touch.irq ?? DEFAULT_XPT2046_IRQ;
|
|
385
|
+
const cal = touch.calibration;
|
|
386
|
+
// ESP32-S3 GPIOs 0-31 are on gpio0, 32-48 on gpio1.
|
|
387
|
+
const gpioController = (pin: number) => pin <= 31 ? 'gpio0' : 'gpio1';
|
|
388
|
+
const zThreshold = touch.minPressure ?? 400;
|
|
389
|
+
// touchscreen-size-* describe the panel the touch layer sits on (the display
|
|
390
|
+
// profile's effective size); a touch-only build falls back to the 12-bit
|
|
391
|
+
// full-scale range so the binding's required props still resolve.
|
|
392
|
+
const sizeX = display?.width ?? cal?.xMax ?? 320;
|
|
393
|
+
const sizeY = display?.height ?? cal?.yMax ?? 240;
|
|
394
|
+
// The display block already wrote cs-gpios with both entries (its CS at
|
|
395
|
+
// index 0, the touch CS at index 1). When there is no display block, enable
|
|
396
|
+
// the bus here with the touch CS as the only entry.
|
|
397
|
+
if (!display) {
|
|
398
|
+
lines.push(`&${bus} {`);
|
|
399
|
+
lines.push(' status = "okay";');
|
|
400
|
+
lines.push(` cs-gpios = <&${gpioController(cs)} ${cs} GPIO_ACTIVE_LOW>;`);
|
|
401
|
+
lines.push('};');
|
|
402
|
+
lines.push('');
|
|
403
|
+
}
|
|
404
|
+
lines.push(`&${bus} {`);
|
|
405
|
+
lines.push(' xpt2046: xpt2046@1 {');
|
|
406
|
+
lines.push(' compatible = "xptek,xpt2046";');
|
|
407
|
+
lines.push(' reg = <1>;');
|
|
408
|
+
// The XPT2046 datasheet max SPI clock is 2.5MHz — the panel bus may run at
|
|
409
|
+
// 80MHz, but this node's spi-max-frequency gates only its own transactions
|
|
410
|
+
// (the adapter's SPI_DT_SPEC picks it up).
|
|
411
|
+
lines.push(' spi-max-frequency = <2500000>;');
|
|
412
|
+
lines.push(` int-gpios = <&${gpioController(irq)} ${irq} GPIO_ACTIVE_LOW>;`);
|
|
413
|
+
lines.push(` touchscreen-size-x = <${sizeX}>;`);
|
|
414
|
+
lines.push(` touchscreen-size-y = <${sizeY}>;`);
|
|
415
|
+
lines.push(` min-x = <${cal?.xMin ?? 0}>;`);
|
|
416
|
+
lines.push(` max-x = <${cal?.xMax ?? 4095}>;`);
|
|
417
|
+
lines.push(` min-y = <${cal?.yMin ?? 0}>;`);
|
|
418
|
+
lines.push(` max-y = <${cal?.yMax ?? 4095}>;`);
|
|
419
|
+
lines.push(` z-threshold = <${zThreshold}>;`);
|
|
420
|
+
lines.push(' };');
|
|
421
|
+
lines.push('};');
|
|
422
|
+
lines.push('');
|
|
423
|
+
}
|
|
@@ -113,9 +113,13 @@ export default defineFrameworkManifest({
|
|
|
113
113
|
},
|
|
114
114
|
},
|
|
115
115
|
dac: {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
// ESP32 DAC (2× 8-bit channels on GPIO25/26) via the Zephyr DAC driver
|
|
117
|
+
// (dac_channel_setup + dac_write_value). nRF52840 / ESP32-S3 have no DAC;
|
|
118
|
+
// usage there lowers to a comment and profileDiagnostics flags it
|
|
119
|
+
// (zephyr-dac-pin-unavailable).
|
|
120
|
+
supported: true,
|
|
121
|
+
partialCoverage: true,
|
|
122
|
+
ops: { 'dac.write': 'supported' },
|
|
119
123
|
},
|
|
120
124
|
interrupts: {
|
|
121
125
|
supported: true,
|
|
@@ -285,9 +289,14 @@ export default defineFrameworkManifest({
|
|
|
285
289
|
},
|
|
286
290
|
display: {
|
|
287
291
|
supported: true,
|
|
288
|
-
partialCoverage:
|
|
289
|
-
|
|
290
|
-
|
|
292
|
+
partialCoverage: true,
|
|
293
|
+
// Partial: mono profiles (ssd1306-zephyr) drive display.* ops via the
|
|
294
|
+
// direct GFX runtime only — no CuttlefishGFX UI rendering path. The
|
|
295
|
+
// ILI9341 UI adapter shares the ST7796S direct-drive transport with a
|
|
296
|
+
// per-controller init table (16-bit RGB565 wire format); hardware-tuned
|
|
297
|
+
// on ST7796S only. E-ink panels are out of scope at this time.
|
|
298
|
+
unsupportedReason: 'Mono panels (ssd1306) are direct-op only (no UI rendering); ili9341 UI path is ported but not yet hardware-verified; e-ink is out of scope at this time.',
|
|
299
|
+
drivers: ['ili9341-zephyr', 'st7796-zephyr', 'ssd1306-zephyr'],
|
|
291
300
|
colorFormat: 'rgb565',
|
|
292
301
|
ops: {
|
|
293
302
|
'display.init': 'supported',
|
|
@@ -370,10 +379,17 @@ export default defineFrameworkManifest({
|
|
|
370
379
|
},
|
|
371
380
|
},
|
|
372
381
|
fs: {
|
|
373
|
-
|
|
374
|
-
|
|
382
|
+
// littlefs on the board's storage_partition, via <zephyr/fs/fs.h>. The
|
|
383
|
+
// shim mounts at /lfs lazily (formats on first use) and the HAL paths are
|
|
384
|
+
// treated as paths within the filesystem. Requires CONFIG_FILE_SYSTEM +
|
|
385
|
+
// CONFIG_FILE_SYSTEM_LITTLEFS (emitted by the scaffold when fs.* is used)
|
|
386
|
+
// and the storage_partition node.
|
|
387
|
+
supported: true,
|
|
375
388
|
partialCoverage: false,
|
|
376
|
-
ops:
|
|
389
|
+
ops: {
|
|
390
|
+
'fs.begin': 'supported', 'fs.read_text': 'supported', 'fs.write_text': 'supported',
|
|
391
|
+
'fs.exists': 'supported', 'fs.remove': 'supported',
|
|
392
|
+
},
|
|
377
393
|
},
|
|
378
394
|
mdns: {
|
|
379
395
|
supported: false,
|
|
@@ -410,10 +426,17 @@ export default defineFrameworkManifest({
|
|
|
410
426
|
ops: { 'temp.read': 'unsupported' },
|
|
411
427
|
},
|
|
412
428
|
hwtimer: {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
429
|
+
// Hardware timers via the Zephyr counter driver (<zephyr/drivers/counter.h>).
|
|
430
|
+
// set_frequency → top value (counter_freq/hz) + on_overflow callback;
|
|
431
|
+
// start arms both; stop halts. A chip declares its free counters
|
|
432
|
+
// (e.g. nRF RTC1; RTC0 is kernel-owned). This is distinct from the JS
|
|
433
|
+
// setInterval/setTimeout k_timer polyfill, which is unaffected.
|
|
434
|
+
supported: true,
|
|
435
|
+
partialCoverage: true,
|
|
436
|
+
ops: {
|
|
437
|
+
'hwtimer.set_frequency': 'supported', 'hwtimer.on_overflow': 'supported',
|
|
438
|
+
'hwtimer.start': 'supported', 'hwtimer.stop': 'supported',
|
|
439
|
+
},
|
|
417
440
|
},
|
|
418
441
|
capacitive: {
|
|
419
442
|
// FT6336U capacitive touch is handled via the strategy-owned touch adapter
|
|
@@ -481,6 +504,9 @@ export default defineFrameworkManifest({
|
|
|
481
504
|
polyfills: {
|
|
482
505
|
emitted: [
|
|
483
506
|
{ id: 'cuttlefish_halt', domain: 'standard', notes: 'Mapped to a k_msleep halt loop (exceptions disabled)' },
|
|
507
|
+
{ id: 'wiring_compat', domain: 'standard', notes: 'HIGH/LOW/digitalRead/etc. macros routing Wiring tokens (referenced unconditionally by the UI runtime header) to the __tc_gpio_* helpers' },
|
|
508
|
+
{ id: 'string_methods', domain: 'embedded', notes: 'STL-free __tc_* string helpers (const char*, inline ASCII case conv, <cstring> only)' },
|
|
509
|
+
{ id: 'static_array', domain: 'embedded', notes: 'STL-free __tc_StaticArray<T,N> wrapper for no-<vector> mutated/struct array literals' },
|
|
484
510
|
{ id: 'timer_methods', domain: 'embedded', notes: 'k_timer + k_work pool (system workqueue); callbacks run in thread context' },
|
|
485
511
|
{ id: 'async_runtime', domain: 'embedded', notes: 'Heap-free static Promise/microtask runtime (generateStaticAsyncRuntime), pumped in loop()' },
|
|
486
512
|
],
|
|
@@ -489,7 +515,7 @@ export default defineFrameworkManifest({
|
|
|
489
515
|
|
|
490
516
|
toolchain: {
|
|
491
517
|
backend: 'west',
|
|
492
|
-
operations: { prepare: true, compile: true, upload: true, monitor: true },
|
|
518
|
+
operations: { prepare: true, compile: true, upload: true, monitor: true, debug: true },
|
|
493
519
|
},
|
|
494
520
|
|
|
495
521
|
libraryResolution: {
|
|
@@ -537,9 +563,9 @@ export default defineFrameworkManifest({
|
|
|
537
563
|
// pure string-snapshot tests (no hardware); they are the safety net that
|
|
538
564
|
// catches regressions like silent pull-resistor / interrupt no-ops.
|
|
539
565
|
halResolutionTests: [
|
|
540
|
-
'adc', 'ble', 'board', 'dac', '
|
|
541
|
-
'
|
|
542
|
-
'uart', 'wdt', 'worker',
|
|
566
|
+
'adc', 'ble', 'board', 'dac', 'fs', 'gpio', 'http', 'hwtimer', 'i2c',
|
|
567
|
+
'interrupts', 'mqtt', 'power', 'preferences', 'pulse', 'pwm', 'random',
|
|
568
|
+
'spi', 'timing', 'tone', 'uart', 'wdt', 'worker',
|
|
543
569
|
],
|
|
544
570
|
},
|
|
545
571
|
|
|
@@ -555,4 +581,8 @@ export default defineFrameworkManifest({
|
|
|
555
581
|
// `cuttlefish doctor` prints the detected Zephyr version + compat result and
|
|
556
582
|
// previews how the configured board target resolves for that version.
|
|
557
583
|
doctor: { available: true },
|
|
584
|
+
|
|
585
|
+
// `cuttlefish licenses` enumerates the Zephyr kernel + west manifest projects
|
|
586
|
+
// and resolves each one's SPDX license (mirrors framework-arduino).
|
|
587
|
+
licenses: { available: true },
|
|
558
588
|
});
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,12 @@ export { Toolchain } from './toolchain/index.js';
|
|
|
16
16
|
// mod.doctor (see framework-package.ts).
|
|
17
17
|
export { runDoctor as doctor } from './doctor.js';
|
|
18
18
|
|
|
19
|
+
// `cuttlefish licenses` — enumerate the Zephyr kernel + west manifest projects
|
|
20
|
+
// and resolve each one's SPDX license. Re-exported under the dispatcher-facing
|
|
21
|
+
// alias `licenses` so the loader picks it up as mod.licenses (see
|
|
22
|
+
// framework-package.ts). Mirrors framework-arduino's presenter.
|
|
23
|
+
export { runLicensesPresenter as licenses } from './licenses.js';
|
|
24
|
+
|
|
19
25
|
// Chip descriptor registry (for downstream tooling / additional boards).
|
|
20
26
|
export {
|
|
21
27
|
chipForTarget,
|