As described in #42403, there was an issue with the existing crc16_ansi() implementation, since it was not calculating the CRC-16-ANSI (aka CRC-16-MODBUS). This is because the existing crc16() function only supported non-reflected input and output (and the CRC-16-ANSI requires reflection on both) and also it did not seem to support correctly inial seeds different from 0x0000 (and, again, the CRC-16-ANSI requires 0xffff as an initial seed). This commit replaces the existing crc16() with a functional pair, crc16() and crc16_reflect(), that also work with any poly, any initial seed and allow to select whether reflection is performed. It also adapts crc16_ansi() so that it actually returns the correct CRC. Fixes #42403. Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
269 lines
8.7 KiB
C
269 lines
8.7 KiB
C
/*
|
|
* 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.
|
|
*
|
|
* 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>
|
|
|
|
#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 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);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|