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 * Flat Test Transition:
12 *
13 * A_ENTRY --> A_RUN --> A_EXIT --> B_ENTRY --> B_RUN --|
14 * |
15 * |----------------------------------------------------|
16 * |
17 * |--> B_EXIT --> C_ENTRY --> C_RUN --> C_EXIT --> D_ENTRY
18 *
19 */
20
21 #define TEST_OBJECT(o) ((struct test_object *)o)
22
23 #define SMF_RUN 3
24
25 #define STATE_A_ENTRY_BIT BIT(0)
26 #define STATE_A_RUN_BIT BIT(1)
27 #define STATE_A_EXIT_BIT BIT(2)
28
29 #define STATE_B_ENTRY_BIT BIT(3)
30 #define STATE_B_RUN_BIT BIT(4)
31 #define STATE_B_EXIT_BIT BIT(5)
32
33 #define STATE_C_ENTRY_BIT BIT(6)
34 #define STATE_C_RUN_BIT BIT(7)
35 #define STATE_C_EXIT_BIT BIT(8)
36
37 #define TEST_ENTRY_VALUE_NUM 0
38 #define TEST_RUN_VALUE_NUM 4
39 #define TEST_EXIT_VALUE_NUM 8
40 #define TEST_VALUE_NUM 9
41
42 static uint32_t test_value[] = {
43 0x00, /* STATE_A_ENTRY */
44 0x01, /* STATE_A_RUN */
45 0x03, /* STATE_A_EXIT */
46 0x07, /* STATE_B_ENTRY */
47 0x0f, /* STATE_B_RUN */
48 0x1f, /* STATE_B_EXIT */
49 0x3f, /* STATE_C_ENTRY */
50 0x7f, /* STATE_C_RUN */
51 0xff, /* STATE_C_EXIT */
52 0x1ff, /* FINAL VALUE */
53 };
54
55 /* Forward declaration of test_states */
56 static const struct smf_state test_states[];
57
58 /* List of all TypeC-level states */
59 enum test_state {
60 STATE_A,
61 STATE_B,
62 STATE_C,
63 STATE_D
64 };
65
66 enum terminate_action {
67 NONE,
68 ENTRY,
69 RUN,
70 EXIT
71 };
72
73 static struct test_object {
74 struct smf_ctx ctx;
75 uint32_t transition_bits;
76 uint32_t tv_idx;
77 enum terminate_action terminate;
78 } test_obj;
79
state_a_entry(void * obj)80 static void state_a_entry(void *obj)
81 {
82 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_A],
83 "Fail to get the currently-executing state at entry. Expected: State A");
84 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_A],
85 "Fail to get the current leaf state at entry. Expected: State A");
86
87 struct test_object *o = TEST_OBJECT(obj);
88
89 o->tv_idx = 0;
90 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A entry failed");
91
92 if (o->terminate == ENTRY) {
93 smf_set_terminate(obj, -1);
94 return;
95 }
96
97 o->transition_bits |= STATE_A_ENTRY_BIT;
98 }
99
state_a_run(void * obj)100 static enum smf_state_result state_a_run(void *obj)
101 {
102 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_A],
103 "Fail to get the currently-executing state at run. Expected: State A");
104 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_A],
105 "Fail to get the current leaf state at run. Expected: State A");
106
107 struct test_object *o = TEST_OBJECT(obj);
108
109 o->tv_idx++;
110 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A run failed");
111
112 o->transition_bits |= STATE_A_RUN_BIT;
113
114 smf_set_state(SMF_CTX(obj), &test_states[STATE_B]);
115 return SMF_EVENT_HANDLED;
116 }
117
state_a_exit(void * obj)118 static void state_a_exit(void *obj)
119 {
120 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_A],
121 "Fail to get the currently-executing state at exit. Expected: State A");
122 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_A],
123 "Fail to get the current leaf state at exit. Expected: State A");
124
125 struct test_object *o = TEST_OBJECT(obj);
126
127 o->tv_idx++;
128 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State A exit failed");
129
130 o->transition_bits |= STATE_A_EXIT_BIT;
131 }
132
state_b_entry(void * obj)133 static void state_b_entry(void *obj)
134 {
135 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_B],
136 "Fail to get the currently-executing state at entry. Expected: State B");
137 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_B],
138 "Fail to get the current leaf state at entry. Expected: State B");
139
140 struct test_object *o = TEST_OBJECT(obj);
141
142 o->tv_idx++;
143 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B entry failed");
144
145 o->transition_bits |= STATE_B_ENTRY_BIT;
146 }
147
state_b_run(void * obj)148 static enum smf_state_result state_b_run(void *obj)
149 {
150 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_B],
151 "Fail to get the currently-executing state at run. Expected: State B");
152 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_B],
153 "Fail to get the current leaf state at run. Expected: State B");
154
155 struct test_object *o = TEST_OBJECT(obj);
156
157 o->tv_idx++;
158 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B run failed");
159
160 if (o->terminate == RUN) {
161 smf_set_terminate(obj, -1);
162 return SMF_EVENT_HANDLED;
163 }
164
165 o->transition_bits |= STATE_B_RUN_BIT;
166
167 smf_set_state(SMF_CTX(obj), &test_states[STATE_C]);
168 return SMF_EVENT_HANDLED;
169 }
170
state_b_exit(void * obj)171 static void state_b_exit(void *obj)
172 {
173 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_B],
174 "Fail to get the currently-executing state at exit. Expected: State B");
175 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_B],
176 "Fail to get the current leaf state at exit. Expected: State B");
177
178 struct test_object *o = TEST_OBJECT(obj);
179
180 o->tv_idx++;
181 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State B exit failed");
182 o->transition_bits |= STATE_B_EXIT_BIT;
183 }
184
state_c_entry(void * obj)185 static void state_c_entry(void *obj)
186 {
187 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_C],
188 "Fail to get the currently-executing state at entry. Expected: State C");
189 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_C],
190 "Fail to get the current leaf state at entry. Expected: State C");
191
192 struct test_object *o = TEST_OBJECT(obj);
193
194 o->tv_idx++;
195 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C entry failed");
196 o->transition_bits |= STATE_C_ENTRY_BIT;
197 }
198
state_c_run(void * obj)199 static enum smf_state_result state_c_run(void *obj)
200 {
201 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_C],
202 "Fail to get the currently-executing state at run. Expected: State C");
203 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_C],
204 "Fail to get the current leaf state at run. Expected: State C");
205
206 struct test_object *o = TEST_OBJECT(obj);
207
208 o->tv_idx++;
209 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C run failed");
210 o->transition_bits |= STATE_C_RUN_BIT;
211
212 smf_set_state(SMF_CTX(obj), &test_states[STATE_D]);
213 return SMF_EVENT_HANDLED;
214 }
215
state_c_exit(void * obj)216 static void state_c_exit(void *obj)
217 {
218 zassert_equal(smf_get_current_executing_state(SMF_CTX(obj)), &test_states[STATE_C],
219 "Fail to get the currently-executing state at exit. Expected: State C");
220 zassert_equal(smf_get_current_leaf_state(SMF_CTX(obj)), &test_states[STATE_C],
221 "Fail to get the current leaf state at exit. Expected: State C");
222
223 struct test_object *o = TEST_OBJECT(obj);
224
225 o->tv_idx++;
226 zassert_equal(o->transition_bits, test_value[o->tv_idx], "Test State C exit failed");
227
228 if (o->terminate == EXIT) {
229 smf_set_terminate(obj, -1);
230 return;
231 }
232
233 o->transition_bits |= STATE_C_EXIT_BIT;
234 }
235
state_d_entry(void * obj)236 static void state_d_entry(void *obj)
237 {
238 struct test_object *o = TEST_OBJECT(obj);
239
240 o->tv_idx++;
241 }
242
state_d_run(void * obj)243 static enum smf_state_result state_d_run(void *obj)
244 {
245 /* Do nothing */
246 return SMF_EVENT_HANDLED;
247 }
248
state_d_exit(void * obj)249 static void state_d_exit(void *obj)
250 {
251 /* Do nothing */
252 }
253
254 static const struct smf_state test_states[] = {
255 [STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit, NULL, NULL),
256 [STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit, NULL, NULL),
257 [STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit, NULL, NULL),
258 [STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit, NULL, NULL),
259 };
260
ZTEST(smf_tests,test_smf_flat)261 ZTEST(smf_tests, test_smf_flat)
262 {
263 /* A) Test transitions */
264
265 test_obj.transition_bits = 0;
266 test_obj.terminate = NONE;
267 smf_set_initial(SMF_CTX(&test_obj), &test_states[STATE_A]);
268
269 for (int i = 0; i < SMF_RUN; i++) {
270 if (smf_run_state(SMF_CTX(&test_obj))) {
271 break;
272 }
273 }
274
275 zassert_equal(TEST_VALUE_NUM, test_obj.tv_idx, "Incorrect test value index");
276 zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
277 "Final state not reached");
278
279 /* B) Test termination in entry action */
280
281 test_obj.transition_bits = 0;
282 test_obj.terminate = ENTRY;
283 smf_set_initial(SMF_CTX(&test_obj), &test_states[STATE_A]);
284
285 for (int i = 0; i < SMF_RUN; i++) {
286 if (smf_run_state(SMF_CTX(&test_obj))) {
287 break;
288 }
289 }
290
291 zassert_equal(TEST_ENTRY_VALUE_NUM, test_obj.tv_idx,
292 "Incorrect test value index for entry termination");
293 zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
294 "Final entry termination state not reached");
295
296 /* C) Test termination in run action */
297
298 test_obj.transition_bits = 0;
299 test_obj.terminate = RUN;
300 smf_set_initial(SMF_CTX(&test_obj), &test_states[STATE_A]);
301
302 for (int i = 0; i < SMF_RUN; i++) {
303 if (smf_run_state(SMF_CTX(&test_obj))) {
304 break;
305 }
306 }
307
308 zassert_equal(TEST_RUN_VALUE_NUM, test_obj.tv_idx,
309 "Incorrect test value index for run termination");
310 zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
311 "Final run termination state not reached");
312
313 /* D) Test termination in exit action */
314
315 test_obj.transition_bits = 0;
316 test_obj.terminate = EXIT;
317 smf_set_initial(SMF_CTX(&test_obj), &test_states[STATE_A]);
318
319 for (int i = 0; i < SMF_RUN; i++) {
320 if (smf_run_state(SMF_CTX(&test_obj))) {
321 break;
322 }
323 }
324
325 zassert_equal(TEST_EXIT_VALUE_NUM, test_obj.tv_idx,
326 "Incorrect test value index for exit termination");
327 zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
328 "Final exit termination state not reached");
329 }
330