跳转至

rocketpi_crc

效果展示

crc

功能说明

  • 集成 component/crc 目录下的多种 CRC 软件实现(CRC4/7/8/16/24/32、CRC32C、CRC32K/4.2 等),并提供统一的 crc.h 接口方便裸机项目引用。
  • 新增 component/crc/crc_test.ccrc_test.h 自检框架,内置 123456789 标准向量,对每一个 CRC 算法执行期望值对比,可在主函数中通过 crc_run_all_tests() 获取结果。
  • Core/Src/main.c 中在系统初始化后调用 CRC 自检,并通过 USART2 打印每项的期望/实测值以及整体 PASS/FAIL,若存在错误会进入 Error_Handler 便于调试。

在线校验

https://www.lddgo.net/encrypt/crc

驱动以及测试代码

Core/Src/main.c
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
static const crc_test_result_t *g_crc_results;
static size_t g_crc_result_count;
static bool g_crc_passed;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
static void CRC_RunSelfTest(void);
static void CRC_LogResults(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

    /* check https://www.lddgo.net/encrypt/crc */
  CRC_RunSelfTest();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 84;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
static void CRC_RunSelfTest(void)
{
  /* 运行所有CRC自检并缓存结果,方便调试查看 */
  g_crc_passed = crc_run_all_tests();
  g_crc_results = crc_get_test_results();
  g_crc_result_count = crc_get_test_count();
  CRC_LogResults();

  if (!g_crc_passed)
  {
    Error_Handler();
  }
}

static void CRC_LogResults(void)
{
  /* 将CRC自检的期望值、实测值和状态通过串口打印 */
  if (g_crc_results == NULL || g_crc_result_count == 0U)
  {
    return;
  }

  char line[128];
  int len = snprintf(line, sizeof(line), "CRC test results (%lu cases):\r\n",
                     (unsigned long)g_crc_result_count);
  if (len > 0)
  {
    HAL_UART_Transmit(&huart2, (uint8_t *)line, (uint16_t)len, HAL_MAX_DELAY);
  }

  for (size_t i = 0; i < g_crc_result_count; ++i)
  {
    const crc_test_result_t *res = &g_crc_results[i];
    const char *status = res->passed ? "OK" : "FAIL";

    len = snprintf(line, sizeof(line), "%s exp=0x%08lX act=0x%08lX %s\r\n",
                   res->name,
                   (unsigned long)res->expected,
                   (unsigned long)res->actual,
                   status);

    if (len > 0)
    {
      HAL_UART_Transmit(&huart2, (uint8_t *)line, (uint16_t)len, HAL_MAX_DELAY);
    }
  }

  len = snprintf(line, sizeof(line), "CRC tests %s\r\n", g_crc_passed ? "PASSED" : "FAILED");
  if (len > 0)
  {
    HAL_UART_Transmit(&huart2, (uint8_t *)line, (uint16_t)len, HAL_MAX_DELAY);
  }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
component/crc/crc.h
/*
 * Bare-metal friendly CRC interface extracted from Zephyr.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef COMPONENT_CRC_CRC_H_
#define COMPONENT_CRC_CRC_H_

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef __weak
#if (defined(__GNUC__) || defined(__clang__)) && !defined(_WIN32)
#define __weak __attribute__((weak))
#else
#define __weak
#endif
#endif

#define CRC24_PGP_INITIAL_VALUE 0x00B704CEU
#define CRC24_PGP_POLY 0x01864CFBU
#define CRC24_FINAL_VALUE_MASK 0x00FFFFFFU

uint16_t crc16(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
uint16_t crc16_reflect(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len);
uint16_t crc16_itu_t(uint16_t seed, const uint8_t *src, size_t len);

uint32_t crc24_pgp(const uint8_t *data, size_t len);
uint32_t crc24_pgp_update(uint32_t crc, const uint8_t *data, size_t len);
uint32_t crc24q_rtcm3(const uint8_t *data, size_t len);

uint32_t crc32_ieee(const uint8_t *data, size_t len);
uint32_t crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len);
uint32_t crc32_c(uint32_t crc, const uint8_t *data, size_t len, bool first_pkt, bool last_pkt);
uint32_t crc32_k_4_2_update(uint32_t crc, const uint8_t *data, size_t len);

uint8_t crc4(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, bool reversed);
uint8_t crc4_ti(uint8_t seed, const uint8_t *src, size_t len);

uint8_t crc7_be(uint8_t seed, const uint8_t *src, size_t len);

uint8_t crc8_ccitt(uint8_t val, const void *buf, size_t cnt);
uint8_t crc8_rohc(uint8_t val, const void *buf, size_t cnt);
uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, bool reversed);

#ifdef __cplusplus
}
#endif

#endif /* COMPONENT_CRC_CRC_H_ */
component/crc/crc16_sw.c
/*
 * Copyright (c) 2017 Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc.h"

uint16_t __weak crc16(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len)
{
    uint16_t crc = seed;
    size_t i, j;

    for (i = 0; i < len; i++) {
        crc ^= (uint16_t)(src[i] << 8U);

        for (j = 0; j < 8; j++) {
            if (crc & 0x8000UL) {
                crc = (crc << 1U) ^ poly;
            } else {
                crc = crc << 1U;
            }
        }
    }

    return crc;
}

uint16_t __weak crc16_reflect(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len)
{
    uint16_t crc = seed;
    size_t i, j;

    for (i = 0; i < len; i++) {
        crc ^= (uint16_t)src[i];

        for (j = 0; j < 8; j++) {
            if (crc & 0x0001UL) {
                crc = (crc >> 1U) ^ poly;
            } else {
                crc = crc >> 1U;
            }
        }
    }

    return crc;
}

uint16_t __weak crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len)
{
    for (; len > 0; len--) {
        uint8_t e, f;

        e = seed ^ *src;
        ++src;
        f = e ^ (e << 4);
        seed = (seed >> 8) ^ ((uint16_t)f << 8) ^ ((uint16_t)f << 3) ^ ((uint16_t)f >> 4);
    }

    return seed;
}

uint16_t __weak crc16_itu_t(uint16_t seed, const uint8_t *src, size_t len)
{
    for (; len > 0; len--) {
        seed = (seed >> 8U) | (seed << 8U);
        seed ^= *src;
        ++src;
        seed ^= (seed & 0xffU) >> 4U;
        seed ^= seed << 12U;
        seed ^= (seed & 0xffU) << 5U;
    }

    return seed;
}
component/crc/crc24_sw.c
/*
 * Copyright (C) 2024 BayLibre.
 * Copyright (c) 2020 Brandon Owen.
 * Copyright (c) 2025 Croxel Inc.
 * Copyright (c) 2025 CogniPilot Foundation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc.h"

uint32_t __weak crc24_pgp(const uint8_t *data, size_t len)
{
    return crc24_pgp_update(CRC24_PGP_INITIAL_VALUE, data, len) & CRC24_FINAL_VALUE_MASK;
}

/* CRC-24 implementation from the section 6.1 of the RFC 4880 */
uint32_t __weak crc24_pgp_update(uint32_t crc, const uint8_t *data, size_t len)
{
    int i;

    while (len--) {
        crc ^= (*data++) << 16;
        for (i = 0; i < 8; i++) {
            crc <<= 1;
            if (crc & 0x01000000) {
                crc ^= CRC24_PGP_POLY;
            }
        }
    }

    return crc;
}

/** This code is originally extracted from github.com/go-gnss/rtcm,
 * licensed as Apache-2.0.
 */

static const uint32_t crc24q[] = {
    0x000000, 0x864cfb, 0x8ad50d, 0x0c99f6, 0x93e6e1, 0x15aa1a, 0x1933ec, 0x9f7f17,
    0xa18139, 0x27cdc2, 0x2b5434, 0xad18cf, 0x3267d8, 0xb42b23, 0xb8b2d5, 0x3efe2e,
    0xc54e89, 0x430272, 0x4f9b84, 0xc9d77f, 0x56a868, 0xd0e493, 0xdc7d65, 0x5a319e,
    0x64cfb0, 0xe2834b, 0xee1abd, 0x685646, 0xf72951, 0x7165aa, 0x7dfc5c, 0xfbb0a7,
    0x0cd1e9, 0x8a9d12, 0x8604e4, 0x00481f, 0x9f3708, 0x197bf3, 0x15e205, 0x93aefe,
    0xad50d0, 0x2b1c2b, 0x2785dd, 0xa1c926, 0x3eb631, 0xb8faca, 0xb4633c, 0x322fc7,
    0xc99f60, 0x4fd39b, 0x434a6d, 0xc50696, 0x5a7981, 0xdc357a, 0xd0ac8c, 0x56e077,
    0x681e59, 0xee52a2, 0xe2cb54, 0x6487af, 0xfbf8b8, 0x7db443, 0x712db5, 0xf7614e,
    0x19a3d2, 0x9fef29, 0x9376df, 0x153a24, 0x8a4533, 0x0c09c8, 0x00903e, 0x86dcc5,
    0xb822eb, 0x3e6e10, 0x32f7e6, 0xb4bb1d, 0x2bc40a, 0xad88f1, 0xa11107, 0x275dfc,
    0xdced5b, 0x5aa1a0, 0x563856, 0xd074ad, 0x4f0bba, 0xc94741, 0xc5deb7, 0x43924c,
    0x7d6c62, 0xfb2099, 0xf7b96f, 0x71f594, 0xee8a83, 0x68c678, 0x645f8e, 0xe21375,
    0x15723b, 0x933ec0, 0x9fa736, 0x19ebcd, 0x8694da, 0x00d821, 0x0c41d7, 0x8a0d2c,
    0xb4f302, 0x32bff9, 0x3e260f, 0xb86af4, 0x2715e3, 0xa15918, 0xadc0ee, 0x2b8c15,
    0xd03cb2, 0x567049, 0x5ae9bf, 0xdca544, 0x43da53, 0xc596a8, 0xc90f5e, 0x4f43a5,
    0x71bd8b, 0xf7f170, 0xfb6886, 0x7d247d, 0xe25b6a, 0x641791, 0x688e67, 0xeec29c,
    0x3347a4, 0xb50b5f, 0xb992a9, 0x3fde52, 0xa0a145, 0x26edbe, 0x2a7448, 0xac38b3,
    0x92c69d, 0x148a66, 0x181390, 0x9e5f6b, 0x01207c, 0x876c87, 0x8bf571, 0x0db98a,
    0xf6092d, 0x7045d6, 0x7cdc20, 0xfa90db, 0x65efcc, 0xe3a337, 0xef3ac1, 0x69763a,
    0x578814, 0xd1c4ef, 0xdd5d19, 0x5b11e2, 0xc46ef5, 0x42220e, 0x4ebbf8, 0xc8f703,
    0x3f964d, 0xb9dab6, 0xb54340, 0x330fbb, 0xac70ac, 0x2a3c57, 0x26a5a1, 0xa0e95a,
    0x9e1774, 0x185b8f, 0x14c279, 0x928e82, 0x0df195, 0x8bbd6e, 0x872498, 0x016863,
    0xfad8c4, 0x7c943f, 0x700dc9, 0xf64132, 0x693e25, 0xef72de, 0xe3eb28, 0x65a7d3,
    0x5b59fd, 0xdd1506, 0xd18cf0, 0x57c00b, 0xc8bf1c, 0x4ef3e7, 0x426a11, 0xc426ea,
    0x2ae476, 0xaca88d, 0xa0317b, 0x267d80, 0xb90297, 0x3f4e6c, 0x33d79a, 0xb59b61,
    0x8b654f, 0x0d29b4, 0x01b042, 0x87fcb9, 0x1883ae, 0x9ecf55, 0x9256a3, 0x141a58,
    0xefaaff, 0x69e604, 0x657ff2, 0xe33309, 0x7c4c1e, 0xfa00e5, 0xf69913, 0x70d5e8,
    0x4e2bc6, 0xc8673d, 0xc4fecb, 0x42b230, 0xddcd27, 0x5b81dc, 0x57182a, 0xd154d1,
    0x26359f, 0xa07964, 0xace092, 0x2aac69, 0xb5d37e, 0x339f85, 0x3f0673, 0xb94a88,
    0x87b4a6, 0x01f85d, 0x0d61ab, 0x8b2d50, 0x145247, 0x921ebc, 0x9e874a, 0x18cbb1,
    0xe37b16, 0x6537ed, 0x69ae1b, 0xefe2e0, 0x709df7, 0xf6d10c, 0xfa48fa, 0x7c0401,
    0x42fa2f, 0xc4b6d4, 0xc82f22, 0x4e63d9, 0xd11cce, 0x575035, 0x5bc9c3, 0xdd8538
};

/**
 * @brief Calculate RTCM3 frame checksum
 *
 * @param[in] data RTCM3 Frame
 * @param[in] size Frame length in bytes.
 *
 * @retval 0 if the data-frame contains a checksum and it matches.
 * @retval Result if data-frame does not contain checksum.
 */
uint32_t crc24q_rtcm3(const uint8_t *data, size_t len)
{
    uint32_t crc = 0;

    for (uint32_t i = 0; i < len; ++i) {
        crc = ((crc << 8) & 0xFFFFFF) ^ crc24q[data[i] ^ (crc >> 16)];
    }

    return crc;
}
component/crc/crc32_sw.c
/*
 * Copyright (c) 2018 Workaround GmbH.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc.h"

uint32_t __weak crc32_ieee(const uint8_t *data, size_t len)
{
    return crc32_ieee_update(0x0, data, len);
}

uint32_t __weak crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len)
{
    /* crc table generated from polynomial 0xedb88320 */
    static const uint32_t table[16] = {
        0x00000000U, 0x1db71064U, 0x3b6e20c8U, 0x26d930acU, 0x76dc4190U, 0x6b6b51f4U,
        0x4db26158U, 0x5005713cU, 0xedb88320U, 0xf00f9344U, 0xd6d6a3e8U, 0xcb61b38cU,
        0x9b64c2b0U, 0x86d3d2d4U, 0xa00ae278U, 0xbdbdf21cU,
    };

    crc = ~crc;

    for (size_t i = 0; i < len; i++) {
        uint8_t byte = data[i];

        crc = (crc >> 4) ^ table[(crc ^ byte) & 0x0f];
        crc = (crc >> 4) ^ table[(crc ^ ((uint32_t)byte >> 4)) & 0x0f];
    }

    return (~crc);
}
component/crc/crc32c_sw.c
/*
 * Copyright (c) 2021 Workaround GmbH.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc.h"

/* crc table generated from polynomial 0x1EDC6F41UL (Castagnoli) */
static const uint32_t crc32c_table[16] = {
    0x00000000UL, 0x105EC76FUL, 0x20BD8EDEUL, 0x30E349B1UL, 0x417B1DBCUL, 0x5125DAD3UL,
    0x61C69362UL, 0x7198540DUL, 0x82F63B78UL, 0x92A8FC17UL, 0xA24BB5A6UL, 0xB21572C9UL,
    0xC38D26C4UL, 0xD3D3E1ABUL, 0xE330A81AUL, 0xF36E6F75UL,
};

/* This value needs to be XORed with the final crc value once crc for
 * the entire stream is calculated. This is a requirement of crc32c algo.
 */
#define CRC32C_XOR_OUT 0xFFFFFFFFUL

/* The crc32c algorithm requires the below value as Init value at the
 * beginning of the stream.
 */
#define CRC32C_INIT 0xFFFFFFFFUL

uint32_t __weak crc32_c(uint32_t crc, const uint8_t *data, size_t len, bool first_pkt,
            bool last_pkt)
{
    if (first_pkt) {
        crc = CRC32C_INIT;
    }

    for (size_t i = 0; i < len; i++) {
        crc = crc32c_table[(crc ^ data[i]) & 0x0F] ^ (crc >> 4);
        crc = crc32c_table[(crc ^ ((uint32_t)data[i] >> 4)) & 0x0F] ^ (crc >> 4);
    }

    return last_pkt ? (crc ^ CRC32C_XOR_OUT) : crc;
}
component/crc/crc32k_4_2_sw.c
/*
 * Copyright (c) 2024 Intercreate, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc.h"

uint32_t __weak crc32_k_4_2_update(uint32_t crc, const uint8_t *const data, const size_t len)
{

#if defined(CONFIG_CRC32_K_4_2_TABLE_256)

    /**
     * CRC table generated from polynomial 0x93a409eb CRC-32K/4.2 (*op) (Koopman)
     *
     * pycrc --width 32 --poly 0x93a409eb --reflect-in False --xor-in 0 --reflect-out False
     * --xor-out 0 --generate table --table-idx-width 8
     */
    static const uint32_t table[256] = {
        0x00000000, 0x93a409eb, 0xb4ec1a3d, 0x274813d6, 0xfa7c3d91, 0x69d8347a, 0x4e9027ac,
        0xdd342e47, 0x675c72c9, 0xf4f87b22, 0xd3b068f4, 0x4014611f, 0x9d204f58, 0x0e8446b3,
        0x29cc5565, 0xba685c8e, 0xceb8e592, 0x5d1cec79, 0x7a54ffaf, 0xe9f0f644, 0x34c4d803,
        0xa760d1e8, 0x8028c23e, 0x138ccbd5, 0xa9e4975b, 0x3a409eb0, 0x1d088d66, 0x8eac848d,
        0x5398aaca, 0xc03ca321, 0xe774b0f7, 0x74d0b91c, 0x0ed5c2cf, 0x9d71cb24, 0xba39d8f2,
        0x299dd119, 0xf4a9ff5e, 0x670df6b5, 0x4045e563, 0xd3e1ec88, 0x6989b006, 0xfa2db9ed,
        0xdd65aa3b, 0x4ec1a3d0, 0x93f58d97, 0x0051847c, 0x271997aa, 0xb4bd9e41, 0xc06d275d,
        0x53c92eb6, 0x74813d60, 0xe725348b, 0x3a111acc, 0xa9b51327, 0x8efd00f1, 0x1d59091a,
        0xa7315594, 0x34955c7f, 0x13dd4fa9, 0x80794642, 0x5d4d6805, 0xcee961ee, 0xe9a17238,
        0x7a057bd3, 0x1dab859e, 0x8e0f8c75, 0xa9479fa3, 0x3ae39648, 0xe7d7b80f, 0x7473b1e4,
        0x533ba232, 0xc09fabd9, 0x7af7f757, 0xe953febc, 0xce1bed6a, 0x5dbfe481, 0x808bcac6,
        0x132fc32d, 0x3467d0fb, 0xa7c3d910, 0xd313600c, 0x40b769e7, 0x67ff7a31, 0xf45b73da,
        0x296f5d9d, 0xbacb5476, 0x9d8347a0, 0x0e274e4b, 0xb44f12c5, 0x27eb1b2e, 0x00a308f8,
        0x93070113, 0x4e332f54, 0xdd9726bf, 0xfadf3569, 0x697b3c82, 0x137e4751, 0x80da4eba,
        0xa7925d6c, 0x34365487, 0xe9027ac0, 0x7aa6732b, 0x5dee60fd, 0xce4a6916, 0x74223598,
        0xe7863c73, 0xc0ce2fa5, 0x536a264e, 0x8e5e0809, 0x1dfa01e2, 0x3ab21234, 0xa9161bdf,
        0xddc6a2c3, 0x4e62ab28, 0x692ab8fe, 0xfa8eb115, 0x27ba9f52, 0xb41e96b9, 0x9356856f,
        0x00f28c84, 0xba9ad00a, 0x293ed9e1, 0x0e76ca37, 0x9dd2c3dc, 0x40e6ed9b, 0xd342e470,
        0xf40af7a6, 0x67aefe4d, 0x3b570b3c, 0xa8f302d7, 0x8fbb1101, 0x1c1f18ea, 0xc12b36ad,
        0x528f3f46, 0x75c72c90, 0xe663257b, 0x5c0b79f5, 0xcfaf701e, 0xe8e763c8, 0x7b436a23,
        0xa6774464, 0x35d34d8f, 0x129b5e59, 0x813f57b2, 0xf5efeeae, 0x664be745, 0x4103f493,
        0xd2a7fd78, 0x0f93d33f, 0x9c37dad4, 0xbb7fc902, 0x28dbc0e9, 0x92b39c67, 0x0117958c,
        0x265f865a, 0xb5fb8fb1, 0x68cfa1f6, 0xfb6ba81d, 0xdc23bbcb, 0x4f87b220, 0x3582c9f3,
        0xa626c018, 0x816ed3ce, 0x12cada25, 0xcffef462, 0x5c5afd89, 0x7b12ee5f, 0xe8b6e7b4,
        0x52debb3a, 0xc17ab2d1, 0xe632a107, 0x7596a8ec, 0xa8a286ab, 0x3b068f40, 0x1c4e9c96,
        0x8fea957d, 0xfb3a2c61, 0x689e258a, 0x4fd6365c, 0xdc723fb7, 0x014611f0, 0x92e2181b,
        0xb5aa0bcd, 0x260e0226, 0x9c665ea8, 0x0fc25743, 0x288a4495, 0xbb2e4d7e, 0x661a6339,
        0xf5be6ad2, 0xd2f67904, 0x415270ef, 0x26fc8ea2, 0xb5588749, 0x9210949f, 0x01b49d74,
        0xdc80b333, 0x4f24bad8, 0x686ca90e, 0xfbc8a0e5, 0x41a0fc6b, 0xd204f580, 0xf54ce656,
        0x66e8efbd, 0xbbdcc1fa, 0x2878c811, 0x0f30dbc7, 0x9c94d22c, 0xe8446b30, 0x7be062db,
        0x5ca8710d, 0xcf0c78e6, 0x123856a1, 0x819c5f4a, 0xa6d44c9c, 0x35704577, 0x8f1819f9,
        0x1cbc1012, 0x3bf403c4, 0xa8500a2f, 0x75642468, 0xe6c02d83, 0xc1883e55, 0x522c37be,
        0x28294c6d, 0xbb8d4586, 0x9cc55650, 0x0f615fbb, 0xd25571fc, 0x41f17817, 0x66b96bc1,
        0xf51d622a, 0x4f753ea4, 0xdcd1374f, 0xfb992499, 0x683d2d72, 0xb5090335, 0x26ad0ade,
        0x01e51908, 0x924110e3, 0xe691a9ff, 0x7535a014, 0x527db3c2, 0xc1d9ba29, 0x1ced946e,
        0x8f499d85, 0xa8018e53, 0x3ba587b8, 0x81cddb36, 0x1269d2dd, 0x3521c10b, 0xa685c8e0,
        0x7bb1e6a7, 0xe815ef4c, 0xcf5dfc9a, 0x5cf9f571};

    for (size_t i = 0; i < len; i++) {
        crc = (crc << 8) ^ table[((crc >> 24) ^ data[i]) & 0xff];
    }

#else

    /**
     * CRC table generated from polynomial 0x93a409eb CRC-32K/4.2 (*op) (Koopman)
     *
     * pycrc --width 32 --poly 0x93a409eb --reflect-in False --xor-in 0 --reflect-out False
     * --xor-out 0 --generate table --table-idx-width 4
     */
    static const uint32_t table[16] = {0x00000000, 0x93a409eb, 0xb4ec1a3d, 0x274813d6,
                       0xfa7c3d91, 0x69d8347a, 0x4e9027ac, 0xdd342e47,
                       0x675c72c9, 0xf4f87b22, 0xd3b068f4, 0x4014611f,
                       0x9d204f58, 0x0e8446b3, 0x29cc5565, 0xba685c8e};

    for (size_t i = 0; i < len; i++) {
        crc = (crc << 4) ^ table[((crc >> 28) ^ (data[i] >> 4)) & 0x0f];
        crc = (crc << 4) ^ table[((crc >> 28) ^ data[i]) & 0x0f];
    }

#endif

    return crc;
}
component/crc/crc4_sw.c
/*
 * Copyright (c) 2023 Michal Morsisko
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc.h"

uint8_t __weak crc4(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
         bool reversed)
{
    uint8_t crc = initial_value;
    size_t i, j, k;

    for (i = 0; i < len; i++) {
        for (j = 0; j < 2; j++) {
            crc ^= ((src[i] >> (4 * (1 - j))) & 0xf);

            for (k = 0; k < 4; k++) {
                if (reversed) {
                    if (crc & 0x01) {
                        crc = (crc >> 1) ^ polynomial;
                    } else {
                        crc >>= 1;
                    }
                } else {
                    if (crc & 0x8) {
                        crc = (crc << 1) ^ polynomial;
                    } else {
                        crc <<= 1;
                    }
                }
            }
        }
    }

    return crc & 0xF;
}

uint8_t __weak crc4_ti(uint8_t seed, const uint8_t *src, size_t len)
{
    static const uint8_t lookup[8] = {0x03, 0x65, 0xcf, 0xa9, 0xb8, 0xde, 0x74, 0x12};
    uint8_t index;

    for (size_t i = 0; i < len; i++) {
        for (size_t j = 0U; j < 2U; j++) {
            index = seed ^ ((src[i] >> (4 * (1 - j))) & 0xf);
            seed = (lookup[index >> 1] >> (1 - (index & 1)) * 4) & 0xf;
        }
    }

    return seed;
}
component/crc/crc7_sw.c
/*
 * Copyright (c) 2018 Google LLC.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc.h"

uint8_t __weak crc7_be(uint8_t seed, const uint8_t *src, size_t len)
{
    while (len-- != 0UL) {
        uint8_t e = seed ^ *src++;
        uint8_t f = e ^ (e >> 4) ^ (e >> 7);

        seed = (f << 1) ^ (f << 4);
    }

    return seed;
}
component/crc/crc8_sw.c
/*
 * Copyright (c) 2020 Intel Corporation
 * Copyright (c) 2017 Nordic Semiconductor ASA
 * Copyright (c) 2015 Runtime Inc
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc.h"

static const uint8_t crc8_ccitt_small_table[16] = {
    0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
    0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
};

static const uint8_t crc8_rohc_small_table[16] = {
    0x00, 0x1c, 0x38, 0x24, 0x70, 0x6c, 0x48, 0x54,
    0xe0, 0xfc, 0xd8, 0xc4, 0x90, 0x8c, 0xa8, 0xb4,
};

uint8_t __weak crc8_ccitt(uint8_t val, const void *buf, size_t cnt)
{
    size_t i;
    const uint8_t *p = buf;

    for (i = 0; i < cnt; i++) {
        val ^= p[i];
        val = (val << 4) ^ crc8_ccitt_small_table[val >> 4];
        val = (val << 4) ^ crc8_ccitt_small_table[val >> 4];
    }
    return val;
}

uint8_t __weak crc8_rohc(uint8_t val, const void *buf, size_t cnt)
{
    size_t i;
    const uint8_t *p = buf;

    for (i = 0; i < cnt; i++) {
        val ^= p[i];
        val = (val >> 4) ^ crc8_rohc_small_table[val & 0x0f];
        val = (val >> 4) ^ crc8_rohc_small_table[val & 0x0f];
    }
    return val;
}

uint8_t __weak crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
            bool reversed)
{
    uint8_t crc = initial_value;
    size_t i, j;

    for (i = 0; i < len; i++) {
        crc ^= src[i];

        for (j = 0; j < 8; j++) {
            if (reversed) {
                if ((crc & 0x01) != 0) {
                    crc = (crc >> 1) ^ polynomial;
                } else {
                    crc >>= 1;
                }
            } else {
                if ((crc & 0x80) != 0) {
                    crc = (crc << 1) ^ polynomial;
                } else {
                    crc <<= 1;
                }
            }
        }
    }

    return crc;
}
component/crc/crc_test.c
/*
 * Simple bare-metal friendly CRC self-tests.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "crc_test.h"

#include "crc.h"

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

typedef uint32_t (*crc_test_func_t)(void);

typedef struct {
    const char *name;
    crc_test_func_t dut;
    crc_test_func_t reference_override;
    uint8_t width;
    uint32_t polynomial;
    uint32_t seed;
    uint32_t xor_out;
    bool lsb_variant;
} crc_test_case_t;

static const uint8_t kTestPayload[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
static const size_t kTestPayloadSize = ARRAY_SIZE(kTestPayload);

/* 根据CRC位宽生成对应的掩码,用于裁剪中间结果 */
static uint32_t crc_mask(uint8_t width)
{
    if (width >= 32U) {
        return 0xFFFFFFFFU;
    }

    return (uint32_t)((1ULL << width) - 1ULL);
}

