diff --git a/sys/checksum/crc8.c b/sys/checksum/crc8.c index 5a502c27a60a..85ee4dc49e5c 100644 --- a/sys/checksum/crc8.c +++ b/sys/checksum/crc8.c @@ -39,4 +39,21 @@ uint8_t crc8(const uint8_t *data, size_t len, uint8_t g_polynom, uint8_t crc) return crc; } +uint8_t crc8_lsb(const uint8_t *data, size_t len, uint8_t g_polynom, uint8_t crc) +{ + for (size_t i = 0; i < len; i++) + { + crc ^= data[i]; + + for (int i = 0; i < 8; i++) + { + bool xor = crc & 0x01; + crc = crc >> 1; + crc = xor ? crc ^ g_polynom : crc; + } + } + + return crc; +} + /** @} */ diff --git a/sys/checksum/doc.md b/sys/checksum/doc.md new file mode 100644 index 000000000000..6807fe1f76da --- /dev/null +++ b/sys/checksum/doc.md @@ -0,0 +1,33 @@ + + +@defgroup sys_checksum Checksum +@ingroup sys_hashes +@brief Checksum function libraries + +This module provides a number of checksum functions. Most notably is the +@ref sys_checksum_crc16_ccitt and the @ref sys_checksum_ucrc16 modules which +provide support for the CRC16 checksum. + +@ref sys_checksum_crc16_ccitt only provides an implementation of the CCITT +flavor of CRC16 (polynomial @$ x^{16} + x^{12} + x^{5} + 1 @$) for big-endian +numbers with starting seed `0x1d0f` (though others can be provided), while +@ref sys_checksum_ucrc16 is more generalized, since it takes the +hexadecimal representation of the polynomial as a parameter and provides +functions and standardized polynomials for both big- and little-endian +numbers. + +The caveat of @ref sys_checksum_ucrc16 is that it is significantly slower +(approximately factor 8) than @ref sys_checksum_crc16_ccitt since the latter +is able to calculate the checksum byte-wise, while the first calculates +needs to calculate it bit-wise. @ref sys_checksum_crc16_ccitt achieves this +advantage by using a look-up table that provides the checksum for every +possible byte-value. It thus trades of memory against speed. If your +platform is rather small equipped in memory you should prefer the +@ref sys_checksum_ucrc16 version. diff --git a/sys/checksum/doc.txt b/sys/checksum/doc.txt deleted file mode 100644 index 843c3871d78d..000000000000 --- a/sys/checksum/doc.txt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 Freie Universität Berlin - * Copyright 2016 Ludwig Knüpfer - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @defgroup sys_checksum Checksum - * @ingroup sys_hashes - * @brief Checksum function libraries - * - * This module provides a number of checksum functions. Most notably is the - * @ref sys_checksum_crc16_ccitt and the @ref sys_checksum_ucrc16 modules which - * provide support for the CRC16 checksum. - * - * @ref sys_checksum_crc16_ccitt only provides an implementation of the CCITT - * flavor of CRC16 (polynomial @$ x^{16} + x^{12} + x^{5} + 1 @$) for big-endian - * numbers with starting seed `0x1d0f` (though others can be provided), while - * @ref sys_checksum_ucrc16 is more generalized, since it takes the - * hexadecimal representation of the polynomial as a parameter and provides - * functions and standardized polynomials for both big- and little-endian - * numbers. - * - * The caveat of @ref sys_checksum_ucrc16 is that it is significantly slower - * (approximately factor 8) than @ref sys_checksum_crc16_ccitt since the latter - * is able to calculate the checksum byte-wise, while the first calculates - * needs to calculate it bit-wise. @ref sys_checksum_crc16_ccitt achieves this - * advantage by using a look-up table that provides the checksum for every - * possible byte-value. It thus trades of memory against speed. If your - * platform is rather small equipped in memory you should prefer the - * @ref sys_checksum_ucrc16 version. - */ diff --git a/sys/include/checksum/crc8.h b/sys/include/checksum/crc8.h index 3ef6ec8a4762..7df120a08b70 100644 --- a/sys/include/checksum/crc8.h +++ b/sys/include/checksum/crc8.h @@ -29,20 +29,37 @@ extern "C" { #endif /** - * @brief Calculate CRC-8 + * @brief Calculate CRC-8 (MSB first) + * + * This CRC8 checksum type is usually more common. * * @param[in] data Start of memory area to checksum * @param[in] len Number of bytes in @p buf to calculate checksum for * @param[in] poly The generator polynomial for the checksum * @param[in] seed The seed (starting value) for the checksum * - * @note Reflected inputs or outputs and final XOR must be realized - * by the caller if needed. + * @note A final XOR must be realized by the caller if needed. * * @return Checksum of the specified memory area. */ uint8_t crc8(const uint8_t *data, size_t len, uint8_t poly, uint8_t seed); +/** + * @brief Calculate a reflected CRC-8 (LSB first) + * + * This CRC8 checksum type is used for example by Onewire. + * + * @param[in] data Start of memory area to checksum + * @param[in] len Number of bytes in @p buf to calculate checksum for + * @param[in] poly The generator polynomial for the checksum + * @param[in] seed The seed (starting value) for the checksum + * + * @note A final XOR must be realized by the caller if needed. + * + * @return Checksum of the specified memory area. + */ +uint8_t crc8_lsb(const uint8_t *data, size_t len, uint8_t poly, uint8_t seed); + #ifdef __cplusplus } #endif diff --git a/tests/unittests/tests-checksum/tests-checksum-crc8-lsb.c b/tests/unittests/tests-checksum/tests-checksum-crc8-lsb.c new file mode 100644 index 000000000000..fe50af4ef5f7 --- /dev/null +++ b/tests/unittests/tests-checksum/tests-checksum-crc8-lsb.c @@ -0,0 +1,91 @@ +/* + * Copyright 2019 Benjamin Valentin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include + +#include "embUnit/embUnit.h" + +#include "checksum/crc8.h" + +#include "tests-checksum.h" + +#define CRC8_POLY 0x31 +#define CRC8_INIT 0xff + +static void test_checksum_crc8_lsb_sequence_empty(void) +{ + unsigned char buf[] = ""; + uint8_t expect = 0xFF; + + TEST_ASSERT_EQUAL_INT(expect, crc8_lsb(buf, sizeof(buf) - 1, CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_lsb_sequence_1a(void) +{ + unsigned char buf[] = "A"; + uint8_t expect = 0x0F; + + TEST_ASSERT_EQUAL_INT(expect, crc8_lsb(buf, sizeof(buf) - 1, CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_lsb_sequence_256a(void) +{ + unsigned char buf[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint8_t expect = 0x0F; + + TEST_ASSERT_EQUAL_INT(expect, crc8_lsb(buf, sizeof(buf) - 1, CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_lsb_sequence_1to9(void) +{ + unsigned char buf[] = "123456789"; + uint8_t expect = 0x20; + + TEST_ASSERT_EQUAL_INT(expect, crc8_lsb(buf, sizeof(buf) - 1, CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_lsb_sequence_4bytes(void) +{ + unsigned char buf[] = { 0x12, 0x34, 0x56, 0x78 }; + uint8_t expect = 0x1C; + + TEST_ASSERT_EQUAL_INT(expect, crc8_lsb(buf, sizeof(buf), CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_lsb_onewire_params(void) +{ + unsigned char buf[] = { 0x2A }; + uint8_t expect = 0x5D; + + TEST_ASSERT_EQUAL_INT(expect, crc8_lsb(buf, sizeof(buf), 0x8C, 0x00)); +} + +Test *tests_checksum_crc8_lsb_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + /* Reference values according to + * http://srecord.sourceforge.net/crc16-ccitt.html */ + new_TestFixture(test_checksum_crc8_lsb_sequence_empty), + new_TestFixture(test_checksum_crc8_lsb_sequence_1a), + new_TestFixture(test_checksum_crc8_lsb_sequence_256a), + new_TestFixture(test_checksum_crc8_lsb_sequence_1to9), + new_TestFixture(test_checksum_crc8_lsb_sequence_4bytes), + new_TestFixture(test_checksum_crc8_lsb_onewire_params), + }; + + EMB_UNIT_TESTCALLER(checksum_crc8_lsb_tests, NULL, NULL, fixtures); + + return (Test *)&checksum_crc8_lsb_tests; +} diff --git a/tests/unittests/tests-checksum/tests-checksum.c b/tests/unittests/tests-checksum/tests-checksum.c index 93aa035c9dee..b7967837cee9 100644 --- a/tests/unittests/tests-checksum/tests-checksum.c +++ b/tests/unittests/tests-checksum/tests-checksum.c @@ -11,6 +11,7 @@ void tests_checksum(void) { TESTS_RUN(tests_checksum_crc8_tests()); + TESTS_RUN(tests_checksum_crc8_lsb_tests()); TESTS_RUN(tests_checksum_crc16_ccitt_kermit_tests()); TESTS_RUN(tests_checksum_crc16_ccitt_mcrf4xx_tests()); TESTS_RUN(tests_checksum_crc16_ccitt_aug_tests()); diff --git a/tests/unittests/tests-checksum/tests-checksum.h b/tests/unittests/tests-checksum/tests-checksum.h index 48999035bdcc..5a0eef038928 100644 --- a/tests/unittests/tests-checksum/tests-checksum.h +++ b/tests/unittests/tests-checksum/tests-checksum.h @@ -36,6 +36,13 @@ void tests_checksum(void); */ Test *tests_checksum_crc8_tests(void); +/** + * @brief Generates tests for checksum/crc8_lsb.h + * + * @return embUnit tests if successful, NULL if not. + */ +Test *tests_checksum_crc8_lsb_tests(void); + /** * @brief Generates tests for crc16-ccitt-kermit from checksum/crc16_ccitt.h *