@typecad/cuttlefish 1.0.0-alpha.6 → 1.0.0-alpha.8
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/dist/api/config.d.ts +32 -0
- package/dist/api/index.d.ts +1 -1
- package/dist/api/schema/types.d.ts +15 -0
- package/dist/api/shared/async-runtime-static.d.ts +12 -1
- package/dist/api/shared/async-runtime-static.js +69 -24
- package/dist/api/shared/async-symbol-detector.d.ts +11 -0
- package/dist/api/shared/async-symbol-detector.js +140 -0
- package/dist/api/shared/async-types.d.ts +24 -0
- package/dist/api/shared/coop-scheduler.d.ts +60 -0
- package/dist/api/shared/coop-scheduler.js +149 -0
- package/dist/api/shared/display-adapter.d.ts +4 -3
- package/dist/api/shared/display-adapter.js +15 -118
- package/dist/api/shared/display-adapters/sdl.js +38 -31
- package/dist/api/shared/display-profile.d.ts +47 -25
- package/dist/api/shared/display-profile.js +31 -164
- package/dist/api/shared/framework-manifest-registry.d.ts +9 -0
- package/dist/api/shared/framework-manifest-registry.js +27 -0
- package/dist/api/shared/framework-manifest.d.ts +581 -0
- package/dist/api/shared/framework-manifest.js +182 -0
- package/dist/api/shared/glcdfont.d.ts +12 -0
- package/dist/api/shared/glcdfont.js +124 -0
- package/dist/api/shared/graphics-strategy.d.ts +37 -0
- package/dist/api/shared/hal-op-ir.d.ts +755 -1
- package/dist/api/shared/hal-op-ir.js +129 -1
- package/dist/api/shared/index.d.ts +20 -2
- package/dist/api/shared/index.js +25 -1
- package/dist/api/shared/ir-core.d.ts +4 -0
- package/dist/api/shared/ir-declarations.d.ts +6 -0
- package/dist/api/shared/native-display-op-resolver.d.ts +10 -0
- package/dist/api/shared/native-display-op-resolver.js +64 -0
- package/dist/api/shared/platform-strategy.d.ts +113 -2
- package/dist/api/shared/polyfill-helper-registry.js +18 -1
- package/dist/api/shared/promise-runtime.d.ts +1 -1
- package/dist/api/shared/promise-runtime.js +95 -13
- package/dist/api/shared/toolchain-types.d.ts +17 -0
- package/dist/api/shared/validate-framework-manifest.d.ts +28 -0
- package/dist/api/shared/validate-framework-manifest.js +494 -0
- package/dist/api/shared/worker-runtime-polyfill.d.ts +22 -0
- package/dist/api/shared/worker-runtime-polyfill.js +34 -0
- package/dist/api/shared/worker-runtime.d.ts +69 -0
- package/dist/api/shared/worker-runtime.js +163 -0
- package/dist/cli.js +186 -82
- package/dist/config-loader.d.ts +7 -2
- package/dist/config-loader.js +23 -3
- package/dist/config-schema.d.ts +112 -70
- package/dist/config-schema.js +14 -0
- package/dist/contract/board-generator.d.ts +17 -0
- package/dist/contract/board-generator.js +57 -0
- package/dist/contract/contract-parser.d.ts +217 -0
- package/dist/contract/contract-parser.js +224 -0
- package/dist/contract/index.d.ts +22 -0
- package/dist/contract/index.js +68 -0
- package/dist/create/board-codegen.js +4 -4
- package/dist/create/board-generators.js +4 -5
- package/dist/create/board-spec.d.ts +72 -75
- package/dist/create/board-spec.js +0 -1
- package/dist/create/init-scaffold.d.ts +9 -2
- package/dist/create/init-scaffold.js +0 -14
- package/dist/create/init-templates.d.ts +2 -0
- package/dist/create/init-templates.js +74 -8
- package/dist/create/init-wizard.js +31 -7
- package/dist/debug/preprocessor.js +178 -39
- package/dist/debug/types.d.ts +23 -0
- package/dist/diagnostics/mermaid-builder.d.ts +1 -1
- package/dist/diagnostics/mermaid-builder.js +34 -24
- package/dist/emit/compliance/arxml-writer.d.ts +11 -0
- package/dist/emit/compliance/arxml-writer.js +34 -0
- package/dist/emit/compliance/compliance-context.d.ts +57 -0
- package/dist/emit/compliance/compliance-context.js +113 -0
- package/dist/emit/compliance/deviation-ledger.d.ts +27 -0
- package/dist/emit/compliance/deviation-ledger.js +47 -0
- package/dist/emit/compliance/deviation-writer.d.ts +30 -0
- package/dist/emit/compliance/deviation-writer.js +37 -0
- package/dist/emit/compliance/index.d.ts +7 -0
- package/dist/emit/compliance/index.js +6 -0
- package/dist/emit/compliance/rule-engine.d.ts +13 -0
- package/dist/emit/compliance/rule-engine.js +101 -0
- package/dist/emit/compliance/rules.d.ts +16 -0
- package/dist/emit/compliance/rules.js +191 -0
- package/dist/emit/compliance/types.d.ts +59 -0
- package/dist/emit/compliance/types.js +8 -0
- package/dist/emit/cpp-emitter.js +4 -3
- package/dist/emit/emitters/class-emitter.js +6 -1
- package/dist/emit/emitters/emitter-context.d.ts +28 -1
- package/dist/emit/emitters/function-emitter-impl.js +153 -53
- package/dist/emit/emitters/line-appender.js +19 -0
- package/dist/emit/emitters/line-marker.d.ts +38 -0
- package/dist/emit/emitters/line-marker.js +39 -0
- package/dist/emit/emitters/output-finalizer.d.ts +6 -0
- package/dist/emit/emitters/output-finalizer.js +101 -12
- package/dist/emit/emitters/setup.d.ts +17 -0
- package/dist/emit/emitters/setup.js +257 -36
- package/dist/emit/emitters/top-level-prep.js +8 -0
- package/dist/emit/emitters/type-decl-emitter.js +28 -3
- package/dist/emit/emitters/ui-emitter.js +33 -9
- package/dist/emit/expression-renderer.d.ts +1 -1
- package/dist/emit/expression-renderer.js +91 -6
- package/dist/emit/route-hal-op.js +18 -5
- package/dist/emit/snprintf-helpers.js +15 -4
- package/dist/emit/statement-renderer.d.ts +10 -0
- package/dist/emit/statement-renderer.js +34 -5
- package/dist/emit/utils/async-state-machine.js +221 -125
- package/dist/emit/utils/hal-op-cpp-type.d.ts +6 -0
- package/dist/emit/utils/hal-op-cpp-type.js +40 -0
- package/dist/framework-package.js +2 -0
- package/dist/framework-registry.d.ts +17 -0
- package/dist/ir/adc-range-validation.js +14 -1
- package/dist/ir/build-ir-state.d.ts +1 -0
- package/dist/ir/build-ir-state.js +14 -0
- package/dist/ir/build-ir.js +9 -5
- package/dist/ir/call-graph.js +16 -0
- package/dist/ir/expression-to-ir.js +164 -0
- package/dist/ir/feature-registry.js +7 -25
- package/dist/ir/function-builder.js +22 -0
- package/dist/ir/hal/hal-emitter.d.ts +5 -2
- package/dist/ir/hal/hal-emitter.js +50 -18
- package/dist/ir/hal/hal-parser.d.ts +6 -0
- package/dist/ir/hal/hal-parser.js +81 -0
- package/dist/ir/hal/hal-plugins.js +723 -1
- package/dist/ir/identifier-collector.js +35 -0
- package/dist/ir/interrupt-analysis.d.ts +5 -1
- package/dist/ir/interrupt-analysis.js +8 -16
- package/dist/ir/network-validation.d.ts +4 -0
- package/dist/ir/network-validation.js +184 -0
- package/dist/ir/ownership-analysis.js +20 -1
- package/dist/ir/pin-capability-validation.js +37 -0
- package/dist/ir/pin-mode-validation.d.ts +2 -2
- package/dist/ir/pin-mode-validation.js +49 -18
- package/dist/ir/program-analysis.d.ts +65 -0
- package/dist/ir/program-analysis.js +318 -2
- package/dist/ir/render-expr.js +11 -0
- package/dist/ir/timing-validation.d.ts +6 -1
- package/dist/ir/timing-validation.js +60 -13
- package/dist/ir/transformers/call-statement.js +105 -0
- package/dist/ir/transformers/expressions.js +62 -0
- package/dist/ir/transformers/hal-call-resolver.js +21 -0
- package/dist/ir/transformers/hal-emit-helpers.js +1 -1
- package/dist/ir/transformers/namespace-methods.js +17 -12
- package/dist/ir/transformers/ui-reactive.js +2 -2
- package/dist/ir/transformers/variables.js +92 -3
- package/dist/ir/type-resolution.js +18 -0
- package/dist/ir/ui-element-auto-wire.js +7 -5
- package/dist/ir/utils/map-statements.d.ts +4 -0
- package/dist/ir/utils/map-statements.js +79 -0
- package/dist/ir/validation-orchestrator.js +9 -2
- package/dist/ir/worker-analysis.d.ts +10 -0
- package/dist/ir/worker-analysis.js +261 -0
- package/dist/libdef/c-to-decl.d.ts +27 -0
- package/dist/libdef/c-to-decl.js +397 -0
- package/dist/libdef/component-decls.d.ts +2 -0
- package/dist/libdef/component-decls.js +6 -0
- package/dist/libdef/component-discovery.d.ts +43 -0
- package/dist/libdef/component-discovery.js +83 -0
- package/dist/libdef/cpp-to-decl.d.ts +9 -0
- package/dist/libdef/cpp-to-decl.js +72 -0
- package/dist/libdef/registry.js +5 -2
- package/dist/lint-cache.d.ts +59 -0
- package/dist/lint-cache.js +257 -0
- package/dist/orchestrator/graph-builder.js +14 -9
- package/dist/platform/coop-scheduler-runtime.d.ts +19 -0
- package/dist/platform/coop-scheduler-runtime.js +41 -0
- package/dist/platform/generic-strategy.d.ts +15 -3
- package/dist/platform/generic-strategy.js +49 -4
- package/dist/safety/safety-bridge.d.ts +11 -0
- package/dist/safety/safety-bridge.js +48 -0
- package/dist/safety/sidecar-bridge.d.ts +5 -0
- package/dist/safety/sidecar-bridge.js +22 -0
- package/dist/safety-hook.d.ts +79 -0
- package/dist/safety-hook.js +35 -0
- package/dist/testing.d.ts +7 -1
- package/dist/testing.js +8 -1
- package/dist/transpile.d.ts +3 -0
- package/dist/transpile.js +175 -41
- package/dist/types.d.ts +13 -2
- package/dist/ui-hook.d.ts +17 -3
- package/dist/utils/cli.js +78 -4
- package/dist/utils/fs.d.ts +13 -0
- package/dist/utils/fs.js +50 -0
- package/package.json +24 -5
- package/dist/api/shared/display-adapters/eink-mono.d.ts +0 -2
- package/dist/api/shared/display-adapters/eink-mono.js +0 -53
- package/dist/api/shared/display-adapters/ssd1309.d.ts +0 -2
- package/dist/api/shared/display-adapters/ssd1309.js +0 -136
- package/dist/api/shared/display-adapters/st7796.d.ts +0 -2
- package/dist/api/shared/display-adapters/st7796.js +0 -132
- package/dist/licenses.d.ts +0 -185
- package/dist/licenses.js +0 -963
|
@@ -423,6 +423,22 @@ function collectHALOpIdentifiers(op) {
|
|
|
423
423
|
// handler is a resolved C++ function name (e.g. "myIsr" or a placeholder)
|
|
424
424
|
identifiers.add(op.handler);
|
|
425
425
|
break;
|
|
426
|
+
case "mqtt.on_message":
|
|
427
|
+
// handler is the user's onMessage callback name (callback() resolves it to
|
|
428
|
+
// a string). Without this the tree-shaker drops the function declaration —
|
|
429
|
+
// the mqtt.on_message op only carries the name, so the function has no
|
|
430
|
+
// other reference and looks unreachable. Same shape as interrupt.attach.
|
|
431
|
+
identifiers.add(op.handler);
|
|
432
|
+
break;
|
|
433
|
+
case "wifi.on_event":
|
|
434
|
+
identifiers.add(op.handler);
|
|
435
|
+
break;
|
|
436
|
+
case "ble.on_read":
|
|
437
|
+
case "ble.on_write":
|
|
438
|
+
case "ble.on_connect":
|
|
439
|
+
case "ble.on_disconnect":
|
|
440
|
+
identifiers.add(op.handler);
|
|
441
|
+
break;
|
|
426
442
|
case "raw": {
|
|
427
443
|
// Raw C++ code may reference user-defined identifiers
|
|
428
444
|
const matches = op.code.match(/[A-Za-z_][A-Za-z0-9_]*/g);
|
|
@@ -435,5 +451,24 @@ function collectHALOpIdentifiers(op) {
|
|
|
435
451
|
}
|
|
436
452
|
// Other HAL ops have only numeric/literal fields — no identifier references
|
|
437
453
|
}
|
|
454
|
+
// wifi.* / http.* / mqtt.* ops carry resolved C++ expression texts in their
|
|
455
|
+
// string fields (e.g. wifi.connect ssid: `WIFI_SSID` — a top-level const, or
|
|
456
|
+
// a quoted literal). Scan every string field for identifiers so referenced
|
|
457
|
+
// globals survive tree-shaking; quoted literals are skipped.
|
|
458
|
+
if (op.operation.startsWith("wifi.") || op.operation.startsWith("http.")
|
|
459
|
+
|| op.operation.startsWith("mqtt.")) {
|
|
460
|
+
for (const value of Object.values(op)) {
|
|
461
|
+
if (typeof value !== "string" || value === op.operation)
|
|
462
|
+
continue;
|
|
463
|
+
if (/^".*"$/.test(value.trim()))
|
|
464
|
+
continue;
|
|
465
|
+
const matches = value.match(/[A-Za-z_][A-Za-z0-9_]*/g);
|
|
466
|
+
if (matches) {
|
|
467
|
+
for (const match of matches) {
|
|
468
|
+
identifiers.add(match);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
438
473
|
return identifiers;
|
|
439
474
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ProgramIR } from '../api/index.js';
|
|
1
|
+
import type { ProgramIR, StatementIR } from '../api/index.js';
|
|
2
2
|
import type { PeripheralUsage } from './peripheral-usage.js';
|
|
3
3
|
import type { Diagnostic } from '../types.js';
|
|
4
4
|
export { walkNestedStatements as scanNestedStatements } from './utils/walk-ir.js';
|
|
@@ -24,6 +24,10 @@ export interface InterruptHandlerInfo {
|
|
|
24
24
|
* @returns Array of diagnostics for interrupt-related issues
|
|
25
25
|
*/
|
|
26
26
|
export declare function analyzeInterruptSafety(program: ProgramIR, usage: PeripheralUsage, isrUnsafeOps?: Map<string, IsrUnsafeOp>): Diagnostic[];
|
|
27
|
+
/** Collect variable names assigned (written) within a statement body. */
|
|
28
|
+
export declare function collectAssignedNames(stmts: readonly StatementIR[], names: Set<string>): void;
|
|
29
|
+
/** Collect variable names read (referenced) within a statement body. */
|
|
30
|
+
export declare function collectReadNames(stmts: readonly StatementIR[], names: Set<string>): void;
|
|
27
31
|
/**
|
|
28
32
|
* Infer `volatile` for global variables shared between ISR callbacks and main
|
|
29
33
|
* code. Mutates the IR (sets isVolatile=true on qualifying var_decls) and
|
|
@@ -7,21 +7,13 @@
|
|
|
7
7
|
import { walkNestedStatements, walkExpressionsInExpression } from './utils/walk-ir.js';
|
|
8
8
|
export { walkNestedStatements as scanNestedStatements } from './utils/walk-ir.js';
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Fallback ISR-unsafe operations used when no platform-specific map is provided.
|
|
11
|
+
* Empty by design — the Wiring-derived specifics (delay, Serial.*, I2C*, SPI*)
|
|
12
|
+
* live in ArduinoStrategy.isrUnsafeOperations(). A generic target has no known
|
|
13
|
+
* ISR-unsafe surface. The orchestrator passes the loaded framework's map; this
|
|
14
|
+
* default only applies when none is supplied.
|
|
12
15
|
*/
|
|
13
|
-
const DEFAULT_ISR_UNSAFE_OPERATIONS = new Map(
|
|
14
|
-
['delay', { reason: 'delay() blocks the CPU and should not be used in interrupt context', severity: 'warning' }],
|
|
15
|
-
['delayMicroseconds', { reason: 'delayMicroseconds() blocks and should be avoided in ISRs', severity: 'warning' }],
|
|
16
|
-
['Serial.print', { reason: 'Serial.print() may not work correctly in interrupt context', severity: 'info' }],
|
|
17
|
-
['Serial.println', { reason: 'Serial.println() may not work correctly in interrupt context', severity: 'info' }],
|
|
18
|
-
['Serial.write', { reason: 'Serial.write() may not work correctly in interrupt context', severity: 'info' }],
|
|
19
|
-
['Serial.read', { reason: 'Serial.read() may not work correctly in interrupt context', severity: 'info' }],
|
|
20
|
-
['I2C0', { reason: 'I2C operations can cause lockups in interrupt context', severity: 'warning' }],
|
|
21
|
-
['I2C1', { reason: 'I2C operations can cause lockups in interrupt context', severity: 'warning' }],
|
|
22
|
-
['SPI0', { reason: 'SPI operations may cause issues in interrupt context', severity: 'info' }],
|
|
23
|
-
['SPI1', { reason: 'SPI operations may cause issues in interrupt context', severity: 'info' }],
|
|
24
|
-
]);
|
|
16
|
+
const DEFAULT_ISR_UNSAFE_OPERATIONS = new Map();
|
|
25
17
|
/**
|
|
26
18
|
* Analyze a program for interrupt handler issues.
|
|
27
19
|
*
|
|
@@ -243,7 +235,7 @@ function scanExpressionForCallbacks(expr, callback, parentExpr) {
|
|
|
243
235
|
// emission path already handles isVolatile (statement-renderer.ts).
|
|
244
236
|
// ---------------------------------------------------------------------------
|
|
245
237
|
/** Collect variable names assigned (written) within a statement body. */
|
|
246
|
-
function collectAssignedNames(stmts, names) {
|
|
238
|
+
export function collectAssignedNames(stmts, names) {
|
|
247
239
|
for (const stmt of stmts) {
|
|
248
240
|
const s = stmt;
|
|
249
241
|
if (stmt.kind === 'assign') {
|
|
@@ -265,7 +257,7 @@ function collectAssignedNames(stmts, names) {
|
|
|
265
257
|
}
|
|
266
258
|
}
|
|
267
259
|
/** Collect variable names read (referenced) within a statement body. */
|
|
268
|
-
function collectReadNames(stmts, names) {
|
|
260
|
+
export function collectReadNames(stmts, names) {
|
|
269
261
|
for (const stmt of stmts) {
|
|
270
262
|
walkExpressionsInStatement(stmt, (expr) => {
|
|
271
263
|
if (expr.kind === 'identifier' && typeof expr.value === 'string') {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ProgramIR } from "../api/index.js";
|
|
2
|
+
import type { Diagnostic } from "../types.js";
|
|
3
|
+
import type { BoardConstants } from "./board-resolver.js";
|
|
4
|
+
export declare function validateNetworkUsage(program: ProgramIR, boardConstants?: BoardConstants): Diagnostic[];
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Network (WiFi / HTTP) Validation
|
|
3
|
+
//
|
|
4
|
+
// Board-aware, compile-time checks for the WiFi/HTTP HAL:
|
|
5
|
+
//
|
|
6
|
+
// wifi-no-radio (error) wifi.*/http.* used on a board whose
|
|
7
|
+
// architecture has no WiFi radio (avr).
|
|
8
|
+
// http-without-wifi (warning) http.* used but the program never
|
|
9
|
+
// brings a WiFi link up (connect /
|
|
10
|
+
// connectSaved / connectAsync / AP).
|
|
11
|
+
// wifi-blocking-in-loop (warning) blocking WiFi.connect()/scan() or
|
|
12
|
+
// Http send inside loop() — stalls every
|
|
13
|
+
// iteration; use async/await instead.
|
|
14
|
+
// wifi-ap-password-short (error) WiFi.startAP() with a literal WPA2
|
|
15
|
+
// password shorter than 8 characters —
|
|
16
|
+
// esp_wifi rejects it at runtime.
|
|
17
|
+
// http-max-body-large (warning) Http maxBody() above 64 KB — the
|
|
18
|
+
// response buffer is heap-allocated.
|
|
19
|
+
//
|
|
20
|
+
// Follows the ADC-validation convention: checks that need board data return
|
|
21
|
+
// nothing when the data is missing (no MCU-name fallbacks).
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
import { walkProgramIR, walkNestedStatements } from "./utils/walk-ir.js";
|
|
24
|
+
/** Architectures with no WiFi radio. Driven by the `architecture` board
|
|
25
|
+
* constant (from the MCU package); absent data emits nothing. */
|
|
26
|
+
const NO_RADIO_ARCHITECTURES = new Set(["avr"]);
|
|
27
|
+
/** Ops that bring the WiFi link (STA or AP) up. */
|
|
28
|
+
const LINK_UP_OPS = new Set([
|
|
29
|
+
"wifi.connect",
|
|
30
|
+
"wifi.connect_start",
|
|
31
|
+
"wifi.connect_saved",
|
|
32
|
+
"wifi.ap_start",
|
|
33
|
+
]);
|
|
34
|
+
/** Blocking waits that stall loop() for their full duration. */
|
|
35
|
+
const BLOCKING_LOOP_OPS = new Set([
|
|
36
|
+
"wifi.connect",
|
|
37
|
+
"wifi.connect_saved",
|
|
38
|
+
"wifi.wait_connected",
|
|
39
|
+
"wifi.wait_disconnected",
|
|
40
|
+
"wifi.scan",
|
|
41
|
+
"http.send",
|
|
42
|
+
]);
|
|
43
|
+
/** Strip surrounding quotes from a resolved HAL string field; returns null
|
|
44
|
+
* when the field is not a literal (identifier/expression — unknowable). */
|
|
45
|
+
function literalString(value) {
|
|
46
|
+
if (typeof value !== "string")
|
|
47
|
+
return null;
|
|
48
|
+
const trimmed = value.trim();
|
|
49
|
+
const match = trimmed.match(/^"((?:[^"\\]|\\.)*)"$/);
|
|
50
|
+
return match ? match[1] : null;
|
|
51
|
+
}
|
|
52
|
+
function diagAt(stmt, partial) {
|
|
53
|
+
const s = stmt;
|
|
54
|
+
return {
|
|
55
|
+
...partial,
|
|
56
|
+
line: s.sourceSpan?.startLine,
|
|
57
|
+
column: s.sourceSpan?.startColumn,
|
|
58
|
+
filePath: s.sourceSpan?.filePath,
|
|
59
|
+
source: "network-validation",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Pull every wifi./http. op out of a statement: hal-op statements, awaited
|
|
63
|
+
* __WIFI_WAIT__/__HTTP_WAIT__ marker calls (hal-expr arg), and hal-expr
|
|
64
|
+
* expressions in call args / initializers / conditions. */
|
|
65
|
+
function collectNetworkOps(stmt, out) {
|
|
66
|
+
const s = stmt;
|
|
67
|
+
const record = (op) => {
|
|
68
|
+
const operation = op?.operation;
|
|
69
|
+
if (typeof operation === "string" && (operation.startsWith("wifi.") || operation.startsWith("http."))) {
|
|
70
|
+
out.push({ op: op, stmt });
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
if (stmt.kind === "hal-op")
|
|
74
|
+
record(s.operation);
|
|
75
|
+
const visitExpr = (expr) => {
|
|
76
|
+
if (!expr || typeof expr !== "object")
|
|
77
|
+
return;
|
|
78
|
+
const e = expr;
|
|
79
|
+
if (e.kind === "hal-expr")
|
|
80
|
+
record(e.operation);
|
|
81
|
+
for (const key of ["args", "elements", "parts"]) {
|
|
82
|
+
if (Array.isArray(e[key]))
|
|
83
|
+
for (const child of e[key])
|
|
84
|
+
visitExpr(child);
|
|
85
|
+
}
|
|
86
|
+
for (const key of ["left", "right", "operand", "condition", "whenTrue", "whenFalse", "inner", "value", "expression"]) {
|
|
87
|
+
if (e[key] && typeof e[key] === "object")
|
|
88
|
+
visitExpr(e[key]);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
for (const key of ["args", "value", "condition", "initializer", "expression"]) {
|
|
92
|
+
if (s[key]) {
|
|
93
|
+
if (Array.isArray(s[key]))
|
|
94
|
+
for (const child of s[key])
|
|
95
|
+
visitExpr(child);
|
|
96
|
+
else
|
|
97
|
+
visitExpr(s[key]);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function validateNetworkUsage(program, boardConstants) {
|
|
102
|
+
const diagnostics = [];
|
|
103
|
+
const constants = boardConstants ?? program.boardConstants;
|
|
104
|
+
// Collect every wifi./http. op in the program.
|
|
105
|
+
const allOps = [];
|
|
106
|
+
walkProgramIR(program, (stmt) => collectNetworkOps(stmt, allOps));
|
|
107
|
+
if (allOps.length === 0)
|
|
108
|
+
return diagnostics;
|
|
109
|
+
const wifiOps = allOps.filter(({ op }) => op.operation.startsWith("wifi."));
|
|
110
|
+
const httpOps = allOps.filter(({ op }) => op.operation.startsWith("http."));
|
|
111
|
+
// ── wifi-no-radio ────────────────────────────────────────────────────────
|
|
112
|
+
const architecture = constants?.get("architecture");
|
|
113
|
+
const archName = typeof architecture === "string" ? architecture.replace(/^["']|["']$/g, "").toLowerCase() : null;
|
|
114
|
+
if (archName && NO_RADIO_ARCHITECTURES.has(archName)) {
|
|
115
|
+
const first = allOps[0];
|
|
116
|
+
diagnostics.push(diagAt(first.stmt, {
|
|
117
|
+
severity: "error",
|
|
118
|
+
code: "wifi-no-radio",
|
|
119
|
+
message: `WiFi/HTTP APIs are used but the target board's architecture ('${archName}') has no WiFi radio.`,
|
|
120
|
+
hint: "Target a WiFi-capable board (e.g. @typecad/board-esp32-devkit) or remove the WiFi/HTTP calls.",
|
|
121
|
+
}));
|
|
122
|
+
// No point piling on the remaining checks for a board that can't radio.
|
|
123
|
+
return diagnostics;
|
|
124
|
+
}
|
|
125
|
+
// ── http-without-wifi ────────────────────────────────────────────────────
|
|
126
|
+
if (httpOps.length > 0 && !wifiOps.some(({ op }) => LINK_UP_OPS.has(op.operation))) {
|
|
127
|
+
diagnostics.push(diagAt(httpOps[0].stmt, {
|
|
128
|
+
severity: "warning",
|
|
129
|
+
code: "http-without-wifi",
|
|
130
|
+
message: "HTTP requests are made but the program never brings the WiFi link up — every request will fail at runtime.",
|
|
131
|
+
hint: "Call WiFi.connect(ssid, password) (or WiFi.connectSaved() / WiFi.startAP()) before sending HTTP requests.",
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
// ── wifi-blocking-in-loop ────────────────────────────────────────────────
|
|
135
|
+
// Blocking hal-op statements inside loop()'s body stall every iteration.
|
|
136
|
+
// Awaited forms are rewritten to __WIFI_WAIT__/__HTTP_WAIT__ marker calls
|
|
137
|
+
// (kind "call"), so only genuine blocking hal-ops are flagged here.
|
|
138
|
+
const loopFn = program.functions.find((fn) => fn.originalName === "loop");
|
|
139
|
+
if (loopFn?.statements) {
|
|
140
|
+
const visit = (stmt) => {
|
|
141
|
+
if (stmt.kind === "hal-op" && BLOCKING_LOOP_OPS.has(stmt.operation?.operation)) {
|
|
142
|
+
const opName = stmt.operation.operation;
|
|
143
|
+
diagnostics.push(diagAt(stmt, {
|
|
144
|
+
severity: "warning",
|
|
145
|
+
code: "wifi-blocking-in-loop",
|
|
146
|
+
message: `Blocking network operation '${opName}' inside loop() stalls every iteration until it completes (seconds for a connect/scan/request).`,
|
|
147
|
+
hint: "Move the call into an async function and `await` it — the transpiler lowers awaited WiFi/HTTP calls to non-blocking start + poll states.",
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
walkNestedStatements(stmt, visit);
|
|
151
|
+
};
|
|
152
|
+
for (const stmt of loopFn.statements)
|
|
153
|
+
visit(stmt);
|
|
154
|
+
}
|
|
155
|
+
// ── wifi-ap-password-short ───────────────────────────────────────────────
|
|
156
|
+
for (const { op, stmt } of wifiOps) {
|
|
157
|
+
if (op.operation !== "wifi.ap_start")
|
|
158
|
+
continue;
|
|
159
|
+
const password = literalString(op.password);
|
|
160
|
+
if (password !== null && password.length > 0 && password.length < 8) {
|
|
161
|
+
diagnostics.push(diagAt(stmt, {
|
|
162
|
+
severity: "error",
|
|
163
|
+
code: "wifi-ap-password-short",
|
|
164
|
+
message: `WiFi.startAP() password is ${password.length} characters — WPA2 requires at least 8, and esp_wifi rejects shorter ones at runtime.`,
|
|
165
|
+
hint: "Use a password of 8+ characters, or omit the password entirely for an open access point.",
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// ── http-max-body-large ──────────────────────────────────────────────────
|
|
170
|
+
for (const { op, stmt } of httpOps) {
|
|
171
|
+
if (op.operation !== "http.set_max_body")
|
|
172
|
+
continue;
|
|
173
|
+
const bytes = Number(String(op.bytes).trim());
|
|
174
|
+
if (Number.isFinite(bytes) && bytes > 65536) {
|
|
175
|
+
diagnostics.push(diagAt(stmt, {
|
|
176
|
+
severity: "warning",
|
|
177
|
+
code: "http-max-body-large",
|
|
178
|
+
message: `Http maxBody(${bytes}) heap-allocates a ${Math.round(bytes / 1024)} KB response buffer — large buffers risk allocation failure under fragmentation.`,
|
|
179
|
+
hint: "Keep the response cap at or below 64 KB, or process large payloads in chunks server-side.",
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return diagnostics;
|
|
184
|
+
}
|
|
@@ -765,6 +765,12 @@ function analyzeExpression(expr, scope, diagnostics, fallbackSpan) {
|
|
|
765
765
|
analyzeExpression(expr.inner, scope, diagnostics, span);
|
|
766
766
|
break;
|
|
767
767
|
}
|
|
768
|
+
case 'call': {
|
|
769
|
+
for (const arg of expr.args) {
|
|
770
|
+
analyzeExpression(arg, scope, diagnostics, span);
|
|
771
|
+
}
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
768
774
|
case 'number':
|
|
769
775
|
case 'string':
|
|
770
776
|
case 'boolean':
|
|
@@ -983,7 +989,20 @@ function validateConstSuggestions(program, diagnostics) {
|
|
|
983
989
|
// keep the binding non-const so push_back/splice/etc. compile. The
|
|
984
990
|
// callee is the lowered C++ name, e.g. "arr.push_back".
|
|
985
991
|
if (stmt.kind === 'call' && typeof stmt.callee === 'string') {
|
|
986
|
-
|
|
992
|
+
// Value-arg array methods (.push/.pop/.fill/...) are lowered in
|
|
993
|
+
// call-statement.ts to a fully-formed raw C++ expression wrapped as
|
|
994
|
+
// `__RAW_STMT__<receiver>.<method>(<args>)` (e.g. `__RAW_STMT__arr.push_back(1)`).
|
|
995
|
+
// Strip the wrapper — and the trailing `(args)` when present — before
|
|
996
|
+
// splitting, otherwise the dot parse yields a receiver of
|
|
997
|
+
// `__RAW_STMT__arr` and a method of `push_back(1)` and the demotion
|
|
998
|
+
// below never fires, leaving a non-compiling `const std::vector` +
|
|
999
|
+
// push_back. Mirrors the __RAW_STMT__ handling in program-analysis.ts.
|
|
1000
|
+
const rawCallee = stmt.callee;
|
|
1001
|
+
const unwrapped = rawCallee.startsWith('__RAW_STMT__')
|
|
1002
|
+
? rawCallee.slice('__RAW_STMT__'.length)
|
|
1003
|
+
: rawCallee;
|
|
1004
|
+
const parenIdx = unwrapped.indexOf('(');
|
|
1005
|
+
const callee = parenIdx > 0 ? unwrapped.slice(0, parenIdx) : unwrapped;
|
|
987
1006
|
const dot = callee.lastIndexOf('.');
|
|
988
1007
|
if (dot > 0) {
|
|
989
1008
|
const receiver = callee.slice(0, dot);
|
|
@@ -77,6 +77,35 @@ function findPinsWithCapability(capability, boardConstants) {
|
|
|
77
77
|
}
|
|
78
78
|
return result;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Does the board declare ANY per-pin `type:'pwm'` function entry anywhere?
|
|
82
|
+
*
|
|
83
|
+
* AVR-family boards (atmega328p, etc.) hardwire PWM to specific timer-output
|
|
84
|
+
* pins, so their MCU descriptors list `{ type:'pwm', ... }` per pin and the
|
|
85
|
+
* capability check correctly rejects PWM on non-timer pins. ESP32-family
|
|
86
|
+
* boards route LEDC to ANY output GPIO via the GPIO matrix, so their MCU
|
|
87
|
+
* descriptors carry zero `type:'pwm'` entries — PWM is a board-wide property
|
|
88
|
+
* (the `pins.pwm` collection), not a per-pin function. On such boards the
|
|
89
|
+
* per-pin capability check would false-positive on every pin, so the caller
|
|
90
|
+
* skips it when this returns false. This distinguishes the two families
|
|
91
|
+
* cleanly (AVR has entries, ESP32 has none) without special-casing arch names.
|
|
92
|
+
*/
|
|
93
|
+
function boardHasAnyPwmFunctionEntries(boardConstants) {
|
|
94
|
+
if (!boardConstants)
|
|
95
|
+
return false;
|
|
96
|
+
for (let i = 0; i < 100; i++) {
|
|
97
|
+
if (boardConstants.get(`pins.all.${i}.name`) === undefined)
|
|
98
|
+
continue;
|
|
99
|
+
for (let j = 0; j < 10; j++) {
|
|
100
|
+
const type = boardConstants.get(`pins.all.${i}.functions.${j}.type`);
|
|
101
|
+
if (type === undefined)
|
|
102
|
+
break;
|
|
103
|
+
if (String(type) === 'pwm')
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
80
109
|
// ---------------------------------------------------------------------------
|
|
81
110
|
// Capability check for a single HAL operation
|
|
82
111
|
// ---------------------------------------------------------------------------
|
|
@@ -88,6 +117,13 @@ function checkCapability(operation, sourceLine, sourceCol, filePath, boardConsta
|
|
|
88
117
|
const capability = operationToCapability(op);
|
|
89
118
|
if (!capability)
|
|
90
119
|
return; // GPIO/timing — always available.
|
|
120
|
+
// ESP32-family boards route PWM (LEDC) to any output GPIO via the GPIO
|
|
121
|
+
// matrix, so they carry zero per-pin `type:'pwm'` entries (unlike AVR,
|
|
122
|
+
// which hardwires PWM to timer-output pins). On such boards the per-pin PWM
|
|
123
|
+
// capability check would reject every pin; skip it and let the framework's
|
|
124
|
+
// LEDC driver handle routing. This does NOT weaken AVR, which has entries.
|
|
125
|
+
if (capability === 'pwm' && !boardHasAnyPwmFunctionEntries(boardConstants))
|
|
126
|
+
return;
|
|
91
127
|
const pin = operation.pin;
|
|
92
128
|
if (typeof pin !== 'number' || pin < 0)
|
|
93
129
|
return;
|
|
@@ -250,6 +286,7 @@ function scanExpression(expr, boardConstants, parentLine, parentCol, parentFileP
|
|
|
250
286
|
case 'identifier':
|
|
251
287
|
case 'raw':
|
|
252
288
|
case 'tuple-access':
|
|
289
|
+
case 'call':
|
|
253
290
|
break;
|
|
254
291
|
default:
|
|
255
292
|
assertNever(expr);
|
|
@@ -4,7 +4,7 @@ import type { Diagnostic } from '../types.js';
|
|
|
4
4
|
* Validate that GPIO I/O operations are preceded by mode configuration.
|
|
5
5
|
*
|
|
6
6
|
* - Read without prior mode → **warning** (undefined behavior on floating pin)
|
|
7
|
-
* - Write without prior mode → **info** (
|
|
8
|
-
* explicit configuration is recommended)
|
|
7
|
+
* - Write without prior mode → **info** (Wiring-derived frameworks implicitly
|
|
8
|
+
* set OUTPUT, but explicit configuration is recommended)
|
|
9
9
|
*/
|
|
10
10
|
export declare function validatePinModeConfig(program: ProgramIR): Diagnostic[];
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// configuration. Generates warnings for reads and info for writes.
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
import { scanNestedStatements } from './interrupt-analysis.js';
|
|
8
|
+
import { hasLoadedFramework, getLoadedFramework } from '../framework-registry.js';
|
|
8
9
|
/** Methods that configure pin mode. */
|
|
9
10
|
const MODE_SET_METHODS = new Set([
|
|
10
11
|
'inputPullUp', 'inputPullDown', 'outputOpenDrain',
|
|
@@ -14,7 +15,7 @@ const MODE_SET_METHODS = new Set([
|
|
|
14
15
|
const READ_METHODS = new Set([
|
|
15
16
|
'read', 'isHigh', 'isLow', 'readAnalog', 'readVoltage',
|
|
16
17
|
]);
|
|
17
|
-
/** Write operations that implicitly set OUTPUT mode on
|
|
18
|
+
/** Write operations that implicitly set OUTPUT mode on Wiring-derived frameworks. */
|
|
18
19
|
const WRITE_METHODS = new Set([
|
|
19
20
|
'write', 'high', 'low', 'toggle', 'pulse', 'pwm', 'tone',
|
|
20
21
|
]);
|
|
@@ -26,8 +27,8 @@ const PIN_RECEIVER_KINDS = new Set([
|
|
|
26
27
|
* Validate that GPIO I/O operations are preceded by mode configuration.
|
|
27
28
|
*
|
|
28
29
|
* - Read without prior mode → **warning** (undefined behavior on floating pin)
|
|
29
|
-
* - Write without prior mode → **info** (
|
|
30
|
-
* explicit configuration is recommended)
|
|
30
|
+
* - Write without prior mode → **info** (Wiring-derived frameworks implicitly
|
|
31
|
+
* set OUTPUT, but explicit configuration is recommended)
|
|
31
32
|
*/
|
|
32
33
|
export function validatePinModeConfig(program) {
|
|
33
34
|
const diagnostics = [];
|
|
@@ -65,7 +66,7 @@ export function validatePinModeConfig(program) {
|
|
|
65
66
|
diagnostics.push({
|
|
66
67
|
severity: 'info',
|
|
67
68
|
message: `Pin '${receiver}' written via '${method}()' without explicit mode configuration. ` +
|
|
68
|
-
`
|
|
69
|
+
`The target framework implicitly sets OUTPUT, but explicit ${receiver}.asOutput() is recommended.`,
|
|
69
70
|
filePath: program.fileName,
|
|
70
71
|
code: 'pin-mode-not-set',
|
|
71
72
|
source: 'pin-mode-validation',
|
|
@@ -112,7 +113,7 @@ export function validatePinModeConfig(program) {
|
|
|
112
113
|
diagnostics.push({
|
|
113
114
|
severity: 'info',
|
|
114
115
|
message: `Pin ${op.pin} written without explicit mode configuration. ` +
|
|
115
|
-
`
|
|
116
|
+
`The target framework implicitly sets OUTPUT, but explicit asOutput() is recommended.`,
|
|
116
117
|
filePath: program.fileName,
|
|
117
118
|
code: 'pin-mode-not-set',
|
|
118
119
|
source: 'pin-mode-validation',
|
|
@@ -148,21 +149,51 @@ export function validatePinModeConfig(program) {
|
|
|
148
149
|
// Raw nodes: after full HAL resolution, some pin ops land as their C++ text
|
|
149
150
|
// (e.g. `digitalRead(2)`, `digitalWrite(2, 1)`) rather than structured
|
|
150
151
|
// hal-expr nodes. Extract the pin number and apply the same mode check.
|
|
151
|
-
//
|
|
152
|
+
// Detect GPIO ops in lowered raw C++ text. Build the read/write name
|
|
153
|
+
// patterns from the loaded framework's HAL vocabulary (halCallNames),
|
|
154
|
+
// classifying names containing "Read" as reads and "Write" as writes (the
|
|
155
|
+
// Wiring-derived convention). Seed with digitalRead/digitalWrite as the
|
|
156
|
+
// canonical Wiring forms so the validator works even when no framework is
|
|
157
|
+
// loaded. Non-Wiring frameworks that emit other call forms register them
|
|
158
|
+
// via halCallNames; this loop picks them up.
|
|
152
159
|
if (e.kind === 'raw' && typeof e.value === 'string') {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
const frameworkHalNames = hasLoadedFramework()
|
|
161
|
+
? getLoadedFramework().strategy.halCallNames?.()
|
|
162
|
+
: undefined;
|
|
163
|
+
const halNames = frameworkHalNames ?? new Set(['digitalRead', 'digitalWrite']);
|
|
164
|
+
const readNames = [...halNames].filter(n => /read/i.test(n));
|
|
165
|
+
const writeNames = [...halNames].filter(n => /write/i.test(n));
|
|
166
|
+
let pin = null;
|
|
167
|
+
let op = null;
|
|
168
|
+
for (const rn of readNames) {
|
|
169
|
+
const esc = rn.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
170
|
+
const m = e.value.match(new RegExp(`${esc}\\((\\d+)\\)`));
|
|
171
|
+
if (m) {
|
|
172
|
+
pin = parseInt(m[1], 10);
|
|
173
|
+
op = { operation: 'gpio.read', pin };
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!op) {
|
|
178
|
+
for (const wn of writeNames) {
|
|
179
|
+
const esc = wn.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
180
|
+
const m = e.value.match(new RegExp(`${esc}\\((\\d+)`));
|
|
181
|
+
if (m) {
|
|
182
|
+
pin = parseInt(m[1], 10);
|
|
183
|
+
op = { operation: 'gpio.write', pin };
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// toggle: a write call whose second arg is a read call on the same pin.
|
|
189
|
+
if (!op) {
|
|
190
|
+
const tm = e.value.match(/\((\d+),\s*\w*[Rr]ead/);
|
|
191
|
+
if (tm) {
|
|
192
|
+
op = { operation: 'gpio.toggle', pin: parseInt(tm[1], 10) };
|
|
193
|
+
}
|
|
165
194
|
}
|
|
195
|
+
if (op)
|
|
196
|
+
checkGpioHalOp(op);
|
|
166
197
|
}
|
|
167
198
|
// Recurse into nested expressions
|
|
168
199
|
if (e.args && Array.isArray(e.args)) {
|
|
@@ -52,6 +52,71 @@ export interface ProgramAnalysisResult {
|
|
|
52
52
|
* __tc_TimerRuntime::MAX_TIMERS to the observed count (floor 1) rather than
|
|
53
53
|
* a blind constant, so a one-timer program links one slot, not eight. */
|
|
54
54
|
timerCallCount: number;
|
|
55
|
+
/** ESP32 peripheral usage — framework-esp32 gates its IDF driver blocks and
|
|
56
|
+
* forced includes on these. Detected from HAL-op operation names, the same
|
|
57
|
+
* way usesUart/usesSPI/usesI2C are. Other frameworks have no CUTTLEFISH_*
|
|
58
|
+
* blocks with these marker names so the setup.ts filters are no-ops there. */
|
|
59
|
+
usesGPIO: boolean;
|
|
60
|
+
usesPWM: boolean;
|
|
61
|
+
usesRmt: boolean;
|
|
62
|
+
usesADC: boolean;
|
|
63
|
+
usesDAC: boolean;
|
|
64
|
+
usesPower: boolean;
|
|
65
|
+
usesWdt: boolean;
|
|
66
|
+
usesInterrupts: boolean;
|
|
67
|
+
usesPulse: boolean;
|
|
68
|
+
usesShift: boolean;
|
|
69
|
+
/** WiFi / HTTP / BLE usage — framework-esp32 gates the __tc_wifi/__tc_http/
|
|
70
|
+
* __tc_ble runtime shims and their esp_wifi/esp_http_client/nimble includes
|
|
71
|
+
* on these. Detected from wifi.* / http.* / ble.* HAL-op operation names. */
|
|
72
|
+
usesWifi: boolean;
|
|
73
|
+
/** Fine-grained WiFi sub-feature tracking — gates individual shim sub-blocks
|
|
74
|
+
* so that unused static helper functions don't trigger -Wunused-function. */
|
|
75
|
+
usesWifiConnect: boolean;
|
|
76
|
+
usesWifiConnectBlocking: boolean;
|
|
77
|
+
usesWifiQuery: boolean;
|
|
78
|
+
usesWifiScan: boolean;
|
|
79
|
+
usesWifiConfig: boolean;
|
|
80
|
+
usesHttp: boolean;
|
|
81
|
+
usesBle: boolean;
|
|
82
|
+
/** Preferences (NVS) usage — framework-esp32 gates the __tc_prefs runtime shim
|
|
83
|
+
* and its nvs_flash/nvs includes on this. Detected from preferences.* ops. */
|
|
84
|
+
usesPreferences: boolean;
|
|
85
|
+
/** Random usage — frameworks gate their PRNG runtime/include on this
|
|
86
|
+
* (e.g. framework-esp32 includes <esp_random.h>). Detected from random.* ops. */
|
|
87
|
+
usesRandom: boolean;
|
|
88
|
+
/** FS (filesystem) usage — frameworks gate their VFS/SD runtime shim on this.
|
|
89
|
+
* Detected from fs.* ops. */
|
|
90
|
+
usesFS: boolean;
|
|
91
|
+
/** mDNS usage — frameworks gate the esp_mdns runtime/include on this. */
|
|
92
|
+
usesMdns: boolean;
|
|
93
|
+
/** MQTT usage — frameworks gate the esp_mqtt runtime/include on this. */
|
|
94
|
+
usesMqtt: boolean;
|
|
95
|
+
/** OTA usage — frameworks gate the esp_https_ota runtime/include on this. */
|
|
96
|
+
usesOta: boolean;
|
|
97
|
+
/** Temperature (die temp) usage. Detected from temp.* ops. */
|
|
98
|
+
usesTemp: boolean;
|
|
99
|
+
/** Hardware timer (GPTimer) usage. Detected from hwtimer.* ops. */
|
|
100
|
+
usesHwtimer: boolean;
|
|
101
|
+
/** Capacitive touch pins usage. Detected from capacitive.* ops. */
|
|
102
|
+
usesCapacitive: boolean;
|
|
103
|
+
/** Worker offload usage. Detected from worker.* ops. Frameworks gate the
|
|
104
|
+
* worker_runtime polyfill (and its per-framework backing) on this. */
|
|
105
|
+
usesWorker: boolean;
|
|
106
|
+
/** Native/desktop: std::chrono / steady_clock usage (gates <chrono>). */
|
|
107
|
+
usesChrono: boolean;
|
|
108
|
+
/** Native/desktop: std::set usage (gates <set>). */
|
|
109
|
+
usesSet: boolean;
|
|
110
|
+
/** Native/desktop: std::algorithm usage (std::sort/find/transform etc., gates <algorithm>). */
|
|
111
|
+
usesAlgorithm: boolean;
|
|
112
|
+
/** Native/desktop: cstdio usage (printf/fprintf/snprintf, gates <cstdio>). */
|
|
113
|
+
usesCstdio: boolean;
|
|
114
|
+
/** digitalRead() in lowered raw text or gpio.read hal-op (gates the native digitalRead shim). */
|
|
115
|
+
usesDigitalRead: boolean;
|
|
116
|
+
/** display.* hal-op present, or a UI is mounted (replaces ad-hoc programUsesDisplay walks). */
|
|
117
|
+
usesDisplay: boolean;
|
|
118
|
+
/** cuttlefish_halt() in lowered raw text (gates the cuttlefish_halt macro polyfill). */
|
|
119
|
+
usesHalt: boolean;
|
|
55
120
|
}
|
|
56
121
|
/**
|
|
57
122
|
* Analyze a program IR in a single pass to detect all features.
|