/* 按MSB先行方式计算参考CRC结果,用于非反射CRC对比 */
static uint32_t crc_reference_msb(const uint8_t *data, size_t len, uint8_t width,
                  uint32_t polynomial, uint32_t seed, uint32_t xor_out)
{
    if (width == 0U) {
        return 0U;
    }

    const uint64_t mask = (width >= 32U) ? 0xFFFFFFFFULL : ((1ULL << width) - 1ULL);
    const uint64_t topbit = 1ULL << (width - 1U);
    const uint64_t poly = ((uint64_t)polynomial) & mask;
    const uint64_t xor_masked = ((uint64_t)xor_out) & mask;
    uint64_t crc = ((uint64_t)seed) & mask;

    for (size_t i = 0; i < len; ++i) {
        uint8_t cur = data[i];

        for (uint8_t bit = 0U; bit < 8U; ++bit) {
            if ((cur & 0x80U) != 0U) {
                crc ^= topbit;
            }

            cur = (uint8_t)((cur << 1U) & 0xFFU);

            if ((crc & topbit) != 0U) {
                crc = ((crc << 1U) & mask) ^ poly;
            } else {
                crc = (crc << 1U) & mask;
            }
        }
    }

    crc ^= xor_masked;
    return (uint32_t)(crc & mask);
}

