diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 7a400d4b8c..689b8f6ab9 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -529,6 +529,7 @@ endif ifneq (,$(filter sht3x,$(USEMODULE))) USEMODULE += xtimer + USEMODULE += checksum FEATURES_REQUIRED += periph_i2c endif diff --git a/drivers/sht3x/sht3x.c b/drivers/sht3x/sht3x.c index c4bd7af0c8..8e2402b761 100644 --- a/drivers/sht3x/sht3x.c +++ b/drivers/sht3x/sht3x.c @@ -20,6 +20,7 @@ #include #include +#include "checksum/crc8.h" #include "sht3x.h" #include "xtimer.h" @@ -99,8 +100,10 @@ static int _status (sht3x_dev_t* dev, uint16_t* status); static int _send_command(sht3x_dev_t* dev, uint16_t cmd); static int _read_data(sht3x_dev_t* dev, uint8_t *data, uint8_t len); -/* helper functions */ -static uint8_t _crc8 (uint8_t data[], int len); +static inline uint8_t _crc8(const void* buf, size_t len) +{ + return crc8(buf, len, 0x31, 0xff); +} /* ------------------------------------------------ */ @@ -416,27 +419,3 @@ static int _status (sht3x_dev_t* dev, uint16_t* status) DEBUG_DEV("status=%02x", dev, *status); return SHT3X_OK; } - - -static const uint8_t g_polynom = 0x31; - -static uint8_t _crc8 (uint8_t data[], int len) -{ - /* initialization value */ - uint8_t crc = 0xff; - - /* iterate over all bytes */ - for (int i=0; i < len; i++) - { - crc ^= data[i]; - - for (int i = 0; i < 8; i++) - { - bool xor = crc & 0x80; - crc = crc << 1; - crc = xor ? crc ^ g_polynom : crc; - } - } - - return crc; -} diff --git a/sys/checksum/crc8.c b/sys/checksum/crc8.c new file mode 100644 index 0000000000..5a502c27a6 --- /dev/null +++ b/sys/checksum/crc8.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 Gunar Schorcht + * + * 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. + */ + +/** + * @ingroup sys_checksum_crc8 + * @brief CRC-8 checksum algorithms + * + * @{ + * + * @file + * @brief CRC-8 implementation + * + * @author Gunar Schorcht + */ + +#include +#include "checksum/crc8.h" + +uint8_t crc8(const uint8_t *data, size_t len, uint8_t g_polynom, uint8_t crc) +{ + /* iterate over all bytes */ + for (size_t i=0; i < len; i++) + { + crc ^= data[i]; + + for (int i = 0; i < 8; i++) + { + bool xor = crc & 0x80; + crc = crc << 1; + crc = xor ? crc ^ g_polynom : crc; + } + } + + return crc; +} + +/** @} */ diff --git a/sys/include/checksum/crc8.h b/sys/include/checksum/crc8.h new file mode 100644 index 0000000000..94523eed38 --- /dev/null +++ b/sys/include/checksum/crc8.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Gunar Schorcht + * + * 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_crc8 CRC-8 + * @ingroup sys_checksum + * @brief CRC-8 checksum algorithms + * + * @{ + * + * @file + * @brief CRC-8 definitions + * + * @author Gunar Schorcht + */ +#ifndef CHECKSUM_CRC8_H +#define CHECKSUM_CRC8_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Calculate CRC-8 + * + * @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. + * + * @return Checksum of the specified memory area. + */ +uint8_t crc8(const uint8_t *data, size_t len, uint8_t poly, uint8_t seed); + +#ifdef __cplusplus +} +#endif + +#endif /* CHECKSUM_CRC8_H */ +/** @} */ diff --git a/tests/unittests/tests-checksum/tests-checksum-crc8.c b/tests/unittests/tests-checksum/tests-checksum-crc8.c new file mode 100644 index 0000000000..85c9304123 --- /dev/null +++ b/tests/unittests/tests-checksum/tests-checksum-crc8.c @@ -0,0 +1,82 @@ +/* + * 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_sequence_empty(void) +{ + unsigned char buf[] = ""; + uint8_t expect = 0xFF; + + TEST_ASSERT_EQUAL_INT(expect, crc8(buf, sizeof(buf) - 1, CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_sequence_1a(void) +{ + unsigned char buf[] = "A"; + uint8_t expect = 0xA0; + + TEST_ASSERT_EQUAL_INT(expect, crc8(buf, sizeof(buf) - 1, CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_sequence_256a(void) +{ + unsigned char buf[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint8_t expect = 0xF0; + + TEST_ASSERT_EQUAL_INT(expect, crc8(buf, sizeof(buf) - 1, CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_sequence_1to9(void) +{ + unsigned char buf[] = "123456789"; + uint8_t expect = 0xF7; + + TEST_ASSERT_EQUAL_INT(expect, crc8(buf, sizeof(buf) - 1, CRC8_POLY, CRC8_INIT)); +} + +static void test_checksum_crc8_sequence_4bytes(void) +{ + unsigned char buf[] = { 0x12, 0x34, 0x56, 0x78 }; + uint8_t expect = 0xE0; + + TEST_ASSERT_EQUAL_INT(expect, crc8(buf, sizeof(buf), CRC8_POLY, CRC8_INIT)); +} + +Test *tests_checksum_crc8_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + /* Reference values according to + * http://srecord.sourceforge.net/crc16-ccitt.html */ + new_TestFixture(test_checksum_crc8_sequence_empty), + new_TestFixture(test_checksum_crc8_sequence_1a), + new_TestFixture(test_checksum_crc8_sequence_256a), + new_TestFixture(test_checksum_crc8_sequence_1to9), + new_TestFixture(test_checksum_crc8_sequence_4bytes), + }; + + EMB_UNIT_TESTCALLER(checksum_crc8_tests, NULL, NULL, fixtures); + + return (Test *)&checksum_crc8_tests; +} diff --git a/tests/unittests/tests-checksum/tests-checksum.c b/tests/unittests/tests-checksum/tests-checksum.c index f4a40582ae..2e046ef934 100644 --- a/tests/unittests/tests-checksum/tests-checksum.c +++ b/tests/unittests/tests-checksum/tests-checksum.c @@ -10,6 +10,7 @@ void tests_checksum(void) { + TESTS_RUN(tests_checksum_crc8_tests()); TESTS_RUN(tests_checksum_crc16_ccitt_tests()); TESTS_RUN(tests_checksum_fletcher16_tests()); TESTS_RUN(tests_checksum_fletcher32_tests()); diff --git a/tests/unittests/tests-checksum/tests-checksum.h b/tests/unittests/tests-checksum/tests-checksum.h index 2c37421b60..b1a0e6a312 100644 --- a/tests/unittests/tests-checksum/tests-checksum.h +++ b/tests/unittests/tests-checksum/tests-checksum.h @@ -29,6 +29,13 @@ extern "C" { */ void tests_checksum(void); +/** + * @brief Generates tests for checksum/crc8.h + * + * @return embUnit tests if successful, NULL if not. + */ +Test *tests_checksum_crc8_tests(void); + /** * @brief Generates tests for checksum/crc16_ccitt.h *