# API reference

Binary protocol between the UPAN motion MCU and a host (the network module over UART, or a PC over USB CDC), encoded with protobuf; each message travels in a COBS frame with a version byte and CRC-16. All quantities are integer metric base units (bu): µm, µm/s and µm/s² for a linear axis, millidegrees, m°/s and m°/s² for a rotary axis; inches never appear in the protocol and are converted by the host, and 0 for speed or acceleration in a command means "use the SoftConfig default".

Package `upan.v1`.

## Messages

### HostMessage

Everything the host sends to the motion core; every HostMessage gets exactly one `Response` with the same `seq`.

| Field | Type | No. | Description |
|---|---|---|---|
| `seq` | `uint32` | 1 | Sequence number, incremented by the host and echoed in the `Response`; 0 is reserved. |
| `move_abs` (oneof body) | `MoveAbs` | 10 | Move to an absolute position. |
| `move_rel` (oneof body) | `MoveRel` | 11 | Move by a relative distance. |
| `jog` (oneof body) | `Jog` | 12 | Continuous move that runs only while the host keeps refreshing it. |
| `stop` (oneof body) | `Stop` | 13 | Decelerate to a stop; also stops a running program. |
| `estop` (oneof body) | `EStop` | 14 | Software emergency stop. |
| `home` (oneof body) | `Home` | 15 | Run the homing sequence configured in `HardConfig.home_method`. |
| `set_position` (oneof body) | `SetPosition` | 16 | Declare the current position without moving. |
| `move_linear` (oneof body) | `MoveLinear` | 17 | Move several axes together along a straight line (firmware v2: later; now `ERROR_UNSUPPORTED`). |
| `travel_discover` (oneof body) | `TravelDiscover` | 18 | Measure the axis travel automatically, from limit switch to limit switch. |
| `program_begin` (oneof body) | `ProgramBegin` | 20 | Start uploading a motion program. |
| `program_chunk` (oneof body) | `ProgramChunk` | 21 | Upload the next block of program instructions. |
| `program_commit` (oneof body) | `ProgramCommit` | 22 | Validate the uploaded program and make it active. |
| `program_run` (oneof body) | `ProgramRun` | 23 | Run the active program. |
| `program_pause` (oneof body) | `ProgramPause` | 24 | Pause the running program after the current move. |
| `program_resume` (oneof body) | `ProgramResume` | 25 | Resume a paused program. |
| `program_abort` (oneof body) | `ProgramAbort` | 26 | Stop the program and reset its instruction counter. |
| `soft_config_get` (oneof body) | `SoftConfigGet` | 30 | Read the working limits (`SoftConfig`). |
| `soft_config_set` (oneof body) | `SoftConfigSet` | 31 | Write the working limits (`SoftConfig`). |
| `hard_config_get` (oneof body) | `HardConfigGet` | 32 | Read the machine limits (`HardConfig`). |
| `hard_config_set` (oneof body) | `HardConfigSet` | 33 | Write the machine limits (`HardConfig`); accepted only over USB and inside the physical-presence window. |
| `output_set` (oneof body) | `OutputSet` | 40 | Set a digital output. |
| `info_get` (oneof body) | `InfoGet` | 50 | Read device information (versions, serial, capabilities). |
| `telemetry_config` (oneof body) | `TelemetryConfig` | 51 | Set the telemetry rate. |
| `fault_clear` (oneof body) | `FaultClear` | 52 | Clear a fault state. |
| `heartbeat` (oneof body) | `Heartbeat` | 53 | Keep-alive from the host. |
| `reset` (oneof body) | `Reset` | 73 | Restart the controller; only while nothing moves. |

### DeviceMessage

Everything the MCU sends to the host.

| Field | Type | No. | Description |
|---|---|---|---|
| `response` (oneof body) | `Response` | 1 | Reply to a `HostMessage`, with the same `seq`. |
| `telemetry` (oneof body) | `Telemetry` | 2 | Periodic state report; the rate is set by `TelemetryConfig`. |
| `event` (oneof body) | `Event` | 3 | Asynchronous event. |
| `heartbeat` (oneof body) | `Heartbeat` | 4 | Keep-alive from the device. |

### Response

Acknowledgement (ACK) or rejection (NACK) of one host command, with details for a rejection and data for `*Get` commands.

