crc: add a faster, chainable version of CRC16/CCITT.
The existing version of crc16_ccitt() is actually CRC-16/AUG-CCITT and gives different results to Linux, Contiki, and the CRC unit in the SAM0 SOC. This version matches Linux. Note that this is an incompatible API change. Signed-off-by: Michael Hope <mlhx@google.com>
This commit is contained in:
parent
88b1ad138e
commit
f77c1d53b5
|
@ -43,20 +43,30 @@ u16_t crc16(const u8_t *src, size_t len, u16_t polynomial,
|
|||
u16_t initial_value, bool pad);
|
||||
|
||||
/**
|
||||
* @brief Compute CCITT variant of CRC 16
|
||||
* @brief Compute the CRC-16/CCITT checksum of a buffer.
|
||||
*
|
||||
* CCITT variant of CRC 16 is using 0x1021 as its polynomial with the initial
|
||||
* value set to 0xffff.
|
||||
* See ITU-T Recommendation V.41 (November 1988). Uses 0x1021 as the
|
||||
* polynomial, reflects the input, and reflects the output.
|
||||
*
|
||||
* To calculate the CRC across non-contigious blocks use the return
|
||||
* value from block N-1 as the seed for block N.
|
||||
*
|
||||
* For CRC-16/CCITT, use 0 as the initial seed. Other checksums in
|
||||
* the same family can be calculated by changing the seed and/or
|
||||
* XORing the final value. Examples include:
|
||||
*
|
||||
* - CCIITT-FALSE: seed=0xffff
|
||||
* - X-25 (used in PPP): seed=0xffff, xor=0xffff, residual=0xf0b8
|
||||
*
|
||||
* @note API changed in Zephyr 1.11.
|
||||
*
|
||||
* @param seed Value to seed the CRC with
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC16 value
|
||||
*/
|
||||
static inline u16_t crc16_ccitt(const u8_t *src, size_t len)
|
||||
{
|
||||
return crc16(src, len, 0x1021, 0xffff, true);
|
||||
}
|
||||
u16_t crc16_ccitt(u16_t seed, const u8_t *src, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute ANSI variant of CRC 16
|
||||
|
|
|
@ -34,3 +34,16 @@ u16_t crc16(const u8_t *src, size_t len, u16_t polynomial,
|
|||
|
||||
return crc;
|
||||
}
|
||||
|
||||
u16_t crc16_ccitt(u16_t seed, const u8_t *src, size_t len)
|
||||
{
|
||||
for (; len > 0; len--) {
|
||||
u8_t e, f;
|
||||
|
||||
e = seed ^ *src++;
|
||||
f = e ^ (e << 4);
|
||||
seed = (seed >> 8) ^ (f << 8) ^ (f << 3) ^ (f >> 4);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
|
|
@ -15,9 +15,12 @@ void test_crc16(void)
|
|||
u8_t test1[] = { 'A' };
|
||||
u8_t test2[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
|
||||
|
||||
zassert(crc16_ccitt(test0, sizeof(test0)) == 0x1d0f, "pass", "fail");
|
||||
zassert(crc16_ccitt(test1, sizeof(test1)) == 0x9479, "pass", "fail");
|
||||
zassert(crc16_ccitt(test2, sizeof(test2)) == 0xe5cc, "pass", "fail");
|
||||
zassert_equal(crc16(test0, sizeof(test0), 0x1021, 0xffff, true),
|
||||
0x1d0f, NULL);
|
||||
zassert_equal(crc16(test1, sizeof(test1), 0x1021, 0xffff, true),
|
||||
0x9479, NULL);
|
||||
zassert_equal(crc16(test2, sizeof(test2), 0x1021, 0xffff, true),
|
||||
0xe5cc, NULL);
|
||||
}
|
||||
|
||||
void test_crc16_ansi(void)
|
||||
|
@ -31,6 +34,47 @@ void test_crc16_ansi(void)
|
|||
zassert(crc16_ansi(test2, sizeof(test2)) == 0x9ecf, "pass", "fail");
|
||||
}
|
||||
|
||||
void test_crc16_ccitt(void)
|
||||
{
|
||||
u8_t test0[] = { };
|
||||
u8_t test1[] = { 'A' };
|
||||
u8_t test2[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
|
||||
u8_t test3[] = { 'Z', 'e', 'p', 'h', 'y', 'r', 0, 0 };
|
||||
u16_t crc;
|
||||
|
||||
zassert_equal(crc16_ccitt(0, test0, sizeof(test0)), 0x0, NULL);
|
||||
zassert_equal(crc16_ccitt(0, test1, sizeof(test1)), 0x538d, NULL);
|
||||
zassert_equal(crc16_ccitt(0, test2, sizeof(test2)), 0x2189, NULL);
|
||||
|
||||
/* Appending the CRC to a buffer and computing the CRC over
|
||||
* the extended buffer leaves a residual of zero.
|
||||
*/
|
||||
crc = crc16_ccitt(0, test3, sizeof(test3) - sizeof(u16_t));
|
||||
test3[sizeof(test3)-2] = (u8_t)(crc >> 0);
|
||||
test3[sizeof(test3)-1] = (u8_t)(crc >> 8);
|
||||
|
||||
zassert_equal(crc16_ccitt(0, test3, sizeof(test3)), 0, NULL);
|
||||
}
|
||||
|
||||
void test_crc16_ccitt_for_ppp(void)
|
||||
{
|
||||
/* Example capture including FCS from
|
||||
* https://www.horo.ch/techno/ppp-fcs/examples_en.html
|
||||
*/
|
||||
u8_t test0[] = {
|
||||
0xff, 0x03, 0xc0, 0x21, 0x01, 0x01, 0x00, 0x17,
|
||||
0x02, 0x06, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x06,
|
||||
0x00, 0x2a, 0x2b, 0x78, 0x07, 0x02, 0x08, 0x02,
|
||||
0x0d, 0x03, 0x06, 0xa5, 0xf8
|
||||
};
|
||||
u8_t test2[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
|
||||
|
||||
zassert_equal(crc16_ccitt(0xffff, test0, sizeof(test0)),
|
||||
0xf0b8, NULL);
|
||||
zassert_equal(crc16_ccitt(0xffff, test2, sizeof(test2)) ^ 0xFFFF,
|
||||
0x906e, NULL);
|
||||
}
|
||||
|
||||
void test_crc8_ccitt(void)
|
||||
{
|
||||
u8_t test0[] = { 0 };
|
||||
|
@ -50,6 +94,8 @@ void test_main(void)
|
|||
ztest_test_suite(test_crc,
|
||||
ztest_unit_test(test_crc16),
|
||||
ztest_unit_test(test_crc16_ansi),
|
||||
ztest_unit_test(test_crc16_ccitt),
|
||||
ztest_unit_test(test_crc16_ccitt_for_ppp),
|
||||
ztest_unit_test(test_crc8_ccitt));
|
||||
ztest_run_test_suite(test_crc);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue