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