1 /*
2 * Copyright 2024 Navimatix GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/gpio.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/ztest_assert.h>
10 #include <stdbool.h>
11 #include <stdint.h>
12 #include <zephyr/ztest.h>
13 #include <zephyr/drivers/stepper.h>
14
15 struct drv8424_api_fixture {
16 const struct device *dev;
17 stepper_event_callback_t callback;
18 };
19
20 struct k_poll_signal stepper_signal;
21 struct k_poll_event stepper_event;
22
drv8424_api_print_event_callback(const struct device * dev,enum stepper_event event,void * dummy)23 static void drv8424_api_print_event_callback(const struct device *dev, enum stepper_event event,
24 void *dummy)
25 {
26 switch (event) {
27 case STEPPER_EVENT_STEPS_COMPLETED:
28 k_poll_signal_raise(&stepper_signal, STEPPER_EVENT_STEPS_COMPLETED);
29 break;
30 case STEPPER_EVENT_LEFT_END_STOP_DETECTED:
31 k_poll_signal_raise(&stepper_signal, STEPPER_EVENT_LEFT_END_STOP_DETECTED);
32 break;
33 case STEPPER_EVENT_RIGHT_END_STOP_DETECTED:
34 k_poll_signal_raise(&stepper_signal, STEPPER_EVENT_RIGHT_END_STOP_DETECTED);
35 break;
36 case STEPPER_EVENT_STALL_DETECTED:
37 k_poll_signal_raise(&stepper_signal, STEPPER_EVENT_STALL_DETECTED);
38 break;
39 default:
40 break;
41 }
42 }
43
drv8424_api_setup(void)44 static void *drv8424_api_setup(void)
45 {
46 static struct drv8424_api_fixture fixture = {
47 .dev = DEVICE_DT_GET(DT_NODELABEL(drv8424)),
48 .callback = drv8424_api_print_event_callback,
49 };
50
51 k_poll_signal_init(&stepper_signal);
52 k_poll_event_init(&stepper_event, K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY,
53 &stepper_signal);
54
55 zassert_not_null(fixture.dev);
56 return &fixture;
57 }
58
drv8424_api_before(void * f)59 static void drv8424_api_before(void *f)
60 {
61 struct drv8424_api_fixture *fixture = f;
62 (void)stepper_set_reference_position(fixture->dev, 0);
63 (void)stepper_set_micro_step_res(fixture->dev, 1);
64 k_poll_signal_reset(&stepper_signal);
65 }
66
drv8424_api_after(void * f)67 static void drv8424_api_after(void *f)
68 {
69 struct drv8424_api_fixture *fixture = f;
70 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE, 0);
71 }
72
ZTEST_F(drv8424_api,test_micro_step_res_set)73 ZTEST_F(drv8424_api, test_micro_step_res_set)
74 {
75 (void)stepper_set_micro_step_res(fixture->dev, 4);
76 enum stepper_micro_step_resolution res;
77 (void)stepper_get_micro_step_res(fixture->dev, &res);
78 zassert_equal(res, 4, "Micro step resolution not set correctly, should be %d but is %d", 4,
79 res);
80 }
81
ZTEST_F(drv8424_api,test_micro_step_res_set_incorrect_value_detection)82 ZTEST_F(drv8424_api, test_micro_step_res_set_incorrect_value_detection)
83 {
84 int ret = 0;
85
86 ret = stepper_set_micro_step_res(fixture->dev, 3);
87 zassert_equal(ret, -EINVAL, "Command should fail with error %d but returned %d", -EINVAL,
88 ret);
89 }
90
ZTEST_F(drv8424_api,test_actual_position_set)91 ZTEST_F(drv8424_api, test_actual_position_set)
92 {
93 int32_t pos = 100u;
94 (void)stepper_set_reference_position(fixture->dev, pos);
95 (void)stepper_get_actual_position(fixture->dev, &pos);
96 zassert_equal(pos, 100u, "Actual position should be %u but is %u", 100u, pos);
97 }
98
ZTEST_F(drv8424_api,test_is_not_moving_when_disabled)99 ZTEST_F(drv8424_api, test_is_not_moving_when_disabled)
100 {
101 int32_t steps = 100;
102 bool moving = true;
103
104 (void)stepper_enable(fixture->dev, true);
105 (void)stepper_set_max_velocity(fixture->dev, 50u);
106 (void)stepper_move_by(fixture->dev, steps);
107 (void)stepper_enable(fixture->dev, false);
108 (void)stepper_is_moving(fixture->dev, &moving);
109 zassert_false(moving, "Driver should not be in state is_moving after being disabled");
110 }
111
ZTEST_F(drv8424_api,test_position_not_updating_when_disabled)112 ZTEST_F(drv8424_api, test_position_not_updating_when_disabled)
113 {
114 int32_t steps = 1000;
115 int32_t position_1 = 0;
116 int32_t position_2 = 0;
117
118 (void)stepper_enable(fixture->dev, true);
119 (void)stepper_set_max_velocity(fixture->dev, 50u);
120 (void)stepper_move_by(fixture->dev, steps);
121 (void)stepper_enable(fixture->dev, false);
122 (void)stepper_get_actual_position(fixture->dev, &position_1);
123 k_msleep(100);
124 (void)stepper_get_actual_position(fixture->dev, &position_2);
125 zassert_equal(position_2, position_1,
126 "Actual position should not have changed from %d but is %d", position_1,
127 position_2);
128 }
129
ZTEST_F(drv8424_api,test_is_not_moving_when_reenabled_after_movement)130 ZTEST_F(drv8424_api, test_is_not_moving_when_reenabled_after_movement)
131 {
132 int32_t steps = 1000;
133 bool moving = true;
134
135 (void)stepper_enable(fixture->dev, true);
136 (void)stepper_set_max_velocity(fixture->dev, 50u);
137 (void)stepper_move_by(fixture->dev, steps);
138 (void)stepper_enable(fixture->dev, false);
139 (void)k_msleep(100);
140 (void)stepper_enable(fixture->dev, true);
141 (void)k_msleep(100);
142 (void)stepper_is_moving(fixture->dev, &moving);
143 zassert_false(moving, "Driver should not be in state is_moving after being reenabled");
144 }
ZTEST_F(drv8424_api,test_position_not_updating_when_reenabled_after_movement)145 ZTEST_F(drv8424_api, test_position_not_updating_when_reenabled_after_movement)
146 {
147 int32_t steps = 1000;
148 int32_t position_1 = 0;
149 int32_t position_2 = 0;
150
151 (void)stepper_enable(fixture->dev, true);
152 (void)stepper_set_max_velocity(fixture->dev, 50u);
153 (void)stepper_move_by(fixture->dev, steps);
154 (void)stepper_enable(fixture->dev, false);
155 (void)stepper_get_actual_position(fixture->dev, &position_1);
156 (void)k_msleep(100);
157 (void)stepper_enable(fixture->dev, true);
158 (void)k_msleep(100);
159 (void)stepper_get_actual_position(fixture->dev, &position_2);
160 zassert_equal(position_2, position_1,
161 "Actual position should not have changed from %d but is %d", position_1,
162 position_2);
163 }
164
ZTEST_F(drv8424_api,test_move_to_positive_direction_movement)165 ZTEST_F(drv8424_api, test_move_to_positive_direction_movement)
166 {
167 int32_t pos = 50;
168
169 (void)stepper_enable(fixture->dev, true);
170 (void)stepper_set_max_velocity(fixture->dev, 50u);
171 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
172 (void)stepper_move_to(fixture->dev, pos);
173 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
174 unsigned int signaled;
175 int result;
176
177 k_poll_signal_check(&stepper_signal, &signaled, &result);
178 zassert_equal(signaled, 1, "No event detected");
179 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
180 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
181 (void)stepper_get_actual_position(fixture->dev, &pos);
182 zassert_equal(pos, 50u, "Target position should be %d but is %d", 50u, pos);
183 }
184
ZTEST_F(drv8424_api,test_move_to_negative_direction_movement)185 ZTEST_F(drv8424_api, test_move_to_negative_direction_movement)
186 {
187 int32_t pos = -50;
188
189 (void)stepper_enable(fixture->dev, true);
190 (void)stepper_set_max_velocity(fixture->dev, 50u);
191 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
192 (void)stepper_move_to(fixture->dev, pos);
193 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
194 unsigned int signaled;
195 int result;
196
197 k_poll_signal_check(&stepper_signal, &signaled, &result);
198 zassert_equal(signaled, 1, "No event detected");
199 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
200 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
201 (void)stepper_get_actual_position(fixture->dev, &pos);
202 zassert_equal(pos, -50, "Target position should be %d but is %d", -50, pos);
203 }
204
ZTEST_F(drv8424_api,test_move_to_identical_current_and_target_position)205 ZTEST_F(drv8424_api, test_move_to_identical_current_and_target_position)
206 {
207 int32_t pos = 0;
208
209 (void)stepper_enable(fixture->dev, true);
210 (void)stepper_set_max_velocity(fixture->dev, 50u);
211 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
212 (void)stepper_move_to(fixture->dev, pos);
213 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
214 unsigned int signaled;
215 int result;
216
217 k_poll_signal_check(&stepper_signal, &signaled, &result);
218 zassert_equal(signaled, 1, "No event detected");
219 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
220 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
221 (void)stepper_get_actual_position(fixture->dev, &pos);
222 zassert_equal(pos, 0, "Target position should not have changed from %d but is %d", 0, pos);
223 }
224
ZTEST_F(drv8424_api,test_move_to_zero_velocity)225 ZTEST_F(drv8424_api, test_move_to_zero_velocity)
226 {
227 int32_t pos = 100;
228 int32_t ret = 0;
229
230 (void)stepper_enable(fixture->dev, true);
231 (void)stepper_set_max_velocity(fixture->dev, 0u);
232 ret = stepper_move_to(fixture->dev, pos);
233
234 zassert_not_equal(ret, 0, "Command should fail with an error code, but returned 0");
235 k_msleep(100);
236 (void)stepper_get_actual_position(fixture->dev, &pos);
237 zassert_equal(pos, 0, "Target position should not have changed from %d but is %d", 0, pos);
238 }
239
ZTEST_F(drv8424_api,test_move_to_is_moving_true_while_moving)240 ZTEST_F(drv8424_api, test_move_to_is_moving_true_while_moving)
241 {
242 int32_t pos = 50;
243 bool moving = false;
244
245 (void)stepper_enable(fixture->dev, true);
246 (void)stepper_set_max_velocity(fixture->dev, 50u);
247 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
248 (void)stepper_move_to(fixture->dev, pos);
249 (void)stepper_is_moving(fixture->dev, &moving);
250 zassert_true(moving, "Driver should be in state is_moving while moving");
251 }
252
ZTEST_F(drv8424_api,test_move_to_is_moving_false_when_completed)253 ZTEST_F(drv8424_api, test_move_to_is_moving_false_when_completed)
254 {
255 int32_t pos = 50;
256 bool moving = false;
257
258 (void)stepper_enable(fixture->dev, true);
259 (void)stepper_set_max_velocity(fixture->dev, 50u);
260 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
261 (void)stepper_move_to(fixture->dev, pos);
262 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
263 unsigned int signaled;
264 int result;
265
266 k_poll_signal_check(&stepper_signal, &signaled, &result);
267 zassert_equal(signaled, 1, "No event detected");
268 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
269 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
270 (void)stepper_is_moving(fixture->dev, &moving);
271 zassert_false(moving, "Driver should not be in state is_moving after finishing");
272 }
273
ZTEST_F(drv8424_api,test_move_to_no_movement_when_disabled)274 ZTEST_F(drv8424_api, test_move_to_no_movement_when_disabled)
275 {
276 int32_t pos = 50;
277 int32_t curr_pos = 50;
278 int32_t ret = 0;
279
280 (void)stepper_set_max_velocity(fixture->dev, 50u);
281 (void)stepper_enable(fixture->dev, false);
282
283 ret = stepper_move_to(fixture->dev, pos);
284 zassert_equal(ret, -ECANCELED, "Move_to should fail with error code %d but returned %d",
285 -ECANCELED, ret);
286 (void)stepper_get_actual_position(fixture->dev, &curr_pos);
287 zassert_equal(curr_pos, 0, "Current position should not have changed from %d but is %d", 0,
288 curr_pos);
289 }
290
ZTEST_F(drv8424_api,test_move_by_positive_step_count)291 ZTEST_F(drv8424_api, test_move_by_positive_step_count)
292 {
293 int32_t steps = 50;
294
295 (void)stepper_enable(fixture->dev, true);
296 (void)stepper_set_max_velocity(fixture->dev, 50u);
297 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
298 (void)stepper_move_by(fixture->dev, steps);
299 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
300 unsigned int signaled;
301 int result;
302
303 k_poll_signal_check(&stepper_signal, &signaled, &result);
304 zassert_equal(signaled, 1, "No event detected");
305 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
306 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
307 (void)stepper_get_actual_position(fixture->dev, &steps);
308 zassert_equal(steps, 50u, "Target position should be %d but is %d", 50u, steps);
309 }
310
ZTEST_F(drv8424_api,test_move_by_negative_step_count)311 ZTEST_F(drv8424_api, test_move_by_negative_step_count)
312 {
313 int32_t steps = -50;
314
315 (void)stepper_enable(fixture->dev, true);
316 (void)stepper_set_max_velocity(fixture->dev, 50u);
317 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
318 (void)stepper_move_by(fixture->dev, steps);
319 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
320 unsigned int signaled;
321 int result;
322
323 k_poll_signal_check(&stepper_signal, &signaled, &result);
324 zassert_equal(signaled, 1, "No event detected");
325 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
326 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
327 (void)stepper_get_actual_position(fixture->dev, &steps);
328 zassert_equal(steps, -50, "Target position should be %d but is %d", -50, steps);
329 }
330
ZTEST_F(drv8424_api,test_move_by_zero_steps_no_movement)331 ZTEST_F(drv8424_api, test_move_by_zero_steps_no_movement)
332 {
333 int32_t steps = 0;
334
335 (void)stepper_enable(fixture->dev, true);
336 (void)stepper_set_max_velocity(fixture->dev, 50u);
337 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
338 (void)stepper_move_by(fixture->dev, steps);
339 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
340 unsigned int signaled;
341 int result;
342
343 k_poll_signal_check(&stepper_signal, &signaled, &result);
344 zassert_equal(signaled, 1, "No event detected");
345 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
346 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
347 (void)stepper_get_actual_position(fixture->dev, &steps);
348 zassert_equal(steps, 0, "Target position should be %d but is %d", 0, steps);
349 }
350
ZTEST_F(drv8424_api,test_move_by_zero_velocity)351 ZTEST_F(drv8424_api, test_move_by_zero_velocity)
352 {
353 int32_t steps = 100;
354 int32_t ret = 0;
355 int32_t pos = 100;
356
357 (void)stepper_enable(fixture->dev, true);
358 (void)stepper_set_max_velocity(fixture->dev, 0u);
359 ret = stepper_move_by(fixture->dev, steps);
360
361 zassert_not_equal(ret, 0, "Command should fail with an error code, but returned 0");
362 k_msleep(100);
363 (void)stepper_get_actual_position(fixture->dev, &pos);
364 zassert_equal(pos, 0, "Target position should not have changed from %d but is %d", 0, pos);
365 }
366
ZTEST_F(drv8424_api,test_move_by_is_moving_true_while_moving)367 ZTEST_F(drv8424_api, test_move_by_is_moving_true_while_moving)
368 {
369 int32_t steps = 50;
370 bool moving = false;
371
372 (void)stepper_enable(fixture->dev, true);
373 (void)stepper_set_max_velocity(fixture->dev, 50u);
374 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
375 (void)stepper_move_by(fixture->dev, steps);
376 (void)stepper_is_moving(fixture->dev, &moving);
377 zassert_true(moving, "Driver should be in state is_moving");
378 }
379
ZTEST_F(drv8424_api,test_move_by_is_moving_false_when_completed)380 ZTEST_F(drv8424_api, test_move_by_is_moving_false_when_completed)
381 {
382 int32_t steps = 50;
383 bool moving = true;
384
385 (void)stepper_enable(fixture->dev, true);
386 (void)stepper_set_max_velocity(fixture->dev, 50u);
387 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
388 (void)stepper_move_by(fixture->dev, steps);
389 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
390 unsigned int signaled;
391 int result;
392
393 k_poll_signal_check(&stepper_signal, &signaled, &result);
394 zassert_equal(signaled, 1, "No event detected");
395 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
396 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
397 (void)stepper_is_moving(fixture->dev, &moving);
398 zassert_false(moving, "Driver should not be in state is_moving after completion");
399 }
400
ZTEST_F(drv8424_api,test_move_by_no_movement_when_disabled)401 ZTEST_F(drv8424_api, test_move_by_no_movement_when_disabled)
402 {
403 int32_t steps = 100;
404 int32_t curr_pos = 100;
405 int32_t ret = 0;
406
407 (void)stepper_set_max_velocity(fixture->dev, 50u);
408 (void)stepper_enable(fixture->dev, false);
409
410 ret = stepper_move_by(fixture->dev, steps);
411 zassert_equal(ret, -ECANCELED, "Move_by should fail with error code %d but returned %d",
412 -ECANCELED, ret);
413 (void)stepper_get_actual_position(fixture->dev, &curr_pos);
414 zassert_equal(curr_pos, 0, "Current position should not have changed from %d but is %d", 0,
415 curr_pos);
416 }
417
ZTEST_F(drv8424_api,test_run_positive_direction_correct_position)418 ZTEST_F(drv8424_api, test_run_positive_direction_correct_position)
419 {
420 int32_t velocity = 50;
421 int32_t steps = 0;
422
423 (void)stepper_enable(fixture->dev, true);
424 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE, velocity);
425 k_busy_wait(110000);
426
427 (void)stepper_get_actual_position(fixture->dev, &steps);
428 zassert_true(IN_RANGE(steps, 4, 6), "Current position should be between 4 and 6 but is %d",
429 steps);
430 }
431
ZTEST_F(drv8424_api,test_run_negative_direction_correct_position)432 ZTEST_F(drv8424_api, test_run_negative_direction_correct_position)
433 {
434 int32_t velocity = 50;
435 int32_t steps = 0;
436
437 (void)stepper_enable(fixture->dev, true);
438 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_NEGATIVE, velocity);
439 k_busy_wait(110000);
440
441 (void)stepper_get_actual_position(fixture->dev, &steps);
442 zassert_true(IN_RANGE(steps, -6, 4),
443 "Current position should be between -6 and -4 but is %d", steps);
444 }
445
ZTEST_F(drv8424_api,test_run_zero_velocity_correct_position)446 ZTEST_F(drv8424_api, test_run_zero_velocity_correct_position)
447 {
448 int32_t velocity = 0;
449 int32_t steps = 0;
450
451 (void)stepper_enable(fixture->dev, true);
452 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE, velocity);
453 k_msleep(100);
454
455 zassert_equal(steps, 0, "Current position should not have changed from %d but is %d", 0,
456 steps);
457 }
458
ZTEST_F(drv8424_api,test_run_is_moving_true_when_velocity_greater_zero)459 ZTEST_F(drv8424_api, test_run_is_moving_true_when_velocity_greater_zero)
460 {
461 int32_t velocity = 50;
462 bool moving = false;
463
464 (void)stepper_enable(fixture->dev, true);
465 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE, velocity);
466 (void)stepper_is_moving(fixture->dev, &moving);
467 zassert_true(moving, "Driver should be in state is_moving");
468 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE, 0);
469 }
470
ZTEST_F(drv8424_api,test_run_is_moving_false_when_velocity_zero)471 ZTEST_F(drv8424_api, test_run_is_moving_false_when_velocity_zero)
472 {
473 int32_t velocity = 50;
474 bool moving = true;
475
476 (void)stepper_enable(fixture->dev, true);
477 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE, velocity);
478 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE, 0);
479 (void)stepper_is_moving(fixture->dev, &moving);
480 zassert_false(moving, "Driver should not be in state is_moving when velocity is 0");
481 }
482
ZTEST_F(drv8424_api,test_run_no_movement_when_disabled)483 ZTEST_F(drv8424_api, test_run_no_movement_when_disabled)
484 {
485 int32_t velocity = 50;
486 int32_t steps = 50;
487 int32_t ret = 0;
488
489 (void)stepper_enable(fixture->dev, false);
490
491 ret = stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE, velocity);
492 zassert_equal(ret, -ECANCELED, "Run should fail with error code %d but returned %d",
493 -ECANCELED, ret);
494 (void)stepper_get_actual_position(fixture->dev, &steps);
495 zassert_equal(steps, 0, "Current position should not have changed from %d but is %d", 0,
496 steps);
497 }
498
499 ZTEST_SUITE(drv8424_api, NULL, drv8424_api_setup, drv8424_api_before, drv8424_api_after, NULL);
500