| Field | Type | No. | Description |
|---|---|---|---|
| `seq` | `uint32` | 1 | `seq` of the `HostMessage` this answers. |
| `error` | `ErrorCode` | 2 | `ERROR_NONE` means the command was accepted (ACK); any other code is a rejection (NACK). |
| `limit_violation` | `LimitViolation` | 3 | For `ERROR_LIMIT_EXCEEDED`: which limit was exceeded and the nearest allowed value, so the caller can correct the request. |
| `program_instruction_index` | `uint32` | 4 | For `ERROR_PROGRAM_INVALID` (and a limit violation found by `ProgramRun`): index of the offending instruction. |
| `axis` | `uint32` | 5 | Which axis rejected the request (0 = first axis); for multi-axis programs and per-axis config. |
| `info` (oneof result) | `Info` | 10 | Result of `InfoGet`. |
| `soft_config` (oneof result) | `SoftConfig` | 11 | Result of `SoftConfigGet`. |
| `hard_config` (oneof result) | `HardConfig` | 12 | Result of `HardConfigGet`. |

### LimitViolation

Details of a rejected command that exceeded a limit.

| Field | Type | No. | Description |
|---|---|---|---|
| `limit` | `LimitKind` | 1 | Which limit was exceeded. |
| `requested` | `sint32` | 2 | Requested value, in base units. |
| `allowed` | `sint32` | 3 | Nearest allowed value, in base units. |

### MoveAbs

Move to an absolute position; requires the axis to be homed.

| Field | Type | No. | Description |
|---|---|---|---|
| `target` | `sint32` | 1 | Target position, in base units (µm or m°). |
| `velocity` | `uint32` | 2 | Speed in bu/s; 0 = `SoftConfig` default. |
| `acceleration` | `uint32` | 3 | Acceleration in bu/s²; 0 = `SoftConfig` default. |

### MoveRel

Move by a distance from the current position; allowed without homing.

| Field | Type | No. | Description |
|---|---|---|---|
| `distance` | `sint32` | 1 | Distance in base units; the sign gives the direction. |
| `velocity` | `uint32` | 2 | Speed in bu/s; 0 = `SoftConfig` default. |
| `acceleration` | `uint32` | 3 | Acceleration in bu/s²; 0 = `SoftConfig` default. |

### Jog

Move for as long as the host keeps it alive: the host must repeat `Jog` (or send `Heartbeat`) more often than `timeout_ms`, otherwise the MCU decelerates on its own.

| Field | Type | No. | Description |
|---|---|---|---|
| `velocity` | `sint32` | 1 | Speed in bu/s; the sign gives the direction; 0 = smooth stop. |
| `acceleration` | `uint32` | 2 | Acceleration in bu/s²; 0 = `SoftConfig` default. |
| `timeout_ms` | `uint32` | 3 | Keep-alive timeout in ms; capped by `SoftConfig.jog_timeout_max_ms`. |

### MoveLinear

Straight-line move of several axes of the controller: all start and stop together and move proportionally; each axis is checked against its own limits. Firmware v2: later, now `ERROR_UNSUPPORTED`.

| Field | Type | No. | Description |
|---|---|---|---|
| `targets` | `repeated AxisTarget` | 1 | Per-axis targets. |
| `velocity` | `uint32` | 2 | Speed along the line in bu/s (line length = square root of the sum of squared distances); 0 = default. |
| `acceleration` | `uint32` | 3 | Acceleration along the line in bu/s²; 0 = default. |
| `relative` | `bool` | 4 | If true, `targets` are distances rather than positions, and homing is not required. |

### AxisTarget

Target for one axis in a `MoveLinear`.

| Field | Type | No. | Description |
|---|---|---|---|
| `axis` | `uint32` | 1 | Axis number: 0 = first axis of the controller. |
| `target` | `sint32` | 2 | Position, or distance when `relative` is set, in that axis's base units. |

### Stop

Decelerate to a stop with the current acceleration; also stops a running program.

### EStop

Software emergency stop: step generation stops immediately; motor holding follows the configuration. The hardware e-stop works independently of the protocol.

### Home

Run homing using the method in `SoftConfig.home_method` (if unset, `HardConfig.home_method`).

### TravelDiscover

Measure the travel automatically: home to its own switch, then drive to the opposite switch and back to the post-homing point. Stores `SoftConfig.travel_min`/`travel_max` (from the homing switch to where the opposite switch released) in flash and ends with `EVENT_TRAVEL_DONE`; the state is `STATE_HOMING` meanwhile. Needs `HOME_LIMIT_MIN` or `HOME_LIMIT_MAX` and both limit switches present and already seen, otherwise `ERROR_INVALID_STATE`.

### SetPosition

Declare the current position to be `value` without moving; marks the axis as homed.

| Field | Type | No. | Description |
|---|---|---|---|
| `value` | `sint32` | 1 | New current position, in base units. |

