@typecad/framework-zephyr 1.0.0-alpha.15 → 1.0.0-alpha.18
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/boardgen.d.ts +1 -9
- package/dist/boardgen.js +228 -45
- package/dist/chips/types.d.ts +1 -1
- package/dist/debug-codegen.js +1 -1
- package/dist/display/touch-adapter.js +1 -1
- package/dist/display/ui-adapter.js +549 -549
- package/dist/doctor.js +4 -4
- package/dist/dt-config/custom-board.js +2 -2
- package/dist/dt-config/kconfig.js +18 -12
- package/dist/dt-config/overlay.d.ts +2 -2
- package/dist/dt-config/overlay.js +2 -2
- package/dist/framework.manifest.d.ts +3 -3
- package/dist/framework.manifest.js +10 -7
- package/dist/index.js +5 -5
- package/dist/licenses.d.ts +2 -2
- package/dist/licenses.js +8 -8
- package/dist/lowering/fs.js +1 -1
- package/dist/lowering/gpio.js +0 -32
- package/dist/lowering/http.js +264 -32
- package/dist/lowering/i2c.js +0 -8
- package/dist/lowering/interrupts.js +6 -0
- package/dist/lowering/mqtt.js +110 -8
- package/dist/lowering/usb.js +11 -11
- package/dist/lowering/wdt.js +2 -29
- package/dist/sdk/board-catalog-sync.d.ts +1 -3
- package/dist/sdk/board-catalog-sync.js +4 -10
- package/dist/strategy.d.ts +22 -44
- package/dist/strategy.js +152 -155
- 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 +241 -502
- package/dist/toolchain/env-check.d.ts +1 -3
- package/dist/toolchain/env-check.js +2 -7
- package/dist/toolchain/index.d.ts +65 -2
- package/dist/toolchain/index.js +432 -55
- package/dist/toolchain/runners.d.ts +16 -0
- package/dist/toolchain/runners.js +75 -0
- package/dist/toolchain/scaffold.d.ts +1 -1
- package/dist/toolchain/scaffold.js +12 -12
- 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/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/boardgen.ts +214 -48
- package/src/chips/types.ts +567 -567
- package/src/display/touch-adapter.ts +204 -204
- package/src/display/ui-adapter.ts +781 -781
- package/src/doctor.ts +4 -4
- package/src/dt-config/custom-board.ts +2 -2
- package/src/dt-config/kconfig.ts +18 -12
- package/src/dt-config/overlay.ts +1058 -1058
- package/src/framework.manifest.ts +538 -535
- package/src/index.ts +5 -5
- package/src/licenses.ts +425 -425
- package/src/lowering/fs.ts +135 -135
- package/src/lowering/gpio.ts +0 -33
- package/src/lowering/http.ts +264 -32
- package/src/lowering/i2c.ts +0 -9
- package/src/lowering/interrupts.ts +6 -0
- package/src/lowering/mqtt.ts +109 -8
- package/src/lowering/usb.ts +221 -221
- package/src/lowering/wdt.ts +2 -25
- package/src/sdk/board-catalog-sync.ts +4 -25
- package/src/strategy.ts +2265 -2309
- package/src/toolchain/debug-config.ts +264 -514
- package/src/toolchain/env-check.ts +279 -285
- package/src/toolchain/index.ts +1703 -1286
- package/src/toolchain/runners.ts +80 -0
- package/src/toolchain/scaffold.ts +296 -296
- package/src/toolchain/west-discover.ts +35 -13
- package/src/toolchain/west-spawn.ts +174 -168
- 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/power.d.ts +0 -9
- package/dist/lowering/power.js +0 -60
- 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/strategy.js
CHANGED
|
@@ -25,6 +25,22 @@ import { syncBoardCatalog, ensureFreshBoardCatalog, } from './sdk/board-catalog-
|
|
|
25
25
|
import { setActiveChip, NO_BOARD_CHIP } from './chips/index.js';
|
|
26
26
|
import { resolveChipFromBoard } from './chips/resolve.js';
|
|
27
27
|
import { emitGpioDevDispatcher } from './chips/controllers.js';
|
|
28
|
+
/**
|
|
29
|
+
* Visit the program's transpile-resolved HAL ops with the same `visit` the IR
|
|
30
|
+
* walk uses. A HAL call inlined into another HAL call's template literal
|
|
31
|
+
* (`USB0.writeLine(\`n: ${gps.available()}\`)`) is lowered to C++ text while
|
|
32
|
+
* the IR is built — it never becomes a hal-op/hal-expr IR node, so the walk
|
|
33
|
+
* alone cannot see it. Such ops ride on ProgramIR.resolvedHalOps; wrapped as
|
|
34
|
+
* `{ operation: op }` they match the hal-op node shape every collector below
|
|
35
|
+
* tests for. Without this fold, shims keyed on these scans (UART RX rings,
|
|
36
|
+
* sensor device handles, per-controller bus state, ADC channels/overrides,
|
|
37
|
+
* dt specs) go undeclared while the baked text still references them — the
|
|
38
|
+
* `'__tc_dt_led0' was not declared` failure class.
|
|
39
|
+
*/
|
|
40
|
+
function visitResolvedHalOps(program, visit) {
|
|
41
|
+
for (const op of program?.resolvedHalOps ?? [])
|
|
42
|
+
visit({ operation: op });
|
|
43
|
+
}
|
|
28
44
|
/**
|
|
29
45
|
* Deep-walk the program IR and collect the HAL pin numbers the program
|
|
30
46
|
* actually touches for a peripheral family ('adc' | 'pwm') — the same walk
|
|
@@ -64,6 +80,7 @@ function collectUsedPins(program, kind, chip) {
|
|
|
64
80
|
}
|
|
65
81
|
};
|
|
66
82
|
visit(program);
|
|
83
|
+
visitResolvedHalOps(program, visit);
|
|
67
84
|
return pins;
|
|
68
85
|
}
|
|
69
86
|
/**
|
|
@@ -99,6 +116,7 @@ function collectAdcOverrideDevices(program) {
|
|
|
99
116
|
}
|
|
100
117
|
};
|
|
101
118
|
visit(program);
|
|
119
|
+
visitResolvedHalOps(program, visit);
|
|
102
120
|
return devices;
|
|
103
121
|
}
|
|
104
122
|
/**
|
|
@@ -136,6 +154,7 @@ function collectPwmOverrideSpecs(program) {
|
|
|
136
154
|
}
|
|
137
155
|
};
|
|
138
156
|
visit(program);
|
|
157
|
+
visitResolvedHalOps(program, visit);
|
|
139
158
|
return specs;
|
|
140
159
|
}
|
|
141
160
|
/**
|
|
@@ -185,6 +204,7 @@ function collectUsedBusIndices(program) {
|
|
|
185
204
|
}
|
|
186
205
|
};
|
|
187
206
|
visit(program);
|
|
207
|
+
visitResolvedHalOps(program, visit);
|
|
188
208
|
return indices;
|
|
189
209
|
}
|
|
190
210
|
/**
|
|
@@ -228,6 +248,7 @@ export function collectSensors(program) {
|
|
|
228
248
|
}
|
|
229
249
|
};
|
|
230
250
|
visit(program);
|
|
251
|
+
visitResolvedHalOps(program, visit);
|
|
231
252
|
return sensors;
|
|
232
253
|
}
|
|
233
254
|
/**
|
|
@@ -266,6 +287,7 @@ export function collectSpiTargets(program) {
|
|
|
266
287
|
}
|
|
267
288
|
};
|
|
268
289
|
visit(program);
|
|
290
|
+
visitResolvedHalOps(program, visit);
|
|
269
291
|
return targets;
|
|
270
292
|
}
|
|
271
293
|
/**
|
|
@@ -305,6 +327,7 @@ export function collectUartRings(program) {
|
|
|
305
327
|
}
|
|
306
328
|
};
|
|
307
329
|
visit(program);
|
|
330
|
+
visitResolvedHalOps(program, visit);
|
|
308
331
|
return rings;
|
|
309
332
|
}
|
|
310
333
|
/**
|
|
@@ -339,6 +362,7 @@ export function collectThreads(program) {
|
|
|
339
362
|
}
|
|
340
363
|
};
|
|
341
364
|
visit(program);
|
|
365
|
+
visitResolvedHalOps(program, visit);
|
|
342
366
|
return threads;
|
|
343
367
|
}
|
|
344
368
|
import { lowerHalOp } from './lowering/index.js';
|
|
@@ -385,13 +409,15 @@ import { httpInitLines } from './lowering/http.js';
|
|
|
385
409
|
import { mqttInitLines } from './lowering/mqtt.js';
|
|
386
410
|
import { preferencesInitLines } from './lowering/preferences.js';
|
|
387
411
|
import { randomInitLines } from './lowering/random.js';
|
|
388
|
-
import { generateZephyrInitCode, generateZephyrBreakpointCode, generateZephyrLogpointCode } from './debug-codegen.js';
|
|
389
412
|
import { generateStaticAsyncRuntime } from '@typecad/cuttlefish/api/shared';
|
|
390
413
|
import { resolveZephyrDisplayOp, newDisplayState } from './display/index.js';
|
|
391
414
|
import { buildDisplayRuntime } from './display/gfx.js';
|
|
392
415
|
import { ZEPHYR_DISPLAY_PROFILES, BUILT_IN_PROFILES } from './display/profiles.js';
|
|
393
416
|
import { zephyrDisplayAdapterGenerator } from './display/ui-adapter.js';
|
|
394
417
|
import { zephyrTouchAdapter } from './display/touch-adapter.js';
|
|
418
|
+
/** debugMode() memo — the boardgen facts lookup is not free and the method is
|
|
419
|
+
* called several times per build (transpile gate + artifact writers). */
|
|
420
|
+
const debugModeMemo = new Map();
|
|
395
421
|
export class ZephyrStrategy {
|
|
396
422
|
constructor() {
|
|
397
423
|
this.id = 'zephyr';
|
|
@@ -437,22 +463,7 @@ export class ZephyrStrategy {
|
|
|
437
463
|
setActiveChip(fromBoard ?? NO_BOARD_CHIP);
|
|
438
464
|
return fromBoard ?? NO_BOARD_CHIP;
|
|
439
465
|
}
|
|
440
|
-
/**
|
|
441
|
-
* Resolve the debug mode for the active target from the platform context.
|
|
442
|
-
* Mirrors resolveChip's target extraction so shimLines/forcedIncludes can
|
|
443
|
-
* gate the printf halt shim + console UART include to printf builds only
|
|
444
|
-
* (gdb builds use VS Code native breakpoints + #line markers, so the
|
|
445
|
-
* __tc_debug_wait_for_continue shim and its <zephyr/drivers/uart.h> include
|
|
446
|
-
* are dead code there).
|
|
447
|
-
*/
|
|
448
|
-
resolveDebugMode(ctx) {
|
|
449
|
-
const fd = ctx?.frameworkData;
|
|
450
|
-
const target = fd?.target ??
|
|
451
|
-
fd?.buildTarget;
|
|
452
|
-
return this.debugMode(target);
|
|
453
|
-
}
|
|
454
466
|
forcedIncludes(_program, ctx) {
|
|
455
|
-
const isPrintf = this.resolveDebugMode(ctx) === 'printf';
|
|
456
467
|
// <zephyr/kernel.h> for k_msleep / k_uptime_get_32 / k_busy_wait / printk.
|
|
457
468
|
// <zephyr/drivers/gpio.h> for the gpio_pin_*_dt / gpio_dt_spec API.
|
|
458
469
|
// <cstdint> because DIRECT_CPP_TYPE_MAP passes int32_t/uint8_t through
|
|
@@ -473,7 +484,7 @@ export class ZephyrStrategy {
|
|
|
473
484
|
// passes int32_t/uint8_t through verbatim.
|
|
474
485
|
const inc = ['<zephyr/kernel.h>', '<zephyr/drivers/gpio.h>', '<cstdint>'];
|
|
475
486
|
// <cstdio> backs the printf family only: __tc_print/__tc_println (emitted
|
|
476
|
-
// solely when
|
|
487
|
+
// solely when the test-runner preprocessor injected them — tracked via
|
|
477
488
|
// usedPolyfillHelpers), raw printf/snprintf in user code (usesCstdio), and
|
|
478
489
|
// the fs/preferences/uart shims (their lowerings snprintf into buffers).
|
|
479
490
|
// A program touching none of those needs no <cstdio>.
|
|
@@ -491,12 +502,6 @@ export class ZephyrStrategy {
|
|
|
491
502
|
inc.push('<zephyr/drivers/spi.h>');
|
|
492
503
|
if (uses('usesUart'))
|
|
493
504
|
inc.push('<zephyr/drivers/uart.h>');
|
|
494
|
-
// uart.h is also needed by the printf-mode debug halt shim
|
|
495
|
-
// (__tc_debug_wait_for_continue polls the console UART) even when the
|
|
496
|
-
// program itself does not use the UART HAL. In gdb mode the shim is not
|
|
497
|
-
// emitted, so skip the include there to avoid pulling in an unused header.
|
|
498
|
-
if (isPrintf && !inc.includes('<zephyr/drivers/uart.h>'))
|
|
499
|
-
inc.push('<zephyr/drivers/uart.h>');
|
|
500
505
|
// USB CDC serial: the class instance is a UART device (uart.h); the
|
|
501
506
|
// device context macros + usbd_* API live in the next-stack header.
|
|
502
507
|
if (uses('usesUsb')) {
|
|
@@ -550,10 +555,11 @@ export class ZephyrStrategy {
|
|
|
550
555
|
// HTTP/S client: Zephyr's http_client_req runs over a pre-connected socket,
|
|
551
556
|
// so the shim pulls in the BSD socket + POSIX DNS surfaces alongside the
|
|
552
557
|
// http client/parser headers. TLS sec tags need tls_credentials; <cstring>
|
|
553
|
-
// /<cstdlib> back the shim's memcpy/strlen/new-nothrow usage (the
|
|
554
|
-
// shim only includes <cstdio>/<cstdint>
|
|
558
|
+
// /<cstdlib>/<new> back the shim's memcpy/strlen/new-nothrow usage (the
|
|
559
|
+
// core shim only includes <cstdio>/<cstdint> — std::nothrow is not
|
|
560
|
+
// guaranteed to arrive transitively).
|
|
555
561
|
if (uses('usesHttp'))
|
|
556
|
-
inc.push('<zephyr/net/socket.h>', '<zephyr/net/http/client.h>', '<zephyr/net/http/parser.h>', '<zephyr/net/tls_credentials.h>', '<zephyr/posix/sys/socket.h>', '<cstring>', '<cstdlib>');
|
|
562
|
+
inc.push('<zephyr/net/socket.h>', '<zephyr/net/http/client.h>', '<zephyr/net/http/parser.h>', '<zephyr/net/tls_credentials.h>', '<zephyr/posix/sys/socket.h>', '<cstring>', '<cstdlib>', '<new>');
|
|
557
563
|
// MQTT client: <zephyr/net/mqtt.h> for mqtt_connect/publish/subscribe, plus
|
|
558
564
|
// <zephyr/net/socket.h> for the zsock_* poll/getaddrinfo API the shim's poll
|
|
559
565
|
// thread uses, and <zephyr/net/tls_credentials.h> for the mqtts:// path
|
|
@@ -608,6 +614,10 @@ export class ZephyrStrategy {
|
|
|
608
614
|
return;
|
|
609
615
|
}
|
|
610
616
|
for (const v of Object.values(node)) {
|
|
617
|
+
if (typeof v === 'string' && v.includes(TOKEN)) {
|
|
618
|
+
found = true;
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
611
621
|
if (Array.isArray(v)) {
|
|
612
622
|
for (const item of v)
|
|
613
623
|
visit(item);
|
|
@@ -620,9 +630,17 @@ export class ZephyrStrategy {
|
|
|
620
630
|
return found;
|
|
621
631
|
}
|
|
622
632
|
/** Pins referenced by gpio.* hal-ops in the program IR. lowerGpio routes a
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
*
|
|
633
|
+
* pin to its devicetree spec by pin NUMBER, so the structured hal-op pins
|
|
634
|
+
* are the authoritative signal for which __tc_dt_* specs are needed —
|
|
635
|
+
* regardless of when the final call text is rendered.
|
|
636
|
+
*
|
|
637
|
+
* A gpio op interpolated into another HAL call's template literal
|
|
638
|
+
* (`USB0.writeLine(\`led: ${led.get()}\`)`) never becomes an IR node —
|
|
639
|
+
* resolveHALExprToText lowers it to C++ text while building the IR and bakes
|
|
640
|
+
* it into an __EMIT__ snprintf prelude, so the walk cannot see its pin. The
|
|
641
|
+
* spec NAME it references is still in that text; collectRawMatches finds it
|
|
642
|
+
* there, or the spec goes undeclared and the build fails on `__tc_dt_led0
|
|
643
|
+
* was not declared in this scope`. */
|
|
626
644
|
collectGpioPinUsage(program) {
|
|
627
645
|
const pins = new Set();
|
|
628
646
|
if (!program)
|
|
@@ -646,13 +664,18 @@ export class ZephyrStrategy {
|
|
|
646
664
|
}
|
|
647
665
|
};
|
|
648
666
|
visit(program);
|
|
667
|
+
visitResolvedHalOps(program, visit);
|
|
649
668
|
return pins;
|
|
650
669
|
}
|
|
651
670
|
/** Run `re` (global) against every raw string in the IR — raw expression
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
671
|
+
* values plus raw hal-op codes — returning capture group 1 of each match
|
|
672
|
+
* (the full match when the regex has no group). This is how references the
|
|
673
|
+
* text scanners must see but that never appear as IR call nodes are
|
|
674
|
+
* discovered: a rawCpp() escape hatch naming `__tc_dt_sw0` directly, and —
|
|
675
|
+
* the reason every string LEAF is scanned, not just raw nodes — the
|
|
676
|
+
* pre-lowered C++ text of a HAL call inlined into another HAL call's
|
|
677
|
+
* template literal, which the IR builder bakes into plain `string` payloads
|
|
678
|
+
* (__EMIT__ snprintf preludes, op data fields) rather than raw nodes. */
|
|
656
679
|
collectRawMatches(program, re) {
|
|
657
680
|
const found = new Set();
|
|
658
681
|
if (!program)
|
|
@@ -664,14 +687,10 @@ export class ZephyrStrategy {
|
|
|
664
687
|
const visit = (node) => {
|
|
665
688
|
if (!node || typeof node !== 'object')
|
|
666
689
|
return;
|
|
667
|
-
if (node.kind === 'raw' && typeof node.value === 'string')
|
|
668
|
-
scan(node.value);
|
|
669
|
-
if (node.operation && typeof node.operation === 'object'
|
|
670
|
-
&& node.operation.operation === 'raw' && typeof node.operation.code === 'string') {
|
|
671
|
-
scan(node.operation.code);
|
|
672
|
-
}
|
|
673
690
|
for (const v of Object.values(node)) {
|
|
674
|
-
if (
|
|
691
|
+
if (typeof v === 'string')
|
|
692
|
+
scan(v);
|
|
693
|
+
else if (Array.isArray(v)) {
|
|
675
694
|
for (const item of v)
|
|
676
695
|
visit(item);
|
|
677
696
|
}
|
|
@@ -700,7 +719,6 @@ export class ZephyrStrategy {
|
|
|
700
719
|
}
|
|
701
720
|
shimLines(program, ctx) {
|
|
702
721
|
const chip = this.resolveChip(ctx, program);
|
|
703
|
-
const isPrintf = this.resolveDebugMode(ctx) === 'printf';
|
|
704
722
|
const a = ctx?.analysis;
|
|
705
723
|
const uses = (f) => (a ? !!a[f] : true);
|
|
706
724
|
const helpers = a?.usedPolyfillHelpers;
|
|
@@ -764,7 +782,7 @@ export class ZephyrStrategy {
|
|
|
764
782
|
if (entryHasUI()) {
|
|
765
783
|
guardBody.push('#ifndef PROGMEM', '#define PROGMEM', '#endif');
|
|
766
784
|
}
|
|
767
|
-
// Test-runner console helpers:
|
|
785
|
+
// Test-runner console helpers: the test-runner's Zephyr shim calls these
|
|
768
786
|
// for protocol output. Overloaded for string (const char*) and numeric
|
|
769
787
|
// (double) so the same call site works for markers and test values.
|
|
770
788
|
// The fs lowering bakes __tc_println into its error paths too, so the
|
|
@@ -953,13 +971,15 @@ export class ZephyrStrategy {
|
|
|
953
971
|
lines.push('// cuttlefish runtime shim. Wrapped in a single include guard so the', '// block is safe to emit into multiple headers and .cpp files within', '// one translation unit (a .cpp may #include several headers that each', '// carry the shim). The guard ensures the definitions are seen exactly', '// once per TU.', '#ifndef CUTTLEFISH_SHIM_DEFINED', '#define CUTTLEFISH_SHIM_DEFINED', ...guardBody, '#endif // CUTTLEFISH_SHIM_DEFINED');
|
|
954
972
|
}
|
|
955
973
|
// Devicetree specs — one per board-defined GPIO pin, but ONLY for pins the
|
|
956
|
-
// program actually addresses (lowerGpio routes by pin number
|
|
957
|
-
// structured gpio.* hal-op pins
|
|
958
|
-
//
|
|
959
|
-
//
|
|
960
|
-
//
|
|
961
|
-
//
|
|
962
|
-
//
|
|
974
|
+
// program actually addresses (lowerGpio routes by pin number; the
|
|
975
|
+
// structured gpio.* hal-op pins plus the spec names appearing in any IR
|
|
976
|
+
// string — including the pre-lowered text of a HAL call inlined into
|
|
977
|
+
// another HAL call's template literal — are visible here) and aliases
|
|
978
|
+
// named verbatim in raw code (rawCpp escape hatches). Emitted OUTSIDE the
|
|
979
|
+
// single CUTTLEFISH_SHIM_DEFINED guard with a per-symbol guard: per-file
|
|
980
|
+
// pin sets differ, and in a multi-header TU the first header's TU-wide
|
|
981
|
+
// guard would otherwise hide the second header's specs. Without a program
|
|
982
|
+
// (capability query), emit them all.
|
|
963
983
|
const usedPins = this.collectGpioPinUsage(program);
|
|
964
984
|
const dtTextRefs = this.collectRawMatches(program, /__tc_dt_([A-Za-z0-9_]+)/g);
|
|
965
985
|
for (const spec of chip.gpio.dtSpecs) {
|
|
@@ -968,32 +988,6 @@ export class ZephyrStrategy {
|
|
|
968
988
|
const guard = `__TC_DT_${spec.dtSpec.replace(/[^A-Za-z0-9_]/g, '_').toUpperCase()}_SPEC`;
|
|
969
989
|
lines.push(`#ifndef ${guard}`, `#define ${guard}`, `static const struct gpio_dt_spec __tc_dt_${spec.dtSpec} = GPIO_DT_SPEC_GET(DT_ALIAS(${spec.dtSpec}), gpios);`, `#endif // ${guard}`);
|
|
970
990
|
}
|
|
971
|
-
// --- Debug-mode halt + per-breakpoint disable registry ---
|
|
972
|
-
//
|
|
973
|
-
// Printf mode only. In gdb mode the cuttlefish debug preprocessor is
|
|
974
|
-
// skipped (core emits #line markers + VS Code native breakpoints instead),
|
|
975
|
-
// so __tc_debug_wait_for_continue is never called — skip the shim and its
|
|
976
|
-
// <zephyr/drivers/uart.h> dependency entirely (forcedIncludes mirrors this).
|
|
977
|
-
//
|
|
978
|
-
// The cuttlefish debug preprocessor injects __tc_debug_wait_for_continue(id)
|
|
979
|
-
// calls at each breakpoint; without these definitions the emitted code
|
|
980
|
-
// would not link.
|
|
981
|
-
//
|
|
982
|
-
// Zephyr's minimal libc has no getchar()/EOF, so the halt polls the console
|
|
983
|
-
// UART directly via uart_poll_in on the system console device, yielding to
|
|
984
|
-
// the scheduler with k_msleep between polls so an unattended breakpoint
|
|
985
|
-
// does not starve the system. ENTER (or any non-'s' byte) = continue;
|
|
986
|
-
// 's'/'S' = skip this breakpoint for the rest of the run (records the id).
|
|
987
|
-
if (isPrintf) {
|
|
988
|
-
lines.push('#ifndef __TC_BP_DISABLED_DEFINED', '#define __TC_BP_DISABLED_DEFINED', 'static bool __tc_bp_disabled[256] = {0};', 'static inline bool __tc_bp_is_disabled(int id) { return id >= 0 && id < 256 && __tc_bp_disabled[id]; }',
|
|
989
|
-
// Console input: poll the UART console device. DEVICE_DT_GET(DT_CHOSEN(zephyr_console))
|
|
990
|
-
// resolves to the board's console (UART0 USB-CDC on the XIAO nRF52840).
|
|
991
|
-
// Not every board DTS declares a zephyr,console chosen (STM32MP1 M-side,
|
|
992
|
-
// display/carrier boards): there is nothing to print a prompt on and
|
|
993
|
-
// nothing to read a key from, so breakpoints auto-continue instead of
|
|
994
|
-
// hanging an unattended run.
|
|
995
|
-
'#if DT_HAS_CHOSEN(zephyr_console)', 'static inline char __tc_debug_wait_for_continue(int id) {', ' const struct device* __con = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));', ' unsigned char __c = 0;', " while (uart_poll_in(__con, &__c) != 0) {", ' k_msleep(10);', ' }', " // Drain the rest of the typed line so the next breakpoint waits fresh.", " unsigned char __peek = 0;", " while (uart_poll_in(__con, &__peek) == 0 && __peek != '\\n') { (void)0; }", " if ((__c == 's') || (__c == 'S')) { if (id >= 0 && id < 256) __tc_bp_disabled[id] = true; }", ' return static_cast<char>(__c);', '}', '#else', 'static inline char __tc_debug_wait_for_continue(int id) { (void)id; return static_cast<char>(0); }', '#endif // DT_HAS_CHOSEN(zephyr_console)', '#endif // __TC_BP_DISABLED_DEFINED', '');
|
|
996
|
-
}
|
|
997
991
|
// --- Zephyr entrypoint ---------------------------------------------------
|
|
998
992
|
// No bridge here: the synthesizer emits main() itself (it keys off
|
|
999
993
|
// entrypointFunctionName()="main" and requiresLoopFunction()=false), with
|
|
@@ -1556,10 +1550,13 @@ export class ZephyrStrategy {
|
|
|
1556
1550
|
// ── Interrupt safety ─────────────────────────────────────────────────────
|
|
1557
1551
|
// Zephyr ISRs run above thread context: anything that sleeps (k_msleep),
|
|
1558
1552
|
// pends, or takes a driver lock is illegal there (asserted by the kernel in
|
|
1559
|
-
// debug builds; corrupts scheduler state otherwise). The
|
|
1560
|
-
//
|
|
1561
|
-
//
|
|
1562
|
-
//
|
|
1553
|
+
// debug builds; corrupts scheduler state otherwise). The keys below are
|
|
1554
|
+
// matched by cuttlefish's interrupt-analysis pass in two shapes: bare/qualified
|
|
1555
|
+
// callee names (call statements) and resolved hal-op payloads — the analyzer
|
|
1556
|
+
// maps timing.delay/delay_microseconds/sleep/busy_wait_us ops back to the
|
|
1557
|
+
// bare timing keys, and matches the op payload's port/bus field (UART0,
|
|
1558
|
+
// I2C0, SPI0, …) against these keys directly. The same keys ArduinoStrategy
|
|
1559
|
+
// uses.
|
|
1563
1560
|
isrUnsafeOperations() {
|
|
1564
1561
|
return new Map([
|
|
1565
1562
|
['delay', {
|
|
@@ -1698,14 +1695,14 @@ export class ZephyrStrategy {
|
|
|
1698
1695
|
catch (err) {
|
|
1699
1696
|
// A malformed facts/as-built file is the USER's error — surface it
|
|
1700
1697
|
// verbatim instead of the generic "cannot generate" below.
|
|
1701
|
-
if (err instanceof Error && (err.message.includes('
|
|
1698
|
+
if (err instanceof Error && (err.message.includes('typecad-hal.facts.json') || err.message.includes('as-built.json')))
|
|
1702
1699
|
throw err;
|
|
1703
1700
|
return undefined;
|
|
1704
1701
|
}
|
|
1705
1702
|
}
|
|
1706
1703
|
/**
|
|
1707
1704
|
* Regenerate the board catalog overlay from the user's own Zephyr tree —
|
|
1708
|
-
* `
|
|
1705
|
+
* `typecad-hal board sync`. After a `west update`, this is how new/changed/
|
|
1709
1706
|
* removed boards reach projects without a cuttlefish release. See
|
|
1710
1707
|
* src/sdk/board-catalog-sync.ts.
|
|
1711
1708
|
*/
|
|
@@ -1714,7 +1711,7 @@ export class ZephyrStrategy {
|
|
|
1714
1711
|
}
|
|
1715
1712
|
/**
|
|
1716
1713
|
* Refresh the overlay only when it is stale (provenance no longer matches
|
|
1717
|
-
* the tree) — the pre-step `
|
|
1714
|
+
* the tree) — the pre-step `typecad-hal board regen` runs so a regen after
|
|
1718
1715
|
* `west update` picks up the tree's boards automatically. Tree walk only
|
|
1719
1716
|
* happens when there is actual refreshing to do.
|
|
1720
1717
|
*/
|
|
@@ -1899,23 +1896,23 @@ export class ZephyrStrategy {
|
|
|
1899
1896
|
requiredIncludes: ['<cstring>'],
|
|
1900
1897
|
forwardDeclarations: [],
|
|
1901
1898
|
helperStructs: [],
|
|
1902
|
-
helperFunctions: [`
|
|
1903
|
-
// TypeCAD string method polyfills (Zephyr, minimal-libc).
|
|
1904
|
-
#ifndef CUTTLEFISH_STR_BUF_SIZE
|
|
1905
|
-
#define CUTTLEFISH_STR_BUF_SIZE 64
|
|
1906
|
-
#endif
|
|
1907
|
-
bool __tc_endsWith(const char* s, const char* suffix) { int sl = strlen(s), tl = strlen(suffix); return sl >= tl && strcmp(s + sl - tl, suffix) == 0; }
|
|
1908
|
-
const char* __tc_toUpperCase(const char* s) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; strncpy(b, s, CUTTLEFISH_STR_BUF_SIZE - 1); b[CUTTLEFISH_STR_BUF_SIZE - 1] = '\\0'; for (char* p = b; *p; p++) { if (*p >= 'a' && *p <= 'z') { *p = static_cast<char>(*p - 32); } } return b; }
|
|
1909
|
-
const char* __tc_toLowerCase(const char* s) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; strncpy(b, s, CUTTLEFISH_STR_BUF_SIZE - 1); b[CUTTLEFISH_STR_BUF_SIZE - 1] = '\\0'; for (char* p = b; *p; p++) { if (*p >= 'A' && *p <= 'Z') { *p = static_cast<char>(*p + 32); } } return b; }
|
|
1910
|
-
const char* __tc_trim(const char* s) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; while (*s == ' ' || *s == '\\t' || *s == '\\n' || *s == '\\r') s++; int len = strlen(s); while (len > 0 && (s[len-1] == ' ' || s[len-1] == '\\t' || s[len-1] == '\\n' || s[len-1] == '\\r')) len--; int cplen = len < CUTTLEFISH_STR_BUF_SIZE - 1 ? len : CUTTLEFISH_STR_BUF_SIZE - 1; strncpy(b, s, cplen); b[cplen] = '\\0'; return b; }
|
|
1911
|
-
const char* __tc_substring2(const char* s, int start, int end) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; int slen = strlen(s); if (start < 0) start = 0; if (end > slen) end = slen; if (end < start) end = start; int len = end - start; if (len >= CUTTLEFISH_STR_BUF_SIZE) len = CUTTLEFISH_STR_BUF_SIZE - 1; strncpy(b, s + start, len); b[len] = '\\0'; return b; }
|
|
1912
|
-
const char* __tc_substring1(const char* s, int start) { return __tc_substring2(s, start, strlen(s)); }
|
|
1913
|
-
const char* __tc_slice2(const char* s, int start, int end) { return __tc_substring2(s, start, end); }
|
|
1914
|
-
const char* __tc_slice1(const char* s, int start) { return __tc_substring2(s, start, strlen(s)); }
|
|
1915
|
-
const char* __tc_replace(const char* s, const char* old, const char* repl) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; const char* pos = strstr(s, old); if (!pos) { strncpy(b, s, CUTTLEFISH_STR_BUF_SIZE - 1); b[CUTTLEFISH_STR_BUF_SIZE - 1] = '\\0'; return b; } int beforeLen = static_cast<int>(pos - s); int oldLen = static_cast<int>(strlen(old)); int replLen = static_cast<int>(strlen(repl)); if (beforeLen + replLen + static_cast<int>(strlen(pos + oldLen)) >= CUTTLEFISH_STR_BUF_SIZE) { strncpy(b, s, CUTTLEFISH_STR_BUF_SIZE - 1); b[CUTTLEFISH_STR_BUF_SIZE - 1] = '\\0'; return b; } memcpy(b, s, beforeLen); memcpy(b + beforeLen, repl, replLen); strcpy(b + beforeLen + replLen, pos + oldLen); return b; }
|
|
1916
|
-
const char* __tc_charAt(const char* s, int idx) { static char buf[2][2]; static uint8_t slot = 0; slot ^= 1; buf[slot][0] = s[idx]; buf[slot][1] = '\\0'; return buf[slot]; }
|
|
1917
|
-
int __tc_charCodeAt(const char* s, int idx) { return static_cast<int>(static_cast<unsigned char>(s[idx])); }
|
|
1918
|
-
int __tc_indexOf(const char* s, const char* needle) { const char* p = strstr(s, needle); return p ? static_cast<int>(p - s) : -1; }
|
|
1899
|
+
helperFunctions: [`
|
|
1900
|
+
// TypeCAD string method polyfills (Zephyr, minimal-libc).
|
|
1901
|
+
#ifndef CUTTLEFISH_STR_BUF_SIZE
|
|
1902
|
+
#define CUTTLEFISH_STR_BUF_SIZE 64
|
|
1903
|
+
#endif
|
|
1904
|
+
bool __tc_endsWith(const char* s, const char* suffix) { int sl = strlen(s), tl = strlen(suffix); return sl >= tl && strcmp(s + sl - tl, suffix) == 0; }
|
|
1905
|
+
const char* __tc_toUpperCase(const char* s) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; strncpy(b, s, CUTTLEFISH_STR_BUF_SIZE - 1); b[CUTTLEFISH_STR_BUF_SIZE - 1] = '\\0'; for (char* p = b; *p; p++) { if (*p >= 'a' && *p <= 'z') { *p = static_cast<char>(*p - 32); } } return b; }
|
|
1906
|
+
const char* __tc_toLowerCase(const char* s) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; strncpy(b, s, CUTTLEFISH_STR_BUF_SIZE - 1); b[CUTTLEFISH_STR_BUF_SIZE - 1] = '\\0'; for (char* p = b; *p; p++) { if (*p >= 'A' && *p <= 'Z') { *p = static_cast<char>(*p + 32); } } return b; }
|
|
1907
|
+
const char* __tc_trim(const char* s) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; while (*s == ' ' || *s == '\\t' || *s == '\\n' || *s == '\\r') s++; int len = strlen(s); while (len > 0 && (s[len-1] == ' ' || s[len-1] == '\\t' || s[len-1] == '\\n' || s[len-1] == '\\r')) len--; int cplen = len < CUTTLEFISH_STR_BUF_SIZE - 1 ? len : CUTTLEFISH_STR_BUF_SIZE - 1; strncpy(b, s, cplen); b[cplen] = '\\0'; return b; }
|
|
1908
|
+
const char* __tc_substring2(const char* s, int start, int end) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; int slen = strlen(s); if (start < 0) start = 0; if (end > slen) end = slen; if (end < start) end = start; int len = end - start; if (len >= CUTTLEFISH_STR_BUF_SIZE) len = CUTTLEFISH_STR_BUF_SIZE - 1; strncpy(b, s + start, len); b[len] = '\\0'; return b; }
|
|
1909
|
+
const char* __tc_substring1(const char* s, int start) { return __tc_substring2(s, start, strlen(s)); }
|
|
1910
|
+
const char* __tc_slice2(const char* s, int start, int end) { return __tc_substring2(s, start, end); }
|
|
1911
|
+
const char* __tc_slice1(const char* s, int start) { return __tc_substring2(s, start, strlen(s)); }
|
|
1912
|
+
const char* __tc_replace(const char* s, const char* old, const char* repl) { static char buf[2][CUTTLEFISH_STR_BUF_SIZE]; static uint8_t slot = 0; slot ^= 1; char* b = buf[slot]; const char* pos = strstr(s, old); if (!pos) { strncpy(b, s, CUTTLEFISH_STR_BUF_SIZE - 1); b[CUTTLEFISH_STR_BUF_SIZE - 1] = '\\0'; return b; } int beforeLen = static_cast<int>(pos - s); int oldLen = static_cast<int>(strlen(old)); int replLen = static_cast<int>(strlen(repl)); if (beforeLen + replLen + static_cast<int>(strlen(pos + oldLen)) >= CUTTLEFISH_STR_BUF_SIZE) { strncpy(b, s, CUTTLEFISH_STR_BUF_SIZE - 1); b[CUTTLEFISH_STR_BUF_SIZE - 1] = '\\0'; return b; } memcpy(b, s, beforeLen); memcpy(b + beforeLen, repl, replLen); strcpy(b + beforeLen + replLen, pos + oldLen); return b; }
|
|
1913
|
+
const char* __tc_charAt(const char* s, int idx) { static char buf[2][2]; static uint8_t slot = 0; slot ^= 1; buf[slot][0] = s[idx]; buf[slot][1] = '\\0'; return buf[slot]; }
|
|
1914
|
+
int __tc_charCodeAt(const char* s, int idx) { return static_cast<int>(static_cast<unsigned char>(s[idx])); }
|
|
1915
|
+
int __tc_indexOf(const char* s, const char* needle) { const char* p = strstr(s, needle); return p ? static_cast<int>(p - s) : -1; }
|
|
1919
1916
|
`],
|
|
1920
1917
|
shimMacros: [],
|
|
1921
1918
|
dependencies: [],
|
|
@@ -1931,27 +1928,27 @@ int __tc_indexOf(const char* s, const char* needle) { const char* p = strstr(s,
|
|
|
1931
1928
|
requiredIncludes: [],
|
|
1932
1929
|
forwardDeclarations: [],
|
|
1933
1930
|
helperStructs: [],
|
|
1934
|
-
helperFunctions: [`
|
|
1935
|
-
#ifndef __TC_STATIC_ARRAY_DEFINED
|
|
1936
|
-
#define __TC_STATIC_ARRAY_DEFINED
|
|
1937
|
-
template<typename T, int N>
|
|
1938
|
-
struct __tc_StaticArray {
|
|
1939
|
-
T data[N];
|
|
1940
|
-
int _size;
|
|
1941
|
-
__tc_StaticArray() : _size(0) {}
|
|
1942
|
-
int length() const { return _size; }
|
|
1943
|
-
int size() const { return _size; }
|
|
1944
|
-
void push(T val) { if (_size < N) data[_size++] = val; }
|
|
1945
|
-
T pop() { return (_size > 0) ? data[--_size] : T(); }
|
|
1946
|
-
int indexOf(T val) const { for (int i = 0; i < _size; i++) if (data[i] == val) return i; return -1; }
|
|
1947
|
-
T& operator[](int i) { return data[i]; }
|
|
1948
|
-
const T& operator[](int i) const { return data[i]; }
|
|
1949
|
-
T* begin() { return &data[0]; }
|
|
1950
|
-
T* end() { return &data[_size]; }
|
|
1951
|
-
const T* begin() const { return &data[0]; }
|
|
1952
|
-
const T* end() const { return &data[_size]; }
|
|
1953
|
-
};
|
|
1954
|
-
#endif
|
|
1931
|
+
helperFunctions: [`
|
|
1932
|
+
#ifndef __TC_STATIC_ARRAY_DEFINED
|
|
1933
|
+
#define __TC_STATIC_ARRAY_DEFINED
|
|
1934
|
+
template<typename T, int N>
|
|
1935
|
+
struct __tc_StaticArray {
|
|
1936
|
+
T data[N];
|
|
1937
|
+
int _size;
|
|
1938
|
+
__tc_StaticArray() : _size(0) {}
|
|
1939
|
+
int length() const { return _size; }
|
|
1940
|
+
int size() const { return _size; }
|
|
1941
|
+
void push(T val) { if (_size < N) data[_size++] = val; }
|
|
1942
|
+
T pop() { return (_size > 0) ? data[--_size] : T(); }
|
|
1943
|
+
int indexOf(T val) const { for (int i = 0; i < _size; i++) if (data[i] == val) return i; return -1; }
|
|
1944
|
+
T& operator[](int i) { return data[i]; }
|
|
1945
|
+
const T& operator[](int i) const { return data[i]; }
|
|
1946
|
+
T* begin() { return &data[0]; }
|
|
1947
|
+
T* end() { return &data[_size]; }
|
|
1948
|
+
const T* begin() const { return &data[0]; }
|
|
1949
|
+
const T* end() const { return &data[_size]; }
|
|
1950
|
+
};
|
|
1951
|
+
#endif
|
|
1955
1952
|
`],
|
|
1956
1953
|
shimMacros: [],
|
|
1957
1954
|
dependencies: [],
|
|
@@ -2085,43 +2082,43 @@ struct __tc_StaticArray {
|
|
|
2085
2082
|
};
|
|
2086
2083
|
}
|
|
2087
2084
|
// ── Debug ─────────────────────────────────────────────────────────────────
|
|
2088
|
-
//
|
|
2089
|
-
//
|
|
2090
|
-
//
|
|
2091
|
-
//
|
|
2092
|
-
// halt emitted in shimLines. See src/debug-codegen.ts.
|
|
2093
|
-
//
|
|
2094
|
-
// Target-selective: targets with a debug probe get native GDB source-level
|
|
2095
|
-
// debugging (core emits #line markers + skips printf instrumentation); the
|
|
2096
|
-
// rest fall back to the printk instrumentation path. The ESP32-S3 has a
|
|
2097
|
-
// built-in USB-JTAG (single-cable GDB via OpenOCD) so it selects 'gdb'.
|
|
2098
|
-
// The XIAO nRF52840 needs its J-Link wired up; its GDB path is a follow-on,
|
|
2099
|
-
// so it stays on printf for now.
|
|
2085
|
+
// Source-level debugging is the GDB flow only (the west-owned gdb server
|
|
2086
|
+
// serves F5 via cortex-debug's external-server mode — see
|
|
2087
|
+
// toolchain/debug-config.ts). The printf/Serial breakpoint instrumentation
|
|
2088
|
+
// pipeline was removed from the product.
|
|
2100
2089
|
debugMode(target) {
|
|
2101
|
-
// `target` is the Zephyr board id (optionally with a /qualifier suffix
|
|
2102
|
-
//
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2090
|
+
// `target` is the Zephyr board id (optionally with a /qualifier suffix).
|
|
2091
|
+
// gdb capability is a FACT of the board: its probe-method table carries a
|
|
2092
|
+
// debug-capable entry (bootloaders mark debug:false; SWD/JTAG probes and
|
|
2093
|
+
// built-in USB-JTAG carry debug:true) — the same table west's runner
|
|
2094
|
+
// selection uses. Boards without a table (or unresolvable targets, e.g.
|
|
2095
|
+
// generated custom boards) report 'none', and --debug fails with an
|
|
2096
|
+
// explicit diagnostic (transpile.ts) rather than building silently.
|
|
2097
|
+
const t = (target ?? '').trim();
|
|
2098
|
+
if (!t)
|
|
2099
|
+
return 'none';
|
|
2100
|
+
const memo = debugModeMemo.get(t);
|
|
2101
|
+
if (memo)
|
|
2102
|
+
return memo;
|
|
2103
|
+
let mode = 'none';
|
|
2104
|
+
try {
|
|
2105
|
+
const g = generateBoard(t);
|
|
2106
|
+
const constants = JSON.parse(g.boardJson).constants;
|
|
2107
|
+
for (let i = 0;; i++) {
|
|
2108
|
+
const id = constants[`zephyr.probeMethods.${i}.id`];
|
|
2109
|
+
if (typeof id !== 'string')
|
|
2110
|
+
break;
|
|
2111
|
+
if (constants[`zephyr.probeMethods.${i}.debug`] !== false) {
|
|
2112
|
+
mode = 'gdb';
|
|
2113
|
+
break;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2106
2116
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
if (boardId.startsWith('blackpill_')) {
|
|
2111
|
-
return 'gdb';
|
|
2117
|
+
catch {
|
|
2118
|
+
// Board not resolvable from facts — 'none' (never crash codegen over
|
|
2119
|
+
// the debug-capability gate).
|
|
2112
2120
|
}
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
// probe + a different OpenOCD cfg/toolchain dir (deferred). Falls through.
|
|
2116
|
-
return 'printf';
|
|
2117
|
-
}
|
|
2118
|
-
generateDebugInitCode() {
|
|
2119
|
-
return generateZephyrInitCode();
|
|
2120
|
-
}
|
|
2121
|
-
generateDebugBreakpointCode(params) {
|
|
2122
|
-
return generateZephyrBreakpointCode(params.fileName, params.lineNum, params.originalLine, params.variables, params.normalizedCondition, params.breakpointId);
|
|
2123
|
-
}
|
|
2124
|
-
generateDebugLogpointCode(params) {
|
|
2125
|
-
return generateZephyrLogpointCode(params.fileName, params.lineNum, params.parts, params.variables);
|
|
2121
|
+
debugModeMemo.set(t, mode);
|
|
2122
|
+
return mode;
|
|
2126
2123
|
}
|
|
2127
2124
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
export function probe(opts) {
|
|
3
|
+
void opts;
|
|
4
|
+
const child = spawn('west', ['build'], {
|
|
5
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
6
|
+
...(process.platform !== 'win32' ? { detached: true } : {}),
|
|
7
|
+
});
|
|
8
|
+
child.on('exit', (code) => { void code; });
|
|
9
|
+
}
|