@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
package/dist/boardgen.js
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
// CONTRACT (custom PCB spec) — and emits the two artifacts a project
|
|
7
7
|
// carries instead of a board package:
|
|
8
8
|
//
|
|
9
|
-
// .
|
|
10
|
-
// @typecad/
|
|
11
|
-
//
|
|
9
|
+
// .typecad-hal/board.ts — typed pin/bus/LED/BUTTON exports (the virtual
|
|
10
|
+
// '@typecad/hal' module resolves here via the
|
|
11
|
+
// project tsconfig — the single import surface)
|
|
12
|
+
// .typecad-hal/board.json — the BoardConstants flat map (pins.all.*,
|
|
12
13
|
// peripherals.*, zephyr.*) the transpiler's
|
|
13
14
|
// resolveChipFromBoard reconstructs its chip
|
|
14
15
|
// view from
|
|
@@ -22,13 +23,14 @@
|
|
|
22
23
|
// matrices) are absent for every board alike.
|
|
23
24
|
//
|
|
24
25
|
// Pure: returns the file contents; the caller (cuttlefish config-loader via
|
|
25
|
-
// the strategy hook, or `
|
|
26
|
+
// the strategy hook, or `typecad-hal board regen`) writes them.
|
|
26
27
|
// ----------------------------------------------------------------------------
|
|
27
28
|
import { parseAsBuiltJson } from './as-built.js';
|
|
28
29
|
import { loadBoardCatalogOverlay, GENERATOR_REV, boardRecordFingerprint, factsFingerprint, findBoardInCatalog, socBusLabelsFromTree, } from '@typecad/cuttlefish/board-catalog';
|
|
30
|
+
import { getBoardGateData } from '@typecad/cuttlefish/board-gate';
|
|
29
31
|
/**
|
|
30
32
|
* The catalog lookups resolve against the local overlay — the user's own
|
|
31
|
-
* Zephyr tree (`
|
|
33
|
+
* Zephyr tree (`typecad-hal board sync`, auto-refreshed when the tree
|
|
32
34
|
* moves). There is no compiled-in database: a machine with no tree and no
|
|
33
35
|
* overlay has no boards, and the error below says exactly that.
|
|
34
36
|
*/
|
|
@@ -36,7 +38,7 @@ function activeBoardData() {
|
|
|
36
38
|
const data = loadBoardCatalogOverlay()?.data;
|
|
37
39
|
if (!data) {
|
|
38
40
|
throw new Error(`No board catalog on this machine. The catalog is generated from your Zephyr tree —\n` +
|
|
39
|
-
`run '
|
|
41
|
+
`run 'typecad-hal board sync' (or point TYPECAD_HAL_BOARD_CATALOG at a catalog file).`);
|
|
40
42
|
}
|
|
41
43
|
return data;
|
|
42
44
|
}
|
|
@@ -75,7 +77,7 @@ export function nrfSaadcAinPads(soc, identifier) {
|
|
|
75
77
|
* S3/C3/C6/H2 dropped it. Sourced from the HAL's dac_periph.c
|
|
76
78
|
* (`dac_channel_io_num[]`), like the nRF SAADC table is from the PS.
|
|
77
79
|
*/
|
|
78
|
-
|
|
80
|
+
function esp32DacPins(soc) {
|
|
79
81
|
const table = {
|
|
80
82
|
esp32: [[0, 25], [1, 26]],
|
|
81
83
|
esp32s2: [[0, 17], [1, 18]],
|
|
@@ -408,7 +410,7 @@ export function parsePinName(soc, name) {
|
|
|
408
410
|
return undefined;
|
|
409
411
|
}
|
|
410
412
|
/** Parse + shape-validate the facts file; a clear error names the file. */
|
|
411
|
-
export function parseUserFactsJson(text, source = '
|
|
413
|
+
export function parseUserFactsJson(text, source = 'typecad-hal.facts.json') {
|
|
412
414
|
let parsed;
|
|
413
415
|
try {
|
|
414
416
|
parsed = JSON.parse(text);
|
|
@@ -445,6 +447,9 @@ export function userFactsForTarget(file, target) {
|
|
|
445
447
|
return hit ? file.boards[hit] : undefined;
|
|
446
448
|
}
|
|
447
449
|
export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = []) {
|
|
450
|
+
// The ungated surface is derived from the project's own hal copy — same
|
|
451
|
+
// resolution (project → cwd → monorepo sibling) as the engine's HAL parser.
|
|
452
|
+
const { ungated: BOARD_UNGATED_EXPORTS, ungatedTypes: BOARD_UNGATED_TYPE_EXPORTS } = getBoardGateData();
|
|
448
453
|
const soc = socOfTarget(entry.identifier);
|
|
449
454
|
const conv = namingConvFor(soc);
|
|
450
455
|
// ── Controller table + datasheet sweep (the same for every board) ──────
|
|
@@ -609,7 +614,7 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
609
614
|
adcSources.push(r.source);
|
|
610
615
|
}
|
|
611
616
|
}
|
|
612
|
-
// User facts (
|
|
617
|
+
// User facts (typecad-hal.facts.json) — the escape hatch. User routes win
|
|
613
618
|
// PER PIN over every harvested source above, and each takeover is warned.
|
|
614
619
|
// Seeded with the pinctrl harvest's own lint results (name↔value
|
|
615
620
|
// disagreements — routes dropped as untrustworthy upstream of here).
|
|
@@ -679,7 +684,7 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
679
684
|
if (siliconDac.length > 0 && !dacSources.includes('dac'))
|
|
680
685
|
dacSources.push('dac');
|
|
681
686
|
}
|
|
682
|
-
// User facts (
|
|
687
|
+
// User facts (typecad-hal.facts.json): dac channels win per pin, and the
|
|
683
688
|
// declared device joins the sources (no analogDevices cross-check — the
|
|
684
689
|
// user vouches for it).
|
|
685
690
|
if (userFacts?.dac) {
|
|
@@ -803,7 +808,7 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
803
808
|
...pins.map((p) => p.ident),
|
|
804
809
|
'LED',
|
|
805
810
|
'BUTTON',
|
|
806
|
-
// '@typecad/hal' imports — a connector silkscreen label can literally be
|
|
811
|
+
// '@typecad/hal/core' imports — a connector silkscreen label can literally be
|
|
807
812
|
// 'Pin' (phyBOARD-Atlas), and `export const Pin` merges with the import.
|
|
808
813
|
'Pin',
|
|
809
814
|
'I2CBus',
|
|
@@ -811,6 +816,9 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
811
816
|
'UART',
|
|
812
817
|
'USBConsole',
|
|
813
818
|
'PWM',
|
|
819
|
+
// The ungated re-export block: a label colliding with any re-exported
|
|
820
|
+
// hal name would be a duplicate module export.
|
|
821
|
+
...BOARD_UNGATED_EXPORTS,
|
|
814
822
|
]);
|
|
815
823
|
buses.i2c.forEach((_, i) => reservedNames.add(`I2C${i}`));
|
|
816
824
|
buses.spi.forEach((_, i) => reservedNames.add(`SPI${i}`));
|
|
@@ -826,49 +834,171 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
826
834
|
continue;
|
|
827
835
|
connectorLabelOwner.set(label, pin);
|
|
828
836
|
}
|
|
837
|
+
// ── Per-pin editor annotations ──────────────────────────────────────────
|
|
838
|
+
// The same harvested facts board.json carries, stamped as JSDoc on the
|
|
839
|
+
// datasheet pin exports so plain tsserver surfaces them in hover and
|
|
840
|
+
// completion detail — board intelligence with zero editor extension. Only
|
|
841
|
+
// pins WITH a fact (silicon route, any-pad matrix membership, bus role, or
|
|
842
|
+
// an alias) get a doc line: bare pads stay bare, and the absence of an
|
|
843
|
+
// annotation says "plain GPIO" without stamping it on every line. Facts and
|
|
844
|
+
// module derive from the same route sets below, so they cannot disagree.
|
|
845
|
+
const pwmRouteByPin = new Map(siliconPwm.map((s) => [s.pin, s]));
|
|
846
|
+
const adcRouteByPin = new Map(siliconAdc.map((s) => [s.pin, s]));
|
|
847
|
+
const dacRouteByPin = new Map(siliconDac.map((s) => [s.pin, s]));
|
|
848
|
+
// Any-pad PWM matrices (ESP32 LEDC, nRF psel, RP2 slices) ride global pad
|
|
849
|
+
// numbers — same base arithmetic the manifest's matrix pins use.
|
|
850
|
+
const matrixBase = controllers.find((c) => c.nodelabel === 'gpio0')?.minPin ?? 0;
|
|
851
|
+
const matrixPwmPins = pwmMatrix
|
|
852
|
+
? new Set(pwmMatrix.pads.map((pad) => matrixBase + pad))
|
|
853
|
+
: undefined;
|
|
854
|
+
// Aliases (connector silkscreen labels, LED/BUTTON) keyed by the aliased
|
|
855
|
+
// pin's HAL number — connectorLabelOwner's values ARE the sweep's GenPin
|
|
856
|
+
// objects, so identity holds through the LED/BUTTON facts too.
|
|
857
|
+
const aliasesByPin = new Map();
|
|
858
|
+
const noteAlias = (pin, label) => {
|
|
859
|
+
if (!pin)
|
|
860
|
+
return;
|
|
861
|
+
const list = aliasesByPin.get(pin.halPin);
|
|
862
|
+
if (list)
|
|
863
|
+
list.push(label);
|
|
864
|
+
else
|
|
865
|
+
aliasesByPin.set(pin.halPin, [label]);
|
|
866
|
+
};
|
|
867
|
+
for (const [label, pin] of connectorLabelOwner)
|
|
868
|
+
noteAlias(pin, label);
|
|
869
|
+
if (ledPinFinal)
|
|
870
|
+
noteAlias(ledPinFinal, 'LED');
|
|
871
|
+
if (buttonPin)
|
|
872
|
+
noteAlias(buttonPin, 'BUTTON');
|
|
873
|
+
extraLedPins.forEach((p, i) => noteAlias(p, `LED${i + 1}`));
|
|
874
|
+
extraButtonPins.forEach((p, i) => noteAlias(p, `BUTTON${i + 1}`));
|
|
875
|
+
// Bus roles (SDA/SCL/MOSI/…) keyed by the route's pad NAME — best-effort
|
|
876
|
+
// uppercase match; pads whose spelling the pin sweep can't place simply
|
|
877
|
+
// carry no role line. (busPads is defined further down; this walks
|
|
878
|
+
// entry.busPins directly to stay above it.)
|
|
879
|
+
const rolesByPinName = new Map();
|
|
880
|
+
for (const b of entry.busPins ?? []) {
|
|
881
|
+
const index = buses[b.bus]?.indexOf(b.nodelabel) ?? -1;
|
|
882
|
+
if (index < 0)
|
|
883
|
+
continue;
|
|
884
|
+
const instance = `${b.bus.toUpperCase()}${index}`;
|
|
885
|
+
for (const route of b.routes) {
|
|
886
|
+
if (!route.pad || !route.role)
|
|
887
|
+
continue;
|
|
888
|
+
const name = route.pad.toUpperCase();
|
|
889
|
+
const role = `${instance} ${route.role.toUpperCase()}`;
|
|
890
|
+
const list = rolesByPinName.get(name);
|
|
891
|
+
if (list) {
|
|
892
|
+
if (!list.includes(role))
|
|
893
|
+
list.push(role);
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
rolesByPinName.set(name, [role]);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
const pinDoc = (p) => {
|
|
901
|
+
const parts = [];
|
|
902
|
+
const pwm = pwmRouteByPin.get(p.halPin);
|
|
903
|
+
if (pwm)
|
|
904
|
+
parts.push(`PWM ${pwm.controller} ch${pwm.channel}`);
|
|
905
|
+
else if (pwmMatrix && matrixPwmPins?.has(p.halPin)) {
|
|
906
|
+
parts.push(`PWM ${pwmMatrix.controller} ch0-${pwmMatrix.channelCount - 1} (any pad)`);
|
|
907
|
+
}
|
|
908
|
+
const adc = adcRouteByPin.get(p.halPin);
|
|
909
|
+
// Primary-unit routes (pinctrl and ESP SARADC alike) omit the controller
|
|
910
|
+
// field — fall back to the pinctrl sources, then the ESP primary unit.
|
|
911
|
+
if (adc)
|
|
912
|
+
parts.push(`ADC ${adc.controller ?? adcSources[0] ?? espAdcUnit ?? 'adc'} ch${adc.channel}`);
|
|
913
|
+
const dac = dacRouteByPin.get(p.halPin);
|
|
914
|
+
if (dac)
|
|
915
|
+
parts.push(`DAC ch${dac.channel}`);
|
|
916
|
+
parts.push(...(rolesByPinName.get(p.name.toUpperCase()) ?? []));
|
|
917
|
+
const aliases = aliasesByPin.get(p.halPin);
|
|
918
|
+
if (aliases)
|
|
919
|
+
parts.push(`aliases: ${aliases.join(', ')}`);
|
|
920
|
+
return parts.length > 0 ? parts.join(' · ') : undefined;
|
|
921
|
+
};
|
|
829
922
|
const ts = [];
|
|
830
|
-
ts.push(`// GENERATED by
|
|
923
|
+
ts.push(`// GENERATED by typecad-hal boardgen from the Zephyr board catalog —`);
|
|
831
924
|
ts.push(`// ${entry.identifier} (${entry.name}, ${entry.vendor}).`);
|
|
832
|
-
ts.push(`// Regenerate with: npx
|
|
925
|
+
ts.push(`// Regenerate with: npx typecad-hal board regen`);
|
|
833
926
|
ts.push('');
|
|
834
|
-
|
|
927
|
+
// The generated module IS the user's '@typecad/hal' (the project tsconfig
|
|
928
|
+
// maps that specifier here), so it reaches the implementation package via
|
|
929
|
+
// the './core' subpath — the one specifier the paths mapping does not
|
|
930
|
+
// capture, avoiding a circular self-reference.
|
|
931
|
+
ts.push(`import { Pin, I2CBus, SPIBus, UART${hasUsb ? ', USBConsole' : ''}${pwmLedSpecs.length > 0 ? ', PWM' : ''} } from '@typecad/hal/core';`);
|
|
835
932
|
ts.push('');
|
|
836
933
|
// ── Hardware-class gateway ─────────────────────────────────────────────
|
|
837
|
-
//
|
|
838
|
-
//
|
|
839
|
-
//
|
|
840
|
-
//
|
|
841
|
-
//
|
|
934
|
+
// This module is the NARROWED surface behind the user's '@typecad/hal'
|
|
935
|
+
// import: every hardware class gated on board facts is re-exported below
|
|
936
|
+
// only when this board's facts support it, so importing unavailable
|
|
937
|
+
// hardware fails at module resolution (editor + transpile) instead of at
|
|
938
|
+
// a deep diagnostic. Everything not gated (the lists hal ships in
|
|
939
|
+
// gate.ts) is re-exported verbatim so the full authoring surface stays
|
|
940
|
+
// importable from the same specifier ('@typecad/hal' is the one specifier —
|
|
941
|
+
// the old '@typecad/board' alias was removed with the rename).
|
|
942
|
+
ts.push('// Always-available HAL surface (not gated on board facts).');
|
|
943
|
+
ts.push(`export { ${BOARD_UNGATED_EXPORTS.join(', ')} } from '@typecad/hal/core';`);
|
|
944
|
+
ts.push(`export type { ${BOARD_UNGATED_TYPE_EXPORTS.join(', ')} } from '@typecad/hal/core';`);
|
|
945
|
+
ts.push('');
|
|
842
946
|
ts.push('// Hardware this board actually has — unavailable hardware is not importable.');
|
|
843
|
-
ts.push(`export { GPIO, Thread, Time, Sensor } from '@typecad/hal';`);
|
|
844
947
|
if (wdtNodeLabel)
|
|
845
|
-
ts.push(`export { Watchdog } from '@typecad/hal';`);
|
|
948
|
+
ts.push(`export { Watchdog } from '@typecad/hal/core';`);
|
|
846
949
|
if (siliconPwm.length > 0 || pwmLedSpecs.length > 0 || pwmMatrix)
|
|
847
|
-
ts.push(`export { PWM } from '@typecad/hal';`);
|
|
950
|
+
ts.push(`export { PWM, Servo } from '@typecad/hal/core';`);
|
|
848
951
|
if (siliconAdc.length > 0)
|
|
849
|
-
ts.push(`export { ADC } from '@typecad/hal';`);
|
|
952
|
+
ts.push(`export { ADC } from '@typecad/hal/core';`);
|
|
850
953
|
if (siliconDac.length > 0)
|
|
851
|
-
ts.push(`export { DAC } from '@typecad/hal';`);
|
|
954
|
+
ts.push(`export { DAC } from '@typecad/hal/core';`);
|
|
955
|
+
// The responder rides the same wired-bus fact as I2CTarget — target-mode
|
|
956
|
+
// support is a controller-driver property discovered at registration
|
|
957
|
+
// (-ENOSYS prints loudly), never a board-name gate.
|
|
852
958
|
if (buses.i2c.length > 0)
|
|
853
|
-
ts.push(`export { I2CTarget } from '@typecad/hal';`);
|
|
959
|
+
ts.push(`export { I2CTarget, I2CResponder } from '@typecad/hal/core';`);
|
|
854
960
|
if (buses.spi.length > 0)
|
|
855
|
-
ts.push(`export { SPITarget } from '@typecad/hal';`);
|
|
961
|
+
ts.push(`export { SPITarget } from '@typecad/hal/core';`);
|
|
856
962
|
if (buses.uart.length > 0)
|
|
857
|
-
ts.push(`export { UART } from '@typecad/hal';`);
|
|
963
|
+
ts.push(`export { UART } from '@typecad/hal/core';`);
|
|
964
|
+
if (hwtimerControllers.length > 0)
|
|
965
|
+
ts.push(`export { Counter } from '@typecad/hal/core';`);
|
|
966
|
+
// Clock rides the same free-counter facts (the zephyr,rtc-counter shim
|
|
967
|
+
// wraps the counter when the board ships no hardware rtc alias).
|
|
858
968
|
if (hwtimerControllers.length > 0)
|
|
859
|
-
ts.push(`export {
|
|
969
|
+
ts.push(`export { Clock } from '@typecad/hal/core';`);
|
|
970
|
+
// CAN rides the harvested controller nodes (ESP32 TWAI, STM32 bxCAN,
|
|
971
|
+
// NXP FlexCAN…); a SoC with none exports nothing.
|
|
972
|
+
if ((entry.canNodes ?? []).length > 0)
|
|
973
|
+
ts.push(`export { CAN } from '@typecad/hal/core';`);
|
|
974
|
+
// I2S rides the harvested i2s@ controllers.
|
|
975
|
+
if ((entry.i2sNodes ?? []).length > 0)
|
|
976
|
+
ts.push(`export { I2S } from '@typecad/hal/core';`);
|
|
977
|
+
// Power rides the SoC's declared cpu-power-states (both the ESP32 family's
|
|
978
|
+
// standby + soft-off pair and STM32's suspend-to-idle count; a SoC with no
|
|
979
|
+
// declared states exports nothing).
|
|
980
|
+
if ((entry.powerStates ?? []).length > 0)
|
|
981
|
+
ts.push(`export { Power } from '@typecad/hal/core';`);
|
|
982
|
+
// KEY/MOUSE are ungated token tables — the derived always-available
|
|
983
|
+
// re-export line above already carries them on every board; only the HID
|
|
984
|
+
// device classes ride the USB gate.
|
|
860
985
|
if (hasUsb)
|
|
861
|
-
ts.push(`export { USBConsole } from '@typecad/hal';`);
|
|
986
|
+
ts.push(`export { USBConsole, Keyboard, Mouse } from '@typecad/hal/core';`);
|
|
862
987
|
// Store/File: a persisted backend needs a storage region — either the
|
|
863
988
|
// board's own storage_partition (harvested reg) or a synthesizable one
|
|
864
989
|
// (flash size known, no existing partition to collide with).
|
|
865
990
|
if (entry.storageReg || (entry.flashKb && !entry.hasStoragePartition)) {
|
|
866
|
-
ts.push(`export { Store, File } from '@typecad/hal';`);
|
|
991
|
+
ts.push(`export { Store, File } from '@typecad/hal/core';`);
|
|
867
992
|
}
|
|
868
993
|
ts.push('');
|
|
869
994
|
if (pins.length > 0) {
|
|
870
995
|
ts.push(`// Datasheet-named pins (derived from the board's devicetree controllers)`);
|
|
996
|
+
ts.push(`// Pins with harvested facts carry them as JSDoc (hover shows routes/roles/aliases);`);
|
|
997
|
+
ts.push(`// a pin without a doc line is plain GPIO — no PWM/ADC/DAC route on this board.`);
|
|
871
998
|
for (const p of pins) {
|
|
999
|
+
const doc = pinDoc(p);
|
|
1000
|
+
if (doc)
|
|
1001
|
+
ts.push(`/** ${doc} */`);
|
|
872
1002
|
ts.push(`export const ${p.ident} = Pin.fromPort('${p.name}');`);
|
|
873
1003
|
}
|
|
874
1004
|
ts.push('');
|
|
@@ -892,28 +1022,52 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
892
1022
|
extraPinDecls.push(p);
|
|
893
1023
|
}
|
|
894
1024
|
for (const p of extraPinDecls) {
|
|
895
|
-
ts.push(`/** ${p.name} (derived from the devicetree controller label). */`);
|
|
896
1025
|
ts.push(`export const ${p.ident} = Pin.fromPort('${p.name}');`);
|
|
897
1026
|
}
|
|
898
1027
|
if (ledPinFinal) {
|
|
899
|
-
ts.push(`/** On-board LED
|
|
1028
|
+
ts.push(`/** On-board LED${entry.led ? '' : ' — addressable strip, this is its data pin'}. */`);
|
|
900
1029
|
ts.push(`export const LED = ${ledPinFinal.ident};`);
|
|
901
1030
|
}
|
|
902
1031
|
if (buttonPin) {
|
|
903
|
-
ts.push(`/** User button
|
|
1032
|
+
ts.push(`/** User button. */`);
|
|
904
1033
|
ts.push(`export const BUTTON = ${buttonPin.ident};`);
|
|
905
1034
|
}
|
|
906
1035
|
if (ledPinFinal || buttonPin || extraPinDecls.length > 0)
|
|
907
1036
|
ts.push('');
|
|
908
|
-
// Bus instance exports from the board's own DTS-wired controllers.
|
|
1037
|
+
// Bus instance exports from the board's own DTS-wired controllers. When the
|
|
1038
|
+
// harvest parsed a controller's pinctrl overrides, the JSDoc carries its pad
|
|
1039
|
+
// routes ("SDA=PB7, SCL=PB8") — the same facts the pins.<bus> conflict-map
|
|
1040
|
+
// constants hold, surfaced for hover.
|
|
1041
|
+
const busPadPairs = (kind, nodelabel) => (entry.busPins ?? [])
|
|
1042
|
+
.filter((b) => b.bus === kind && b.nodelabel === nodelabel)
|
|
1043
|
+
.flatMap((b) => b.routes)
|
|
1044
|
+
.filter((r) => r.pad && r.role)
|
|
1045
|
+
.map((r) => `${r.role.toUpperCase()}=${r.pad}`);
|
|
1046
|
+
const busDoc = (kind, index, nodelabel) => {
|
|
1047
|
+
const label = kind === 'i2c' ? `I2C bus ${index}` : kind === 'spi' ? `SPI bus ${index}` : `UART ${index}`;
|
|
1048
|
+
const pads = busPadPairs(kind, nodelabel);
|
|
1049
|
+
return `Board-wired ${label}${pads.length > 0 ? ` (${pads.join(', ')})` : ''}.`;
|
|
1050
|
+
};
|
|
909
1051
|
const busLines = [];
|
|
910
|
-
buses.i2c.forEach((
|
|
911
|
-
|
|
912
|
-
|
|
1052
|
+
buses.i2c.forEach((nodelabel, i) => {
|
|
1053
|
+
busLines.push(`/** ${busDoc('i2c', i, nodelabel)} */`);
|
|
1054
|
+
busLines.push(`export const I2C${i} = new I2CBus('I2C${i}');`);
|
|
1055
|
+
});
|
|
1056
|
+
buses.spi.forEach((nodelabel, i) => {
|
|
1057
|
+
busLines.push(`/** ${busDoc('spi', i, nodelabel)} */`);
|
|
1058
|
+
busLines.push(`export const SPI${i} = new SPIBus('SPI${i}');`);
|
|
1059
|
+
});
|
|
1060
|
+
buses.uart.forEach((nodelabel, i) => {
|
|
1061
|
+
busLines.push(`/** ${busDoc('uart', i, nodelabel)} */`);
|
|
1062
|
+
busLines.push(`export const UART${i} = new UART('UART${i}');`);
|
|
1063
|
+
});
|
|
913
1064
|
// USB CDC instance (the thin HAL's USBConsole): the board's DTS turns the
|
|
914
|
-
// device controller on (zephyr_udc0 status okay).
|
|
915
|
-
|
|
1065
|
+
// device controller on (zephyr_udc0 status okay). CDC has no pinctrl pad
|
|
1066
|
+
// routes — the console rides the controller's silicon-fixed DP/DM pads.
|
|
1067
|
+
if (hasUsb) {
|
|
1068
|
+
busLines.push(`/** USB serial console — the board's USB connector (no pin to configure). */`);
|
|
916
1069
|
busLines.push(`export const USB0 = new USBConsole('USB0');`);
|
|
1070
|
+
}
|
|
917
1071
|
// PWM-driven LEDs (pwm-leds): addressed by the board's own devicetree
|
|
918
1072
|
// alias (DT_ALIAS(pwm_led0) in the lowering) — no overlay needed. The
|
|
919
1073
|
// construction period comes from the DTS cell when it is a plain number
|
|
@@ -922,7 +1076,7 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
922
1076
|
pwmLedSpecs.forEach((l, i) => {
|
|
923
1077
|
const period = l.periodNs ?? 1_000_000;
|
|
924
1078
|
const name = i === 0 ? 'PWMLED' : `PWMLED${i}`;
|
|
925
|
-
busLines.push(`/** Board PWM LED (
|
|
1079
|
+
busLines.push(`/** Board PWM-driven LED (already constructed — call setDuty() to dim it). */`);
|
|
926
1080
|
busLines.push(`export const ${name} = new PWM(${8192 + i}, { periodNs: ${period} });`);
|
|
927
1081
|
});
|
|
928
1082
|
if (busLines.length > 0) {
|
|
@@ -945,12 +1099,15 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
945
1099
|
// GPIO driver API (`gpio_pin_configure` flags + `gpio_pin_interrupt_configure`):
|
|
946
1100
|
// every GPIO controller implements them, so they are universally true —
|
|
947
1101
|
// a platform fact, not a per-pad one. Analog/PWM ride the harvested
|
|
948
|
-
// silicon routes (honest per-pad facts)
|
|
1102
|
+
// silicon routes (honest per-pad facts); PWM counts both route kinds —
|
|
1103
|
+
// fixed pinctrl routes AND any-pad matrices (ESP32 LEDC, nRF psel), the
|
|
1104
|
+
// same set union the pin JSDoc and the PWM export gate read, so the
|
|
1105
|
+
// hover annotation and the capability flag cannot disagree.
|
|
949
1106
|
constants[`pins.all.${i}.capabilities.digitalInput`] = true;
|
|
950
1107
|
constants[`pins.all.${i}.capabilities.digitalOutput`] = true;
|
|
951
1108
|
constants[`pins.all.${i}.capabilities.analogInput`] = siliconAdcPins.has(p.halPin);
|
|
952
1109
|
constants[`pins.all.${i}.capabilities.analogOutput`] = siliconDacPins.has(p.halPin);
|
|
953
|
-
constants[`pins.all.${i}.capabilities.pwm`] = siliconPwmPins.has(p.halPin);
|
|
1110
|
+
constants[`pins.all.${i}.capabilities.pwm`] = siliconPwmPins.has(p.halPin) || (matrixPwmPins?.has(p.halPin) ?? false);
|
|
954
1111
|
constants[`pins.all.${i}.capabilities.interrupt`] = true;
|
|
955
1112
|
constants[`pins.all.${i}.capabilities.pullUp`] = true;
|
|
956
1113
|
constants[`pins.all.${i}.capabilities.pullDown`] = true;
|
|
@@ -959,6 +1116,39 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
959
1116
|
constants[`pins.all.${i}.capabilities.touch`] = false;
|
|
960
1117
|
constants[`pins.all.${i}.capabilities.openDrain`] = true;
|
|
961
1118
|
});
|
|
1119
|
+
// CPU power states — the harvested PM capability facts (which levels
|
|
1120
|
+
// exist, their idle timing, and whether the automatic policy may enter
|
|
1121
|
+
// them; ESP32's soft-off is explicit-entry only).
|
|
1122
|
+
const powerStates = entry.powerStates ?? [];
|
|
1123
|
+
powerStates.forEach((ps, i) => {
|
|
1124
|
+
constants[`zephyr.power.states.${i}.name`] = ps.name;
|
|
1125
|
+
if (ps.minResidencyUs !== undefined)
|
|
1126
|
+
constants[`zephyr.power.states.${i}.minResidencyUs`] = ps.minResidencyUs;
|
|
1127
|
+
if (ps.exitLatencyUs !== undefined)
|
|
1128
|
+
constants[`zephyr.power.states.${i}.exitLatencyUs`] = ps.exitLatencyUs;
|
|
1129
|
+
constants[`zephyr.power.states.${i}.enabled`] = ps.enabled;
|
|
1130
|
+
});
|
|
1131
|
+
if (powerStates.length > 0) {
|
|
1132
|
+
constants['zephyr.power.softOff'] = powerStates.some((ps) => ps.name === 'soft-off');
|
|
1133
|
+
}
|
|
1134
|
+
if (entry.rtcWakeTimer)
|
|
1135
|
+
constants['zephyr.power.wakeTimer'] = true;
|
|
1136
|
+
// CAN controllers — the harvested labeled nodes (the CAN class gate). The
|
|
1137
|
+
// ESP32 TWAI pads ride along: loopback overlays route both TWAI functions
|
|
1138
|
+
// onto the TX pad.
|
|
1139
|
+
(entry.canNodes ?? []).forEach((c, i) => {
|
|
1140
|
+
constants[`zephyr.can.controllers.${i}.nodeLabel`] = c.nodeLabel;
|
|
1141
|
+
constants[`zephyr.can.controllers.${i}.compatible`] = c.compatible;
|
|
1142
|
+
if (c.txPad !== undefined)
|
|
1143
|
+
constants[`zephyr.can.controllers.${i}.txPad`] = c.txPad;
|
|
1144
|
+
if (c.rxPad !== undefined)
|
|
1145
|
+
constants[`zephyr.can.controllers.${i}.rxPad`] = c.rxPad;
|
|
1146
|
+
});
|
|
1147
|
+
// I2S controllers — the harvested labeled nodes (the I2S class gate).
|
|
1148
|
+
(entry.i2sNodes ?? []).forEach((c, i) => {
|
|
1149
|
+
constants[`zephyr.i2s.controllers.${i}.nodeLabel`] = c.nodeLabel;
|
|
1150
|
+
constants[`zephyr.i2s.controllers.${i}.compatible`] = c.compatible;
|
|
1151
|
+
});
|
|
962
1152
|
constants['peripherals.i2c.count'] = buses.i2c.length;
|
|
963
1153
|
constants['peripherals.spi.count'] = buses.spi.length;
|
|
964
1154
|
constants['peripherals.uart.count'] = buses.uart.length;
|
|
@@ -1126,16 +1316,67 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
1126
1316
|
});
|
|
1127
1317
|
// Bus controllers the board's own DTS wires up — resolveChipFromBoard
|
|
1128
1318
|
// reconstructs the bus lists from these, and the overlays enable the
|
|
1129
|
-
// nodes the program uses.
|
|
1319
|
+
// nodes the program uses. Each controller also carries its board-DTS
|
|
1320
|
+
// pinctrl routes when the harvest parsed them (`pinctrl` = the route
|
|
1321
|
+
// names, `pads` = `role=PAD` pairs) — the diagnostics report's
|
|
1322
|
+
// peripheral-usage table and the pins.<bus> conflict-map read them.
|
|
1323
|
+
const busPads = (kind, nodelabel) => (entry.busPins ?? []).filter((b) => b.bus === kind && b.nodelabel === nodelabel).flatMap((b) => b.routes);
|
|
1324
|
+
const busPinMap = (kind) => {
|
|
1325
|
+
const parts = [];
|
|
1326
|
+
buses[kind].forEach((nodelabel, i) => {
|
|
1327
|
+
const pairs = busPads(kind, nodelabel)
|
|
1328
|
+
.filter((r) => r.pad && r.role)
|
|
1329
|
+
.map((r) => `${r.role}=${r.pad}`);
|
|
1330
|
+
if (pairs.length > 0)
|
|
1331
|
+
parts.push(`${i}:${pairs.join(',')}`);
|
|
1332
|
+
});
|
|
1333
|
+
return parts.join(';');
|
|
1334
|
+
};
|
|
1130
1335
|
buses.i2c.forEach((nodelabel, i) => {
|
|
1131
1336
|
constants[`zephyr.i2c.controllers.${i}.nodeLabel`] = nodelabel;
|
|
1337
|
+
const routes = busPads('i2c', nodelabel);
|
|
1338
|
+
if (routes.length > 0) {
|
|
1339
|
+
constants[`zephyr.i2c.controllers.${i}.pinctrl`] = routes.map((r) => r.name).join(',');
|
|
1340
|
+
constants[`zephyr.i2c.controllers.${i}.pads`] = routes.filter((r) => r.pad).map((r) => `${r.role ?? ''}=${r.pad}`).join(',');
|
|
1341
|
+
}
|
|
1132
1342
|
});
|
|
1133
1343
|
buses.spi.forEach((nodelabel, i) => {
|
|
1134
1344
|
constants[`zephyr.spi.controllers.${i}.nodeLabel`] = nodelabel;
|
|
1345
|
+
const routes = busPads('spi', nodelabel);
|
|
1346
|
+
if (routes.length > 0) {
|
|
1347
|
+
constants[`zephyr.spi.controllers.${i}.pinctrl`] = routes.map((r) => r.name).join(',');
|
|
1348
|
+
constants[`zephyr.spi.controllers.${i}.pads`] = routes.filter((r) => r.pad).map((r) => `${r.role ?? ''}=${r.pad}`).join(',');
|
|
1349
|
+
}
|
|
1135
1350
|
});
|
|
1136
1351
|
buses.uart.forEach((nodelabel, i) => {
|
|
1137
1352
|
constants[`zephyr.uart.controllers.${i}.nodeLabel`] = nodelabel;
|
|
1353
|
+
const routes = busPads('uart', nodelabel);
|
|
1354
|
+
if (routes.length > 0) {
|
|
1355
|
+
constants[`zephyr.uart.controllers.${i}.pinctrl`] = routes.map((r) => r.name).join(',');
|
|
1356
|
+
constants[`zephyr.uart.controllers.${i}.pads`] = routes.filter((r) => r.pad).map((r) => `${r.role ?? ''}=${r.pad}`).join(',');
|
|
1357
|
+
}
|
|
1138
1358
|
});
|
|
1359
|
+
// The board's console controller (chosen zephyr,console) — the
|
|
1360
|
+
// diagnostics annotate the UART instance the bootloader logs on.
|
|
1361
|
+
if (entry.console)
|
|
1362
|
+
constants['zephyr.console'] = entry.console;
|
|
1363
|
+
// Bus pad conflict maps (analyzeResources): "<inst>:<role>=<PAD>,...;..."
|
|
1364
|
+
const i2cPinMap = busPinMap('i2c');
|
|
1365
|
+
const spiPinMap = busPinMap('spi');
|
|
1366
|
+
const uartPinMap = busPinMap('uart');
|
|
1367
|
+
if (i2cPinMap)
|
|
1368
|
+
constants['pins.i2c'] = i2cPinMap;
|
|
1369
|
+
if (spiPinMap)
|
|
1370
|
+
constants['pins.spi'] = spiPinMap;
|
|
1371
|
+
if (uartPinMap)
|
|
1372
|
+
constants['pins.uart'] = uartPinMap;
|
|
1373
|
+
// Board silicon identity for the diagnostics metadata (the report's
|
|
1374
|
+
// SRAM/flash context) — flash is a devicetree fact, sram/clock are not
|
|
1375
|
+
// harvested and stay absent.
|
|
1376
|
+
if (soc)
|
|
1377
|
+
constants['mcu'] = soc;
|
|
1378
|
+
if (entry.flashKb)
|
|
1379
|
+
constants['memory.flash'] = entry.flashKb * 1024;
|
|
1139
1380
|
// USB device (CDC-ACM): the board's DTS turned the controller on.
|
|
1140
1381
|
if (hasUsb) {
|
|
1141
1382
|
constants['zephyr.usb.controller'] = entry.usbController ?? 'zephyr_udc0';
|
|
@@ -1202,7 +1443,7 @@ export function buildModule(entry, userFacts, factsSuffix = '', seedWarnings = [
|
|
|
1202
1443
|
constants,
|
|
1203
1444
|
// Source fingerprint: covers the record content, the extraction
|
|
1204
1445
|
// revision, and the tree provenance (when the record came from a
|
|
1205
|
-
// catalog). `
|
|
1446
|
+
// catalog). `typecad-hal build` recomputes it cheaply and regenerates
|
|
1206
1447
|
// this module when it moves — a board change in the config, the catalog
|
|
1207
1448
|
// overlay, or the Zephyr tree itself recreates the module.
|
|
1208
1449
|
source: {
|
|
@@ -1227,8 +1468,8 @@ export function generateBoard(target, opts) {
|
|
|
1227
1468
|
if (!found) {
|
|
1228
1469
|
const hint = loadBoardCatalogOverlay()
|
|
1229
1470
|
? `'${target}' is not a board target in the current catalog. ` +
|
|
1230
|
-
`It may be new in your Zephyr tree — run '
|
|
1231
|
-
: `No board catalog on this machine. Run '
|
|
1471
|
+
`It may be new in your Zephyr tree — run 'typecad-hal board sync' and retry.`
|
|
1472
|
+
: `No board catalog on this machine. Run 'typecad-hal board sync' first.`;
|
|
1232
1473
|
throw new Error(hint);
|
|
1233
1474
|
}
|
|
1234
1475
|
// The as-built snapshot (this project's last successful build's resolved
|
|
@@ -1250,7 +1491,7 @@ export function generateBoard(target, opts) {
|
|
|
1250
1491
|
asBuiltWarnings.push(`ignoring as-built snapshot: ${err.message}`);
|
|
1251
1492
|
}
|
|
1252
1493
|
}
|
|
1253
|
-
// The project's
|
|
1494
|
+
// The project's typecad-hal.facts.json, when present: the section for THIS
|
|
1254
1495
|
// board merges into the manifest (user routes win per pin), and the raw
|
|
1255
1496
|
// text hashes into the module's source fingerprint so edits regenerate.
|
|
1256
1497
|
let facts;
|
package/dist/chips/resolve.js
CHANGED
|
@@ -196,6 +196,23 @@ export function resolveChipFromBoard(bc) {
|
|
|
196
196
|
// (+ optional vid/pid for the device descriptor).
|
|
197
197
|
const usbController = bc.get('zephyr.usb.controller');
|
|
198
198
|
const usbCdcInstances = bc.get('zephyr.usb.cdcInstances');
|
|
199
|
+
const wakeTimer = bc.get('zephyr.power.wakeTimer');
|
|
200
|
+
const i2sControllers = [];
|
|
201
|
+
for (let ii = 0; bc.get(`zephyr.i2s.controllers.${ii}.nodeLabel`) !== undefined; ii++) {
|
|
202
|
+
i2sControllers.push({
|
|
203
|
+
nodeLabel: String(bc.get(`zephyr.i2s.controllers.${ii}.nodeLabel`)),
|
|
204
|
+
compatible: String(bc.get(`zephyr.i2s.controllers.${ii}.compatible`)),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
const canControllers = [];
|
|
208
|
+
for (let ci = 0; bc.get(`zephyr.can.controllers.${ci}.nodeLabel`) !== undefined; ci++) {
|
|
209
|
+
canControllers.push({
|
|
210
|
+
nodeLabel: String(bc.get(`zephyr.can.controllers.${ci}.nodeLabel`)),
|
|
211
|
+
compatible: String(bc.get(`zephyr.can.controllers.${ci}.compatible`)),
|
|
212
|
+
...(bc.get(`zephyr.can.controllers.${ci}.txPad`) !== undefined ? { txPad: Number(bc.get(`zephyr.can.controllers.${ci}.txPad`)) } : {}),
|
|
213
|
+
...(bc.get(`zephyr.can.controllers.${ci}.rxPad`) !== undefined ? { rxPad: Number(bc.get(`zephyr.can.controllers.${ci}.rxPad`)) } : {}),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
199
216
|
const usbVid = bc.get('zephyr.usb.vid');
|
|
200
217
|
const usbPid = bc.get('zephyr.usb.pid');
|
|
201
218
|
// Optional 1200-baud touch-to-reset data (BOSSA-bootloader boards).
|
|
@@ -327,6 +344,9 @@ export function resolveChipFromBoard(bc) {
|
|
|
327
344
|
...(storageOffset != null && storageSize != null
|
|
328
345
|
? { storage: { offset: storageOffset, size: storageSize, ...(storagePreexisting ? { preexisting: true } : {}) } }
|
|
329
346
|
: {}),
|
|
347
|
+
...(wakeTimer ? { powerWakeTimer: true } : {}),
|
|
348
|
+
...(canControllers.length > 0 ? { can: { controllers: canControllers } } : {}),
|
|
349
|
+
...(i2sControllers.length > 0 ? { i2s: { controllers: i2sControllers } } : {}),
|
|
330
350
|
...(usbController && usbCdcInstances && usbCdcInstances > 0
|
|
331
351
|
? {
|
|
332
352
|
usb: {
|
package/dist/chips/types.d.ts
CHANGED
|
@@ -219,6 +219,27 @@ export interface ZephyrDacChannel {
|
|
|
219
219
|
* Pure-data descriptor for a Zephyr board + its SoC's peripheral layout.
|
|
220
220
|
*/
|
|
221
221
|
export interface ZephyrChipDescriptor {
|
|
222
|
+
/** The SoC's RTC wake timer (ESP32 family rtc_timer fact) — Power.offFor
|
|
223
|
+
* arms it (esp_sleep_enable_timer_wakeup) before soft-off. */
|
|
224
|
+
readonly powerWakeTimer?: boolean;
|
|
225
|
+
/** CAN controllers (harvested labeled can@ nodes) — the lowering
|
|
226
|
+
* addresses the first by its DT nodelabel. */
|
|
227
|
+
readonly can?: {
|
|
228
|
+
controllers: readonly {
|
|
229
|
+
nodeLabel: string;
|
|
230
|
+
compatible: string;
|
|
231
|
+
txPad?: number;
|
|
232
|
+
rxPad?: number;
|
|
233
|
+
}[];
|
|
234
|
+
};
|
|
235
|
+
/** I2S controllers (harvested labeled i2s@ nodes) — the lowering
|
|
236
|
+
* addresses each by its DT nodelabel. */
|
|
237
|
+
readonly i2s?: {
|
|
238
|
+
controllers: readonly {
|
|
239
|
+
nodeLabel: string;
|
|
240
|
+
compatible: string;
|
|
241
|
+
}[];
|
|
242
|
+
};
|
|
222
243
|
/** Zephyr board target (the `west build -b <id>` argument), e.g. 'xiao_ble'. */
|
|
223
244
|
readonly id: string;
|
|
224
245
|
/** SoC family, e.g. 'nrf52840'. */
|
|
@@ -436,7 +457,7 @@ export interface ZephyrChipDescriptor {
|
|
|
436
457
|
* verified with the board, instead of in user configs. One probe method
|
|
437
458
|
* serves BOTH flashing and debugging (the same attach session); entries
|
|
438
459
|
* that cannot debug (bootloaders) set `debug: false`. Users select one via
|
|
439
|
-
* `zephyr.probe` in
|
|
460
|
+
* `zephyr.probe` in typecad-hal.config.ts or `--probe` on the CLI;
|
|
440
461
|
* `zephyr.runner`/`runnerArgs` remain the raw escape hatch underneath.
|
|
441
462
|
*/
|
|
442
463
|
readonly probeMethods?: readonly ZephyrProbeMethod[];
|
package/dist/debug-codegen.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// stdlibSupport.hasIostream=false), so the GenericStrategy's std::cout fallback
|
|
7
7
|
// used by the debug preprocessor would NOT compile. This module routes every
|
|
8
8
|
// debug line through printk("...\n") — the always-available Zephyr console,
|
|
9
|
-
// with no CONFIG_CONSOLE dependency — so `
|
|
9
|
+
// with no CONFIG_CONSOLE dependency — so `typecad-hal build --debug` produces
|
|
10
10
|
// compiling output.
|
|
11
11
|
//
|
|
12
12
|
// The halt primitive is __tc_debug_wait_for_continue() (emitted in
|