### ProgramBegin

Start a program upload. Programs are uploaded as Begin, then Chunk messages, then Commit.

| Field | Type | No. | Description |
|---|---|---|---|
| `instruction_count` | `uint32` | 1 | Total number of instructions in the program. |
| `crc32` | `uint32` | 2 | CRC-32 (zlib variant) over the protobuf encoding of each `Instruction`, in order. |

### ProgramChunk

One block of program instructions; chunks must arrive in order.

| Field | Type | No. | Description |
|---|---|---|---|
| `offset` | `uint32` | 1 | Index of the first instruction in this chunk (equal to the number already received). |
| `instructions` | `repeated Instruction` | 2 | Instructions in this chunk. |

### ProgramCommit

Finish the upload: validate the whole program (statically, since it has no conditions) and only then make it active.

### ProgramRun

Run the active program; requires the axis to be homed.

| Field | Type | No. | Description |
|---|---|---|---|
| `repeat` | `uint32` | 1 | Number of times to run the program; 0 or 1 = once. |

### ProgramPause

Finish the current move and stop, keeping the program position.

### ProgramResume

Resume a paused program.

### ProgramAbort

Like `Stop`, and also reset the program counter.

### Instruction

One step of a motion program.

| Field | Type | No. | Description |
|---|---|---|---|
| `move_abs` (oneof op) | `MoveAbs` | 1 | Move to an absolute position. |
| `move_rel` (oneof op) | `MoveRel` | 2 | Move by a relative distance. |
| `home` (oneof op) | `Home` | 3 | Run homing. |
| `wait_time` (oneof op) | `WaitTime` | 4 | Wait for a fixed time. |
| `wait_input` (oneof op) | `WaitInput` | 5 | Wait for an input to reach a level. |
| `set_output` (oneof op) | `SetOutput` | 6 | Set a digital output. |
| `loop_begin` (oneof op) | `LoopBegin` | 7 | Start of a repeated block. |
| `loop_end` (oneof op) | `LoopEnd` | 8 | End of a repeated block. |
| `move_linear` (oneof op) | `MoveLinear` | 9 | Straight-line move of several axes together; all axes are checked when the program is run (firmware v2: later). |

### WaitTime

Pause the program for a fixed time.

| Field | Type | No. | Description |
|---|---|---|---|
| `ms` | `uint32` | 1 | Wait time in ms. |

### WaitInput

Wait until a digital input reaches a level. Input numbers start at 0; rev 1 has inputs 0–1, and a higher number is rejected with `ERROR_INVALID_VALUE`.

| Field | Type | No. | Description |
|---|---|---|---|
| `input` | `uint32` | 1 | Input number. |
| `level` | `bool` | 2 | Level to wait for. |
| `timeout_ms` | `uint32` | 3 | Timeout in ms; 0 = no timeout. On timeout the program is aborted (`EVENT_PROGRAM_ABORTED` with `ERROR_TIMEOUT`). |

### SetOutput

Program step that sets a digital output. Output numbers start at 0; rev 1 has outputs 0–1.

| Field | Type | No. | Description |
|---|---|---|---|
| `output` | `uint32` | 1 | Output number. |
| `level` | `bool` | 2 | Level to set. |

### LoopBegin

Start of a block repeated `count` times, closed by `LoopEnd`.

| Field | Type | No. | Description |
|---|---|---|---|
| `count` | `uint32` | 1 | Number of repetitions, at least 1. Nesting depth is limited by the firmware. |

### LoopEnd

End of the block opened by the matching `LoopBegin`.

### SoftConfig

Working limits for the current job; must lie inside `HardConfig`. Can be changed by an app or an agent.

