15.4. Handshake and capability negotiation¶
The cam and host both arrive at the transport with their own ideas about how the protocol should run: which CRC modes, whether ACKs are required, what the largest payload they can buffer is. Before real traffic starts they exchange a handshake that fixes those parameters for the rest of the session.
15.4.1. The host opens the connection¶
The cam side starts the protocol stack at boot (or the application
restarts it with protocol.init() to change parameters), then
sits quietly waiting for a host. From the cam’s point of view there
is nothing to do until a packet arrives.
The host side opens the transport – USB port or UART – and
immediately sends a PROTO_SYNC packet
(opcode 0x00). This packet has a magic payload that lets the cam
recognise it even if both sides got out of sync, and it’s the only
packet the cam ever responds to before capabilities are negotiated.
If the cam doesn’t reply within the retransmit timeout the host
sends PROTO_SYNC again, up to rtx_retries times. After that
it gives up and reports a connection failure. The retry is what
makes “unplug, replug, restart the host script” work without the
cam needing to know the host went away.
15.4.2. Capability exchange¶
Once the cam acknowledges the sync, the host sends
PROTO_GET_CAPS (opcode 0x01) to ask what the cam supports.
The reply payload reports:
CRC validation enabled or disabled
Sequence-number tracking enabled or disabled
ACKs enabled or disabled
Event notifications enabled or disabled
The cam’s maximum payload size in bytes
The current retransmit retry count, timeout, and polling parameters
The host compares those against its own configuration. If the host
needs to change any of them – for example, to negotiate a smaller
max payload because its receive buffer is smaller than the cam’s –
it sends PROTO_SET_CAPS (opcode 0x02) with the new values.
The cam reconfigures its stack and acknowledges. From here on, every
packet that crosses the wire follows that shared contract.
If the host doesn’t override anything, the defaults are all on: CRC validation, sequence-number tracking, ACKs, and event notifications. The default max payload is the cam’s per-board buffer minus 14 bytes of framing overhead (the 10-byte header plus the 4-byte trailing payload CRC). For most cam-to-laptop work the defaults are the right starting point; the reliability page covers when and why an application opts pieces of them off.
15.4.3. Channel discovery¶
After capabilities, the host sends CHANNEL_LIST (opcode
0x20). The cam replies with a list of registered channels –
the four built-in ones (stdin, stdout, stream,
profile) plus any the application registered with
protocol.register(). Each entry carries the channel’s ID, its
name, and its capability flags (read-only, write-only, lockable).
The host stashes the list and uses it later when application code
asks for channel_read("frame") or channel_write("config",
...) – the name is looked up to a channel ID once, then every
subsequent packet on that channel uses the ID directly.
If the cam registers a new channel after the initial list – common
when an application starts running after the handshake – the cam
emits a CHANNEL_REGISTERED event packet. The host listens for
those and refreshes its internal channel list, so a host script that
attached early sees newly-registered channels appear without
restarting.
The handshake takes a few round-trips on connection setup and then never repeats. Steady-state traffic is just packets: framed bytes in, framed bytes out, the channel IDs already known on both sides.