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 drv84xx_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 
drv84xx_api_print_event_callback(const struct device * dev,enum stepper_event event,void * dummy)23 static void drv84xx_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 
drv84xx_api_setup(void)44 static void *drv84xx_api_setup(void)
45 {
46 	static struct drv84xx_api_fixture fixture = {
47 		.dev = DEVICE_DT_GET(DT_ALIAS(stepper)),
48 		.callback = drv84xx_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 
drv84xx_api_before(void * f)59 static void drv84xx_api_before(void *f)
60 {
61 	struct drv84xx_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 
drv84xx_api_after(void * f)67 static void drv84xx_api_after(void *f)
68 {
69 	struct drv84xx_api_fixture *fixture = f;
70 	(void)stepper_disable(fixture->dev);
71 }
72 
ZTEST_F(drv84xx_api,test_micro_step_res_set)73 ZTEST_F(drv84xx_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(drv84xx_api,test_actual_position_set)82 ZTEST_F(drv84xx_api, test_actual_position_set)
83 {
84 	int32_t pos = 100u;
85 	(void)stepper_set_reference_position(fixture->dev, pos);
86 	(void)stepper_get_actual_position(fixture->dev, &pos);
87 	zassert_equal(pos, 100u, "Actual position should be %u but is %u", 100u, pos);
88 }
89 
ZTEST_F(drv84xx_api,test_move_to_positive_direction_movement)90 ZTEST_F(drv84xx_api, test_move_to_positive_direction_movement)
91 {
92 	int32_t pos = 50;
93 
94 	(void)stepper_enable(fixture->dev);
95 	(void)stepper_set_microstep_interval(fixture->dev, 20000000);
96 	(void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
97 	(void)stepper_move_to(fixture->dev, pos);
98 	(void)k_poll(&stepper_event, 1, K_SECONDS(5));
99 	unsigned int signaled;
100 	int result;
101 
102 	k_poll_signal_check(&stepper_signal, &signaled, &result);
103 	zassert_equal(signaled, 1, "No event detected");
104 	zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
105 		      "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
106 	(void)stepper_get_actual_position(fixture->dev, &pos);
107 	zassert_equal(pos, 50u, "Target position should be %d but is %d", 50u, pos);
108 }
109 
ZTEST_F(drv84xx_api,test_move_to_negative_direction_movement)110 ZTEST_F(drv84xx_api, test_move_to_negative_direction_movement)
111 {
112 	int32_t pos = -50;
113 
114 	(void)stepper_enable(fixture->dev);
115 	(void)stepper_set_microstep_interval(fixture->dev, 20000000);
116 	(void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
117 	(void)stepper_move_to(fixture->dev, pos);
118 	(void)k_poll(&stepper_event, 1, K_SECONDS(5));
119 	unsigned int signaled;
120 	int result;
121 
122 	k_poll_signal_check(&stepper_signal, &signaled, &result);
123 	zassert_equal(signaled, 1, "No event detected");
124 	zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
125 		      "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
126 	(void)stepper_get_actual_position(fixture->dev, &pos);
127 	zassert_equal(pos, -50, "Target position should be %d but is %d", -50, pos);
128 }
129 
ZTEST_F(drv84xx_api,test_move_to_identical_current_and_target_position)130 ZTEST_F(drv84xx_api, test_move_to_identical_current_and_target_position)
131 {
132 	int32_t pos = 0;
133 
134 	(void)stepper_enable(fixture->dev);
135 	(void)stepper_set_microstep_interval(fixture->dev, 20000000);
136 	(void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
137 	(void)stepper_move_to(fixture->dev, pos);
138 	(void)k_poll(&stepper_event, 1, K_SECONDS(5));
139 	unsigned int signaled;
140 	int result;
141 
142 	k_poll_signal_check(&stepper_signal, &signaled, &result);
143 	zassert_equal(signaled, 1, "No event detected");
144 	zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
145 		      "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
146 	(void)stepper_get_actual_position(fixture->dev, &pos);
147 	zassert_equal(pos, 0, "Target position should not have changed from %d but is %d", 0, pos);
148 }
149 
ZTEST_F(drv84xx_api,test_move_to_is_moving_true_while_moving)150 ZTEST_F(drv84xx_api, test_move_to_is_moving_true_while_moving)
151 {
152 	int32_t pos = 50;
153 	bool moving = false;
154 
155 	(void)stepper_enable(fixture->dev);
156 	(void)stepper_set_microstep_interval(fixture->dev, 20000000);
157 	(void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
158 	(void)stepper_move_to(fixture->dev, pos);
159 	(void)stepper_is_moving(fixture->dev, &moving);
160 	zassert_true(moving, "Driver should be in state is_moving while moving");
161 }
162 
ZTEST_F(drv84xx_api,test_move_to_is_moving_false_when_completed)163 ZTEST_F(drv84xx_api, test_move_to_is_moving_false_when_completed)
164 {
165 	int32_t pos = 50;
166 	bool moving = false;
167 
168 	(void)stepper_enable(fixture->dev);
169 	(void)stepper_set_microstep_interval(fixture->dev, 20000000);
170 	(void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
171 	(void)stepper_move_to(fixture->dev, pos);
172 	(void)k_poll(&stepper_event, 1, K_SECONDS(5));
173 	unsigned int signaled;
174 	int result;
175 
176 	k_poll_signal_check(&stepper_signal, &signaled, &result);
177 	zassert_equal(signaled, 1, "No event detected");
178 	zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
179 		      "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
180 	(void)stepper_is_moving(fixture->dev, &moving);
181 	zassert_false(moving, "Driver should not be in state is_moving after finishing");
182 }
183 
ZTEST_F(drv84xx_api,test_move_by_zero_steps_no_movement)184 ZTEST_F(drv84xx_api, test_move_by_zero_steps_no_movement)
185 {
186 	int32_t steps = 0;
187 
188 	(void)stepper_enable(fixture->dev);
189 	(void)stepper_set_microstep_interval(fixture->dev, 20000000);
190 	(void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
191 	(void)stepper_move_by(fixture->dev, steps);
192 	(void)k_poll(&stepper_event, 1, K_SECONDS(5));
193 	unsigned int signaled;
194 	int result;
195 
196 	k_poll_signal_check(&stepper_signal, &signaled, &result);
197 	zassert_equal(signaled, 1, "No event detected");
198 	zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
199 		      "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
200 	(void)stepper_get_actual_position(fixture->dev, &steps);
201 	zassert_equal(steps, 0, "Target position should be %d but is %d", 0, steps);
202 }
203 
ZTEST_F(drv84xx_api,test_move_by_is_moving_true_while_moving)204 ZTEST_F(drv84xx_api, test_move_by_is_moving_true_while_moving)
205 {
206 	int32_t steps = 50;
207 	bool moving = false;
208 
209 	(void)stepper_enable(fixture->dev);
210 	(void)stepper_set_microstep_interval(fixture->dev, 20000000);
211 	(void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
212 	(void)stepper_move_by(fixture->dev, steps);
213 	(void)stepper_is_moving(fixture->dev, &moving);
214 	zassert_true(moving, "Driver should be in state is_moving");
215 }
216 
ZTEST_F(drv84xx_api,test_move_by_is_moving_false_when_completed)217 ZTEST_F(drv84xx_api, test_move_by_is_moving_false_when_completed)
218 {
219 	int32_t steps = 50;
220 	bool moving = true;
221 
222 	(void)stepper_enable(fixture->dev);
223 	(void)stepper_set_microstep_interval(fixture->dev, 20000000);
224 	(void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
225 	(void)stepper_move_by(fixture->dev, steps);
226 	(void)k_poll(&stepper_event, 1, K_SECONDS(5));
227 	unsigned int signaled;
228 	int result;
229 
230 	k_poll_signal_check(&stepper_signal, &signaled, &result);
231 	zassert_equal(signaled, 1, "No event detected");
232 	zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
233 		      "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
234 	(void)stepper_is_moving(fixture->dev, &moving);
235 	zassert_false(moving, "Driver should not be in state is_moving after completion");
236 }
237 
ZTEST_F(drv84xx_api,test_run_positive_direction_correct_position)238 ZTEST_F(drv84xx_api, test_run_positive_direction_correct_position)
239 {
240 	uint64_t step_interval = 20000000;
241 	int32_t steps = 0;
242 
243 	(void)stepper_enable(fixture->dev);
244 	(void)stepper_set_microstep_interval(fixture->dev, step_interval);
245 	(void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE);
246 	k_busy_wait(110000);
247 
248 	(void)stepper_get_actual_position(fixture->dev, &steps);
249 	zassert_true(IN_RANGE(steps, 4, 6), "Current position should be between 4 and 6 but is %d",
250 		     steps);
251 }
252 
ZTEST_F(drv84xx_api,test_run_negative_direction_correct_position)253 ZTEST_F(drv84xx_api, test_run_negative_direction_correct_position)
254 {
255 	uint64_t step_interval = 20000000;
256 	int32_t steps = 0;
257 
258 	(void)stepper_enable(fixture->dev);
259 	(void)stepper_set_microstep_interval(fixture->dev, step_interval);
260 	(void)stepper_run(fixture->dev, STEPPER_DIRECTION_NEGATIVE);
261 	k_busy_wait(110000);
262 
263 	(void)stepper_get_actual_position(fixture->dev, &steps);
264 	zassert_true(IN_RANGE(steps, -6, 4),
265 		     "Current position should be between -6 and -4 but is %d", steps);
266 }
267 
ZTEST_F(drv84xx_api,test_run_zero_step_interval_correct_position)268 ZTEST_F(drv84xx_api, test_run_zero_step_interval_correct_position)
269 {
270 	uint64_t step_interval = 0;
271 	int32_t steps = 0;
272 
273 	(void)stepper_enable(fixture->dev);
274 	(void)stepper_set_microstep_interval(fixture->dev, step_interval);
275 	(void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE);
276 	k_msleep(100);
277 
278 	zassert_equal(steps, 0, "Current position should not have changed from %d but is %d", 0,
279 		      steps);
280 }
281 
ZTEST_F(drv84xx_api,test_run_is_moving_true_when_step_interval_greater_zero)282 ZTEST_F(drv84xx_api, test_run_is_moving_true_when_step_interval_greater_zero)
283 {
284 	uint64_t step_interval = 20000000;
285 	bool moving = false;
286 
287 	(void)stepper_enable(fixture->dev);
288 	(void)stepper_set_microstep_interval(fixture->dev, step_interval);
289 	(void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE);
290 	(void)stepper_is_moving(fixture->dev, &moving);
291 	zassert_true(moving, "Driver should be in state is_moving");
292 	(void)stepper_disable(fixture->dev);
293 }
294 
295 ZTEST_SUITE(drv84xx_api, NULL, drv84xx_api_setup, drv84xx_api_before, drv84xx_api_after, NULL);
296