| Field | Type | No. | Description |
|---|---|---|---|
| `travel_min` | `sint32` | 1 | Minimum allowed position, in base units. |
| `travel_max` | `sint32` | 2 | Maximum allowed position, in base units. |
| `velocity_max` | `uint32` | 3 | Maximum speed, in bu/s. |
| `acceleration_max` | `uint32` | 4 | Maximum acceleration, in bu/s². |
| `velocity_default` | `uint32` | 5 | Speed used when a command gives 0, in bu/s. |
| `acceleration_default` | `uint32` | 6 | Acceleration used when a command gives 0, in bu/s². |
| `jog_timeout_max_ms` | `uint32` | 7 | Upper bound for `Jog.timeout_ms`, in ms. |
| `display_units` | `DisplayUnits` | 8 | Preferred display units for user interfaces only; does not affect motion. |
| `travel_per_rev` | `uint32` | 9 | Base units per motor revolution after calibration ("moved 100 mm, measured 101"); 0 uses `HardConfig.travel_per_rev`. `HardConfig` limits are motor limits in steps and are only re-expressed in the new bu, so the motor never goes further or faster than the owner allowed. Changing it clears homed and clips `travel_min`/`travel_max` to the new bounds. |
| `invert_direction` | `bool` | 10 | Reverse the direction on top of `HardConfig.invert_direction` (XOR). Changing it clears homed. |
| `home_method` (oneof _home_method) | `HomeMethod` | 11 | Homing method; unset uses `HardConfig.home_method`. StallGuard works only with a driver in the socket. |
| `home_velocity` | `uint32` | 12 | Speed for searching the homing switch, in bu/s; 0 uses `HardConfig.home_velocity`. |
| `home_latch_velocity` | `uint32` | 13 | Speed of an optional slow second approach to the switch, in bu/s; 0 skips it (switch homing only). |
| `home_position` (oneof _home_position) | `sint32` | 14 | Coordinate assigned to the switch point; unset uses the `HardConfig` travel limit on that side. |
| `home_backoff` | `uint32` | 15 | Distance to move away from the switch after homing, in bu, so the working zero sits clear of it; 0 stays at the switch point. |
| `input_bindings` | `repeated InputBinding` | 16 | What the universal inputs do on their own (`InputBinding`); at most one binding per input. |

### InputBinding

An action the firmware runs by itself when an input becomes active, without a browser or control rights (the input is a person at the machine). If it cannot run (axis busy, fault, not homed), `EVENT_INPUT_ACTION` reports why. An input held at power-up starts nothing.

| Field | Type | No. | Description |
|---|---|---|---|
| `input` | `uint32` | 1 | Input number: 0–5 for UIN1–UIN6. |
| `action` | `InputAction` | 2 | What to do (`InputAction`). |
| `value` | `sint32` | 3 | Parameter of the action: position for `MOVE_TO`, distance for `MOVE_BY`, value for `SET_POSITION` (bu); speed for `JOG_*` and `RUN_TOGGLE` in bu/s (0 uses `SoftConfig.velocity_default`); repeat count for `PROGRAM_RUN` (0 runs once); output number 0–3 for `OUTPUT_TOGGLE`. |
| `invert` | `bool` | 4 | Act when the input carries no current (a normally closed button). |
| `debounce_ms` | `uint32` | 5 | How long the level must hold before the action fires, in ms; 0 means 20 ms, at most 1000. |

### SoftConfigGet

Read the current `SoftConfig`.

| Field | Type | No. | Description |
|---|---|---|---|
| `axis` | `uint32` | 1 | Axis of the controller: 0 = first axis. Other axes come later in firmware v2 (now `ERROR_UNSUPPORTED`). |

### SoftConfigSet

Replace the `SoftConfig`.

| Field | Type | No. | Description |
|---|---|---|---|
| `config` | `SoftConfig` | 1 | New working limits. |
| `axis` | `uint32` | 2 | Axis of the controller: 0 = first axis. Other axes come later in firmware v2 (now `ERROR_UNSUPPORTED`). |

### HardConfig

Machine limits and mechanics. Can be changed only over USB inside the physical-presence window.

