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