Line data Source code
1 1 : /*
2 : * Copyright (c) 2018 Workaround GmbH.
3 : * Copyright (c) 2017 Intel Corporation.
4 : * Copyright (c) 2017 Nordic Semiconductor ASA
5 : * Copyright (c) 2015 Runtime Inc
6 : * Copyright (c) 2018 Google LLC.
7 : * Copyright (c) 2022 Meta
8 : *
9 : * SPDX-License-Identifier: Apache-2.0
10 : */
11 : /** @file
12 : * @brief CRC computation function
13 : */
14 :
15 : #ifndef ZEPHYR_INCLUDE_SYS_CRC_H_
16 : #define ZEPHYR_INCLUDE_SYS_CRC_H_
17 :
18 : #include <zephyr/types.h>
19 : #include <stdbool.h>
20 : #include <stddef.h>
21 :
22 : #include <zephyr/sys/__assert.h>
23 :
24 : #ifdef __cplusplus
25 : extern "C" {
26 : #endif
27 :
28 : /* Initial value expected to be used at the beginning of the crc8_ccitt
29 : * computation.
30 : */
31 0 : #define CRC8_CCITT_INITIAL_VALUE 0xFF
32 0 : #define CRC8_ROHC_INITIAL_VALUE 0xFF
33 :
34 : /* Initial value expected to be used at the beginning of the OpenPGP CRC-24 computation. */
35 0 : #define CRC24_PGP_INITIAL_VALUE 0x00B704CEU
36 : /*
37 : * The CRC-24 value is stored on a 32-bit value, only the 3 least significant bytes
38 : * are meaningful. Use the following mask to only keep the CRC-24 value.
39 : */
40 0 : #define CRC24_FINAL_VALUE_MASK 0x00FFFFFFU
41 :
42 : /**
43 : * @defgroup checksum Checksum
44 : * @ingroup os_services
45 : */
46 :
47 : /**
48 : * @defgroup crc CRC
49 : * @ingroup checksum
50 : * @{
51 : */
52 :
53 : /**
54 : * @brief CRC algorithm enumeration
55 : *
56 : * These values should be used with the @ref crc dispatch function.
57 : */
58 1 : enum crc_type {
59 : CRC4, /**< Use @ref crc4 */
60 : CRC4_TI, /**< Use @ref crc4_ti */
61 : CRC7_BE, /**< Use @ref crc7_be */
62 : CRC8, /**< Use @ref crc8 */
63 : CRC8_CCITT, /**< Use @ref crc8_ccitt */
64 : CRC8_ROHC, /**< Use @ref crc8_rohc */
65 : CRC16, /**< Use @ref crc16 */
66 : CRC16_ANSI, /**< Use @ref crc16_ansi */
67 : CRC16_CCITT, /**< Use @ref crc16_ccitt */
68 : CRC16_ITU_T, /**< Use @ref crc16_itu_t */
69 : CRC24_PGP, /**< Use @ref crc24_pgp */
70 : CRC32_C, /**< Use @ref crc32_c */
71 : CRC32_IEEE, /**< Use @ref crc32_ieee */
72 : };
73 :
74 : /**
75 : * @brief Generic function for computing a CRC-16 without input or output
76 : * reflection.
77 : *
78 : * Compute CRC-16 by passing in the address of the input, the input length
79 : * and polynomial used in addition to the initial value. This is O(n*8) where n
80 : * is the length of the buffer provided. No reflection is performed.
81 : *
82 : * @note If you are planning to use a CRC based on poly 0x1012 the functions
83 : * crc16_itu_t() is faster and thus recommended over this one.
84 : *
85 : * @param poly The polynomial to use omitting the leading x^16
86 : * coefficient
87 : * @param seed Initial value for the CRC computation
88 : * @param src Input bytes for the computation
89 : * @param len Length of the input in bytes
90 : *
91 : * @return The computed CRC16 value (without any XOR applied to it)
92 : */
93 1 : uint16_t crc16(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
94 :
95 : /**
96 : * @brief Generic function for computing a CRC-16 with input and output
97 : * reflection.
98 : *
99 : * Compute CRC-16 by passing in the address of the input, the input length
100 : * and polynomial used in addition to the initial value. This is O(n*8) where n
101 : * is the length of the buffer provided. Both input and output are reflected.
102 : *
103 : * @note If you are planning to use a CRC based on poly 0x1012 the function
104 : * crc16_ccitt() is faster and thus recommended over this one.
105 : *
106 : * The following checksums can, among others, be calculated by this function,
107 : * depending on the value provided for the initial seed and the value the final
108 : * calculated CRC is XORed with:
109 : *
110 : * - CRC-16/ANSI, CRC-16/MODBUS, CRC-16/USB, CRC-16/IBM
111 : * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-modbus
112 : * poly: 0x8005 (0xA001) initial seed: 0xffff, xor output: 0x0000
113 : *
114 : * @param poly The polynomial to use omitting the leading x^16
115 : * coefficient. Important: please reflect the poly. For example,
116 : * use 0xA001 instead of 0x8005 for CRC-16-MODBUS.
117 : * @param seed Initial value for the CRC computation
118 : * @param src Input bytes for the computation
119 : * @param len Length of the input in bytes
120 : *
121 : * @return The computed CRC16 value (without any XOR applied to it)
122 : */
123 1 : uint16_t crc16_reflect(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
124 : /**
125 : * @brief Generic function for computing CRC 8
126 : *
127 : * Compute CRC 8 by passing in the address of the input, the input length
128 : * and polynomial used in addition to the initial value.
129 : *
130 : * @param src Input bytes for the computation
131 : * @param len Length of the input in bytes
132 : * @param polynomial The polynomial to use omitting the leading x^8
133 : * coefficient
134 : * @param initial_value Initial value for the CRC computation
135 : * @param reversed Should we use reflected/reversed values or not
136 : *
137 : * @return The computed CRC8 value
138 : */
139 1 : uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
140 : bool reversed);
141 :
142 : /**
143 : * @brief Compute the checksum of a buffer with polynomial 0x1021, reflecting
144 : * input and output.
145 : *
146 : * This function is able to calculate any CRC that uses 0x1021 as it polynomial
147 : * and requires reflecting both the input and the output. It is a fast variant
148 : * that runs in O(n) time, where n is the length of the input buffer.
149 : *
150 : * The following checksums can, among others, be calculated by this function,
151 : * depending on the value provided for the initial seed and the value the final
152 : * calculated CRC is XORed with:
153 : *
154 : * - CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/KERMIT
155 : * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-kermit
156 : * initial seed: 0x0000, xor output: 0x0000
157 : *
158 : * - CRC-16/X-25, CRC-16/IBM-SDLC, CRC-16/ISO-HDLC
159 : * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-sdlc
160 : * initial seed: 0xffff, xor output: 0xffff
161 : *
162 : * @note To calculate the CRC across non-contiguous blocks use the return
163 : * value from block N-1 as the seed for block N.
164 : *
165 : * See ITU-T Recommendation V.41 (November 1988).
166 : *
167 : * @param seed Value to seed the CRC with
168 : * @param src Input bytes for the computation
169 : * @param len Length of the input in bytes
170 : *
171 : * @return The computed CRC16 value (without any XOR applied to it)
172 : */
173 1 : uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len);
174 :
175 : /**
176 : * @brief Compute the checksum of a buffer with polynomial 0x1021, no
177 : * reflection of input or output.
178 : *
179 : * This function is able to calculate any CRC that uses 0x1021 as it polynomial
180 : * and requires no reflection on both the input and the output. It is a fast
181 : * variant that runs in O(n) time, where n is the length of the input buffer.
182 : *
183 : * The following checksums can, among others, be calculated by this function,
184 : * depending on the value provided for the initial seed and the value the final
185 : * calculated CRC is XORed with:
186 : *
187 : * - CRC-16/XMODEM, CRC-16/ACORN, CRC-16/LTE
188 : * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-xmodem
189 : * initial seed: 0x0000, xor output: 0x0000
190 : *
191 : * - CRC16/CCITT-FALSE, CRC-16/IBM-3740, CRC-16/AUTOSAR
192 : * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-3740
193 : * initial seed: 0xffff, xor output: 0x0000
194 : *
195 : * - CRC-16/GSM
196 : * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-gsm
197 : * initial seed: 0x0000, xor output: 0xffff
198 : *
199 : * @note To calculate the CRC across non-contiguous blocks use the return
200 : * value from block N-1 as the seed for block N.
201 : *
202 : * See ITU-T Recommendation V.41 (November 1988) (MSB first).
203 : *
204 : * @param seed Value to seed the CRC with
205 : * @param src Input bytes for the computation
206 : * @param len Length of the input in bytes
207 : *
208 : * @return The computed CRC16 value (without any XOR applied to it)
209 : */
210 1 : uint16_t crc16_itu_t(uint16_t seed, const uint8_t *src, size_t len);
211 :
212 : /**
213 : * @brief Compute the ANSI (or Modbus) variant of CRC-16
214 : *
215 : * The ANSI variant of CRC-16 uses 0x8005 (0xA001 reflected) as its polynomial
216 : * with the initial * value set to 0xffff.
217 : *
218 : * @param src Input bytes for the computation
219 : * @param len Length of the input in bytes
220 : *
221 : * @return The computed CRC16 value
222 : */
223 1 : static inline uint16_t crc16_ansi(const uint8_t *src, size_t len)
224 : {
225 : return crc16_reflect(0xA001, 0xffff, src, len);
226 : }
227 :
228 : /**
229 : * @brief Generate IEEE conform CRC32 checksum.
230 : *
231 : * @param data Pointer to data on which the CRC should be calculated.
232 : * @param len Data length.
233 : *
234 : * @return CRC32 value.
235 : *
236 : */
237 1 : uint32_t crc32_ieee(const uint8_t *data, size_t len);
238 :
239 : /**
240 : * @brief Update an IEEE conforming CRC32 checksum.
241 : *
242 : * @param crc CRC32 checksum that needs to be updated.
243 : * @param data Pointer to data on which the CRC should be calculated.
244 : * @param len Data length.
245 : *
246 : * @return CRC32 value.
247 : *
248 : */
249 1 : uint32_t crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len);
250 :
251 : /**
252 : * @brief Calculate CRC32C (Castagnoli) checksum.
253 : *
254 : * @param crc CRC32C checksum that needs to be updated.
255 : * @param data Pointer to data on which the CRC should be calculated.
256 : * @param len Data length.
257 : * @param first_pkt Whether this is the first packet in the stream.
258 : * @param last_pkt Whether this is the last packet in the stream.
259 : *
260 : * @return CRC32 value.
261 : *
262 : */
263 1 : uint32_t crc32_c(uint32_t crc, const uint8_t *data,
264 : size_t len, bool first_pkt, bool last_pkt);
265 :
266 : /**
267 : * @brief Compute CCITT variant of CRC 8
268 : *
269 : * Normal CCITT variant of CRC 8 is using 0x07.
270 : *
271 : * @param initial_value Initial value for the CRC computation
272 : * @param buf Input bytes for the computation
273 : * @param len Length of the input in bytes
274 : *
275 : * @return The computed CRC8 value
276 : */
277 1 : uint8_t crc8_ccitt(uint8_t initial_value, const void *buf, size_t len);
278 :
279 : /**
280 : * @brief Compute ROHC variant of CRC 8
281 : *
282 : * ROHC (Robust Header Compression) variant of CRC 8.
283 : * Uses 0x07 as the polynomial with reflection.
284 : *
285 : * @param initial_value Initial value for the CRC computation
286 : * @param buf Input bytes for the computation
287 : * @param len Length of the input in bytes
288 : *
289 : * @return The computed CRC8 value
290 : */
291 1 : uint8_t crc8_rohc(uint8_t initial_value, const void *buf, size_t len);
292 :
293 : /**
294 : * @brief Compute the CRC-7 checksum of a buffer.
295 : *
296 : * See JESD84-A441. Used by the MMC protocol. Uses 0x09 as the
297 : * polynomial with no reflection. The CRC is left
298 : * justified, so bit 7 of the result is bit 6 of the CRC.
299 : *
300 : * @param seed Value to seed the CRC with
301 : * @param src Input bytes for the computation
302 : * @param len Length of the input in bytes
303 : *
304 : * @return The computed CRC7 value
305 : */
306 1 : uint8_t crc7_be(uint8_t seed, const uint8_t *src, size_t len);
307 :
308 : /**
309 : * @brief Compute the CRC-4 checksum of a buffer.
310 : *
311 : * Used by the TMAG5170 sensor. Uses 0x03 as the
312 : * polynomial with no reflection. 4 most significant
313 : * bits of the CRC result will be set to zero.
314 : *
315 : * @param seed Value to seed the CRC with
316 : * @param src Input bytes for the computation
317 : * @param len Length of the input in bytes
318 : *
319 : * @return The computed CRC4 value
320 : */
321 1 : uint8_t crc4_ti(uint8_t seed, const uint8_t *src, size_t len);
322 :
323 : /**
324 : * @brief Generic function for computing CRC 4
325 : *
326 : * Compute CRC 4 by passing in the address of the input, the input length
327 : * and polynomial used in addition to the initial value. The input buffer
328 : * must be aligned to a whole byte. It is guaranteed that 4 most significant
329 : * bits of the result will be set to zero.
330 : *
331 : * @param src Input bytes for the computation
332 : * @param len Length of the input in bytes
333 : * @param polynomial The polynomial to use omitting the leading x^4
334 : * coefficient
335 : * @param initial_value Initial value for the CRC computation
336 : * @param reversed Should we use reflected/reversed values or not
337 : *
338 : * @return The computed CRC4 value
339 : */
340 1 : uint8_t crc4(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
341 : bool reversed);
342 :
343 : /**
344 : * @brief Generate an OpenPGP CRC-24 checksum as defined in RFC 4880 section 6.1.
345 : *
346 : * @param data A pointer to the data on which the CRC will be calculated.
347 : * @param len Data length in bytes.
348 : *
349 : * @return The CRC-24 value.
350 : */
351 1 : uint32_t crc24_pgp(const uint8_t *data, size_t len);
352 :
353 : /**
354 : * @brief Update an OpenPGP CRC-24 checksum.
355 : *
356 : * @param crc The CRC-24 checksum that needs to be updated. The full 32-bit value of the CRC needs
357 : * to be used between calls, do not mask the value to keep only the last 24 bits.
358 : * @param data A pointer to the data on which the CRC will be calculated.
359 : * @param len Data length in bytes.
360 : *
361 : * @return The CRC-24 value. When the last buffer of data has been processed, mask the value
362 : * with CRC24_FINAL_VALUE_MASK to keep only the meaningful 24 bits of the CRC result.
363 : */
364 1 : uint32_t crc24_pgp_update(uint32_t crc, const uint8_t *data, size_t len);
365 :
366 : /**
367 : * @brief Compute a CRC checksum, in a generic way.
368 : *
369 : * This is a dispatch function that calls the individual CRC routine
370 : * determined by @p type.
371 : *
372 : * For 7, 8, 16 and 24-bit CRCs, the relevant @p seed and @p poly values should
373 : * be passed in via the least-significant byte(s).
374 : *
375 : * Similarly, for 7, 8, 16 and 24-bit CRCs, the relevant result is stored in the
376 : * least-significant byte(s) of the returned value.
377 : *
378 : * @param type CRC algorithm to use.
379 : * @param src Input bytes for the computation
380 : * @param len Length of the input in bytes
381 : * @param seed Value to seed the CRC with
382 : * @param poly The polynomial to use omitting the leading coefficient
383 : * @param reflect Should we use reflected/reversed values or not
384 : * @param first Whether this is the first packet in the stream.
385 : * @param last Whether this is the last packet in the stream.
386 : * @return uint32_t the computed CRC value
387 : */
388 1 : static inline uint32_t crc_by_type(enum crc_type type, const uint8_t *src, size_t len,
389 : uint32_t seed, uint32_t poly, bool reflect, bool first,
390 : bool last)
391 : {
392 : switch (type) {
393 : case CRC4:
394 : return crc4(src, len, poly, seed, reflect);
395 : case CRC4_TI:
396 : return crc4_ti(seed, src, len);
397 : case CRC7_BE:
398 : return crc7_be(seed, src, len);
399 : case CRC8:
400 : return crc8(src, len, poly, seed, reflect);
401 : case CRC8_CCITT:
402 : return crc8_ccitt(seed, src, len);
403 : case CRC8_ROHC:
404 : return crc8_rohc(seed, src, len);
405 : case CRC16:
406 : if (reflect) {
407 : return crc16_reflect(poly, seed, src, len);
408 : } else {
409 : return crc16(poly, seed, src, len);
410 : }
411 : case CRC16_ANSI:
412 : return crc16_ansi(src, len);
413 : case CRC16_CCITT:
414 : return crc16_ccitt(seed, src, len);
415 : case CRC16_ITU_T:
416 : return crc16_itu_t(seed, src, len);
417 : case CRC24_PGP: {
418 : uint32_t crc = crc24_pgp_update(seed, src, len);
419 :
420 : if (last)
421 : crc &= CRC24_FINAL_VALUE_MASK;
422 : return crc;
423 : }
424 : case CRC32_C:
425 : return crc32_c(seed, src, len, first, last);
426 : case CRC32_IEEE:
427 : return crc32_ieee_update(seed, src, len);
428 : default:
429 : break;
430 : }
431 :
432 : __ASSERT_NO_MSG(false);
433 : return -1;
434 : }
435 :
436 : /**
437 : * @}
438 : */
439 :
440 : #ifdef __cplusplus
441 : }
442 : #endif
443 :
444 : #endif
|