/* 按LSB先行方式计算参考CRC结果,用于反射CRC对比 */
static uint32_t crc_reference_lsb(const uint8_t *data, size_t len, uint8_t width,
                  uint32_t polynomial, uint32_t seed, uint32_t xor_out)
{
    if (width == 0U) {
        return 0U;
    }

    const uint64_t mask = (width >= 32U) ? 0xFFFFFFFFULL : ((1ULL << width) - 1ULL);
    const uint64_t poly = ((uint64_t)polynomial) & mask;
    const uint64_t xor_masked = ((uint64_t)xor_out) & mask;
    uint64_t crc = ((uint64_t)seed) & mask;

    for (size_t i = 0; i < len; ++i) {
        crc ^= data[i];

        for (uint8_t bit = 0U; bit < 8U; ++bit) {
            if ((crc & 0x01ULL) != 0U) {
                crc = (crc >> 1U) ^ poly;
            } else {
                crc >>= 1U;
            }

            crc &= mask;
        }
    }

    crc ^= xor_masked;
    return (uint32_t)(crc & mask);
}

/* Device-under-test helpers */
/* 计算单次CRC32 IEEE基准值 */
static uint32_t dut_crc32_ieee(void)
{
    return crc32_ieee(kTestPayload, kTestPayloadSize);
}

