@typecad/framework-zephyr 1.0.0-alpha.16 → 1.0.0-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -21
- package/README.md +49 -87
- package/dist/as-built.d.ts +2 -2
- package/dist/as-built.js +2 -2
- package/dist/audit.d.ts +111 -0
- package/dist/audit.js +416 -0
- package/dist/boardgen.d.ts +1 -9
- package/dist/boardgen.js +288 -47
- package/dist/chips/resolve.js +20 -0
- package/dist/chips/types.d.ts +22 -1
- package/dist/debug-codegen.js +1 -1
- package/dist/display/bindings.d.ts +55 -0
- package/dist/display/bindings.js +316 -0
- package/dist/display/gfx.d.ts +2 -3
- package/dist/display/gfx.js +166 -154
- package/dist/display/index.js +20 -1
- package/dist/display/mipi-dbi-host.d.ts +9 -0
- package/dist/display/mipi-dbi-host.js +174 -0
- package/dist/display/profiles.d.ts +109 -4
- package/dist/display/profiles.js +270 -7
- package/dist/display/touch-adapter.js +119 -49
- package/dist/display/ui-adapter-eink.d.ts +2 -0
- package/dist/display/ui-adapter-eink.js +4 -0
- package/dist/display/ui-adapter-gray.d.ts +8 -0
- package/dist/display/ui-adapter-gray.js +170 -0
- package/dist/display/ui-adapter-mono.d.ts +13 -0
- package/dist/display/ui-adapter-mono.js +230 -0
- package/dist/display/ui-adapter-native.d.ts +10 -0
- package/dist/display/ui-adapter-native.js +295 -0
- package/dist/display/ui-adapter-shared.d.ts +11 -0
- package/dist/display/ui-adapter-shared.js +122 -0
- package/dist/display/ui-adapter.js +510 -558
- package/dist/doctor.js +4 -4
- package/dist/dt-config/custom-board.js +2 -2
- package/dist/dt-config/kconfig.d.ts +62 -1
- package/dist/dt-config/kconfig.js +141 -38
- package/dist/dt-config/overlay.d.ts +15 -2
- package/dist/dt-config/overlay.js +433 -18
- package/dist/framework.manifest.d.ts +10 -4
- package/dist/framework.manifest.js +133 -17
- package/dist/index.d.ts +2 -0
- package/dist/index.js +14 -6
- package/dist/licenses.d.ts +2 -2
- package/dist/licenses.js +13 -92
- package/dist/lowering/can.d.ts +25 -0
- package/dist/lowering/can.js +97 -0
- package/dist/lowering/clock.d.ts +17 -0
- package/dist/lowering/clock.js +58 -0
- package/dist/lowering/fs.js +1 -1
- package/dist/lowering/gpio.js +0 -32
- package/dist/lowering/hid.d.ts +27 -0
- package/dist/lowering/hid.js +244 -0
- package/dist/lowering/http.js +264 -32
- package/dist/lowering/i2c.d.ts +8 -0
- package/dist/lowering/i2c.js +137 -5
- package/dist/lowering/i2s.d.ts +27 -0
- package/dist/lowering/i2s.js +98 -0
- package/dist/lowering/index.d.ts +9 -1
- package/dist/lowering/index.js +25 -1
- package/dist/lowering/interrupts.js +6 -0
- package/dist/lowering/matrix.d.ts +15 -0
- package/dist/lowering/matrix.js +63 -0
- package/dist/lowering/mqtt.js +110 -8
- package/dist/lowering/power.d.ts +3 -2
- package/dist/lowering/power.js +20 -45
- package/dist/lowering/pwm.js +25 -0
- package/dist/lowering/sensor.d.ts +2 -2
- package/dist/lowering/sensor.js +8 -4
- package/dist/lowering/strip.d.ts +16 -0
- package/dist/lowering/strip.js +70 -0
- package/dist/lowering/thread.js +5 -1
- package/dist/lowering/trace.d.ts +44 -0
- package/dist/lowering/trace.js +239 -0
- package/dist/lowering/uart.js +6 -1
- package/dist/lowering/usb.d.ts +3 -1
- package/dist/lowering/usb.js +16 -13
- package/dist/lowering/wdt.js +2 -29
- package/dist/sbom.d.ts +181 -0
- package/dist/sbom.js +901 -0
- package/dist/sdk/board-catalog-sync.d.ts +1 -3
- package/dist/sdk/board-catalog-sync.js +4 -10
- package/dist/strategy.d.ts +82 -46
- package/dist/strategy.js +639 -182
- package/dist/tmp-probe.d.ts +2 -0
- package/dist/tmp-probe.js +9 -0
- package/dist/toolchain/debug-config.d.ts +50 -90
- package/dist/toolchain/debug-config.js +239 -510
- package/dist/toolchain/env-check.d.ts +1 -3
- package/dist/toolchain/env-check.js +2 -7
- package/dist/toolchain/index.d.ts +28 -3
- package/dist/toolchain/index.js +498 -62
- package/dist/toolchain/runners.d.ts +16 -0
- package/dist/toolchain/runners.js +75 -0
- package/dist/toolchain/scaffold.d.ts +5 -2
- package/dist/toolchain/scaffold.js +79 -15
- package/dist/toolchain/west-discover.d.ts +6 -0
- package/dist/toolchain/west-discover.js +36 -13
- package/dist/toolchain/west-spawn.js +8 -2
- package/dist/west-inventory.d.ts +25 -0
- package/dist/west-inventory.js +97 -0
- package/installer/README.md +328 -328
- package/installer/install.sh +2 -2
- package/installer/templates/project/.typecad/activate-zephyr.ps1 +1 -1
- package/installer/templates/project/.typecad/activate-zephyr.sh +1 -1
- package/installer/templates/project/.vscode/settings.json +1 -1
- package/installer/templates/project/README.md +2 -2
- package/package.json +5 -5
- package/src/as-built.ts +206 -206
- package/src/audit.ts +529 -0
- package/src/boardgen.ts +265 -50
- package/src/chips/resolve.ts +21 -0
- package/src/chips/types.ts +10 -1
- package/src/display/bindings.ts +347 -0
- package/src/display/gfx.ts +318 -306
- package/src/display/index.ts +87 -70
- package/src/display/mipi-dbi-host.ts +183 -0
- package/src/display/profiles.ts +458 -139
- package/src/display/touch-adapter.ts +119 -49
- package/src/display/ui-adapter-eink.ts +13 -0
- package/src/display/ui-adapter-gray.ts +178 -0
- package/src/display/ui-adapter-mono.ts +238 -0
- package/src/display/ui-adapter-native.ts +304 -0
- package/src/display/ui-adapter-shared.ts +125 -0
- package/src/display/ui-adapter.ts +732 -781
- package/src/doctor.ts +4 -4
- package/src/dt-config/custom-board.ts +2 -2
- package/src/dt-config/kconfig.ts +647 -505
- package/src/dt-config/overlay.ts +1475 -1058
- package/src/framework.manifest.ts +659 -535
- package/src/index.ts +16 -6
- package/src/licenses.ts +346 -425
- package/src/lowering/can.ts +140 -0
- package/src/lowering/clock.ts +91 -0
- package/src/lowering/fs.ts +135 -135
- package/src/lowering/gpio.ts +0 -33
- package/src/lowering/hid.ts +261 -0
- package/src/lowering/http.ts +264 -32
- package/src/lowering/i2c.ts +142 -5
- package/src/lowering/i2s.ts +143 -0
- package/src/lowering/index.ts +18 -1
- package/src/lowering/interrupts.ts +6 -0
- package/src/lowering/matrix.ts +70 -0
- package/src/lowering/mqtt.ts +109 -8
- package/src/lowering/power.ts +41 -0
- package/src/lowering/pwm.ts +192 -167
- package/src/lowering/sensor.ts +159 -155
- package/src/lowering/strip.ts +81 -0
- package/src/lowering/thread.ts +5 -1
- package/src/lowering/trace.ts +270 -0
- package/src/lowering/uart.ts +6 -1
- package/src/lowering/usb.ts +16 -13
- package/src/lowering/wdt.ts +2 -25
- package/src/sbom.ts +1117 -0
- package/src/sdk/board-catalog-sync.ts +4 -25
- package/src/strategy.ts +2680 -2309
- package/src/toolchain/debug-config.ts +262 -522
- package/src/toolchain/env-check.ts +279 -285
- package/src/toolchain/index.ts +1792 -1359
- package/src/toolchain/runners.ts +80 -0
- package/src/toolchain/scaffold.ts +355 -296
- package/src/toolchain/west-discover.ts +35 -13
- package/src/toolchain/west-spawn.ts +174 -168
- package/src/west-inventory.ts +102 -0
- package/dist/async/timer-polyfill.d.ts +0 -10
- package/dist/async/timer-polyfill.js +0 -95
- package/dist/chips/board-overrides.d.ts +0 -7
- package/dist/chips/board-overrides.js +0 -11
- package/dist/chips/esp32.d.ts +0 -2
- package/dist/chips/esp32.js +0 -71
- package/dist/chips/esp32s3.d.ts +0 -2
- package/dist/chips/esp32s3.js +0 -103
- package/dist/chips/soc/.d.ts +0 -2
- package/dist/chips/soc/.js +0 -129
- package/dist/chips/soc/esp32.d.ts +0 -2
- package/dist/chips/soc/esp32.js +0 -120
- package/dist/chips/soc/esp32c3.d.ts +0 -2
- package/dist/chips/soc/esp32c3.js +0 -90
- package/dist/chips/soc/esp32c6.d.ts +0 -2
- package/dist/chips/soc/esp32c6.js +0 -109
- package/dist/chips/soc/esp32s3.d.ts +0 -2
- package/dist/chips/soc/esp32s3.js +0 -189
- package/dist/chips/soc/index.d.ts +0 -2
- package/dist/chips/soc/index.js +0 -23
- package/dist/chips/soc/nrf52840.d.ts +0 -2
- package/dist/chips/soc/nrf52840.js +0 -130
- package/dist/chips/soc/rp2040.d.ts +0 -2
- package/dist/chips/soc/rp2040.js +0 -141
- package/dist/chips/soc/rp2350a.d.ts +0 -2
- package/dist/chips/soc/rp2350a.js +0 -145
- package/dist/chips/soc/samd21g18a.d.ts +0 -2
- package/dist/chips/soc/samd21g18a.js +0 -143
- package/dist/chips/soc/stm32f411xe.d.ts +0 -2
- package/dist/chips/soc/stm32f411xe.js +0 -251
- package/dist/chips/xiao-ble.d.ts +0 -2
- package/dist/chips/xiao-ble.js +0 -100
- package/dist/lowering/pulse.d.ts +0 -7
- package/dist/lowering/pulse.js +0 -51
- package/dist/lowering/tone.d.ts +0 -10
- package/dist/lowering/tone.js +0 -63
- package/dist/lowering/worker-backing.d.ts +0 -14
- package/dist/lowering/worker-backing.js +0 -79
- package/dist/lowering/worker.d.ts +0 -6
- package/dist/lowering/worker.js +0 -14
- package/dist/sdk/board-data.generated.d.ts +0 -2
- package/dist/sdk/board-data.generated.js +0 -4
- package/dist/sdk/catalog-walker.d.ts +0 -90
- package/dist/sdk/catalog-walker.js +0 -682
- package/dist/sdk/dts-reader.d.ts +0 -83
- package/dist/sdk/dts-reader.js +0 -596
- package/src/debug-codegen.ts +0 -207
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// CAN lowering — Zephyr's can API over the harvested controller node
|
|
3
|
+
//
|
|
4
|
+
// The controller is addressed by its DT nodelabel (chip.can, the harvested
|
|
5
|
+
// can@ node — ESP32 TWAI, STM32 bxCAN, NXP FlexCAN…). begin() applies
|
|
6
|
+
// mode + bitrate + start in the required order (mode and bitrate need a
|
|
7
|
+
// stopped controller); send() builds one can_frame and submits it with a
|
|
8
|
+
// bounded timeout and no tx callback (blocking-send form); onReceive()
|
|
9
|
+
// installs the accept-all filter whose trampoline carries the frame as
|
|
10
|
+
// ten scalars — the Matrix discipline (ISR context, set-a-variable work).
|
|
11
|
+
// ----------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
14
|
+
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
15
|
+
|
|
16
|
+
/** The C variable names for a CAN controller's state. */
|
|
17
|
+
function prefix(idx: number): string {
|
|
18
|
+
return `__tc_can${idx}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Which can.* verbs the program actually uses on a controller — the
|
|
22
|
+
* init block emits only the state those verbs reference (Zephyr's -Werror
|
|
23
|
+
* turns an unreferenced static function/variable into a build failure:
|
|
24
|
+
* a send-only program must not carry the rx trampoline). */
|
|
25
|
+
export interface CanUsage {
|
|
26
|
+
begin: boolean;
|
|
27
|
+
send: boolean;
|
|
28
|
+
onReceive: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Emit the per-controller CAN state: device handle, rx trampoline +
|
|
33
|
+
* handler slot, and the accept-all filters. Called from shimLines when the
|
|
34
|
+
* program uses can.* on this controller and the chip declares it.
|
|
35
|
+
*/
|
|
36
|
+
export function canInitLines(chip: ZephyrChipDescriptor, controllerIndex: number, usage: CanUsage): string[] {
|
|
37
|
+
const ctrl = chip.can?.controllers[controllerIndex];
|
|
38
|
+
if (!ctrl) return [];
|
|
39
|
+
const p = prefix(controllerIndex);
|
|
40
|
+
const lines: string[] = [
|
|
41
|
+
'// CUTTLEFISH_CAN_BEGIN',
|
|
42
|
+
`static const struct device* ${p}_dev = DEVICE_DT_GET(DT_NODELABEL(${ctrl.nodeLabel}));`,
|
|
43
|
+
];
|
|
44
|
+
if (usage.begin) {
|
|
45
|
+
// Shim-scoped (not per call site): a second begin() anywhere in the
|
|
46
|
+
// program must not re-fire can_start on a started controller.
|
|
47
|
+
lines.push(`static bool ${p}_started = false;`);
|
|
48
|
+
}
|
|
49
|
+
if (usage.onReceive) {
|
|
50
|
+
lines.push(
|
|
51
|
+
`static void (*${p}_rx)(double, double, double, double, double, double, double, double, double, double) = NULL;`,
|
|
52
|
+
// dlc-bounded: drivers fill only data[0..dlc-1] — copy into a zeroed
|
|
53
|
+
// local so the handler's b0..b7 tail is zero, as the class documents.
|
|
54
|
+
'static void __tc_can_rx_trampoline(const struct device* dev, struct can_frame* frame, void* user_data) {',
|
|
55
|
+
' (void)dev;',
|
|
56
|
+
' (void)user_data;',
|
|
57
|
+
` if (${p}_rx != NULL) {`,
|
|
58
|
+
' uint8_t __tc_d[8] = { 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U };',
|
|
59
|
+
' for (uint32_t __tc_i = 0U; (__tc_i < 8U) && (__tc_i < static_cast<uint32_t>(frame->dlc)); ++__tc_i) { __tc_d[__tc_i] = frame->data[__tc_i]; }',
|
|
60
|
+
` ${p}_rx(static_cast<double>(frame->id), static_cast<double>(frame->dlc),`,
|
|
61
|
+
` static_cast<double>(__tc_d[0]), static_cast<double>(__tc_d[1]),`,
|
|
62
|
+
` static_cast<double>(__tc_d[2]), static_cast<double>(__tc_d[3]),`,
|
|
63
|
+
` static_cast<double>(__tc_d[4]), static_cast<double>(__tc_d[5]),`,
|
|
64
|
+
` static_cast<double>(__tc_d[6]), static_cast<double>(__tc_d[7]));`,
|
|
65
|
+
' }',
|
|
66
|
+
'}',
|
|
67
|
+
// Two accept-all filters: can_filter_matches_filter never delivers an
|
|
68
|
+
// IDE (29-bit) frame to a filter without CAN_FILTER_IDE — one filter
|
|
69
|
+
// per frame format, so extended sends are receivable too.
|
|
70
|
+
`static const struct can_filter ${p}_filter = { .id = 0U, .mask = 0U, .flags = 0U };`,
|
|
71
|
+
`static const struct can_filter ${p}_filter_ext = { .id = 0U, .mask = 0U, .flags = CAN_FILTER_IDE };`,
|
|
72
|
+
`static bool ${p}_filter_added = false;`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (usage.send) {
|
|
76
|
+
lines.push(
|
|
77
|
+
`static void __tc_can_tx_done(const struct device* dev, int error, void* user_data) {`,
|
|
78
|
+
' (void)dev; (void)error; (void)user_data;',
|
|
79
|
+
'}',
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
lines.push('// CUTTLEFISH_CAN_END');
|
|
83
|
+
return lines;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Resolve a HAL can.* op to Zephyr C++.
|
|
88
|
+
* Returns `{ code }` for statement ops.
|
|
89
|
+
*/
|
|
90
|
+
export function lowerCan(
|
|
91
|
+
op: HALOpIR,
|
|
92
|
+
chip: ZephyrChipDescriptor,
|
|
93
|
+
): { code?: string; expression?: string } {
|
|
94
|
+
const o = op as any;
|
|
95
|
+
// DAC discipline: a board with no harvested can@ node lowers to a comment
|
|
96
|
+
// naming the constraint (the board gate already refuses the CAN import;
|
|
97
|
+
// this keeps the manifest probe and direct-lowering paths honest).
|
|
98
|
+
if (!chip.can || chip.can.controllers.length === 0) {
|
|
99
|
+
return { code: `/* ${op.operation}: this board's chip data declares no CAN controller (no harvested can@ node) */` };
|
|
100
|
+
}
|
|
101
|
+
const idx = Math.min(Number(o.instance ?? 0), chip.can.controllers.length - 1);
|
|
102
|
+
const p = prefix(idx);
|
|
103
|
+
const started = `${p}_started`;
|
|
104
|
+
|
|
105
|
+
switch (op.operation) {
|
|
106
|
+
case 'can.begin': {
|
|
107
|
+
// Mode and bitrate require a STOPPED controller — apply them before
|
|
108
|
+
// the start, and start exactly once. Failures printk (the loud-
|
|
109
|
+
// diagnostics policy): a CAN bus that never comes up is otherwise a
|
|
110
|
+
// silent hang at the first send.
|
|
111
|
+
return {
|
|
112
|
+
code: `{ int __tc_err; if (${o.loopback}) { __tc_err = can_set_mode(${p}_dev, CAN_MODE_LOOPBACK); if (__tc_err != 0) { printk("typecad-hal can: set_mode failed: %d\\n", __tc_err); } } __tc_err = can_set_bitrate(${p}_dev, ${o.hz}); if (__tc_err != 0) { printk("typecad-hal can: bitrate failed: %d\\n", __tc_err); } if (!${started}) { ${started} = true; __tc_err = can_start(${p}_dev); if (__tc_err != 0) { printk("typecad-hal can: start failed: %d\\n", __tc_err); } } }`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
case 'can.send': {
|
|
116
|
+
const bytes = (o.data ?? []) as (number | string)[];
|
|
117
|
+
if (bytes.length > 8) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`CAN send: classic frames carry at most 8 bytes — got ${bytes.length}.`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const assigns = bytes
|
|
123
|
+
.map((b, i) => `__tc_frame.data[${i}] = static_cast<uint8_t>(${b});`)
|
|
124
|
+
.join(' ');
|
|
125
|
+
return {
|
|
126
|
+
code: `{ struct can_frame __tc_frame = { 0 }; __tc_frame.id = static_cast<uint32_t>(${o.id}); __tc_frame.dlc = ${bytes.length}U; __tc_frame.flags = ${o.extended ? 'CAN_FRAME_IDE' : '0U'}; ${assigns} int __tc_err = can_send(${p}_dev, &__tc_frame, K_MSEC(100), __tc_can_tx_done, NULL); if (__tc_err != 0) { printk("typecad-hal can: send failed: %d\\n", __tc_err); } }`,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
case 'can.on_receive': {
|
|
130
|
+
return {
|
|
131
|
+
code: `{ ${p}_rx = ${o.handler}; if (!${p}_filter_added) { ${p}_filter_added = true; (void)can_add_rx_filter(${p}_dev, __tc_can_rx_trampoline, NULL, &${p}_filter); (void)can_add_rx_filter(${p}_dev, __tc_can_rx_trampoline, NULL, &${p}_filter_ext); } }`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
default:
|
|
135
|
+
throw new Error(
|
|
136
|
+
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
137
|
+
`Open an issue or use rawCpp() to emit it manually.`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Clock lowering — rtc_set_time / rtc_get_time on the `rtc` DT alias
|
|
3
|
+
//
|
|
4
|
+
// The alias is Zephyr's own discovery convention. Boards with a hardware
|
|
5
|
+
// calendar RTC alias it themselves; the overlay generator synthesizes a
|
|
6
|
+
// zephyr,rtc-counter shim (a child of the board's first free counter — the
|
|
7
|
+
// counter driver keeps the parent, so Counter and Clock coexist) when they
|
|
8
|
+
// do not.
|
|
9
|
+
//
|
|
10
|
+
// Epoch ↔ civil conversion is Howard Hinnant's days_from_civil pair —
|
|
11
|
+
// pure int64 arithmetic, no libc timezone machinery, valid over the whole
|
|
12
|
+
// Unix range. The helpers live in the shim block so both ops share them.
|
|
13
|
+
// ----------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
16
|
+
|
|
17
|
+
const RTC_DEV = 'DEVICE_DT_GET(DT_ALIAS(rtc))';
|
|
18
|
+
|
|
19
|
+
/** The conversion helpers + device handle. Called from shimLines when the
|
|
20
|
+
* program uses clock.* — each helper only when its consuming op appears
|
|
21
|
+
* (a now()-only program must not carry the unused set() helper: -Werror
|
|
22
|
+
* fails the build on unreferenced static functions). */
|
|
23
|
+
export function clockInitLines(usage: { set: boolean; now: boolean }): string[] {
|
|
24
|
+
const lines: string[] = [
|
|
25
|
+
'// CUTTLEFISH_CLOCK_BEGIN',
|
|
26
|
+
`static const struct device* __tc_rtc = ${RTC_DEV};`,
|
|
27
|
+
];
|
|
28
|
+
if (usage.now) {
|
|
29
|
+
lines.push(
|
|
30
|
+
'static int64_t __tc_days_from_civil(int32_t yy, int32_t mm, int32_t dd) {',
|
|
31
|
+
' yy -= (mm <= 2) ? 1 : 0;',
|
|
32
|
+
' const int32_t era = (yy >= 0 ? yy : yy - 399) / 400;',
|
|
33
|
+
' const int32_t yoe = yy - era * 400;',
|
|
34
|
+
' const int32_t doy = (153 * (mm + (mm > 2 ? -3 : 9)) + 2) / 5 + dd - 1;',
|
|
35
|
+
' const int32_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;',
|
|
36
|
+
' return (static_cast<int64_t>(era) * 146097) + static_cast<int64_t>(doe) - 719468;',
|
|
37
|
+
'}',
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
if (usage.set) {
|
|
41
|
+
lines.push(
|
|
42
|
+
'static void __tc_civil_from_days(int64_t z, int32_t* yy, int32_t* mm, int32_t* dd) {',
|
|
43
|
+
' z += 719468;',
|
|
44
|
+
' const int64_t era = (z >= 0 ? z : z - 146096) / 146097;',
|
|
45
|
+
' const int64_t doe = z - (era * 146097);',
|
|
46
|
+
' const int64_t yoe = (doe - (doe / 1460) + (doe / 36524) - (doe / 146096)) / 365;',
|
|
47
|
+
' const int64_t y = yoe + (era * 400);',
|
|
48
|
+
' const int64_t doy = doe - ((365 * yoe) + (yoe / 4) - (yoe / 100));',
|
|
49
|
+
' const int64_t mp = ((5 * doy) + 2) / 153;',
|
|
50
|
+
' const int64_t d = doy - (((153 * mp) + 2) / 5) + 1;',
|
|
51
|
+
' const int64_t m = mp + (mp < 10 ? 3 : -9);',
|
|
52
|
+
' *yy = static_cast<int32_t>(y + (m <= 2 ? 1 : 0));',
|
|
53
|
+
' *mm = static_cast<int32_t>(m);',
|
|
54
|
+
' *dd = static_cast<int32_t>(d);',
|
|
55
|
+
'}',
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
lines.push('// CUTTLEFISH_CLOCK_END');
|
|
59
|
+
return lines;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The all-zero/unknown rtc_time initializer (wday/yday unknown per the
|
|
63
|
+
* struct's contract). */
|
|
64
|
+
const TM_INIT = 'struct rtc_time __tc_tm = { 0, 0, 0, 0, 0, 0, -1, -1, -1, 0 }';
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolve a HAL clock.* op to Zephyr C++.
|
|
68
|
+
* Returns `{ code }` for set, `{ expression }` for now.
|
|
69
|
+
*/
|
|
70
|
+
export function lowerClock(op: HALOpIR): { code?: string; expression?: string } {
|
|
71
|
+
const o = op as any;
|
|
72
|
+
|
|
73
|
+
switch (op.operation) {
|
|
74
|
+
case 'clock.set': {
|
|
75
|
+
// epoch (runtime text) → civil date → rtc_set_time.
|
|
76
|
+
return {
|
|
77
|
+
code: `{ int64_t __tc_ep = static_cast<int64_t>(${o.epoch}); int32_t __tc_y = 0; int32_t __tc_mo = 0; int32_t __tc_d = 0; __tc_civil_from_days(__tc_ep / 86400, &__tc_y, &__tc_mo, &__tc_d); int64_t __tc_sod = __tc_ep % 86400; ${TM_INIT}; __tc_tm.tm_year = __tc_y - 1900; __tc_tm.tm_mon = __tc_mo - 1; __tc_tm.tm_mday = __tc_d; __tc_tm.tm_hour = static_cast<int32_t>(__tc_sod / 3600); __tc_tm.tm_min = static_cast<int32_t>((__tc_sod % 3600) / 60); __tc_tm.tm_sec = static_cast<int32_t>(__tc_sod % 60); (void)rtc_set_time(__tc_rtc, &__tc_tm); }`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
case 'clock.now': {
|
|
81
|
+
return {
|
|
82
|
+
expression: `({ ${TM_INIT}; double __tc_epoch = 0.0; if (rtc_get_time(__tc_rtc, &__tc_tm) == 0) { int64_t __tc_days = __tc_days_from_civil(__tc_tm.tm_year + 1900, __tc_tm.tm_mon + 1, __tc_tm.tm_mday); __tc_epoch = static_cast<double>((__tc_days * 86400) + (static_cast<int64_t>(__tc_tm.tm_hour) * 3600) + (static_cast<int64_t>(__tc_tm.tm_min) * 60) + static_cast<int64_t>(__tc_tm.tm_sec)); } __tc_epoch; })`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
default:
|
|
86
|
+
throw new Error(
|
|
87
|
+
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
88
|
+
`Open an issue or use rawCpp() to emit it manually.`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/lowering/fs.ts
CHANGED
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Filesystem lowering — Zephyr FS API (littlefs on the storage partition)
|
|
3
|
-
//
|
|
4
|
-
// HAL `fs.*` (begin/read_text/write_text/exists/remove) maps onto Zephyr's
|
|
5
|
-
// <zephyr/fs/fs.h>. A littlefs filesystem is mounted at "/lfs" on the board's
|
|
6
|
-
// `storage_partition` fixed-partition (the same partition the ZMS settings
|
|
7
|
-
// backend uses for preferences — a program should not use both surfaces at
|
|
8
|
-
// once without dedicating separate partitions). The mount is lazy: it formats
|
|
9
|
-
// + remounts on first use when the partition is unformatted.
|
|
10
|
-
//
|
|
11
|
-
// The HAL paths are treated as paths WITHIN the filesystem: the shim joins the
|
|
12
|
-
// mount point, so fs.read_text("/data.txt") reads "/lfs/data.txt". This keeps
|
|
13
|
-
// the mount point an implementation detail.
|
|
14
|
-
//
|
|
15
|
-
// Requires Kconfig CONFIG_FILE_SYSTEM + CONFIG_FILE_SYSTEM_LITTLEFS (+ FLASH /
|
|
16
|
-
// FLASH_MAP) — emitted by the scaffold when the program uses fs.* — and the
|
|
17
|
-
// storage_partition node (added by the overlay).
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Emit the littlefs mount + the typed helper API the lowering calls into.
|
|
24
|
-
* Called from shimLines when the program uses the filesystem. The helpers are
|
|
25
|
-
* `static` so multiple TUs that carry the shim (guarded by the include guard)
|
|
26
|
-
* do not collide.
|
|
27
|
-
*/
|
|
28
|
-
export function fsInitLines(): string[] {
|
|
29
|
-
return [
|
|
30
|
-
'// CUTTLEFISH_FS_BEGIN',
|
|
31
|
-
'static struct fs_mount_t __tc_fs_mp;',
|
|
32
|
-
'static bool __tc_fs_mounted = false;',
|
|
33
|
-
'',
|
|
34
|
-
'FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(__tc_fs_data);',
|
|
35
|
-
'static struct fs_mount_t __tc_fs_mp_init = {',
|
|
36
|
-
' .type = FS_LITTLEFS,',
|
|
37
|
-
' .mnt_point = "/lfs",',
|
|
38
|
-
' .fs_data = &__tc_fs_data,',
|
|
39
|
-
' .storage_dev = (void *)FIXED_PARTITION_ID(storage_partition),',
|
|
40
|
-
'};',
|
|
41
|
-
'',
|
|
42
|
-
'static void __tc_fs_ensure_mount(void) {',
|
|
43
|
-
' if (__tc_fs_mounted) return;',
|
|
44
|
-
' __tc_fs_mp = __tc_fs_mp_init;',
|
|
45
|
-
' int rc = fs_mount(&__tc_fs_mp);',
|
|
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.',
|
|
50
|
-
' (void)fs_mkfs(FS_LITTLEFS, static_cast<uintptr_t>(FIXED_PARTITION_ID(storage_partition)), NULL, 0);',
|
|
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), "
|
|
58
|
-
' __tc_println(__tc_fs_err);',
|
|
59
|
-
' }',
|
|
60
|
-
'}',
|
|
61
|
-
'',
|
|
62
|
-
'// Join the mount point with the user path (paths are within the FS).',
|
|
63
|
-
'static const char* __tc_fs_path(const char* p) {',
|
|
64
|
-
' static char buf[128];',
|
|
65
|
-
' if (!p) return "/lfs";',
|
|
66
|
-
' const char* s = (p[0] == \'/\') ? p + 1 : p;',
|
|
67
|
-
' (void)snprintf(buf, sizeof(buf), "/lfs/%s", s);',
|
|
68
|
-
' return buf;',
|
|
69
|
-
'}',
|
|
70
|
-
'',
|
|
71
|
-
'static bool __tc_fs_begin(void) { __tc_fs_ensure_mount(); return true; }',
|
|
72
|
-
'',
|
|
73
|
-
'static const char* __tc_fs_read_text(const char* path) {',
|
|
74
|
-
' __tc_fs_ensure_mount();',
|
|
75
|
-
' static char buf[256];',
|
|
76
|
-
' buf[0] = 0;',
|
|
77
|
-
' struct fs_file_t f;',
|
|
78
|
-
' fs_file_t_init(&f);',
|
|
79
|
-
' if (fs_open(&f, __tc_fs_path(path), FS_O_READ) == 0) {',
|
|
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;',
|
|
85
|
-
' (void)fs_close(&f);',
|
|
86
|
-
' }',
|
|
87
|
-
' return buf;',
|
|
88
|
-
'}',
|
|
89
|
-
'',
|
|
90
|
-
'static void __tc_fs_write_text(const char* path, const char* content) {',
|
|
91
|
-
' __tc_fs_ensure_mount();',
|
|
92
|
-
' struct fs_file_t f;',
|
|
93
|
-
' fs_file_t_init(&f);',
|
|
94
|
-
' if (fs_open(&f, __tc_fs_path(path), FS_O_WRITE | FS_O_CREATE | FS_O_TRUNC) == 0) {',
|
|
95
|
-
' (void)fs_write(&f, content, (content ? strlen(content) : 0));',
|
|
96
|
-
' (void)fs_close(&f);',
|
|
97
|
-
' }',
|
|
98
|
-
'}',
|
|
99
|
-
'',
|
|
100
|
-
'static bool __tc_fs_exists(const char* path) {',
|
|
101
|
-
' __tc_fs_ensure_mount();',
|
|
102
|
-
' struct fs_dirent ent;',
|
|
103
|
-
' return fs_stat(__tc_fs_path(path), &ent) == 0;',
|
|
104
|
-
'}',
|
|
105
|
-
'',
|
|
106
|
-
'static bool __tc_fs_remove(const char* path) {',
|
|
107
|
-
' __tc_fs_ensure_mount();',
|
|
108
|
-
' return fs_unlink(__tc_fs_path(path)) == 0;',
|
|
109
|
-
'}',
|
|
110
|
-
'// CUTTLEFISH_FS_END',
|
|
111
|
-
];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Resolve a HAL fs.* op to Zephyr C++.
|
|
116
|
-
* Returns `{ code }` — each op's code is the body of the HAL FS class method.
|
|
117
|
-
*/
|
|
118
|
-
export function lowerFs(op: HALOpIR): { code?: string; expression?: string } {
|
|
119
|
-
const o = op as any;
|
|
120
|
-
switch (op.operation) {
|
|
121
|
-
case 'fs.read_text':
|
|
122
|
-
return { code: `return __tc_fs_read_text(${o.path});` };
|
|
123
|
-
case 'fs.write_text':
|
|
124
|
-
return { code: `__tc_fs_write_text(${o.path}, ${o.content});` };
|
|
125
|
-
case 'fs.exists':
|
|
126
|
-
return { code: `return __tc_fs_exists(${o.path});` };
|
|
127
|
-
case 'fs.remove':
|
|
128
|
-
return { code: `return __tc_fs_remove(${o.path});` };
|
|
129
|
-
default:
|
|
130
|
-
throw new Error(
|
|
131
|
-
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
132
|
-
`Open an issue or use rawCpp() to emit it manually.`,
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Filesystem lowering — Zephyr FS API (littlefs on the storage partition)
|
|
3
|
+
//
|
|
4
|
+
// HAL `fs.*` (begin/read_text/write_text/exists/remove) maps onto Zephyr's
|
|
5
|
+
// <zephyr/fs/fs.h>. A littlefs filesystem is mounted at "/lfs" on the board's
|
|
6
|
+
// `storage_partition` fixed-partition (the same partition the ZMS settings
|
|
7
|
+
// backend uses for preferences — a program should not use both surfaces at
|
|
8
|
+
// once without dedicating separate partitions). The mount is lazy: it formats
|
|
9
|
+
// + remounts on first use when the partition is unformatted.
|
|
10
|
+
//
|
|
11
|
+
// The HAL paths are treated as paths WITHIN the filesystem: the shim joins the
|
|
12
|
+
// mount point, so fs.read_text("/data.txt") reads "/lfs/data.txt". This keeps
|
|
13
|
+
// the mount point an implementation detail.
|
|
14
|
+
//
|
|
15
|
+
// Requires Kconfig CONFIG_FILE_SYSTEM + CONFIG_FILE_SYSTEM_LITTLEFS (+ FLASH /
|
|
16
|
+
// FLASH_MAP) — emitted by the scaffold when the program uses fs.* — and the
|
|
17
|
+
// storage_partition node (added by the overlay).
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Emit the littlefs mount + the typed helper API the lowering calls into.
|
|
24
|
+
* Called from shimLines when the program uses the filesystem. The helpers are
|
|
25
|
+
* `static` so multiple TUs that carry the shim (guarded by the include guard)
|
|
26
|
+
* do not collide.
|
|
27
|
+
*/
|
|
28
|
+
export function fsInitLines(): string[] {
|
|
29
|
+
return [
|
|
30
|
+
'// CUTTLEFISH_FS_BEGIN',
|
|
31
|
+
'static struct fs_mount_t __tc_fs_mp;',
|
|
32
|
+
'static bool __tc_fs_mounted = false;',
|
|
33
|
+
'',
|
|
34
|
+
'FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(__tc_fs_data);',
|
|
35
|
+
'static struct fs_mount_t __tc_fs_mp_init = {',
|
|
36
|
+
' .type = FS_LITTLEFS,',
|
|
37
|
+
' .mnt_point = "/lfs",',
|
|
38
|
+
' .fs_data = &__tc_fs_data,',
|
|
39
|
+
' .storage_dev = (void *)FIXED_PARTITION_ID(storage_partition),',
|
|
40
|
+
'};',
|
|
41
|
+
'',
|
|
42
|
+
'static void __tc_fs_ensure_mount(void) {',
|
|
43
|
+
' if (__tc_fs_mounted) return;',
|
|
44
|
+
' __tc_fs_mp = __tc_fs_mp_init;',
|
|
45
|
+
' int rc = fs_mount(&__tc_fs_mp);',
|
|
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.',
|
|
50
|
+
' (void)fs_mkfs(FS_LITTLEFS, static_cast<uintptr_t>(FIXED_PARTITION_ID(storage_partition)), NULL, 0);',
|
|
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), "typecad-hal-fs: mount failed rc=%d", rc);',
|
|
58
|
+
' __tc_println(__tc_fs_err);',
|
|
59
|
+
' }',
|
|
60
|
+
'}',
|
|
61
|
+
'',
|
|
62
|
+
'// Join the mount point with the user path (paths are within the FS).',
|
|
63
|
+
'static const char* __tc_fs_path(const char* p) {',
|
|
64
|
+
' static char buf[128];',
|
|
65
|
+
' if (!p) return "/lfs";',
|
|
66
|
+
' const char* s = (p[0] == \'/\') ? p + 1 : p;',
|
|
67
|
+
' (void)snprintf(buf, sizeof(buf), "/lfs/%s", s);',
|
|
68
|
+
' return buf;',
|
|
69
|
+
'}',
|
|
70
|
+
'',
|
|
71
|
+
'static bool __tc_fs_begin(void) { __tc_fs_ensure_mount(); return true; }',
|
|
72
|
+
'',
|
|
73
|
+
'static const char* __tc_fs_read_text(const char* path) {',
|
|
74
|
+
' __tc_fs_ensure_mount();',
|
|
75
|
+
' static char buf[256];',
|
|
76
|
+
' buf[0] = 0;',
|
|
77
|
+
' struct fs_file_t f;',
|
|
78
|
+
' fs_file_t_init(&f);',
|
|
79
|
+
' if (fs_open(&f, __tc_fs_path(path), FS_O_READ) == 0) {',
|
|
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;',
|
|
85
|
+
' (void)fs_close(&f);',
|
|
86
|
+
' }',
|
|
87
|
+
' return buf;',
|
|
88
|
+
'}',
|
|
89
|
+
'',
|
|
90
|
+
'static void __tc_fs_write_text(const char* path, const char* content) {',
|
|
91
|
+
' __tc_fs_ensure_mount();',
|
|
92
|
+
' struct fs_file_t f;',
|
|
93
|
+
' fs_file_t_init(&f);',
|
|
94
|
+
' if (fs_open(&f, __tc_fs_path(path), FS_O_WRITE | FS_O_CREATE | FS_O_TRUNC) == 0) {',
|
|
95
|
+
' (void)fs_write(&f, content, (content ? strlen(content) : 0));',
|
|
96
|
+
' (void)fs_close(&f);',
|
|
97
|
+
' }',
|
|
98
|
+
'}',
|
|
99
|
+
'',
|
|
100
|
+
'static bool __tc_fs_exists(const char* path) {',
|
|
101
|
+
' __tc_fs_ensure_mount();',
|
|
102
|
+
' struct fs_dirent ent;',
|
|
103
|
+
' return fs_stat(__tc_fs_path(path), &ent) == 0;',
|
|
104
|
+
'}',
|
|
105
|
+
'',
|
|
106
|
+
'static bool __tc_fs_remove(const char* path) {',
|
|
107
|
+
' __tc_fs_ensure_mount();',
|
|
108
|
+
' return fs_unlink(__tc_fs_path(path)) == 0;',
|
|
109
|
+
'}',
|
|
110
|
+
'// CUTTLEFISH_FS_END',
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Resolve a HAL fs.* op to Zephyr C++.
|
|
116
|
+
* Returns `{ code }` — each op's code is the body of the HAL FS class method.
|
|
117
|
+
*/
|
|
118
|
+
export function lowerFs(op: HALOpIR): { code?: string; expression?: string } {
|
|
119
|
+
const o = op as any;
|
|
120
|
+
switch (op.operation) {
|
|
121
|
+
case 'fs.read_text':
|
|
122
|
+
return { code: `return __tc_fs_read_text(${o.path});` };
|
|
123
|
+
case 'fs.write_text':
|
|
124
|
+
return { code: `__tc_fs_write_text(${o.path}, ${o.content});` };
|
|
125
|
+
case 'fs.exists':
|
|
126
|
+
return { code: `return __tc_fs_exists(${o.path});` };
|
|
127
|
+
case 'fs.remove':
|
|
128
|
+
return { code: `return __tc_fs_remove(${o.path});` };
|
|
129
|
+
default:
|
|
130
|
+
throw new Error(
|
|
131
|
+
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
132
|
+
`Open an issue or use rawCpp() to emit it manually.`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
package/src/lowering/gpio.ts
CHANGED
|
@@ -30,39 +30,6 @@ function findDtSpec(chip: ZephyrChipDescriptor, pin: number) {
|
|
|
30
30
|
return chip.gpio.dtSpecs.find((s) => s.pin === pin);
|
|
31
31
|
}
|
|
32
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
33
|
// ── Thin GPIO (hal/gpio-pin.ts) — flag tokens ─────────────────────────────
|
|
67
34
|
//
|
|
68
35
|
// "GPIO.OUTPUT | GPIO.PULL_UP" token text maps name-for-name onto the GPIO_*
|