Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions sys/checksum/crc8.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/** @} */
33 changes: 33 additions & 0 deletions sys/checksum/doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!--
Copyright 2016 Freie Universität Berlin
Copyright 2016 Ludwig Knüpfer <[email protected]>

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.
35 changes: 0 additions & 35 deletions sys/checksum/doc.txt

This file was deleted.

23 changes: 20 additions & 3 deletions sys/include/checksum/crc8.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
91 changes: 91 additions & 0 deletions tests/unittests/tests-checksum/tests-checksum-crc8-lsb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2019 Benjamin Valentin <[email protected]>
*
* 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 <stdint.h>

#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;
}
1 change: 1 addition & 0 deletions tests/unittests/tests-checksum/tests-checksum.c
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
7 changes: 7 additions & 0 deletions tests/unittests/tests-checksum/tests-checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down