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