<reponame>veronistar/specification
\chapter{Transport layer}\label{sec:transport_layer}

This chapter defines the transport layer of UAVCAN.
First, general implementation-agnostic concepts are introduced.
Afterwards, they are further defined for each supported transport medium, e.g., CAN FD.

As the specification is extended to add support for new transport protocols,
some of the generic aspects may be pushed to lower-level transport-specific sections
if they are found to map poorly on the newly added transports.
Such changes are guaranteed to preserve full backward compatibility of the existing transport protocols.

\section{Core concepts}

\subsection{Transfer}

A \emph{transfer} is an act of data transmission between nodes.

\subsubsection{Broadcast and unicast transfers}

A transfer that is addressed to any interested node except the source node is a \emph{broadcast transfer}.
A transfer that is addressed to one particular node is a \emph{unicast transfer}.

In the case of broadcast transfers, the sending node makes the data widely available on the bus,
allowing any interested node to freely opt-in and process
it\footnote{The word ``broadcast'' should not lead one to believe that every node is required to
process such transfers. The opt-in logic is facilitated by automatic acceptance filtering features
implemented on the transport layer.}.
The decision of whether to process any given transfer or not is made by receiving nodes.

In the case of unicast transfers, the addressing logic is inverted:
the sending node decides which particular remote node should receive the transfer.
All other nodes remain unaffected by such transmission and take no part in the addressing process.

\subsubsection{Message and service transfers}

A \emph{message transfer} is a broadcast transfer that contains a serialized message and its
metadata\footnote{Such as the subject-ID and the source node-ID.}.

A \emph{service transfer} is a unicast transfer that contains either a service request or a service response
with related metadata.

\subsubsection{Single-frame and multi-frame transfers}

Both message and service transfers can be further distinguished between single-frame and multi-frame transfers.

A \emph{single-frame transfer} is a transfer that is entirely contained in a single transport frame.
The amount of data that can be exchanged using single-frame transfers is dependent on the transport protocol in use.

A \emph{multi-frame transfer} is a transfer that has its payload distributed over multiple transport frames.
The UAVCAN protocol stack handles transfer decomposition and reassembly automatically.

The choice between single-frame and multi-frame transfers is made by the UAVCAN protocol logic on
the transmitting node based on the amount of payload data to be transferred.
The application does not have any control over the type of transfer that will be used
except limiting the amount of payload data.
UAVCAN protocol implementations must always choose single-frame transfers if possible;
multi-frame transfers can be used only if all of the requested payload cannot be allocated in one transport frame.

\subsubsection{Common properties}

The properties listed in the table \ref{table:common_transfer_properties} are common to all types of transfers.

\begin{UAVCANSimpleTable}{Common transfer properties}{|l X|}\label{table:common_transfer_properties}
    Property        & Description \\
    Payload         & The serialized object. \\
    Port-ID         & A numerical identifier that indicates how the data should be processed.
                      This is the subject-ID for message transfers and service-ID for service transfers. \\
    Source node-ID  & The node-ID of the transmitting node (excepting anonymous message transfers). \\
    Priority        & A non-negative integer value that defines the transfer urgency.
                      Higher priority transfers can preempt lower priority transfers. \\
    Transfer-ID     & A small overflowing integer that increments with every transfer
                      of this data type from a given node. \\
\end{UAVCANSimpleTable}

\subsection{Message publication}

Message publication is the main method of communication between UAVCAN nodes.

A published message is carried by a single message transfer that contains the serialized message object.
A published message does not contain any additional fields besides those listed in the table
\ref{table:common_transfer_properties}.

In order to publish a message, the publishing node must have a node-ID that is unique within the network.
An exception applies to \emph{anonymous message publications}.

\subsubsection{Anonymous message publication}\label{sec:transport_anonymous_message_publication}

An anonymous message transfer is a transfer that can be sent from a node that does not have a node-ID.
This kind of message transfer is especially useful for facilitation of \emph{plug-and-play nodes}
(a high-level concept that is reviewed in detail in chapter \ref{sec:application_layer}).

A node that does not have a node-ID is said to be in \emph{passive mode}.
Passive nodes are unable to initiate regular data exchanges,
but they can listen to the transfers exchanged over the bus,
and they can emit anonymous message transfers.

An anonymous message has the same properties as a regular message, except for the source node-ID.

An anonymous transfer can only be a single-frame transfer. Multi-frame anonymous message transfers are not allowed.
This restriction must be kept in mind when designing message data types
intended for use with anonymous message transfers:
when used with anonymous transfers, the whole message must fit into a single transport frame;
however, the same data type can be used with multi-frame regular (non-anonymous) transfers, if desired.

