blob: ba625335a983f0a0b2e82c093b7f1975b1cc6ebd [file] [log] [blame]
/*
* Copyright (c) 2018 Workaround GmbH.
* Copyright (c) 2017 Intel Corporation.
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
* Copyright (c) 2018 Google LLC.
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file
* @brief CRC computation function
*/
#ifndef ZEPHYR_INCLUDE_SYS_CRC_H_
#define ZEPHYR_INCLUDE_SYS_CRC_H_
#include <zephyr/types.h>
#include <stdbool.h>
#include <stddef.h>
#include <zephyr/sys/__assert.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Initial value expected to be used at the beginning of the crc8_ccitt
* computation.
*/
#define CRC8_CCITT_INITIAL_VALUE 0xFF
/**
* @defgroup checksum Checksum
*/
/**
* @defgroup crc CRC
* @ingroup checksum
* @{
*/
/**
* @brief CRC algorithm enumeration
*
* These values should be used with the @ref crc dispatch function.
*/
enum crc_type {
CRC7_BE, /**< Use @ref crc7_be */
CRC8, /**< Use @ref crc8 */
CRC8_CCITT, /**< Use @ref crc8_ccitt */
CRC16, /**< Use @ref crc16 */
CRC16_ANSI, /**< Use @ref crc16_ansi */
CRC16_CCITT, /**< Use @ref crc16_ccitt */
CRC16_ITU_T, /**< Use @ref crc16_itu_t */
CRC32_C, /**< Use @ref crc32_c */
CRC32_IEEE, /**< Use @ref crc32_ieee */
};
/**
* @brief Generic function for computing a CRC-16 without input or output
* reflection.
*
* Compute CRC-16 by passing in the address of the input, the input length
* and polynomial used in addition to the initial value. This is O(n*8) where n
* is the length of the buffer provided. No reflection is performed.
*
* @note If you are planning to use a CRC based on poly 0x1012 the functions
* crc16_itu_t() is faster and thus recommended over this one.
*
* @param poly The polynomial to use omitting the leading x^16
* coefficient
* @param seed Initial value for the CRC computation
* @param src Input bytes for the computation
* @param len Length of the input in bytes
*
* @return The computed CRC16 value (without any XOR applied to it)
*/
uint16_t crc16(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
/**
* @brief Generic function for computing a CRC-16 with input and output
* reflection.
*
* Compute CRC-16 by passing in the address of the input, the input length
* and polynomial used in addition to the initial value. This is O(n*8) where n
* is the length of the buffer provided. Both input and output are reflected.
*
* @note If you are planning to use a CRC based on poly 0x1012 the function
* crc16_ccitt() is faster and thus recommended over this one.
*
* The following checksums can, among others, be calculated by this function,
* depending on the value provided for the initial seed and the value the final
* calculated CRC is XORed with:
*
* - CRC-16/ANSI, CRC-16/MODBUS, CRC-16/USB, CRC-16/IBM
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-modbus
* poly: 0x8005 (0xA001) initial seed: 0xffff, xor output: 0x0000
*
* @param poly The polynomial to use omitting the leading x^16
* coefficient. Important: please reflect the poly. For example,
* use 0xA001 instead of 0x8005 for CRC-16-MODBUS.
* @param seed Initial value for the CRC computation
* @param src Input bytes for the computation
* @param len Length of the input in bytes
*
* @return The computed CRC16 value (without any XOR applied to it)
*/
uint16_t crc16_reflect(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
/**
* @brief Generic function for computing CRC 8
*
* Compute CRC 8 by passing in the address of the input, the input length
* and polynomial used in addition to the initial value.
*
* @param src Input bytes for the computation
* @param len Length of the input in bytes
* @param polynomial The polynomial to use omitting the leading x^8
* coefficient
* @param initial_value Initial value for the CRC computation
* @param reversed Should we use reflected/reversed values or not
*
* @return The computed CRC8 value
*/
uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
bool reversed);
/**
* @brief Compute the checksum of a buffer with polynomial 0x1021, reflecting
* input and output.
*
* This function is able to calculate any CRC that uses 0x1021 as it polynomial
* and requires reflecting both the input and the output. It is a fast variant
* that runs in O(n) time, where n is the length of the input buffer.
*
* The following checksums can, among others, be calculated by this function,
* depending on the value provided for the initial seed and the value the final
* calculated CRC is XORed with:
*
* - CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/KERMIT
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-kermit
* initial seed: 0x0000, xor output: 0x0000
*
* - CRC-16/X-25, CRC-16/IBM-SDLC, CRC-16/ISO-HDLC
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-sdlc
* initial seed: 0xffff, xor output: 0xffff
*
* @note To calculate the CRC across non-contiguous blocks use the return
* value from block N-1 as the seed for block N.
*
* See ITU-T Recommendation V.41 (November 1988).
*
* @param seed Value to seed the CRC with
* @param src Input bytes for the computation
* @param len Length of the input in bytes
*
* @return The computed CRC16 value (without any XOR applied to it)
*/
uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len);
/**
* @brief Compute the checksum of a buffer with polynomial 0x1021, no
* reflection of input or output.
*
* This function is able to calculate any CRC that uses 0x1021 as it polynomial
* and requires no reflection on both the input and the output. It is a fast
* variant that runs in O(n) time, where n is the length of the input buffer.
*
* The following checksums can, among others, be calculated by this function,
* depending on the value provided for the initial seed and the value the final
* calculated CRC is XORed with:
*
* - CRC-16/XMODEM, CRC-16/ACORN, CRC-16/LTE
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-xmodem
* initial seed: 0x0000, xor output: 0x0000
*
* - CRC16/CCITT-FALSE, CRC-16/IBM-3740, CRC-16/AUTOSAR
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-3740
* initial seed: 0xffff, xor output: 0x0000
*
* - CRC-16/GSM
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-gsm
* initial seed: 0x0000, xor output: 0xffff
*
* @note To calculate the CRC across non-contiguous blocks use the return
* value from block N-1 as the seed for block N.
*
* See ITU-T Recommendation V.41 (November 1988) (MSB first).
*
* @param seed Value to seed the CRC with
* @param src Input bytes for the computation
* @param len Length of the input in bytes
*
* @return The computed CRC16 value (without any XOR applied to it)
*/
uint16_t crc16_itu_t(uint16_t seed, const uint8_t *src, size_t len);
/**
* @brief Compute the ANSI (or Modbus) variant of CRC-16
*
* The ANSI variant of CRC-16 uses 0x8005 (0xA001 reflected) as its polynomial
* with the initial * value set to 0xffff.
*
* @param src Input bytes for the computation
* @param len Length of the input in bytes
*
* @return The computed CRC16 value
*/
static inline uint16_t crc16_ansi(const uint8_t *src, size_t len)
{
return crc16_reflect(0xA001, 0xffff, src, len);
}
/**
* @brief Generate IEEE conform CRC32 checksum.
*
* @param *data Pointer to data on which the CRC should be calculated.
* @param len Data length.
*
* @return CRC32 value.
*
*/
uint32_t crc32_ieee(const uint8_t *data, size_t len);
/**
* @brief Update an IEEE conforming CRC32 checksum.
*
* @param crc CRC32 checksum that needs to be updated.
* @param *data Pointer to data on which the CRC should be calculated.
* @param len Data length.
*
* @return CRC32 value.
*
*/
uint32_t crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len);
/**
* @brief Calculate CRC32C (Castagnoli) checksum.
*
* @param crc CRC32C checksum that needs to be updated.
* @param *data Pointer to data on which the CRC should be calculated.
* @param len Data length.
* @param first_pkt Whether this is the first packet in the stream.
* @param last_pkt Whether this is the last packet in the stream.
*
* @return CRC32 value.
*
*/
uint32_t crc32_c(uint32_t crc, const uint8_t *data,
size_t len, bool first_pkt, bool last_pkt);
/**
* @brief Compute CCITT variant of CRC 8
*
* Normal CCITT variant of CRC 8 is using 0x07.
*
* @param initial_value Initial value for the CRC computation
* @param buf Input bytes for the computation
* @param len Length of the input in bytes
*
* @return The computed CRC8 value
*/
uint8_t crc8_ccitt(uint8_t initial_value, const void *buf, size_t len);
/**
* @brief Compute the CRC-7 checksum of a buffer.
*
* See JESD84-A441. Used by the MMC protocol. Uses 0x09 as the
* polynomial with no reflection. The CRC is left
* justified, so bit 7 of the result is bit 6 of the CRC.
*
* @param seed Value to seed the CRC with
* @param src Input bytes for the computation
* @param len Length of the input in bytes
*
* @return The computed CRC7 value
*/
uint8_t crc7_be(uint8_t seed, const uint8_t *src, size_t len);
/**
* @brief Compute a CRC checksum, in a generic way.
*
* This is a dispatch function that calls the individual CRC routine
* determined by @p type.
*
* For 7, 8, and 16-bit CRCs, the relevant @p seed and @p poly values should
* be passed in via the least-significant byte(s).
*
* Similarly, for 7, 8, and 16-bit CRCs, the relevant result is stored in the
* least-significant byte(s) of the returned value.
*
* @param type CRC algorithm to use.
* @param src Input bytes for the computation
* @param len Length of the input in bytes
* @param seed Value to seed the CRC with
* @param poly The polynomial to use omitting the leading coefficient
* @param reflect Should we use reflected/reversed values or not
* @param first Whether this is the first packet in the stream.
* @param last Whether this is the last packet in the stream.
* @return uint32_t the computed CRC value
*/
static inline uint32_t crc_by_type(enum crc_type type, const uint8_t *src, size_t len,
uint32_t seed, uint32_t poly, bool reflect, bool first,
bool last)
{
switch (type) {
case CRC7_BE:
return crc7_be(seed, src, len);
case CRC8:
return crc8(src, len, poly, seed, reflect);
case CRC8_CCITT:
return crc8_ccitt(seed, src, len);
case CRC16:
if (reflect) {
return crc16_reflect(poly, seed, src, len);
} else {
return crc16(poly, seed, src, len);
}
case CRC16_ANSI:
return crc16_ansi(src, len);
case CRC16_CCITT:
return crc16_ccitt(seed, src, len);
case CRC16_ITU_T:
return crc16_itu_t(seed, src, len);
case CRC32_C:
return crc32_c(seed, src, len, first, last);
case CRC32_IEEE:
return crc32_ieee_update(seed, src, len);
default:
break;
}
__ASSERT_NO_MSG(false);
return -1;
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif