Skip to content

Commit e7155a4

Browse files
Add Cyphal/serial (#128)
Closes #99 --------- Co-authored-by: maksimdrachov <[email protected]>
1 parent c6ed43d commit e7155a4

File tree

4 files changed

+238
-1
lines changed

4 files changed

+238
-1
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@
261261
"natively",
262262
"ned",
263263
"neq",
264+
"Netw",
264265
"NMEA",
265266
"NMI",
266267
"nodiscard",
@@ -302,6 +303,7 @@
302303
"pseudorandom",
303304
"PSU",
304305
"py",
306+
"pycyphal",
305307
"pydsdl",
306308
"Pygments",
307309
"quaternion",
@@ -372,6 +374,7 @@
372374
"Tx",
373375
"Typ",
374376
"u-Blox",
377+
"UART",
375378
"UAV",
376379
"UAVCAN",
377380
"uavcan.org",

specification/introduction/introduction.tex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ \section{Referenced sources}
224224
\item ``A Passive Solution to the Sensor Synchronization Problem'', Edwin Olson.
225225
\item ``Implementing a Distributed High-Resolution Real-Time Clock using the CAN-Bus'', M. Gergeleit and H. Streich.
226226
\item ``In Search of an Understandable Consensus Algorithm (Extended Version)'', Diego Ongaro and John Ousterhout.
227+
\item ``Consistent Overhead Byte Stuffing'', Stuart Cheshire and Mary Baker.
227228
\end{itemize}
228229

229230
\section{Revision history}
@@ -239,7 +240,7 @@ \subsection{v1.0 -- work in progress}
239240
\item The constraint on DSDL namespaces being defined in a single folder was removed. Namespaces can be hosted
240241
across multiple repositories and code can be generated from a union of said folders.
241242

242-
\item Cyphal/UDP transport specification has been introduced.
243+
\item Cyphal/UDP and Cyphal/serial transport specifications have been introduced.
243244
\end{itemize}
244245

245246
\subsection{v1.0-beta -- Sep 2020}
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
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}

specification/transport/transport.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ \chapter{Transport layer}\label{sec:transport}
2222
\clearpage\input{transport/abstract.tex}
2323
\clearpage\input{transport/can/can.tex}
2424
\clearpage\input{transport/udp/udp.tex}
25+
\clearpage\input{transport/serial/serial.tex}

0 commit comments

Comments
 (0)