From ec5354cd8004c187ba73c238012003cdb3ad1e28 Mon Sep 17 00:00:00 2001 From: Pisit Sawangvonganan Date: Sat, 5 Oct 2024 18:10:12 +0700 Subject: [PATCH] lib: crc: add `crc8_rohc` for CRC-8/ROHC variant calculation This commit introduces the `crc8_rohc` function to the CRC library, implementing the CRC-8/ROHC (RObust Header Compression) variant. This algorithm is widely used in networking protocols, which is commonly found in modem subsystems. Signed-off-by: Pisit Sawangvonganan --- include/zephyr/sys/crc.h | 26 ++++++++++++++++++++++---- lib/crc/crc8_sw.c | 18 ++++++++++++++++++ lib/crc/crc_shell.c | 1 + tests/unit/crc/main.c | 23 +++++++++++++++++++++++ 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/include/zephyr/sys/crc.h b/include/zephyr/sys/crc.h index c16281b10fd..7a0c33cf9b5 100644 --- a/include/zephyr/sys/crc.h +++ b/include/zephyr/sys/crc.h @@ -29,6 +29,7 @@ extern "C" { * computation. */ #define CRC8_CCITT_INITIAL_VALUE 0xFF +#define CRC8_ROHC_INITIAL_VALUE 0xFF /* Initial value expected to be used at the beginning of the OpenPGP CRC-24 computation. */ #define CRC24_PGP_INITIAL_VALUE 0x00B704CEU @@ -58,9 +59,10 @@ enum crc_type { CRC4, /**< Use @ref crc4 */ CRC4_TI, /**< Use @ref crc4_ti */ CRC7_BE, /**< Use @ref crc7_be */ - CRC8, /**< Use @ref crc8 */ + CRC8, /**< Use @ref crc8 */ CRC8_CCITT, /**< Use @ref crc8_ccitt */ - CRC16, /**< Use @ref crc16 */ + CRC8_ROHC, /**< Use @ref crc8_rohc */ + CRC16, /**< Use @ref crc16 */ CRC16_ANSI, /**< Use @ref crc16_ansi */ CRC16_CCITT, /**< Use @ref crc16_ccitt */ CRC16_ITU_T, /**< Use @ref crc16_itu_t */ @@ -135,7 +137,7 @@ uint16_t crc16_reflect(uint16_t poly, uint16_t seed, const uint8_t *src, size_t * @return The computed CRC8 value */ uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, - bool reversed); + bool reversed); /** * @brief Compute the checksum of a buffer with polynomial 0x1021, reflecting @@ -274,6 +276,20 @@ uint32_t crc32_c(uint32_t crc, const uint8_t *data, */ uint8_t crc8_ccitt(uint8_t initial_value, const void *buf, size_t len); +/** + * @brief Compute ROHC variant of CRC 8 + * + * ROHC (Robust Header Compression) variant of CRC 8. + * Uses 0x07 as the polynomial with reflection. + * + * @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_rohc(uint8_t initial_value, const void *buf, size_t len); + /** * @brief Compute the CRC-7 checksum of a buffer. * @@ -322,7 +338,7 @@ uint8_t crc4_ti(uint8_t seed, const uint8_t *src, size_t len); * @return The computed CRC4 value */ uint8_t crc4(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, - bool reversed); + bool reversed); /** * @brief Generate an OpenPGP CRC-24 checksum as defined in RFC 4880 section 6.1. @@ -384,6 +400,8 @@ static inline uint32_t crc_by_type(enum crc_type type, const uint8_t *src, size_ return crc8(src, len, poly, seed, reflect); case CRC8_CCITT: return crc8_ccitt(seed, src, len); + case CRC8_ROHC: + return crc8_rohc(seed, src, len); case CRC16: if (reflect) { return crc16_reflect(poly, seed, src, len); diff --git a/lib/crc/crc8_sw.c b/lib/crc/crc8_sw.c index 06bbeea516b..59900e14a62 100644 --- a/lib/crc/crc8_sw.c +++ b/lib/crc/crc8_sw.c @@ -13,6 +13,11 @@ static const uint8_t crc8_ccitt_small_table[16] = { 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 crc8_ccitt(uint8_t val, const void *buf, size_t cnt) { size_t i; @@ -26,6 +31,19 @@ uint8_t crc8_ccitt(uint8_t val, const void *buf, size_t cnt) return val; } +uint8_t 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 crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, bool reversed) { diff --git a/lib/crc/crc_shell.c b/lib/crc/crc_shell.c index e2647ee6623..3d08a59aa17 100644 --- a/lib/crc/crc_shell.c +++ b/lib/crc/crc_shell.c @@ -24,6 +24,7 @@ static const char *const crc_types[] = { [CRC7_BE] = "7_be", [CRC8] = "8", [CRC8_CCITT] = "8_ccitt", + [CRC8_ROHC] = "8_rohc", [CRC16] = "16", [CRC16_ANSI] = "16_ansi", [CRC16_CCITT] = "16_ccitt", diff --git a/tests/unit/crc/main.c b/tests/unit/crc/main.c index 2ea2d1b4ba5..ecb85d3483e 100644 --- a/tests/unit/crc/main.c +++ b/tests/unit/crc/main.c @@ -187,6 +187,29 @@ ZTEST(crc, test_crc8_ccitt) sizeof(test2)) == 0xFB, "pass", "fail"); } +ZTEST(crc, test_crc8_rohc) +{ + uint8_t test0[] = { 0 }; + uint8_t test1[] = { 'A' }; + uint8_t test2[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + uint8_t test3[] = { 0x07, 0x3F }; /* GSM 07.10 example */ + uint8_t test4[] = { 0x07, 0x3F, 0x89 }; /* GSM 07.10 example */ + uint8_t test5[] = { 0x03, 0x3f, 0x01, 0x1c }; /* Our GSM 07.10 calc */ + + zassert(crc8_rohc(CRC8_ROHC_INITIAL_VALUE, test0, + sizeof(test0)) == 0xcf, "pass", "fail"); + zassert(crc8_rohc(CRC8_ROHC_INITIAL_VALUE, test1, + sizeof(test1)) == 0x2e, "pass", "fail"); + zassert(crc8_rohc(CRC8_ROHC_INITIAL_VALUE, test2, + sizeof(test2)) == 0xd0, "pass", "fail"); + zassert(crc8_rohc(CRC8_ROHC_INITIAL_VALUE, test3, + sizeof(test3)) == 0x76, "pass", "fail"); + zassert(crc8_rohc(CRC8_ROHC_INITIAL_VALUE, test4, + sizeof(test4)) == 0xcf, "pass", "fail"); + zassert(crc8_rohc(CRC8_ROHC_INITIAL_VALUE, test5, + sizeof(test5)) == 0xcf, "pass", "fail"); +} + ZTEST(crc, test_crc7_be) { uint8_t test0[] = { 0 };