REQ-CAN-001 |
CAN bus transport |
The protocol shall use the CAN bus as the communication channel
between clients and servers. All protocol interactions follow a
client-server model where the client initiates requests and the server
processes them. |
REQ-CAN-002 |
Extended CAN identifiers |
The protocol shall use exclusively 29-bit extended CAN identifiers
for all transmitted and received frames. Both client and server shall
silently discard any frame using an 11-bit standard identifier. |
REQ-CAN-003 |
CAN identifier structure |
The 29-bit CAN identifier shall encode four fields: a 5-bit priority
field (bits 28-24), a 4-bit category field (bits 23-20), an 8-bit
message type field (bits 19-12), and a 12-bit node address field (bits
11-0). |
REQ-CAN-004 |
Client-server model |
The protocol shall follow a client-server architecture where the
client is the sole initiator of commands and queries, and the server
listens for incoming frames, processes them, and sends responses. The
server shall not initiate unsolicited commands to the client. |
REQ-CAN-005 |
Server node identity |
Each server shall be configured with a unique 12-bit node address
(1-4095) that identifies it on the CAN bus. The server shall process
only frames addressed to its own node address or to the broadcast
address (0x000). |
REQ-CAN-005.1 |
Node address from a base and an offset |
A server node address derived from a configured base and an offset,
such as a board identifier, shall be the base plus the offset. When the
base is the broadcast address, or the sum would exceed 4095, the base
0x001 shall be used instead. |
REQ-CAN-006 |
Multi-server client support |
The client shall support communication with multiple servers on the
same CAN bus by addressing frames to different server node addresses.
The client shall maintain independent sequence counters per server. |
REQ-CAN-006.1 |
Single-client server |
Each server shall serve exactly one client. The server shall
maintain a single sequence counter shared by all sequence-validated
categories, so concurrent command streams originating from more than one
client are not supported and shall be rejected with a sequence error.
The relationship is therefore one client to many servers, never many
clients to one server. |
REQ-CAN-007 |
Broadcast message support |
The protocol shall reserve node address 0x000 as the broadcast
address. All servers shall accept frames addressed to 0x000 regardless
of their configured node address, enabling simultaneous control of
multiple servers. |
REQ-CAN-008 |
Default system category |
The protocol shall define a built-in System category (0x0) that
provides heartbeat, command acknowledgement, status request, and
category discovery messages. This category shall be available without
any application-specific extensions. |
REQ-CAN-009 |
Server heartbeat mechanism |
The server shall automatically begin transmitting heartbeat frames
upon startup. A heartbeat frame shall contain a 1-byte protocol version
identifier and shall be sent at the lowest CAN priority level. The
server shall transmit a heartbeat at least 1 second after the last
message of any kind was sent, acting as a keep-alive during periods of
silence. The heartbeat shall not be sent while the server is actively
transmitting other messages within the 1-second window. |
REQ-CAN-009.1 |
Client online/offline detection |
The client shall use received heartbeat frames (and other messages)
to determine whether a server is online or offline. When a heartbeat is
received from a server, the client shall consider that server online and
notify the application layer. When no messages are received from a
server within a configurable timeout, the client shall consider that
server offline and notify the application layer. |
REQ-CAN-010 |
Protocol version identification |
The heartbeat frame shall carry a protocol version byte that allows
the client to verify wire-format compatibility with the server. |
REQ-CAN-011 |
Command acknowledgement |
The server shall transmit a 4-byte acknowledgement frame for every
processed command, containing the original command’s category, message
type, a status code indicating success or the specific error condition
(unknown command, invalid payload, invalid state, or sequence error),
and an expected-sequence byte (REQ-CAN-037). Messages rejected by rate
limiting are the exception: per REQ-CAN-022 they are silently discarded
and receive no acknowledgement, since sending one would itself add
traffic during the overload condition rate limiting exists to shed. |
REQ-CAN-012 |
Status request |
The client shall be able to send a status request message to a
server. Upon receiving this message, the server shall respond by
transmitting a heartbeat message, allowing the client to quickly confirm
the server is online without waiting for the next scheduled
heartbeat. |
REQ-CAN-013 |
Category-based message dispatch |
The protocol shall dispatch received frames to handlers based on the
category field in the CAN identifier. Each category handler shall be
independently registered and shall process only its own message
types. |
REQ-CAN-014 |
Application-defined categories |
The protocol shall allow applications to define additional message
categories beyond the built-in System and Firmware Upgrade categories by
registering custom category handlers on the server and client. Category
identifiers 0x2 to 0xF shall be available to applications.
RegisterCategory() shall reject, by returning false without registering,
an attempt to register a category whose ID is already registered, or
that would exceed canMaxRegisteredCategories (8) categories registered
at once on that server or client. This bound exists because the category
discovery response (REQ-CAN-008) reports every registered category ID in
a single 8-byte frame; it must never truncate. |
REQ-CAN-015 |
Fixed-point data encoding |
A floating-point value transmitted over CAN with a scale factor
shall be encoded as a big-endian signed fixed-point integer with a
defined per-quantity scale factor, with saturation clamping to prevent
integer overflow. |
REQ-CAN-049 |
Single-precision floating-point encoding |
A floating-point value transmitted over CAN without a scale factor
shall be encoded as its 4-byte IEEE 754 single-precision bit pattern, in
the same big-endian byte order as an unsigned 32-bit integer, so that
every value, including signed zero, infinities and NaN, is received bit
for bit as it was sent. |
REQ-CAN-016 |
Short payload rejection |
The server shall reject any command frame whose payload is shorter
than the minimum required length for the given message type, and shall
respond with an invalid-payload error without applying any state
changes. A category handler that is registered for the message type but
rejects the payload shall likewise be answered with an invalid-payload
error, not an unknown-command error; unknown-command shall be reserved
for a message type no registered handler claims. |
REQ-CAN-017 |
Sequence number validation |
The server shall validate command frames using an 8-bit sequence
counter in the first payload byte. The first received command shall be
accepted regardless of its sequence value. Subsequent commands shall be
accepted only if their sequence number equals the previous sequence
number plus one, modulo 256. Out-of-sequence commands shall be rejected
with a sequence error response. |
REQ-CAN-018 |
Sequence number wrap-around |
The sequence counter shall wrap from 255 to 0 without error,
allowing continuous operation without sequence resets. |
REQ-CAN-019 |
Sequence bypass per category |
Individual category handlers shall be able to declare whether they
require sequence number validation. Categories or specific message types
that do not require sequencing shall bypass validation entirely. |
REQ-CAN-020 |
Unknown message category handling |
The server shall silently discard any received frame whose category
field does not correspond to a registered category handler, without
generating any response. |
REQ-CAN-021 |
Unknown message type handling |
The server shall respond with an unknown-command error when a frame
is received with a registered category but an unrecognized message
type. |
REQ-CAN-022 |
Message rate limiting |
The server shall enforce a configurable maximum number of received
messages per second. Messages exceeding this limit shall be silently
discarded. The rate counter shall be reset automatically every second by
an internal timer. Every accepted frame shall be counted, including a
frame consumed by the ISO-TP transport, and a reassembled PDU shall not
be counted a second time when it is dispatched. Frames carrying
emergency priority shall be counted against a separate, configurable
budget (default 20 per second) and shall not consume, or be refused by,
the budget for other traffic. Rate limiting shall be applied before any
other validation, so that its cost stays bounded under a flood. |
REQ-CAN-023 |
Node address filtering |
The server shall process only CAN frames whose node address matches
its configured local address or the broadcast address (0x000), and shall
silently discard all other frames. |
REQ-CAN-024 |
No dynamic memory allocation |
The CAN protocol library shall not perform any dynamic memory
allocation and shall use only statically-sized data structures. |
REQ-CAN-025 |
Category discovery |
The client shall be able to send a category list request message to
a server. Upon receiving this message, the server shall respond with a
category list response containing the IDs of all registered category
handlers. The response payload shall list one category ID per byte, and
shall always fit in a single CAN frame: RegisterCategory() refuses the
ninth category (REQ-CAN-014), so the number of registered categories
never exceeds the 8 bytes available and the response never truncates. A
server needing to expose more than 8 categories is not currently
supported. |
REQ-CAN-048 |
Discovery completion |
The client shall keep at most one category discovery pending, and
shall refuse a request made while one is pending or addressed to the
broadcast node ID. Only a category list response from the node asked
shall complete the pending discovery. If none arrives within a
configurable timeout (default 1 s), the client shall complete it without
an answer. |
REQ-CAN-026 |
Per-server sequence counter on client |
The client shall maintain independent 8-bit sequence counters for
each server node it communicates with. The sequence counter for a node
shall start at 0 on the first command and increment by 1 for each
subsequent command to that same node. Counters for different nodes shall
be independent. Up to 8 server nodes may be tracked simultaneously. |
REQ-CAN-027 |
Server liveness detection |
The client shall track server liveness independently for each server
node. When any frame is received from a source node ID (non-zero), the
client shall call OnServerOnline(nodeId) the first time and reset a
per-server timeout timer (default 3 s). If no frame is received from a
server within the timeout period, the client shall call
OnServerOffline(nodeId). Up to 8 server liveness slots may be tracked
simultaneously. |
REQ-CAN-028 |
Send queue overflow indication |
The CanFrameTransport::SendFrame() method shall return true if the
frame was successfully sent or enqueued, and false if the frame was
refused under the admission rules of REQ-CAN-040. The onDone callback
shall not be called when false is returned. |
REQ-CAN-039 |
Send queue priority ordering |
Frames waiting in the send queue shall be transmitted in order of
their CAN identifier priority field, most urgent first, once the frame
currently being transmitted completes. Frames of equal priority shall be
transmitted in the order they were accepted. |
REQ-CAN-040 |
Send queue emergency reservation |
The send queue shall hold at most 8 frames, of which at most 6 may
carry a priority other than emergency, so that 2 slots are always
available to emergency-priority frames. A non-emergency frame that would
exceed its share, or that arrives when all 8 slots are occupied, shall
displace the lowest-priority, most recently accepted non-emergency
queued frame when that frame is less urgent than itself, and shall
otherwise be refused. An emergency-priority frame arriving at a full
queue shall displace the lowest-priority, most recently accepted
non-emergency frame. A displaced frame’s onDone callback shall be
invoked exactly once with false. An emergency-priority frame arriving at
a queue that holds only emergency-priority frames shall be refused. |
REQ-CAN-041 |
Bounded send failure handling and transport counters |
When the controller reports that an emergency-priority frame failed
to transmit, the transport shall retransmit it, ahead of any queued
frame, at most 2 times before completing it with false. A failed frame
of any other priority shall complete with false without retransmission.
The transport shall count refused and failed emergency frames, emergency
retransmissions, displaced frames, refused non-emergency frames and
failed non-emergency frames, and shall expose these counts to the
application. |
REQ-CAN-029 |
ISO-TP segmentation support |
The library shall provide an optional ISO 15765-2 (ISO-TP) transport
layer that segments PDUs exceeding 8 bytes into multiple CAN frames and
reassembles them at the receiver. The transport layer shall be
attachable to CanProtocolServer and CanProtocolClient via
AttachIsoTpTransport(). A PDU reassembled on a data identifier that
names a registered category shall be dispatched to that category’s
segmented handler through the same admission, sequence validation and
acknowledgement as a single frame. |
REQ-CAN-030 |
ISO-TP frame types |
The ISO-TP implementation shall support all four ISO 15765-2 frame
types: Single Frame (SF, PCI nibble 0x0), First Frame (FF, PCI nibble
0x1), Consecutive Frame (CF, PCI nibble 0x2), and Flow Control (FC, PCI
nibble 0x3). |
REQ-CAN-031 |
ISO-TP flow control |
The sender shall wait for a Flow Control (ContinueToSend) frame from
the receiver before transmitting Consecutive Frames. The receiver shall
emit a Flow Control frame after receiving the First Frame, advertising
the block size and separation time it is configured with (default 0 and
0), and a further Flow Control frame after each complete block when the
block size is not 0. The sender shall honour the block size and
separation time it receives. On Flow Status = Wait, the sender shall
restart the N_Bs timer and continue waiting rather than aborting, up to
N_WFTmax (16) consecutive Wait frames, after which it shall abort. On
Flow Status = Overflow, the sender shall abort immediately. A Flow
Control frame carrying a reserved Flow Status (3 to 15), or too short to
decode, shall abort the transfer as an unexpected frame and shall not be
reported as an overflow. |
REQ-CAN-032 |
ISO-TP N_Bs timeout |
The sender shall abort an in-progress multi-frame transmission and
notify the abort callback with reason nBsTimeout if no Flow Control
frame is received within 1000 ms of sending the First Frame or the last
block of Consecutive Frames. |
REQ-CAN-033 |
ISO-TP N_Cr timeout |
The receiver shall abort reassembly and notify the abort callback
with reason nCrTimeout if no Consecutive Frame is received within 1000
ms of the previous frame. |
REQ-CAN-034 |
ISO-TP no dynamic memory allocation |
The ISO-TP transport layer shall not perform any dynamic memory
allocation. Channel state and PDU buffers shall use statically-sized
storage provided at construction time via
IsoTpTransportImpl::WithStorage. |
REQ-CAN-035 |
ISO-TP channel management |
IsoTpTransportImpl shall support multiple independent channels, each
a connection with one peer identified by a receive identifier and a
transmit identifier. Frames from the peer arrive on the receive
identifier; data and flow control sent to the peer leave on the transmit
identifier, so a transmission and a reception may run on one channel at
the same time. RegisterReceiveChannel(dataId, fcId) shall open or extend
the channel whose receive identifier is dataId and whose transmit
identifier is fcId; SendPdu(dataId, fcId) shall use the channel whose
transmit identifier is dataId and whose receive identifier is fcId,
opening one that accepts only flow control if none exists. A pair
sharing only one identifier with another channel, or a second
registration of the same pair, shall be refused without modifying state.
The maximum number of simultaneous channels shall be bounded at compile
time via the MaxChannels template parameter (default 4). A channel shall
stay open until the application calls ReleaseChannel with either of its
identifiers; releasing shall end any transfer in progress on it without
a report. |
REQ-CAN-046 |
ISO-TP unexpected and failed transfers |
The receiver shall handle unexpected frames as ISO 15765-2 requires.
It shall ignore a frame with an unknown protocol control nibble, a
single frame whose length is zero, above seven or beyond the frame, a
first frame shorter than eight bytes or declaring fewer than eight
bytes, a consecutive frame while no reception is in progress, a
consecutive frame shorter than eight bytes that is not the last of the
transfer or, when it is the last, too short to hold the bytes still
expected, and a flow control frame. A valid single or first frame
arriving during a reception shall end that reception, reported as an
unexpected frame, and shall then be processed as a new reception. A
transfer that fails shall be discarded and reported once through the
transport’s abort callback; the channel shall stay open. The protocol
objects shall not install the abort callback, which belongs to the
application, and shall not release channels. |
REQ-CAN-047 |
ISO-TP N_As timeout |
The sender shall abort a transfer and notify the abort callback with
reason nAsTimeout if a Single Frame or a Consecutive Frame that is not
followed by a wait for Flow Control has not been reported sent within
1000 ms of being handed to the CAN transport. |
REQ-CAN-036 |
Server-side client-liveness detection |
The client shall automatically begin transmitting heartbeat frames
upon construction, broadcast to node 0x000, following the same
quiet-period keep-alive rule as the server’s own heartbeat
(REQ-CAN-009). The server shall restart its client-liveness timeout
(default 3 s) on every command it accepts, not only heartbeats, since a
client sending commands continuously may defer its own heartbeat frame
indefinitely. A command is accepted when it is addressed to the server,
is in the command range of a registered category, passes sequence
validation where the category requires it, and its handler accepts the
payload. A frame that is rate limited, discarded or answered with an
error shall not restart the timeout. The first command accepted after
construction, or after Offline(), shall notify the application via
CanProtocolServerObserver::Online(); further accepted commands shall not
notify it again. If the timeout elapses without a further accepted
command, the server shall notify CanProtocolServerObserver::Offline(). A
server tracks liveness for one client only, consistent with
REQ-CAN-006.1. Because the CAN identifier carries the destination but
not the source, the server assumes a single trusted controller on the
bus and treats any accepted command as coming from it. |
REQ-CAN-037 |
Sequence resynchronization on sequence error |
The sequenceError acknowledgement (REQ-CAN-011) shall carry, in its
fourth byte, the sequence number the server expected. On receiving a
sequenceError acknowledgement, the client shall adopt that value as its
next sequence number for the acknowledging server, so that a single lost
frame, or the client’s own sequence state having reset independently of
the server, does not leave the two sides unable to recover. |
REQ-CAN-038 |
Command acknowledgement timeout |
When the client sends a sequence-validated command, it shall start a
timer (default 1 s, configurable). If no acknowledgement of any status
arrives for that command before the timer elapses, the client shall
notify the application via
CanProtocolClientObserver::OnCommandAckTimeout(nodeId, category,
messageType). Receiving a matching acknowledgement before the timer
elapses shall cancel it. The client shall not automatically retry the
timed-out command. |
REQ-CAN-045 |
Client sequence consumption |
The client shall take a server’s next sequence number, record the
command as awaiting acknowledgement and start its acknowledgement timer
(REQ-CAN-038) before the command frame reaches the CAN driver, so that
an acknowledgement delivered while the frame is being sent is matched to
that command. A command the client does not send, because its payload
leaves no room for the sequence byte or its send queue refuses the
frame, shall leave the client’s sequence state for every server as it
was. A command accepted for sending whose frame then fails to leave the
node shall give its sequence number back, unless a later command to the
same server has already taken the next number, and its loss shall be
reported through the acknowledgement timeout. |
REQ-CAN-042 |
Emergency command admission |
A command whose CAN identifier carries emergency priority shall be
exempt from sequence validation, so that it is accepted whatever the
server’s sequence state. It shall still carry the sequence byte when its
category requires sequence validation. When such a command is accepted,
the server shall adopt its sequence byte as the last accepted sequence
number, so that ordinary commands from a client that counted it continue
without a sequence error. The same rules shall apply to single frames
and to reassembled ISO-TP PDUs. |
REQ-CAN-043 |
Sequence advance only on accepted commands |
The server shall advance its sequence counter only when a command is
accepted as defined in REQ-CAN-036. A command answered with
sequenceError, invalidPayload or unknownCommand, or discarded, shall
leave the counter unchanged, on both the single-frame and the ISO-TP
receive paths. |
REQ-CAN-044 |
Server receive counters |
The server shall count frames refused by the ordinary rate limit,
frames refused by the emergency rate limit, addressed frames it
discarded or answered with an error, and accepted emergency-priority
commands, and shall expose these counts to the application. |
REQ-CAN-048 |
Single pending heartbeat |
The server shall keep at most one heartbeat frame queued or in
transmission at a time. A status request received, or the heartbeat
interval elapsing, while a heartbeat is pending shall not enqueue
another; the pending heartbeat answers them. A heartbeat the send queue
refuses shall not count as pending, so the next interval or status
request sends one again. |