Skip to content

Commit 734c570

Browse files
authored
Merge pull request #21552 from Teufelchen1/feat/crc16fcs
checksum: Add crc16-fcs / IBM-SDLC
2 parents b1296af + 65fc4b0 commit 734c570

File tree

8 files changed

+217
-3
lines changed

8 files changed

+217
-3
lines changed

sys/checksum/crc16_ccitt.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,21 @@ uint16_t crc16_ccitt_mcrf4xx_calc(const unsigned char *buf, size_t len)
123123
return crc16_ccitt_kermit_update(0xFFFF, buf, len);
124124
}
125125

126+
uint16_t crc16_ccitt_fcs_start(const unsigned char *buf, size_t len)
127+
{
128+
return crc16_ccitt_kermit_update(0xFFFF, buf, len);
129+
}
130+
131+
uint16_t crc16_ccitt_fcs_finish(uint16_t crc, const unsigned char *buf, size_t len)
132+
{
133+
return crc16_ccitt_kermit_update(crc, buf, len) ^ 0xFFFFU;
134+
}
135+
136+
uint16_t crc16_ccitt_fcs_calc(const unsigned char *buf, size_t len)
137+
{
138+
return crc16_ccitt_fcs_start(buf, len) ^ 0xFFFFU;
139+
}
140+
126141
uint16_t crc16_ccitt_false_update(uint16_t crc, const unsigned char *buf, size_t len)
127142
{
128143
while (len--) {

sys/include/checksum/crc16_ccitt.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,71 @@ uint16_t crc16_ccitt_kermit_update(uint16_t crc, const unsigned char *buf, size_
7171
*/
7272
uint16_t crc16_ccitt_kermit_calc(const unsigned char *buf, size_t len);
7373

74+
/**
75+
* @brief Start a CRC16-CCITT-FCS / IBM-SDLC calculation
76+
*
77+
* @param[in] buf Start of the memory area to checksum
78+
* @param[in] len Number of bytes to checksum
79+
*
80+
* @return Partial checksum of the specified memory area. To be finalised
81+
* with crc16_ccitt_fcs_finish()
82+
*/
83+
uint16_t crc16_ccitt_fcs_start(const unsigned char *buf, size_t len);
84+
85+
/**
86+
* @brief Update CRC16-CCITT-FCS / IBM-SDLC
87+
*
88+
* @param[in] crc A start value for the CRC calculation, usually the
89+
* return value of a previous call to
90+
* crc16_ccitt_fcs_start() or crc16_ccitt_fcs_update()
91+
* @param[in] buf Start of the memory area to checksum
92+
* @param[in] len Number of bytes to checksum
93+
*
94+
* @return Partial checksum of the specified memory area based on the
95+
* given start value. To be finalised with crc16_ccitt_fcs_finish()
96+
*/
97+
static inline uint16_t crc16_ccitt_fcs_update(uint16_t crc, const unsigned char *buf,
98+
size_t len)
99+
{
100+
/* Since CCITT-KERMIT and CCITT-FCS only differ in the starting
101+
* seed, we wrap around crc16_ccitt_kermit_update() for updating */
102+
return crc16_ccitt_kermit_update(crc, buf, len);
103+
}
104+
105+
/**
106+
* @brief Finalise CRC16-CCITT-FCS / IBM-SDLC
107+
*
108+
* @param[in] crc A start value for the CRC calculation, usually the
109+
* return value of a previous call to
110+
* crc16_ccitt_fcs_start() or crc16_ccitt_fcs_update()
111+
* @param[in] buf Start of the memory area to checksum
112+
* @param[in] len Number of bytes to checksum
113+
*
114+
* @return Checksum of the specified memory area based on the
115+
* given start value.
116+
*/
117+
uint16_t crc16_ccitt_fcs_finish(uint16_t crc, const unsigned char *buf, size_t len);
118+
119+
/**
120+
* @brief Calculate CRC16-CCITT-FCS / IBM-SDLC in one pass.
121+
*
122+
* Parameter | Value
123+
* --------: | :----
124+
* Polynom | `0x1021`
125+
* Init | `0xffff`
126+
* Refin | `true`
127+
* Refout | `true`
128+
* Xorout | `0xffff`
129+
* Check | `0x906e`
130+
* Residue | `0xf0b8`
131+
*
132+
* @param[in] buf Start of the memory area to checksum
133+
* @param[in] len Number of bytes to checksum
134+
*
135+
* @return Checksum of the specified memory area
136+
*/
137+
uint16_t crc16_ccitt_fcs_calc(const unsigned char *buf, size_t len);
138+
74139
/**
75140
* @brief Update CRC16-CCITT-MCRF4XX
76141
*

tests/unittests/tests-checksum/tests-checksum-crc16-ccitt-false.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 Bennet Blischke <[email protected]>
2+
* Copyright 2022 Bennet Hattesen <[email protected]>
33
*
44
* This file is subject to the terms and conditions of the GNU Lesser
55
* General Public License v2.1. See the file LICENSE in the top level
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2025 Bennet Hattesen <[email protected]>
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
#include <stdio.h>
9+
#include <stdint.h>
10+
11+
#include "embUnit/embUnit.h"
12+
13+
#include "checksum/crc16_ccitt.h"
14+
15+
#include "tests-checksum.h"
16+
17+
static int calc_and_compare_crc16_ccitt_fcs_with_update(const unsigned char *buf,
18+
size_t len, size_t split,
19+
uint16_t expected)
20+
{
21+
uint16_t result = crc16_ccitt_fcs_start(buf, split);
22+
23+
result = crc16_ccitt_fcs_finish(result, buf + split, len - split);
24+
return result == expected;
25+
}
26+
27+
static int calc_and_compare_crc16_ccitt_fcs(const unsigned char *buf, size_t len,
28+
uint16_t expected)
29+
{
30+
uint16_t result = crc16_ccitt_fcs_calc(buf, len);
31+
32+
return result == expected;
33+
}
34+
35+
static void test_checksum_crc16_ccitt_fcs_sequence_empty(void)
36+
{
37+
unsigned char buf[] = "";
38+
uint16_t expect = 0x0000;
39+
40+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs(buf, sizeof(buf) - 1, expect));
41+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs_with_update(buf, sizeof(buf) - 1,
42+
(sizeof(buf) - 1) / 2, expect));
43+
}
44+
45+
static void test_checksum_crc16_ccitt_fcs_sequence_1a(void)
46+
{
47+
unsigned char buf[] = "A";
48+
uint16_t expect = 0xA3F5;
49+
50+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs(buf, sizeof(buf) - 1, expect));
51+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs_with_update(buf, sizeof(buf) - 1,
52+
(sizeof(buf) - 1) / 2, expect));
53+
}
54+
55+
static void test_checksum_crc16_ccitt_fcs_sequence_256a(void)
56+
{
57+
unsigned char buf[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
58+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
59+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
60+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
61+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
62+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
63+
"AAAA";
64+
uint16_t expect = 0x0F9F;
65+
66+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs(buf, sizeof(buf) - 1, expect));
67+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs_with_update(buf, sizeof(buf) - 1,
68+
(sizeof(buf) - 1) / 2, expect));
69+
}
70+
71+
static void test_checksum_crc16_ccitt_fcs_sequence_1to9(void)
72+
{
73+
unsigned char buf[] = "123456789";
74+
uint16_t expect = 0x906E;
75+
76+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs(buf, sizeof(buf) - 1, expect));
77+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs_with_update(buf, sizeof(buf)
78+
- 1, (sizeof(buf) - 1) / 2,
79+
expect));
80+
}
81+
82+
static void test_checksum_crc16_ccitt_fcs_sequence_4bytes(void)
83+
{
84+
unsigned char buf[] = { 0x12, 0x34, 0x56, 0x78 };
85+
uint16_t expect = 0x9B2E;
86+
87+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs(buf, sizeof(buf), expect));
88+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs_with_update(buf, sizeof(buf),
89+
sizeof(buf) / 2, expect));
90+
}
91+
92+
static void test_checksum_crc16_ccitt_fcs_sequence_6bytes(void)
93+
{
94+
unsigned char buf[] = { 0x00, 0x01, 0x02, 0x03 };
95+
uint16_t expect = 0xA729;
96+
97+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs(buf, sizeof(buf), expect));
98+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs_with_update(buf, sizeof(buf),
99+
sizeof(buf) / 2, expect));
100+
101+
unsigned char buf2[] = { 0x00, 0x01, 0x02, 0x03, 0x29, 0xA7 };
102+
uint16_t expect2 = 0x0F47;
103+
104+
// Residue test
105+
TEST_ASSERT(crc16_ccitt_fcs_start(buf2, sizeof(buf2)) == 0xF0B8);
106+
107+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs(buf2, sizeof(buf2), expect2));
108+
TEST_ASSERT(calc_and_compare_crc16_ccitt_fcs_with_update(buf2, sizeof(buf2),
109+
sizeof(buf2) / 2, expect2));
110+
}
111+
112+
Test *tests_checksum_crc16_ccitt_fcs_tests(void)
113+
{
114+
EMB_UNIT_TESTFIXTURES(fixtures) {
115+
new_TestFixture(test_checksum_crc16_ccitt_fcs_sequence_empty),
116+
new_TestFixture(test_checksum_crc16_ccitt_fcs_sequence_1a),
117+
new_TestFixture(test_checksum_crc16_ccitt_fcs_sequence_256a),
118+
new_TestFixture(test_checksum_crc16_ccitt_fcs_sequence_1to9),
119+
new_TestFixture(test_checksum_crc16_ccitt_fcs_sequence_4bytes),
120+
new_TestFixture(test_checksum_crc16_ccitt_fcs_sequence_6bytes),
121+
};
122+
123+
EMB_UNIT_TESTCALLER(checksum_crc16_ccitt_fcs_tests, NULL, NULL, fixtures);
124+
125+
return (Test *)&checksum_crc16_ccitt_fcs_tests;
126+
}

tests/unittests/tests-checksum/tests-checksum-crc16-ccitt-kermit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 Bennet Blischke <[email protected]>
2+
* Copyright 2022 Bennet Hattesen <[email protected]>
33
*
44
* This file is subject to the terms and conditions of the GNU Lesser
55
* General Public License v2.1. See the file LICENSE in the top level

tests/unittests/tests-checksum/tests-checksum-crc16-ccitt-mcrf4xx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 Bennet Blischke <[email protected]>
2+
* Copyright 2022 Bennet Hattesen <[email protected]>
33
*
44
* This file is subject to the terms and conditions of the GNU Lesser
55
* General Public License v2.1. See the file LICENSE in the top level

tests/unittests/tests-checksum/tests-checksum.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ void tests_checksum(void)
1313
TESTS_RUN(tests_checksum_crc8_tests());
1414
TESTS_RUN(tests_checksum_crc8_lsb_tests());
1515
TESTS_RUN(tests_checksum_crc16_ccitt_kermit_tests());
16+
TESTS_RUN(tests_checksum_crc16_ccitt_fcs_tests());
1617
TESTS_RUN(tests_checksum_crc16_ccitt_mcrf4xx_tests());
1718
TESTS_RUN(tests_checksum_crc16_ccitt_aug_tests());
1819
TESTS_RUN(tests_checksum_crc16_ccitt_false_tests());

tests/unittests/tests-checksum/tests-checksum.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ Test *tests_checksum_crc8_lsb_tests(void);
5050
*/
5151
Test *tests_checksum_crc16_ccitt_kermit_tests(void);
5252

53+
/**
54+
* @brief Generates tests for crc16-ccitt-fcs from checksum/crc16_ccitt.h
55+
*
56+
* @return embUnit tests if successful, NULL if not.
57+
*/
58+
Test *tests_checksum_crc16_ccitt_fcs_tests(void);
59+
5360
/**
5461
* @brief Generates tests for crc16-ccitt-mcrf4xx from checksum/crc16_ccitt.h
5562
*

0 commit comments

Comments
 (0)