/* 分块调用CRC32 IEEE更新接口验证持续性 */
static uint32_t dut_crc32_ieee_chunked(void)
{
    const size_t split = 4U;
    uint32_t crc = crc32_ieee_update(0U, kTestPayload, split);

    return crc32_ieee_update(crc, &kTestPayload[split], kTestPayloadSize - split);
}

/* 验证CRC32C Castagnoli软件实现 */
static uint32_t dut_crc32_c(void)
{
    return crc32_c(0U, kTestPayload, kTestPayloadSize, true, true);
}

/* 验证CRC32K/4.2查表实现 */
static uint32_t dut_crc32_k(void)
{
    return crc32_k_4_2_update(0U, kTestPayload, kTestPayloadSize);
}

/* 验证PGP CRC24一次性计算 */
static uint32_t dut_crc24_pgp(void)
{
    return crc24_pgp(kTestPayload, kTestPayloadSize) & CRC24_FINAL_VALUE_MASK;
}

/* 分块调用PGP CRC24以测试上下文保持 */
static uint32_t dut_crc24_pgp_chunked(void)
{
    const size_t split = 3U;
    uint32_t crc = crc24_pgp_update(CRC24_PGP_INITIAL_VALUE, kTestPayload, split);

    crc = crc24_pgp_update(crc, &kTestPayload[split], kTestPayloadSize - split);

    return crc & CRC24_FINAL_VALUE_MASK;
}