| Field | Type | No. | Description |
|---|---|---|---|
| `axis_kind` | `AxisKind` | 1 | Linear or rotary axis; selects the base units (µm or millidegrees). |
| `full_steps_per_rev` | `uint32` | 2 | Motor full steps per revolution (usually 200). |
| `microsteps` | `uint32` | 3 | Microsteps per full step (1–256). |
| `travel_per_rev` | `uint32` | 4 | Travel per motor revolution, in base units (screw pitch × gear ratio). |
| `invert_direction` | `bool` | 5 | Reverse the motor direction. |
| `travel_min` | `sint32` | 6 | Minimum machine position, in base units. |
| `travel_max` | `sint32` | 7 | Maximum machine position, in base units. |
| `velocity_max` | `uint32` | 8 | Maximum machine speed, in bu/s. |
| `acceleration_max` | `uint32` | 9 | Maximum machine acceleration, in bu/s². |
| `run_current_ma` | `uint32` | 10 | Peak phase current while running, in mA (the value on the motor nameplate). |
| `hold_current_ma` | `uint32` | 11 | Phase current while holding, in mA. |
| `limit_min_active_low` | `bool` | 12 | The min limit switch input is active low. |
| `limit_max_active_low` | `bool` | 13 | The max limit switch input is active low. |
| `home_method` | `HomeMethod` | 14 | How `Home` finds the reference position. |
| `home_velocity` | `uint32` | 15 | Homing speed, in bu/s. |
| `encoder_enabled` | `bool` | 16 | An encoder is connected and used. |
| `encoder_counts_per_rev` | `uint32` | 17 | Encoder counts per motor revolution. |
| `following_error_max` | `uint32` | 18 | Maximum allowed difference between encoder and commanded position, in base units; exceeding it causes a fault. |
| `driver_mode` | `DriverMode` | 19 | Built-in driver or external Step/Dir driver. |
| `limit_min_absent` | `bool` | 20 | No min limit switch is fitted; the input is ignored. The default (false) assumes a switch is fitted, so a host that does not know this field cannot silently disable the protection. |
| `limit_max_absent` | `bool` | 21 | No max limit switch is fitted; the input is ignored. The default (false) assumes a switch is fitted. |
| `encoder_invert` | `bool` | 22 | The encoder counts in the opposite direction to the steps (A/B swapped); corrects it without rewiring. |
| `stallguard_threshold` | `sint32` | 23 | StallGuard threshold of the driver in the socket (TMC2209: SGTHRS 0…255, higher is more sensitive; depends on the driver). Used by the `HOME_STALLGUARD_*` methods and tuned on the actual mechanics. |
| `estop_absent` | `bool` | 25 | No emergency-stop button is wired: the E-STOP input is ignored. The EStop command always works. |
| `limit_min_seen` | `bool` | 26 | Auto-detection: the min limit input has been closed at least once, so a switch is wired. Until then the input does not stop motion, so a new device runs out of the box. Set by the firmware and kept in flash; reset with HardConfigSet (presence required). |
| `limit_max_seen` | `bool` | 27 | Auto-detection for the max limit input; see limit_min_seen. |
| `estop_seen` | `bool` | 28 | Auto-detection for the E-STOP input; see limit_min_seen. |

### HardConfigGet

Read the current `HardConfig`.

| Field | Type | No. | Description |
|---|---|---|---|
| `axis` | `uint32` | 1 | Axis of the controller: 0 = first axis. Other axes come later in firmware v2 (now `ERROR_UNSUPPORTED`). |

### HardConfigSet

Replace the `HardConfig`; accepted only over USB and inside the physical-presence window.

| Field | Type | No. | Description |
|---|---|---|---|
| `config` | `HardConfig` | 1 | New machine configuration. |
| `axis` | `uint32` | 2 | Axis of the controller: 0 = first axis. Other axes come later in firmware v2 (now `ERROR_UNSUPPORTED`). Hard config: only over USB with the presence window open. |

### OutputSet

Set a digital output immediately. Output numbers start at 0.

| Field | Type | No. | Description |
|---|---|---|---|
| `output` | `uint32` | 1 | Output number. |
| `level` | `bool` | 2 | Level to set. |

### InfoGet

Request device information.

### Info

Device identity and capabilities.

| Field | Type | No. | Description |
|---|---|---|---|
| `protocol_version` | `uint32` | 1 | Protocol version. |
| `firmware_version` | `string` | 2 | Firmware version (semver). |
| `hardware_revision` | `string` | 3 | Hardware revision. |
| `serial` | `string` | 4 | Device serial number. |
| `capabilities` | `uint32` | 5 | Bit mask of `Capability` values. |
| `transport` | `Transport` | 6 | Channel over which this request arrived. |
| `reset_cause` | `ResetCause` | 7 | Why the MCU last started (diagnostics). |

### TelemetryConfig

Configure periodic telemetry for the transport the command arrives on.

| Field | Type | No. | Description |
|---|---|---|---|
| `rate_hz` | `uint32` | 1 | Telemetry rate in Hz; 0 = off. The MCU caps the rate. |

### FaultClear

Clear the fault state if its cause is gone.

### Heartbeat

Keep-alive message, sent in both directions.

| Field | Type | No. | Description |
|---|---|---|---|
| `uptime_ms` | `uint32` | 1 | Sender uptime in ms. |

### Reset

Restart the controller; only while nothing moves.

### Telemetry

Periodic snapshot of the axis state.

