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