Anonymous messages may require special handling logic depending on the transport layer in use.

\subsubsection{Message timing requirements}

Generally, a message transmission should be aborted if it cannot be completed in 1 second.
Applications are allowed to deviate from this recommendation,
provided that every such deviation is explicitly documented.
It is expected that high-frequency high-priority messages may opt for lower timeout values,
whereas low-priority delayable data may opt for higher timeout values to account for network congestion.

\subsection{Service invocation}

A service invocation sequence consists of two related service transfers:
\emph{service request transfer} and \emph{service response transfer}.

A service request transfer is sent from the invoking node -- \emph{client node} -- to the node
that provides the service -- \emph{server node}.
Upon handling the request, the server node responds to the client node with a service response transfer.
The client will match the response with the corresponding request by comparing the following values:
server node-ID, service-ID, and the transfer-ID.

The tables \ref{table:service_request_transfer_properties} and \ref{table:service_response_transfer_properties}
describe the properties of service request and service response transfers, respectively.

Both the client and the server must have node-ID values that are unique within the network;
service invocation is not available to passive nodes.
The client and the server must be two distinct nodes.

\begin{UAVCANSimpleTable}{Service request transfer properties}{|l X|}\label{table:service_request_transfer_properties}
    Property                        & Description \\
    Payload                         & The serialized service request object. \\
    Service-ID                      & See the table \ref{table:common_transfer_properties}. \\
    Source node-ID                  & The node-ID of the client (the invoking node). \\
    Destination node-ID             & The node-ID of the server (the invoked node). \\
    Priority                        & See the table \ref{table:common_transfer_properties}. \\
    Transfer-ID                     & An integer value that:
        \begin{enumerate}
            \item allows the server to distinguish the request from other requests from the same client;
            \item allows the client to match the response with its request.
        \end{enumerate} \\
\end{UAVCANSimpleTable}

\begin{UAVCANSimpleTable}{Service response transfer properties}{|l X|}\label{table:service_response_transfer_properties}
    Property                        & Description \\
    Payload                         & The serialized service response object. \\
    Service-ID                      & Same value as in the request transfer. \\
    Source node-ID                  & The node-ID of the server (the invoked node). \\
    Destination node-ID             & The node-ID of the client (the invoking node). \\
    Priority                        & Same value as in the request transfer. \\
    Transfer-ID                     & Same value as in the request transfer. \\
\end{UAVCANSimpleTable}

\subsubsection{Service timing requirements}

Applications are recommended to follow the service invocation timing recommendations specified below.
Applications are allowed to deviate from these recommendations,
provided that every such deviation is explicitly documented.

\begin{itemize}
    \item Service transfer transmission should be aborted if does not complete in 1 second.
    \item The client should stop waiting for a response from the server if one has not arrived within 1 second.
\end{itemize}

If the server uses a significant part of the timeout period to process the request,
the client might drop the request before receiving the response.
It is recommended to ensure that the server will be able to process any request in less than 0.5 seconds.

\subsection{Transfer priority}\label{sec:transfer_prioritization}

UAVCAN transfers are prioritized by means of the transfer priority property,
which allows at least 8 (eight) different priority levels for all types of transfers
(some transports may support more than eight priority levels).
Transfers with higher priority levels preempt transfers with lower priority levels,
delaying their transmission until there are no more higher priority transfers to exchange.

\begin{remark}[breakable]
    The priority level mnemonics and their usage recommendations are specified in the following list.
    The mapping between the mnemonics and actual numeric identifiers is transport-dependent.

    % https://forum.uavcan.org/t/transfer-priority-level-mnemonics/218/6?u=pavel.kirienko
    \begin{description}
        \item[Exceptional] -- The bus designer can ignore these messages when calculating bus load since they
        should only be sent when a total system failure has occurred.
        For example, a self-destruct message on a rocket would use this priority.
        Another analogy is an NMI on a microcontroller.

        \item[Immediate] -- Immediate is a ``high priority message'' but with additional latency constraints.
        Since exceptional messages are not considered when designing a bus, the latency of immediate messages
        can be determined by considering only immediate messages.

        \item[Fast] -- Fast and immediate are both ``high priority messages'' but with additional latency constraints.
        Since exceptional messages are not considered when designing a bus,
        the latency of fast messages can be determined by considering only immediate and fast messages.

        \item[High] -- High priority messages are more important than nominal messages but have looser
        latency requirements than fast messages. This priority is used so that,
        in the presence of rogue nominal messages, important commands can be received.
        For example, one might envision a failure mode where a temperature sensor starts to
        load a vehicle bus with nominal messages.
        The vehicle remains operational (for a time) because the controller is exchanging fast and
        immediate messages with sensors and actuators.
        A system safety monitor is able to detect the distressed bus and command the vehicle to a
        safe state by sending high priority messages to the controller.

        \item[Nominal] -- This is what all messages should use by default.
        Specifically the heartbeat messages should use this priority.

        \item[Low] -- Low priority messages are expected to be sent on a bus under all conditions but cannot
        prevent the delivery of nominal messages.
        They are allowed to be delayed but latency should be constrained by the bus designer.

        \item[Slow] -- Slow messages are low priority messages that have no time sensitivity at all.
        The bus designer need only ensure that, for all possible system states,
        these messages will eventually be sent.

        \item[Optional] -- These messages might never be sent (theoretically) for some possible system states.
        The system must tolerate never exchanging optional messages in every possible state.
        The bus designer can ignore these messages when calculating bus load.
        This should be the priority used for diagnostic or debug messages that are not required on an
        operational system.
    \end{description}
