21#include "hal/crc_api.h"
25#include "platform/mbed_assert.h"
29#include "platform/SingletonPtr.h"
30#include "rtos/Mutex.h"
32#include <mstd_type_traits>
57template<u
int32_t polynomial, u
int8_t w
idth, CrcMode mode>
60constexpr bool have_crc_table(uint32_t polynomial, uint8_t width)
62#if MBED_CRC_TABLE_SIZE > 0
73constexpr CrcMode choose_crc_mode(uint32_t polynomial, uint8_t width, CrcMode mode_limit)
77 mode_limit == CrcMode::HARDWARE && HAL_CRC_IS_SUPPORTED(polynomial, width) ? CrcMode::HARDWARE :
79 mode_limit <= CrcMode::TABLE && have_crc_table(polynomial, width) ? CrcMode::TABLE :
154template <u
int32_t polynomial = POLY_32BIT_ANSI, u
int8_t w
idth = 32, CrcMode mode_limit = CrcMode::HARDWARE>
156 impl::MbedCRC<polynomial, width, impl::choose_crc_mode(polynomial, width, mode_limit)> crc_impl;
162 HARDWARE = int(::mbed::CrcMode::HARDWARE),
168 typedef size_t crc_data_size_t;
186 MbedCRC(uint32_t initial_xor, uint32_t final_xor,
bool reflect_data,
bool reflect_remainder) :
187 crc_impl(initial_xor, final_xor, reflect_data, reflect_remainder)
194 template<u
int32_t poly = polynomial, std::enable_if_t<poly == POLY_32BIT_ANSI && w
idth == 32,
int> = 0>
199 template<u
int32_t poly = polynomial, std::enable_if_t<poly == POLY_16BIT_IBM && w
idth == 16,
int> = 0>
204 template<u
int32_t poly = polynomial, std::enable_if_t<poly == POLY_16BIT_CCITT && w
idth == 16,
int> = 0>
209 template<u
int32_t poly = polynomial, std::enable_if_t<poly == POLY_7BIT_SD && w
idth == 7,
int> = 0>
214 template<u
int32_t poly = polynomial, std::enable_if_t<poly == POLY_8BIT_CCITT && w
idth == 8,
int> = 0>
229 int32_t
compute(
const void *buffer, crc_data_size_t size, uint32_t *crc)
231 return crc_impl.compute(buffer, size, crc);
257 return crc_impl.compute_partial(buffer, size, crc);
272 return crc_impl.compute_partial_start(crc);
286 return crc_impl.compute_partial_stop(crc);
310#if !defined(DOXYGEN_ONLY)
314template <u
int32_t polynomial, u
int8_t w
idth, CrcMode mode>
317 typedef size_t crc_data_size_t;
320 MbedCRC(uint32_t initial_xor, uint32_t final_xor,
bool reflect_data,
bool reflect_remainder) :
321 _initial_value(adjust_initial_value(initial_xor, reflect_data)),
322 _final_xor(final_xor),
323 _reflect_data(reflect_data),
324 _reflect_remainder(reflect_remainder)
326 static_assert(width <= 32,
"Max 32-bit CRC supported");
338 int32_t compute(
const void *buffer, crc_data_size_t size, uint32_t *crc)
342 status = compute_partial_start(crc);
347 status = compute_partial(buffer, size, crc);
352 status = compute_partial_stop(crc);
377 int32_t compute_partial(
const void *buffer, crc_data_size_t size, uint32_t *crc)
379 const uint8_t *data =
static_cast<const uint8_t *
>(buffer);
380 return do_compute_partial(data, size, crc);
393 int32_t compute_partial_start(uint32_t *crc)
396 if (mode == CrcMode::HARDWARE) {
400 config.
width = width;
410 *crc = _initial_value;
423 int32_t compute_partial_stop(uint32_t *crc)
426 if (mode == CrcMode::HARDWARE) {
427 *crc = hal_crc_get_result();
432 uint_fast32_t p_crc = *crc;
433 if (mode == CrcMode::BITWISE) {
436 if (!_reflect_remainder) {
437 p_crc = reflect_crc(p_crc);
441 p_crc = _reflect_remainder ? reflect(p_crc) : shift_right(p_crc);
445 if (!_reflect_remainder) {
446 p_crc = reflect_crc(p_crc);
451 p_crc &= get_crc_mask();
464 static constexpr uint32_t reflect_constant(uint32_t data)
467 return ((data & 0x00000001) << 31) |
468 ((data & 0x00000002) << 29) |
469 ((data & 0x00000004) << 27) |
470 ((data & 0x00000008) << 25) |
471 ((data & 0x00000010) << 23) |
472 ((data & 0x00000020) << 21) |
473 ((data & 0x00000040) << 19) |
474 ((data & 0x00000080) << 17) |
475 ((data & 0x00000100) << 15) |
476 ((data & 0x00000200) << 13) |
477 ((data & 0x00000400) << 11) |
478 ((data & 0x00000800) << 9) |
479 ((data & 0x00001000) << 7) |
480 ((data & 0x00002000) << 5) |
481 ((data & 0x00004000) << 3) |
482 ((data & 0x00008000) << 1) |
483 ((data & 0x00010000) >> 1) |
484 ((data & 0x00020000) >> 3) |
485 ((data & 0x00040000) >> 5) |
486 ((data & 0x00080000) >> 7) |
487 ((data & 0x00100000) >> 9) |
488 ((data & 0x00200000) >> 11) |
489 ((data & 0x00400000) >> 13) |
490 ((data & 0x00800000) >> 15) |
491 ((data & 0x01000000) >> 17) |
492 ((data & 0x02000000) >> 19) |
493 ((data & 0x04000000) >> 21) |
494 ((data & 0x08000000) >> 23) |
495 ((data & 0x10000000) >> 25) |
496 ((data & 0x20000000) >> 27) |
497 ((data & 0x40000000) >> 29) |
498 ((data & 0x80000000) >> 31);
513#ifdef MSTD_HAS_IS_CONSTANT_EVALUATED
514 static constexpr uint32_t reflect(uint32_t data)
516 return mstd::is_constant_evaluated() ? reflect_constant(data) : __RBIT(data);
519 static uint32_t reflect(uint32_t data)
530 static MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED
531 uint_fast32_t reflect_byte(uint_fast32_t data)
533 return reflect(data) >> 24;
540 static constexpr uint32_t get_reflected_polynomial()
542 return shift_right(reflect_constant(polynomial));
549 static constexpr uint32_t get_top_polynomial()
551 return shift_left(polynomial);
554 const uint32_t _initial_value;
555 const uint32_t _final_xor;
556 const bool _reflect_data;
557 const bool _reflect_remainder;
560 using crc_table_t = std::conditional_t<width <= 8, uint8_t,
561 std::conditional_t<width <= 16, uint16_t,
566#if MBED_CRC_TABLE_SIZE > 0
568 static const crc_table_t _crc_table[MBED_CRC_TABLE_SIZE];
571 static constexpr uint32_t adjust_initial_value(uint32_t initial_xor,
bool reflect_data)
573 if (mode == CrcMode::BITWISE) {
578 return reflect_data ? reflect_crc(initial_xor) : shift_left(initial_xor);
579 }
else if (mode == CrcMode::TABLE) {
582 return reflect_crc(initial_xor);
593 if (mode == CrcMode::HARDWARE) {
594 mbed_crc_mutex->
lock();
604 if (mode == CrcMode::HARDWARE) {
614 static constexpr uint32_t get_crc_mask()
616 return (uint32_t)((uint32_t)2U << (width - 1)) - 1U;
624 static MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED
625 uint32_t reflect_crc(uint32_t data)
627 return reflect(data) >> (32 - width);
635 static constexpr uint32_t shift_left(uint32_t data)
637 return data << (32 - width);
645 static constexpr uint32_t shift_right(uint32_t data)
647 return data >> (32 - width);
651#if (defined __GNUC__ || defined __clang__) && \
652 (defined __arm__ || defined __ARM_ARCH)
653#if (__ARM_ARCH_7M__ == 1U) || \
654 (__ARM_ARCH_7EM__ == 1U) || \
655 (__ARM_ARCH_8M_MAIN__ == 1U) || \
656 (__ARM_ARCH_8_1M_MAIN__ == 1U) || \
657 (__ARM_ARCH_7A__ == 1U)
659#define MBED_CRC_ARM_THUMB2 1
660#define MBED_CRC_THUMB1 0
661#elif (__ARM_ARCH_6M__ == 1U) || \
662 (__ARM_ARCH_8M_BASE__ == 1U)
664#define MBED_CRC_ARM_THUMB2 0
665#define MBED_CRC_THUMB1 1
667#error "Unknown ARM architecture for CRC optimization"
671#define MBED_CRC_ARM_THUMB2 0
672#define MBED_CRC_THUMB1 0
687 static uint_fast32_t do_1_bit_normal(uint_fast32_t p_crc)
689#if MBED_CRC_ARM_THUMB2
690 __asm(
".syntax unified\n\t"
691 "LSLS" "\t%[p_crc], %[p_crc], #1\n\t"
693 "EORCS" "\t%[p_crc], %[poly]"
694 : [p_crc]
"+&r" (p_crc)
695 : [poly]
"rI" (get_top_polynomial())
698 __asm(
".syntax unified\n\t"
699 "LSLS" "\t%[p_crc], %[p_crc], #1\n\t"
701 "EORS" "\t%[p_crc], %[poly]\n"
703 : [p_crc]
"+&l" (p_crc)
704 : [poly]
"l" (get_top_polynomial())
707 if (p_crc & 0x80000000) {
708 p_crc = (p_crc << 1) ^ get_top_polynomial();
710 p_crc = (p_crc << 1);
727 static uint_fast32_t do_1_bit_reflected(uint_fast32_t p_crc)
729#if MBED_CRC_ARM_THUMB2
730 __asm(
".syntax unified\n\t"
731 "LSRS" "\t%[p_crc], %[p_crc], #1\n\t"
733 "EORCS" "\t%[p_crc], %[poly]"
734 : [p_crc]
"+&r" (p_crc)
735 : [poly]
"rI" (get_reflected_polynomial())
738 __asm(
".syntax unified\n\t"
739 "LSRS" "\t%[p_crc], %[p_crc], #1\n\t"
741 "EORS" "\t%[p_crc], %[poly]\n"
743 : [p_crc]
"+&l" (p_crc)
744 : [poly]
"l" (get_reflected_polynomial())
748 p_crc = (p_crc >> 1) ^ get_reflected_polynomial();
750 p_crc = (p_crc >> 1);
764 template<CrcMode mode_ = mode>
765 std::enable_if_t<mode_ == CrcMode::BITWISE, int32_t>
766 do_compute_partial(
const uint8_t *data, crc_data_size_t size, uint32_t *crc)
const
768 uint_fast32_t p_crc = *crc;
772 for (crc_data_size_t
byte = 0;
byte < size;
byte++) {
776 for (
unsigned int bit = 8; bit > 0; --bit) {
777 p_crc = do_1_bit_reflected(p_crc);
782 for (crc_data_size_t
byte = 0;
byte < size;
byte++) {
783 p_crc ^= (uint_fast32_t) data[
byte] << 24;
786 for (
unsigned int bit = 8; bit > 0; --bit) {
787 p_crc = do_1_bit_normal(p_crc);
797#if MBED_CRC_TABLE_SIZE > 0
805 template<CrcMode mode_ = mode>
806 std::enable_if_t<mode_ == CrcMode::TABLE, int32_t>
807 do_compute_partial(
const uint8_t *data, crc_data_size_t size, uint32_t *crc)
const
809 uint_fast32_t p_crc = *crc;
812 bool reflect = !_reflect_data;
814 for (crc_data_size_t
byte = 0;
byte < size;
byte++) {
815 uint_fast32_t data_byte = data[byte];
817 data_byte = reflect_byte(data_byte);
819#if MBED_CRC_TABLE_SIZE == 16
820 p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4);
822 p_crc = _crc_table[(data_byte ^ p_crc) & 0xF] ^ (p_crc >> 4);
824 p_crc = _crc_table[(data_byte ^ p_crc) & 0xFF] ^ (p_crc >> 8);
839 template<CrcMode mode_ = mode>
840 std::enable_if_t<mode_ == CrcMode::HARDWARE, int32_t>
841 do_compute_partial(
const uint8_t *data, crc_data_size_t size, uint32_t *)
const
850#if MBED_CRC_TABLE_SIZE > 0
886uint32_t mbed_tiny_compute_crc32(
const void *data,
int datalen);
CRC object provides CRC generation through hardware or software.
int32_t compute(const void *buffer, crc_data_size_t size, uint32_t *crc)
Compute CRC for the data input Compute CRC performs the initialization, computation and collection of...
int32_t compute_partial_stop(uint32_t *crc)
Get the final CRC value of partial computation.
constexpr MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder)
Lifetime of CRC object.
static constexpr uint8_t get_width()
Get the current CRC width.
int32_t compute_partial_start(uint32_t *crc)
Compute partial start, indicate start of partial computation.
int32_t compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc)
Compute partial CRC for the data input.
static constexpr uint32_t get_polynomial()
Get the current CRC polynomial.
void unlock()
Unlock the mutex that has previously been locked by the same thread.
void lock()
Wait until a Mutex becomes available.
CrcMode
CRC mode selection.
@ BITWISE
Use table-based computation (if table available), else bitwise.
@ TABLE
Use hardware (if available), else table-based computation.
void hal_crc_compute_partial(const uint8_t *data, const size_t size)
Writes data to the current CRC module.
void hal_crc_compute_partial_start(const crc_mbed_config_t *config)
Initialize the hardware CRC module with the given polynomial.
@ POLY_8BIT_CCITT
x8+x2+x+1
@ POLY_16BIT_IBM
x16+x15+x2+1
@ POLY_16BIT_CCITT
x16+x12+x5+1
@ POLY_32BIT_ANSI
x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
Utility class for creating and using a singleton.
uint32_t initial_xor
Initial seed value for the computation.
uint32_t width
CRC Bit Width.
bool reflect_in
Reflect bits on input.
uint32_t polynomial
CRC Polynomial.
bool reflect_out
Reflect bits in final result before returning.
uint32_t final_xor
Final xor value for the computation.