# Systems and scenes

Firmware rarely runs alone. A system wires microcontrollers and parts together; a scene runs them, each with its own firmware, in lock-step virtual time.

## The system editor

In a project, open **Systems** and choose **New system**. The editor is a canvas:

- Drag in microcontrollers and parts, and wire their pins.
- Each microcontroller says which links it can join. The canvas refuses a wire whose link its models cannot run, and says why.
- Pick the firmware for each microcontroller: one you upload, or a starter for that part.
- **Run** shows every console and a bus monitor of UART bytes, CAN frames, SPI words and I2C transfers. Pause, change speed or stop, then read the report and verdict.

A system can hold other systems. To put a system in a 3D world, use the [Proving Ground](https://circuittwin.ai/docs/proving-ground).

## What runs today

| Link                                            | Scene section             | Notes                                                                                                                     |
| ----------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| UART                                            | uartLinks                 | Every UART model                                                                                                          |
| SPI and I2C                                     | spiLinks, i2cBuses        | The SPI slave or I2C target needs a model with that mode: the STM32 SPI and I2C models and the Nordic SPIS and TWIS today |
| CAN and CAN FD                                  | canBuses                  | Through transceivers in a system                                                                                          |
| RS-485 (UARTs through half-duplex transceivers) | rs485Buses                | Through transceivers in a system                                                                                          |
| Ethernet                                        | media with kind: ethernet | STM32 Ethernet MACs; write it in the scene, the system editor does not draw it                                            |

Every link between microcontrollers is `provisional`: it carries bytes and frames at the level the firmware observes, not line levels or electrical timing.

## A system file: two boards on a CAN bus

The editor stores systems as `ct.system/2`. The same document works from the CLI: parts, the wires between their pins, and buses. Older `ct.system/1` files still compile.

can-two-nucleo.system.json

```
{
  "schemaVersion": "ct.system/2",
  "id": "can-two-nucleo",
  "parts": [
    { "name": "a", "kind": "mcu", "board": "nucleo-f767zi", "firmware": "firmware/can-ping.elf" },
    { "name": "b", "kind": "mcu", "board": "nucleo-f767zi", "firmware": "firmware/can-pong.elf" },
    { "name": "xa", "part": "SN65HVD230" },
    { "name": "xb", "part": "SN65HVD230" }
  ],
  "buses": [{ "name": "can0", "kind": "can", "bitRateBps": 500000 }],
  "wires": [
    { "id": "a-tx", "from": { "part": "a", "pin": "PD1" }, "to": { "part": "xa", "pin": "D" } },
    { "id": "a-rx", "from": { "part": "a", "pin": "PD0" }, "to": { "part": "xa", "pin": "R" } },
    { "id": "a-gnd", "from": { "part": "a", "pin": "GND" }, "to": { "part": "xa", "pin": "GND" } },
    { "id": "xa-h", "from": { "part": "xa", "pin": "CANH" }, "to": { "bus": "can0", "pin": "CANH" } },
    { "id": "xa-l", "from": { "part": "xa", "pin": "CANL" }, "to": { "bus": "can0", "pin": "CANL" } },
    { "id": "b-tx", "from": { "part": "b", "pin": "PD1" }, "to": { "part": "xb", "pin": "D" } },
    { "id": "b-rx", "from": { "part": "b", "pin": "PD0" }, "to": { "part": "xb", "pin": "R" } },
    { "id": "b-gnd", "from": { "part": "b", "pin": "GND" }, "to": { "part": "xb", "pin": "GND" } },
    { "id": "xb-h", "from": { "part": "xb", "pin": "CANH" }, "to": { "bus": "can0", "pin": "CANH" } },
    { "id": "xb-l", "from": { "part": "xb", "pin": "CANL" }, "to": { "bus": "can0", "pin": "CANL" } },
    { "id": "gnd", "from": { "part": "a", "pin": "GND" }, "to": { "part": "b", "pin": "GND" } }
  ],
  "until": { "machine": "a", "marker": "A DONE" },
  "maxMs": 400
}
```

terminal

```
ct system compile can-two-nucleo.system.json --output can-two-nucleo.scene.json
ct scene run can-two-nucleo.scene.json
ct system convert old.system.json --output new.system.json   # ct.system/1 or a board, as ct.system/2
```

`ct system compile` reads the pin multiplexing of each microcontroller twin, works out which controller every wire belongs to, and writes the scene. It explains every wire it cannot use. Exit codes: `0` without errors, `1` with errors, `2` for an unreadable document. Problems carry a severity (`error`, `warning`, `info`), the wires they concern and a code such as `system.wire.same-direction` (TX wired to TX) or `system.wire.no-ground` (two boards share no ground).

## A scene: two boards on a UART link

You can also write a scene by hand:

uart-two-nucleo.scene.json

```
{
  "schemaVersion": "ct.scene/1",
  "id": "uart-two-nucleo",
  "machines": [
    { "name": "a", "board": "nucleo-f767zi", "firmware": "firmware/uart-a.elf" },
    { "name": "b", "board": "nucleo-f767zi", "firmware": "firmware/uart-b.elf" }
  ],
  "uartLinks": [
    {
      "name": "usart2",
      "baudBps": 115200,
      "ends": [
        { "machine": "a", "uart": "USART2" },
        { "machine": "b", "uart": "USART2" }
      ]
    }
  ],
  "until": { "machine": "a", "marker": "A DONE" },
  "maxMs": 200
}
```

terminal

```
ct scene run uart-two-nucleo.scene.json --junit scene.xml
ct scene run uart-two-nucleo.scene.json --cloud       # run it on the hosted service
```

The report lists every machine and every bus record. A run of the same scene gives the same report every time.

### Scene fields

| Field                   | Meaning                                                                                                      |
| ----------------------- | ------------------------------------------------------------------------------------------------------------ |
| machines\[\]            | name, board (built-in id, board file or MCU twin bundle) and firmware                                        |
| uartLinks\[\]           | name, baudBps, ends (machine, uart)                                                                          |
| spiLinks\[\]            | name, clockHz, a master and its slaves (machine, spi)                                                        |
| i2cBuses\[\]            | name, a controller and its targets (machine, i2c)                                                            |
| canBuses\[\]            | name, nodes (machine, controller such as CAN1 or FDCAN1), timing (nominalBps, and dataBps for CAN FD)        |
| rs485Buses\[\]          | name, baudBps, frameBits (default 8N1), nodes (machine, uart, optional driverEnable and receiverEnable pins) |
| media\[\]               | name, kind (ethernet), nodes (machine, peripheral such as ETH)                                               |
| circuits\[\]            | Analog circuits solved beside a machine; their node voltages reach the machine’s converters                  |
| until, maxMs, quantumNs | Stop when a machine prints a marker; the virtual time budget; the lock-step quantum                          |
| registers\[\]           | Peripheral registers to report after the run, read without side effects                                      |
