# CRUMB Circuit Simulation

Running HIL LISP scripts inside the CRUMB circuit simulator via LISP→Arduino-C transpilation.

## Overview

CRUMB is a circuit simulator with an Arduino Nano and virtual components. `hil-cli crumb` transpiles HIL LISP to Arduino C, injects it into a `.cru` circuit file, and opens CRUMB for simulation.

## Quick Start

```powershell
# Transpile and open in CRUMB
hil-cli crumb src/main.hil --open

# Transpile only (generate .cru without opening)
hil-cli crumb src/main.hil

# Strict mode (fail on unsupported ops)
hil-cli crumb src/main.hil --strict
```

## How It Works

1. **LISP → C Transpilation**: AST is compiled to Arduino C source
2. **Template Cloning**: `.cru` template is copied and modified
3. **Code Injection**: C source is injected into the Nano component's first `<xsd:string>` element
4. **Name Registration**: `.cru` is copied to Documents and registered in `%APPDATA%\recent.log`
5. **CRUMB Launch**: CRUMBWPF.exe is started with the `.cru` file

## Transpiler Features

### Supported HIL Ops in CRUMB

| Category | Operations |
|----------|------------|
| **Digital I/O** | WRITE D, READ D, SET, TOGGLE |
| **Analog I/O** | WRITE A, WRITE P, READ A, PWM |
| **Timing** | DELAY, MILLIS (via Arduino core) |
| **Math** | +, -, *, /, RANDOM, MAP, CONSTRAIN |
| **Control Flow** | IF, WHILE, DO, DEFUN, INCLUDE |
| **Macros** | User-defined macros with return values |
| **Buzzer** | TONE (passive buzzer on D11) |
| **Sensors** | LM35, ULTRASONIC (HC-SR04), DHT11/DHT22 |
| **Communication** | I2C (bit-bang), LCD (4-bit mode), Serial |
| **Motion** | SERVO (PWM), PID controller |
| **Advanced** | STRUCT, NEW, NeoPixel, MP3, SD, RTC, Interrupts |

### Real Implementations

All protocols use **real Arduino API** — no mocks. The generated C works on
both CRUMB simulator and real Arduino hardware.

| Operation | Implementation |
|-----------|----------------|
| LM35 | `map(analogRead(pin), 0, 1023, 0, 500)` |
| ULTRASONIC | `pulseIn(echo, HIGH)` with trigger pulse |
| DHT-READ | Bit-banged DHT protocol with checksum |
| SERVO | PWM pulse via `micros()` timing |
| I2C-WRITE/READ | Bit-banged I2C (SDA/SCL pins) |
| LCD-INIT/CLEAR/PRINT | 4-bit mode with RS/EN/D4-D7 pins |
| PID-INIT/CLOSED-LOOP | Pure math PID controller |
| ATTENTION/ON-EVENT | `attachInterrupt()` |
| ON-CHANGE | `attachInterrupt(..., CHANGE)` |
| NEO-SET/SHOW | Bit-banged WS2812B protocol |
| MP3-PLAY/VOL | DFPlayer Mini serial commands |
| SD-WRITE | SPI transfer |
| RTC-READ | DS1307 via I2C |
| BATCH-BEGIN/END | No-op (host concept) |
| AUTOPILOT-BEGIN/END | No-op (firmware concept) |

## Code Generation Pattern

The transpiler generates Arduino-compatible C:

```c
#include <Arduino.h>

// User variables (static ints in loop scope)
static int _hil_ran = 0;

// DEFUN → C functions (names sanitized with cIdent)
int DUAL_BLINK() {
  digitalWrite(13, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  delay(500);
  return 0;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (!_hil_ran) {
    _hil_ran = 1;
    DUAL_BLINK();
  }
}
```

### Name Sanitization

HIL LISP names with hyphens (e.g., `DUAL-BLINK`) are converted to valid C identifiers (`DUAL_BLINK`). All user-defined names are uppercased.

### Run-Once Guard

Scripts are wrapped in `if (!_hil_ran)` to prevent re-execution when CRUMB's C interpreter calls `loop()` repeatedly.

### Empty Else Suppression

The transpiler suppresses empty `else {}` blocks for cleaner generated code.

### MAP Guard

`MAP` in generated C checks for degenerate ranges (`inMax == inMin`) and returns 0 to prevent division-by-zero.

### TONE Support

```lisp
(TONE 11 1000 500)  ; Pin 11, 1000 Hz, 500 ms
```

Generates `tone(11, 1000, 500)` — works with CRUMB's passive buzzer on D11.

## CRUMB Requirements

### Components

Your `.cru` must contain at minimum:
- **Arduino Nano** (toolID 20) — runs the generated code
- **Virtual Serial Monitor** — displays `Serial.print` output

### Buzzer

For sound: use a **passive buzzer** component (not active buzzer) connected to pin D11. The transpiler generates `tone()` calls which require a passive buzzer to produce audio.

### Simulation Frequency

CRUMB runs at a low simulation frequency. The buzzer may not be audible at default settings. Increase CRUMB's simulation frequency if needed (see CRUMB documentation).

## Common Issues

### Generated code uses underscores but I wrote hyphens

HIL LISP names with hyphens are converted to underscores in C. `DUAL-BLINK` becomes `DUAL_BLINK`. This is expected — the transpiler handles name sanitization automatically.

### `CRUMBWPF.exe` doesn't open

1. Check CRUMB installation path
2. Set `HIL_CRUMB_DIR` if not in default location
3. Use `hil-cli doctor` to verify CRUMB is detected

### `.cru` file opens but Nano does nothing

1. Press **RUN** button in CRUMB
2. Check serial monitor is open (baud 9600)
3. Look for `[HIL-CRUMB] ...` mock messages in serial output

### Division by zero

MAP with degenerate ranges (`inMax == inMin`) is guarded. For manual division by zero, the result is 0 (not a crash).

### UTF-8 BOM errors

HIL scripts must be UTF-8 without BOM. Re-save in your editor as UTF-8 (not "UTF-8 with BOM").

### Strict mode failures

`--strict` fails if the script uses unsupported ops. Remove the op or drop `--strict` (the op will be mocked at runtime).

## Example

```lisp
; buzzer_test.hil
(SET pin 11)
(SET freq 1000)
(SET dur 500)

(WRITE D pin 1)
(TONE pin freq dur)
(LOG "Buzzer on pin " pin " at " freq " Hz")
```

Transpiles to:

```c
#include <Arduino.h>

static int _hil_ran = 0;
static int PIN = 11;
static int FREQ = 1000;
static int DUR = 500;

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (!_hil_ran) {
    _hil_ran = 1;
    digitalWrite(PIN, HIGH);
    tone(PIN, FREQ, DUR);
    Serial.print("Buzzer on pin ");
    Serial.print((int)(PIN));
    Serial.print(" at ");
    Serial.print((int)(FREQ));
    Serial.print(" Hz");
    Serial.println();
  }
}
```

## Troubleshooting

See [TROUBLESHOOTING.md](TROUBLESHOOTING.md) for more issues.

## Further Reading

- [HIL-LISP-REFERENCE.md](HIL-LISP-REFERENCE.md) — Full language reference
- [CLI.md](CLI.md) — CLI command reference
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) — Common issues and fixes