\end{remark}

\subsection{Transfer descriptor}\label{sec:transfer_descriptor}

Transfer emission and reception processes rely on the concept of \emph{transfer descriptor}.

A transfer descriptor is a set of properties that identify a particular set of transfers that originate
from the same source node, share the same port-ID, same kind (message or service), and are addressed to the same
destination node (the latter applies only to unicast transfers).

The properties that constitute a transfer descriptor are listed below:

\begin{itemize}
    \item Transfer kind (message or service).
    \item Port-ID (subject-ID for message transfers, service-ID for service transfers).
    \item Source node-ID.
    \item Destination node-ID (only for service transfers).
\end{itemize}

For convenience, two derived definitions are introduced.
Their objective is to simplify the description of transfer reception and emission logic that appears later in this
specification.
\begin{description}
    \item[Emitted transfer descriptor] -- a transfer descriptor where the source node-ID equals the local node's ID.
    \item[Received transfer descriptor] -- a transfer descriptor where the destination node-ID equals
    the local node's ID (for service transfers) or is not defined (for message transfers).
\end{description}

\subsubsection{Hard real-time considerations}

Hard real-time applications require a predictable and deterministic data processing time.
The concept of transfer descriptor plays an important role in communication;
hence, its contribution to the worst case data processing load should be carefully analyzed.

\begin{remark}
    From the above definition of transfer descriptor it is easy to derive that for any
    message subject-ID or any service subject-ID the maximum number of transfer descriptors
    that can be observed by the local node will never exceed the number of nodes on the bus minus
    one\footnote{The local node cannot exchange data with itself, hence minus one.}.
    If the number of nodes on the bus cannot be known in advance, it can be considered to equal 128,
    which is the maximum node capacity of a UAVCAN bus.

    The total number of distinct transfer descriptors that can be observed by a node on any valid UAVCAN bus
    is a product of the number of distinct port-ID values utilized by the node and the number of other nodes on the bus.

    The transport emission and reception logic defined later in this specification relies on data structures
    indexed by transfer descriptor values.
    Elements of such structures can be easily accessed via constant-complexity static look-up tables
    because the worst case number of elements is always statically known.
\end{remark}

\section{Transfer emission}

\subsection{Transfer-ID computation}\label{sec:transfer_id}

The \emph{transfer-ID} is a small unsigned integer value in the range from 0 to 31, inclusive,
that is provided for every transfer.
This value is crucial for many aspects of UAVCAN communication\footnote{One might be tempted to use the transfer-ID
value for temporal synchronization of parallel message streams originating from the same node,
where messages bearing the same transfer-ID value are supposed to correspond to the same moment of time.
Such use is strongly discouraged because it is impossible to detect if one node is more than
32 messages behind another.
If temporal synchronization is necessary, explicit time stamping should be used instead.};
specifically:
\begin{description}
    \item[Message sequence monitoring] - the continuously increasing transfer-ID allows receiving nodes to
    detect lost messages and detect when a message stream from any remote node is interrupted.

    \item[Service response matching] - when a server responds to a request, it uses the same transfer-ID for the
    response as in the request,
    allowing any node to emit concurrent requests to the same server while being able to
    match each response with the corresponding request.

    \item[Transport frame deduplication] - for single-frame transfers,
    the transfer-ID allows receiving nodes to work around the transport
    frame duplication problem\footnote{This is a well-known issue that can be observed with certain
    transports such as CAN bus -- a frame that appears valid to the receiver may under certain
    (rare) conditions appear invalid to the transmitter, triggering the latter to retransmit the frame,
    in which case it will be duplicated on the side of the receiver.
    Sequence counting mechanisms such as the transfer-ID or the toggle bit (both of which are used in UAVCAN)
    allow applications to circumvent this problem.} (multi-frame transfers combat the frame duplication
    problem using the toggle bit, which is introduced later).

    \item[Multi-frame transfer reassembly] - more info is provided in section \ref{sec:transfer_reception}.

    \item[Automatic management of redundant interfaces] - the transfer-ID parameter allows the UAVCAN protocol
    stack to perform automatic switchover to a back-up interface shall the primary interface fail.
    The switchover logic can be completely transparent to the application, joining several independent
    redundant physical transports into a highly reliable single virtual communication channel.
