@typecad/framework-zephyr 1.0.0-alpha.14 → 1.0.0-alpha.16
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 -47
- 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/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 +267 -10
- 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 +319 -0
- package/dist/chips/xiao-ble.js +21 -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 +72 -1
- package/dist/dt-config/kconfig.js +115 -26
- package/dist/dt-config/overlay.js +548 -28
- package/dist/framework.manifest.d.ts +3 -3
- package/dist/framework.manifest.js +122 -185
- package/dist/index.d.ts +4 -1
- package/dist/index.js +8 -2
- package/dist/lowering/adc.d.ts +20 -2
- package/dist/lowering/adc.js +121 -29
- 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 +82 -5
- 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 +3 -5
- package/dist/lowering/power.js +0 -4
- package/dist/lowering/preferences.js +49 -77
- package/dist/lowering/pulse.js +0 -31
- package/dist/lowering/pwm.d.ts +12 -1
- package/dist/lowering/pwm.js +78 -14
- 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 +16 -4
- 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 +97 -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 +839 -222
- 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 +226 -76
- package/dist/toolchain/env-check.d.ts +4 -4
- package/dist/toolchain/env-check.js +5 -5
- package/dist/toolchain/index.d.ts +115 -1
- package/dist/toolchain/index.js +680 -71
- package/dist/toolchain/scaffold.js +39 -7
- package/dist/toolchain/west-discover.d.ts +4 -0
- package/dist/toolchain/west-discover.js +17 -6
- 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 +15 -15
- package/src/as-built.ts +206 -0
- package/src/boardgen.ts +1428 -0
- package/src/chips/index.ts +35 -54
- package/src/chips/resolve.ts +285 -10
- package/src/chips/types.ts +325 -1
- 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 +165 -18
- package/src/dt-config/overlay.ts +537 -25
- package/src/framework.manifest.ts +123 -185
- package/src/index.ts +57 -41
- package/src/lowering/adc.ts +222 -118
- 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 -155
- 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 +3 -5
- package/src/lowering/preferences.ts +327 -354
- package/src/lowering/pwm.ts +167 -99
- 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 +97 -112
- package/src/sdk/board-catalog-sync.ts +62 -0
- package/src/strategy.ts +848 -237
- package/src/toolchain/bossac-touch.ts +112 -0
- package/src/toolchain/compat.ts +8 -3
- package/src/toolchain/debug-config.ts +676 -522
- package/src/toolchain/env-check.ts +9 -9
- package/src/toolchain/index.ts +1359 -645
- package/src/toolchain/scaffold.ts +38 -7
- package/src/toolchain/west-discover.ts +19 -6
- 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 -82
- 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
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
// Runtime Exception (RUNTIME_EXCEPTION.md at the repo root).
|
|
30
30
|
// ---------------------------------------------------------------------------
|
|
31
31
|
/** Render a HAL field: pass through (already rendered by the resolver). */
|
|
32
|
+
function unq(v) {
|
|
33
|
+
return String(v).replace(/^"|"$/g, '');
|
|
34
|
+
}
|
|
32
35
|
function s(v) {
|
|
33
36
|
return String(v);
|
|
34
37
|
}
|
|
@@ -73,10 +76,7 @@ export function preferencesInitLines() {
|
|
|
73
76
|
` bool used;`,
|
|
74
77
|
`};`,
|
|
75
78
|
``,
|
|
76
|
-
`// Active namespace prefix ("tc/<ns>/"). begin() overwrites it; end() clears.`,
|
|
77
|
-
`// prefs_ns is deliberately sized to hold "tc/" + a 16-char ns + "/" + NUL.`,
|
|
78
79
|
`static struct {`,
|
|
79
|
-
` char ns[24];`,
|
|
80
80
|
` bool loaded;`,
|
|
81
81
|
` __tc_prefs_slot slots[__TC_PREFS_SLOT_COUNT];`,
|
|
82
82
|
`} __tc_prefs;`,
|
|
@@ -96,15 +96,18 @@ export function preferencesInitLines() {
|
|
|
96
96
|
` __tc_prefs.slots[i].len = static_cast<uint8_t>(got);`,
|
|
97
97
|
` // Type is encoded as the first byte of the stored value (see put_*).`,
|
|
98
98
|
` __tc_prefs.slots[i].type = __tc_prefs.slots[i].val[0];`,
|
|
99
|
-
`
|
|
99
|
+
` // h_set hands us the name RELATIVE to the handler's "tc"`,
|
|
100
|
+
` // subtree ("rig/marker") — the cache keys full names, so`,
|
|
101
|
+
` // re-attach the prefix or loaded entries never match a lookup.`,
|
|
102
|
+
` (void)snprintf(__tc_prefs.slots[i].key, __TC_PREFS_KEY_LEN, "tc/%s", name);`,
|
|
100
103
|
` __tc_prefs.slots[i].used = true;`,
|
|
101
104
|
` return 0;`,
|
|
102
105
|
` }`,
|
|
103
106
|
` }`,
|
|
104
107
|
` return 0; // cache full — silently drop (matches ESP32 NVS-full behavior)`,
|
|
105
108
|
`}`,
|
|
106
|
-
`static int __tc_prefs_h_get(const char*
|
|
107
|
-
` (void)
|
|
109
|
+
`static int __tc_prefs_h_get(const char* full, char* val, int val_len_max) {`,
|
|
110
|
+
` (void)full; (void)val; (void)val_len_max;`,
|
|
108
111
|
` return -ENOENT;`,
|
|
109
112
|
`}`,
|
|
110
113
|
`static int __tc_prefs_h_commit(void) { return 0; }`,
|
|
@@ -122,12 +125,6 @@ export function preferencesInitLines() {
|
|
|
122
125
|
` }`,
|
|
123
126
|
`}`,
|
|
124
127
|
``,
|
|
125
|
-
`// Build the full settings name "tc/<ns>/<key>" into out. ns is the active`,
|
|
126
|
-
`// prefix set by begin(); the slot's key[] stores this full path so remove()`,
|
|
127
|
-
`// and clear() can settings_delete the exact stored name.`,
|
|
128
|
-
`static void __tc_prefs_full(char* out, size_t outsz, const char* key) {`,
|
|
129
|
-
` (void)snprintf(out, outsz, "%s%s", __tc_prefs.ns, key);`,
|
|
130
|
-
`}`,
|
|
131
128
|
``,
|
|
132
129
|
`// Slot lookup by full settings name. Returns nullptr when absent (the get_*`,
|
|
133
130
|
`// helpers then fall back to the caller's default value, matching the ESP32`,
|
|
@@ -159,9 +156,8 @@ export function preferencesInitLines() {
|
|
|
159
156
|
`// as val[0] so h_set can recover it on the next boot without a separate`,
|
|
160
157
|
`// name→type map.`,
|
|
161
158
|
`template <typename T>`,
|
|
162
|
-
`static inline void __tc_prefs_put(const char*
|
|
163
|
-
`
|
|
164
|
-
` __tc_prefs_full(full, sizeof(full), key);`,
|
|
159
|
+
`static inline void __tc_prefs_put(const char* full, uint8_t tag, const T& value) {`,
|
|
160
|
+
` __tc_prefs_ensure_loaded(); // begin() is gone — mount lazily here`,
|
|
165
161
|
` uint8_t buf[1U + sizeof(T)];`,
|
|
166
162
|
` buf[0] = tag;`,
|
|
167
163
|
` (void)memcpy(&buf[1], &value, sizeof(T));`,
|
|
@@ -177,9 +173,8 @@ export function preferencesInitLines() {
|
|
|
177
173
|
`}`,
|
|
178
174
|
``,
|
|
179
175
|
`template <typename T>`,
|
|
180
|
-
`static inline T __tc_prefs_get(const char*
|
|
181
|
-
`
|
|
182
|
-
` __tc_prefs_full(full, sizeof(full), key);`,
|
|
176
|
+
`static inline T __tc_prefs_get(const char* full, uint8_t tag, T def) {`,
|
|
177
|
+
` __tc_prefs_ensure_loaded();`,
|
|
183
178
|
` __tc_prefs_slot* slot = __tc_prefs_find(full);`,
|
|
184
179
|
` if (slot == nullptr || slot->type != tag || slot->len < (1U + sizeof(T))) {`,
|
|
185
180
|
` return def;`,
|
|
@@ -192,23 +187,12 @@ export function preferencesInitLines() {
|
|
|
192
187
|
`// ── Lifecycle (session model on top of the flat key-space) ──────────────`,
|
|
193
188
|
`// begin records "tc/<ns>/" as the prefix every subsequent key is built under.`,
|
|
194
189
|
`// end clears the prefix (NOT the cache). Both are cheap on Zephyr: the real`,
|
|
195
|
-
`// work is in settings_load() at boot. They exist for portability with the`,
|
|
196
|
-
`// ESP32 NVS session model and so a future session-needing backend has a hook.`,
|
|
197
|
-
`static inline void __tc_prefs_begin(const char* ns, bool readOnly) {`,
|
|
198
|
-
` (void)readOnly;`,
|
|
199
|
-
` __tc_prefs_ensure_loaded();`,
|
|
200
|
-
` (void)snprintf(__tc_prefs.ns, sizeof(__tc_prefs.ns), "tc/%s/", ns);`,
|
|
201
|
-
`}`,
|
|
202
|
-
`static inline void __tc_prefs_end(void) {`,
|
|
203
|
-
` __tc_prefs.ns[0] = '\\0';`,
|
|
204
|
-
`}`,
|
|
205
190
|
``,
|
|
206
191
|
`// remove: drop one key from flash and the cache. Falls back to no-op if the`,
|
|
207
192
|
`// slot isn't cached (settings_delete on a missing key returns -ENOENT, which`,
|
|
208
193
|
`// we swallow).`,
|
|
209
|
-
`static inline void __tc_prefs_remove(const char*
|
|
210
|
-
`
|
|
211
|
-
` __tc_prefs_full(full, sizeof(full), key);`,
|
|
194
|
+
`static inline void __tc_prefs_remove(const char* full) {`,
|
|
195
|
+
` __tc_prefs_ensure_loaded();`,
|
|
212
196
|
` (void)settings_delete(full);`,
|
|
213
197
|
` __tc_prefs_slot* slot = __tc_prefs_find(full);`,
|
|
214
198
|
` if (slot != nullptr) { slot->used = false; }`,
|
|
@@ -218,11 +202,12 @@ export function preferencesInitLines() {
|
|
|
218
202
|
`// authoritative list of keys we have written) and settings_delete each whose`,
|
|
219
203
|
`// full name starts with the active ns prefix, then mark the slot free. Only`,
|
|
220
204
|
`// the active namespace is cleared — keys under other namespaces survive.`,
|
|
221
|
-
`static inline void __tc_prefs_clear(
|
|
222
|
-
`
|
|
205
|
+
`static inline void __tc_prefs_clear(const char* prefix) {`,
|
|
206
|
+
` __tc_prefs_ensure_loaded();`,
|
|
207
|
+
` const size_t plen = strlen(prefix);`,
|
|
223
208
|
` for (int i = 0; i < __TC_PREFS_SLOT_COUNT; i++) {`,
|
|
224
209
|
` if (__tc_prefs.slots[i].used &&`,
|
|
225
|
-
` strncmp(__tc_prefs.slots[i].key,
|
|
210
|
+
` strncmp(__tc_prefs.slots[i].key, prefix, plen) == 0) {`,
|
|
226
211
|
` (void)settings_delete(__tc_prefs.slots[i].key);`,
|
|
227
212
|
` __tc_prefs.slots[i].used = false;`,
|
|
228
213
|
` }`,
|
|
@@ -232,39 +217,38 @@ export function preferencesInitLines() {
|
|
|
232
217
|
`// ── Typed accessors ─────────────────────────────────────────────────────`,
|
|
233
218
|
`// Each put_* stamps its tag byte and persists; each get_* reads the cache and`,
|
|
234
219
|
`// returns the default on miss/type-mismatch (mirrors ESP32 Preferences).`,
|
|
235
|
-
`static inline void __tc_prefs_put_int(const char*
|
|
236
|
-
` __tc_prefs_put<int32_t>(
|
|
220
|
+
`static inline void __tc_prefs_put_int(const char* full, int32_t v) {`,
|
|
221
|
+
` __tc_prefs_put<int32_t>(full, ${TAG.INT}, v);`,
|
|
237
222
|
`}`,
|
|
238
|
-
`static inline int32_t __tc_prefs_get_int(const char*
|
|
239
|
-
` return __tc_prefs_get<int32_t>(
|
|
223
|
+
`static inline int32_t __tc_prefs_get_int(const char* full, int32_t def) {`,
|
|
224
|
+
` return __tc_prefs_get<int32_t>(full, ${TAG.INT}, def);`,
|
|
240
225
|
`}`,
|
|
241
|
-
`static inline void __tc_prefs_put_uint(const char*
|
|
242
|
-
` __tc_prefs_put<uint32_t>(
|
|
226
|
+
`static inline void __tc_prefs_put_uint(const char* full, uint32_t v) {`,
|
|
227
|
+
` __tc_prefs_put<uint32_t>(full, ${TAG.UINT}, v);`,
|
|
243
228
|
`}`,
|
|
244
|
-
`static inline uint32_t __tc_prefs_get_uint(const char*
|
|
245
|
-
` return __tc_prefs_get<uint32_t>(
|
|
229
|
+
`static inline uint32_t __tc_prefs_get_uint(const char* full, uint32_t def) {`,
|
|
230
|
+
` return __tc_prefs_get<uint32_t>(full, ${TAG.UINT}, def);`,
|
|
246
231
|
`}`,
|
|
247
|
-
`static inline void __tc_prefs_put_bool(const char*
|
|
232
|
+
`static inline void __tc_prefs_put_bool(const char* full, bool v) {`,
|
|
248
233
|
` uint8_t b = v ? 1U : 0U;`,
|
|
249
|
-
` __tc_prefs_put<uint8_t>(
|
|
234
|
+
` __tc_prefs_put<uint8_t>(full, ${TAG.BOOL}, b);`,
|
|
250
235
|
`}`,
|
|
251
|
-
`static inline bool __tc_prefs_get_bool(const char*
|
|
252
|
-
` uint8_t b = __tc_prefs_get<uint8_t>(
|
|
236
|
+
`static inline bool __tc_prefs_get_bool(const char* full, bool def) {`,
|
|
237
|
+
` uint8_t b = __tc_prefs_get<uint8_t>(full, ${TAG.BOOL}, def ? 1U : 0U);`,
|
|
253
238
|
` return b != 0U;`,
|
|
254
239
|
`}`,
|
|
255
|
-
`static inline void __tc_prefs_put_float(const char*
|
|
256
|
-
` __tc_prefs_put<float>(
|
|
240
|
+
`static inline void __tc_prefs_put_float(const char* full, float v) {`,
|
|
241
|
+
` __tc_prefs_put<float>(full, ${TAG.FLOAT}, v);`,
|
|
257
242
|
`}`,
|
|
258
|
-
`static inline float __tc_prefs_get_float(const char*
|
|
259
|
-
` return __tc_prefs_get<float>(
|
|
243
|
+
`static inline float __tc_prefs_get_float(const char* full, float def) {`,
|
|
244
|
+
` return __tc_prefs_get<float>(full, ${TAG.FLOAT}, def);`,
|
|
260
245
|
`}`,
|
|
261
246
|
``,
|
|
262
247
|
`// Strings are length-prefixed into the value buffer (capped at STR_LEN so the`,
|
|
263
248
|
`// whole slot still fits in __TC_PREFS_VAL_LEN). get copies out with a NUL and`,
|
|
264
249
|
`// returns def when the slot is absent or the wrong type.`,
|
|
265
|
-
`static inline void __tc_prefs_put_string(const char*
|
|
266
|
-
`
|
|
267
|
-
` __tc_prefs_full(full, sizeof(full), key);`,
|
|
250
|
+
`static inline void __tc_prefs_put_string(const char* full, const char* v) {`,
|
|
251
|
+
` __tc_prefs_ensure_loaded();`,
|
|
268
252
|
` uint8_t buf[1U + __TC_PREFS_STR_LEN];`,
|
|
269
253
|
` buf[0] = ${TAG.STRING};`,
|
|
270
254
|
` size_t n = strlen(v);`,
|
|
@@ -280,10 +264,9 @@ export function preferencesInitLines() {
|
|
|
280
264
|
` slot->used = true;`,
|
|
281
265
|
` }`,
|
|
282
266
|
`}`,
|
|
283
|
-
`static inline const char* __tc_prefs_get_string(const char*
|
|
267
|
+
`static inline const char* __tc_prefs_get_string(const char* full, const char* def) {`,
|
|
268
|
+
` __tc_prefs_ensure_loaded();`,
|
|
284
269
|
` static char out[__TC_PREFS_STR_LEN + 1U];`,
|
|
285
|
-
` char full[__TC_PREFS_KEY_LEN];`,
|
|
286
|
-
` __tc_prefs_full(full, sizeof(full), key);`,
|
|
287
270
|
` __tc_prefs_slot* slot = __tc_prefs_find(full);`,
|
|
288
271
|
` if (slot == nullptr || slot->type != ${TAG.STRING} || slot->len < 1U) {`,
|
|
289
272
|
` return def;`,
|
|
@@ -307,37 +290,26 @@ export function preferencesInitLines() {
|
|
|
307
290
|
export function lowerPreferences(op) {
|
|
308
291
|
const o = op;
|
|
309
292
|
switch (op.operation) {
|
|
310
|
-
case 'preferences.begin':
|
|
311
|
-
// readOnly is honored as a no-op: Zephyr settings has no read-only mount,
|
|
312
|
-
// and silently ignoring it matches the ESP32 Preferences behavior when
|
|
313
|
-
// an RO handle is written (the put returns an error the app doesn't see).
|
|
314
|
-
return { code: `__tc_prefs_begin(${s(o.namespace)}, ${o.readOnly ? 'true' : 'false'});` };
|
|
315
|
-
case 'preferences.end':
|
|
316
|
-
return { code: `__tc_prefs_end();` };
|
|
317
293
|
case 'preferences.clear':
|
|
318
|
-
return { code: `__tc_prefs_clear();` };
|
|
294
|
+
return { code: `__tc_prefs_clear("tc/${unq(o.ns)}/");` };
|
|
319
295
|
case 'preferences.remove':
|
|
320
|
-
return { code: `__tc_prefs_remove(
|
|
296
|
+
return { code: `__tc_prefs_remove("tc/${unq(o.ns)}/${unq(o.key)}");` };
|
|
321
297
|
case 'preferences.put_int':
|
|
322
|
-
return { code: `__tc_prefs_put_int(
|
|
298
|
+
return { code: `__tc_prefs_put_int("tc/${unq(o.ns)}/${unq(o.key)}", ${s(o.value)});` };
|
|
323
299
|
case 'preferences.get_int':
|
|
324
|
-
return { expression: `__tc_prefs_get_int(
|
|
325
|
-
case 'preferences.put_uint':
|
|
326
|
-
return { code: `__tc_prefs_put_uint(${s(o.key)}, ${s(o.value)});` };
|
|
327
|
-
case 'preferences.get_uint':
|
|
328
|
-
return { expression: `__tc_prefs_get_uint(${s(o.key)}, ${s(o.defaultValue)})` };
|
|
300
|
+
return { expression: `__tc_prefs_get_int("tc/${unq(o.ns)}/${unq(o.key)}", ${s(o.defaultValue)})` };
|
|
329
301
|
case 'preferences.put_bool':
|
|
330
|
-
return { code: `__tc_prefs_put_bool(
|
|
302
|
+
return { code: `__tc_prefs_put_bool("tc/${unq(o.ns)}/${unq(o.key)}", ${o.value ? 'true' : 'false'});` };
|
|
331
303
|
case 'preferences.get_bool':
|
|
332
|
-
return { expression: `__tc_prefs_get_bool(
|
|
304
|
+
return { expression: `__tc_prefs_get_bool("tc/${unq(o.ns)}/${unq(o.key)}", ${o.defaultValue ? 'true' : 'false'})` };
|
|
333
305
|
case 'preferences.put_float':
|
|
334
|
-
return { code: `__tc_prefs_put_float(
|
|
306
|
+
return { code: `__tc_prefs_put_float("tc/${unq(o.ns)}/${unq(o.key)}", ${s(o.value)});` };
|
|
335
307
|
case 'preferences.get_float':
|
|
336
|
-
return { expression: `__tc_prefs_get_float(
|
|
308
|
+
return { expression: `__tc_prefs_get_float("tc/${unq(o.ns)}/${unq(o.key)}", ${s(o.defaultValue)})` };
|
|
337
309
|
case 'preferences.put_string':
|
|
338
|
-
return { code: `__tc_prefs_put_string(
|
|
310
|
+
return { code: `__tc_prefs_put_string("tc/${unq(o.ns)}/${unq(o.key)}", ${s(o.value)});` };
|
|
339
311
|
case 'preferences.get_string':
|
|
340
|
-
return { expression: `__tc_prefs_get_string(
|
|
312
|
+
return { expression: `__tc_prefs_get_string("tc/${unq(o.ns)}/${unq(o.key)}", ${s(o.defaultValue)})` };
|
|
341
313
|
default:
|
|
342
314
|
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
343
315
|
`Open an issue or use rawCpp() to emit it manually.`);
|
package/dist/lowering/pulse.js
CHANGED
|
@@ -44,37 +44,6 @@ export function lowerPulseOrShift(op, chip) {
|
|
|
44
44
|
expression: `({ int64_t __max = static_cast<int64_t>(${timeout} / 1000); int64_t __t0 = k_uptime_get(); bool __ok = true; while (gpio_pin_get_raw(${dev}, ${pin}) != ${want}) { if ((k_uptime_get() - __t0) > __max) { __ok = false; break; } } int32_t __ret = 0; if (__ok) { int64_t __start = k_uptime_get(); while (gpio_pin_get_raw(${dev}, ${pin}) == ${want}) { } __ret = static_cast<int32_t>((k_uptime_get() - __start) * 1000); } __ret; })`,
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
case 'shift.out': {
|
|
48
|
-
// Bit-bang `value` (MSB or LSB first) via dataPin + clockPin. The two
|
|
49
|
-
// pins may sit on different GPIO controllers on multi-controller SoCs
|
|
50
|
-
// (ESP32-S3), so each is resolved to its own owning controller.
|
|
51
|
-
const dataPin = o.dataPin;
|
|
52
|
-
const clockPin = o.clockPin;
|
|
53
|
-
const dataDev = devForPin(chip, dataPin);
|
|
54
|
-
const clockDev = devForPin(chip, clockPin);
|
|
55
|
-
const msbFirst = o.bitOrder === 'msb';
|
|
56
|
-
const init = msbFirst ? '7' : '0';
|
|
57
|
-
const test = msbFirst ? '(__i >= 0)' : '(__i < 8)';
|
|
58
|
-
const step = msbFirst ? '__i--' : '__i++';
|
|
59
|
-
return {
|
|
60
|
-
code: `for (int __i = ${init}; ${test}; ${step}) { gpio_pin_set_raw(${dataDev}, ${controllerRawPinForPin(chip, dataPin)}, (${o.value} >> __i) & 1); gpio_pin_set_raw(${clockDev}, ${controllerRawPinForPin(chip, clockPin)}, 1); k_busy_wait(1); gpio_pin_set_raw(${clockDev}, ${controllerRawPinForPin(chip, clockPin)}, 0); }`,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
case 'shift.in': {
|
|
64
|
-
// Read 8 bits (MSB or LSB first) from dataPin, clocking on clockPin.
|
|
65
|
-
const dataPin = o.dataPin;
|
|
66
|
-
const clockPin = o.clockPin;
|
|
67
|
-
const dataDev = devForPin(chip, dataPin);
|
|
68
|
-
const clockDev = devForPin(chip, clockPin);
|
|
69
|
-
const msbFirst = o.bitOrder === 'msb';
|
|
70
|
-
const init = msbFirst ? '7' : '0';
|
|
71
|
-
const test = msbFirst ? '(__i >= 0)' : '(__i < 8)';
|
|
72
|
-
const step = msbFirst ? '__i--' : '__i++';
|
|
73
|
-
const accum = msbFirst ? '__v = (__v << 1)' : '__v |= (bit << __i)';
|
|
74
|
-
return {
|
|
75
|
-
expression: `({ uint8_t __v = 0; for (int __i = ${init}; ${test}; ${step}) { gpio_pin_set_raw(${clockDev}, ${controllerRawPinForPin(chip, clockPin)}, 1); k_busy_wait(1); int bit = gpio_pin_get_raw(${dataDev}, ${controllerRawPinForPin(chip, dataPin)}); gpio_pin_set_raw(${clockDev}, ${controllerRawPinForPin(chip, clockPin)}, 0); ${accum}; } __v; })`,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
47
|
default:
|
|
79
48
|
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
80
49
|
`Open an issue or use rawCpp() to emit it manually.`);
|
package/dist/lowering/pwm.d.ts
CHANGED
|
@@ -14,6 +14,13 @@ export declare function pwmDtAlias(spec: ZephyrPwmSpec): string;
|
|
|
14
14
|
* expression and fails to compile (caught by the blackpill E2E west build).
|
|
15
15
|
*/
|
|
16
16
|
export declare function pwmDtAliasToken(spec: ZephyrPwmSpec): string;
|
|
17
|
+
/**
|
|
18
|
+
* Look up a PWM spec by HAL pin number. Matrix pins (ESP32 LEDC) synthesize
|
|
19
|
+
* a spec on the fly: the channel is inert here — the emitted C++ addresses
|
|
20
|
+
* the pin only via its `tc-pwm<pin>` alias (the DT pwms cell carries the
|
|
21
|
+
* real channel, assigned by the overlay generator over the driven pins).
|
|
22
|
+
*/
|
|
23
|
+
export declare function findPwmSpec(chip: ZephyrChipDescriptor, pin: number): ZephyrPwmSpec | undefined;
|
|
17
24
|
/**
|
|
18
25
|
* Emit the per-channel PWM spec declarations. One per spec in the chip
|
|
19
26
|
* descriptor that the PROGRAM ACTUALLY DRIVES (`usedPins`) — a spec for an
|
|
@@ -22,7 +29,11 @@ export declare function pwmDtAliasToken(spec: ZephyrPwmSpec): string;
|
|
|
22
29
|
* program), every spec is emitted. Called from shimLines when the program
|
|
23
30
|
* uses PWM.
|
|
24
31
|
*/
|
|
25
|
-
export declare function pwmInitLines(chip: ZephyrChipDescriptor, usedPins?: ReadonlySet<number
|
|
32
|
+
export declare function pwmInitLines(chip: ZephyrChipDescriptor, usedPins?: ReadonlySet<number>, userSpecs?: readonly {
|
|
33
|
+
pin: number;
|
|
34
|
+
controller: string;
|
|
35
|
+
channel: number;
|
|
36
|
+
}[]): string[];
|
|
26
37
|
/**
|
|
27
38
|
* Resolve a HAL pwm.* op to Zephyr C++.
|
|
28
39
|
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
package/dist/lowering/pwm.js
CHANGED
|
@@ -24,9 +24,20 @@ export function pwmDtAlias(spec) {
|
|
|
24
24
|
export function pwmDtAliasToken(spec) {
|
|
25
25
|
return pwmDtAlias(spec).replace(/-/g, '_');
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Look up a PWM spec by HAL pin number. Matrix pins (ESP32 LEDC) synthesize
|
|
29
|
+
* a spec on the fly: the channel is inert here — the emitted C++ addresses
|
|
30
|
+
* the pin only via its `tc-pwm<pin>` alias (the DT pwms cell carries the
|
|
31
|
+
* real channel, assigned by the overlay generator over the driven pins).
|
|
32
|
+
*/
|
|
33
|
+
export function findPwmSpec(chip, pin) {
|
|
34
|
+
const spec = chip.pwm?.specs.find((s) => s.pin === pin);
|
|
35
|
+
if (spec)
|
|
36
|
+
return spec;
|
|
37
|
+
const m = chip.pwm?.matrix;
|
|
38
|
+
if (m && m.pins.includes(pin))
|
|
39
|
+
return { pin, controller: m.controller, channel: 0 };
|
|
40
|
+
return undefined;
|
|
30
41
|
}
|
|
31
42
|
/** The C variable name emitted for a PWM channel's spec. */
|
|
32
43
|
function pwmVarName(spec) {
|
|
@@ -40,13 +51,37 @@ function pwmVarName(spec) {
|
|
|
40
51
|
* program), every spec is emitted. Called from shimLines when the program
|
|
41
52
|
* uses PWM.
|
|
42
53
|
*/
|
|
43
|
-
export function pwmInitLines(chip, usedPins) {
|
|
54
|
+
export function pwmInitLines(chip, usedPins, userSpecs) {
|
|
44
55
|
const lines = ['// CUTTLEFISH_PWM_BEGIN'];
|
|
45
56
|
for (const spec of chip.pwm?.specs ?? []) {
|
|
46
57
|
if (usedPins && !usedPins.has(spec.pin))
|
|
47
58
|
continue;
|
|
48
59
|
lines.push(`static const struct pwm_dt_spec ${pwmVarName(spec)} = PWM_DT_SPEC_GET(DT_ALIAS(${pwmDtAliasToken(spec)}));`);
|
|
49
60
|
}
|
|
61
|
+
// Inline-override pins (the escape hatch): the construction opts vouch for
|
|
62
|
+
// controller+channel on a pin the manifest does not map — the alias var
|
|
63
|
+
// the lowered calls reference (the DT node itself comes from the overlay
|
|
64
|
+
// regen's marker merge).
|
|
65
|
+
for (const spec of userSpecs ?? []) {
|
|
66
|
+
if (chip.pwm?.specs.some((s) => s.pin === spec.pin))
|
|
67
|
+
continue;
|
|
68
|
+
if (usedPins && !usedPins.has(spec.pin))
|
|
69
|
+
continue;
|
|
70
|
+
lines.push(`static const struct pwm_dt_spec ${pwmVarName(spec)} = PWM_DT_SPEC_GET(DT_ALIAS(${pwmDtAliasToken(spec)}));`);
|
|
71
|
+
}
|
|
72
|
+
// Matrix pins (ESP32 LEDC): one alias per driven pin, ascending — the same
|
|
73
|
+
// order the overlay generator assigns channels in, though the C++ never
|
|
74
|
+
// needs the channel (the DT pwms cell carries it). An omitted usage set
|
|
75
|
+
// (probe paths) emits every matrix pin, mirroring the static behavior.
|
|
76
|
+
const m = chip.pwm?.matrix;
|
|
77
|
+
if (m) {
|
|
78
|
+
const pins = (usedPins ? [...usedPins].filter((p) => m.pins.includes(p)) : [...m.pins])
|
|
79
|
+
.sort((a, b) => a - b);
|
|
80
|
+
for (const pin of pins) {
|
|
81
|
+
const spec = { pin, controller: m.controller, channel: 0 };
|
|
82
|
+
lines.push(`static const struct pwm_dt_spec ${pwmVarName(spec)} = PWM_DT_SPEC_GET(DT_ALIAS(${pwmDtAliasToken(spec)}));`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
50
85
|
lines.push('// CUTTLEFISH_PWM_END');
|
|
51
86
|
return lines;
|
|
52
87
|
}
|
|
@@ -56,7 +91,20 @@ export function pwmInitLines(chip, usedPins) {
|
|
|
56
91
|
*/
|
|
57
92
|
export function lowerPwm(op, chip) {
|
|
58
93
|
const o = op;
|
|
59
|
-
|
|
94
|
+
// Construction-time controller/channel overrides (hal/pwm-pin.ts opts):
|
|
95
|
+
// the user vouches for the routing. The spec synthesizes from the
|
|
96
|
+
// override (addressing rides the tc-pwm<pin> alias like a matrix pin) and
|
|
97
|
+
// a marker comment carries controller+channel to the overlay regen, which
|
|
98
|
+
// synthesizes the DT node — the transpiler cannot.
|
|
99
|
+
const hasOverride = (typeof o.controllerOverride === 'string' && o.controllerOverride !== '')
|
|
100
|
+
|| (typeof o.channelOverride === 'number' && o.channelOverride >= 0);
|
|
101
|
+
const spec = hasOverride
|
|
102
|
+
? {
|
|
103
|
+
pin: o.pin,
|
|
104
|
+
controller: o.controllerOverride ?? 'pwm0',
|
|
105
|
+
channel: o.channelOverride ?? 0,
|
|
106
|
+
}
|
|
107
|
+
: findPwmSpec(chip, o.pin);
|
|
60
108
|
if (!spec) {
|
|
61
109
|
// Probe / unlisted pin: return a comment so the resolver reports non-
|
|
62
110
|
// undefined (the manifest validator's probe sends pin:0 with no spec).
|
|
@@ -64,18 +112,34 @@ export function lowerPwm(op, chip) {
|
|
|
64
112
|
return { code: `/* pwm on pin ${o.pin}: no PWM spec in chip descriptor */` };
|
|
65
113
|
}
|
|
66
114
|
const v = pwmVarName(spec);
|
|
115
|
+
// The overlay regen (toolchain) parses this into a synthesized pwm-leds
|
|
116
|
+
// spec: pin → controller/channel. Comment placement inside the block
|
|
117
|
+
// braces is legal C.
|
|
118
|
+
const marker = hasOverride
|
|
119
|
+
? `/* cuttlefish-user-facts: pwm pin=${spec.pin} controller=${spec.controller} channel=${spec.channel} */ `
|
|
120
|
+
: '';
|
|
67
121
|
switch (op.operation) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
122
|
+
// ── Thin PWM (hal/pwm-pin.ts) — ns-true verbs ──────────────────────────
|
|
123
|
+
// Zephyr 4.4 has pwm_set_dt (period + pulse) and pwm_set_pulse_dt (pulse
|
|
124
|
+
// only) — no period-only setter. The construction period is established
|
|
125
|
+
// once via pwm_set_dt(period, pulse 0 = line idle), then every set is one
|
|
126
|
+
// pwm_set_pulse_dt. No 0–255 scaling anywhere.
|
|
127
|
+
case 'pwm.set_pulse': {
|
|
128
|
+
return {
|
|
129
|
+
code: `{ ${marker}static bool __tc_pwm_p${o.pin}_prd = false; if (!__tc_pwm_p${o.pin}_prd) { (void)pwm_set_dt(&${v}, ${o.periodNs}, 0); __tc_pwm_p${o.pin}_prd = true; } (void)pwm_set_pulse_dt(&${v}, ${o.pulseNs}); }`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
case 'pwm.set_duty': {
|
|
133
|
+
// duty is 0.0–1.0; pulse = duty × the construction period.
|
|
134
|
+
return {
|
|
135
|
+
code: `{ ${marker}static bool __tc_pwm_p${o.pin}_prd = false; if (!__tc_pwm_p${o.pin}_prd) { (void)pwm_set_dt(&${v}, ${o.periodNs}, 0); __tc_pwm_p${o.pin}_prd = true; } (void)pwm_set_pulse_dt(&${v}, static_cast<uint32_t>(static_cast<double>(${o.duty}) * static_cast<double>(${o.periodNs}))); }`,
|
|
136
|
+
};
|
|
71
137
|
}
|
|
72
|
-
case 'pwm.
|
|
73
|
-
// period
|
|
74
|
-
|
|
138
|
+
case 'pwm.set_period': {
|
|
139
|
+
// No period-only API: pwm_set_dt applies the new period and resets the
|
|
140
|
+
// pulse to idle — follow with setPulse/setDuty to drive the line.
|
|
141
|
+
return { code: `${marker}(void)pwm_set_dt(&${v}, ${o.periodNs}, 0);` };
|
|
75
142
|
}
|
|
76
|
-
case 'pwm.get_resolution':
|
|
77
|
-
// Arduino-compatible 8-bit duty range.
|
|
78
|
-
return { expression: '8' };
|
|
79
143
|
default:
|
|
80
144
|
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
81
145
|
`Open an issue or use rawCpp() to emit it manually.`);
|
package/dist/lowering/random.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// the configured entropy source (the nRF52840 hardware RNG when
|
|
6
6
|
// CONFIG_HARDWARE_DEVICE_RANDOM_GENERATOR is selected, or the default test/
|
|
7
7
|
// xoroshiro generator otherwise). It is seeded automatically at boot from the
|
|
8
|
-
// entropy driver, so
|
|
8
|
+
// entropy driver, so there is no implicit seeding step.
|
|
9
9
|
//
|
|
10
10
|
// The HAL random surface is the Arduino-core model:
|
|
11
11
|
// random.int() → a non-negative 31-bit integer [0, 2^31 - 1]
|
|
@@ -70,7 +70,7 @@ export function randomInitLines() {
|
|
|
70
70
|
`}`,
|
|
71
71
|
``,
|
|
72
72
|
`// Re-seed the PRNG. After this call the sequence is deterministic from`,
|
|
73
|
-
`// \`seed\`, matching
|
|
73
|
+
`// \`seed\`, matching the platform's randomSeed. A literal zero seed is accepted and`,
|
|
74
74
|
`// remapped to the same odd constant (xorshift32 cannot start from 0).`,
|
|
75
75
|
`static inline void __tc_rand_seed(uint32_t seed) {`,
|
|
76
76
|
` __tc_rand_state = (seed == 0U) ? 0x9E3779B9U : seed;`,
|
|
@@ -84,7 +84,7 @@ export function randomInitLines() {
|
|
|
84
84
|
`}`,
|
|
85
85
|
``,
|
|
86
86
|
`// Half-open range [min, max-1]. Implements the HAL contract directly rather`,
|
|
87
|
-
`// than calling
|
|
87
|
+
`// than calling the platform random(min, max): the modulus rejection-free form`,
|
|
88
88
|
`// avoids the modulo bias a naive (rand % (max-min)) introduces. max > min`,
|
|
89
89
|
`// is assumed (the HAL validates this at the source level).`,
|
|
90
90
|
`static inline int32_t __tc_rand_range(int32_t min, int32_t max) {`,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
2
|
+
/** Strip the 'SENSOR.' property-access prefix from a part token arg. */
|
|
3
|
+
export declare function sensorPartKey(part: string): string;
|
|
4
|
+
/** Strip the 'CHAN.' property-access prefix from a channel arg. */
|
|
5
|
+
export declare function sensorChanName(chan: string): string;
|
|
6
|
+
/** All names a constructed sensor is known by, derived from the op facts. */
|
|
7
|
+
export interface SensorNames {
|
|
8
|
+
/** DT nodelabel of the child node the overlay emits
|
|
9
|
+
* (tc_<part>_i2c<N>_0x<addr> / tc_<part>_spi<N>_cs<pin>). */
|
|
10
|
+
dtLabel: string;
|
|
11
|
+
/** C device-handle variable (__tc_sensor_<stem>_dev). */
|
|
12
|
+
devVar: string;
|
|
13
|
+
/** C sensor_value scratch variable (__tc_sensor_<stem>_val). */
|
|
14
|
+
valVar: string;
|
|
15
|
+
/** The controller index the bus string carries. */
|
|
16
|
+
busIndex: number;
|
|
17
|
+
/** The bus port: I2C address or SPI CS pin. */
|
|
18
|
+
port: number;
|
|
19
|
+
/** 'i2c' | 'spi'. */
|
|
20
|
+
busKind: 'i2c' | 'spi';
|
|
21
|
+
}
|
|
22
|
+
/** Derive a sensor's DT/C++ names. The scanner regexes the emitted __tc_
|
|
23
|
+
* prefix form, so the part group must stay [a-z0-9_]+ and greedy. */
|
|
24
|
+
export declare function sensorNames(part: string, bus: string, port: number | string, busKind?: string): SensorNames;
|
|
25
|
+
/**
|
|
26
|
+
* Emit the per-sensor state block (device handle + sensor_value scratch).
|
|
27
|
+
* Called from shimLines for each distinct sensor the program's ops reference.
|
|
28
|
+
*/
|
|
29
|
+
export declare function sensorStateLines(part: string, bus: string, port: number | string, busKind?: string, spiHz?: number | string, spiMode?: number | string, alertPin?: number | string): string[];
|
|
30
|
+
/**
|
|
31
|
+
* Resolve a HAL sensor.* op to Zephyr C++.
|
|
32
|
+
* Returns `{ code }` for fetch (statement), `{ expression }` for get (value).
|
|
33
|
+
*/
|
|
34
|
+
export declare function lowerSensor(op: HALOpIR): {
|
|
35
|
+
code?: string;
|
|
36
|
+
expression?: string;
|
|
37
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Sensor lowering — Zephyr's uniform sensor API over the generated catalog
|
|
3
|
+
//
|
|
4
|
+
// One code shape for every part in @typecad/hal's sensor catalog: the op's
|
|
5
|
+
// part token resolves to the DT compatible, the bus string to the controller
|
|
6
|
+
// index, and the address to the I2C reg. The names are derived identically
|
|
7
|
+
// here (device handles), in strategy.ts state blocks, and in the overlay
|
|
8
|
+
// scanner (dt-config/overlay.ts + toolchain/index.ts) — the tc-pwm<pin>
|
|
9
|
+
// discipline: both sides derive from the same facts, so they cannot drift.
|
|
10
|
+
//
|
|
11
|
+
// Kconfig: nothing per-part. The in-tree driver Kconfigs are `default y` on
|
|
12
|
+
// DT_HAS_<COMPAT>_ENABLED, so the overlay's child node IS the enable switch;
|
|
13
|
+
// CONFIG_SENSOR (the umbrella under `if SENSOR`) is usage-gated in
|
|
14
|
+
// dt-config/kconfig.ts off the lowered `sensor_` tokens.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
import { SENSOR_PART_INFO } from '@typecad/hal';
|
|
17
|
+
import { parseControllerIndex } from './util.js';
|
|
18
|
+
/** Strip the 'SENSOR.' property-access prefix from a part token arg. */
|
|
19
|
+
export function sensorPartKey(part) {
|
|
20
|
+
return part.replace(/^SENSOR\./, '');
|
|
21
|
+
}
|
|
22
|
+
/** Strip the 'CHAN.' property-access prefix from a channel arg. */
|
|
23
|
+
export function sensorChanName(chan) {
|
|
24
|
+
return chan.replace(/^CHAN\./, '');
|
|
25
|
+
}
|
|
26
|
+
/** Derive a sensor's DT/C++ names. The scanner regexes the emitted __tc_
|
|
27
|
+
* prefix form, so the part group must stay [a-z0-9_]+ and greedy. */
|
|
28
|
+
export function sensorNames(part, bus, port, busKind = 'i2c') {
|
|
29
|
+
const partKey = sensorPartKey(String(part));
|
|
30
|
+
const busIndex = parseControllerIndex(typeof bus === 'string' ? bus : String(bus));
|
|
31
|
+
const portNum = typeof port === 'number' ? port : parseInt(String(port));
|
|
32
|
+
const stem = busKind === 'spi'
|
|
33
|
+
? `${partKey}_spi${busIndex}_cs${portNum}`
|
|
34
|
+
: `${partKey}_i2c${busIndex}_0x${portNum.toString(16)}`;
|
|
35
|
+
return {
|
|
36
|
+
dtLabel: `tc_${stem}`,
|
|
37
|
+
devVar: `__tc_sensor_${stem}_dev`,
|
|
38
|
+
valVar: `__tc_sensor_${stem}_val`,
|
|
39
|
+
busIndex,
|
|
40
|
+
port: portNum,
|
|
41
|
+
busKind: busKind === 'spi' ? 'spi' : 'i2c',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the part token against the generated catalog, validating the bus
|
|
46
|
+
* kind and (when the driver scan knows them) the channel. Throws a build-time
|
|
47
|
+
* error with the Zephyr-facing name — the same words the user would meet in
|
|
48
|
+
* Zephyr docs, checked before west ever runs.
|
|
49
|
+
*/
|
|
50
|
+
/** @internal */
|
|
51
|
+
function requirePartInfo(partKey) {
|
|
52
|
+
const info = SENSOR_PART_INFO[partKey];
|
|
53
|
+
if (!info) {
|
|
54
|
+
throw new Error(`Sensor part '${partKey}' is not in the Zephyr sensor catalog (SENSOR in @typecad/hal). ` +
|
|
55
|
+
`Check the token against the catalog — it is the compatible with , and - replaced by _.`);
|
|
56
|
+
}
|
|
57
|
+
return info;
|
|
58
|
+
}
|
|
59
|
+
/** Validate the op's bus kind against the part's bindings. */
|
|
60
|
+
function requireBusKind(partKey, info, busKind) {
|
|
61
|
+
if (!info.buses.includes(busKind)) {
|
|
62
|
+
throw new Error(`Sensor part '${partKey}' (${info.compatible}) does not bind on ${busKind.toUpperCase()} — ` +
|
|
63
|
+
`its bindings are ${info.buses.join('/').toUpperCase()}.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Emit the per-sensor state block (device handle + sensor_value scratch).
|
|
68
|
+
* Called from shimLines for each distinct sensor the program's ops reference.
|
|
69
|
+
*/
|
|
70
|
+
export function sensorStateLines(part, bus, port, busKind = 'i2c', spiHz = 0, spiMode = 0, alertPin = -1) {
|
|
71
|
+
const partKey = sensorPartKey(String(part));
|
|
72
|
+
requireBusKind(partKey, requirePartInfo(partKey), busKind);
|
|
73
|
+
const n = sensorNames(part, bus, port, busKind);
|
|
74
|
+
// The config comment carries construction facts (SPI clock, mode, alert
|
|
75
|
+
// GPIO) to the overlay scanner — they shape the DT node, not the C++.
|
|
76
|
+
const cfg = `// tc-sensor-cfg: ${n.dtLabel} hz=${Number(spiHz)} mode=${Number(spiMode)} alert=${Number(alertPin)}`;
|
|
77
|
+
return [
|
|
78
|
+
'// CUTTLEFISH_SENSOR_BEGIN',
|
|
79
|
+
`static const struct device* ${n.devVar} = DEVICE_DT_GET(DT_NODELABEL(${n.dtLabel}));`,
|
|
80
|
+
`static struct sensor_value ${n.valVar};`,
|
|
81
|
+
cfg,
|
|
82
|
+
'// CUTTLEFISH_SENSOR_END',
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve a HAL sensor.* op to Zephyr C++.
|
|
87
|
+
* Returns `{ code }` for fetch (statement), `{ expression }` for get (value).
|
|
88
|
+
*/
|
|
89
|
+
export function lowerSensor(op) {
|
|
90
|
+
const o = op;
|
|
91
|
+
const partKey = sensorPartKey(String(o.part));
|
|
92
|
+
const info = requirePartInfo(partKey);
|
|
93
|
+
requireBusKind(partKey, info, String(o.busKind ?? 'i2c'));
|
|
94
|
+
const n = sensorNames(o.part, o.bus, o.port ?? o.address, String(o.busKind ?? 'i2c'));
|
|
95
|
+
switch (op.operation) {
|
|
96
|
+
case 'sensor.fetch':
|
|
97
|
+
// sensor_sample_fetch. The leading (void) keeps the value scratch
|
|
98
|
+
// referenced under Zephyr's -Werror when the program fetches but never
|
|
99
|
+
// reads a channel (the state block is emitted per referenced sensor).
|
|
100
|
+
return {
|
|
101
|
+
code: `(void)${n.valVar}; sensor_sample_fetch(${n.devVar});`,
|
|
102
|
+
};
|
|
103
|
+
case 'sensor.get': {
|
|
104
|
+
const chan = sensorChanName(String(o.chan));
|
|
105
|
+
if (info.channels.length > 0 && !info.channels.includes(chan)) {
|
|
106
|
+
throw new Error(`Sensor part '${partKey}' (${info.compatible}) does not serve channel '${chan}' — ` +
|
|
107
|
+
`its driver serves: ${info.channels.join(', ')}.`);
|
|
108
|
+
}
|
|
109
|
+
// sensor_value is val1 + val2 * 1e-6; evaluate once per read.
|
|
110
|
+
return {
|
|
111
|
+
expression: `(sensor_channel_get(${n.devVar}, SENSOR_CHAN_${chan}, &${n.valVar}), ` +
|
|
112
|
+
`static_cast<double>(${n.valVar}.val1) + static_cast<double>(${n.valVar}.val2) / 1000000.0)`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
default:
|
|
116
|
+
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
117
|
+
`Open an issue or use rawCpp() to emit it manually.`);
|
|
118
|
+
}
|
|
119
|
+
}
|
package/dist/lowering/spi.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
2
2
|
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
3
|
+
export interface SpiTargetNames {
|
|
4
|
+
dtLabel: string;
|
|
5
|
+
varName: string;
|
|
6
|
+
busIndex: number;
|
|
7
|
+
cs: number;
|
|
8
|
+
}
|
|
9
|
+
/** Derive a thin SPI target's names from the op facts. */
|
|
10
|
+
export declare function spiTargetNames(bus: string, cs: number | string): SpiTargetNames;
|
|
11
|
+
/** The per-target state block: one spi_dt_spec against the DT child node the
|
|
12
|
+
* overlay emits, plus the tc-spit-cfg comment the overlay scanner reads (the
|
|
13
|
+
* tc-sensor-cfg channel). Called from shimLines for each distinct target. */
|
|
14
|
+
export declare function spiTargetStateLines(bus: string, cs: number | string, hz?: number | string, mode?: number | string): string[];
|
|
3
15
|
/**
|
|
4
16
|
* Emit the per-controller SPI state. The bus device resolves at compile time;
|
|
5
17
|
* a static spi_config holds the base operation flags, and mutable runtime fields
|