mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-02-05 15:18:45 +00:00
207 lines
8.4 KiB
C++
207 lines
8.4 KiB
C++
#ifndef SDV_CRC_H
|
|
#define SDV_CRC_H
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <stddef.h>
|
|
|
|
namespace sdv
|
|
{
|
|
/**
|
|
* @brief Reflect the bits within the data type (change the order MSB <--> LSB).
|
|
* @tparam T The type to use for bit reflection.
|
|
* @param[in] tValue The value to reflect. Must be a arithmetic or boolean type.
|
|
* @return The reflected value.
|
|
*/
|
|
template <typename T>
|
|
constexpr T reflect(T tValue)
|
|
{
|
|
static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, bool>);
|
|
|
|
T tMask = 1;
|
|
T tReflection{0};
|
|
for (size_t nBit = 0; nBit < sizeof(T) * 8; nBit++)
|
|
{
|
|
tReflection <<= 1;
|
|
if (tValue & tMask)
|
|
tReflection |= 0x1;
|
|
tMask <<= 1;
|
|
}
|
|
return tReflection;
|
|
}
|
|
|
|
/**
|
|
* @brief Templated CRC calculation class
|
|
* @tparam TCRC The CRC type to use for the calculation.
|
|
* @tparam tPolynomial The polynomial of the CRC function.
|
|
* @tparam tInitVal The initial value to use for the calculation.
|
|
* @tparam tXorOut XOR the result with the provided value.
|
|
* @tparam bReflectIn Reflect the input bits.
|
|
* @tparam bReflectOut Reflect the output bits.
|
|
*/
|
|
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
|
|
class crc
|
|
{
|
|
public:
|
|
using TCRCType = TCRC; ///< CRC type
|
|
|
|
/**
|
|
* @brief Calculate the CRC checksum value providing a buffer with data of type T.
|
|
* @attention This function doesn't reset the CRC that was calculated before.
|
|
* @remarks The CRC calculation occurs byte-wise regardless of the endianness of the the processor architecture.
|
|
* @tparam T Type of the value buffer to calculate the CRC for.
|
|
* @param[in] pData Pointer to the value buffer.
|
|
* @param[in] nCount Amount of values in the buffer.
|
|
* @return The calculated CRC checksum.
|
|
*/
|
|
template <typename T>
|
|
TCRCType calc_checksum(const T* pData, size_t nCount) noexcept;
|
|
|
|
/**
|
|
* @brief Add one value to the calculation.
|
|
* @remarks The CRC calculation occurs byte-wise regardless of the endianness of the the processor architecture.
|
|
* @tparam T Type of the value buffer to calculate the CRC for.
|
|
* @param[in] tValue The value to add to the calculation.
|
|
*/
|
|
template <typename T>
|
|
void add(T tValue) noexcept;
|
|
|
|
/**
|
|
* @brief Get the currently calculated checksum.
|
|
* @return The CRC checksum.
|
|
*/
|
|
TCRCType get_checksum() const noexcept;
|
|
|
|
/**
|
|
* @brief Set a CRC checksum to continue the calculation with additional data.
|
|
* @param[in] tCrcValue The previously calculated CRC value.
|
|
*/
|
|
void set_checksum(TCRCType tCrcValue) noexcept;
|
|
|
|
/**
|
|
* @brief Reset the current calculation (resets the CRC value to its initial value).
|
|
*/
|
|
void reset() noexcept;
|
|
|
|
private:
|
|
/**
|
|
* @brief With of the CRC type in bits.
|
|
*/
|
|
static constexpr uint64_t m_nWidth = 8 * sizeof(TCRCType);
|
|
|
|
/**
|
|
* @brief MSB for the CRC type.
|
|
*/
|
|
static constexpr uint64_t m_nMsb = 1ull << (m_nWidth - 1);
|
|
|
|
/**
|
|
* @brief CRC lookup table.
|
|
*/
|
|
static constexpr auto m_arrTable = []
|
|
{
|
|
std::array<TCRCType, 256> arrTemp{};
|
|
for (size_t tDividend = 0; tDividend < 256; ++tDividend)
|
|
{
|
|
TCRCType tRemainder = static_cast<TCRCType>(tDividend << (m_nWidth - 8));
|
|
for (uint8_t bit = 8; bit > 0; --bit)
|
|
{
|
|
if (tRemainder & m_nMsb)
|
|
tRemainder = (tRemainder << 1) ^ tPolynomial;
|
|
else
|
|
tRemainder = (tRemainder << 1);
|
|
}
|
|
arrTemp[tDividend] = tRemainder;
|
|
}
|
|
return arrTemp;
|
|
}();
|
|
|
|
TCRCType m_tCrcValue = tInitVal; ///< Calculated CRC value.
|
|
};
|
|
|
|
/// SAE-J1850: polynomial 0x1D, initial = 0xFF, final_xor = 0xFF, reflect_input = false, reflect_output = false
|
|
using crcSAE_J1850 = sdv::crc<uint8_t, 0x1du, 0xff, 0xff, false, false>;
|
|
|
|
/// AUTOSAR_8H2F: polynomial 0x2F, initial = 0xFF, final_xor = 0xFF, reflect_input = false, reflect_output = false)
|
|
using crcAUTOSAR_8H2F = sdv::crc<uint8_t, 0x2fu, 0xff, 0xff, false, false>;
|
|
|
|
/// CCITT-FALSE: polynomial 0x1021, initial = 0xFFFF, final_xor = 0, reflect_input = false, reflect_output = false
|
|
using crcCCITT_FALSE = sdv::crc<uint16_t, 0x1021u, 0xffffu, 0, false, false> ;
|
|
|
|
/// ARC: polynomial 0x8005, initial = 0, final_xor = 0, reflect_input = true, reflect_output = true
|
|
using crcARC = sdv::crc<uint16_t, 0x8005, 0, 0, true, true>;
|
|
|
|
/// IEEE_802_3 polynomial 0x04C11DB7, initial = 0xFFFFFFFF, final_xor = 0xFFFFFFFF, reflect_input = true, reflect_output = true
|
|
using crcIEEE_802_3 = sdv::crc<uint32_t, 0x04C11DB7u, 0xffffffffu, 0xffffffffu, true, true> ;
|
|
|
|
/// AUTOSAR_P4 polynomial 0xF4ACFB13, initial = 0xFFFFFFFF, final_xor = 0xFFFFFFFF, reflect_input = true, reflect_output = true
|
|
using crcAUTOSAR_P4 = sdv::crc<uint32_t, 0xF4ACFB13u, 0xffffffffu, 0xffffffffu, true, true> ;
|
|
|
|
/// CRC32-C Castagnoli polynomial 0x1EDC6F41, initial = 0xFFFFFFFF, final_xor = 0xFFFFFFFF, reflect_input = true,
|
|
/// reflect_output = true
|
|
using crcCRC32C = sdv::crc<uint32_t, 0x1EDC6F41, 0xffffffffu, 0xffffffffu, true, true> ;
|
|
|
|
/// ECMA (polynomial 0x42F0E1EBA9EA3693, initial = 0xFFFFFFFFFFFFFFFF, final_xor = 0xFFFFFFFFFFFFFFFF, reflect_input = true,
|
|
/// reflect_output = true
|
|
using crcECMA = sdv::crc<uint64_t, 0x42F0E1EBA9EA3693, 0xffffffffffffffffu, 0xffffffffffffffffu, true, true>;
|
|
|
|
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
|
|
template <typename T>
|
|
typename crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::TCRCType
|
|
crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::calc_checksum(const T* pData, size_t nCount) noexcept
|
|
{
|
|
if (!pData || !nCount) return get_checksum();
|
|
for (size_t nIndex = 0; nIndex < nCount; nIndex++)
|
|
add(pData[nIndex]);
|
|
return get_checksum();
|
|
}
|
|
|
|
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
|
|
template <typename T>
|
|
inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::add(T tValue) noexcept
|
|
{
|
|
if constexpr (bReflectIn)
|
|
{
|
|
for (size_t nIndex = 0; nIndex < sizeof(T); ++nIndex)
|
|
{
|
|
uint8_t data = static_cast<uint8_t>(reflect(reinterpret_cast<uint8_t*>(&tValue)[nIndex]) ^ (m_tCrcValue >> (m_nWidth - 8)));
|
|
m_tCrcValue = m_arrTable[data] ^ (m_tCrcValue << 8);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (size_t nIndex = 0; nIndex < sizeof(T); ++nIndex)
|
|
{
|
|
uint8_t data = static_cast<uint8_t>((reinterpret_cast<uint8_t*>(&tValue)[nIndex]) ^ (m_tCrcValue >> (m_nWidth - 8)));
|
|
m_tCrcValue = m_arrTable[data] ^ (m_tCrcValue << 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
|
|
inline typename crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::TCRCType
|
|
crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::get_checksum() const noexcept
|
|
{
|
|
if constexpr (bReflectOut)
|
|
return static_cast<TCRCType>(reflect(m_tCrcValue) ^ tXorOut);
|
|
else
|
|
return static_cast<TCRCType>(m_tCrcValue ^ tXorOut);
|
|
}
|
|
|
|
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
|
|
inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::set_checksum(TCRCType tCrcValue) noexcept
|
|
{
|
|
if constexpr (bReflectOut)
|
|
m_tCrcValue = static_cast<TCRCType>(reflect(static_cast<TCRCType>(tCrcValue ^ tXorOut)));
|
|
else
|
|
m_tCrcValue = static_cast<TCRCType>(tCrcValue ^ tXorOut);
|
|
}
|
|
|
|
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
|
|
inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::reset() noexcept
|
|
{
|
|
m_tCrcValue = tInitVal;
|
|
}
|
|
|
|
} // namespace sdv
|
|
|
|
#endif // SDV_CRC_H
|