Hardware Simulation

@typecad/hal/sim runs your program's logic in Node.js against a simulated board — virtual pins, buses, and mock devices. No board attached, no flashing: CI jobs and failure-path tests that would be impossible on real hardware.

function

createSimBoard

Builds a SimBoard — a virtual board with the pin and bus populations you ask for. Typed accessors (.digital(n), .i2c(0), ...) throw if that pin or bus doesn't exist, so the sim stays honest about the hardware.

Example first

sim.test.ts
import { createSimBoard } from '@typecad/hal/sim';

const board = createSimBoard({ digitalPinCount: 14 });
const pin = board.digital(13);

pin.asOutput();
pin.write(1);
if (!pin.isHigh()) throw new Error('pin did not set');

pin.injectValue(0);                       // pretend the wire changed
if (!pin.isLow()) throw new Error('inject failed');

const history = pin.getHistory();         // every write, with timestamps

SimBoardConfig

OptionDefaultMeaning
digitalPinCount14Digital pins
analogPinCount6Analog-capable pins
i2cBusCount / spiBusCount / uartCount1Bus population
pwmPins / interruptPins[]Pins with PWM or interrupt capability
uartRxBufferSize / uartTxBufferSize256Serial buffer sizes (bytes)
pattern

mock devices

Attach JavaScript objects as I2C/SPI peripherals: scripted register responses for the happy path, empty reads for fault injection, and an operation log proving exactly what your code put on the wire.

Example first

i2c-mock.ts
import { createSimBoard } from '@typecad/hal/sim';

const board = createSimBoard({});
const i2c = board.i2c(0);

// a minimal BME280: respond to register reads
i2c.attachDevice(0x76, {
  read(register: number, count: number): number[] {
    if (register === 0xD0) return [0x60];   // chip id
    return new Array(count).fill(0);
  },
  write(register: number, data: number[]): void {},
});

const id = i2c.device(0x76).read(0xD0, 1);
if (id[0] !== 0x60) throw new Error('wrong chip');

i2c.getLog();        // every read/write with address, register, data, timestamp
i2c.clearLog();

SPI — keyed by chip select

spi-mock.ts
// SPI mocks are keyed by chip-select pin
const board = createSimBoard({});
const spi = board.spi(0);
const cs = board.digital(10);

spi.attachDevice(cs, {
  transfer(mosi: number[]): number[] {
    return [0xEF, 0x40, 0x18];               // JEDEC id bytes
  },
});

const id = spi.device(cs).readRegister(0x9F, 3);

What can be simulated

Simulator classWhat it does
SimDigitalPinwrite/read/toggle, input pulls, injected values, write history
SimAnalogPininject raw counts or volts, resolution and reference voltage
SimPWMPinduty writes, percent readback
SimInterruptPinfire interrupts and pin transitions by hand
SimSerialPortprint/write into a TX buffer you can peek at, inject RX bytes
SimI2CBusattach mock devices, operation log, NACK on unknown addresses
SimSPIBusattach mock devices by chip-select pin, transfer logs
© 2026 typeCAD — code-defined electronics github