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