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