@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/adc.ts
CHANGED
|
@@ -1,102 +1,222 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// ADC lowering — nRF SAADC via raw adc_read
|
|
3
|
-
//
|
|
4
|
-
// The XIAO nRF52840 has no pre-declared ADC channel nodes in devicetree, so we
|
|
5
|
-
// cannot use the `adc_dt_spec` convenience. Instead the lowering configures the
|
|
6
|
-
// channel up-front against DEVICE_DT_GET(DT_NODELABEL(adc)) and reads it with
|
|
7
|
-
// `adc_read`. The channel index comes from the chip descriptor's pin→channel
|
|
8
|
-
// map (XIAO D0–D3 = AIN0–AIN3).
|
|
9
|
-
//
|
|
10
|
-
// Channel setup is emitted in adcInitLines() (one per channel used); the ops
|
|
11
|
-
// then just read. A static `adc_channel_cfg` + a per-channel "configured" flag
|
|
12
|
-
// guards the setup, so repeated reads don't reconfigure.
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
16
|
-
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// ADC lowering — nRF SAADC via raw adc_read
|
|
3
|
+
//
|
|
4
|
+
// The XIAO nRF52840 has no pre-declared ADC channel nodes in devicetree, so we
|
|
5
|
+
// cannot use the `adc_dt_spec` convenience. Instead the lowering configures the
|
|
6
|
+
// channel up-front against DEVICE_DT_GET(DT_NODELABEL(adc)) and reads it with
|
|
7
|
+
// `adc_read`. The channel index comes from the chip descriptor's pin→channel
|
|
8
|
+
// map (XIAO D0–D3 = AIN0–AIN3).
|
|
9
|
+
//
|
|
10
|
+
// Channel setup is emitted in adcInitLines() (one per channel used); the ops
|
|
11
|
+
// then just read. A static `adc_channel_cfg` + a per-channel "configured" flag
|
|
12
|
+
// guards the setup, so repeated reads don't reconfigure.
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
16
|
+
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
17
|
+
import { ZEPHYR_ADC_GAINS, ZEPHYR_ADC_REFERENCES } from '@typecad/hal';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the SAADC channel index for an adc.read argument; -1 if unmapped.
|
|
21
|
+
*
|
|
22
|
+
* The numeric argument serves two HAL forms: `InputPin.readAnalog()` passes
|
|
23
|
+
* a GPIO number, while the Arduino-compat `ADC.read(channel)` passes an ADC
|
|
24
|
+
* channel number. Pin-first resolution keeps readAnalog behavior unchanged;
|
|
25
|
+
* the channel fallback makes `ADC.read(n)` resolve on targets where channel
|
|
26
|
+
* n does not alias GPIO n (e.g. the XIAO's AIN2 = P0.28). Where a number
|
|
27
|
+
* matches both a mapped pin and another channel's index, the pin wins.
|
|
28
|
+
*/
|
|
29
|
+
export function adcChannelForPin(chip: ZephyrChipDescriptor, pin: number): number {
|
|
30
|
+
const channels = chip.adc?.channels ?? [];
|
|
31
|
+
const byPin = channels.find((c) => c.pin === pin);
|
|
32
|
+
if (byPin) return byPin.channel;
|
|
33
|
+
const byChannel = channels.find((c) => c.channel === pin);
|
|
34
|
+
return byChannel ? byChannel.channel : -1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the owning ADC controller's node label for an adc.read argument.
|
|
39
|
+
* Defaults to the descriptor's primary (`chip.adc.nodeLabel`) — channels on
|
|
40
|
+
* additional controllers (STM32 adc3-only routes, ESP32 adc2 pads) carry
|
|
41
|
+
* their controller explicitly, and their device handle is
|
|
42
|
+
* `__tc_adc_<label>_dev` (the primary keeps the unsuffixed `__tc_adc_dev`
|
|
43
|
+
* so single-controller output is unchanged).
|
|
44
|
+
*/
|
|
45
|
+
export function adcControllerForPin(chip: ZephyrChipDescriptor, pin: number): string {
|
|
46
|
+
const channels = chip.adc?.channels ?? [];
|
|
47
|
+
const byPin = channels.find((c) => c.pin === pin);
|
|
48
|
+
if (byPin) return byPin.controller ?? chip.adc?.nodeLabel ?? 'adc';
|
|
49
|
+
const byChannel = channels.find((c) => c.channel === pin);
|
|
50
|
+
return byChannel?.controller ?? chip.adc?.nodeLabel ?? 'adc';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The C++ device-handle symbol for an ADC controller nodelabel. The primary
|
|
54
|
+
* controller maps to the historical unsuffixed `__tc_adc_dev`. */
|
|
55
|
+
function adcDevSymbol(controller: string, primary: string): string {
|
|
56
|
+
return controller === primary ? '__tc_adc_dev' : `__tc_adc_${controller}_dev`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ── Thin ADC (hal/adc-pin.ts) — gain/reference tokens ──────────────────────
|
|
60
|
+
//
|
|
61
|
+
// "ADC.GAIN_1_4" / "ADC.REF_INTERNAL" token text maps name-for-
|
|
62
|
+
// name onto the enum adc_gain / adc_reference macros. The name sets come from
|
|
63
|
+
// the GENERATED Zephyr token tables (scripts/gen-zephyr-hal-tokens.mjs —
|
|
64
|
+
// parsed from the pinned tree's headers, so the set cannot drift from
|
|
65
|
+
// upstream); empty/absent tokens mean "use the chip descriptor's pair".
|
|
66
|
+
|
|
67
|
+
const ADC_GAIN_TOKENS: Record<string, string> = Object.fromEntries(
|
|
68
|
+
ZEPHYR_ADC_GAINS.map((g) => [`ADC.GAIN_${g}`, `ADC_GAIN_${g}`]),
|
|
69
|
+
);
|
|
70
|
+
const ADC_REF_TOKENS: Record<string, string> = Object.fromEntries(
|
|
71
|
+
ZEPHYR_ADC_REFERENCES.map((r) => [`ADC.REF_${r}`, `ADC_REF_${r}`]),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
/** Resolve one thin-ADC token to its macro; undefined when absent/empty.
|
|
75
|
+
* Unknown tokens are build errors naming the valid spellings. */
|
|
76
|
+
function adcThinToken(token: string | undefined, map: Record<string, string>, kind: string): string | undefined {
|
|
77
|
+
const t = String(token ?? '').trim();
|
|
78
|
+
if (!t || t === '0' || t === "''") return undefined;
|
|
79
|
+
const m = map[t];
|
|
80
|
+
if (!m) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`ADC ${kind} token '${t}' is not a known ADC.* token — valid ${kind}s: ${Object.keys(map).join(', ')}.`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
return m;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Emit the per-channel ADC setup state. One block per channel in the chip
|
|
90
|
+
* descriptor that the PROGRAM ACTUALLY READS (`usedPins`) — an unread
|
|
91
|
+
* channel's `static` setup function would trip -Wunused-function in the
|
|
92
|
+
* single generated TU. When `usedPins` is omitted (probe paths with no
|
|
93
|
+
* program), every descriptor channel is emitted. Each block is guarded by a
|
|
94
|
+
* `static bool __tc_adc<N>_ready` so the first read configures it and
|
|
95
|
+
* subsequent reads skip. Called from shimLines when the program uses ADC.
|
|
96
|
+
*/
|
|
97
|
+
export function adcInitLines(
|
|
98
|
+
chip: ZephyrChipDescriptor,
|
|
99
|
+
usedPins?: ReadonlySet<number>,
|
|
100
|
+
overrideDevices?: ReadonlySet<string>,
|
|
101
|
+
): string[] {
|
|
102
|
+
const primary = chip.adc?.nodeLabel ?? 'adc';
|
|
103
|
+
const res = chip.adc?.resolution ?? 12;
|
|
104
|
+
const vref = chip.adc?.vrefMv ?? 3000;
|
|
105
|
+
// Gain/reference are SoC-specific: the nRF SAADC scheme (gain 1/4 against
|
|
106
|
+
// the 0.6V internal ref, vref-mv 3000 = VDD) is the default; the STM32
|
|
107
|
+
// driver requires exactly ADC_GAIN_1 + ADC_REF_INTERNAL (Zephyr maps
|
|
108
|
+
// "internal" to the VREF+ pad) with vref-mv = VDDA. The descriptor carries
|
|
109
|
+
// the SoC's pair so the emitted channel setup validates in the driver.
|
|
110
|
+
const gain = chip.adc?.gain ?? 'ADC_GAIN_1_4';
|
|
111
|
+
const reference = chip.adc?.reference ?? 'ADC_REF_INTERNAL';
|
|
112
|
+
const owns = (c: { controller?: string }, label: string) => (c.controller ?? primary) === label;
|
|
113
|
+
const channels = (chip.adc?.channels ?? []).filter(
|
|
114
|
+
(c) =>
|
|
115
|
+
!usedPins ||
|
|
116
|
+
// Pin-form usage (the ADC/readAnalog path): the exact channel.
|
|
117
|
+
[...usedPins].some((n) => n === c.pin) ||
|
|
118
|
+
// Channel-number fallback (the Arduino-compat ADC.read(n) form) — must
|
|
119
|
+
// match the CONTROLLER too, or colliding indices across controllers
|
|
120
|
+
// (both ESP32 SARADC units expose channel 0) over-include.
|
|
121
|
+
[...usedPins].some((n) => adcChannelForPin(chip, n) === c.channel && owns(c, adcControllerForPin(chip, n))),
|
|
122
|
+
);
|
|
123
|
+
const lines: string[] = ['// CUTTLEFISH_ADC_BEGIN'];
|
|
124
|
+
lines.push(`static const struct device* __tc_adc_dev = DEVICE_DT_GET(DT_NODELABEL(${primary}));`);
|
|
125
|
+
// Additional controllers referenced by used channels get their own device
|
|
126
|
+
// handle (sorted for deterministic output). Channel indices collide across
|
|
127
|
+
// controllers, so non-primary setup symbols carry the controller label.
|
|
128
|
+
const extraControllers = [...new Set(channels.map((c) => c.controller).filter((x): x is string => !!x && x !== primary))].sort();
|
|
129
|
+
// Inline-override devices (escape hatch): handles for the DT labels the
|
|
130
|
+
// construction opts name — they may not appear in the manifest at all.
|
|
131
|
+
for (const label of (overrideDevices ?? [])) {
|
|
132
|
+
if (label !== primary && !extraControllers.includes(label)) extraControllers.push(label);
|
|
133
|
+
}
|
|
134
|
+
for (const label of extraControllers) {
|
|
135
|
+
lines.push(`static const struct device* __tc_adc_${label}_dev = DEVICE_DT_GET(DT_NODELABEL(${label}));`);
|
|
136
|
+
}
|
|
137
|
+
for (const c of channels) {
|
|
138
|
+
const n = c.channel;
|
|
139
|
+
const dev = adcDevSymbol(c.controller ?? primary, primary);
|
|
140
|
+
const sym = c.controller && c.controller !== primary ? `__tc_adc_${c.controller}_${n}` : `__tc_adc${n}`;
|
|
141
|
+
lines.push(
|
|
142
|
+
`static bool ${sym}_ready = false;`,
|
|
143
|
+
`static void ${sym}_setup(void) {`,
|
|
144
|
+
` if (${sym}_ready) return;`,
|
|
145
|
+
` const struct adc_channel_cfg cfg = {`,
|
|
146
|
+
` .gain = ${gain},`,
|
|
147
|
+
` .reference = ${reference},`,
|
|
148
|
+
` .acquisition_time = ADC_ACQ_TIME_DEFAULT,`,
|
|
149
|
+
` .channel_id = ${n},`,
|
|
150
|
+
` .differential = 0,`,
|
|
151
|
+
` };`,
|
|
152
|
+
` adc_channel_setup(${dev}, &cfg);`,
|
|
153
|
+
` ${sym}_ready = true;`,
|
|
154
|
+
`}`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
lines.push(`#define __TC_ADC_VREF_MV ${vref}`);
|
|
158
|
+
lines.push(`#define __TC_ADC_RESOLUTION ${res}`);
|
|
159
|
+
lines.push('// CUTTLEFISH_ADC_END');
|
|
160
|
+
return lines;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Resolve a HAL adc.* op to Zephyr C++.
|
|
165
|
+
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
|
166
|
+
*/
|
|
167
|
+
export function lowerAdc(
|
|
168
|
+
op: HALOpIR,
|
|
169
|
+
chip: ZephyrChipDescriptor,
|
|
170
|
+
): { code?: string; expression?: string } {
|
|
171
|
+
const o = op as any;
|
|
172
|
+
const res = chip.adc?.resolution ?? 12;
|
|
173
|
+
const vref = chip.adc?.vrefMv ?? 3000;
|
|
174
|
+
const gain = chip.adc?.gain ?? 'ADC_GAIN_1_4';
|
|
175
|
+
const reference = chip.adc?.reference ?? 'ADC_REF_INTERNAL';
|
|
176
|
+
|
|
177
|
+
switch (op.operation) {
|
|
178
|
+
case 'adc.read_raw':
|
|
179
|
+
case 'adc.read_mv': {
|
|
180
|
+
// Construction-time overrides (hal/adc-pin.ts opts: channel/device/
|
|
181
|
+
// pinctrl): the user vouches for the routing on a pin the facts layer
|
|
182
|
+
// does not cover. The channel and device symbol come from the op; the
|
|
183
|
+
// marker comment carries device/pinctrl to the overlay regen (the
|
|
184
|
+
// transpiler cannot synthesize DT nodes) and suppresses the
|
|
185
|
+
// unavailable-pin diagnostic.
|
|
186
|
+
const hasOverride = (typeof o.channelOverride === 'number' && o.channelOverride >= 0)
|
|
187
|
+
|| (typeof o.deviceOverride === 'string' && o.deviceOverride !== '')
|
|
188
|
+
|| (typeof o.pinctrlOverride === 'string' && o.pinctrlOverride !== '');
|
|
189
|
+
const ch = hasOverride && typeof o.channelOverride === 'number' && o.channelOverride >= 0
|
|
190
|
+
? (o.channelOverride as number)
|
|
191
|
+
: adcChannelForPin(chip, o.pin);
|
|
192
|
+
const primary = chip.adc?.nodeLabel ?? 'adc';
|
|
193
|
+
const devCtrl = (typeof o.deviceOverride === 'string' && o.deviceOverride !== '')
|
|
194
|
+
? (o.deviceOverride as string)
|
|
195
|
+
: adcControllerForPin(chip, o.pin);
|
|
196
|
+
const dev = adcDevSymbol(devCtrl, primary);
|
|
197
|
+
const gainMacro = adcThinToken(o.gain, ADC_GAIN_TOKENS, 'gain');
|
|
198
|
+
const refMacro = adcThinToken(o.reference, ADC_REF_TOKENS, 'reference');
|
|
199
|
+
const g = gainMacro ?? gain;
|
|
200
|
+
const r = refMacro ?? reference;
|
|
201
|
+
const marker = hasOverride
|
|
202
|
+
? `/* cuttlefish-user-facts: adc pin=${o.pin}`
|
|
203
|
+
+ `${typeof o.deviceOverride === 'string' && o.deviceOverride !== '' ? ` device=${o.deviceOverride}` : ''}`
|
|
204
|
+
+ `${typeof o.pinctrlOverride === 'string' && o.pinctrlOverride !== '' ? ` pinctrl=${o.pinctrlOverride}` : ''}`
|
|
205
|
+
+ ` channel=${ch} */ `
|
|
206
|
+
: '';
|
|
207
|
+
const setup = `static bool __tc_adct${o.pin}_done = false; if (!__tc_adct${o.pin}_done) { const struct adc_channel_cfg __tc_adct${o.pin}_cfg = { .gain = ${g}, .reference = ${r}, .acquisition_time = ADC_ACQ_TIME_DEFAULT, .channel_id = ${ch}, .differential = 0 }; adc_channel_setup(${dev}, &__tc_adct${o.pin}_cfg); __tc_adct${o.pin}_done = true; }`;
|
|
208
|
+
const read = `int16_t __b = 0; struct adc_sequence __s = { .channels = BIT(${ch}), .buffer = &__b, .buffer_size = sizeof(__b), .resolution = ${res} }; adc_read(${dev}, &__s);`;
|
|
209
|
+
if (op.operation === 'adc.read_raw') {
|
|
210
|
+
return { expression: `({ ${marker}${setup} ${read} __b; })` };
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
expression: `({ ${marker}${setup} ${read} int32_t __v = __b; adc_raw_to_millivolts(${vref}, ${g}, ${res}, &__v); __v; })`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
default:
|
|
217
|
+
throw new Error(
|
|
218
|
+
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
219
|
+
`Open an issue or use rawCpp() to emit it manually.`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
package/src/lowering/ble.ts
CHANGED
|
@@ -91,6 +91,9 @@ export function bleInitLines(): string[] {
|
|
|
91
91
|
`// bt_gatt_chrc metadata for each characteristic declaration attr.`,
|
|
92
92
|
`static struct bt_gatt_chrc __tc_ble_chrc_meta[__TC_BLE_MAX_CHARS];`,
|
|
93
93
|
`// The flat attribute array + its wrapping service. Plus per-char CCC cfg.`,
|
|
94
|
+
`static struct bt_gatt_ccc_managed_user_data __tc_ble_ccc[__TC_BLE_MAX_CHARS];`,
|
|
95
|
+
`// write_ccc dereferences cfg_changed — every slot needs the no-op.`,
|
|
96
|
+
`static void __tc_ble_ccc_changed(const struct bt_gatt_attr* a, uint16_t v) { (void)a; (void)v; }`,
|
|
94
97
|
`static struct bt_gatt_attr __tc_ble_attrs[__TC_BLE_MAX_ATTRS];`,
|
|
95
98
|
`static size_t __tc_ble_attr_count = 0;`,
|
|
96
99
|
`static struct bt_gatt_service __tc_ble_svc;`,
|
|
@@ -145,8 +148,10 @@ export function bleInitLines(): string[] {
|
|
|
145
148
|
` if (idx < 0 || idx >= __TC_BLE_MAX_CHARS || !__tc_ble.on_read[idx]) return 0;`,
|
|
146
149
|
` const char* t = __tc_ble_char_defs[idx].type;`,
|
|
147
150
|
` if (t && strcmp(t, "utf8") == 0) {`,
|
|
148
|
-
`
|
|
149
|
-
`
|
|
151
|
+
` // Hoisted string callbacks return std::string BY VALUE — call through`,
|
|
152
|
+
` // the true signature and borrow c_str() for the copy below.`,
|
|
153
|
+
` std::string s_v = reinterpret_cast<std::string(*)(void)>(__tc_ble.on_read[idx])();`,
|
|
154
|
+
` return bt_gatt_attr_read(conn, attr, buf, len, offset, s_v.c_str(), s_v.size());`,
|
|
150
155
|
` } else if (t && strcmp(t, "float32") == 0) {`,
|
|
151
156
|
` double d = reinterpret_cast<double(*)(void)>(__tc_ble.on_read[idx])();`,
|
|
152
157
|
` float f = static_cast<float>(d);`,
|
|
@@ -266,6 +271,7 @@ export function bleInitLines(): string[] {
|
|
|
266
271
|
`// (declaration + value); the value attr carries the char index in user_data.`,
|
|
267
272
|
`static void __tc_ble_build_svc_table(void) {`,
|
|
268
273
|
` size_t a = 0;`,
|
|
274
|
+
` for (int c = 0; c < __TC_BLE_MAX_CHARS; c++) { __tc_ble_ccc[c].cfg_changed = __tc_ble_ccc_changed; }`,
|
|
269
275
|
` for (int s = 0; s < static_cast<int>(__tc_ble.svc_count); s++) {`,
|
|
270
276
|
` // Primary service declaration.`,
|
|
271
277
|
` __tc_ble_attrs[a].uuid = BT_UUID_GATT_PRIMARY;`,
|
|
@@ -301,6 +307,17 @@ export function bleInitLines(): string[] {
|
|
|
301
307
|
` __tc_ble_attrs[a].perm = BT_GATT_PERM_READ | BT_GATT_PERM_WRITE;`,
|
|
302
308
|
` __tc_ble.val_attr_idx[c] = static_cast<int>(a);`,
|
|
303
309
|
` a++;`,
|
|
310
|
+
` if (__tc_ble_char_defs[c].perms & 4) {`,
|
|
311
|
+
` // CCC descriptor — without it a central cannot subscribe`,
|
|
312
|
+
` // and notifications never reach anyone.`,
|
|
313
|
+
` __tc_ble_attrs[a].uuid = BT_UUID_GATT_CCC;`,
|
|
314
|
+
` __tc_ble_attrs[a].read = bt_gatt_attr_read_ccc;`,
|
|
315
|
+
` __tc_ble_attrs[a].write = bt_gatt_attr_write_ccc;`,
|
|
316
|
+
` __tc_ble_attrs[a].user_data = &__tc_ble_ccc[c];`,
|
|
317
|
+
` __tc_ble_attrs[a].handle = 0;`,
|
|
318
|
+
` __tc_ble_attrs[a].perm = BT_GATT_PERM_READ | BT_GATT_PERM_WRITE;`,
|
|
319
|
+
` a++;`,
|
|
320
|
+
` }`,
|
|
304
321
|
` }`,
|
|
305
322
|
` }`,
|
|
306
323
|
` __tc_ble_attr_count = a;`,
|
|
@@ -323,24 +340,28 @@ export function bleInitLines(): string[] {
|
|
|
323
340
|
` bt_gatt_service_register(&__tc_ble_svc);`,
|
|
324
341
|
` __tc_ble.status = 1; // Initializing`,
|
|
325
342
|
` bt_enable(NULL); // synchronous`,
|
|
343
|
+
` bt_enable(NULL); // synchronous`,
|
|
326
344
|
` __tc_ble.inited = true;`,
|
|
327
345
|
` __tc_ble_advertise_start();`,
|
|
328
346
|
`}`,
|
|
329
347
|
``,
|
|
330
348
|
`// ── Notify ──`,
|
|
349
|
+
`// Explicit-conn: the NULL (broadcast) form hit an ESP32 controller assert`,
|
|
350
|
+
`// (lld_con.c) on the first push after subscription on the S3.`,
|
|
331
351
|
`static void __tc_ble_notify(int idx, int16_t value) {`,
|
|
332
352
|
` if (idx < 0 || idx >= __TC_BLE_MAX_CHARS) return;`,
|
|
353
|
+
` if (__tc_ble.conn == NULL) return; // no link: a NULL-conn notify asserted the controller`,
|
|
333
354
|
` int ai = __tc_ble.val_attr_idx[idx];`,
|
|
334
355
|
` if (ai == 0) return;`,
|
|
335
356
|
` const char* t = __tc_ble_char_defs[idx].type;`,
|
|
336
357
|
` if (t && strcmp(t, "uint32") == 0) {`,
|
|
337
|
-
` uint32_t u = static_cast<uint32_t>(value); bt_gatt_notify(
|
|
358
|
+
` uint32_t u = static_cast<uint32_t>(value); bt_gatt_notify(__tc_ble.conn, &__tc_ble_attrs[ai], &u, sizeof(u));`,
|
|
338
359
|
` } else if (t && strcmp(t, "float32") == 0) {`,
|
|
339
|
-
` float f = static_cast<float>(value); bt_gatt_notify(
|
|
360
|
+
` float f = static_cast<float>(value); bt_gatt_notify(__tc_ble.conn, &__tc_ble_attrs[ai], &f, sizeof(f));`,
|
|
340
361
|
` } else if (t && strcmp(t, "boolean") == 0) {`,
|
|
341
|
-
` uint8_t b = value ? 1 : 0; bt_gatt_notify(
|
|
362
|
+
` uint8_t b = value ? 1 : 0; bt_gatt_notify(__tc_ble.conn, &__tc_ble_attrs[ai], &b, sizeof(b));`,
|
|
342
363
|
` } else {`,
|
|
343
|
-
` int16_t s16 = value; bt_gatt_notify(
|
|
364
|
+
` int16_t s16 = value; bt_gatt_notify(__tc_ble.conn, &__tc_ble_attrs[ai], &s16, sizeof(s16));`,
|
|
344
365
|
` }`,
|
|
345
366
|
`}`,
|
|
346
367
|
``,
|
|
@@ -348,18 +369,7 @@ export function bleInitLines(): string[] {
|
|
|
348
369
|
` return __tc_ble.status == 3 && __tc_ble.connected_clients > 0;`,
|
|
349
370
|
`}`,
|
|
350
371
|
`static inline int __tc_ble_client_count(void) { return __tc_ble.connected_clients; }`,
|
|
351
|
-
`static inline void __tc_ble_set_name(const char* name) { strncpy(__tc_ble.name, name, sizeof(__tc_ble.name) - 1); __tc_ble.name[sizeof(__tc_ble.name) - 1] = 0; }`,
|
|
352
|
-
`static inline void __tc_ble_set_tx_power(int dbm) { (void)dbm; /* nRF TX power via bt_le_set_tx_power — deferred */ }`,
|
|
353
372
|
``,
|
|
354
|
-
`static inline bool __tc_ble_until_connected(uint32_t timeout_ms) {`,
|
|
355
|
-
` int64_t deadline = static_cast<int64_t>(k_uptime_get()) + static_cast<int64_t>(timeout_ms);`,
|
|
356
|
-
` while (!__tc_ble_is_connected()) {`,
|
|
357
|
-
` if (timeout_ms > 0 && k_uptime_get() >= deadline) return false;`,
|
|
358
|
-
` k_msleep(50);`,
|
|
359
|
-
` }`,
|
|
360
|
-
` return true;`,
|
|
361
|
-
`}`,
|
|
362
|
-
`static inline void __tc_ble_until_connected_start(void) { /* __tc_ble_server_begin already started advertising */ }`,
|
|
363
373
|
`// CUTTLEFISH_BLE_END`,
|
|
364
374
|
``,
|
|
365
375
|
];
|
|
@@ -404,21 +414,14 @@ export function lowerBle(op: HALOpIR): { code?: string; expression?: string } {
|
|
|
404
414
|
case 'ble.on_disconnect':
|
|
405
415
|
return { code: `__tc_ble.on_disconnect = (${s(o.handler)});` };
|
|
406
416
|
case 'ble.notify':
|
|
407
|
-
|
|
417
|
+
// Index-based: val_attr_idx[idx] resolves the registered attr (the
|
|
418
|
+
// declaration-order slot). current_char would be whatever add_char ran
|
|
419
|
+
// last — wrong for a standalone notify after later declarations.
|
|
420
|
+
return { expression: `__tc_ble_notify(${s(o.index ?? 0)}, ${s(o.value)})` };
|
|
408
421
|
case 'ble.is_connected':
|
|
409
422
|
return { expression: `__tc_ble_is_connected()` };
|
|
410
423
|
case 'ble.client_count':
|
|
411
424
|
return { expression: `__tc_ble_client_count()` };
|
|
412
|
-
case 'ble.status':
|
|
413
|
-
return { expression: `__tc_ble.status` };
|
|
414
|
-
case 'ble.set_name':
|
|
415
|
-
return { code: `__tc_ble_set_name(${s(o.name)});` };
|
|
416
|
-
case 'ble.set_tx_power':
|
|
417
|
-
return { code: `__tc_ble_set_tx_power(${s(o.dbm)});` };
|
|
418
|
-
case 'ble.until_connected':
|
|
419
|
-
return { expression: `__tc_ble_until_connected(${s(o.timeoutMs)})` };
|
|
420
|
-
case 'ble.until_connected_start':
|
|
421
|
-
return { code: `__tc_ble_until_connected_start();` };
|
|
422
425
|
default:
|
|
423
426
|
throw new Error(
|
|
424
427
|
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
@@ -426,3 +429,4 @@ export function lowerBle(op: HALOpIR): { code?: string; expression?: string } {
|
|
|
426
429
|
);
|
|
427
430
|
}
|
|
428
431
|
}
|
|
432
|
+
|
package/src/lowering/dac.ts
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// DAC lowering — Zephyr DAC driver via dac_channel_setup / dac_write_value
|
|
3
|
-
//
|
|
4
|
-
// Targets with a DAC (ESP32: 2× 8-bit channels on GPIO25/26) declare a `dac`
|
|
5
|
-
// entry in the chip descriptor: the DT device node label + the pin→channel map.
|
|
6
|
-
// The lowering emits a `dac_channel_setup` (lazy, on first write) + a
|
|
7
|
-
// `dac_write_value` against DEVICE_DT_GET(DT_NODELABEL(<device>)).
|
|
8
|
-
//
|
|
9
|
-
// Targets without a DAC (nRF52840, ESP32-S3) omit `dac`; usage there lowers to a
|
|
10
|
-
// comment and profileDiagnostics flags it (mirror of the ADC pin-validity gate).
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
|
|
13
|
-
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
14
|
-
import type { ZephyrChipDescriptor, ZephyrDacChannel } from '../chips/types.js';
|
|
15
|
-
|
|
16
|
-
/** Look up a DAC channel by HAL pin number. */
|
|
17
|
-
function findDacChannel(chip: ZephyrChipDescriptor, pin: number): ZephyrDacChannel | undefined {
|
|
18
|
-
return chip.dac?.channels.find((c) => c.pin === pin);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Emit the DAC device handle. Called from shimLines when the program uses the
|
|
23
|
-
* DAC (the chip must declare a `dac` entry, or nothing is emitted).
|
|
24
|
-
*/
|
|
25
|
-
export function dacInitLines(chip: ZephyrChipDescriptor): string[] {
|
|
26
|
-
if (!chip.dac) return [];
|
|
27
|
-
return [
|
|
28
|
-
'// CUTTLEFISH_DAC_BEGIN',
|
|
29
|
-
`static const struct device* __tc_dac_dev = DEVICE_DT_GET(DT_NODELABEL(${chip.dac.device}));`,
|
|
30
|
-
'// CUTTLEFISH_DAC_END',
|
|
31
|
-
];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Resolve a HAL dac.* op to Zephyr C++.
|
|
36
|
-
* Returns `{ code }` for statement ops.
|
|
37
|
-
*/
|
|
38
|
-
export function lowerDac(
|
|
39
|
-
op: HALOpIR,
|
|
40
|
-
chip: ZephyrChipDescriptor,
|
|
41
|
-
): { code?: string; expression?: string } {
|
|
42
|
-
const o = op as any;
|
|
43
|
-
|
|
44
|
-
// No DAC on this target (e.g. nRF52840). Return a comment so the resolver
|
|
45
|
-
// reports non-undefined (the manifest validator's probe sends pin:25 on the
|
|
46
|
-
// default chip, which has no DAC). profileDiagnostics flags real misuse.
|
|
47
|
-
if (!chip.dac) {
|
|
48
|
-
return { code: `/* dac on pin ${o.pin}: no DAC on ${chip.id} */` };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const ch = findDacChannel(chip, o.pin);
|
|
52
|
-
if (!ch) {
|
|
53
|
-
const valid = [...chip.dac.channels].map((c) => c.pin).sort((a, b) => a - b).join(', ');
|
|
54
|
-
return {
|
|
55
|
-
code: `/* dac on pin ${o.pin}: not a DAC pin on ${chip.id} (valid: ${valid}) */`,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
switch (op.operation) {
|
|
60
|
-
case 'dac.
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
code: [
|
|
66
|
-
`{ static bool
|
|
67
|
-
` if (!
|
|
68
|
-
` static const struct dac_channel_cfg
|
|
69
|
-
` (void)dac_channel_setup(__tc_dac_dev, &
|
|
70
|
-
`
|
|
71
|
-
` }`,
|
|
72
|
-
` (void)dac_write_value(__tc_dac_dev, ${ch.channel}, ${o.value}); }`,
|
|
73
|
-
].join(' '),
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
default:
|
|
77
|
-
throw new Error(
|
|
78
|
-
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
79
|
-
`Open an issue or use rawCpp() to emit it manually.`,
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// DAC lowering — Zephyr DAC driver via dac_channel_setup / dac_write_value
|
|
3
|
+
//
|
|
4
|
+
// Targets with a DAC (ESP32: 2× 8-bit channels on GPIO25/26) declare a `dac`
|
|
5
|
+
// entry in the chip descriptor: the DT device node label + the pin→channel map.
|
|
6
|
+
// The lowering emits a `dac_channel_setup` (lazy, on first write) + a
|
|
7
|
+
// `dac_write_value` against DEVICE_DT_GET(DT_NODELABEL(<device>)).
|
|
8
|
+
//
|
|
9
|
+
// Targets without a DAC (nRF52840, ESP32-S3) omit `dac`; usage there lowers to a
|
|
10
|
+
// comment and profileDiagnostics flags it (mirror of the ADC pin-validity gate).
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
14
|
+
import type { ZephyrChipDescriptor, ZephyrDacChannel } from '../chips/types.js';
|
|
15
|
+
|
|
16
|
+
/** Look up a DAC channel by HAL pin number. */
|
|
17
|
+
function findDacChannel(chip: ZephyrChipDescriptor, pin: number): ZephyrDacChannel | undefined {
|
|
18
|
+
return chip.dac?.channels.find((c) => c.pin === pin);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Emit the DAC device handle. Called from shimLines when the program uses the
|
|
23
|
+
* DAC (the chip must declare a `dac` entry, or nothing is emitted).
|
|
24
|
+
*/
|
|
25
|
+
export function dacInitLines(chip: ZephyrChipDescriptor): string[] {
|
|
26
|
+
if (!chip.dac) return [];
|
|
27
|
+
return [
|
|
28
|
+
'// CUTTLEFISH_DAC_BEGIN',
|
|
29
|
+
`static const struct device* __tc_dac_dev = DEVICE_DT_GET(DT_NODELABEL(${chip.dac.device}));`,
|
|
30
|
+
'// CUTTLEFISH_DAC_END',
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a HAL dac.* op to Zephyr C++.
|
|
36
|
+
* Returns `{ code }` for statement ops.
|
|
37
|
+
*/
|
|
38
|
+
export function lowerDac(
|
|
39
|
+
op: HALOpIR,
|
|
40
|
+
chip: ZephyrChipDescriptor,
|
|
41
|
+
): { code?: string; expression?: string } {
|
|
42
|
+
const o = op as any;
|
|
43
|
+
|
|
44
|
+
// No DAC on this target (e.g. nRF52840). Return a comment so the resolver
|
|
45
|
+
// reports non-undefined (the manifest validator's probe sends pin:25 on the
|
|
46
|
+
// default chip, which has no DAC). profileDiagnostics flags real misuse.
|
|
47
|
+
if (!chip.dac) {
|
|
48
|
+
return { code: `/* dac on pin ${o.pin}: no DAC on ${chip.id} */` };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const ch = findDacChannel(chip, o.pin);
|
|
52
|
+
if (!ch) {
|
|
53
|
+
const valid = [...chip.dac.channels].map((c) => c.pin).sort((a, b) => a - b).join(', ');
|
|
54
|
+
return {
|
|
55
|
+
code: `/* dac on pin ${o.pin}: not a DAC pin on ${chip.id} (valid: ${valid}) */`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
switch (op.operation) {
|
|
60
|
+
case 'dac.write_value': {
|
|
61
|
+
// Thin DAC: raw code with the construction resolution (0 = the
|
|
62
|
+
// descriptor channel's), lazy setup per pin.
|
|
63
|
+
const res = Number(o.resolution) > 0 ? Number(o.resolution) : ch.resolution;
|
|
64
|
+
return {
|
|
65
|
+
code: [
|
|
66
|
+
`{ static bool __tc_dact${o.pin}_done = false;`,
|
|
67
|
+
` if (!__tc_dact${o.pin}_done) {`,
|
|
68
|
+
` static const struct dac_channel_cfg __tc_dact${o.pin}_cfg = { .channel_id = ${ch.channel}, .resolution = ${res} };`,
|
|
69
|
+
` (void)dac_channel_setup(__tc_dac_dev, &__tc_dact${o.pin}_cfg);`,
|
|
70
|
+
` __tc_dact${o.pin}_done = true;`,
|
|
71
|
+
` }`,
|
|
72
|
+
` (void)dac_write_value(__tc_dac_dev, ${ch.channel}, ${o.value}); }`,
|
|
73
|
+
].join(' '),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(
|
|
78
|
+
`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
79
|
+
`Open an issue or use rawCpp() to emit it manually.`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|