1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! The CRC-16/MCRF4XX checksum every MAVLink frame carries, and the `CRC_EXTRA`
//! seed derived from a message's shape.
//!
//! MAVLink names its checksum "X.25", but the accumulator it actually uses omits the
//! final inversion that true CRC-16/X-25 applies, which makes it CRC-16/MCRF4XX. The
//! distinction is not cosmetic: the two share a polynomial, initial value, and
//! reflection and differ only in that final XOR, so a frame checked with the wrong one
//! is silently rejected. This module pins the MCRF4XX parameters and is anchored to the
//! catalogue check value, so that trap is closed.
// The reflected form of the CRC-16/CCITT polynomial 0x1021, used because the checksum
// reflects its input and output and so processes each byte least-significant bit first.
const POLY_REFLECTED: u16 = 0x8408;
/// Folds more bytes into a running CRC-16/MCRF4XX.
///
/// # Arguments
///
/// * `crc` - the running value; start a fresh checksum from `0xFFFF`.
/// * `data` - the bytes to fold in.
///
/// # Returns
///
/// The updated CRC.
pub const
/// Computes the CRC-16/MCRF4XX of a byte slice.
///
/// The parameters are width 16, polynomial `0x1021`, initial value `0xFFFF`, input and
/// output reflected, and no final inversion (`xorout = 0x0000`). True CRC-16/X-25 differs
/// only in that final inversion, so this checks `0x6F91` over `"123456789"` where X-25
/// checks `0x906E`.
///
/// # Arguments
///
/// * `data` - the bytes to check.
///
/// # Returns
///
/// The 16-bit CRC.
///
/// # Examples
///
/// ```
/// use pamoja_mavlink::crc16_mcrf4xx;
///
/// // The catalogue check value for CRC-16/MCRF4XX.
/// assert_eq!(crc16_mcrf4xx(b"123456789"), 0x6F91);
/// ```
pub const
/// Computes the checksum a frame carries: the CRC over its bytes with the message's
/// `CRC_EXTRA` folded in last.
///
/// # Arguments
///
/// * `frame` - the frame bytes the checksum covers: everything after the start marker up
/// to but not including the two checksum bytes (and not the signature).
/// * `crc_extra` - the `CRC_EXTRA` seed for the frame's message id.
///
/// # Returns
///
/// The 16-bit checksum to append, low byte first.
pub const
/// Derives a message's `CRC_EXTRA` from its name and base fields.
///
/// MAVLink computes this over the message name, then each base (non-extension) field's
/// type and name in wire order, with an array field's length folded in as one byte, and
/// reduces the 16-bit result to a byte. A receiver folds the seed into every frame's
/// checksum, so a sender and receiver that disagree about a message's shape reject each
/// other's frames instead of silently misreading them. Extension fields are excluded,
/// which is what lets a message gain extension fields without breaking compatibility.
///
/// # Arguments
///
/// * `name` - the message name, such as `"HEARTBEAT"`.
/// * `fields` - the base fields in wire order, each as `(type, name, array_len)`, where
/// `type` is the MAVLink C type such as `"uint16_t"` and `array_len` is `0` for a
/// scalar field.
///
/// # Returns
///
/// The `CRC_EXTRA` byte.
///
/// # Examples
///
/// ```
/// use pamoja_mavlink::message_crc_extra;
///
/// // HEARTBEAT, in wire order: the 4-byte field first, then the five bytes.
/// let crc_extra = message_crc_extra(
/// "HEARTBEAT",
/// &[
/// ("uint32_t", "custom_mode", 0),
/// ("uint8_t", "type", 0),
/// ("uint8_t", "autopilot", 0),
/// ("uint8_t", "base_mode", 0),
/// ("uint8_t", "system_status", 0),
/// ("uint8_t", "mavlink_version", 0),
/// ],
/// );
/// assert_eq!(crc_extra, 50);
/// ```
// The seed derivation itself, over any sequence of `(type, name, array_len)` fields, so
// the descriptor layer derives the same value without collecting its fields into a slice.
pub