> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crucihil.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Rig Backends

> Available backends for CAN, Ethernet, power, GPIO, and DoIP

Each interface section in the rig TOML specifies a `backend` field. This determines which driver is used at runtime. Switching backends requires only a TOML change — test code is unaffected.

## CAN backends

### `virtual`

In-process simulation. No hardware or OS dependencies. Frames are passed through an in-memory queue.

```toml theme={null}
[rig.can.can0]
interface = "can0"
bitrate   = 500000
backend   = "virtual"
```

Best for: CI, local development, unit tests, any environment without CAN hardware.

### `socketcan`

Linux SocketCAN. Uses the `python-can` SocketCAN interface. Requires the CAN interface to be configured in the OS before connecting:

```bash theme={null}
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up
```

```toml theme={null}
[rig.can.powertrain]
interface = "can0"
bitrate   = 500000
fd        = false
backend   = "socketcan"
```

Best for: Linux bench machines with SocketCAN adapters (Kvaser, EMS, or any native CAN interface). No extra install needed — `python-can` ships with the base package.

### `peak`

PEAK PCAN adapters (PCAN-USB, PCAN-PCI). Uses the `python-can` PCAN interface.

```toml theme={null}
[rig.can.powertrain]
interface = "PCAN_USBBUS1"
bitrate   = 500000
fd        = false
backend   = "peak"
```

For CAN-FD:

```toml theme={null}
[rig.can.powertrain]
interface = "PCAN_USBBUS1"
bitrate   = 500000
fd        = true
backend   = "peak"
```

Best for: Windows and Linux benches with PEAK USB or PCIe adapters. No extra install needed — `python-can` ships with the base package.

### Custom backend (module path)

Any Python class implementing `AbstractCANBackend` can be loaded by specifying its module path. Use `"module.path:ClassName"`, or a bare module path that exports a `Backend` attribute:

```toml theme={null}
[rig.can.custom_bus]
interface = "COM3"
bitrate   = 500000
backend   = "myorg.my_can_adapter:MyCANBackend"
```

CruciHiL resolves the path via `importlib`. This works for every interface type — CAN, SOME/IP, DoIP, power, GPIO, UDP, and UDS sections all accept a module path in their `backend` field. The class must implement:

```python theme={null}
from crucihil.hal.backends.base import AbstractCANBackend

class MyCANBackend(AbstractCANBackend):
    async def connect(self, interface: str, bitrate: int, fd: bool = False) -> None: ...
    async def disconnect(self) -> None: ...
    async def send(self, arb_id: int, data: bytes) -> None: ...
    def add_listener(self, cb) -> None: ...
    def remove_listener(self, cb) -> None: ...
```

Generate a stub with:

```bash theme={null}
crucihil scaffold --adapter can --name MyCANAdapter
```

## DoIP backends

### `virtual`

In-process DoIP simulation. Responds to entity discovery and routing activation without network hardware.

```toml theme={null}
[rig.ethernet.eth0]
interface      = "eth0"
ip             = "127.0.0.1"
doip_backend   = "virtual"
someip_backend = "python-someip"
```

### `python-doip`

Real DoIP transport using the `python-doip` library. Requires an actual DoIP gateway on the network.

```toml theme={null}
[rig.ethernet.chassis_eth]
interface      = "eth1"
ip             = "169.254.0.1"
doip_backend   = "python-doip"
someip_backend = "python-someip"
```

Best for: ECUs with DoIP-capable diagnostic interfaces (many Tier 1 ECUs support ISO 13400-2).

## SOME/IP backends

### `python-someip`

SOME/IP Events and Fields. Currently backed by the in-process virtual SOME/IP implementation — used in the virtual rig. Scope: Events and Fields only (Methods come later).

```toml theme={null}
[rig.ethernet.eth0]
someip_backend = "python-someip"
```

### `vsomeip`

Real SOME/IP via the vsomeip wrapper backend.

```toml theme={null}
[rig.ethernet.chassis_eth]
someip_backend = "vsomeip"
```

## Power backends

### `virtual_power`

In-process power simulation. Tracks on/off state in memory. No hardware dependency.

```toml theme={null}
[rig.power.ecu_main]
backend = "virtual_power"
default = "on"
```

### `gpio_relay`

Controls power via a GPIO output pin. Typically used with a relay board connected to a GPIO header.

