1 /*
2 * Copyright (c) 2025 Renesas Electronics Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/crc.h>
8
9 #include <zephyr/device.h>
10 #include <zephyr/ztest.h>
11 #include <zephyr/logging/log.h>
12
13 #define WAIT_THREAD_STACK_SIZE 1024
14 #define WAIT_THREAD_PRIO -10
15
16 static void wait_thread_entry(void *a, void *b, void *c);
17
18 K_THREAD_STACK_DEFINE(wait_thread_stack_area, WAIT_THREAD_STACK_SIZE);
19 struct k_thread wait_thread_data;
20
21 /* Define result of CRC computation */
22 #define RESULT_CRC_16_THREADSAFE_WAIT_THREAD_ENTRY 0xD543
23
24 /**
25 * 1) Take the semaphore
26 * 2) Sleep for 50 ms (to allow ztest main thread to attempt to acquire semaphore)
27 * 3) Give the semaphore
28 */
wait_thread_entry(void * a,void * b,void * c)29 static void wait_thread_entry(void *a, void *b, void *c)
30 {
31 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
32
33 uint8_t data[8] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4};
34
35 struct crc_ctx ctx = {
36 .type = CRC16,
37 .polynomial = CRC16_POLY,
38 .seed = CRC16_INIT_VAL,
39 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
40 };
41
42 crc_begin(dev, &ctx);
43
44 k_sleep(K_MSEC(50));
45
46 crc_update(dev, &ctx, data, sizeof(data));
47 crc_finish(dev, &ctx);
48 zassert_equal(crc_verify(&ctx, RESULT_CRC_16_THREADSAFE_WAIT_THREAD_ENTRY), 0);
49 }
50
51 /* Define result of CRC computation */
52 #define RESULT_CRC_8 0xB2
53
54 /**
55 * @brief Test that crc8 works
56 */
ZTEST(crc,test_crc_8)57 ZTEST(crc, test_crc_8)
58 {
59 #ifndef CONFIG_CRC_DRIVER_HAS_CRC8
60 ztest_test_skip();
61 #endif
62
63 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
64
65 uint8_t data[8] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4};
66
67 struct crc_ctx ctx = {
68 .type = CRC8,
69 .polynomial = CRC8_POLY,
70 .seed = CRC8_INIT_VAL,
71 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
72 };
73
74 crc_begin(dev, &ctx);
75
76 k_sleep(K_MSEC(50));
77
78 crc_update(dev, &ctx, data, sizeof(data));
79 crc_finish(dev, &ctx);
80 zassert_equal(crc_verify(&ctx, RESULT_CRC_8), 0);
81 }
82
83 /* Define result of CRC computation */
84 #define RESULT_CRC_16 0xD543
85
86 /**
87 * @brief Test that crc16 works
88 */
ZTEST(crc,test_crc_16)89 ZTEST(crc, test_crc_16)
90 {
91 #ifndef CONFIG_CRC_DRIVER_HAS_CRC16
92 ztest_test_skip();
93 #endif
94
95 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
96
97 uint8_t data[8] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4};
98
99 struct crc_ctx ctx = {
100 .type = CRC16,
101 .polynomial = CRC16_POLY,
102 .seed = CRC16_INIT_VAL,
103 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
104 };
105
106 zassert_equal(crc_begin(dev, &ctx), 0);
107 zassert_equal(crc_update(dev, &ctx, data, sizeof(data)), 0);
108 zassert_equal(crc_finish(dev, &ctx), 0);
109
110 zassert_equal(crc_verify(&ctx, RESULT_CRC_16), 0);
111 }
112
113 /* Define result of CRC computation */
114 #define RESULT_CRC_CCITT 0x445C
115
116 /**
117 * @brief Test that crc_16_ccitt works
118 */
ZTEST(crc,test_crc_16_ccitt)119 ZTEST(crc, test_crc_16_ccitt)
120 {
121 #ifndef CONFIG_CRC_DRIVER_HAS_CRC16_CCITT
122 ztest_test_skip();
123 #endif
124
125 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
126
127 uint8_t data[8] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4};
128
129 struct crc_ctx ctx = {
130 .type = CRC16_CCITT,
131 .polynomial = CRC16_CCITT_POLY,
132 .seed = CRC16_CCITT_INIT_VAL,
133 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
134 };
135
136 zassert_equal(crc_begin(dev, &ctx), 0);
137 zassert_equal(crc_update(dev, &ctx, data, sizeof(data)), 0);
138 zassert_equal(crc_finish(dev, &ctx), 0);
139
140 zassert_equal(crc_verify(&ctx, RESULT_CRC_CCITT), 0);
141 }
142
143 /* Define result of CRC computation */
144 #define RESULT_CRC_32_C 0xBB19ECB2
145
146 /**
147 * @brief Test that crc_32_c works
148 */
ZTEST(crc,test_crc_32_c)149 ZTEST(crc, test_crc_32_c)
150 {
151 #ifndef CONFIG_CRC_DRIVER_HAS_CRC32_C
152 ztest_test_skip();
153 #endif
154
155 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
156
157 uint8_t data[8] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4};
158
159 struct crc_ctx ctx = {
160 .type = CRC32_C,
161 .polynomial = CRC32C_POLY,
162 .seed = CRC32_C_INIT_VAL,
163 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
164 };
165
166 zassert_equal(crc_begin(dev, &ctx), 0);
167 zassert_equal(crc_update(dev, &ctx, data, sizeof(data)), 0);
168 zassert_equal(crc_finish(dev, &ctx), 0);
169
170 zassert_equal(crc_verify(&ctx, RESULT_CRC_32_C), 0);
171 }
172
173 /* Define result of CRC computation */
174 #define RESULT_CRC_32_IEEE 0xCEA4A6C2
175
176 /**
177 * @brief Test that crc_32_ieee works
178 */
ZTEST(crc,test_crc_32_ieee)179 ZTEST(crc, test_crc_32_ieee)
180 {
181 #ifndef CONFIG_CRC_DRIVER_HAS_CRC32_IEEE
182 ztest_test_skip();
183 #endif
184
185 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
186
187 uint8_t data[8] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4};
188 struct crc_ctx ctx = {
189 .type = CRC32_IEEE,
190 .polynomial = CRC32_IEEE_POLY,
191 .seed = CRC32_IEEE_INIT_VAL,
192 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
193 };
194
195 zassert_equal(crc_begin(dev, &ctx), 0);
196 zassert_equal(crc_update(dev, &ctx, data, sizeof(data)), 0);
197 zassert_equal(crc_finish(dev, &ctx), 0);
198 zassert_equal(crc_verify(&ctx, RESULT_CRC_32_IEEE), 0);
199 }
200
201 /* Define result of CRC computation */
202 #define RESULT_CRC_8_REMAIN_3 0xBB
203
204 /**
205 * @brief Test that crc_8_remain_3 works
206 */
ZTEST(crc,test_crc_8_remain_3)207 ZTEST(crc, test_crc_8_remain_3)
208 {
209 #ifndef CONFIG_CRC_DRIVER_HAS_CRC8
210 ztest_test_skip();
211 #endif
212
213 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
214
215 uint8_t data[11] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4, 0x3D, 0x4D, 0x51};
216
217 struct crc_ctx ctx = {
218 .type = CRC8,
219 .polynomial = CRC8_POLY,
220 .seed = CRC8_INIT_VAL,
221 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
222 };
223
224 zassert_equal(crc_begin(dev, &ctx), 0);
225 zassert_equal(crc_update(dev, &ctx, data, sizeof(data)), 0);
226 zassert_equal(crc_finish(dev, &ctx), 0);
227 zassert_equal(crc_verify(&ctx, RESULT_CRC_8_REMAIN_3), 0);
228 }
229
230 /* Define result of CRC computation */
231 #define RESULT_CRC_16_REMAIN_1 0x2055
232
233 /**
234 * @brief Test that crc_16_remain_1 works
235 */
ZTEST(crc,test_crc_16_remain_1)236 ZTEST(crc, test_crc_16_remain_1)
237 {
238 #ifndef CONFIG_CRC_DRIVER_HAS_CRC16
239 ztest_test_skip();
240 #endif
241
242 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
243
244 uint8_t data[9] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4, 0x3D};
245
246 struct crc_ctx ctx = {
247 .type = CRC16,
248 .polynomial = CRC16_POLY,
249 .seed = CRC16_INIT_VAL,
250 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
251 };
252
253 zassert_equal(crc_begin(dev, &ctx), 0);
254 zassert_equal(crc_update(dev, &ctx, data, sizeof(data)), 0);
255 zassert_equal(crc_finish(dev, &ctx), 0);
256
257 zassert_equal(crc_verify(&ctx, RESULT_CRC_16_REMAIN_1), 0);
258 }
259
260 /* Define result of CRC computation */
261 #define RESULT_CRC_CCITT_REMAIN_2 0x24BD
262
263 /**
264 * @brief Test that crc_16_ccitt works
265 */
ZTEST(crc,test_crc_16_ccitt_remain_2)266 ZTEST(crc, test_crc_16_ccitt_remain_2)
267 {
268 #ifndef CONFIG_CRC_DRIVER_HAS_CRC16_CCITT
269 ztest_test_skip();
270 #endif
271
272 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
273
274 uint8_t data[10] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4, 0xFF, 0xA0};
275
276 struct crc_ctx ctx = {
277 .type = CRC16_CCITT,
278 .polynomial = CRC16_CCITT_POLY,
279 .seed = CRC16_CCITT_INIT_VAL,
280 .reversed = CRC_FLAG_REVERSE_OUTPUT | CRC_FLAG_REVERSE_INPUT,
281 };
282
283 zassert_equal(crc_begin(dev, &ctx), 0);
284 zassert_equal(crc_update(dev, &ctx, data, sizeof(data)), 0);
285 zassert_equal(crc_finish(dev, &ctx), 0);
286
287 zassert_equal(crc_verify(&ctx, RESULT_CRC_CCITT_REMAIN_2), 0);
288 }
289
290 /* Select CRC test variant macros */
291 #ifdef CONFIG_CRC_DRIVER_HAS_CRC8
292 #define CRC_TEST_VARIANT CRC8
293 #define CRC_TEST_POLY CRC8_POLY
294 #define CRC_TEST_INIT_VAL CRC8_INIT_VAL
295 #define CRC_TEST_REVERSE_CONFIG (CRC_FLAG_REVERSE_INPUT | CRC_FLAG_REVERSE_OUTPUT)
296 #define CRC_TEST_DISCONTINUOUS_BUF_EXPECTED 0x75
297 #elif defined(CONFIG_CRC_DRIVER_HAS_CRC16)
298 #define CRC_TEST_VARIANT CRC16
299 #define CRC_TEST_POLY CRC16_POLY
300 #define CRC_TEST_INIT_VAL CRC16_INIT_VAL
301 #define CRC_TEST_REVERSE_CONFIG (CRC_FLAG_REVERSE_INPUT | CRC_FLAG_REVERSE_OUTPUT)
302 #define CRC_TEST_DISCONTINUOUS_BUF_EXPECTED 0xBDE3
303 #else
304 #define CRC_TEST_VARIANT CRC32_C
305 #define CRC_TEST_POLY CRC32C_POLY
306 #define CRC_TEST_INIT_VAL CRC32_C_INIT_VAL
307 #define CRC_TEST_REVERSE_CONFIG (CRC_FLAG_REVERSE_INPUT | CRC_FLAG_REVERSE_OUTPUT)
308 #define CRC_TEST_DISCONTINUOUS_BUF_EXPECTED 0x20477127
309 #endif
310
311 /**
312 * @brief Test CRC calculation with discontinuous buffers.
313 */
ZTEST(crc,test_discontinuous_buf)314 ZTEST(crc, test_discontinuous_buf)
315 {
316 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
317
318 uint8_t data1[5] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E};
319 uint8_t data2[5] = {0x49, 0x00, 0xC4, 0x3B, 0x78};
320
321 struct crc_ctx ctx = {
322 .type = CRC_TEST_VARIANT,
323 .polynomial = CRC_TEST_POLY,
324 .seed = CRC_TEST_INIT_VAL,
325 .reversed = CRC_TEST_REVERSE_CONFIG,
326 };
327
328 zassert_equal(crc_begin(dev, &ctx), 0);
329 zassert_equal(crc_update(dev, &ctx, data1, sizeof(data1)), 0);
330 zassert_equal(crc_update(dev, &ctx, data2, sizeof(data2)), 0);
331 zassert_equal(crc_finish(dev, &ctx), 0);
332 zassert_equal(crc_verify(&ctx, CRC_TEST_DISCONTINUOUS_BUF_EXPECTED), 0);
333 }
334
335 /* Define result of CRC computation */
336 #ifdef CONFIG_CRC_DRIVER_HAS_CRC8
337 #define CRC_TEST_THREADSAFE_EXPECTED 0xBB
338 #elif defined(CONFIG_CRC_DRIVER_HAS_CRC16)
339 #define CRC_TEST_THREADSAFE_EXPECTED 0x24CA
340 #else
341 #define CRC_TEST_THREADSAFE_EXPECTED 0x9BCEE9AB
342 #endif
343
344 /**
345 * @brief Test CRC function semaphore wait for thread safety
346 *
347 * Verifies that CRC operations are blocked until a semaphore is released. A new thread
348 * acquires the semaphore, and the main thread's CRC operations wait until it is released.
349 */
ZTEST(crc,test_crc_threadsafe)350 ZTEST(crc, test_crc_threadsafe)
351 {
352
353 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_crc));
354
355 uint8_t data[11] = {0x0A, 0x2B, 0x4C, 0x6D, 0x8E, 0x49, 0x00, 0xC4, 0x3D, 0x4D, 0x51};
356
357 struct crc_ctx ctx = {
358 .type = CRC_TEST_VARIANT,
359 .polynomial = CRC_TEST_POLY,
360 .seed = CRC_TEST_INIT_VAL,
361 .reversed = CRC_TEST_REVERSE_CONFIG,
362 };
363
364 /**
365 * Create new thread that will immediately take the semaphore
366 */
367 k_thread_create(&wait_thread_data, wait_thread_stack_area,
368 K_THREAD_STACK_SIZEOF(wait_thread_stack_area), wait_thread_entry, NULL,
369 NULL, NULL, WAIT_THREAD_PRIO, 0, K_NO_WAIT);
370
371 /**
372 * Sleep for 10 ms to ensure that new thread has taken lock
373 */
374 k_sleep(K_MSEC(10));
375
376 /**
377 * Attempt to take semaphore, this should wait for the new thread to give the semaphore
378 * before executing
379 */
380 crc_begin(dev, &ctx);
381 crc_update(dev, &ctx, data, sizeof(data));
382 crc_finish(dev, &ctx);
383 zassert_equal(crc_verify(&ctx, CRC_TEST_THREADSAFE_EXPECTED), 0);
384 }
385
386 ZTEST_SUITE(crc, NULL, NULL, NULL, NULL, NULL);
387