\end{description}

For message transfers and service request transfers the ID value should be computed as described below.
For service response transfers this value must be directly copied from the corresponding service request transfer.

Every node that is interested in emitting transfers must maintain a mapping
(or a similar functionally equivalent static structure\footnote{For example, simple static variables.})
from emitted transfer descriptors (section \ref{sec:transfer_descriptor}) to transfer-ID counters.
This mapping is referred to as the \emph{emitted transfer-ID map}.

Whenever a node needs to emit a transfer, it will query its transfer-ID map for the appropriate transfer descriptor.
If the map does not contain such entry, a new entry will be created with the transfer-ID counter initialized to zero.
The node will use the current value of the transfer-ID from the map for the transfer,
and then the value stored in the map will be incremented by one.
When the stored transfer-ID exceeds its maximum value, it will roll over to zero.

It is expected that some nodes will need to emit certain transfers aperiodically or on an ad-hoc basis,
thereby creating unused entries in the emitted transfer-ID map.
If such aperiodic or ad-hoc transfers are of interest,
the worst case number of unused entries can be determined statically as a function of the number of
port identifiers used and the number of addressed nodes on the bus (the latter applies to services only).
Nodes are not allowed to remove any entries from the transfer-ID map as long as they are running.

\subsection{Single frame transfers}

If the size of the entire transfer payload does not exceed the space available for payload in a single transport frame,
the whole transfer will be contained in one transport frame.
Such transfer is called a \emph{single-frame transfer}.

Single frame transfers are more efficient than multi-frame transfers in terms of throughput, latency,
and data overhead.

\subsection{Multi-frame transfers}\label{sec:transport_multi_frame_transfers}

\emph{Multi-frame transfers} are used when the size of the transfer payload exceeds the space available
for payload in a single transport frame.

Two new concepts are introduced in the context of multi-frame transfers, both of which are reviewed below in detail:
\begin{samepage}
\begin{itemize}
    \item Transfer CRC\footnote{CRC stands for ``cyclic redundancy check'', an error-detecting code
    added to data transmissions to reduce the likelihood of undetected data corruption.}.
    \item Toggle bit.
\end{itemize}
\end{samepage}

In order to emit a multi-frame transfer, the node must first compute the CRC for the entirety of the transfer payload.
The node appends the resulting CRC value at the end of the transfer payload in the big-endian byte order,
and then emits the resulting byte set in chunks as an ordered sequence of transport frames,
where the first transport frame contains the beginning of the payload bytes,
and the last transport frame contains the last bytes of the payload (possibly none) plus the transfer CRC.

The data field of all transport frames of a multi-frame transfer, except the last one, should be fully utilized.
Applications are allowed to limit the maximum amount of data transferred per transport frame in order to
improve the preemption granularity, thus reducing the worst case latency of higher priority
transfers\footnote{For example, some CAN FD applications may choose to restrict the maximum payload size to 32 bytes
rather than the protocol limit of 64 bytes, as that provides more opportunities for higher-priority frames to
take over the bus. The trade-off is that smaller frames lead to higher transfer fragmentation, increase the bus load,
and increase the overall average latency.}.
Receiving nodes must be prepared to reconstruct multi-frame transfers that utilize the
available payload space partially.

All frames of a multi-frame transfer should be pushed to the transmission queue at once,
in the proper order from the first frame to the last frame.
Explicit gap time between transport frames belonging to the same transfer should not be introduced;
rather, implementations always should strive to minimize it.
Re-ordering of frames belonging to the same multi-frame transfer is prohibited.

\subsubsection{Transfer CRC}\label{sec:transfer_crc}

Transfer CRC allows receiving nodes to ensure that a received multi-frame transfer has been reassembled correctly.

