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 void 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 }
109 
state_a_exit(void * obj)110 static void state_a_exit(void *obj)
111 {
112 	struct test_object *o = TEST_OBJECT(obj);
113 
114 	o->tv_idx++;
115 	zassert_equal(o->transition_bits, test_value[o->tv_idx],
116 		      "Test State A exit failed");
117 
118 	o->transition_bits |= STATE_A_EXIT_BIT;
119 }
120 
state_b_entry(void * obj)121 static void state_b_entry(void *obj)
122 {
123 	struct test_object *o = TEST_OBJECT(obj);
124 
125 	o->tv_idx++;
126 	zassert_equal(o->transition_bits, test_value[o->tv_idx],
127 		      "Test State B entry failed");
128 
129 	o->transition_bits |= STATE_B_ENTRY_BIT;
130 }
131 
state_b_run(void * obj)132 static void state_b_run(void *obj)
133 {
134 	struct test_object *o = TEST_OBJECT(obj);
135 
136 	o->tv_idx++;
137 	zassert_equal(o->transition_bits, test_value[o->tv_idx],
138 		      "Test State B run failed");
139 
140 	if (o->terminate == RUN) {
141 		smf_set_terminate(obj, -1);
142 		return;
143 	}
144 
145 	o->transition_bits |= STATE_B_RUN_BIT;
146 
147 	smf_set_state(SMF_CTX(obj), &test_states[STATE_C]);
148 }
149 
state_b_exit(void * obj)150 static void state_b_exit(void *obj)
151 {
152 	struct test_object *o = TEST_OBJECT(obj);
153 
154 	o->tv_idx++;
155 	zassert_equal(o->transition_bits, test_value[o->tv_idx],
156 		      "Test State B exit failed");
157 	o->transition_bits |= STATE_B_EXIT_BIT;
158 }
159 
state_c_entry(void * obj)160 static void state_c_entry(void *obj)
161 {
162 	struct test_object *o = TEST_OBJECT(obj);
163 
164 	o->tv_idx++;
165 	zassert_equal(o->transition_bits, test_value[o->tv_idx],
166 		      "Test State C entry failed");
167 	o->transition_bits |= STATE_C_ENTRY_BIT;
168 }
169 
state_c_run(void * obj)170 static void state_c_run(void *obj)
171 {
172 	struct test_object *o = TEST_OBJECT(obj);
173 
174 	o->tv_idx++;
175 	zassert_equal(o->transition_bits, test_value[o->tv_idx],
176 		      "Test State C run failed");
177 	o->transition_bits |= STATE_C_RUN_BIT;
178 
179 	smf_set_state(SMF_CTX(obj), &test_states[STATE_D]);
180 }
181 
state_c_exit(void * obj)182 static void state_c_exit(void *obj)
183 {
184 	struct test_object *o = TEST_OBJECT(obj);
185 
186 	o->tv_idx++;
187 	zassert_equal(o->transition_bits, test_value[o->tv_idx],
188 		      "Test State C exit failed");
189 
190 	if (o->terminate == EXIT) {
191 		smf_set_terminate(obj, -1);
192 		return;
193 	}
194 
195 	o->transition_bits |= STATE_C_EXIT_BIT;
196 }
197 
state_d_entry(void * obj)198 static void state_d_entry(void *obj)
199 {
200 	struct test_object *o = TEST_OBJECT(obj);
201 
202 	o->tv_idx++;
203 }
204 
state_d_run(void * obj)205 static void state_d_run(void *obj)
206 {
207 	/* Do nothing */
208 }
209 
state_d_exit(void * obj)210 static void state_d_exit(void *obj)
211 {
212 	/* Do nothing */
213 }
214 
215 static const struct smf_state test_states[] = {
216 	[STATE_A] = SMF_CREATE_STATE(state_a_entry, state_a_run, state_a_exit, NULL, NULL),
217 	[STATE_B] = SMF_CREATE_STATE(state_b_entry, state_b_run, state_b_exit, NULL, NULL),
218 	[STATE_C] = SMF_CREATE_STATE(state_c_entry, state_c_run, state_c_exit, NULL, NULL),
219 	[STATE_D] = SMF_CREATE_STATE(state_d_entry, state_d_run, state_d_exit, NULL, NULL),
220 };
221 
ZTEST(smf_tests,test_smf_flat)222 ZTEST(smf_tests, test_smf_flat)
223 {
224 	/* A) Test transitions */
225 
226 	test_obj.transition_bits = 0;
227 	test_obj.terminate = NONE;
228 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
229 
230 	for (int i = 0; i < SMF_RUN; i++) {
231 		if (smf_run_state((struct smf_ctx *)&test_obj)) {
232 			break;
233 		}
234 	}
235 
236 	zassert_equal(TEST_VALUE_NUM, test_obj.tv_idx,
237 		      "Incorrect test value index");
238 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
239 		      "Final state not reached");
240 
241 	/* B) Test termination in entry action */
242 
243 	test_obj.transition_bits = 0;
244 	test_obj.terminate = ENTRY;
245 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
246 
247 	for (int i = 0; i < SMF_RUN; i++) {
248 		if (smf_run_state((struct smf_ctx *)&test_obj)) {
249 			break;
250 		}
251 	}
252 
253 	zassert_equal(TEST_ENTRY_VALUE_NUM, test_obj.tv_idx,
254 		      "Incorrect test value index for entry termination");
255 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
256 		      "Final entry termination state not reached");
257 
258 	/* C) Test termination in run action */
259 
260 	test_obj.transition_bits = 0;
261 	test_obj.terminate = RUN;
262 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
263 
264 	for (int i = 0; i < SMF_RUN; i++) {
265 		if (smf_run_state((struct smf_ctx *)&test_obj)) {
266 			break;
267 		}
268 	}
269 
270 	zassert_equal(TEST_RUN_VALUE_NUM, test_obj.tv_idx,
271 		      "Incorrect test value index for run termination");
272 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
273 		      "Final run termination state not reached");
274 
275 	/* D) Test termination in exit action */
276 
277 	test_obj.transition_bits = 0;
278 	test_obj.terminate = EXIT;
279 	smf_set_initial((struct smf_ctx *)&test_obj, &test_states[STATE_A]);
280 
281 	for (int i = 0; i < SMF_RUN; i++) {
282 		if (smf_run_state((struct smf_ctx *)&test_obj)) {
283 			break;
284 		}
285 	}
286 
287 	zassert_equal(TEST_EXIT_VALUE_NUM, test_obj.tv_idx,
288 		      "Incorrect test value index for exit termination");
289 	zassert_equal(test_obj.transition_bits, test_value[test_obj.tv_idx],
290 		      "Final exit termination state not reached");
291 }
292