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