It should be understood that the transfer CRC is not intended for bit-level data integrity checks,
as that must be managed by the transport layer implementation on a per-frame
basis\footnote{Bit-level errors at the transport frame level may compromise the error-detecting
properties of the transfer CRC.}.
As such, the transfer CRC allows receiving nodes to ensure that all of the frames of a multi-frame
transfer were received, all of the received frames were reassembled in the correct order,
and that all of the received frames belong to the same multi-frame transfer.

The transfer CRC is computed over the entire payload of the transfer.
Certain transport implementations\footnote{Such as CAN FD.} may require a short sequence of padding bytes
to be added at the end of the transfer payload due to the low granularity of the frame payload length property;
in that case, the padding bytes must be included in the CRC computation as well,
as if they were part of the useful payload.

The resulting CRC value is appended to the transfer in the \emph{big-endian byte order}
(most significant byte first),
in order to take advantage of the CRC residue check intrinsic to the used algorithm.

The transfer CRC algorithm specification is provided in the table \ref{table:transfer_crc_params}.

\begin{minipage}{0.7\textwidth}
\begin{UAVCANSimpleTable}{Transfer CRC algorithm parameters}{|ll|}\label{table:transfer_crc_params}
    Property        & Value \\
    Name            & CRC-16/CCITT-FALSE \\
    Initial value   & $\mathrm{FFFF}_{16}$ \\
    Polynomial      & $\mathrm{1021}_{16}$ \\
    Reverse         & No \\
    Output XOR      & $0$ \\
    Residue         & $0$ \\
    Check           & $\left(49, 50, \ldots, 56, 57\right) \rightarrow \mathrm{29B1}_{16}$ \\
\end{UAVCANSimpleTable}
\end{minipage}

The following code snippet provides a basic implementation of the transfer CRC algorithm in C++.

\begin{minipage}{0.9\textwidth}
\begin{minted}{cpp}
// UAVCAN transfer CRC algorithm implementation in C++.
// License: CC0, no copyright reserved.

#include <iostream>
#include <cstdint>
#include <cstddef>

class TransferCRC
{
    std::uint16_t value_ = 0xFFFFU;

public:
    void add(std::uint8_t byte)
    {
        value_ ^= static_cast<std::uint16_t>(byte) << 8U;
        for (std::uint8_t bit = 8; bit > 0; --bit)
        {
            if ((value_ & 0x8000U) != 0)
            {
                value_ = (value_ << 1U) ^ 0x1021U;
            }
            else
            {
                value_ = value_ << 1U;
            }
        }
    }

    void add(const std::uint8_t* bytes, std::size_t length)
    {
        while (length-- > 0)
        {
            add(*bytes++);
        }
    }

    [[nodiscard]] std::uint16_t get() const { return value_; }
};

int main()
{
    TransferCRC crc;
    crc.add(reinterpret_cast<const std::uint8_t*>("123456789"), 9);
    std::cout << std::hex << "0x" << crc.get() << std::endl;  // Outputs 0x29B1
    return 0;
}
\end{minted}
\end{minipage}

\subsubsection{Toggle bit}\label{sec:toggle_bit}

The toggle bit is a property defined at the transport frame level.
Its purpose is to detect and avoid transport frame duplication errors in multi-frame
transfers\footnote{In single-frame transfers, transport frame deduplication is based on the transfer-ID counter.}.

The toggle bit of the first transport frame of a multi-frame transfer must be set to one.
The toggle bits of the following transport frames of the transfer must alternate,
i.e., the toggle bit of the second transport frame must be zero,
the toggle bit of the third transport frame must be one, and so on.

For single-frame transfers, the toggle bit must be set to one or removed completely,
whichever option works best for the particular transport.

Transfers where the initial value of the toggle bit is zero must be ignored.
The initial state of the toggle bit may be inverted in the future revisions of the protocol
to facilitate automatic protocol version detection.

\subsection{Redundant interface support}

In configurations with redundant bus interfaces,
nodes are required to submit every outgoing transfer to the transmission queues of
all available redundant interfaces simultaneously.
It is recognized that perfectly simultaneous transmission may not be possible due to different
utilization rates of the redundant interfaces and different phasing of their traffic;
however, that is not an issue for UAVCAN.
If perfectly simultaneous frame submission is not possible, interfaces with lower numerical index
should be handled in the first order.

An exception to the above rule applies if the payload of the transfer depends on some properties
of the interface through which the transfer is emitted.
An example of such a special case is the time synchronization algorithm leveraged by UAVCAN
(documented in chapter \ref{sec:application_layer} of the specification).