| Field | Type | No. | Description |
|---|---|---|---|
| `uptime_ms` | `uint32` | 1 | Device uptime in ms. |
| `state` | `AxisState` | 2 | Current axis state. |
| `homed` | `bool` | 3 | The axis has a valid reference position. |
| `position` | `sint32` | 4 | Commanded position, in base units. |
| `velocity` | `sint32` | 5 | Current speed, in bu/s. |
| `target` | `sint32` | 6 | Target position of the current move, in base units. |
| `encoder_position` | `sint32` | 7 | Position measured by the encoder, in base units (if `CAP_ENCODER`). |
| `following_error` | `sint32` | 8 | Difference between encoder and commanded position, in base units. |
| `inputs` | `uint32` | 9 | Bit mask of digital input levels. |
| `outputs` | `uint32` | 10 | Bit mask of digital output levels. |
| `limit_min` | `bool` | 11 | Min limit switch is active. |
| `limit_max` | `bool` | 12 | Max limit switch is active. |
| `estop_input` | `bool` | 13 | Emergency stop input is active. |
| `motor_current_ma` | `uint32` | 14 | Motor current, in mA. |
| `stallguard` | `uint32` | 15 | Raw StallGuard value (`SG_RESULT`). |
| `supply_mv` | `uint32` | 16 | Supply voltage, in mV. |
| `driver_flags` | `uint32` | 17 | Bit mask of `DriverFlag` values. |
| `program_pc` | `uint32` | 18 | Index of the current program instruction. |
| `program_repeat` | `uint32` | 19 | Which repetition of the program is running. |

### Event

Asynchronous notification from the device; events are sent on all transports.

| Field | Type | No. | Description |
|---|---|---|---|
| `uptime_ms` | `uint32` | 1 | Device uptime when the event occurred, in ms. |
| `kind` | `EventKind` | 2 | Event type. |
| `position` | `sint32` | 3 | Position at the moment of the event, in base units. |
| `error` | `ErrorCode` | 4 | Cause, for `EVENT_FAULT` and `EVENT_PROGRAM_ABORTED`. |
| `detail` | `uint32` | 5 | Extra detail, e.g. an input number or instruction index. |
| `axis` | `uint32` | 6 | Axis that caused the event (0 = first axis). |

## Enums

### ErrorCode

Result code of a command; also the cause carried by fault and abort events.

| Value | No. | Description |
|---|---|---|
| `ERROR_NONE` | 0 | Accepted (ACK). |
| `ERROR_MALFORMED` | 1 | The message could not be parsed, or its `oneof` is empty. |
| `ERROR_UNSUPPORTED` | 2 | Command unknown to this firmware. |
| `ERROR_INVALID_STATE` | 3 | Not allowed in the current state, e.g. `ProgramResume` without a pause. |
| `ERROR_BUSY` | 4 | A move is already in progress. |
| `ERROR_NOT_HOMED` | 5 | Absolute move requested before homing. |
| `ERROR_LIMIT_EXCEEDED` | 6 | A limit would be exceeded; see `Response.limit_violation`. |
| `ERROR_ESTOP_ACTIVE` | 7 | Emergency stop is active. |
| `ERROR_FAULT_ACTIVE` | 8 | A fault is active; send `FaultClear`. |
| `ERROR_TRANSPORT_NOT_ALLOWED` | 9 | Command not allowed on this transport, e.g. `HardConfigSet` over UART. |
| `ERROR_PRESENCE_REQUIRED` | 10 | The physical-presence window is not open. |
| `ERROR_PROGRAM_INVALID` | 11 | The program is invalid; see `Response.program_instruction_index`. |
| `ERROR_PROGRAM_TOO_LARGE` | 12 | The program is too large. |
| `ERROR_PROGRAM_CHECKSUM` | 13 | Program CRC-32 does not match. |
| `ERROR_NO_PROGRAM` | 14 | No program is loaded. |
| `ERROR_INVALID_VALUE` | 15 | A value is outside the accepted format (not a machine limit). |
| `ERROR_NO_MOTOR_POWER` | 16 | No motor power (USB only); motion is not allowed. |
| `ERROR_HOMING_FAILED` | 17 | Homing did not find the switch or stop within the travel (reported in `Event.error`). |
| `ERROR_TIMEOUT` | 18 | Timeout, e.g. `WaitInput` in a program (reported in `Event.error`). |
| `ERROR_LIMIT_SWITCH` | 19 | A limit switch in the direction of motion is active (in `Event.error`, or a NACK for a move towards it). |
| `ERROR_DRIVER` | 20 | Driver error such as overtemperature or short circuit (reported in `Event.error`). |
| `ERROR_FOLLOWING_ERROR` | 21 | Encoder position diverged from the commanded position (reported in `Event.error`). |
| `ERROR_STORAGE` | 22 | Saving to flash failed; the configuration was not changed. |
| `ERROR_BUS` | 23 | An axis used by the program is not present or not configured on this controller. |
| `ERROR_IMAGE` | 24 | Firmware or package image is not for this board (reserved for v2 updates). |
| `ERROR_SIGNATURE` | 25 | Image signature does not match (reserved for v2 updates). |
| `ERROR_OVERVOLTAGE` | 26 | The socket over-voltage protection tripped: a driver in a StepStick socket lost power with the supply above ~23 V, or the supply rose above ~27 V (power supply too high, or energy fed back while braking). |
| `ERROR_OVP_FAILED` | 27 | Backup supply check: the supply is above 28.5 V while the drivers in the StepStick sockets are still powered, so the over-voltage cut-off did not work. Motion is stopped and the drivers are switched off. |

