@typecad/cuttlefish 1.0.0-alpha.3 → 1.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/api/shared/display-adapter.d.ts +2 -1
- package/dist/api/shared/display-adapter.js +8 -1
- package/dist/api/shared/display-adapters/sdl.js +9 -2
- package/dist/api/shared/display-profile.d.ts +20 -3
- package/dist/api/shared/display-profile.js +21 -6
- package/dist/api/shared/framework-manifest-registry.d.ts +9 -0
- package/dist/api/shared/framework-manifest-registry.js +25 -0
- package/dist/api/shared/framework-manifest.d.ts +462 -0
- package/dist/api/shared/framework-manifest.js +149 -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 +28 -0
- package/dist/api/shared/hal-op-ir.d.ts +427 -1
- package/dist/api/shared/hal-op-ir.js +95 -1
- package/dist/api/shared/index.d.ts +11 -1
- package/dist/api/shared/index.js +14 -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 +9 -0
- package/dist/api/shared/promise-runtime.js +78 -0
- package/dist/api/shared/types.d.ts +8 -0
- package/dist/api/shared/validate-framework-manifest.d.ts +28 -0
- package/dist/api/shared/validate-framework-manifest.js +417 -0
- package/dist/cli-utils.d.ts +1 -0
- package/dist/cli-utils.js +3 -1
- package/dist/cli.js +175 -4
- package/dist/config-loader.js +20 -1
- package/dist/config-schema.d.ts +36 -36
- package/dist/create/board-spec.d.ts +4 -4
- package/dist/create/index.d.ts +1 -1
- package/dist/create/index.js +1 -1
- package/dist/create/init-scaffold.d.ts +3 -0
- package/dist/create/init-scaffold.js +74 -2
- package/dist/create/init-templates.d.ts +4 -0
- package/dist/create/init-templates.js +217 -17
- package/dist/create/init-wizard.js +20 -1
- package/dist/emit/cpp-emitter.js +4 -3
- package/dist/emit/emitters/emitter-context.d.ts +5 -0
- package/dist/emit/emitters/function-emitter-impl.js +69 -59
- package/dist/emit/emitters/output-finalizer.d.ts +6 -0
- package/dist/emit/emitters/output-finalizer.js +21 -11
- package/dist/emit/emitters/setup.js +155 -0
- package/dist/emit/emitters/top-level-prep.js +2 -0
- package/dist/emit/emitters/ui-emitter.js +23 -8
- package/dist/emit/expression-renderer.js +10 -1
- package/dist/emit/snprintf-helpers.js +8 -0
- package/dist/emit/statement-renderer.js +13 -0
- package/dist/emit/utils/async-state-machine.js +185 -116
- 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/ir/adc-range-validation.js +26 -25
- package/dist/ir/build-ir.js +5 -1
- package/dist/ir/expression-to-ir.js +57 -6
- package/dist/ir/feature-registry.js +7 -25
- package/dist/ir/hal/hal-emitter.d.ts +5 -2
- package/dist/ir/hal/hal-emitter.js +40 -12
- package/dist/ir/hal/hal-parser.d.ts +6 -0
- package/dist/ir/hal/hal-parser.js +74 -0
- package/dist/ir/hal/hal-plugins.js +571 -0
- package/dist/ir/identifier-collector.js +18 -0
- package/dist/ir/interrupt-analysis.js +8 -3
- package/dist/ir/memory-budget-validation.js +1 -0
- package/dist/ir/network-validation.d.ts +4 -0
- package/dist/ir/network-validation.js +184 -0
- package/dist/ir/ownership-analysis.js +33 -1
- package/dist/ir/peripheral-ownership.js +5 -0
- package/dist/ir/peripheral-validation.d.ts +1 -1
- package/dist/ir/peripheral-validation.js +6 -3
- package/dist/ir/pin-alias-conflict.d.ts +1 -1
- package/dist/ir/pin-alias-conflict.js +2 -1
- package/dist/ir/pin-capability-validation.js +34 -32
- package/dist/ir/pin-mode-validation.js +5 -0
- package/dist/ir/pin-safety.d.ts +1 -1
- package/dist/ir/pin-safety.js +2 -1
- package/dist/ir/program-analysis.d.ts +39 -0
- package/dist/ir/program-analysis.js +192 -0
- package/dist/ir/pulldown-validation.d.ts +1 -1
- package/dist/ir/pulldown-validation.js +2 -1
- package/dist/ir/pwm-timer-sharing.d.ts +1 -1
- package/dist/ir/pwm-timer-sharing.js +2 -1
- package/dist/ir/resource-analysis.js +2 -0
- package/dist/ir/timer0-pwm-timing-conflict.d.ts +1 -1
- package/dist/ir/timer0-pwm-timing-conflict.js +2 -1
- package/dist/ir/timing-validation.d.ts +6 -1
- package/dist/ir/timing-validation.js +51 -12
- package/dist/ir/transformers/expressions.js +58 -0
- package/dist/ir/transformers/hal-emit-helpers.js +1 -1
- package/dist/ir/transformers/variables.js +86 -19
- package/dist/ir/try-catch-validation.js +2 -0
- package/dist/ir/type-resolution.js +2 -2
- package/dist/ir/unit-suspicion-validation.js +9 -7
- package/dist/ir/validation-orchestrator.js +9 -7
- 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/idf-discovery.d.ts +7 -0
- package/dist/libdef/idf-discovery.js +59 -0
- package/dist/libdef/registry.js +5 -2
- package/dist/licenses.d.ts +185 -0
- package/dist/licenses.js +963 -0
- package/dist/lint-cache.d.ts +59 -0
- package/dist/lint-cache.js +257 -0
- package/dist/orchestrator/graph-builder.js +6 -2
- package/dist/stores/display-profile-store.d.ts +1 -0
- package/dist/stores/display-profile-store.js +1 -0
- package/dist/testing.d.ts +4 -2
- package/dist/testing.js +4 -2
- package/dist/transpile.d.ts +3 -0
- package/dist/transpile.js +78 -32
- package/dist/types.d.ts +5 -1
- package/dist/ui-hook.d.ts +17 -1
- package/dist/utils/cli.js +71 -1
- package/dist/utils/fs.d.ts +13 -0
- package/dist/utils/fs.js +50 -0
- package/package.json +9 -4
- package/dist/ir/heap-array-validation.d.ts +0 -24
- package/dist/ir/heap-array-validation.js +0 -29
|
@@ -80,7 +80,7 @@ function findPinsWithCapability(capability, boardConstants) {
|
|
|
80
80
|
// ---------------------------------------------------------------------------
|
|
81
81
|
// Capability check for a single HAL operation
|
|
82
82
|
// ---------------------------------------------------------------------------
|
|
83
|
-
function checkCapability(operation, sourceLine, sourceCol, boardConstants, diagnostics) {
|
|
83
|
+
function checkCapability(operation, sourceLine, sourceCol, filePath, boardConstants, diagnostics) {
|
|
84
84
|
// Only operations with a pin field are capability-checked.
|
|
85
85
|
const op = operation.operation;
|
|
86
86
|
if (!('pin' in operation))
|
|
@@ -145,48 +145,49 @@ function checkCapability(operation, sourceLine, sourceCol, boardConstants, diagn
|
|
|
145
145
|
hint,
|
|
146
146
|
line: sourceLine,
|
|
147
147
|
column: sourceCol,
|
|
148
|
+
filePath,
|
|
148
149
|
source: 'pin-capability-validation',
|
|
149
150
|
});
|
|
150
151
|
}
|
|
151
152
|
// ---------------------------------------------------------------------------
|
|
152
153
|
// IR tree scanner
|
|
153
154
|
// ---------------------------------------------------------------------------
|
|
154
|
-
function scanExpression(expr, boardConstants, parentLine, parentCol, diagnostics) {
|
|
155
|
+
function scanExpression(expr, boardConstants, parentLine, parentCol, parentFilePath, diagnostics) {
|
|
155
156
|
if (!expr || typeof expr !== 'object')
|
|
156
157
|
return;
|
|
157
158
|
switch (expr.kind) {
|
|
158
159
|
case 'binary': {
|
|
159
|
-
scanExpression(expr.left, boardConstants, parentLine, parentCol, diagnostics);
|
|
160
|
-
scanExpression(expr.right, boardConstants, parentLine, parentCol, diagnostics);
|
|
160
|
+
scanExpression(expr.left, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
161
|
+
scanExpression(expr.right, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
161
162
|
break;
|
|
162
163
|
}
|
|
163
164
|
case 'ternary': {
|
|
164
|
-
scanExpression(expr.condition, boardConstants, parentLine, parentCol, diagnostics);
|
|
165
|
-
scanExpression(expr.whenTrue, boardConstants, parentLine, parentCol, diagnostics);
|
|
166
|
-
scanExpression(expr.whenFalse, boardConstants, parentLine, parentCol, diagnostics);
|
|
165
|
+
scanExpression(expr.condition, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
166
|
+
scanExpression(expr.whenTrue, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
167
|
+
scanExpression(expr.whenFalse, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
167
168
|
break;
|
|
168
169
|
}
|
|
169
170
|
case 'property-access': {
|
|
170
|
-
scanExpression(expr.object, boardConstants, parentLine, parentCol, diagnostics);
|
|
171
|
+
scanExpression(expr.object, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
171
172
|
break;
|
|
172
173
|
}
|
|
173
174
|
case 'unary': {
|
|
174
|
-
scanExpression(expr.operand, boardConstants, parentLine, parentCol, diagnostics);
|
|
175
|
+
scanExpression(expr.operand, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
175
176
|
break;
|
|
176
177
|
}
|
|
177
178
|
case 'paren': {
|
|
178
|
-
scanExpression(expr.inner, boardConstants, parentLine, parentCol, diagnostics);
|
|
179
|
+
scanExpression(expr.inner, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
179
180
|
break;
|
|
180
181
|
}
|
|
181
182
|
case 'array': {
|
|
182
183
|
for (const el of expr.elements) {
|
|
183
|
-
scanExpression(el, boardConstants, parentLine, parentCol, diagnostics);
|
|
184
|
+
scanExpression(el, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
184
185
|
}
|
|
185
186
|
break;
|
|
186
187
|
}
|
|
187
188
|
case 'object': {
|
|
188
189
|
for (const field of expr.fields) {
|
|
189
|
-
scanExpression(field.value, boardConstants, parentLine, parentCol, diagnostics);
|
|
190
|
+
scanExpression(field.value, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
190
191
|
}
|
|
191
192
|
break;
|
|
192
193
|
}
|
|
@@ -204,43 +205,43 @@ function scanExpression(expr, boardConstants, parentLine, parentCol, diagnostics
|
|
|
204
205
|
}
|
|
205
206
|
case 'method-call': {
|
|
206
207
|
for (const arg of expr.args) {
|
|
207
|
-
scanExpression(arg, boardConstants, parentLine, parentCol, diagnostics);
|
|
208
|
+
scanExpression(arg, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
208
209
|
}
|
|
209
210
|
break;
|
|
210
211
|
}
|
|
211
212
|
case 'element-access': {
|
|
212
|
-
scanExpression(expr.object, boardConstants, parentLine, parentCol, diagnostics);
|
|
213
|
-
scanExpression(expr.index, boardConstants, parentLine, parentCol, diagnostics);
|
|
213
|
+
scanExpression(expr.object, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
214
|
+
scanExpression(expr.index, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
214
215
|
break;
|
|
215
216
|
}
|
|
216
217
|
case 'string_concat': {
|
|
217
218
|
for (const part of expr.parts) {
|
|
218
|
-
scanExpression(part, boardConstants, parentLine, parentCol, diagnostics);
|
|
219
|
+
scanExpression(part, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
219
220
|
}
|
|
220
221
|
break;
|
|
221
222
|
}
|
|
222
223
|
case 'template_string': {
|
|
223
|
-
scanExpression(expr.expression, boardConstants, parentLine, parentCol, diagnostics);
|
|
224
|
+
scanExpression(expr.expression, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
224
225
|
break;
|
|
225
226
|
}
|
|
226
227
|
case 'spread_array': {
|
|
227
|
-
scanExpression(expr.spreadExpr, boardConstants, parentLine, parentCol, diagnostics);
|
|
228
|
+
scanExpression(expr.spreadExpr, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
228
229
|
for (const el of expr.additionalElements) {
|
|
229
|
-
scanExpression(el, boardConstants, parentLine, parentCol, diagnostics);
|
|
230
|
+
scanExpression(el, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
230
231
|
}
|
|
231
232
|
break;
|
|
232
233
|
}
|
|
233
234
|
case 'instanceof': {
|
|
234
|
-
scanExpression(expr.object, boardConstants, parentLine, parentCol, diagnostics);
|
|
235
|
+
scanExpression(expr.object, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
235
236
|
break;
|
|
236
237
|
}
|
|
237
238
|
case 'await': {
|
|
238
|
-
scanExpression(expr.value, boardConstants, parentLine, parentCol, diagnostics);
|
|
239
|
+
scanExpression(expr.value, boardConstants, parentLine, parentCol, parentFilePath, diagnostics);
|
|
239
240
|
break;
|
|
240
241
|
}
|
|
241
242
|
case 'hal-expr': {
|
|
242
243
|
// Expression-form HAL operation (e.g. adc.read used as a value).
|
|
243
|
-
checkCapability(expr.operation, parentLine, parentCol, boardConstants, diagnostics);
|
|
244
|
+
checkCapability(expr.operation, parentLine, parentCol, parentFilePath, boardConstants, diagnostics);
|
|
244
245
|
break;
|
|
245
246
|
}
|
|
246
247
|
case 'number':
|
|
@@ -259,20 +260,21 @@ function scanStatement(stmt, boardConstants, diagnostics) {
|
|
|
259
260
|
return;
|
|
260
261
|
const line = stmt.sourceSpan?.startLine;
|
|
261
262
|
const col = stmt.sourceSpan?.startColumn;
|
|
263
|
+
const filePath = stmt.sourceSpan?.filePath;
|
|
262
264
|
switch (stmt.kind) {
|
|
263
265
|
case 'var_decl': {
|
|
264
266
|
if (stmt.initializer)
|
|
265
|
-
scanExpression(stmt.initializer, boardConstants, line, col, diagnostics);
|
|
267
|
+
scanExpression(stmt.initializer, boardConstants, line, col, filePath, diagnostics);
|
|
266
268
|
break;
|
|
267
269
|
}
|
|
268
270
|
case 'assign': {
|
|
269
271
|
if (stmt.value)
|
|
270
|
-
scanExpression(stmt.value, boardConstants, line, col, diagnostics);
|
|
272
|
+
scanExpression(stmt.value, boardConstants, line, col, filePath, diagnostics);
|
|
271
273
|
break;
|
|
272
274
|
}
|
|
273
275
|
case 'if': {
|
|
274
276
|
if (stmt.condition)
|
|
275
|
-
scanExpression(stmt.condition, boardConstants, line, col, diagnostics);
|
|
277
|
+
scanExpression(stmt.condition, boardConstants, line, col, filePath, diagnostics);
|
|
276
278
|
for (const s of stmt.thenBranch)
|
|
277
279
|
scanStatement(s, boardConstants, diagnostics);
|
|
278
280
|
if (stmt.elseBranch)
|
|
@@ -283,14 +285,14 @@ function scanStatement(stmt, boardConstants, diagnostics) {
|
|
|
283
285
|
case 'while':
|
|
284
286
|
case 'do_while': {
|
|
285
287
|
if (stmt.condition)
|
|
286
|
-
scanExpression(stmt.condition, boardConstants, line, col, diagnostics);
|
|
288
|
+
scanExpression(stmt.condition, boardConstants, line, col, filePath, diagnostics);
|
|
287
289
|
for (const s of stmt.body)
|
|
288
290
|
scanStatement(s, boardConstants, diagnostics);
|
|
289
291
|
break;
|
|
290
292
|
}
|
|
291
293
|
case 'for': {
|
|
292
294
|
if (stmt.condition)
|
|
293
|
-
scanExpression(stmt.condition, boardConstants, line, col, diagnostics);
|
|
295
|
+
scanExpression(stmt.condition, boardConstants, line, col, filePath, diagnostics);
|
|
294
296
|
if (stmt.initializer)
|
|
295
297
|
scanStatement(stmt.initializer, boardConstants, diagnostics);
|
|
296
298
|
if (stmt.increment)
|
|
@@ -309,23 +311,23 @@ function scanStatement(stmt, boardConstants, diagnostics) {
|
|
|
309
311
|
}
|
|
310
312
|
case 'return': {
|
|
311
313
|
if (stmt.value)
|
|
312
|
-
scanExpression(stmt.value, boardConstants, line, col, diagnostics);
|
|
314
|
+
scanExpression(stmt.value, boardConstants, line, col, filePath, diagnostics);
|
|
313
315
|
break;
|
|
314
316
|
}
|
|
315
317
|
case 'call': {
|
|
316
318
|
for (const arg of stmt.args) {
|
|
317
|
-
scanExpression(arg, boardConstants, line, col, diagnostics);
|
|
319
|
+
scanExpression(arg, boardConstants, line, col, filePath, diagnostics);
|
|
318
320
|
}
|
|
319
321
|
break;
|
|
320
322
|
}
|
|
321
323
|
case 'hal-op': {
|
|
322
324
|
// Statement-form HAL operation — the primary capability check target.
|
|
323
|
-
checkCapability(stmt.operation, line, col, boardConstants, diagnostics);
|
|
325
|
+
checkCapability(stmt.operation, line, col, filePath, boardConstants, diagnostics);
|
|
324
326
|
break;
|
|
325
327
|
}
|
|
326
328
|
case 'switch': {
|
|
327
329
|
if (stmt.expression)
|
|
328
|
-
scanExpression(stmt.expression, boardConstants, line, col, diagnostics);
|
|
330
|
+
scanExpression(stmt.expression, boardConstants, line, col, filePath, diagnostics);
|
|
329
331
|
for (const c of stmt.cases) {
|
|
330
332
|
for (const s of c.body)
|
|
331
333
|
scanStatement(s, boardConstants, diagnostics);
|
|
@@ -355,7 +357,7 @@ function scanStatement(stmt, boardConstants, diagnostics) {
|
|
|
355
357
|
}
|
|
356
358
|
case 'throw': {
|
|
357
359
|
if (stmt.value)
|
|
358
|
-
scanExpression(stmt.value, boardConstants, line, col, diagnostics);
|
|
360
|
+
scanExpression(stmt.value, boardConstants, line, col, filePath, diagnostics);
|
|
359
361
|
break;
|
|
360
362
|
}
|
|
361
363
|
case 'update':
|
|
@@ -43,6 +43,7 @@ export function validatePinModeConfig(program) {
|
|
|
43
43
|
message: `Analog pin '${receiver}' used as digital output. ` +
|
|
44
44
|
`Analog input capability (ADC) is lost while pin is in OUTPUT mode. ` +
|
|
45
45
|
`Call ${receiver}.asInput() to restore analog reading.`,
|
|
46
|
+
filePath: program.fileName,
|
|
46
47
|
code: 'analog-pin-as-output',
|
|
47
48
|
source: 'pin-mode-validation',
|
|
48
49
|
});
|
|
@@ -55,6 +56,7 @@ export function validatePinModeConfig(program) {
|
|
|
55
56
|
severity: 'warning',
|
|
56
57
|
message: `Pin '${receiver}' read via '${method}()' without prior mode configuration. ` +
|
|
57
58
|
`Call ${receiver}.asInput() or ${receiver}.inputPullUp() first.`,
|
|
59
|
+
filePath: program.fileName,
|
|
58
60
|
code: 'pin-mode-not-set',
|
|
59
61
|
source: 'pin-mode-validation',
|
|
60
62
|
});
|
|
@@ -64,6 +66,7 @@ export function validatePinModeConfig(program) {
|
|
|
64
66
|
severity: 'info',
|
|
65
67
|
message: `Pin '${receiver}' written via '${method}()' without explicit mode configuration. ` +
|
|
66
68
|
`Arduino implicitly sets OUTPUT, but explicit ${receiver}.asOutput() is recommended.`,
|
|
69
|
+
filePath: program.fileName,
|
|
67
70
|
code: 'pin-mode-not-set',
|
|
68
71
|
source: 'pin-mode-validation',
|
|
69
72
|
});
|
|
@@ -100,6 +103,7 @@ export function validatePinModeConfig(program) {
|
|
|
100
103
|
severity: 'warning',
|
|
101
104
|
message: `Pin ${op.pin} read without prior mode configuration. ` +
|
|
102
105
|
`Call asInput() or inputPullUp() first — reading a floating pin is undefined behavior.`,
|
|
106
|
+
filePath: program.fileName,
|
|
103
107
|
code: 'pin-mode-not-set',
|
|
104
108
|
source: 'pin-mode-validation',
|
|
105
109
|
});
|
|
@@ -109,6 +113,7 @@ export function validatePinModeConfig(program) {
|
|
|
109
113
|
severity: 'info',
|
|
110
114
|
message: `Pin ${op.pin} written without explicit mode configuration. ` +
|
|
111
115
|
`Arduino implicitly sets OUTPUT, but explicit asOutput() is recommended.`,
|
|
116
|
+
filePath: program.fileName,
|
|
112
117
|
code: 'pin-mode-not-set',
|
|
113
118
|
source: 'pin-mode-validation',
|
|
114
119
|
});
|
package/dist/ir/pin-safety.d.ts
CHANGED
|
@@ -8,4 +8,4 @@ import type { Diagnostic } from '../types.js';
|
|
|
8
8
|
* @param boardConstants - Board constants containing pins.unsafe array
|
|
9
9
|
* @returns Array of diagnostic warnings for unsafe pin usage
|
|
10
10
|
*/
|
|
11
|
-
export declare function validateUnsafePins(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
|
|
11
|
+
export declare function validateUnsafePins(usage: PeripheralUsage, boardConstants: BoardConstants | undefined, filePath: string): Diagnostic[];
|
package/dist/ir/pin-safety.js
CHANGED
|
@@ -30,7 +30,7 @@ function buildUnsafePinMessage(pinName, boardConstants) {
|
|
|
30
30
|
* @param boardConstants - Board constants containing pins.unsafe array
|
|
31
31
|
* @returns Array of diagnostic warnings for unsafe pin usage
|
|
32
32
|
*/
|
|
33
|
-
export function validateUnsafePins(usage, boardConstants) {
|
|
33
|
+
export function validateUnsafePins(usage, boardConstants, filePath) {
|
|
34
34
|
const diagnostics = [];
|
|
35
35
|
if (!boardConstants)
|
|
36
36
|
return diagnostics;
|
|
@@ -50,6 +50,7 @@ export function validateUnsafePins(usage, boardConstants) {
|
|
|
50
50
|
severity: 'warning',
|
|
51
51
|
message: buildUnsafePinMessage(pinName, boardConstants),
|
|
52
52
|
code: 'unsafe-pin-usage',
|
|
53
|
+
filePath,
|
|
53
54
|
source: 'pin-safety',
|
|
54
55
|
});
|
|
55
56
|
}
|
|
@@ -29,6 +29,22 @@ export interface ProgramAnalysisResult {
|
|
|
29
29
|
usesTiming: boolean;
|
|
30
30
|
usesWDT: boolean;
|
|
31
31
|
usesStrPtr: boolean;
|
|
32
|
+
usesUart: boolean;
|
|
33
|
+
usesSPI: boolean;
|
|
34
|
+
usesI2C: boolean;
|
|
35
|
+
usesEEPROM: boolean;
|
|
36
|
+
usesTone: boolean;
|
|
37
|
+
/** map()/constrain() Arduino-API calls. framework-avr gates its native
|
|
38
|
+
* _native_map/_native_constrain helpers on these (they're dead code
|
|
39
|
+
* otherwise — no other internal caller references them). */
|
|
40
|
+
usesMap: boolean;
|
|
41
|
+
usesConstrain: boolean;
|
|
42
|
+
/** Comprehensive timing gate for the native millis() Timer0 ISR on AVR.
|
|
43
|
+
* True when the program directly uses millis/delay/micros, OR has hidden
|
|
44
|
+
* consumers of the soft clock: setInterval/setTimeout (timerCallCount),
|
|
45
|
+
* async functions (the runtime polls millis), or a mounted UI (per-frame
|
|
46
|
+
* tick injected by the emitter, not present in user source). */
|
|
47
|
+
usesNativeTiming: boolean;
|
|
32
48
|
hasSerialBegin: boolean;
|
|
33
49
|
hasGenerators: boolean;
|
|
34
50
|
usesStdMap: boolean;
|
|
@@ -36,6 +52,29 @@ export interface ProgramAnalysisResult {
|
|
|
36
52
|
* __tc_TimerRuntime::MAX_TIMERS to the observed count (floor 1) rather than
|
|
37
53
|
* a blind constant, so a one-timer program links one slot, not eight. */
|
|
38
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
|
+
usesHttp: boolean;
|
|
74
|
+
usesBle: boolean;
|
|
75
|
+
/** Preferences (NVS) usage — framework-esp32 gates the __tc_prefs runtime shim
|
|
76
|
+
* and its nvs_flash/nvs includes on this. Detected from preferences.* ops. */
|
|
77
|
+
usesPreferences: boolean;
|
|
39
78
|
}
|
|
40
79
|
/**
|
|
41
80
|
* Analyze a program IR in a single pass to detect all features.
|
|
@@ -102,6 +102,30 @@ function analyzeExpression(expr, result, strategy) {
|
|
|
102
102
|
if (expr.callee.startsWith("WDT.") || expr.callee === "WDT") {
|
|
103
103
|
result.usesWDT = true;
|
|
104
104
|
}
|
|
105
|
+
// Native AVR peripheral usage from namespace-prefixed method calls
|
|
106
|
+
// (Serial.* / SPI.* / Wire.* / EEPROM.*). The HAL resolver lowers these
|
|
107
|
+
// to structured hal-ops (detected in analyzeStatement) OR to bare
|
|
108
|
+
// lowered calls; these checks cover the pre-lowering and direct forms.
|
|
109
|
+
if (expr.callee.startsWith("Serial.") || expr.callee === "Serial") {
|
|
110
|
+
result.usesUart = true;
|
|
111
|
+
}
|
|
112
|
+
if (expr.callee.startsWith("SPI.") || expr.callee === "SPI") {
|
|
113
|
+
result.usesSPI = true;
|
|
114
|
+
}
|
|
115
|
+
if (expr.callee.startsWith("Wire.") || expr.callee === "Wire") {
|
|
116
|
+
result.usesI2C = true;
|
|
117
|
+
}
|
|
118
|
+
if (expr.callee.startsWith("EEPROM.") || expr.callee === "EEPROM") {
|
|
119
|
+
result.usesEEPROM = true;
|
|
120
|
+
}
|
|
121
|
+
// map()/constrain() Arduino-API calls appear as method-call exprs
|
|
122
|
+
// (callee "map"/"constrain"). framework-avr lowers these to _native_map/
|
|
123
|
+
// _native_constrain via symbol aliases, so the helpers are dead code
|
|
124
|
+
// unless the program actually calls them.
|
|
125
|
+
if (expr.callee === "map")
|
|
126
|
+
result.usesMap = true;
|
|
127
|
+
if (expr.callee === "constrain")
|
|
128
|
+
result.usesConstrain = true;
|
|
105
129
|
// Count setInterval/setTimeout call sites (post-rename callee names) so
|
|
106
130
|
// __tc_TimerRuntime::MAX_TIMERS can be sized to the observed count.
|
|
107
131
|
if (expr.callee === "__tc_setInterval" || expr.callee === "__tc_setTimeout"
|
|
@@ -192,6 +216,23 @@ function analyzeExpression(expr, result, strategy) {
|
|
|
192
216
|
analyzeExpression(expr.expression, result, strategy);
|
|
193
217
|
}
|
|
194
218
|
break;
|
|
219
|
+
case "hal-expr":
|
|
220
|
+
// Value-position HAL ops (e.g. `const ip = WiFi.localIP()` lowers to a
|
|
221
|
+
// hal-expr initializer) never pass through the statement-level hal-op
|
|
222
|
+
// detection above, so mirror the wifi./http. flag detection here. These
|
|
223
|
+
// gate the framework-esp32 __tc_wifi/__tc_http runtime shims.
|
|
224
|
+
if (expr.operation && typeof expr.operation.operation === "string") {
|
|
225
|
+
const opName = expr.operation.operation;
|
|
226
|
+
if (opName.startsWith("wifi."))
|
|
227
|
+
result.usesWifi = true;
|
|
228
|
+
if (opName.startsWith("http."))
|
|
229
|
+
result.usesHttp = true;
|
|
230
|
+
if (opName.startsWith("ble."))
|
|
231
|
+
result.usesBle = true;
|
|
232
|
+
if (opName.startsWith("preferences."))
|
|
233
|
+
result.usesPreferences = true;
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
195
236
|
}
|
|
196
237
|
}
|
|
197
238
|
/**
|
|
@@ -218,6 +259,11 @@ function analyzeStatement(statement, result, strategy) {
|
|
|
218
259
|
if (statement.callee === "millis" || statement.callee === "delay") {
|
|
219
260
|
result.usesMillis = true;
|
|
220
261
|
}
|
|
262
|
+
// Awaited HAL wait markers become async state-machine poll states that
|
|
263
|
+
// arm deadlines via currentTimeMillis().
|
|
264
|
+
if (statement.callee === "__WIFI_WAIT__" || statement.callee === "__HTTP_WAIT__" || statement.callee === "__HAL_WAIT__") {
|
|
265
|
+
result.usesMillis = true;
|
|
266
|
+
}
|
|
221
267
|
// Namespace-qualified polyfill entry points used as bare call statements
|
|
222
268
|
// (e.g. `Timing.delay(5);`). The expression-level analyzer (case
|
|
223
269
|
// "method-call") already checks these prefixes, but a statement-form call
|
|
@@ -234,6 +280,35 @@ function analyzeStatement(statement, result, strategy) {
|
|
|
234
280
|
if (statement.callee.startsWith("WDT.") || statement.callee === "WDT") {
|
|
235
281
|
result.usesWDT = true;
|
|
236
282
|
}
|
|
283
|
+
// Native AVR peripheral usage from statement-form calls. tone()/noTone()
|
|
284
|
+
// are bare Arduino-API calls; console.* / Serial.* drive UART; the
|
|
285
|
+
// namespace prefixes mirror the method-call checks above.
|
|
286
|
+
if (statement.callee === "tone" || statement.callee === "noTone") {
|
|
287
|
+
result.usesTone = true;
|
|
288
|
+
}
|
|
289
|
+
// console.* is NOT UART: on ESP-IDF it lowers to printf, on Arduino to
|
|
290
|
+
// Serial via hasConsoleCalls. Only real UART HAL / Serial peripheral
|
|
291
|
+
// usage should gate the uart shim (avoids unused __tc_uart*_init).
|
|
292
|
+
if (statement.callee.startsWith("_uart_")) {
|
|
293
|
+
result.usesUart = true;
|
|
294
|
+
}
|
|
295
|
+
if (statement.callee.startsWith("Serial.") || statement.callee === "Serial") {
|
|
296
|
+
result.usesUart = true;
|
|
297
|
+
}
|
|
298
|
+
if (statement.callee.startsWith("SPI.") || statement.callee === "SPI") {
|
|
299
|
+
result.usesSPI = true;
|
|
300
|
+
}
|
|
301
|
+
if (statement.callee.startsWith("Wire.") || statement.callee === "Wire") {
|
|
302
|
+
result.usesI2C = true;
|
|
303
|
+
}
|
|
304
|
+
if (statement.callee.startsWith("EEPROM.") || statement.callee === "EEPROM") {
|
|
305
|
+
result.usesEEPROM = true;
|
|
306
|
+
}
|
|
307
|
+
// Statement-form map()/constrain() mirror the method-call checks above.
|
|
308
|
+
if (statement.callee === "map")
|
|
309
|
+
result.usesMap = true;
|
|
310
|
+
if (statement.callee === "constrain")
|
|
311
|
+
result.usesConstrain = true;
|
|
237
312
|
// The HAL resolver lowers WDT.*/Timing.* namespace calls to bare AVR
|
|
238
313
|
// library functions (WDT.reset() → wdt_reset(), Timing.delay() → delay(),
|
|
239
314
|
// Timing.millis() → millis()). When that happens the `WDT.`/`Timing.`
|
|
@@ -357,6 +432,73 @@ function analyzeStatement(statement, result, strategy) {
|
|
|
357
432
|
}
|
|
358
433
|
break;
|
|
359
434
|
case "hal-op":
|
|
435
|
+
// Structured HAL ops carry a typed operation name (e.g. "spi.begin",
|
|
436
|
+
// "i2c.read_byte", "tone.play", "uart.write") rather than raw code.
|
|
437
|
+
// Detect peripheral usage here so framework-avr's driver shims can be
|
|
438
|
+
// gated on actual use. Without this, SPI0.begin() → spi.begin hal-op
|
|
439
|
+
// would be invisible (no raw code to scan) and the SPI driver would
|
|
440
|
+
// always be emitted. Same blind spot the wdt.* fix below the raw-code
|
|
441
|
+
// block addresses for the watchdog.
|
|
442
|
+
if (statement.operation && typeof statement.operation.operation === "string") {
|
|
443
|
+
const opName = statement.operation.operation;
|
|
444
|
+
if (opName.startsWith("spi."))
|
|
445
|
+
result.usesSPI = true;
|
|
446
|
+
if (opName.startsWith("i2c."))
|
|
447
|
+
result.usesI2C = true;
|
|
448
|
+
if (opName.startsWith("tone."))
|
|
449
|
+
result.usesTone = true;
|
|
450
|
+
if (opName.startsWith("uart."))
|
|
451
|
+
result.usesUart = true;
|
|
452
|
+
// Display HAL ops (display.init from ui.mount, display.flush per frame)
|
|
453
|
+
// always imply GPIO usage (CS/DC/RST pins). Native SPI/I2C display
|
|
454
|
+
// adapters emit their own transport #includes (driver/spi_master.h,
|
|
455
|
+
// driver/i2c_master.h) — we don't force usesSPI/usesI2C here because
|
|
456
|
+
// that would pull headers even for non-display SPI/I2C code, and the
|
|
457
|
+
// display's transport type can't be determined from the op alone.
|
|
458
|
+
if (opName.startsWith("display.")) {
|
|
459
|
+
result.usesGPIO = true;
|
|
460
|
+
}
|
|
461
|
+
// ESP32 peripheral usage — framework-esp32 gates IDF driver blocks
|
|
462
|
+
// and forced includes on these. No-op for other frameworks (their
|
|
463
|
+
// shimLines emit no CUTTLEFISH_* blocks with these marker names).
|
|
464
|
+
if (opName.startsWith("gpio."))
|
|
465
|
+
result.usesGPIO = true;
|
|
466
|
+
if (opName.startsWith("pwm."))
|
|
467
|
+
result.usesPWM = true;
|
|
468
|
+
if (opName.startsWith("rmt."))
|
|
469
|
+
result.usesRmt = true;
|
|
470
|
+
if (opName.startsWith("adc."))
|
|
471
|
+
result.usesADC = true;
|
|
472
|
+
if (opName.startsWith("dac."))
|
|
473
|
+
result.usesDAC = true;
|
|
474
|
+
if (opName.startsWith("power."))
|
|
475
|
+
result.usesPower = true;
|
|
476
|
+
if (opName.startsWith("wdt."))
|
|
477
|
+
result.usesWdt = true;
|
|
478
|
+
if (opName.startsWith("interrupt."))
|
|
479
|
+
result.usesInterrupts = true;
|
|
480
|
+
if (opName.startsWith("pulse."))
|
|
481
|
+
result.usesPulse = true;
|
|
482
|
+
if (opName.startsWith("shift."))
|
|
483
|
+
result.usesShift = true;
|
|
484
|
+
if (opName.startsWith("wifi."))
|
|
485
|
+
result.usesWifi = true;
|
|
486
|
+
if (opName.startsWith("http."))
|
|
487
|
+
result.usesHttp = true;
|
|
488
|
+
if (opName.startsWith("ble."))
|
|
489
|
+
result.usesBle = true;
|
|
490
|
+
if (opName.startsWith("preferences."))
|
|
491
|
+
result.usesPreferences = true;
|
|
492
|
+
// Timing HAL ops (timing.delay/millis/micros) carry a typed operation
|
|
493
|
+
// name, not raw code, so the regex scans below miss them. Mirror the
|
|
494
|
+
// raw-code timing detection here so usesMillis/usesTiming (and thus
|
|
495
|
+
// usesNativeTiming) fire for `delay()`/`millis()` on AVR.
|
|
496
|
+
if (opName === "timing.delay" || opName === "timing.delay_microseconds"
|
|
497
|
+
|| opName === "timing.millis" || opName === "timing.micros") {
|
|
498
|
+
result.usesTiming = true;
|
|
499
|
+
result.usesMillis = true;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
360
502
|
// Scan raw C++ code in HAL ops for polyfill helper usage
|
|
361
503
|
if (statement.operation && statement.operation.operation === "raw" && typeof statement.operation.code === "string") {
|
|
362
504
|
const code = statement.operation.code;
|
|
@@ -384,6 +526,21 @@ function analyzeStatement(statement, result, strategy) {
|
|
|
384
526
|
result.usesTiming = true;
|
|
385
527
|
result.usesMillis = true;
|
|
386
528
|
}
|
|
529
|
+
// Native AVR peripheral usage inside raw hal-op code (e.g. the
|
|
530
|
+
// EEPROM namespace lowers to `EEPROM.write(...)` in a raw hal-op;
|
|
531
|
+
// Serial/SPI/Wire may appear as lowered library calls too).
|
|
532
|
+
if (/\bEEPROM\b/.test(code) || /\beeprom_(read|write|update)_byte\b/.test(code)) {
|
|
533
|
+
result.usesEEPROM = true;
|
|
534
|
+
}
|
|
535
|
+
if (/\bSerial\b/.test(code)) {
|
|
536
|
+
result.usesUart = true;
|
|
537
|
+
}
|
|
538
|
+
if (/\bSPI\b/.test(code)) {
|
|
539
|
+
result.usesSPI = true;
|
|
540
|
+
}
|
|
541
|
+
if (/\bWire\b/.test(code)) {
|
|
542
|
+
result.usesI2C = true;
|
|
543
|
+
}
|
|
387
544
|
}
|
|
388
545
|
break;
|
|
389
546
|
case "update":
|
|
@@ -431,10 +588,32 @@ export function analyzeProgram(program, strategy) {
|
|
|
431
588
|
usesTiming: false,
|
|
432
589
|
usesWDT: false,
|
|
433
590
|
usesStrPtr: false,
|
|
591
|
+
usesUart: false,
|
|
592
|
+
usesSPI: false,
|
|
593
|
+
usesI2C: false,
|
|
594
|
+
usesEEPROM: false,
|
|
595
|
+
usesTone: false,
|
|
596
|
+
usesMap: false,
|
|
597
|
+
usesConstrain: false,
|
|
598
|
+
usesNativeTiming: false,
|
|
434
599
|
hasSerialBegin: false,
|
|
435
600
|
hasGenerators: false,
|
|
436
601
|
usesStdMap: false,
|
|
437
602
|
timerCallCount: 0,
|
|
603
|
+
usesGPIO: false,
|
|
604
|
+
usesPWM: false,
|
|
605
|
+
usesRmt: false,
|
|
606
|
+
usesADC: false,
|
|
607
|
+
usesDAC: false,
|
|
608
|
+
usesPower: false,
|
|
609
|
+
usesWdt: false,
|
|
610
|
+
usesInterrupts: false,
|
|
611
|
+
usesPulse: false,
|
|
612
|
+
usesShift: false,
|
|
613
|
+
usesWifi: false,
|
|
614
|
+
usesHttp: false,
|
|
615
|
+
usesBle: false,
|
|
616
|
+
usesPreferences: false,
|
|
438
617
|
};
|
|
439
618
|
// Analyze type aliases
|
|
440
619
|
for (const typeAlias of program.typeAliases) {
|
|
@@ -585,5 +764,18 @@ export function analyzeProgram(program, strategy) {
|
|
|
585
764
|
if (loweredConsoleInCallback()) {
|
|
586
765
|
result.hasConsoleCalls = true;
|
|
587
766
|
}
|
|
767
|
+
// Derive the comprehensive native-timing gate for the AVR millis() Timer0
|
|
768
|
+
// ISR. The ISR is needed whenever the program touches the soft clock
|
|
769
|
+
// directly (millis/delay/micros) OR has a hidden consumer: setInterval/
|
|
770
|
+
// setTimeout (the scheduler polls millis), or async functions (the runtime
|
|
771
|
+
// polls millis). The per-frame UI tick is injected by the emitter, not
|
|
772
|
+
// present in user source — the setup emitter ORs entryHasUI() in at the
|
|
773
|
+
// consume site. Without this gate, every AVR program pulled in the Timer0
|
|
774
|
+
// ISR even when it never uses timing.
|
|
775
|
+
const hasAsync = program.functions.some(fn => fn.isAsync);
|
|
776
|
+
result.usesNativeTiming = result.usesMillis
|
|
777
|
+
|| result.usesTiming
|
|
778
|
+
|| result.timerCallCount > 0
|
|
779
|
+
|| hasAsync;
|
|
588
780
|
return result;
|
|
589
781
|
}
|
|
@@ -4,4 +4,4 @@ import type { BoardConstants } from './board-resolver.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Validate that pins used with inputPullDown() support pulldown on this board.
|
|
6
6
|
*/
|
|
7
|
-
export declare function validatePulldownSupport(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
|
|
7
|
+
export declare function validatePulldownSupport(usage: PeripheralUsage, boardConstants: BoardConstants | undefined, filePath: string): Diagnostic[];
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* Validate that pins used with inputPullDown() support pulldown on this board.
|
|
9
9
|
*/
|
|
10
|
-
export function validatePulldownSupport(usage, boardConstants) {
|
|
10
|
+
export function validatePulldownSupport(usage, boardConstants, filePath) {
|
|
11
11
|
const diagnostics = [];
|
|
12
12
|
if (usage.inputPulldownPins.size === 0) {
|
|
13
13
|
return diagnostics;
|
|
@@ -22,6 +22,7 @@ export function validatePulldownSupport(usage, boardConstants) {
|
|
|
22
22
|
diagnostics.push({
|
|
23
23
|
code: 'pulldown-not-supported',
|
|
24
24
|
message: `${pinName ?? `pin ${pinNumber}`} does not support hardware pulldown${arch ? ` on ${arch.toUpperCase()} boards` : ''}. Use ${pinName ?? 'pin'}.asInput() or ${pinName ?? 'pin'}.inputPullUp() instead.`,
|
|
25
|
+
filePath,
|
|
25
26
|
source: 'pulldown-validation',
|
|
26
27
|
severity: 'error',
|
|
27
28
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Diagnostic } from '../types.js';
|
|
2
2
|
import type { BoardConstants } from './board-resolver.js';
|
|
3
3
|
import type { PeripheralUsage } from './peripheral-usage.js';
|
|
4
|
-
export declare function validatePWMTimerSharing(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
|
|
4
|
+
export declare function validatePWMTimerSharing(usage: PeripheralUsage, boardConstants: BoardConstants | undefined, filePath: string): Diagnostic[];
|
|
@@ -52,7 +52,7 @@ function getPwmTimerPins(boardConstants) {
|
|
|
52
52
|
}
|
|
53
53
|
return Array.from(pinsByIndex.values()).filter(pin => pin.timerId.length > 0);
|
|
54
54
|
}
|
|
55
|
-
export function validatePWMTimerSharing(usage, boardConstants) {
|
|
55
|
+
export function validatePWMTimerSharing(usage, boardConstants, filePath) {
|
|
56
56
|
if (usage.pwmPinsUsed.size < 2 || !boardConstants) {
|
|
57
57
|
return [];
|
|
58
58
|
}
|
|
@@ -85,6 +85,7 @@ export function validatePWMTimerSharing(usage, boardConstants) {
|
|
|
85
85
|
diagnostics.push({
|
|
86
86
|
severity: 'info',
|
|
87
87
|
code: 'pwm-timer-sharing',
|
|
88
|
+
filePath,
|
|
88
89
|
source: 'pwm-timer-sharing',
|
|
89
90
|
message: `${references.join(', ')} share ${timerId}${boardLabel}. Duty cycle can differ per pin, but timer-wide PWM settings are shared across that group. Prefer pins on different timer groups if you need independent PWM timing behavior.`,
|
|
90
91
|
});
|
|
@@ -34,6 +34,7 @@ export function analyzeResources(program, strategy) {
|
|
|
34
34
|
diagnostics.push({
|
|
35
35
|
severity: 'warning',
|
|
36
36
|
message: `${pinRef} is configured as ${peripheralName} ${func.role.toUpperCase()}. Using it as GPIO may interfere with communication.\n → ${suggestion}`,
|
|
37
|
+
filePath: program.fileName,
|
|
37
38
|
code: 'peripheral-pin-conflict',
|
|
38
39
|
source: 'resource-analysis',
|
|
39
40
|
});
|
|
@@ -58,6 +59,7 @@ export function analyzeResources(program, strategy) {
|
|
|
58
59
|
severity: 'error',
|
|
59
60
|
message: `Hardware Conflict: Pin '${pinName}' is required by both ${peripheralName} and ${other}.`,
|
|
60
61
|
hint: `Move one of the peripherals to different pins if your board supports remapping, or avoid using both simultaneously.`,
|
|
62
|
+
filePath: program.fileName,
|
|
61
63
|
code: 'peripheral-peripheral-conflict',
|
|
62
64
|
source: 'resource-analysis',
|
|
63
65
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Diagnostic } from '../types.js';
|
|
2
2
|
import type { BoardConstants } from './board-resolver.js';
|
|
3
3
|
import type { PeripheralUsage } from './peripheral-usage.js';
|
|
4
|
-
export declare function validateTimer0PWMTimingConflict(usage: PeripheralUsage, boardConstants: BoardConstants | undefined): Diagnostic[];
|
|
4
|
+
export declare function validateTimer0PWMTimingConflict(usage: PeripheralUsage, boardConstants: BoardConstants | undefined, filePath: string): Diagnostic[];
|