Redundant interfaces are used for increased fault tolerance, not for load sharing reasons.
Whenever a node is connected to an interface the likelihood of the interface failing is increased.
This suggests that backup interfaces may only interconnect with mission-critical equipment,
unless a homogeneous network architecture is desired\footnote{Heterogeneous transport configuration
complicates the analysis of the network, which might make it impractical in safety-critical deployments.
In that case, a simpler configuration where each available redundant bus is connected to every node may be
preferred.}.
See section \ref{sec:phy_non_uniform_transport_redundancy}.

\section{Transfer reception}\label{sec:transfer_reception}

\subsection{Transfer-ID comparison}\label{sec:transfer_id_forward_distance}

The following explanation relies on the concept of the \emph{transfer-ID forward distance}.
Transfer-ID forward distance $F$ is a function of two transfer-ID values,
$A$ and $B$, that defines the number of increment operations that need to be applied to
$A$ so that $A^\prime{} = B$, assuming modulo 32 arithmetic\footnote{%
    For example:
    $A=0, B=0, F\rightarrow0$;
    $A=0, B=5, F\rightarrow5$;
    $A=5, B=0, F\rightarrow27$;
    $A=31, B=30, F\rightarrow31$;
    $A=31, B=0, F\rightarrow1$.
}:
$$A + F = B \quad (\bmod{}\ 32)$$
The \emph{half range} of transfer-ID is 16.

The following code sample provides an example implementation of the transfer-ID comparison algorithm in C++.

\begin{minipage}{0.9\textwidth}  % Mini page is needed to prevent page breaks within the snippet
\begin{minted}{cpp}
// UAVCAN transfer-ID forward distance computation algorithm implemented in C++.
// License: CC0, no copyright reserved.

#include <cstdint>
#include <iostream>
#include <cassert>

constexpr std::uint8_t TransferIDBitLength = 5;  // Defined by the specification

[[nodiscard]]
constexpr std::uint8_t computeForwardDistance(std::uint8_t a, std::uint8_t b)
{
    constexpr std::uint8_t MaxValue = (1U << TransferIDBitLength) - 1U;
    assert((a <= MaxValue) && (b <= MaxValue));

    std::int16_t d = static_cast<std::int16_t>(b) - static_cast<std::int16_t>(a);
    if (d < 0)
    {
        d += 1U << TransferIDBitLength;
    }

    assert(d >= 0);
    assert(d <= MaxValue);
    assert(((a + d) & MaxValue) == b);
    return static_cast<std::uint8_t>(d);
}

int main()
{
    assert(0  == computeForwardDistance(0, 0));
    assert(1  == computeForwardDistance(0, 1));
    assert(7  == computeForwardDistance(0, 7));
    assert(0  == computeForwardDistance(7, 7));
    assert(31 == computeForwardDistance(31, 30)); // overflow
    assert(1  == computeForwardDistance(31, 0));  // overflow
    return 0;
}
\end{minted}
\end{minipage}

\subsection{State variables}

\subsubsection{Main principles}

Nodes that receive transfers must keep a certain set of state variables for each
received transfer descriptor (section \ref{sec:transfer_descriptor}).

The set of state variables as documented in the table \ref{table:transfer_receiver_state_variables}
will be referred to as the \emph{receiver state}.
For the purposes of this specification, it is assumed that the node will maintain a
mapping from transfer descriptors to receiver states, which will be referred to as the \emph{receiver map}.
It is understood that implementations might prefer different architectures, which is permitted as
long as the resulting behavior of the node observable at the protocol level is functionally equivalent.

Whenever a node receives a transfer, it will query its receiver map for the matching received transfer descriptor.
If the matching state does not exist, the node will add a new receiver state to the map
and initialize it as defined in section \ref{sec:transfer_reception_initial_state}.
The node then will proceed with the procedure of \emph{receiver state update},
which is defined in section \ref{sec:transfer_reception_state_update_redundant} for redundant transports
and section \ref{sec:transfer_reception_state_update_non_redundant} for non-redundant transports.

It is expected that some transfers will be aperiodic or ad-hoc,
which implies that the receiver map may over time accumulate receiver states that are no longer used.
Therefore, nodes are allowed, but not required, to remove any receiver state from the receiver map
as soon as the state reaches the \emph{transfer-ID timeout condition}\footnote{Such behavior is
not recommended for hard real-time applications, where deterministic static look-up tables
should be preferred instead.},
as defined in section \ref{sec:transfer_id_timeout_condition}.

Receiver state can only be modified when a new transport frame of a matching transfer is received.
This guarantee simplifies implementation, as it implies that the receiver states will not
require any periodic background maintenance activities.