### LimitKind

Which limit a `LimitViolation` refers to.

| Value | No. | Description |
|---|---|---|
| `LIMIT_UNSPECIFIED` | 0 | Not specified. |
| `LIMIT_TRAVEL_MIN` | 1 | Minimum travel position. |
| `LIMIT_TRAVEL_MAX` | 2 | Maximum travel position. |
| `LIMIT_VELOCITY` | 3 | Maximum speed. |
| `LIMIT_ACCELERATION` | 4 | Maximum acceleration. |
| `LIMIT_JOG_TIMEOUT` | 5 | Maximum jog timeout (`SoftConfig.jog_timeout_max_ms`). |

### InputAction

Actions an input can trigger through `InputBinding`.

| Value | No. | Description |
|---|---|---|
| `INPUT_NONE` | 0 | No action. |
| `INPUT_STOP` | 1 | Smooth stop of everything, including a program — same as `Stop`. |
| `INPUT_ESTOP` | 2 | Emergency stop — same as the `EStop` command (functional, not certified). |
| `INPUT_FAULT_CLEAR` | 3 | Clear a fault — same as `FaultClear`. |
| `INPUT_HOME` | 4 | Run homing — same as `Home`. |
| `INPUT_MOVE_TO` | 5 | Preset position: move to `value` (needs homing). |
| `INPUT_MOVE_BY` | 6 | Step by `value`. |
| `INPUT_SET_POSITION` | 7 | Declare the current position as `value` ("set zero"). |
| `INPUT_JOG_POS` | 8 | Move in + while the input is active. |
| `INPUT_JOG_NEG` | 9 | Move in − while the input is active. |
| `INPUT_RUN_TOGGLE` | 10 | Start or stop continuous motion in the current direction (velocity mode). |
| `INPUT_DIRECTION` | 11 | Reverse the `RUN_TOGGLE` direction; while moving, it stops first. |
| `INPUT_PROGRAM_RUN` | 12 | Run the loaded program. |
| `INPUT_PROGRAM_PAUSE` | 13 | Pause the program, or resume it if paused. |
| `INPUT_OUTPUT_TOGGLE` | 14 | Toggle output `value`. |

### DisplayUnits

Units preferred for display in user interfaces; the protocol itself is always metric.

| Value | No. | Description |
|---|---|---|
| `DISPLAY_UNITS_METRIC` | 0 | Metric. |
| `DISPLAY_UNITS_IMPERIAL` | 1 | Imperial (inches). |

### AxisKind

Type of axis, which selects the base units.

| Value | No. | Description |
|---|---|---|
| `AXIS_LINEAR` | 0 | Linear axis: µm, µm/s, µm/s². |
| `AXIS_ROTARY` | 1 | Rotary axis: millidegrees, m°/s, m°/s². |

### HomeMethod

How the axis finds its reference position.

| Value | No. | Description |
|---|---|---|
| `HOME_NONE` | 0 | No homing; reference is set only with `SetPosition`. |
| `HOME_LIMIT_MIN` | 1 | Home to the min limit switch. |
| `HOME_LIMIT_MAX` | 2 | Home to the max limit switch. |
| `HOME_STALLGUARD_MIN` | 3 | Home towards the min end without a switch, detecting the stop with StallGuard. |
| `HOME_STALLGUARD_MAX` | 4 | Home towards the max end without a switch, detecting the stop with StallGuard. |

### DriverMode

Which motor driver the axis uses.

| Value | No. | Description |
|---|---|---|
| `DRIVER_INTERNAL` | 0 | Driver in the StepStick socket on the board (steps are still generated by the motion core). |
| `DRIVER_EXTERNAL_STEP_DIR` | 1 | External driver connected through the Step/Dir output. |

### ResetCause

Why the MCU last started.

| Value | No. | Description |
|---|---|---|
| `RESET_UNKNOWN` | 0 | Unknown. |
| `RESET_POWER_ON` | 1 | Power-on, or supply dropped below the brown-out threshold. |
| `RESET_PIN` | 2 | Reset pin: the reset button or a programmer. |
| `RESET_WATCHDOG` | 3 | Watchdog: the firmware hung and should be investigated. |
| `RESET_SOFTWARE` | 4 | Software reset (the Reset command, an update). |
| `RESET_OPTION_BYTES` | 5 | Reset after writing option bytes. |
| `RESET_LOW_POWER` | 6 | Low-power-mode reset. |