<Warning>
  `gpio_relay` and `bench_psu` are reserved names whose hardware implementations
  have not shipped yet — using one fails at rig init with guidance. Until they
  ship, use a [custom power backend](#custom-power-backend) via module path.
</Warning>

```toml theme={null}
[rig.power.ecu_main]
backend  = "gpio_relay"
gpio_pin = 18
default  = "off"
```

### `bench_psu`

Controls a bench power supply over serial. Supported instruments include Keysight E3631A and compatible.

```toml theme={null}
[rig.power.ecu_12v]
backend = "bench_psu"
port    = "/dev/ttyUSB0"
model   = "keysight_e3631a"
default = "off"
```

### Custom power backend

```toml theme={null}
[rig.power.custom_supply]
backend = "myorg.bench_hardware:CustomPSUBackend"
default = "off"
```

Implement `AbstractPowerBackend`:

```python theme={null}
from crucihil.hal.backends.base import AbstractPowerBackend

class CustomPSUBackend(AbstractPowerBackend):
    async def connect(self) -> None: ...
    async def disconnect(self) -> None: ...
    async def on(self) -> None: ...
    async def off(self) -> None: ...
    async def read_voltage(self) -> float: ...
    async def set_voltage(self, voltage: float) -> None: ...
```

## GPIO backends

### `virtual_gpio`

In-process GPIO simulation. Default for all GPIO pins in virtual mode.

```toml theme={null}
[rig.gpio]
ignition_enable = { pin = 22, direction = "out", default = false, backend = "virtual_gpio" }
```

### `linux_gpio`

Linux GPIO for bench machines and single-board computers with a GPIO header.

<Warning>
  `linux_gpio` is a reserved name whose hardware implementation has not shipped
  yet — using it fails at rig init with guidance. Until it ships, use a
  [custom GPIO backend](#custom-gpio-backend) via module path.
</Warning>

```toml theme={null}
[rig.gpio]
ignition_enable = { pin = 22, direction = "out", default = false, backend = "linux_gpio" }
```

### Custom GPIO backend

```toml theme={null}
[rig.gpio]
relay_1 = { pin = 1, direction = "out", default = false, backend = "myorg.io_board:IOBoardGPIO" }
```

Implement `AbstractGPIOBackend`:

```python theme={null}
from crucihil.hal.backends.base import AbstractGPIOBackend

class IOBoardGPIO(AbstractGPIOBackend):
    async def connect(self) -> None: ...
    async def disconnect(self) -> None: ...
    async def setup_pin(self, name: str, pin: int, direction: str, default: bool) -> None: ...
    async def set(self, name: str, high: bool) -> None: ...
    async def read(self, name: str) -> bool: ...
```

## UDP backends

### `virtual_udp`

In-process UDP simulation for `[rig.udp.<name>]` sections. Currently the only built-in UDP backend — a real UDP transport ships in a later phase. Custom module paths are accepted.

```toml theme={null}
[rig.udp.telemetry]
interface = "eth0"
ip        = "192.168.1.10"
port      = 5005
backend   = "virtual_udp"
```

## UDS backends

### `virtual_uds`

In-process UDS simulation for the `[rig.uds]` section. Currently the only built-in UDS backend — custom module paths are accepted. UDS over DoIP does not use this section; it is handled by `[rig.ethernet]` + `[rig.ecus]`.

```toml theme={null}
[rig.uds]
backend = "virtual_uds"
timeout = 2.0
```

## Custom protocol transports

`[rig.custom.<name>]` sections pair a codec with a transport. Built-in transports are the virtual twins:

| Backend            | Shape                                             |
| ------------------ | ------------------------------------------------- |
| `virtual_datagram` | Datagram (CAN-like, message-oriented)             |
| `virtual_stream`   | Stream (UART/TCP-like, framer delimits)           |
| `virtual_spi`      | Transactional (register-map peripheral emulation) |
| `virtual_i2c`      | Transactional (register-map peripheral emulation) |

```toml theme={null}
[rig.custom.motor_bus]
backend     = "virtual_datagram"
definitions = "defs/motor_protocol.yaml"
codec       = "declarative"
kind        = "datagram"
```

Real-hardware transports are loaded via module path (`backend = "myorg.uart_bridge:UARTTransport"`). Generate a stub with `crucihil scaffold --adapter datagram|stream|transactional|codec`. See [Custom Protocols](/guides/custom-protocols) for the declarative wire-format YAML and the round-trip verification harness.

## Backend selection summary

| Interface       | Development / CI                                                      | Linux bench                 | Windows bench   | Custom HW   |
| --------------- | --------------------------------------------------------------------- | --------------------------- | --------------- | ----------- |
| CAN             | `virtual`                                                             | `socketcan`                 | `peak`          | module path |
| DoIP            | `virtual`                                                             | `python-doip`               | `python-doip`   | module path |
| SOME/IP         | `python-someip`                                                       | `python-someip`             | `python-someip` | —           |
| Power           | `virtual_power`                                                       | `gpio_relay` or `bench_psu` | `bench_psu`     | module path |
| GPIO            | `virtual_gpio`                                                        | `linux_gpio`                | —               | module path |
| UDP             | `virtual_udp`                                                         | module path                 | module path     | module path |
| UDS             | `virtual_uds`                                                         | module path                 | module path     | module path |
| Custom protocol | `virtual_datagram` / `virtual_stream` / `virtual_spi` / `virtual_i2c` | module path                 | module path     | module path |

## See also

* [Rig Configuration Overview](/rig-config/overview)
* [`crucihil scaffold --adapter`](/cli/scaffold) — generate custom backend stubs