/* 验证RTCM3使用的CRC24Q */
static uint32_t dut_crc24q(void)
{
    return crc24q_rtcm3(kTestPayload, kTestPayloadSize) & CRC24_FINAL_VALUE_MASK;
}

/* 验证CRC16多项式0x1021实现 */
static uint32_t dut_crc16(void)
{
    return crc16(0x1021U, 0xFFFFU, kTestPayload, kTestPayloadSize);
}

/* 验证CRC16 CCITT非反射实现 */
static uint32_t dut_crc16_ccitt(void)
{
    return crc16_ccitt(0xFFFFU, kTestPayload, kTestPayloadSize);
}

/* 验证CRC16反射算法实现 */
static uint32_t dut_crc16_reflect(void)
{
    return crc16_reflect(0xA001U, 0xFFFFU, kTestPayload, kTestPayloadSize);
}

/* 验证ITU-T CRC16实现 */
static uint32_t dut_crc16_itu_t(void)
{
    return crc16_itu_t(0x0000U, kTestPayload, kTestPayloadSize);
}

/* 验证CRC8 CCITT实现 */
static uint32_t dut_crc8_ccitt(void)
{
    return crc8_ccitt(0x00U, kTestPayload, kTestPayloadSize);
}

/* 验证ROHC CRC8实现 */
static uint32_t dut_crc8_rohc(void)
{
    return crc8_rohc(0xFFU, kTestPayload, kTestPayloadSize);
}

