164 lines
4.5 KiB
C++
164 lines
4.5 KiB
C++
/*
|
|
{{copyright}}
|
|
*/
|
|
|
|
/*
|
|
{{version}}
|
|
*/
|
|
|
|
/*
|
|
{{license}}
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <span>
|
|
|
|
namespace sdi_ToolBox::generic
|
|
{
|
|
//--------------------------------------------------------------
|
|
/**
|
|
* @class CRC16_modbus
|
|
* @brief CRC16 calculator for the Modbus protocol.
|
|
*
|
|
* Provides both static and incremental interfaces to compute the CRC16 checksum
|
|
* as used in the Modbus protocol (polynomial 0xA001, initial value 0xFFFF).
|
|
*
|
|
* Usage examples:
|
|
* @code
|
|
* // One-shot CRC calculation
|
|
* std::array<uint8_t, 8> data = { ... };
|
|
* uint16_t crc = Crc16_modbus::computeCRC(data);
|
|
*
|
|
* // Incremental CRC calculation
|
|
* Crc16_modbus crcHandle;
|
|
* crcHandle.init();
|
|
* for (uint8_t b : data) {
|
|
* crcHandle.update(b);
|
|
* }
|
|
* uint16_t crc = crcHandle.finalize();
|
|
* @endcode
|
|
*/
|
|
class CRC16_modbus
|
|
{
|
|
static constexpr uint16_t INITIAL_VALUE = 0xFFFF;
|
|
|
|
public:
|
|
/**
|
|
* @brief Computes the CRC16 of the given data in one call.
|
|
* @param data The data buffer to compute the CRC for.
|
|
* @return The computed CRC16 value.
|
|
*/
|
|
static uint16_t computeCRC(const std::span<const uint8_t> &data);
|
|
|
|
public:
|
|
CRC16_modbus() = default; // Default constructor
|
|
virtual ~CRC16_modbus() = default; // Default destructor
|
|
CRC16_modbus(const CRC16_modbus &other) = default; // Copy constructor
|
|
CRC16_modbus(CRC16_modbus &&other) noexcept = default; // Move constructor
|
|
CRC16_modbus &operator=(const CRC16_modbus &other) = default; // Copy assignment
|
|
CRC16_modbus &operator=(CRC16_modbus &&other) noexcept = default; // Move assignment
|
|
|
|
/**
|
|
* @brief Constructs and initializes the CRC with the given data.
|
|
* @param data The data buffer to initialize and update the CRC with.
|
|
*/
|
|
explicit CRC16_modbus(const std::span<const uint8_t> &data);
|
|
|
|
/**
|
|
* @brief Initializes or re-initializes the CRC to the default value (0xFFFF).
|
|
*/
|
|
void init();
|
|
|
|
/**
|
|
* @brief Updates the CRC with a single byte.
|
|
* @param val The byte value to update the CRC with.
|
|
*/
|
|
void update(const uint8_t &val);
|
|
|
|
/**
|
|
* @brief Updates the CRC with a data buffer.
|
|
* @param data The data buffer to update the CRC with.
|
|
*/
|
|
void update(const std::span<const uint8_t> &data);
|
|
|
|
/**
|
|
* @brief Finalizes the CRC calculation and returns the CRC value.
|
|
* @return The finalized CRC16 value.
|
|
*/
|
|
uint16_t finalize() const;
|
|
|
|
/**
|
|
* @brief Returns the current CRC value.
|
|
* @return The current CRC16 value.
|
|
*/
|
|
[[nodiscard]] uint16_t getCRC() const;
|
|
|
|
protected:
|
|
uint16_t m_crc = INITIAL_VALUE; // Current CRC value
|
|
};
|
|
//--------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------
|
|
/* Compute CRC in one go */
|
|
inline uint16_t CRC16_modbus::computeCRC(const std::span<const uint8_t> &data)
|
|
{
|
|
const CRC16_modbus crc(data);
|
|
return crc.finalize();
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Constructor */
|
|
inline CRC16_modbus::CRC16_modbus(const std::span<const uint8_t> &data)
|
|
{
|
|
init();
|
|
update(data);
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Reinit crc handle */
|
|
inline void CRC16_modbus::init()
|
|
{
|
|
m_crc = INITIAL_VALUE;
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Update CRC */
|
|
inline void CRC16_modbus::update(const uint8_t &val)
|
|
{
|
|
constexpr uint16_t PolynomialValue = 0xA001;
|
|
|
|
m_crc ^= static_cast<uint16_t>(val); // XOR byte into least sig. byte of crc
|
|
for (int i = 8; i != 0; i--) // Loop over each bit
|
|
{
|
|
if ((m_crc & 0x0001) != 0) // If the LSB is set
|
|
{
|
|
m_crc >>= 1; // Shift right and XOR PolynomialValue
|
|
m_crc ^= PolynomialValue;
|
|
}
|
|
else // Else LSB is not set
|
|
{
|
|
m_crc >>= 1; // Just shift right
|
|
}
|
|
}
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Update CRC */
|
|
inline void CRC16_modbus::update(const std::span<const uint8_t> &data)
|
|
{
|
|
for (const auto &c : data)
|
|
update(c);
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Finalize and return CRC value */
|
|
inline uint16_t CRC16_modbus::finalize() const
|
|
{
|
|
return getCRC();
|
|
}
|
|
//--------------------------------------------------------------
|
|
/* Return CRC value */
|
|
inline uint16_t CRC16_modbus::getCRC() const
|
|
{
|
|
return m_crc;
|
|
}
|
|
//--------------------------------------------------------------
|
|
} // namespace sdi_ToolBox::generic
|