1 /*
2  * Copyright 2021 The Chromium OS Authors
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/smf.h>
9 
10 /*
11  * Hierarchical Test Transition:
12  *
13  *	PARENT_AB_ENTRY --> A_ENTRY --> A_RUN --> PARENT_AB_RUN ---|
14  *	                                                           |
15  *	|----------------------------------------------------------|
16  *	|
17  *	|--> B_ENTRY --> B_RUN --> B_EXIT --> PARENT_AB_EXIT ------|
18  *	                                                           |
19  *	|----------------------------------------------------------|
20  *	|
21  *	|--> PARENT_C_ENTRY --> C_ENTRY --> C_RUN --> C_EXIT ------|
22  *	                                                           |
23  *      |----------------------------------------------------------|
24  *      |
25  *	|--> PARENT_C_EXIT
26  */
27 
28 /*
29  * Hierarchical 10 Ancestor State Test Transition:
30  *
31  *	P10_ENTRY --> P09_ENTRY --> ... -- P02_ENTRY --> P01_ENTRY --|
32  *                                                                   |
33  *      |------------------------------------------------------------|
34  *      |
35  *      |--> A_ENTRY --> A_RUN --> P01_RUN --> P02_RUN --> P03_RUN --|
36  *                                                                   |
37  *      |------------------------------------------------------------|
38  *      |
39  *      |--> ... --> P09_RUN --> P10_RUN --> B_ENTRY -->
40  */
41 
42 #define TEST_OBJECT(o) ((struct test_object *)o)
43 
44 #define SMF_RUN 3
45 
46 #define PARENT_AB_ENTRY_BIT BIT(0)
47 #define STATE_A_ENTRY_BIT   BIT(1)
48 #define STATE_A_RUN_BIT     BIT(2)
49 #define PARENT_AB_RUN_BIT   BIT(3)
50 #define STATE_A_EXIT_BIT    BIT(4)
51 #define STATE_B_ENTRY_BIT   BIT(5)
52 #define STATE_B_RUN_BIT     BIT(6)
53 #define STATE_B_EXIT_BIT    BIT(7)
54 #define PARENT_AB_EXIT_BIT  BIT(8)
55 #define PARENT_C_ENTRY_BIT  BIT(9)
56 #define STATE_C_ENTRY_BIT   BIT(10)
57 #define STATE_C_RUN_BIT     BIT(11)
58 #define STATE_C_EXIT_BIT    BIT(12)
59 #define PARENT_C_EXIT_BIT   BIT(13)
60 
61 #define TEST_PARENT_ENTRY_VALUE_NUM 0
62 #define TEST_PARENT_RUN_VALUE_NUM   3
63 #define TEST_PARENT_EXIT_VALUE_NUM  8
64 #define TEST_ENTRY_VALUE_NUM        1
65 #define TEST_RUN_VALUE_NUM          6
66 #define TEST_EXIT_VALUE_NUM         12
67 #define TEST_VALUE_NUM              14
68 static uint32_t test_value[] = {
69 	0x00,   /* PARENT_AB_ENTRY */
70 	0x01,   /* STATE_A_ENTRY */
71 	0x03,   /* STATE_A_RUN */
72 	0x07,   /* PARENT_AB_RUN */
73 	0x0f,   /* STATE_A_EXIT */
74 	0x1f,   /* STATE_B_ENTRY */
75 	0x3f,   /* STATE_B_RUN */
76 	0x7f,   /* STATE_B_EXIT */
77 	0xff,   /* STATE_AB_EXIT */
78 	0x1ff,  /* PARENT_C_ENTRY */
79 	0x3ff,  /* STATE_C_ENTRY */
80 	0x7ff,  /* STATE_C_RUN */
81 	0xfff,  /* STATE_C_EXIT */
82 	0x1fff, /* PARENT_C_EXIT */
83 	0x3fff, /* FINAL VALUE */
84 };
85 
86 /* Forward declaration of test_states */
87 static const struct smf_state test_states[];
88 
89 /* List of all TypeC-level states */
90 enum test_state {
91 	PARENT_AB,
92 	PARENT_C,
93 	STATE_A,
94 	STATE_B,
95 	STATE_C,
96 	STATE_D
97 };
98 
99 enum terminate_action {
100 	NONE,
101 	PARENT_ENTRY,
102 	PARENT_RUN,
103 	PARENT_EXIT,
104 	ENTRY,
105 	RUN,
106 	EXIT
107 };
108 
109 static struct test_object {
110 	struct smf_ctx ctx;
111 	uint32_t transition_bits;
112 	uint32_t tv_idx;
113 	enum terminate_action terminate;
114 } test_obj;
115 
parent_ab_entry(void * obj)116 static void parent_ab_entry(void *obj)
117 {
118 	struct test_object *o = TEST_OBJECT(obj);
119 
120 	o->tv_idx = 0;
121 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent AB entry failed");
122 
123 	if (o->terminate == PARENT_ENTRY) {
124 		smf_set_terminate(obj, -1);
125 		return;
126 	}
127 
128 	o->transition_bits |= PARENT_AB_ENTRY_BIT;
129 }
130 
parent_ab_run(void * obj)131 static enum smf_state_result parent_ab_run(void *obj)
132 {
133 	struct test_object *o = TEST_OBJECT(obj);
134 
135 	o->tv_idx++;
136 
137 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent AB run failed");
138 
139 	if (o->terminate == PARENT_RUN) {
140 		smf_set_terminate(obj, -1);
141 		return SMF_EVENT_PROPAGATE;
142 	}
143 
144 	o->transition_bits |= PARENT_AB_RUN_BIT;
145 
146 	smf_set_state(SMF_CTX(obj), &test_states[STATE_B]);
147 	return SMF_EVENT_PROPAGATE;
148 }
149 
parent_ab_exit(void * obj)150 static void parent_ab_exit(void *obj)
151 {
152 	struct test_object *o = TEST_OBJECT(obj);
153 
154 	o->tv_idx++;
155 
156 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent AB exit failed");
157 
158 	if (o->terminate == PARENT_EXIT) {
159 		smf_set_terminate(obj, -1);
160 		return;
161 	}
162 
163 	o->transition_bits |= PARENT_AB_EXIT_BIT;
164 }
165 
parent_c_entry(void * obj)166 static void parent_c_entry(void *obj)
167 {
168 	struct test_object *o = TEST_OBJECT(obj);
169 
170 	o->tv_idx++;
171 
172 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent C entry failed");
173 	o->transition_bits |= PARENT_C_ENTRY_BIT;
174 }
175 
parent_c_run(void * obj)176 static enum smf_state_result parent_c_run(void *obj)
177 {
178 	/* This state should not be reached */
179 	zassert_true(0, "Test Parent C run failed");
180 	return SMF_EVENT_PROPAGATE;
181 }
182 
parent_c_exit(void * obj)183 static void parent_c_exit(void *obj)
184 {
185 	struct test_object *o = TEST_OBJECT(obj);
186 
187 	o->tv_idx++;
188 
189 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test Parent C exit failed");
190 	o->transition_bits |= PARENT_C_EXIT_BIT;
191 }
192 
state_a_entry(void * obj)193 static void state_a_entry(void *obj)
194 {
195 	struct test_object *o = TEST_OBJECT(obj);
196 
197 	o->tv_idx++;
198 
199 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A entry failed");
200 
201 	if (o->terminate == ENTRY) {
202 		smf_set_terminate(obj, -1);
203 		return;
204 	}
205 
206 	o->transition_bits |= STATE_A_ENTRY_BIT;
207 }
208 
state_a_run(void * obj)209 static enum smf_state_result state_a_run(void *obj)
210 {
211 	struct test_object *o = TEST_OBJECT(obj);
212 
213 	o->tv_idx++;
214 
215 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A run failed");
216 
217 	o->transition_bits |= STATE_A_RUN_BIT;
218 
219 	/* Return to parent run state */
220 	return SMF_EVENT_PROPAGATE;
221 }
222 
state_a_exit(void * obj)223 static void state_a_exit(void *obj)
224 {
225 	struct test_object *o = TEST_OBJECT(obj);
226 
227 	o->tv_idx++;
228 
229 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A exit failed");
230 	o->transition_bits |= STATE_A_EXIT_BIT;
231 }
232 
state_b_entry(void * obj)233 static void state_b_entry(void *obj)
234 {
235 	struct test_object *o = TEST_OBJECT(obj);
236 
237 	o->tv_idx++;
238 
239 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B entry failed");
240 	o->transition_bits |= STATE_B_ENTRY_BIT;
241 }
242 
state_b_run(void * obj)243 static enum smf_state_result state_b_run(void *obj)
244 {
245 	struct test_object *o = TEST_OBJECT(obj);
246 
247 	o->tv_idx++;
248 
249 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B run failed");
250 
251 	if (o->terminate == RUN) {
252 		smf_set_terminate(obj, -1);
253 		return SMF_EVENT_PROPAGATE;
254 	}
255 
256 	o->transition_bits |= STATE_B_RUN_BIT;
257 
258 	smf_set_state(SMF_CTX(obj), &test_states[STATE_C]);
259 	return SMF_EVENT_PROPAGATE;
260 }
261 
state_b_exit(void * obj)262 static void state_b_exit(void *obj)
263 {
264 	struct test_object *o = TEST_OBJECT(obj);
265 
266 	o->tv_idx++;
267 
268 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B exit failed");
269 	o->transition_bits |= STATE_B_EXIT_BIT;
270 }
271 
state_c_entry(void * obj)272 static void state_c_entry(void *obj)
273 {
274 	struct test_object *o = TEST_OBJECT(obj);
275 
276 	o->tv_idx++;
277 
278 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C entry failed");
279 	o->transition_bits |= STATE_C_ENTRY_BIT;
280 }
281 
state_c_run(void * obj)282 static enum smf_state_result state_c_run(void *obj)
283 {
284 	struct test_object *o = TEST_OBJECT(obj);
285 
286 	o->tv_idx++;
287 
288 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C run failed");
289 	o->transition_bits |= STATE_C_RUN_BIT;
290 
291 	smf_set_state(SMF_CTX(obj), &test_states[STATE_D]);
292 	return SMF_EVENT_PROPAGATE;
293 }
294 
state_c_exit(void * obj)295 static void state_c_exit(void *obj)
296 {
297 	struct test_object *o = TEST_OBJECT(obj);
298 
299 	o->tv_idx++;
300 
301 	zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C exit failed");
302 
303 	if (o->terminate == EXIT) {
304 		smf_set_terminate(obj, -1);
305 		return;
306 	}
307 
308 	o->transition_bits |= STATE_C_EXIT_BIT;
309 }
310 
state_d_entry(void * obj)311 static void state_d_entry(void *obj)
312 {
313 	struct test_object *o = TEST_OBJECT(obj);
314 
315 	o->tv_idx++;
316 }
317 
state_d_run(void * obj)318 static enum smf_state_result state_d_run(void *obj)
319 {
320 	/* Do nothing */
321 	return SMF_EVENT_PROPAGATE;
322 }
323 
state_d_exit(void * obj)324 static void state_d_exit(void *obj)
325 {
326 	/* Do nothing */
327 }
328 
329 static const struct smf_state test_states[] = {
330 	[PARENT_AB] = SMF_CREATE_STATE(parent_ab_entry, parent_ab_run, parent_ab_exit, NULL, NULL),
331 	[PARENT_C] = SMF_CREATE_STATE(parent_c_entry, parent_c_run, parent_c_exit, NULL, NULL),
332 	[STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit,
333 				     &test_states[PARENT_AB], NULL),
334 	[STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit,
335 				     &test_states[PARENT_AB], NULL),
336 	[STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit,
337 				     &test_states[PARENT_C], NULL),
338 	[STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit, NULL, NULL),
339 };
340 
ZTEST(smf_tests,test_smf_hierarchical)341 ZTEST(smf_tests, test_smf_hierarchical)
342 {
343 	/* A) Test state transitions */
344 
345 	test_obj.transition_bits = 0;
346 	test_obj.terminate = NONE;
347 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
348 
349 	for (int i = 0; i < SMF_RUN; i++) {
350 		if (smf_run_state((struct smf_ctx *)&test_obj) < 0) {
351 			break;
352 		}
353 	}
354 
355 	zassert_equal(TEST_VALUE_NUM, test_obj.tv_idx, "Incorrect test value index");
356 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
357 		      "Final state not reached");
358 
359 	/* B) Test termination in parent entry action */
360 
361 	test_obj.transition_bits = 0;
362 	test_obj.terminate = PARENT_ENTRY;
363 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
364 
365 	for (int i = 0; i < SMF_RUN; i++) {
366 		if (smf_run_state((struct smf_ctx *)&test_obj) < 0) {
367 			break;
368 		}
369 	}
370 
371 	zassert_equal(TEST_PARENT_ENTRY_VALUE_NUM, test_obj.tv_idx,
372 		      "Incorrect test value index for parent entry termination");
373 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
374 		      "Final parent entry termination state not reached");
375 
376 	/* C) Test termination in parent run action */
377 
378 	test_obj.transition_bits = 0;
379 	test_obj.terminate = PARENT_RUN;
380 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
381 
382 	for (int i = 0; i < SMF_RUN; i++) {
383 		if (smf_run_state((struct smf_ctx *)&test_obj) < 0) {
384 			break;
385 		}
386 	}
387 
388 	zassert_equal(TEST_PARENT_RUN_VALUE_NUM, test_obj.tv_idx,
389 		      "Incorrect test value index for parent run termination");
390 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
391 		      "Final parent run termination state not reached");
392 
393 	/* D) Test termination in parent exit action */
394 
395 	test_obj.transition_bits = 0;
396 	test_obj.terminate = PARENT_EXIT;
397 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
398 
399 	for (int i = 0; i < SMF_RUN; i++) {
400 		if (smf_run_state((struct smf_ctx *)&test_obj) < 0) {
401 			break;
402 		}
403 	}
404 
405 	zassert_equal(TEST_PARENT_EXIT_VALUE_NUM, test_obj.tv_idx,
406 		      "Incorrect test value index for parent exit termination");
407 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
408 		      "Final parent exit termination state not reached");
409 
410 	/* E) Test termination in child entry action */
411 
412 	test_obj.transition_bits = 0;
413 	test_obj.terminate = ENTRY;
414 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
415 
416 	for (int i = 0; i < SMF_RUN; i++) {
417 		if (smf_run_state((struct smf_ctx *)&test_obj) < 0) {
418 			break;
419 		}
420 	}
421 
422 	zassert_equal(TEST_ENTRY_VALUE_NUM, test_obj.tv_idx,
423 		      "Incorrect test value index for entry termination");
424 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
425 		      "Final entry termination state not reached");
426 
427 	/* F) Test termination in child run action */
428 
429 	test_obj.transition_bits = 0;
430 	test_obj.terminate = RUN;
431 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
432 
433 	for (int i = 0; i < SMF_RUN; i++) {
434 		if (smf_run_state((struct smf_ctx *)&test_obj) < 0) {
435 			break;
436 		}
437 	}
438 
439 	zassert_equal(TEST_RUN_VALUE_NUM, test_obj.tv_idx,
440 		      "Incorrect test value index for run termination");
441 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
442 		      "Final run termination state not reached");
443 
444 	/* G) Test termination in child exit action */
445 
446 	test_obj.transition_bits = 0;
447 	test_obj.terminate = EXIT;
448 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
449 
450 	for (int i = 0; i < SMF_RUN; i++) {
451 		if (smf_run_state((struct smf_ctx *)&test_obj) < 0) {
452 			break;
453 		}
454 	}
455 
456 	zassert_equal(TEST_EXIT_VALUE_NUM, test_obj.tv_idx,
457 		      "Incorrect test value index for exit termination");
458 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
459 		      "Final exit termination state not reached");
460 }
461