GPIO & Digital I/O

Cuttlefish provides a unified, type-safe interface for interacting with the physical pins of your microcontroller. Unlike traditional embedded APIs where you pass integer pin numbers to functions, Cuttlefish treats pins as objects with specific, compile-time verified capabilities.


Basic Usage

To use a pin, you typically start by defining its mode. Cuttlefish uses fluent mode conversion to provide type safety: once you call .asOutput(), your editor will only suggest output-related methods.

import { D13, D2, HIGH } from '@typecad/board';

// Configure pin 13 as an output, initially HIGH (on)
const led = D13.asOutput(HIGH);

// Configure pin 2 as an input with internal pull-up resistor
const button = D2.asInputPullUp();

Output Operations

Output operations are available on any pin switched to output with .asOutput().

high() and low()

The most common way to control a digital state.

led.high(); // Set to logic HIGH (e.g. 5V or 3.3V)
led.low();  // Set to logic LOW (GND)

write(value: DigitalValue)

Use this when the value is determined by a variable or logic expression. DigitalValue is a type alias for boolean.

import { HIGH, LOW } from '@typecad/hal';

let state = HIGH;
led.write(state);
led.write(!state); // Set to LOW

toggle()

Inverts the current state of the pin. This is more efficient than reading the state and writing the inverse manually.

// Create a simple blinker
setInterval(() => {
  led.toggle();
}, 500);

pulse(duration: number)

Sets the pin HIGH for a specific number of milliseconds, then returns it to LOW.

// Briefly flash an indicator
led.pulse(50);

Input Operations

Input operations are available on any pin switched to input with .asInput() or .asInputPullUp().

Setup

The examples below use a pushbutton wired to D2. Configure it as an input with the internal pull-up resistor enabled — the returned InputPin handle carries the read methods:

import { D2 } from '@typecad/board';

// Button to GND; the internal pull-up keeps it HIGH until pressed.
const button = D2.asInputPullUp();

read()

Returns the current state as a boolean (true for HIGH, false for LOW).

const isPressed = button.read();

isHigh() and isLow()

Semantic helpers for cleaner conditional logic.

if (button.isLow()) {
  // Logic for a pressed button (assuming Pull-Up)
}

API Reference

Configuration Methods

MethodReturnsDescription
.asOutput(initial?)OutputPinSets mode to OUTPUT. Optional initial value sets state immediately.
.asInput()InputPinSets mode to INPUT (high-impedance — effectively disconnected).
.asInputPullUp()InputPinSets mode to INPUT with the internal pull-up resistor enabled.
.asInputPullDown()InputPinSets mode to INPUT with internal pull-down (if supported by hardware).

Output Handle (OutputPin)

MethodParametersDescription
high()Sets the pin state to HIGH.
low()Sets the pin state to LOW.
write(val)val: booleanSets the pin to the provided state.
toggle()Flips the pin state.
pulse(ms)ms: numberPulses the pin HIGH for the specified milliseconds.

Input Handle (InputPin)

MethodReturnsDescription
read()booleanReturns the current digital state.
isHigh()booleanReturns true if the pin is currently HIGH.
isLow()booleanReturns true if the pin is currently LOW.

Advanced Examples

1. Simple Debounced Toggle

This example toggles an LED whenever a button is pressed, with a simple delay for debouncing.

import { D2, D13, delay } from '@typecad/board';

const button = D2.asInputPullUp();
const led = D13.asOutput();

while (true) {
  if (button.isLow()) {
    led.toggle();
    delay(200); // Debounce delay
  }
}

2. Controlling Pin Groups

For operations on multiple pins (like an 8-bit LED bar or a parallel bus), use createPinGroup.

import { D2, D3, D4, D5, delay } from '@typecad/board';
import { createPinGroup } from '@typecad/hal';

// Define a group for 4 LEDs
const leds = createPinGroup([D2, D3, D4, D5]);

// Write a binary pattern (1010)
leds.writePattern(0b1010);

delay(1000);

// Clear all LEDs in the group
leds.fill(false);

3. Asynchronous Edge Waiting

Instead of polling in a loop, you can wait for a change (edge) on the pin — rising (LOW→HIGH) or falling (HIGH→LOW).

import { D2 } from '@typecad/board';

const sensor = D2.asInput();

async function monitor() {
  console.log("Waiting for trigger...");
  await sensor.waitForRising();
  console.log("Trigger detected!");
}

monitor();