@typecad/framework-zephyr 1.0.0-alpha.13 → 1.0.0-alpha.15
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/README.md +22 -35
- package/dist/as-built.d.ts +33 -0
- package/dist/as-built.js +188 -0
- package/dist/async/timer-polyfill.js +1 -1
- package/dist/boardgen.d.ts +128 -0
- package/dist/boardgen.js +1366 -0
- package/dist/chips/board-overrides.d.ts +7 -0
- package/dist/chips/board-overrides.js +11 -0
- package/dist/chips/controllers.d.ts +28 -8
- package/dist/chips/controllers.js +49 -12
- package/dist/chips/esp32s3.js +49 -0
- package/dist/chips/index.d.ts +6 -12
- package/dist/chips/index.js +18 -34
- package/dist/chips/resolve.d.ts +16 -2
- package/dist/chips/resolve.js +298 -15
- package/dist/chips/soc/.d.ts +2 -0
- package/dist/chips/soc/.js +129 -0
- package/dist/chips/soc/esp32.d.ts +2 -0
- package/dist/chips/soc/esp32.js +120 -0
- package/dist/chips/soc/esp32c3.d.ts +2 -0
- package/dist/chips/soc/esp32c3.js +90 -0
- package/dist/chips/soc/esp32c6.d.ts +2 -0
- package/dist/chips/soc/esp32c6.js +109 -0
- package/dist/chips/soc/esp32s3.d.ts +2 -0
- package/dist/chips/soc/esp32s3.js +189 -0
- package/dist/chips/soc/index.d.ts +2 -0
- package/dist/chips/soc/index.js +23 -0
- package/dist/chips/soc/nrf52840.d.ts +2 -0
- package/dist/chips/soc/nrf52840.js +130 -0
- package/dist/chips/soc/rp2040.d.ts +2 -0
- package/dist/chips/soc/rp2040.js +141 -0
- package/dist/chips/soc/rp2350a.d.ts +2 -0
- package/dist/chips/soc/rp2350a.js +145 -0
- package/dist/chips/soc/samd21g18a.d.ts +2 -0
- package/dist/chips/soc/samd21g18a.js +143 -0
- package/dist/chips/soc/stm32f411xe.d.ts +2 -0
- package/dist/chips/soc/stm32f411xe.js +251 -0
- package/dist/chips/types.d.ts +382 -12
- package/dist/chips/xiao-ble.js +33 -0
- package/dist/display/profiles.js +1 -1
- package/dist/doctor.js +38 -4
- package/dist/dt-config/custom-board.d.ts +23 -0
- package/dist/dt-config/custom-board.js +227 -0
- package/dist/dt-config/kconfig.d.ts +83 -1
- package/dist/dt-config/kconfig.js +116 -27
- package/dist/dt-config/overlay.js +623 -18
- package/dist/framework.manifest.d.ts +20 -30
- package/dist/framework.manifest.js +124 -178
- package/dist/index.d.ts +4 -1
- package/dist/index.js +8 -2
- package/dist/lowering/adc.d.ts +26 -5
- package/dist/lowering/adc.js +137 -31
- package/dist/lowering/ble.js +31 -28
- package/dist/lowering/dac.js +9 -9
- package/dist/lowering/fs.js +18 -10
- package/dist/lowering/gpio.d.ts +2 -0
- package/dist/lowering/gpio.js +90 -10
- package/dist/lowering/http.js +39 -14
- package/dist/lowering/hwtimer.d.ts +4 -0
- package/dist/lowering/hwtimer.js +35 -10
- package/dist/lowering/i2c.js +46 -54
- package/dist/lowering/index.d.ts +5 -5
- package/dist/lowering/index.js +15 -16
- package/dist/lowering/interrupts.d.ts +22 -5
- package/dist/lowering/interrupts.js +104 -22
- package/dist/lowering/mqtt.js +12 -6
- package/dist/lowering/power.js +0 -4
- package/dist/lowering/preferences.js +49 -77
- package/dist/lowering/pulse.js +5 -36
- package/dist/lowering/pwm.d.ts +32 -3
- package/dist/lowering/pwm.js +105 -17
- package/dist/lowering/random.js +3 -3
- package/dist/lowering/sensor.d.ts +37 -0
- package/dist/lowering/sensor.js +119 -0
- package/dist/lowering/spi.d.ts +12 -0
- package/dist/lowering/spi.js +65 -40
- package/dist/lowering/thread.d.ts +14 -0
- package/dist/lowering/thread.js +55 -0
- package/dist/lowering/timing.js +20 -46
- package/dist/lowering/tone.js +18 -5
- package/dist/lowering/uart.d.ts +13 -0
- package/dist/lowering/uart.js +72 -51
- package/dist/lowering/usb.d.ts +34 -0
- package/dist/lowering/usb.js +206 -0
- package/dist/lowering/wdt.d.ts +1 -1
- package/dist/lowering/wdt.js +17 -7
- package/dist/lowering/wifi.d.ts +3 -2
- package/dist/lowering/wifi.js +120 -111
- package/dist/sdk/board-catalog-sync.d.ts +16 -0
- package/dist/sdk/board-catalog-sync.js +41 -0
- package/dist/sdk/board-data.generated.d.ts +2 -0
- package/dist/sdk/board-data.generated.js +4 -0
- package/dist/sdk/catalog-walker.d.ts +90 -0
- package/dist/sdk/catalog-walker.js +682 -0
- package/dist/sdk/dts-reader.d.ts +83 -0
- package/dist/sdk/dts-reader.js +596 -0
- package/dist/strategy.d.ts +136 -17
- package/dist/strategy.js +881 -212
- package/dist/toolchain/bossac-touch.d.ts +18 -0
- package/dist/toolchain/bossac-touch.js +88 -0
- package/dist/toolchain/compat.d.ts +2 -2
- package/dist/toolchain/compat.js +8 -3
- package/dist/toolchain/debug-config.d.ts +21 -26
- package/dist/toolchain/debug-config.js +212 -72
- package/dist/toolchain/env-check.d.ts +4 -4
- package/dist/toolchain/env-check.js +5 -5
- package/dist/toolchain/index.d.ts +66 -1
- package/dist/toolchain/index.js +713 -58
- package/dist/toolchain/scaffold.d.ts +9 -0
- package/dist/toolchain/scaffold.js +84 -7
- package/dist/toolchain/west-discover.d.ts +8 -1
- package/dist/toolchain/west-discover.js +19 -6
- package/dist/toolchain/west-spawn.js +17 -5
- package/installer/CHANGELOG.md +473 -0
- package/installer/README.md +328 -0
- package/installer/environment.yml +46 -0
- package/installer/etc/conda/activate.d/zephyr.bat +7 -0
- package/installer/etc/conda/activate.d/zephyr.ps1 +12 -0
- package/installer/etc/conda/activate.d/zephyr.sh +20 -0
- package/installer/etc/conda/deactivate.d/zephyr.bat +6 -0
- package/installer/etc/conda/deactivate.d/zephyr.ps1 +6 -0
- package/installer/etc/conda/deactivate.d/zephyr.sh +4 -0
- package/installer/install.mjs +580 -0
- package/installer/install.ps1 +619 -0
- package/installer/install.sh +310 -0
- package/installer/lib/detect-platform.sh +62 -0
- package/installer/lib/fetch-sdk.sh +304 -0
- package/installer/lib/init-workspace.sh +153 -0
- package/installer/lib/write-activation.sh +76 -0
- package/installer/patches/tfm-c-include-separators.patch +19 -0
- package/installer/patches/zephyr-tfm-nordic-zephyr-include.patch +24 -0
- package/installer/templates/project/.typecad/activate-zephyr.ps1 +31 -0
- package/installer/templates/project/.typecad/activate-zephyr.sh +31 -0
- package/installer/templates/project/.vscode/settings.json +30 -0
- package/installer/templates/project/README.md +58 -0
- package/installer/versions.env +110 -0
- package/package.json +16 -16
- package/src/as-built.ts +206 -0
- package/src/boardgen.ts +1428 -0
- package/src/chips/controllers.ts +61 -12
- package/src/chips/index.ts +35 -54
- package/src/chips/resolve.ts +316 -14
- package/src/chips/types.ts +388 -13
- package/src/display/profiles.ts +1 -1
- package/src/doctor.ts +110 -77
- package/src/dt-config/custom-board.ts +325 -0
- package/src/dt-config/kconfig.ts +177 -19
- package/src/dt-config/overlay.ts +1058 -450
- package/src/framework.manifest.ts +125 -178
- package/src/index.ts +57 -41
- package/src/lowering/adc.ts +222 -102
- package/src/lowering/ble.ts +32 -28
- package/src/lowering/dac.ts +82 -82
- package/src/lowering/fs.ts +18 -10
- package/src/lowering/gpio.ts +242 -152
- package/src/lowering/http.ts +512 -488
- package/src/lowering/hwtimer.ts +139 -101
- package/src/lowering/i2c.ts +116 -126
- package/src/lowering/index.ts +91 -93
- package/src/lowering/interrupts.ts +113 -21
- package/src/lowering/mqtt.ts +12 -6
- package/src/lowering/preferences.ts +327 -354
- package/src/lowering/pwm.ts +167 -74
- package/src/lowering/random.ts +3 -3
- package/src/lowering/sensor.ts +155 -0
- package/src/lowering/spi.ts +164 -124
- package/src/lowering/thread.ts +63 -0
- package/src/lowering/timing.ts +46 -72
- package/src/lowering/uart.ts +73 -51
- package/src/lowering/usb.ts +221 -0
- package/src/lowering/wdt.ts +95 -84
- package/src/lowering/wifi.ts +120 -111
- package/src/sdk/board-catalog-sync.ts +62 -0
- package/src/strategy.ts +888 -229
- package/src/toolchain/bossac-touch.ts +112 -0
- package/src/toolchain/compat.ts +8 -3
- package/src/toolchain/debug-config.ts +666 -522
- package/src/toolchain/env-check.ts +9 -9
- package/src/toolchain/index.ts +765 -44
- package/src/toolchain/scaffold.ts +81 -7
- package/src/toolchain/west-discover.ts +334 -316
- package/src/toolchain/west-spawn.ts +17 -5
- package/src/async/timer-polyfill.ts +0 -107
- package/src/chips/esp32.ts +0 -74
- package/src/chips/esp32s3.ts +0 -57
- package/src/chips/xiao-ble.ts +0 -70
- package/src/lowering/power.ts +0 -70
- package/src/lowering/pulse.ts +0 -93
- package/src/lowering/tone.ts +0 -60
- package/src/lowering/worker-backing.ts +0 -94
- package/src/lowering/worker.ts +0 -17
package/src/lowering/fs.ts
CHANGED
|
@@ -34,21 +34,29 @@ export function fsInitLines(): string[] {
|
|
|
34
34
|
'FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(__tc_fs_data);',
|
|
35
35
|
'static struct fs_mount_t __tc_fs_mp_init = {',
|
|
36
36
|
' .type = FS_LITTLEFS,',
|
|
37
|
+
' .mnt_point = "/lfs",',
|
|
37
38
|
' .fs_data = &__tc_fs_data,',
|
|
38
39
|
' .storage_dev = (void *)FIXED_PARTITION_ID(storage_partition),',
|
|
39
|
-
' .mnt_point = "/lfs",',
|
|
40
40
|
'};',
|
|
41
41
|
'',
|
|
42
42
|
'static void __tc_fs_ensure_mount(void) {',
|
|
43
43
|
' if (__tc_fs_mounted) return;',
|
|
44
44
|
' __tc_fs_mp = __tc_fs_mp_init;',
|
|
45
45
|
' int rc = fs_mount(&__tc_fs_mp);',
|
|
46
|
-
' if (rc
|
|
47
|
-
' //
|
|
46
|
+
' if (rc != 0) {',
|
|
47
|
+
' // Any mount failure with a valid config means the partition is',
|
|
48
|
+
' // unformatted or corrupt (littlefs reports -EIO on erased flash,',
|
|
49
|
+
' // not only -ENODATA/-EINVAL) — format it and remount once.',
|
|
48
50
|
' (void)fs_mkfs(FS_LITTLEFS, static_cast<uintptr_t>(FIXED_PARTITION_ID(storage_partition)), NULL, 0);',
|
|
49
|
-
'
|
|
51
|
+
' rc = fs_mount(&__tc_fs_mp);',
|
|
52
|
+
' }',
|
|
53
|
+
' if (rc == 0) {',
|
|
54
|
+
' __tc_fs_mounted = true;',
|
|
55
|
+
' } else {',
|
|
56
|
+
' char __tc_fs_err[48];',
|
|
57
|
+
' (void)snprintf(__tc_fs_err, sizeof(__tc_fs_err), "cuttlefish-fs: mount failed rc=%d", rc);',
|
|
58
|
+
' __tc_println(__tc_fs_err);',
|
|
50
59
|
' }',
|
|
51
|
-
' __tc_fs_mounted = true;',
|
|
52
60
|
'}',
|
|
53
61
|
'',
|
|
54
62
|
'// Join the mount point with the user path (paths are within the FS).',
|
|
@@ -69,8 +77,11 @@ export function fsInitLines(): string[] {
|
|
|
69
77
|
' struct fs_file_t f;',
|
|
70
78
|
' fs_file_t_init(&f);',
|
|
71
79
|
' if (fs_open(&f, __tc_fs_path(path), FS_O_READ) == 0) {',
|
|
72
|
-
'
|
|
73
|
-
'
|
|
80
|
+
' // Terminate at the READ length: the buffer is static and shared',
|
|
81
|
+
' // across reads, so bytes from a longer previous file survive a',
|
|
82
|
+
' // short read otherwise.',
|
|
83
|
+
' ssize_t n = fs_read(&f, buf, sizeof(buf) - 1);',
|
|
84
|
+
' buf[(n > 0) ? n : 0] = 0;',
|
|
74
85
|
' (void)fs_close(&f);',
|
|
75
86
|
' }',
|
|
76
87
|
' return buf;',
|
|
@@ -107,9 +118,6 @@ export function fsInitLines(): string[] {
|
|
|
107
118
|
export function lowerFs(op: HALOpIR): { code?: string; expression?: string } {
|
|
108
119
|
const o = op as any;
|
|
109
120
|
switch (op.operation) {
|
|
110
|
-
case 'fs.begin':
|
|
111
|
-
// No payload (the op carries only its discriminator).
|
|
112
|
-
return { code: 'return __tc_fs_begin();' };
|
|
113
121
|
case 'fs.read_text':
|
|
114
122
|
return { code: `return __tc_fs_read_text(${o.path});` };
|
|
115
123
|
case 'fs.write_text':
|
package/src/lowering/gpio.ts
CHANGED
|
@@ -1,152 +1,242 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// GPIO lowering — devicetree-spec bridge
|
|
3
|
-
//
|
|
4
|
-
// Translates HAL gpio.* ops to Zephyr driver C++. Two addressing modes:
|
|
5
|
-
//
|
|
6
|
-
// 1. Devicetree spec (preferred): if the HAL pin matches a dtSpec in the
|
|
7
|
-
// active chip descriptor, emit gpio_pin_*_dt() calls against a
|
|
8
|
-
// `__tc_dt_<alias>` gpio_dt_spec. This honors the node's polarity flags
|
|
9
|
-
// (GPIO_ACTIVE_LOW), so logical value 1 = LED on for an active-low LED.
|
|
10
|
-
//
|
|
11
|
-
// 2. Raw fallback: pins without a dtSpec are addressed via the SoC's gpio
|
|
12
|
-
// controller node (DEVICE_DT_GET(DT_NODELABEL(gpio0))) and the
|
|
13
|
-
// gpio_pin_*_raw() API. Polarity is physical (raw bypasses DT flags).
|
|
14
|
-
// The manifest validator's probe (which sends {operation, pin:0} with no
|
|
15
|
-
// port) hits this path, so it must return a lowered result, not undefined.
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
19
|
-
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
20
|
-
import { controllerNodelabelForPin } from '../chips/controllers.js';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (m === '
|
|
55
|
-
return '';
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// GPIO lowering — devicetree-spec bridge
|
|
3
|
+
//
|
|
4
|
+
// Translates HAL gpio.* ops to Zephyr driver C++. Two addressing modes:
|
|
5
|
+
//
|
|
6
|
+
// 1. Devicetree spec (preferred): if the HAL pin matches a dtSpec in the
|
|
7
|
+
// active chip descriptor, emit gpio_pin_*_dt() calls against a
|
|
8
|
+
// `__tc_dt_<alias>` gpio_dt_spec. This honors the node's polarity flags
|
|
9
|
+
// (GPIO_ACTIVE_LOW), so logical value 1 = LED on for an active-low LED.
|
|
10
|
+
//
|
|
11
|
+
// 2. Raw fallback: pins without a dtSpec are addressed via the SoC's gpio
|
|
12
|
+
// controller node (DEVICE_DT_GET(DT_NODELABEL(gpio0))) and the
|
|
13
|
+
// gpio_pin_*_raw() API. Polarity is physical (raw bypasses DT flags).
|
|
14
|
+
// The manifest validator's probe (which sends {operation, pin:0} with no
|
|
15
|
+
// port) hits this path, so it must return a lowered result, not undefined.
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
19
|
+
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
20
|
+
import { controllerNodelabelForPin, controllerRawPinForPin } from '../chips/controllers.js';
|
|
21
|
+
import { ZEPHYR_GPIO_FLAGS } from '@typecad/hal';
|
|
22
|
+
|
|
23
|
+
/** The C identifier emitted for a pin's gpio_dt_spec variable. */
|
|
24
|
+
export function dtSpecVarName(dtSpec: string): string {
|
|
25
|
+
return `__tc_dt_${dtSpec}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Look up a dtSpec by GPIO pin number; undefined if the pin has none. */
|
|
29
|
+
function findDtSpec(chip: ZephyrChipDescriptor, pin: number) {
|
|
30
|
+
return chip.gpio.dtSpecs.find((s) => s.pin === pin);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// HAL passes UPPERCASE modes ("OUTPUT") while docs say lowercase ("output").
|
|
34
|
+
// The *_pullup / *_pulldown modes map to GPIO_INPUT (Zephyr does not have
|
|
35
|
+
// separate input+pull mode flags) and OR in a GPIO_PULL_UP / GPIO_PULL_DOWN
|
|
36
|
+
// bit via `dtFlagsForMode` — without that bit the pin floats, so INPUT_PULLUP
|
|
37
|
+
// was a silent no-op (bug B1). Mirrors the gpio_pullup_en/gpio_pulldown_en
|
|
38
|
+
// extras framework-esp32 emits for the same modes.
|
|
39
|
+
const MODE_MAP: Record<string, string> = {
|
|
40
|
+
output: 'GPIO_OUTPUT',
|
|
41
|
+
OUTPUT: 'GPIO_OUTPUT',
|
|
42
|
+
input: 'GPIO_INPUT',
|
|
43
|
+
INPUT: 'GPIO_INPUT',
|
|
44
|
+
input_pullup: 'GPIO_INPUT',
|
|
45
|
+
INPUT_PULLUP: 'GPIO_INPUT',
|
|
46
|
+
input_pulldown: 'GPIO_INPUT',
|
|
47
|
+
INPUT_PULLDOWN: 'GPIO_INPUT',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** Additional DT flag bits for a HAL mode, OR'd into the configure flags.
|
|
51
|
+
* Returns '' for modes with no extra bits so the join leaves the mode alone. */
|
|
52
|
+
function dtFlagsForMode(mode: string): string {
|
|
53
|
+
const m = (mode ?? '').toLowerCase();
|
|
54
|
+
if (m === 'input_pullup') return ' | GPIO_PULL_UP';
|
|
55
|
+
if (m === 'input_pulldown') return ' | GPIO_PULL_DOWN';
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Combined mode + pull flags for a HAL mode string, e.g.
|
|
60
|
+
* 'INPUT_PULLUP' → 'GPIO_INPUT | GPIO_PULL_UP'. */
|
|
61
|
+
function flagsForMode(mode: string): string {
|
|
62
|
+
const base = MODE_MAP[mode] ?? 'GPIO_INPUT';
|
|
63
|
+
return base + dtFlagsForMode(mode);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── Thin GPIO (hal/gpio-pin.ts) — flag tokens ─────────────────────────────
|
|
67
|
+
//
|
|
68
|
+
// "GPIO.OUTPUT | GPIO.PULL_UP" token text maps name-for-name onto the GPIO_*
|
|
69
|
+
// macros. The name set comes from the GENERATED Zephyr token table (parsed
|
|
70
|
+
// from the pinned tree's headers); unknown tokens are build errors listing
|
|
71
|
+
// the valid spellings — the sensor-catalog discipline.
|
|
72
|
+
|
|
73
|
+
const GPIO_FLAG_TOKENS: Record<string, string> = Object.fromEntries(
|
|
74
|
+
ZEPHYR_GPIO_FLAGS.map((f) => [`GPIO.${f}`, `GPIO_${f}`]),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
/** Map thin-GPIO flag token text to the GPIO_* macro expression. */
|
|
78
|
+
export function gpioFlagsToMacros(flags: string): string {
|
|
79
|
+
const tokens = String(flags ?? '')
|
|
80
|
+
.split('|')
|
|
81
|
+
.map((t) => t.trim())
|
|
82
|
+
.filter(Boolean);
|
|
83
|
+
if (tokens.length === 0) return 'GPIO_INPUT';
|
|
84
|
+
const macros = tokens.map((t) => {
|
|
85
|
+
const m = GPIO_FLAG_TOKENS[t];
|
|
86
|
+
if (!m) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`GPIO flag '${t}' is not a known GPIO.* token — valid: ${Object.keys(GPIO_FLAG_TOKENS).join(', ')}.`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return m;
|
|
92
|
+
});
|
|
93
|
+
return macros.join(' | ');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Guarded per-pin configure statement for the dt-spec path: construction
|
|
97
|
+
* flags apply exactly once, ahead of the first use. */
|
|
98
|
+
function dtSpecConfigure(varName: string, dtSpec: string, flags: string): string {
|
|
99
|
+
return `{ ${dtSpecGuardConfigure(varName, dtSpec, flags)} }`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The guard body only (no wrapping braces) — for fusing into
|
|
103
|
+
* statement-expressions. */
|
|
104
|
+
function dtSpecGuardConfigure(varName: string, dtSpec: string, flags: string): string {
|
|
105
|
+
const done = `__tc_gpio_cfg_${dtSpec.replace(/-/g, '_')}_done`;
|
|
106
|
+
return `static bool ${done} = false; if (!${done}) { gpio_pin_configure_dt(&${varName}, ${gpioFlagsToMacros(flags)}); ${done} = true; }`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Guarded per-pin configure statement for the raw-controller path. */
|
|
110
|
+
function rawConfigure(controller: string, rawPin: number, pin: number, flags: string): string {
|
|
111
|
+
return `{ ${rawGuardConfigure(controller, rawPin, pin, flags)} }`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The raw-path guard body only — for fusing into statement-expressions. */
|
|
115
|
+
function rawGuardConfigure(controller: string, rawPin: number, pin: number, flags: string): string {
|
|
116
|
+
const done = `__tc_gpio_cfg_raw${pin}_done`;
|
|
117
|
+
return `static bool ${done} = false; if (!${done}) { gpio_pin_configure(${controller}, ${rawPin}, ${gpioFlagsToMacros(flags)}); ${done} = true; }`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a HAL gpio.* op to Zephyr C++.
|
|
122
|
+
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
|
123
|
+
*/
|
|
124
|
+
export function lowerGpio(
|
|
125
|
+
op: HALOpIR,
|
|
126
|
+
chip: ZephyrChipDescriptor,
|
|
127
|
+
): { code?: string; expression?: string } {
|
|
128
|
+
const o = op as any;
|
|
129
|
+
const pin: number = o.pin;
|
|
130
|
+
const spec = findDtSpec(chip, pin);
|
|
131
|
+
|
|
132
|
+
if (spec) {
|
|
133
|
+
return lowerGpioDtSpec(op, spec.dtSpec);
|
|
134
|
+
}
|
|
135
|
+
return lowerGpioRaw(op, chip);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Devicetree-spec path — polarity-correct via gpio_pin_*_dt(). */
|
|
139
|
+
function lowerGpioDtSpec(
|
|
140
|
+
op: HALOpIR,
|
|
141
|
+
dtSpec: string,
|
|
142
|
+
): { code?: string; expression?: string } {
|
|
143
|
+
const o = op as any;
|
|
144
|
+
const varName = dtSpecVarName(dtSpec);
|
|
145
|
+
|
|
146
|
+
switch (op.operation) {
|
|
147
|
+
case 'gpio.configure':
|
|
148
|
+
// Thin GPIO: construction flags, applied once per pin (guard).
|
|
149
|
+
return { code: dtSpecConfigure(varName, dtSpec, o.flags) };
|
|
150
|
+
case 'gpio.read_cfg':
|
|
151
|
+
// Thin GPIO get(): the guarded configure FUSED into the read — one
|
|
152
|
+
// statement-expression, correct in any expression position (a method's
|
|
153
|
+
// leading side-effect ops are dropped when the call sits in a pure
|
|
154
|
+
// expression, e.g. an if-condition).
|
|
155
|
+
return {
|
|
156
|
+
expression: `({ ${dtSpecGuardConfigure(varName, dtSpec, o.flags)} gpio_pin_get_dt(&${varName}); })`,
|
|
157
|
+
};
|
|
158
|
+
case 'gpio.write': {
|
|
159
|
+
// Literal 0/1 stays as-is; runtime expression coerced to int via ternary.
|
|
160
|
+
const v = o.value;
|
|
161
|
+
const rhs = typeof v === 'string' ? `((${v}) ? 1 : 0)` : v ? 1 : 0;
|
|
162
|
+
return { code: `gpio_pin_set_dt(&${varName}, ${rhs});` };
|
|
163
|
+
}
|
|
164
|
+
case 'gpio.read':
|
|
165
|
+
return { expression: `gpio_pin_get_dt(&${varName})` };
|
|
166
|
+
case 'gpio.toggle':
|
|
167
|
+
return { code: `gpio_pin_toggle_dt(&${varName});` };
|
|
168
|
+
default:
|
|
169
|
+
throw new Error(
|
|
170
|
+
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
171
|
+
`Open an issue or use rawCpp() to emit it manually.`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Raw-controller path — for pins without a DT spec (and the manifest probe).
|
|
178
|
+
* Uses the SoC's primary GPIO controller node. Polarity is physical.
|
|
179
|
+
*/
|
|
180
|
+
function lowerGpioRaw(
|
|
181
|
+
op: HALOpIR,
|
|
182
|
+
chip: ZephyrChipDescriptor,
|
|
183
|
+
): { code?: string; expression?: string } {
|
|
184
|
+
const o = op as any;
|
|
185
|
+
const pin: number = o.pin;
|
|
186
|
+
// Resolve the owning controller by pin range (ESP32-S3 splits GPIO across
|
|
187
|
+
// gpio0/gpio1; STM32 across gpioa/gpiob/gpioc). For single-controller SoCs
|
|
188
|
+
// this is just chip.gpioController. The raw API takes the PORT-RELATIVE
|
|
189
|
+
// index (STM32 gpiob is 0-15), not the global HAL pin number.
|
|
190
|
+
const controller = `DEVICE_DT_GET(DT_NODELABEL(${controllerNodelabelForPin(chip, pin)}))`;
|
|
191
|
+
const rawPin = controllerRawPinForPin(chip, pin);
|
|
192
|
+
|
|
193
|
+
switch (op.operation) {
|
|
194
|
+
case 'gpio.configure':
|
|
195
|
+
// Thin GPIO: construction flags, applied once per pin (guard).
|
|
196
|
+
return { code: rawConfigure(controller, rawPin, pin, o.flags) };
|
|
197
|
+
case 'gpio.read_cfg':
|
|
198
|
+
// Fused guarded configure + raw read (see the dt-spec path above).
|
|
199
|
+
return {
|
|
200
|
+
expression: `({ ${rawGuardConfigure(controller, rawPin, pin, o.flags)} gpio_pin_get_raw(${controller}, ${rawPin}); })`,
|
|
201
|
+
};
|
|
202
|
+
case 'gpio.shift_out':
|
|
203
|
+
case 'gpio.shift_in': {
|
|
204
|
+
// Bit-bang over the raw-controller path (shift pairs are arbitrary
|
|
205
|
+
// pins): configure both once (guarded), then clock the bits. Zephyr
|
|
206
|
+
// verbs only — gpio_pin_set_raw / gpio_pin_get_raw / k_busy_wait.
|
|
207
|
+
const dataCtrl = `DEVICE_DT_GET(DT_NODELABEL(${controllerNodelabelForPin(chip, o.dataPin)}))`;
|
|
208
|
+
const dataRaw = controllerRawPinForPin(chip, o.dataPin);
|
|
209
|
+
const clkCtrl = `DEVICE_DT_GET(DT_NODELABEL(${controllerNodelabelForPin(chip, o.clockPin)}))`;
|
|
210
|
+
const clkRaw = controllerRawPinForPin(chip, o.clockPin);
|
|
211
|
+
const cfg = `{ static bool __tc_shf${o.dataPin}_${o.clockPin}_done = false; if (!__tc_shf${o.dataPin}_${o.clockPin}_done) { gpio_pin_configure(${dataCtrl}, ${dataRaw}, GPIO_INPUT); gpio_pin_configure(${clkCtrl}, ${clkRaw}, GPIO_OUTPUT); __tc_shf${o.dataPin}_${o.clockPin}_done = true; } }`;
|
|
212
|
+
if (op.operation === 'gpio.shift_out') {
|
|
213
|
+
return {
|
|
214
|
+
code: `${cfg} for (int __i = ${(o.msbFirst ?? true) ? '7' : '0'}; ${(o.msbFirst ?? true) ? '__i >= 0' : '__i < 8'}; ${(o.msbFirst ?? true) ? '__i--' : '__i++'}) { gpio_pin_set_raw(${dataCtrl}, ${dataRaw}, ((static_cast<uint8_t>(${o.value})) >> __i) & 1); gpio_pin_set_raw(${clkCtrl}, ${clkRaw}, 1); k_busy_wait(1); gpio_pin_set_raw(${clkCtrl}, ${clkRaw}, 0); }`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
expression: `({ ${cfg} uint8_t __b = 0; for (int __i = ${(o.msbFirst ?? true) ? '7' : '0'}; ${(o.msbFirst ?? true) ? '__i >= 0' : '__i < 8'}; ${(o.msbFirst ?? true) ? '__i--' : '__i++'}) { gpio_pin_set_raw(${clkCtrl}, ${clkRaw}, 1); k_busy_wait(1); __b = static_cast<uint8_t>((__b << 1) | (gpio_pin_get_raw(${dataCtrl}, ${dataRaw}) & 1)); gpio_pin_set_raw(${clkCtrl}, ${clkRaw}, 0); } __b; })`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
case 'gpio.write': {
|
|
222
|
+
const v = o.value;
|
|
223
|
+
const rhs = typeof v === 'string' ? `((${v}) ? 1 : 0)` : v ? 1 : 0;
|
|
224
|
+
return { code: `gpio_pin_set_raw(${controller}, ${rawPin}, ${rhs});` };
|
|
225
|
+
}
|
|
226
|
+
case 'gpio.read':
|
|
227
|
+
return { expression: `gpio_pin_get_raw(${controller}, ${rawPin})` };
|
|
228
|
+
case 'gpio.toggle':
|
|
229
|
+
// Native atomic toggle — never read-modify-write. gpio_pin_get_raw on
|
|
230
|
+
// a direction-only output reads the input latch, which is undefined on
|
|
231
|
+
// SoCs that don't latch it. Zephyr's toggle API has no _raw variant —
|
|
232
|
+
// gpio_pin_toggle is the driver-level atomic toggle, and for pins
|
|
233
|
+
// configured without GPIO_ACTIVE_LOW the logical level equals the
|
|
234
|
+
// physical one, so it matches the get_raw/set_raw used elsewhere.
|
|
235
|
+
return { code: `gpio_pin_toggle(${controller}, ${rawPin});` };
|
|
236
|
+
default:
|
|
237
|
+
throw new Error(
|
|
238
|
+
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
239
|
+
`Open an issue or use rawCpp() to emit it manually.`,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|