Appendix A — Requirements Catalogue

Generated from documents/requirements/*.yaml at build time. These are the normative requirements the design in this booklet implements; each section corresponds to one requirement file.

Can Protocol

ID Title Shall
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.

Firmware Upgrade

ID Title Shall
REQ-FWU-001 Upgrade session initiation The client shall be able to initiate a firmware upgrade session by sending a Begin Upgrade command containing the total firmware size in bytes (uint32). The server shall reject the request if an upgrade is already in progress (Busy) or the size exceeds available storage (InvalidSize).
REQ-FWU-002 Upgrade session abort The client shall be able to abort a firmware upgrade session at any time by sending an Abort command. The server shall discard any received data and return to the Idle state.
REQ-FWU-003 Block-based data transfer Firmware data shall be transferred in blocks of up to 6 bytes per CAN frame, with each block identified by a uint16 block index (bytes 0–1). Blocks shall be transmitted in ascending order starting from index 0.
REQ-FWU-004 Per-block acknowledgement The server shall acknowledge each received data block with a Data Block Ack containing the block index and a status code. The client shall not consider a block successfully transferred until the corresponding ack with Ok status is received.
REQ-FWU-005 Block write failure handling If the server fails to write a block to flash storage, it shall respond with a WriteError status in the Data Block Ack. The client may retransmit the failed block.
REQ-FWU-006 CRC32 integrity verification After all data blocks have been transferred, the client shall send a Verify command containing the expected CRC32 of the complete firmware image. The server shall compute the CRC32 over the received data and respond with match or mismatch status. The CRC32 shall be the checksum, and cover the bytes, that the firmware-upgrade specification defines for Verify (section 4.3).
REQ-FWU-007 Firmware activation The client shall be able to command the server to activate the newly uploaded firmware by sending an Activate command. This command shall only be accepted after a successful CRC32 verification (Complete state). The server shall perform the firmware swap and reboot.
REQ-FWU-008 Activation safety The server shall reject Activate commands if the firmware has not been successfully verified (NotReady error), preventing activation of corrupt or incomplete images.
REQ-FWU-009 Upgrade progress query The client shall be able to query the current upgrade state at any time. The server shall respond with the current state, the number of blocks received, and the total number of blocks expected.
REQ-FWU-010 Active firmware preservation The firmware upgrade process shall not overwrite the currently running firmware. Incoming firmware shall be written to a staging area or inactive flash bank, preserving the active image until activation.
REQ-FWU-011 Upgrade state machine The firmware upgrade process shall follow a defined state machine with states: Idle, Receiving, Verifying, Complete, and Error. Commands that are not valid in the current state shall be rejected with an InvalidState error.
REQ-FWU-012 Sequence validation bypass The firmware upgrade category shall not require protocol-level sequence validation (RequiresSequenceValidation = false). Transfer ordering shall be enforced by the explicit block index in each Data Block message, since the protocol’s 8-bit sequence counter is insufficient for the number of blocks in a typical firmware transfer.
REQ-FWU-013 Maximum firmware size The firmware upgrade protocol shall support firmware images up to 393216 bytes (65536 blocks × 6 bytes per block), limited by the uint16 block index field. Transfers exceeding this limit shall be rejected during Begin Upgrade.
REQ-FWU-014 Response message type IDs Response message types within the firmware upgrade category shall use IDs formed by adding 0x80 to the corresponding command message type ID, reserving 0x00–0x7F for commands and 0x80–0xFF for responses.
REQ-FWU-015 Session inactivity timeout The server shall abort a firmware upgrade session if, after its application accepts BeginUpgrade or the last DataBlock, no further DataBlock is accepted and no Verify, Activate, or Abort command is received within a configurable inactivity timeout period (default 30 s). On timeout the server shall transition to Idle state and notify the application via the OnSessionTimeout() observer callback. A refused BeginUpgrade shall not open a session and a refused DataBlock shall not extend one. QueryProgress commands shall not reset the inactivity timer.
REQ-FWU-016 Commands without an application When no application is attached to the firmware upgrade category, the server shall answer Begin Upgrade, Data Block, Verify, and Activate with their response carrying NotReady and a categoryError acknowledgement, acknowledge Abort with success, and answer Query Progress with state Idle, zero blocks, and a success acknowledgement.
REQ-FWU-017 Undefined status and state values The client shall discard a firmware upgrade response whose status is not a defined error code, or whose state is not a defined upgrade state, without notifying its application.