Safety-Critical Firmware

A safety surface for the firmware, not a certification: voted and verified I/O, radiation-tolerant storage, bounds-checked arithmetic, and ASIL-graded rule checks — all compiled into the program you'd have written anyway.

functions

safe.read / safe.write

I/O with a verdict. read samples the pin three times and votes (2-of-3), then checks the pin's mode — reading an output-configured pin is a configuration fault, not a signal fault. write verifies with a readback.

Example first

safe-read.ts
import { safe, SafetyFaultCategory } from '@typecad/cuttlefish/safety';
import { GPIO, BUTTON_PIN } from '@typecad/hal';

const pin = new GPIO(BUTTON_PIN, GPIO.INPUT);

safe.read(pin).ok((r) => render(r.value)).fail((r) => {
  // r.value is the 2-of-3 vote anyway — use it with care
  if (r.category === SafetyFaultCategory.Configuration) {
    // the pin is configured as an output — a code bug, not noise
  }
});
safe-write.ts
safe.write(enable_pin, 1).fail((r) => {
  // write-then-readback mismatch — the actuator isn't following
});

Results carry value, category (Signal vs Configuration), a code (stuck-high, stuck-low, vote disagreement, mode mismatch, write mismatch), and ok() / fail() continuation methods.

types

SafeVariable / SafeInt

Ambient global types — declared in the generated env file, no import. SafeVariable is triple-redundant storage with inverted-redundancy validation: a bit flip in one replica is detected and repaired. SafeInt is chainable arithmetic that clamps at the type's limits and raises a sticky fault.

Example first

safe-variable.ts
let position: SafeVariable<number> = SafeVariable(0);

position.set(42);
if (position.valid()) {
  display(position.get());
}
// bit-flip a replica and the XOR invariant repairs it — hasFault() reports it
safe-int.ts
let total: SafeInt<number> = SafeInt(2147483640);

total.add(5);          // clamps at INT32_MAX — sticky fault
if (total.hasFault()) {
  log('overflow');
}
total.reset(0);        // clears the fault
reference

ASIL annotations

Comment decorators grade functions into the ISO 26262 rule set. Unannotated functions are quality-managed and unchecked; annotated ones must satisfy the rules for their level or the build fails.

Example first

annotations.ts
// @asilD — deepest rule set for this function
function deploy(flux: number): number { ... }

// @asilC — recursion + loop checks
// @asilB — recursion check
// no annotation = quality-managed, no rules
RuleFromCatches
RecursionASIL B and upAny recursive call in a safety function
Dynamic allocationASIL Dnew / array growth outside setup — nothing allocates at runtime
Unbounded loopsASIL C and upwhile(true) without a bound
InitializationASIL DVariables used in a safety function but never initialized in setup
GotoASIL C and upIncluding the labeled-break shapes
© 2026 typeCAD — code-defined electronics github