### Capability

Bit flags combined in `Info.capabilities`.

| Value | No. | Description |
|---|---|---|
| `CAP_NONE` | 0 | No optional capabilities. |
| `CAP_ENCODER` | 1 | Encoder input. |
| `CAP_STALLGUARD` | 2 | StallGuard stall detection. |
| `CAP_EXTERNAL_DRIVER` | 8 | External Step/Dir driver output. |

### Transport

Channel a request arrived on.

| Value | No. | Description |
|---|---|---|
| `TRANSPORT_UNKNOWN` | 0 | Unknown. |
| `TRANSPORT_UART_MODULE` | 1 | Network layer of the same controller (WebSocket, apps on the device). |
| `TRANSPORT_USB` | 2 | USB CDC. |

### AxisState

State of the axis.

| Value | No. | Description |
|---|---|---|
| `STATE_IDLE` | 0 | Idle. |
| `STATE_MOVING` | 1 | Executing a move. |
| `STATE_JOGGING` | 2 | Jogging. |
| `STATE_HOMING` | 3 | Homing. |
| `STATE_PROGRAM_RUNNING` | 4 | Running a program. |
| `STATE_PROGRAM_PAUSED` | 5 | Program paused. |
| `STATE_FAULT` | 6 | Fault; needs `FaultClear`. |
| `STATE_ESTOP` | 7 | Emergency stop active. |

### DriverFlag

Bit flags combined in `Telemetry.driver_flags`.

| Value | No. | Description |
|---|---|---|
| `DRV_NONE` | 0 | No driver flags set. |
| `DRV_OVERTEMP_WARN` | 1 | Driver overtemperature warning. |
| `DRV_OVERTEMP` | 2 | Driver overtemperature. |
| `DRV_SHORT` | 4 | Short circuit detected. |
| `DRV_OPEN_LOAD` | 8 | Open load (motor phase not connected). |
| `DRV_UNDERVOLTAGE` | 16 | Supply undervoltage. |
| `DRV_SOCKET_OVP` | 32 | Set by the motion core: the driver in the socket is silent because the over-voltage protection cut its power (see `ERROR_OVERVOLTAGE`). |

### EventKind

Type of an `Event`.

| Value | No. | Description |
|---|---|---|
| `EVENT_UNSPECIFIED` | 0 | Not specified. |
| `EVENT_MOVE_DONE` | 1 | A move finished. |
| `EVENT_HOME_DONE` | 2 | Homing finished. |
| `EVENT_PROGRAM_DONE` | 3 | The program finished. |
| `EVENT_PROGRAM_ABORTED` | 4 | The program was aborted; the cause is in `error`. |
| `EVENT_LIMIT_HIT` | 5 | A limit switch was hit. |
| `EVENT_STALL` | 6 | A motor stall was detected. |
| `EVENT_FOLLOWING_ERROR` | 7 | Following error exceeded the maximum. |
| `EVENT_FAULT` | 8 | The device entered a fault; the cause is in `error`. |
| `EVENT_ESTOP_PRESSED` | 9 | Emergency stop pressed. |
| `EVENT_ESTOP_RELEASED` | 10 | Emergency stop released. |
| `EVENT_INPUT_CHANGED` | 11 | A digital input changed. |
| `EVENT_JOG_TIMEOUT` | 12 | A jog stopped because it was not refreshed in time. |
| `EVENT_PRESENCE_WINDOW_OPEN` | 13 | The physical-presence window opened (confirmed on the device). |
| `EVENT_DRIVER_LOST` | 14 | A driver in a socket lost its motor power while the axis was standing; `error` gives the cause (`ERROR_OVERVOLTAGE`, `ERROR_NO_MOTOR_POWER` or `ERROR_DRIVER`). The position is lost (`homed = false`); during a move this is a FAULT instead. |
| `EVENT_DRIVER_READY` | 15 | The driver in the socket answers again and the motion core has rewritten its configuration; motion is allowed. |
| `EVENT_INPUT_ACTION` | 16 | An input with a bound action fired; `detail` is the input number, `error` says why the action did not run (`ERROR_NONE` if it did). |
| `EVENT_TRAVEL_DONE` | 17 | Travel measurement finished and `SoftConfig.travel_min`/`travel_max` updated; `position` is `travel_max`, `detail` is the travel length in bu. |
