Protocol

System Design establishes the Station–Pod link as a request–response protocol with the Station as sole initiator, and names three conceptual message categories: commands, status queries, and events. This page defines the wire-level realization of that model: the frame layout, how a request is correlated with its response, and the concrete communication patterns built on top of that correlation. The request–response model itself and the choice to generate the protocol code with commsdsl are decisions made elsewhere and are not repeated here. See ADR-003 and ADR-006.

The protocol is defined as a single schema shared by the Station and every Pod, so both sides agree on the same frame layout, message set, and field encoding by construction. Schema: cocktail-maker-protocol.

Framing

Every exchange between the Station and a Pod is carried in a single frame:

Field Type Purpose

Sync

uint16 (0xabcd)

Fixed marker that lets a receiver find the start of the next frame on the raw USB CDC byte stream.

Size

uint16

Length of the frame from this point onward, used to know when a full frame has been received.

MsgId

uint16

Identifies which message the payload contains (e.g. Dispense, Ack).

TransactionId

uint8

Correlates this frame with the request it belongs to. See Transaction Correlation.

Payload

message-specific

The fields of the message identified by MsgId.

Checksum

uint16 (CRC-16)

Computed over Size through Payload. Protects the frame’s integrity on the wire.

There is no byte-stuffing or escaping layer. Framing relies on Sync, Size, and the CRC alone.

Transaction Correlation

TransactionId is not a field of any individual message. It is a transport-level field carried by every frame, regardless of which message it holds. The Station generates a TransactionId for each request it sends and reuses it for every frame that belongs to the same exchange. This includes an immediate Ack/Nak, a dedicated response, and any event that concludes a longer-running action later on. A Pod must echo the TransactionId of the request it is reacting to on every frame it sends back for that exchange. Because a TransactionId is only required to be unique among requests that are currently pending, the Station is free to reuse a value once its exchange has concluded.

transaction-correlation

This is the only correlation mechanism the protocol has. There is no separate request or session identifier. TransactionId scopes exactly one request/response exchange. It does not identify any higher-level operation a caller of the protocol may be carrying out, and such an operation may itself require several such exchanges.

Communication Patterns

Every message exchange follows one of three patterns, distinguished by how many frames a Pod sends back for a single request and how far apart in time they arrive.

Request / Response

The simplest pattern: a request is answered by exactly one dedicated response message, carrying the same TransactionId. Used by Ping/Pong (keep-alive) and DeviceInfoRequest/DeviceInfoResponse.

pattern-request-response

Request / Acknowledgement

A request that only needs to confirm it was accepted is answered by the generic Ack, or Nak if it could not be executed. Nak carries an ErrorCode explaining the reason, rather than each command defining its own failure message. Used by EmergencyStop, LoadCellCalibrateWithRefWeight, LoadCellTare, and HighlightDispenser.

pattern-request-ack
Table 1. ErrorCode values
Value Meaning

InvalidParameter

A field in the request had an invalid value.

DispenserNotFound

The referenced DispenserId does not exist on this Pod.

UnsupportedInCurrentState

The Pod cannot perform this action in its current state.

HardwareFault

An underlying actuator or sensor reported a fault.

Busy

The Pod is already executing another action.

NotCalibrated

The action requires a calibration that has not been performed.

InternalError

An unspecified internal error occurred.

DispenserEmpty

The dispenser has no ingredient left to act on.

Request / Acknowledgement / Event

Some requests trigger a physical action whose duration cannot be bounded tightly enough to hold a single response open. Dispensing a liquid and running a pump calibration routine are both examples of this. These are acknowledged immediately with Ack/Nak, and once the underlying action completes, the Pod sends a dedicated event carrying the same TransactionId as the original request. This is the mechanism that lets the Station attribute an event arriving seconds later back to the exact request that caused it, even though other exchanges may have started and finished with different transaction ids in the meantime. Used by Dispense (followed by DispenseFinished) and PumpStartCalibration (followed by PumpFinishedCalibrationResponse). The completion event must reuse the TransactionId of the request that triggered it.

pattern-request-ack-event

A Nak can still arrive in place of the event if the action fails after having been accepted, so a caller of this pattern must be prepared to receive either outcome under the same TransactionId.

Messages

Message Direction Category Purpose

Ping

Station → Pod

Request / Response

Keep-alive request.

Pong

Pod → Station

Request / Response

Keep-alive response.

Ack

Pod → Station

Request / Acknowledgement

Generic positive acknowledgement of a command, identified by TransactionId.

Nak

Pod → Station

Request / Acknowledgement

Generic negative acknowledgement, carrying an ErrorCode.

DeviceInfoRequest

Station → Pod

Request / Response

Requests the Pod’s device information.

DeviceInfoResponse

Pod → Station

Request / Response

Hardware/firmware revision, pump/valve counts, and device name.

EmergencyStop

Station → Pod

Request / Acknowledgement

Requests the Pod to bring itself into a safe state.

LoadCellCalibrateWithRefWeight

Station → Pod

Request / Acknowledgement

Calibrates a dispenser’s load cell against a known reference weight.

LoadCellTare

Station → Pod

Request / Acknowledgement

Zeroes a dispenser’s load cell at its currently applied weight.

PumpStartCalibration

Station → Pod

Request / Acknowledgement / Event

Starts calibration of a pump over a given number of steps.

PumpFinishedCalibrationResponse

Pod → Station

Request / Acknowledgement / Event

Reports steps-per-millilitre once a pump calibration has finished.

HighlightDispenser

Station → Pod

Request / Acknowledgement

Drives a dispenser’s LED effect for a given duration.

Dispense

Station → Pod

Request / Acknowledgement / Event

Requests a given amount of liquid to be dispensed.

DispenseFinished

Pod → Station

Request / Acknowledgement / Event

Reports the amount actually dispensed once the action has finished.