|
| 1 | +\section{Cyphal/serial (experimental)}\label{sec:transport_serial} |
| 2 | + |
| 3 | +\hyphenation{Cyphal/serial} % Disable hyphenation. |
| 4 | + |
| 5 | +\subsection{Overview} |
| 6 | + |
| 7 | +This section specifies a concrete transport that operates on top of raw byte-level communication channels, |
| 8 | +such as TCP/IP connections, SSL, UART, RS-232, RS-422, USB CDC ACM, |
| 9 | +and any similar communication links that allow exchange of unstructured byte streams. |
| 10 | +Cyphal/serial may also be used to store Cyphal frames in files. |
| 11 | +\textbf{% |
| 12 | + As of this version, the Cyphal/serial specification remains experimental. |
| 13 | + Breaking changes affecting wire compatibility are possible. |
| 14 | +} |
| 15 | + |
| 16 | +As Cyphal/serial is designed to operate over unstructured byte streams, |
| 17 | +it defines a custom framing protocol, custom frame header format, and a custom integrity checking mechanism. |
| 18 | + |
| 19 | +\begin{CyphalSimpleTable}{Cyphal/serial transport capabilities\label{table:transport_serial_capabilities}}{|l X l|} |
| 20 | + Parameter & Value & References \\ |
| 21 | + |
| 22 | + Maximum node-ID value & |
| 23 | + 65534 (16 bits wide). & |
| 24 | + \ref{sec:basic} \\ |
| 25 | + |
| 26 | + Transfer-ID mode & |
| 27 | + Monotonic, 64 bits wide. & |
| 28 | + \ref{sec:transport_transfer_id} \\ |
| 29 | + |
| 30 | + Number of transfer priority levels & |
| 31 | + 8 (no additional levels). & |
| 32 | + \ref{sec:transport_transfer_priority} \\ |
| 33 | + |
| 34 | + Largest single-frame transfer payload & |
| 35 | + Unlimited. & |
| 36 | + \ref{sec:transport_transfer_payload} \\ |
| 37 | + |
| 38 | + Anonymous transfers & |
| 39 | + Available. & |
| 40 | + \ref{sec:transport_route_specifier} \\ |
| 41 | +\end{CyphalSimpleTable} |
| 42 | + |
| 43 | +\subsection{Framing} |
| 44 | + |
| 45 | +Cyphal/serial uses the ``Consistent Overhead Byte Stuffing'' (COBS) encapsulation method\footnote{% |
| 46 | + Stuart Cheshire and Mary Baker. 1999. Consistent overhead Byte stuffing. |
| 47 | + IEEE/ACM Trans. Netw. 7, 2 (April 1999), 159--172. \mbox{\url{https://doi.org/10.1109/90.769765}}. |
| 48 | + The COBS overhead is 1 byte in every 254 bytes of encapsulated data, which is about 0.4\%. |
| 49 | +} with zero byte as the frame delimiter. |
| 50 | +Due to the nature of COBS, the frame delimiter will not appear in the frame payload. |
| 51 | +A frame delimiter may terminate a frame and/or indicate the start of a new frame. |
| 52 | +The number of frame delimiters between adjacent frames may exceed one. |
| 53 | + |
| 54 | +\begin{figure}[H] |
| 55 | + \centering |
| 56 | + $$ |
| 57 | + \texttt{\huge{...}}% |
| 58 | + \underbrace{\texttt{\huge{0}}}_{\substack{\text{frame} \\ \text{delimiter}}}% |
| 59 | + \underbrace{\texttt{\huge{<frame>}}}_{\substack{\text{COBS-encoded} \\ \text{frame contents}}}% |
| 60 | + \underbrace{\texttt{\huge{0}}}_{\substack{\text{frame} \\ \text{delimiter}}}% |
| 61 | + \underbrace{\texttt{\huge{<frame>}}}_{\substack{\text{COBS-encoded} \\ \text{frame contents}}}% |
| 62 | + \underbrace{\texttt{\huge{0}}}_{\substack{\text{frame} \\ \text{delimiter}}}% |
| 63 | + \texttt{\huge{...}}% |
| 64 | + $$ |
| 65 | + \caption{COBS framing\label{fig:transport_serial_cobs}} |
| 66 | +\end{figure} |
| 67 | + |
| 68 | +A frame consists of two parts: |
| 69 | +the fixed-size header (section~\ref{sec:transport_serial_header}) |
| 70 | +immediately followed by the payload (section~\ref{sec:transport_serial_payload}). |
| 71 | +The header contains a dedicated header-CRC field which allows implementations to detect frame corruption early. |
| 72 | + |
| 73 | +Neither the underlying medium nor the Cyphal/serial transport layer impose any restrictions on the maximum frame size, |
| 74 | +which allows all Cyphal/serial transfers to be single-frame transfers\footnote{% |
| 75 | + Omitting multi-frame transfers as a requirement is expected to simplify implementations. |
| 76 | +}. |
| 77 | + |
| 78 | +\subsection{Header}\label{sec:transport_serial_header} |
| 79 | + |
| 80 | +The layout of the Cyphal/serial header is shown in the following snippet in DSDL notation |
| 81 | +(section~\ref{sec:dsdl}). |
| 82 | + |
| 83 | +\begin{samepage} |
| 84 | +\begin{minted}{python} |
| 85 | +# This 24-byte header can be aliased as a C structure with each field being naturally aligned: |
| 86 | +# |
| 87 | +# uint8_t version; |
| 88 | +# uint8_t priority; |
| 89 | +# uint16_t source_node_id; |
| 90 | +# uint16_t destination_node_id; |
| 91 | +# uint16_t data_specifier_snm; |
| 92 | +# uint64_t transfer_id; |
| 93 | +# uint32_t frame_index_eot; |
| 94 | +# uint16_t user_data; |
| 95 | +# uint8_t header_crc16_big_endian[2]; |
| 96 | + |
| 97 | +uint4 version |
| 98 | +# The version of the header format. This document specifies version 1. |
| 99 | +# Packets with an unknown version number must be ignored. |
| 100 | + |
| 101 | +void4 |
| 102 | + |
| 103 | +uint3 priority |
| 104 | +# The values are assigned from 0 (HIGHEST priority) to 7 (LOWEST priority). |
| 105 | +# The numerical priority identifiers are chosen to be consistent with Cyphal/CAN. |
| 106 | + |
| 107 | +void5 |
| 108 | + |
| 109 | +uint16 source_node_id |
| 110 | +# The node-ID of the source node. |
| 111 | +# Value 65535 represents anonymous transfers. |
| 112 | + |
| 113 | +uint16 destination_node_id |
| 114 | +# The node-ID of the destination node. |
| 115 | +# Value 65535 represents broadcast transfers. |
| 116 | + |
| 117 | +uint15 data_specifier |
| 118 | +# If this is a message transfer, this value equals the subject-ID. |
| 119 | +# If this is a service response transfer, this value equals the service-ID. |
| 120 | +# If this is a service request transfer, this value equals 16384 + service-ID. |
| 121 | + |
| 122 | +bool service_not_message |
| 123 | +# If true, this is a service transfer. If false, this is a message transfer. |
| 124 | + |
| 125 | +@assert _offset_ == {64} |
| 126 | +uint64 transfer_id |
| 127 | +# The monotonic transfer-ID value of the current transfer (never overflows). |
| 128 | + |
| 129 | +uint31 frame_index |
| 130 | +# Transmit zero. Drop frame if received non-zero. |
| 131 | + |
| 132 | +bool end_of_transfer |
| 133 | +# Transmit true. Drop frame if received false. |
| 134 | + |
| 135 | +uint16 user_data |
| 136 | +# Opaque application-specific data with user-defined semantics. |
| 137 | +# Generic implementations should emit zero and ignore this field upon reception. |
| 138 | + |
| 139 | +uint8[2] header_crc16_big_endian |
| 140 | +# CRC-16/CCITT-FALSE of the preceding serialized header data in the big endian byte order. |
| 141 | +# Application of the CRC function to the entire header shall yield zero, otherwise the header is malformed. |
| 142 | + |
| 143 | +@assert _offset_ / 8 == {24} |
| 144 | +@sealed # The payload data follows. |
| 145 | +\end{minted} |
| 146 | +\end{samepage} |
| 147 | + |
| 148 | +\subsection{Payload}\label{sec:transport_serial_payload} |
| 149 | + |
| 150 | +The transfer payload is appended with a transfer CRC field. |
| 151 | +The transfer CRC function is \textbf{CRC-32C} (section~\ref{sec:appendix_crc32c}), |
| 152 | +and its value is serialized in the little-endian byte order. |
| 153 | +The transfer CRC function is applied to the entire transfer payload and only transfer payload (header not included). |
| 154 | + |
| 155 | +A node receiving a transfer should verify the correctness of its transfer CRC. |
| 156 | + |
| 157 | +\subsection{Examples} |
| 158 | + |
| 159 | +% $ ncat --broker --listen -p 50905 -vv |
| 160 | +% |
| 161 | +% $ nc localhost 50905 | xxd -g1 |
| 162 | +% |
| 163 | +% $ export UAVCAN__SERIAL__IFACE='socket://127.0.0.1:50905' |
| 164 | +% $ export UAVCAN__NODE__ID=1234 |
| 165 | +% $ y pub -N1 1234:uavcan.primitive.string '"012345678"' |
| 166 | +\begin{remark} |
| 167 | + The snippet given below contains the hexadecimal dump of the following Cyphal/serial transfer: |
| 168 | + |
| 169 | + \begin{description} |
| 170 | + \item[Priority] nominal |
| 171 | + \item[Transfer-ID] 0 |
| 172 | + \item[Transfer kind] message with the subject-ID 1234 |
| 173 | + \item[Source node-ID] 1234 |
| 174 | + \item[Destination node-ID] None |
| 175 | + \item[Header user data] 0 |
| 176 | + \item[Transfer payload] \verb|uavcan.primitive.String.1| containing string ``\verb|012345678|'' |
| 177 | + \end{description} |
| 178 | + |
| 179 | + The payload is shown in segments for clarity: |
| 180 | + |
| 181 | + \begin{itemize} |
| 182 | + \item The first byte is the starting delimiter of the first frame. |
| 183 | + \item The second byte is a COBS overhead byte (one for the entire transfer). |
| 184 | + \item The following block of 24 bytes is the COBS-encoded header. |
| 185 | + \item The third-to-last block is the COBS-encoded transfer payload, |
| 186 | + containing the two bytes of the array length prefix followed by the string data. |
| 187 | + \item The second-to-last block of four bytes is the COBS-encoded transfer-CRC. |
| 188 | + \item The last byte is the ending frame delimiter. |
| 189 | + \end{itemize} |
| 190 | + |
| 191 | + \begin{verbatim} |
| 192 | +00 |
| 193 | +09 |
| 194 | +01 04 d2 04 ff ff d2 04 01 01 01 01 01 01 01 01 01 01 02 80 01 04 08 12 |
| 195 | +09 0e 30 31 32 33 34 35 36 37 38 |
| 196 | +84 a2 2d e2 |
| 197 | +00 |
| 198 | + \end{verbatim} |
| 199 | +\end{remark} |
| 200 | + |
| 201 | +\begin{remark} |
| 202 | + The snippet given below contains the hexadecimal dump of the following Cyphal/serial transfer: |
| 203 | + |
| 204 | + \begin{description} |
| 205 | + \item[Priority] nominal |
| 206 | + \item[Transfer-ID] 0 |
| 207 | + \item[Transfer kind] message with the subject-ID 1234 |
| 208 | + \item[Source node-ID] 4321 |
| 209 | + \item[Destination node-ID] None |
| 210 | + \item[Header user data] 0 |
| 211 | + \item[Transfer payload] \verb|uavcan.primitive.Empty.1| |
| 212 | + \end{description} |
| 213 | + |
| 214 | + The payload is shown in segments for clarity: |
| 215 | + |
| 216 | + \begin{itemize} |
| 217 | + \item The first byte is the starting delimiter of the first frame. |
| 218 | + \item The second byte is a COBS overhead byte (one for the entire transfer). |
| 219 | + \item The following block of 24 bytes is the COBS-encoded header. |
| 220 | + \item The second-to-last block of four bytes is the COBS-encoded transfer-CRC, |
| 221 | + which is zero as the payload is empty. |
| 222 | + \item The last byte is the ending frame delimiter. |
| 223 | + \end{itemize} |
| 224 | + |
| 225 | + \begin{verbatim} |
| 226 | +00 |
| 227 | +09 |
| 228 | +01 04 d2 04 ff ff e1 10 01 01 01 01 01 01 01 01 01 01 02 80 01 03 50 79 |
| 229 | +01 01 01 01 |
| 230 | +00 |
| 231 | + \end{verbatim} |
| 232 | +\end{remark} |
0 commit comments