/* 验证可配置的CRC8 MSB模式 */
static uint32_t dut_crc8_msb(void)
{
    return crc8(kTestPayload, kTestPayloadSize, 0x07U, 0x00U, false);
}

/* 验证可配置的CRC8 LSB模式 */
static uint32_t dut_crc8_lsb(void)
{
    return crc8(kTestPayload, kTestPayloadSize, 0x07U, 0x00U, true);
}

/* 验证CRC4 MSB模式 */
static uint32_t dut_crc4_msb(void)
{
    return crc4(kTestPayload, kTestPayloadSize, 0x03U, 0x00U, false) & 0xFU;
}

/* 验证CRC4 LSB模式 */
static uint32_t dut_crc4_lsb(void)
{
    return crc4(kTestPayload, kTestPayloadSize, 0x03U, 0x00U, true) & 0xFU;
}

/* 验证TI特定的CRC4算法 */
static uint32_t dut_crc4_ti(void)
{
    return crc4_ti(0x00U, kTestPayload, kTestPayloadSize) & 0xFU;
}

/* 验证CRC7大端实现 */
static uint32_t dut_crc7(void)
{
    return crc7_be(0x00U, kTestPayload, kTestPayloadSize) & 0x7FU;
}

/* 手写CRC4 LSB参考实现,用于校验API */
static uint32_t ref_crc4_reversed(void)
{
    uint8_t crc = 0x00U;

    for (size_t i = 0; i < kTestPayloadSize; ++i) {
        const uint8_t byte = kTestPayload[i];

        for (uint8_t nibble = 0U; nibble < 2U; ++nibble) {
            const uint8_t shift = (1U - nibble) * 4U;
            const uint8_t part = (byte >> shift) & 0x0FU;

            crc ^= part;

            for (uint8_t bit = 0U; bit < 4U; ++bit) {
                if ((crc & 0x01U) != 0U) {
                    crc = (uint8_t)((crc >> 1U) ^ 0x03U);
                } else {
                    crc >>= 1U;
                }
            }
        }
    }

    return (uint32_t)(crc & 0x0FU);
}

