# CAN Protocol — CAN IO Board Bus: **500 kbit/s**, 11-bit (standard) identifiers, classic CAN 2.0. Base ID: **0x100** (configurable in `firmware/include/config.h`). | ID | Direction | Purpose | |--------------|-------------|-------------------------------| | base + 0 = `0x100` | board → bus | Status frame | | base + 1 = `0x101` | bus → board | Command frame | Bit numbering in all bitmaps: bit0 = IN1/OUT1, bit1 = IN2/OUT2, … 1 = active. ## Status frame — ID 0x100, DLC 8 Sent every second (heartbeat), immediately on any input/output change, in response to `GET_STATUS`, and once at boot. | Byte | Meaning | |------|------------------------------------------------| | 0 | Input bitmap (bit0=IN1 … bit3=IN4) | | 1 | Output bitmap (bit0=OUT1, bit1=OUT2) | | 2 | Reason: 0=periodic, 1=change, 2=request, 3=boot| | 3 | Reserved (0) | | 4–7 | Uptime in seconds, uint32 little-endian | Example: `05 02 01 00 3C 00 00 00` → IN1+IN3 active, OUT2 on, reason=change, uptime 60 s. ## Command frame — ID 0x101 Byte 0 selects the command. Malformed/unknown frames are ignored. | Cmd | Name | DLC | Layout | |------|-------------|-----|--------------------------------------------| | 0x00 | GET_STATUS | ≥1 | `[00]` → board replies with a status frame | | 0x01 | SET_OUTPUT | ≥3 | `[01, index, value]` index 0-based, value 0=off / ≠0=on | | 0x02 | SET_ALL | ≥3 | `[02, mask, values]` outputs where mask bit=1 get the corresponding values bit | | 0x03 | TOGGLE | ≥2 | `[03, index]` | Examples (send to `0x101`): | Bytes | Effect | |--------------|---------------------------| | `00` | request status | | `01 00 01` | OUT1 on | | `01 01 00` | OUT2 off | | `02 03 03` | OUT1 + OUT2 both on | | `02 03 00` | OUT1 + OUT2 both off | | `03 00` | toggle OUT1 | Every accepted output change triggers an immediate status frame (reason = change), so the bus always confirms what actually happened — there is no separate ACK. ## Local rules (run on the board itself) Evaluated on the activation edge of an input; releasing does nothing (outputs latch): | Input | Action | |-------|-----------| | IN1 | OUT1 → ON | | IN2 | OUT1 → OFF| | IN3 | OUT2 → ON | | IN4 | OUT2 → OFF| Inputs already active at power-up are reported but do **not** fire rules.