\begin{UAVCANSimpleTable}{Transfer reception state variables}{|l X|}
    State               & Description \label{table:transfer_receiver_state_variables} \\
    Transfer payload    & Useful payload byte sequence; extended upon reception of new matching transport frames. \\
    Transfer-ID         & The transfer-ID value of the next expected transport frame. Section \ref{sec:transfer_id}. \\
    Next toggle bit     & Expected value of the toggle bit in the next transport frame.
                          Section \ref{sec:toggle_bit}. \\
    Transfer timestamp  & The local monotonic timestamp sampled when the first frame of the transfer arrived.
                          Here, ``monotonic'' means that the reference clock does not change its rate or make leaps. \\
    Interface index     & Only in the case of redundant transport interfaces. \\
\end{UAVCANSimpleTable}

\subsubsection{Initial state}\label{sec:transfer_reception_initial_state}

The initial state is reached when a new entry of the receiver map is created or an existing entry is reset.
Like any other state update, an entry can be created or reset only synchronously with
the reception of a matching transport frame.

Upon reset, the receiver state will meet the following conditions:

\begin{itemize}
    \item The transfer payload buffer is empty.
    \item The transfer-ID state matches the actual transfer-ID value from the newly received transfer,
    unless this is a non-first frame of a multi-frame transfer.
    In the latter case, the transfer-ID state will match the received transfer-ID value incremented by one.
    \item The toggle bit is set to its initial state (section \ref{sec:toggle_bit}).
    \item The transfer timestamp matches the reception timestamp from the transport frame.
    \item The interface index matches the index of the interface that the new frame was received from
    (for nodes with redundant interfaces only).
\end{itemize}

A receiver state must be reset when any of the following conditions are met:

\begin{itemize}
    \item A new receiver state instance is created.

    \item A transfer-ID timeout condition is reached (section \ref{sec:transfer_id_timeout_condition}).

    \item A first frame of a transfer (either a multi-frame or a single-frame; in the latter case, the same frame
    would also be the last frame of the transfer) is received from the same interface as the previous frame
    (does not apply to non-redundantly interfaced nodes),
    and the transfer-ID forward distance (section \ref{sec:transfer_id_forward_distance}) from the received
    transfer-ID to the stored transfer-ID is greater than one.

    \item Only for redundantly interfaced nodes: A first frame of a transfer is received,
    an interface switchover condition is reached (section \ref{sec:transfer_interface_switchover_condition}),
    and the transfer-ID forward distance from the stored transfer-ID to the received transfer-ID is
    less than the transfer-ID half range (section \ref{sec:transfer_id_forward_distance}).
\end{itemize}

\subsubsection{Transfer-ID timeout condition}\label{sec:transfer_id_timeout_condition}

A state is said to have reached the transfer-ID timeout condition
if the last matching transfer was seen more than 2 (two) seconds ago.
When this condition is reached, the receiver must accept the next transfer disregarding its transfer-ID value.

Nodes are allowed to use different timeout values, if that is believed to benefit the application.
If a different timeout value is used, it must be explicitly documented.

Low timeout values increase the risk of undetected transfer duplication when such transfers are significantly
delayed due to bus congestion, which is possible with very low-priority transfers when the bus utilization is high.

High timeout values increase the risk of an undetected transfer loss when a remote node suffers an emitted transfer-ID
map state loss (e.g., due to the whole node being restarted).
However, the effects of such a transfer loss caused by a loss of state on a remote node
are always constrained to the first transfer only.

\subsubsection{Interface switchover condition}\label{sec:transfer_interface_switchover_condition}

This condition is only applicable for configurations with redundant transport interfaces.
It means that the node is allowed to receive the next transfer from an interface that is not the same
the previous transfer was received from.

The condition is reached when the last matching transfer was successfully received more than
$T_\text{switch}$ seconds ago. The value of $T_\text{switch}$ should not exceed the reception transfer
ID timeout, as defined in section \ref{sec:transfer_id_timeout_condition},
because if $T_\text{switch}$ were to exceed the transfer-ID timeout, an interface switchover would be
performed by the normal receiver state reset procedure, rendering $T_\text{switch}$ useless.

The actual value of $T_\text{switch}$ can be either a constant chosen by the designer according
to the application requirements (e.g., the maximum recovery time in the event of an interface failure),
or the protocol stack can estimate this value automatically by analyzing the transfer intervals.

Nodes are required to let the first interface time out before using the next one because the
transfer-ID field is expected to wrap around frequently (every 32 transfers).
Different interfaces are expected to exhibit different latencies even in a properly functioning system,
especially if the system contains both redundantly-interfaced and non-redundantly-interfaced nodes.
If the latency of a backup interface relative to the primary interface exceeds 32 transfer intervals,
and receiving nodes were to be allowed to switch between interfaces freely disregarding the timeout,
the receiving node would skip the whole period of transfer-IDs (32 transfers will be lost).
The problem would primarily affect low-priority transfers where large latencies are more likely.

