style: update ESLint rules and clean up code formatting across multiple files
This commit is contained in:
parent
53efc226a3
commit
692af00258
|
|
@ -21,5 +21,24 @@ export default defineConfig([
|
|||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn',
|
||||
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' },
|
||||
],
|
||||
'@typescript-eslint/no-namespace': 'off',
|
||||
'@typescript-eslint/no-empty-object-type': 'warn',
|
||||
'@typescript-eslint/ban-ts-comment': 'warn',
|
||||
'react-hooks/set-state-in-effect': 'warn',
|
||||
'react-hooks/purity': 'warn',
|
||||
'no-unused-vars': 'off',
|
||||
'react-hooks/exhaustive-deps': 'warn',
|
||||
'react-refresh/only-export-components': 'warn',
|
||||
'no-empty': ['warn', { allowEmptyCatch: true }],
|
||||
'no-irregular-whitespace': 'warn',
|
||||
'no-control-regex': 'off',
|
||||
'prefer-const': 'warn',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
|
|
|||
|
|
@ -39,10 +39,7 @@
|
|||
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import { spawnSync } from 'child_process';
|
||||
import {
|
||||
mkdtempSync, writeFileSync, readFileSync,
|
||||
rmSync, mkdirSync, readdirSync,
|
||||
} from 'fs';
|
||||
import { mkdtempSync, writeFileSync, readFileSync, rmSync, mkdirSync, readdirSync } from 'fs';
|
||||
import { tmpdir } from 'os';
|
||||
import { join } from 'path';
|
||||
|
||||
|
|
@ -56,7 +53,11 @@ beforeEach(() => {
|
|||
let counter = 0;
|
||||
let depth = 0;
|
||||
vi.stubGlobal('requestAnimationFrame', (cb: FrameRequestCallback) => {
|
||||
if (depth === 0) { depth++; cb(0); depth--; }
|
||||
if (depth === 0) {
|
||||
depth++;
|
||||
cb(0);
|
||||
depth--;
|
||||
}
|
||||
return ++counter;
|
||||
});
|
||||
vi.stubGlobal('cancelAnimationFrame', vi.fn());
|
||||
|
|
@ -77,18 +78,14 @@ const EMPTY_HEX = ':00000001FF\n';
|
|||
* TINY85_BLINK_HEX — sets PB1 HIGH then loops.
|
||||
* Uses ATtiny85 DDRB (I/O 0x17 → mem 0x37) and PORTB (I/O 0x18 → mem 0x38).
|
||||
*/
|
||||
const TINY85_BLINK_HEX =
|
||||
':0A0000000FEF07BB02E008BBFFCFC3\n' +
|
||||
':00000001FF\n';
|
||||
const TINY85_BLINK_HEX = ':0A0000000FEF07BB02E008BBFFCFC3\n' + ':00000001FF\n';
|
||||
|
||||
/**
|
||||
* TINY85_PB0_HEX — sets PB0 HIGH (bit 0).
|
||||
* LDI r16, 0xFF → OUT DDRB → LDI r16, 0x01 → OUT PORTB → RJMP .-2
|
||||
* Checksum: 0xC4
|
||||
*/
|
||||
const TINY85_PB0_HEX =
|
||||
':0A0000000FEF07BB01E008BBFFCFC4\n' +
|
||||
':00000001FF\n';
|
||||
const TINY85_PB0_HEX = ':0A0000000FEF07BB01E008BBFFCFC4\n' + ':00000001FF\n';
|
||||
|
||||
/**
|
||||
* TINY85_PWM_HEX — writes 0x80 to OCR0B (I/O 0x3C → mem 0x5C) to test PWM.
|
||||
|
|
@ -99,9 +96,7 @@ const TINY85_PB0_HEX =
|
|||
* word = 1011 1 11 10000 1100 = 0xBF0C → bytes 0x0C 0xBF
|
||||
* Checksum: 0xB5
|
||||
*/
|
||||
const TINY85_PWM_HEX =
|
||||
':0A0000000FEF07BB00E80CBFFFCFB5\n' +
|
||||
':00000001FF\n';
|
||||
const TINY85_PWM_HEX = ':0A0000000FEF07BB00E80CBFFFCFB5\n' + ':00000001FF\n';
|
||||
|
||||
// ─── Lifecycle ────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -279,11 +274,11 @@ describe('ATtiny85 — PWM monitoring', () => {
|
|||
sim.loadHex(EMPTY_HEX);
|
||||
|
||||
const pwmCb = vi.fn();
|
||||
pm.onPwmChange(1, pwmCb); // PB1 = OCR0B pin
|
||||
pm.onPwmChange(1, pwmCb); // PB1 = OCR0B pin
|
||||
|
||||
// Directly write a PWM value to OCR0B in CPU data memory
|
||||
const cpu = (sim as any).cpu;
|
||||
cpu.data[0x5C] = 128; // 50% duty cycle
|
||||
cpu.data[0x5c] = 128; // 50% duty cycle
|
||||
|
||||
sim.start();
|
||||
sim.stop();
|
||||
|
|
@ -297,7 +292,7 @@ describe('ATtiny85 — PWM monitoring', () => {
|
|||
sim.loadHex(EMPTY_HEX);
|
||||
|
||||
const pwmCb = vi.fn();
|
||||
pm.onPwmChange(0, pwmCb); // PB0 = OCR0A pin
|
||||
pm.onPwmChange(0, pwmCb); // PB0 = OCR0A pin
|
||||
|
||||
const cpu = (sim as any).cpu;
|
||||
cpu.data[0x56] = 64;
|
||||
|
|
@ -311,9 +306,9 @@ describe('ATtiny85 — PWM monitoring', () => {
|
|||
it('ATtiny85 PWM covers 4 pins (OCR0A/OCR0B/OCR1A/OCR1B)', () => {
|
||||
const TINY85_PWM_MAP = [
|
||||
{ addr: 0x56, pin: 0 }, // OCR0A → PB0
|
||||
{ addr: 0x5C, pin: 1 }, // OCR0B → PB1
|
||||
{ addr: 0x4E, pin: 1 }, // OCR1A → PB1
|
||||
{ addr: 0x4B, pin: 4 }, // OCR1B → PB4
|
||||
{ addr: 0x5c, pin: 1 }, // OCR0B → PB1
|
||||
{ addr: 0x4e, pin: 1 }, // OCR1A → PB1
|
||||
{ addr: 0x4b, pin: 4 }, // OCR1B → PB4
|
||||
];
|
||||
|
||||
const pm = new PinManager();
|
||||
|
|
@ -408,17 +403,21 @@ describe('ATtiny85 — end-to-end compilation', () => {
|
|||
const tmpDir = mkdtempSync(join(tmpdir(), 'attiny85-e2e-'));
|
||||
const sketchDir = join(tmpDir, 'sketch');
|
||||
mkdirSync(sketchDir);
|
||||
writeFileSync(join(sketchDir, 'sketch.ino'), `
|
||||
writeFileSync(
|
||||
join(sketchDir, 'sketch.ino'),
|
||||
`
|
||||
void setup() {
|
||||
pinMode(1, OUTPUT);
|
||||
digitalWrite(1, HIGH);
|
||||
}
|
||||
void loop() {}
|
||||
`);
|
||||
`,
|
||||
);
|
||||
|
||||
try {
|
||||
const result = spawnSync(
|
||||
'arduino-cli', ['compile', '--fqbn', FQBN, '--output-dir', sketchDir, sketchDir],
|
||||
'arduino-cli',
|
||||
['compile', '--fqbn', FQBN, '--output-dir', sketchDir, sketchDir],
|
||||
{ encoding: 'utf8', timeout: 60000 },
|
||||
);
|
||||
expect(result.status).toBe(0);
|
||||
|
|
|
|||
|
|
@ -78,11 +78,11 @@ describe('MOSFET PWM LED — scheduler key diagnostic', () => {
|
|||
{ timeout: 30_000 },
|
||||
async () => {
|
||||
const { netlist } = buildNetlist(buildInput(1.0)); // 100% duty = full on
|
||||
|
||||
|
||||
console.log('\n=== NETLIST ===\n' + netlist + '\n==============');
|
||||
|
||||
const cooked = await runNetlist(netlist);
|
||||
|
||||
|
||||
console.log('RAW variableNames:', cooked.variableNames);
|
||||
|
||||
// Mirror CircuitScheduler.drain() exactly
|
||||
|
|
@ -94,9 +94,9 @@ describe('MOSFET PWM LED — scheduler key diagnostic', () => {
|
|||
if (Number.isFinite(i)) branchCurrents[src] = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
console.log('branchCurrents keys (scheduler-filtered):', Object.keys(branchCurrents));
|
||||
|
||||
|
||||
console.log('v_led1_sense:', branchCurrents['v_led1_sense']);
|
||||
|
||||
expect(Object.keys(branchCurrents)).toContain('v_led1_sense');
|
||||
|
|
|
|||
|
|
@ -89,9 +89,9 @@ async function solveAndGetLedCurrent(
|
|||
describe('NPN Transistor Switch — diagnostic', () => {
|
||||
it('pin 9 HIGH: LED conducts ~20 mA', { timeout: 30_000 }, async () => {
|
||||
const { current, netlist } = await solveAndGetLedCurrent('HIGH');
|
||||
|
||||
|
||||
console.log('\n=== NETLIST (pin9=HIGH) ===\n' + netlist);
|
||||
|
||||
|
||||
console.log('LED current (HIGH):', current);
|
||||
expect(current).toBeGreaterThan(5e-3);
|
||||
});
|
||||
|
|
@ -101,9 +101,9 @@ describe('NPN Transistor Switch — diagnostic', () => {
|
|||
{ timeout: 30_000 },
|
||||
async () => {
|
||||
const { current, netlist } = await solveAndGetLedCurrent('LOW');
|
||||
|
||||
|
||||
console.log('\n=== NETLIST (pin9=LOW) ===\n' + netlist);
|
||||
|
||||
|
||||
console.log('LED current (LOW):', current);
|
||||
// If this fails with >1µA, we have reproduced the bug.
|
||||
expect(current).toBeLessThan(1e-6);
|
||||
|
|
|
|||
|
|
@ -148,20 +148,20 @@ describe('NPN LED switch — integration pipeline', () => {
|
|||
avr.runCycles(1);
|
||||
if (pm.getPinState(9)) highCycle = i;
|
||||
}
|
||||
|
||||
|
||||
console.log('pin 9 went HIGH after', highCycle, 'cycles');
|
||||
expect(highCycle).toBeGreaterThanOrEqual(0);
|
||||
|
||||
// Solve with pin 9 HIGH and assert LED conducts.
|
||||
const highPins = collectPinStates(pm, npnSwitchWires());
|
||||
|
||||
|
||||
console.log('pinStates after HIGH write:', highPins);
|
||||
expect(highPins['9']).toEqual({ type: 'digital', v: 5 });
|
||||
|
||||
const { netlist: nlHigh } = buildNetlist(npnSwitchInput(highPins));
|
||||
const cookedHigh = await runNetlist(nlHigh);
|
||||
const iHigh = Math.abs(cookedHigh.dcValue('i(v_led1_sense)'));
|
||||
|
||||
|
||||
console.log('HIGH: LED current =', iHigh, 'A');
|
||||
expect(iHigh).toBeGreaterThan(5e-3);
|
||||
|
||||
|
|
@ -171,21 +171,21 @@ describe('NPN LED switch — integration pipeline', () => {
|
|||
avr.runCycles(1);
|
||||
if (!pm.getPinState(9)) lowCycle = i;
|
||||
}
|
||||
|
||||
|
||||
console.log('pin 9 went LOW after', lowCycle, 'additional cycles');
|
||||
expect(lowCycle).toBeGreaterThanOrEqual(0);
|
||||
|
||||
const lowPins = collectPinStates(pm, npnSwitchWires());
|
||||
|
||||
|
||||
console.log('pinStates after LOW write:', lowPins);
|
||||
expect(lowPins['9']).toBeUndefined();
|
||||
|
||||
const { netlist: nlLow } = buildNetlist(npnSwitchInput(lowPins));
|
||||
|
||||
|
||||
console.log('\n=== NETLIST (after AVR LOW) ===\n' + nlLow);
|
||||
const cookedLow = await runNetlist(nlLow);
|
||||
const iLow = Math.abs(cookedLow.dcValue('i(v_led1_sense)'));
|
||||
|
||||
|
||||
console.log('LOW: LED current =', iLow, 'A');
|
||||
expect(iLow).toBeLessThan(1e-6);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const BOARD_TABS: BoardTab[] = [
|
|||
{ id: 'raspberry-pi-pico', label: 'Pico', color: '#ffffff', bg: '#c11c31' },
|
||||
{ id: 'esp32', label: 'ESP32 (Xtensa)', color: '#ffffff', bg: '#e77d11' },
|
||||
{ id: 'esp32-c3', label: 'ESP32-C3 (RISC-V)', color: '#ffffff', bg: '#27ae60' },
|
||||
{ id: 'attiny85', label: 'ATtiny85', color: '#ffffff', bg: '#5d4037' },
|
||||
{ id: 'attiny85', label: 'ATtiny85', color: '#ffffff', bg: '#5d4037' },
|
||||
{ id: 'multi', label: 'Multi-Board', color: '#ffffff', bg: '#7b2d8b' },
|
||||
{ id: 'analog', label: 'Analog', color: '#ffffff', bg: '#0ea5a5' },
|
||||
];
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ export const PiTerminal: React.FC<PiTerminalProps> = ({ boardId }) => {
|
|||
termRef.current = null;
|
||||
fitAddonRef.current = null;
|
||||
};
|
||||
|
||||
}, [boardId]);
|
||||
|
||||
// ResizeObserver → refit terminal when container size changes
|
||||
|
|
|
|||
|
|
@ -221,7 +221,6 @@ const ChannelCanvas: React.FC<ChannelCanvasProps> = ({
|
|||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
|
||||
drawWaveform(canvas, samples, channel.color, windowEndMs, windowMs);
|
||||
|
||||
}, [samples, channel.color, windowEndMs, windowMs]);
|
||||
|
||||
return (
|
||||
|
|
@ -256,7 +255,6 @@ const RulerCanvas: React.FC<RulerCanvasProps> = ({ windowEndMs, windowMs, timeDi
|
|||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
|
||||
drawRuler(canvas, windowEndMs, windowMs, timeDivMs);
|
||||
|
||||
}, [windowEndMs, windowMs, timeDivMs]);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1287,7 +1287,6 @@ export const SimulatorCanvas = () => {
|
|||
}, 150);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
|
||||
}, [components.length]);
|
||||
|
||||
// Render component using dynamic renderer
|
||||
|
|
|
|||
|
|
@ -6221,11 +6221,17 @@ void loop() {
|
|||
{
|
||||
id: 'attiny85-blink',
|
||||
title: 'ATtiny85: Blink LED',
|
||||
description: 'Classic blink on the ATtiny85 built-in LED (PB1). Great first sketch for this tiny 8-bit chip.',
|
||||
description:
|
||||
'Classic blink on the ATtiny85 built-in LED (PB1). Great first sketch for this tiny 8-bit chip.',
|
||||
category: 'basics',
|
||||
difficulty: 'beginner',
|
||||
boardFilter: 'attiny85',
|
||||
boards: [{ boardKind: 'attiny85', x: 120, y: 160, code: `// ATtiny85 — Blink built-in LED on PB1
|
||||
boards: [
|
||||
{
|
||||
boardKind: 'attiny85',
|
||||
x: 120,
|
||||
y: 160,
|
||||
code: `// ATtiny85 — Blink built-in LED on PB1
|
||||
// Pin 1 = PB1 = OC0B/OC1A (also Digispark LED)
|
||||
|
||||
void setup() {
|
||||
|
|
@ -6237,7 +6243,9 @@ void loop() {
|
|||
delay(500);
|
||||
digitalWrite(1, LOW);
|
||||
delay(500);
|
||||
}` }],
|
||||
}`,
|
||||
},
|
||||
],
|
||||
code: '',
|
||||
components: [],
|
||||
wires: [],
|
||||
|
|
@ -6246,11 +6254,17 @@ void loop() {
|
|||
{
|
||||
id: 'attiny85-button-led',
|
||||
title: 'ATtiny85: Button + LED',
|
||||
description: 'Press the button on PB0 to light the LED on PB1. Uses internal pull-up resistor — no external resistor needed.',
|
||||
description:
|
||||
'Press the button on PB0 to light the LED on PB1. Uses internal pull-up resistor — no external resistor needed.',
|
||||
category: 'basics',
|
||||
difficulty: 'beginner',
|
||||
boardFilter: 'attiny85',
|
||||
boards: [{ boardKind: 'attiny85', x: 100, y: 150, code: `// ATtiny85 — Button on PB0, LED on PB1
|
||||
boards: [
|
||||
{
|
||||
boardKind: 'attiny85',
|
||||
x: 100,
|
||||
y: 150,
|
||||
code: `// ATtiny85 — Button on PB0, LED on PB1
|
||||
// Button wiring: one leg to PB0, other leg to GND
|
||||
// INPUT_PULLUP means HIGH = released, LOW = pressed
|
||||
|
||||
|
|
@ -6262,28 +6276,56 @@ void setup() {
|
|||
void loop() {
|
||||
bool pressed = (digitalRead(0) == LOW);
|
||||
digitalWrite(1, pressed ? HIGH : LOW);
|
||||
}` }],
|
||||
}`,
|
||||
},
|
||||
],
|
||||
code: '',
|
||||
components: [
|
||||
{ type: 'wokwi-pushbutton', id: 'tiny-btn1', x: 380, y: 130, properties: { color: 'green' } },
|
||||
{ type: 'wokwi-led', id: 'tiny-led1', x: 380, y: 240, properties: { color: 'red' } },
|
||||
{ type: 'wokwi-led', id: 'tiny-led1', x: 380, y: 240, properties: { color: 'red' } },
|
||||
],
|
||||
wires: [
|
||||
{ id: 'tb-pb0', start: { componentId: 'attiny85', pinName: 'PB0' }, end: { componentId: 'tiny-btn1', pinName: '1.l' }, color: '#ffcc00' },
|
||||
{ id: 'tb-gnd1', start: { componentId: 'attiny85', pinName: 'GND' }, end: { componentId: 'tiny-btn1', pinName: '2.l' }, color: '#000000' },
|
||||
{ id: 'tb-pb1', start: { componentId: 'attiny85', pinName: 'PB1' }, end: { componentId: 'tiny-led1', pinName: 'A' }, color: '#ff4444' },
|
||||
{ id: 'tb-gnd2', start: { componentId: 'attiny85', pinName: 'GND' }, end: { componentId: 'tiny-led1', pinName: 'C' }, color: '#000000' },
|
||||
{
|
||||
id: 'tb-pb0',
|
||||
start: { componentId: 'attiny85', pinName: 'PB0' },
|
||||
end: { componentId: 'tiny-btn1', pinName: '1.l' },
|
||||
color: '#ffcc00',
|
||||
},
|
||||
{
|
||||
id: 'tb-gnd1',
|
||||
start: { componentId: 'attiny85', pinName: 'GND' },
|
||||
end: { componentId: 'tiny-btn1', pinName: '2.l' },
|
||||
color: '#000000',
|
||||
},
|
||||
{
|
||||
id: 'tb-pb1',
|
||||
start: { componentId: 'attiny85', pinName: 'PB1' },
|
||||
end: { componentId: 'tiny-led1', pinName: 'A' },
|
||||
color: '#ff4444',
|
||||
},
|
||||
{
|
||||
id: 'tb-gnd2',
|
||||
start: { componentId: 'attiny85', pinName: 'GND' },
|
||||
end: { componentId: 'tiny-led1', pinName: 'C' },
|
||||
color: '#000000',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
id: 'attiny85-pwm-fade',
|
||||
title: 'ATtiny85: PWM LED Fade',
|
||||
description: 'Smoothly fade an LED in and out using analogWrite() on PB1 (OC0B). Shows Timer0 PWM on the ATtiny85.',
|
||||
description:
|
||||
'Smoothly fade an LED in and out using analogWrite() on PB1 (OC0B). Shows Timer0 PWM on the ATtiny85.',
|
||||
category: 'basics',
|
||||
difficulty: 'intermediate',
|
||||
boardFilter: 'attiny85',
|
||||
boards: [{ boardKind: 'attiny85', x: 100, y: 150, code: `// ATtiny85 — PWM LED fade on PB1 (OC0B / Timer0)
|
||||
boards: [
|
||||
{
|
||||
boardKind: 'attiny85',
|
||||
x: 100,
|
||||
y: 150,
|
||||
code: `// ATtiny85 — PWM LED fade on PB1 (OC0B / Timer0)
|
||||
// analogWrite() uses Timer0 on the ATtiny85
|
||||
|
||||
void setup() {
|
||||
|
|
@ -6302,27 +6344,56 @@ void loop() {
|
|||
delay(6);
|
||||
}
|
||||
delay(200);
|
||||
}` }],
|
||||
}`,
|
||||
},
|
||||
],
|
||||
code: '',
|
||||
components: [
|
||||
{ type: 'wokwi-led', id: 'tiny-fade-led', x: 380, y: 200, properties: { color: 'yellow' } },
|
||||
{ type: 'wokwi-resistor', id: 'tiny-fade-r1', x: 380, y: 300, properties: { resistance: '220' } },
|
||||
{ type: 'wokwi-led', id: 'tiny-fade-led', x: 380, y: 200, properties: { color: 'yellow' } },
|
||||
{
|
||||
type: 'wokwi-resistor',
|
||||
id: 'tiny-fade-r1',
|
||||
x: 380,
|
||||
y: 300,
|
||||
properties: { resistance: '220' },
|
||||
},
|
||||
],
|
||||
wires: [
|
||||
{ id: 'tf-pb1', start: { componentId: 'attiny85', pinName: 'PB1' }, end: { componentId: 'tiny-fade-led', pinName: 'A' }, color: '#ffcc00' },
|
||||
{ id: 'tf-led-r', start: { componentId: 'tiny-fade-led', pinName: 'C' }, end: { componentId: 'tiny-fade-r1', pinName: '1' }, color: '#888888' },
|
||||
{ id: 'tf-gnd', start: { componentId: 'attiny85', pinName: 'GND' }, end: { componentId: 'tiny-fade-r1', pinName: '2' }, color: '#000000' },
|
||||
{
|
||||
id: 'tf-pb1',
|
||||
start: { componentId: 'attiny85', pinName: 'PB1' },
|
||||
end: { componentId: 'tiny-fade-led', pinName: 'A' },
|
||||
color: '#ffcc00',
|
||||
},
|
||||
{
|
||||
id: 'tf-led-r',
|
||||
start: { componentId: 'tiny-fade-led', pinName: 'C' },
|
||||
end: { componentId: 'tiny-fade-r1', pinName: '1' },
|
||||
color: '#888888',
|
||||
},
|
||||
{
|
||||
id: 'tf-gnd',
|
||||
start: { componentId: 'attiny85', pinName: 'GND' },
|
||||
end: { componentId: 'tiny-fade-r1', pinName: '2' },
|
||||
color: '#000000',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
id: 'attiny85-ntc-sensor',
|
||||
title: 'ATtiny85: NTC Temperature Sensor',
|
||||
description: 'Read temperature from an NTC thermistor on PB3 (ADC3). The LED on PB1 blinks faster as temperature rises.',
|
||||
description:
|
||||
'Read temperature from an NTC thermistor on PB3 (ADC3). The LED on PB1 blinks faster as temperature rises.',
|
||||
category: 'sensors',
|
||||
difficulty: 'intermediate',
|
||||
boardFilter: 'attiny85',
|
||||
boards: [{ boardKind: 'attiny85', x: 100, y: 150, code: `// ATtiny85 — NTC Thermistor on PB3 (ADC3)
|
||||
boards: [
|
||||
{
|
||||
boardKind: 'attiny85',
|
||||
x: 100,
|
||||
y: 150,
|
||||
code: `// ATtiny85 — NTC Thermistor on PB3 (ADC3)
|
||||
// Wiring: NTC between VCC and PB3, 10k resistor between PB3 and GND
|
||||
// LED on PB1: blinks faster when temperature increases
|
||||
|
||||
|
|
@ -6358,21 +6429,53 @@ void loop() {
|
|||
delay(blinkDelay / 2);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
delay(blinkDelay / 2);
|
||||
}` }],
|
||||
}`,
|
||||
},
|
||||
],
|
||||
code: '',
|
||||
components: [
|
||||
{ type: 'wokwi-ntc-temperature-sensor', id: 'tiny-ntc1', x: 380, y: 150, properties: { temperature: '25' } },
|
||||
{ type: 'wokwi-led', id: 'tiny-ntc-led', x: 380, y: 300, properties: { color: 'red' } },
|
||||
{
|
||||
type: 'wokwi-ntc-temperature-sensor',
|
||||
id: 'tiny-ntc1',
|
||||
x: 380,
|
||||
y: 150,
|
||||
properties: { temperature: '25' },
|
||||
},
|
||||
{ type: 'wokwi-led', id: 'tiny-ntc-led', x: 380, y: 300, properties: { color: 'red' } },
|
||||
],
|
||||
wires: [
|
||||
{ id: 'tn-vcc', start: { componentId: 'attiny85', pinName: 'VCC' }, end: { componentId: 'tiny-ntc1', pinName: 'VCC' }, color: '#ff4444' },
|
||||
{ id: 'tn-gnd', start: { componentId: 'attiny85', pinName: 'GND' }, end: { componentId: 'tiny-ntc1', pinName: 'GND' }, color: '#000000' },
|
||||
{ id: 'tn-out', start: { componentId: 'attiny85', pinName: 'PB3' }, end: { componentId: 'tiny-ntc1', pinName: 'OUT' }, color: '#aa44ff' },
|
||||
{ id: 'tn-led', start: { componentId: 'attiny85', pinName: 'PB1' }, end: { componentId: 'tiny-ntc-led', pinName: 'A' }, color: '#ff4444' },
|
||||
{ id: 'tn-lgnd', start: { componentId: 'attiny85', pinName: 'GND' }, end: { componentId: 'tiny-ntc-led', pinName: 'C' }, color: '#000000' },
|
||||
{
|
||||
id: 'tn-vcc',
|
||||
start: { componentId: 'attiny85', pinName: 'VCC' },
|
||||
end: { componentId: 'tiny-ntc1', pinName: 'VCC' },
|
||||
color: '#ff4444',
|
||||
},
|
||||
{
|
||||
id: 'tn-gnd',
|
||||
start: { componentId: 'attiny85', pinName: 'GND' },
|
||||
end: { componentId: 'tiny-ntc1', pinName: 'GND' },
|
||||
color: '#000000',
|
||||
},
|
||||
{
|
||||
id: 'tn-out',
|
||||
start: { componentId: 'attiny85', pinName: 'PB3' },
|
||||
end: { componentId: 'tiny-ntc1', pinName: 'OUT' },
|
||||
color: '#aa44ff',
|
||||
},
|
||||
{
|
||||
id: 'tn-led',
|
||||
start: { componentId: 'attiny85', pinName: 'PB1' },
|
||||
end: { componentId: 'tiny-ntc-led', pinName: 'A' },
|
||||
color: '#ff4444',
|
||||
},
|
||||
{
|
||||
id: 'tn-lgnd',
|
||||
start: { componentId: 'attiny85', pinName: 'GND' },
|
||||
end: { componentId: 'tiny-ntc-led', pinName: 'C' },
|
||||
color: '#000000',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
// Merge legacy examples with circuit-focused examples (analog, digital gates,
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ PartSimulationRegistry.register('servo', {
|
|||
const pinManager = (avrSimulator as any).pinManager as
|
||||
| import('../PinManager').PinManager
|
||||
| undefined;
|
||||
|
||||
|
||||
const hasCpuCycles =
|
||||
typeof (avrSimulator as any).getCurrentCycles === 'function' &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
@ -381,14 +381,14 @@ PartSimulationRegistry.register('servo', {
|
|||
| undefined;
|
||||
if (pinManager) {
|
||||
let riseTime = -1; // cycle count at last rising edge
|
||||
|
||||
|
||||
const getCycles = () =>
|
||||
typeof (avrSimulator as any).getCurrentCycles === 'function'
|
||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
((avrSimulator as any).getCurrentCycles() as number)
|
||||
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(((avrSimulator as any).cpu?.cycles ?? 0) as number);
|
||||
|
||||
|
||||
const clockHz =
|
||||
typeof (avrSimulator as any).getClockHz === 'function'
|
||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
|
|||
|
|
@ -638,7 +638,7 @@ PartSimulationRegistry.register('dht22', {
|
|||
// After the MCU releases DATA HIGH and we begin responding, we ignore all
|
||||
// pin-change callbacks until the full waveform has been emitted.
|
||||
// DHT22 response is ~5 ms; gate for ~12.5 ms scaled to the CPU clock.
|
||||
|
||||
|
||||
const clockHz: number =
|
||||
typeof (simulator as any).getClockHz === 'function'
|
||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
|
|||
|
|
@ -645,7 +645,7 @@ PartSimulationRegistry.register('hc-sr04', {
|
|||
let distanceCm = parseFloat(el.distance) || 10; // default distance in cm
|
||||
|
||||
// ── ESP32 path: delegate protocol to backend QEMU worker ──
|
||||
|
||||
|
||||
const handledNatively =
|
||||
typeof (simulator as any).registerSensor === 'function' &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
@ -679,7 +679,6 @@ PartSimulationRegistry.register('hc-sr04', {
|
|||
const cleanup = simulator.pinManager.onPinChange(trigPin, (_: number, state: boolean) => {
|
||||
if (!state) return; // only react on TRIG HIGH
|
||||
if (typeof simulator.schedulePinChange === 'function') {
|
||||
|
||||
const clockHz: number =
|
||||
typeof (simulator as any).getClockHz === 'function'
|
||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ async function bootEngine(): Promise<Simulation> {
|
|||
await sim.start();
|
||||
singleton = sim;
|
||||
const dt = performance.now() - t0;
|
||||
|
||||
|
||||
console.log(`[SpiceEngine] boot in ${dt.toFixed(0)}ms`);
|
||||
return sim;
|
||||
})();
|
||||
|
|
@ -82,7 +82,6 @@ export async function runNetlist(netlist: string): Promise<SpiceResult> {
|
|||
|
||||
const dt = performance.now() - t0;
|
||||
if (dt > 200) {
|
||||
|
||||
console.log(`[SpiceEngine] slow solve: ${dt.toFixed(0)}ms`);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ export async function loadExample(
|
|||
|
||||
if (eb.code) {
|
||||
const AVR_BOARDS = ['arduino-uno', 'arduino-nano', 'arduino-mega', 'attiny85'];
|
||||
const filename = AVR_BOARDS.includes(boardId) ? 'sketch.ino' : 'main.cpp';
|
||||
const filename = AVR_BOARDS.includes(boardId) ? 'sketch.ino' : 'main.cpp';
|
||||
useEditorStore.getState().setActiveGroup(board.activeFileGroupId);
|
||||
useEditorStore.getState().loadFiles([{ name: filename, content: eb.code }]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 092ad4333d148ac57d28035ee5ae3e8f9b819313
|
||||
Subproject commit 81f87f158e954fa68969425226a7c08dac200ead
|
||||
Loading…
Reference in New Issue