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