/* 手写CRC7参考实现,用于校验API */
static uint32_t ref_crc7(void)
{
    uint8_t seed = 0x00U;

    for (size_t i = 0; i < kTestPayloadSize; ++i) {
        uint8_t e = seed ^ kTestPayload[i];
        uint8_t f = e ^ (e >> 4U) ^ (e >> 7U);

        seed = (uint8_t)(((f << 1U) ^ (f << 4U)) & 0xFFU);
    }

    return (uint32_t)(seed & 0x7FU);
}

static const crc_test_case_t kTestCases[] = {
    {"crc32_ieee", dut_crc32_ieee, NULL, 32U, 0xEDB88320U, 0xFFFFFFFFU, 0xFFFFFFFFU, true},
    {"crc32_ieee_stream", dut_crc32_ieee_chunked, NULL, 32U, 0xEDB88320U, 0xFFFFFFFFU, 0xFFFFFFFFU,
     true},
    {"crc32_c", dut_crc32_c, NULL, 32U, 0x82F63B78U, 0xFFFFFFFFU, 0xFFFFFFFFU, true},
    {"crc32_k_4_2", dut_crc32_k, NULL, 32U, 0x93A409EBU, 0x00000000U, 0x00000000U, false},
    {"crc24_pgp", dut_crc24_pgp, NULL, 24U, CRC24_PGP_POLY, CRC24_PGP_INITIAL_VALUE, 0x000000U, false},
    {"crc24_pgp_stream", dut_crc24_pgp_chunked, NULL, 24U, CRC24_PGP_POLY, CRC24_PGP_INITIAL_VALUE,
     0x000000U, false},
    {"crc24q_rtcm3", dut_crc24q, NULL, 24U, 0x01864CFBU, 0x000000U, 0x000000U, false},
    {"crc16", dut_crc16, NULL, 16U, 0x1021U, 0xFFFFU, 0x0000U, false},
    {"crc16_ccitt", dut_crc16_ccitt, NULL, 16U, 0x8408U, 0xFFFFU, 0x0000U, true},
    {"crc16_reflect", dut_crc16_reflect, NULL, 16U, 0xA001U, 0xFFFFU, 0x0000U, true},
    {"crc16_itu_t", dut_crc16_itu_t, NULL, 16U, 0x1021U, 0x0000U, 0x0000U, false},
    {"crc8_ccitt", dut_crc8_ccitt, NULL, 8U, 0x07U, 0x00U, 0x00U, false},
    {"crc8_rohc", dut_crc8_rohc, NULL, 8U, 0xE0U, 0xFFU, 0x00U, true},
    {"crc8_msb_api", dut_crc8_msb, NULL, 8U, 0x07U, 0x00U, 0x00U, false},
    {"crc8_lsb_api", dut_crc8_lsb, NULL, 8U, 0x07U, 0x00U, 0x00U, true},
    {"crc4", dut_crc4_msb, NULL, 4U, 0x03U, 0x00U, 0x00U, false},
    {"crc4_reversed", dut_crc4_lsb, ref_crc4_reversed, 4U, 0x03U, 0x00U, 0x00U, true},
    {"crc4_ti", dut_crc4_ti, NULL, 4U, 0x03U, 0x00U, 0x00U, false},
    {"crc7_be", dut_crc7, ref_crc7, 7U, 0x09U, 0x00U, 0x00U, false},
};

