|
3 | 3 | # Author: Pavel Kirienko <pavel@opencyphal.org> |
4 | 4 |
|
5 | 5 | """ |
6 | | -Cyphal/Serial transport overview |
| 6 | +Cyphal/serial transport overview |
7 | 7 | ++++++++++++++++++++++++++++++++ |
8 | 8 |
|
9 | | -The Cyphal/Serial transport is designed for OSI L1 byte-level duplex serial links and tunnels: |
| 9 | +The Cyphal/serial transport is designed for byte-level communication channels, such as: |
10 | 10 |
|
11 | | -- UART, RS-422/485/232 (duplex); the recommended rates are: 115200 bps, 921600 bps, 3 Mbps, 10 Mbps, 100 Mbps. |
12 | | -- USB CDC ACM. |
13 | | -- TCP/IP encapsulation. |
| 11 | +- TCP/IP |
| 12 | +- UART, RS-422/232 |
| 13 | +- USB CDC ACM |
14 | 14 |
|
15 | | -It may also be suited for raw transport log storage, because one-dimensional flat binary files are structurally |
16 | | -similar to serial byte-level links. |
| 15 | +It may also be suited for raw transport log storage. |
17 | 16 |
|
18 | 17 | This transport module contains no media sublayers because the media abstraction |
19 | 18 | is handled directly by the `PySerial <https://pypi.org/project/pyserial>`_ |
20 | 19 | library and the underlying operating system. |
21 | 20 |
|
22 | | -The serial transport supports all transfer categories: |
| 21 | +For the full protocol definition, please refer to the `Cyphal Specification <https://opencyphal.org/specification>`_. |
23 | 22 |
|
24 | | -+--------------------+--------------------------+---------------------------+ |
25 | | -| Supported transfers| Unicast | Broadcast | |
26 | | -+====================+==========================+===========================+ |
27 | | -|**Message** | Yes, non-spec extension | Yes | |
28 | | -+--------------------+--------------------------+---------------------------+ |
29 | | -|**Service** | Yes | Banned by Specification | |
30 | | -+--------------------+--------------------------+---------------------------+ |
31 | 23 |
|
| 24 | +Forward error correction (FEC) |
| 25 | +++++++++++++++++++++++++++++++ |
32 | 26 |
|
33 | | -Protocol definition |
34 | | -+++++++++++++++++++ |
35 | | -
|
36 | | -The packet header is defined as follows (byte/bit ordering in this definition follow the DSDL specification: |
37 | | -least significant first):: |
38 | | -
|
39 | | - uint4 version # = 1, Discard the frame if not. |
40 | | - void4 |
41 | | -
|
42 | | - uint3 priority # 0 = highest, 7 = lowest; the rest are unused. |
43 | | - void5 |
44 | | -
|
45 | | - uint16 source_node_id # 0xFFFF = anonymous. |
46 | | - uint16 destination_node_id # 0xFFFF = broadcast. |
47 | | - uint16 data_specifier # subject-ID | (service-ID + RNR (Request, Not Response)) |
48 | | -
|
49 | | - uint64 transfer_id |
50 | | -
|
51 | | - uint31 frame_index |
52 | | - bool end_of_transfer # Set if last frame of the transfer |
53 | | -
|
54 | | - uint16 user_data # Opaque application-specific data with user-defined semantics. |
55 | | - # Generic implementations should ignore |
56 | | -
|
57 | | - uint8[2] header_crc_be # CRC-16-CCITT of the header (all fields above). |
58 | | - # Most significant byte first. |
59 | | -
|
60 | | -For message frames, the data specifier field contains the subject-ID value, |
61 | | -so that the most significant bit is always cleared. |
62 | | -For service frames, the most significant bit (15th) is always set, |
63 | | -and the second-to-most-significant bit (14th) is set for request transfers only; |
64 | | -the remaining 14 least significant bits contain the service-ID value. |
65 | | -
|
66 | | -Total header size: 24 bytes (192 bits). |
67 | | -
|
68 | | -The header is prepended before the frame payload; the resulting structure is |
69 | | -encoded into its serialized form using the following packet format: |
70 | | -
|
71 | | -+-------------------------+--------------+---------------+--------------------------------+-------------------------+ |
72 | | -| Frame delimiter **0x00**|Escaped header|Escaped payload| Escaped CRC-32C of the payload | Frame delimiter **0x00**| |
73 | | -+=========================+==============+===============+================================+=========================+ |
74 | | -| 1 byte | 24 bytes | >=0 bytes | 4 bytes | 1 byte | |
75 | | -+-------------------------+--------------+---------------+--------------------------------+-------------------------+ |
76 | | -| Single-byte frame | | Four bytes long, little-endian | Same frame delimiter as | |
77 | | -| delimiter **0x00**. | | byte order; The CRC is | at the start. | |
78 | | -| Begins a new frame and | | computed over the unescaped | Terminates the current | |
79 | | -| possibly terminates the | | (i.e., original form) payload, | frame and possibly | |
80 | | -| previous frame. | | not including the header | begins the next frame. | |
81 | | -| | | (because the header has a | | |
82 | | -| | | dedicated CRC). | | |
83 | | -| +------------------------------+--------------------------------+ | |
84 | | -| | This part is escaped using COBS alorithm by Chesire and Baker | | |
85 | | -| | http://www.stuartcheshire.org/papers/COBSforToN.pdf. | | |
86 | | -| | A frame delimiter (0) is guaranteed to never occur here. | | |
87 | | -+-------------------------+------------------------------+--------------------------------+-------------------------+ |
88 | | -
|
89 | | -The frame encoding overhead is 1 byte in every 254 bytes of the header+payload+CRC, which is about ~0.4%. |
90 | | -There is a somewhat relevant discussion at |
91 | | -https://forum.opencyphal.org/t/uavcan-serial-issues-with-dma-friendliness-and-bandwidth-overhead/846. |
92 | | -
|
93 | | -The last four bytes of a multi-frame transfer payload contain the CRC32C (Castagnoli) hash of the transfer |
94 | | -payload in little-endian byte order. |
95 | | -The multi-frame transfer logic (decomposition and reassembly) is implemented in a separate |
96 | | -transport-agnostic module :mod:`pycyphal.transport.commons.high_overhead_transport`. |
97 | | -**Despite the fact that the support for multi-frame transfers is built into this transport, |
98 | | -it should not be relied on and it may be removed later.** |
99 | | -The reason is that serial links do not have native support for framing, and as such, |
100 | | -it is possible to configure the MTU to be arbitrarily high to avoid multi-frame transfers completely. |
101 | | -The lack of multi-frame transfers simplifies implementations drastically, which is important for |
102 | | -deeply-embedded systems. As such, all serial transfers should be single-frame transfers. |
103 | | -
|
104 | | -Note that we use CRC-32C (Castagnoli) as the header/frame CRC instead of CRC-32K2 (Koopman-2) |
105 | | -which is superior at short data blocks offering the Hamming distance of 6 as opposed to 4. |
106 | | -This is because Castagnoli is superior for transfer CRC which is often sufficiently long |
107 | | -to flip the balance in favor of Castagnoli rather than Koopman. |
108 | | -We could use Koopman for the header/frame CRC and keep Castagnoli for the transfer CRC, |
109 | | -but such diversity is harmful because it would require implementers to keep two separate CRC tables |
110 | | -which may be costly in embedded applications and may deteriorate the performance of CPU caches. |
111 | | -
|
112 | | -
|
113 | | -Unreliable links and temporal redundancy |
114 | | -++++++++++++++++++++++++++++++++++++++++ |
115 | | -
|
116 | | -The serial transport supports the deterministic data loss mitigation option, |
117 | | -where a transfer can be repeated several times to reduce the probability of its loss. |
| 27 | +This transport supports optional FEC through full duplication of transfers. |
118 | 28 | This feature is discussed in detail in the documentation for the UDP transport :mod:`pycyphal.transport.udp`. |
119 | 29 |
|
120 | 30 |
|
|
0 commit comments