\subsection{State update in a redundant interface configuration}
\label{sec:transfer_reception_state_update_redundant}

The following pseudocode demonstrates the transfer reception process
for a configuration with redundant transport interfaces.

\clearpage
\begin{minted}{cpp}
// Constants:
tid_timeout := 2 seconds;
tid_half_range := 16;
iface_switch_delay := UserDefinedConstant; // Or autodetect

// State variables:
initialized := 0;
payload;
this_transfer_timestamp;
current_transfer_id;
iface_index;
toggle;

function receiveFrame(frame)
{
    // Resolving the state flags:
    tid_timed_out := (frame.timestamp - this_transfer_timestamp) > tid_timeout;
    same_iface := frame.iface_index == iface_index;
    first_frame := frame.start_of_transfer;
    non_wrapped_tid := computeForwardDistance(current_transfer_id, frame.transfer_id) < tid_half_range;
    not_previous_tid := computeForwardDistance(frame.transfer_id, current_transfer_id) > 1;
    iface_switch_allowed := (frame.timestamp - this_transfer_timestamp) > iface_switch_delay;
    // Using the state flags from above, deciding whether we need to reset:
    need_restart :=
        (!initialized) or
        (tid_timed_out) or
        (same_iface and first_frame and not_previous_tid) or
        (iface_switch_allowed and first_frame and non_wrapped_tid);

    if (need_restart)
    {
        initialized := 1;
        iface_index := frame.iface_index;
        current_transfer_id := frame.transfer_id;
        payload.clear();
        toggle := 0;
        if (!first_frame)
        {
            current_transfer_id.increment();
            return;         // Ignore this frame, since the start of the transfer has already been missed
        }
    }

    if (frame.iface_index != iface_index)
    {
        return;  // Wrong interface, ignore
    }

    if (frame.toggle != toggle)
    {
        return;  // Unexpected toggle bit, ignore
    }

    if (frame.transfer_id != current_transfer_id)
    {
        return;  // Unexpected transfer-ID, ignore
    }

    if (first_frame)
    {
        this_transfer_timestamp := frame.timestamp;
    }

    toggle := !toggle;
    payload.append(frame.data);

    if (frame.last_frame)
    {
        // CRC validation for multi-frame transfers is intentionally omitted for brevity
        processTransfer(payload, ...);
        current_transfer_id.increment();
        toggle := 0;
        payload.clear();
    }
}
\end{minted}

\clearpage
\subsection{State update in a non-redundant interface configuration}
\label{sec:transfer_reception_state_update_non_redundant}

The following pseudocode demonstrates the transfer reception process for a configuration
with a non-redundant transport interface.
This is a specialization of the more general algorithm defined for redundant transport.

\begin{minted}{cpp}
// Constants:
tid_timeout := 2 seconds;

// State variables:
initialized := 0;
payload;
this_transfer_timestamp;
current_transfer_id;
toggle;

function receiveFrame(frame)
{
    // Resolving the state flags:
    tid_timed_out := (frame.timestamp - this_transfer_timestamp) > tid_timeout;
    first_frame := frame.start_of_transfer;
    not_previous_tid := computeForwardDistance(frame.transfer_id, current_transfer_id) > 1;
    // Using the state flags from above, deciding whether we need to reset:
    need_restart :=
        (!initialized) or
        (tid_timed_out) or
        (first_frame and not_previous_tid);

    if (need_restart)
    {
        initialized := 1;
        current_transfer_id := frame.transfer_id;
        payload.clear();
        toggle := 0;
        if (!first_frame)
        {
            current_transfer_id.increment();
            return; // Ignore this frame, since the start of the transfer has already been missed
        }
    }

    if (frame.toggle != toggle)
    {
        return;  // Unexpected toggle bit, ignore
    }

    if (frame.transfer_id != current_transfer_id)
    {
        return;  // Unexpected transfer-ID, ignore
    }

    if (first_frame)
    {
        this_transfer_timestamp := frame.timestamp;
    }

    toggle := !toggle;
    payload.append(frame.data);

    if (frame.last_frame)
    {
        // CRC validation for multi-frame transfers is intentionally omitted for brevity
        processTransfer(payload, ...);
        current_transfer_id.increment();
        toggle := 0;
        payload.clear();
    }
}
\end{minted}

% Please keep \clearpage in front of every transport-specific specification to enforce clear separation!
\clearpage\input{transport_layer/can.tex}