static crc_test_result_t g_results[ARRAY_SIZE(kTestCases)];
static bool g_tests_run;

/* 根据测试用例属性选择合适的参考实现 */
static uint32_t run_reference(const crc_test_case_t *tc)
{
    if (tc->reference_override != NULL) {
        return tc->reference_override();
    }

    if (tc->lsb_variant) {
        return crc_reference_lsb(kTestPayload, kTestPayloadSize, tc->width, tc->polynomial,
                     tc->seed, tc->xor_out);
    }

    return crc_reference_msb(kTestPayload, kTestPayloadSize, tc->width, tc->polynomial,
                 tc->seed, tc->xor_out);
}

/* 运行全部CRC测试并记录结果,返回总体是否通过 */
bool crc_run_all_tests(void)
{
    bool all_pass = true;

    for (size_t i = 0; i < ARRAY_SIZE(kTestCases); ++i) {
        const crc_test_case_t *tc = &kTestCases[i];
        const uint32_t expected = run_reference(tc) & crc_mask(tc->width);
        const uint32_t actual = tc->dut() & crc_mask(tc->width);

        g_results[i].name = tc->name;
        g_results[i].expected = expected;
        g_results[i].actual = actual;
        g_results[i].passed = (expected == actual);

        if (!g_results[i].passed) {
            all_pass = false;
        }
    }

    g_tests_run = true;
    return all_pass;
}

/* 返回当前注册的CRC测试用例数量 */
size_t crc_get_test_count(void)
{
    return ARRAY_SIZE(kTestCases);
}

/* 返回最近一次执行的CRC测试结果数组 */
const crc_test_result_t *crc_get_test_results(void)
{
    if (!g_tests_run) {
        (void)crc_run_all_tests();
    }

    return g_results;
}
component/crc/crc_test.h
/*
 * CRC self-test API.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef COMPONENT_CRC_CRC_TEST_H_
#define COMPONENT_CRC_CRC_TEST_H_

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    const char *name;
    uint32_t expected;
    uint32_t actual;
    bool passed;
} crc_test_result_t;

bool crc_run_all_tests(void);
size_t crc_get_test_count(void);
const crc_test_result_t *crc_get_test_results(void);

#ifdef __cplusplus
}
#endif

#endif /* COMPONENT_CRC_CRC_TEST_H_ */