@typecad/simulator
v1.0.0-alpha.6
Published
Hardware simulation runtime for TypeCAD — test HAL code in Node.js without hardware
Downloads
527
Maintainers
Readme
@typecad/simulator
Node.js hardware simulation runtime for TypeCAD.
Overview
@typecad/simulator provides a simulated hardware runtime for TypeCAD firmware and tests. It exposes simulated GPIO pins, serial ports, I2C buses, SPI buses, PWM pins, and interrupt pins so you can verify hardware logic without using a physical board.
When to use the simulator
@typecad/simulator is best for testing and validating hardware-facing logic in Node.js before you use a real board. It is not a transpiler output checker, and it does not replace @typecad/expect for firmware-level hardware tests.
Use the simulator when you want to:
- unit test control logic for buttons, LEDs, and buses
- verify that a parser sends the correct serial bytes
- mock sensor input through analog or I2C injection
- exercise interrupt-driven code paths without physical hardware
- run CI-friendly tests that are fast and deterministic
Do not use it for:
- verifying TypeCAD transpilation output
- measuring real ADC noise or analog timing
- checking exact microsecond timing behavior
Quick start
import { createSimBoard } from '@typecad/simulator';
const board = createSimBoard({ boardType: 'arduino-uno' });
const button = board.digital(2).asInputPullUp();
const led = board.digital(13).asOutput();
button.injectValue(0); // simulate a pressed active-low button
if (!button.read()) {
led.high();
}
console.log(led.getBitValue()); // 1Example: button-driven LED logic
This pattern is the real value of the simulator: you can test logic driven by external inputs without a board.
import { describe, it, expect } from 'vitest';
import { createSimBoard } from '@typecad/simulator';
function updateLed(button: any, led: any) {
if (!button.read()) {
led.high();
} else {
led.low();
}
}
describe('button toggle logic', () => {
it('turns the LED on when the button is pressed', () => {
const board = createSimBoard({ boardType: 'arduino-uno' });
const button = board.digital(2).asInputPullUp();
const led = board.digital(13).asOutput();
button.injectValue(0); // press button
updateLed(button, led);
expect(led.getBitValue()).toBe(1);
});
});How to use
Create a simulated board
Use createSimBoard() with a board type and optional custom counts:
boardType— board identifier such asarduino-unoorarduino-nano. Known board types carry default PWM/interrupt pin maps; custom/unknown types have no capability pins unless declared viapwmPins/interruptPins.digitalPinCount— number of digital pinsanalogPinCount— number of analog pinsuartCount— number of serial portsi2cBusCount— number of I2C busesspiBusCount— number of SPI busespwmPins/interruptPins— override the capability pin numbers (defaults to the board type's map, or empty for custom boards)
Access simulated peripherals
The SimBoard instance exposes typed accessors:
board.digital(pin)—SimDigitalPinboard.analog(pin)—SimAnalogPinboard.pwm(pin)—SimPWMPinboard.interrupt(pin)—SimInterruptPinboard.serial(port)—SimSerialPortboard.i2c(bus)—SimI2CBusboard.spi(bus)—SimSPIBus
Simulating a real board package
When you already depend on a @typecad/board-* package, use createBoardFromDefinition() to build a SimBoard whose pin layout, PWM/interrupt pins, ADC resolution/reference, and bus counts match the real board — instead of hardcoding them in createSimBoard():
import { ArduinoUno } from '@typecad/board-arduino-uno';
import { createBoardFromDefinition } from '@typecad/simulator';
const board = createBoardFromDefinition(ArduinoUno);
board.digital(13).asOutput().high(); // LED on PB5 (pin 13)
board.pwm(9).pwm(50); // PWM on PB1 (pin 9)
board.analog(0).injectVoltage(2.5); // A0, 10-bit ADC, 5V referenceThis is the recommended path for board-specific tests. The board package must be built so its BoardDefinition is importable at runtime. See the Software-Defined Hardware docs for the full list of derived fields.
Verify state and reset
The simulated board supports reset and state inspection, making it useful for unit tests and firmware validation without hardware:
board.digital(13).output();
board.digital(13).high();
expect(board.digital(13).getBitValue()).toBe(1);
board.reset();
expect(board.digital(13).getBitValue()).toBe(0);HAL compatibility
@typecad/simulator is built on the same hardware abstraction contract used by the rest of the ecosystem. The simulator package owns the runtime contract hierarchy (BasePin, PWMPin, AnalogPin, InterruptPin, II2CBus, ISPIBus, ISerialPort, and the I2CStatus/SPIStatus/UARTStatus enums) in its own contracts.ts, and re-exports it for consumers. Primitive and protocol-shape types (PinMode, DigitalValue, AnalogValue, InterruptHandler, I2CAddress, SPIMode, SPIBitOrder, SPISettings) are imported from @typecad/hal:
SimDigitalPinimplementsBasePinand digital pin semantics.SimAnalogPinimplementsAnalogPinsemantics.SimPWMPinimplementsPWMPinsemantics (includinggetPwmFrequency()/getPwmResolution()).SimInterruptPinimplementsInterruptPinsemantics.SimSerialPortimplementsISerialPort/ UART communication semantics.SimI2CBusandSimSPIBusexpose the same bus-style APIs expected by TypeCAD HAL consumers.
How the simulator uses HAL concepts
PinModevalues are imported from@typecad/haland used to track simulated pin direction and pull state.- capability flags like
digitalInput,pwm, andinterruptare modeled using the same type definitions that HAL packages expose for pin capabilities. - serial, I2C, and SPI simulation classes rely on the shared TypeCAD bus interfaces to ensure host code can interact with them using the same method names and semantics as real hardware.
createSimBoard()selects default PWM and interrupt pin sets by board type, matching the physical pin layout conventions used by TypeCAD board packages.
This makes the simulator a practical way to validate hardware logic and unit tests while staying aligned with TypeCAD's HAL abstraction layer.
