1 /*
2 * Copyright (c) 2024 Glenn Andrews
3 * State Machine example copyright (c) Miro Samek
4 *
5 * Implementation of the statechart in Figure 2.11 of
6 * Practical UML Statecharts in C/C++, 2nd Edition by Miro Samek
7 * https://www.state-machine.com/psicc2
8 * Used with permission of the author.
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/smf.h>
15 #include <stdbool.h>
16 #include "hsm_psicc2_thread.h"
17 #include <zephyr/logging/log.h>
18
19 LOG_MODULE_REGISTER(hsm_psicc2_thread);
20
21 /* User defined object */
22 struct s_object {
23 /* This must be first */
24 struct smf_ctx ctx;
25
26 /* Other state specific data add here */
27 struct hsm_psicc2_event event;
28 int foo;
29 } s_obj;
30
31 /* Declaration of possible states */
32 enum demo_states {
33 STATE_INITIAL,
34 STATE_S,
35 STATE_S1,
36 STATE_S2,
37 STATE_S11,
38 STATE_S21,
39 STATE_S211,
40 };
41
42 /* Forward declaration of state table */
43 static const struct smf_state demo_states[];
44
45 /********* STATE_INITIAL *********/
initial_entry(void * o)46 static void initial_entry(void *o)
47 {
48 LOG_INF("%s", __func__);
49 struct s_object *obj = (struct s_object *)o;
50
51 obj->foo = false;
52 }
53
initial_run(void * o)54 static void initial_run(void *o)
55 {
56 LOG_INF("%s", __func__);
57 }
58
initial_exit(void * o)59 static void initial_exit(void *o)
60 {
61 LOG_INF("%s", __func__);
62 }
63
64 /********* STATE_S *********/
s_entry(void * o)65 static void s_entry(void *o)
66 {
67 LOG_INF("%s", __func__);
68 }
69
s_run(void * o)70 static void s_run(void *o)
71 {
72 LOG_INF("%s", __func__);
73 struct s_object *obj = (struct s_object *)o;
74
75 switch (obj->event.event_id) {
76 case EVENT_E:
77 LOG_INF("%s received EVENT_E", __func__);
78 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S11]);
79 break;
80 case EVENT_I:
81 if (obj->foo) {
82 LOG_INF("%s received EVENT_I and set foo false", __func__);
83 obj->foo = false;
84 } else {
85 LOG_INF("%s received EVENT_I and did nothing", __func__);
86 }
87 smf_set_handled(SMF_CTX(obj));
88 break;
89 case EVENT_TERMINATE:
90 LOG_INF("%s received SMF_EVENT_TERMINATE. Terminating", __func__);
91 smf_set_terminate(SMF_CTX(obj), -1);
92 }
93 }
94
s_exit(void * o)95 static void s_exit(void *o)
96 {
97 LOG_INF("%s", __func__);
98 }
99
100 /********* STATE_S1 *********/
s1_entry(void * o)101 static void s1_entry(void *o)
102 {
103 LOG_INF("%s", __func__);
104 }
105
s1_run(void * o)106 static void s1_run(void *o)
107 {
108 LOG_INF("%s", __func__);
109 struct s_object *obj = (struct s_object *)o;
110
111 switch (obj->event.event_id) {
112 case EVENT_A:
113 LOG_INF("%s received EVENT_A", __func__);
114 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S1]);
115 break;
116 case EVENT_B:
117 LOG_INF("%s received EVENT_B", __func__);
118 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S11]);
119 break;
120 case EVENT_C:
121 LOG_INF("%s received EVENT_C", __func__);
122 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S2]);
123 break;
124 case EVENT_D:
125 if (!obj->foo) {
126 LOG_INF("%s received EVENT_D and acted on it", __func__);
127 obj->foo = true;
128 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S]);
129 } else {
130 LOG_INF("%s received EVENT_D and ignored it", __func__);
131 }
132 break;
133 case EVENT_F:
134 LOG_INF("%s received EVENT_F", __func__);
135 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S211]);
136 break;
137 case EVENT_I:
138 LOG_INF("%s received EVENT_I", __func__);
139 smf_set_handled(SMF_CTX(obj));
140 break;
141 }
142 }
143
s1_exit(void * o)144 static void s1_exit(void *o)
145 {
146 LOG_INF("%s", __func__);
147 }
148
149 /********* STATE_S11 *********/
s11_entry(void * o)150 static void s11_entry(void *o)
151 {
152 LOG_INF("%s", __func__);
153 }
154
s11_run(void * o)155 static void s11_run(void *o)
156 {
157 LOG_INF("%s", __func__);
158 struct s_object *obj = (struct s_object *)o;
159
160 switch (obj->event.event_id) {
161 case EVENT_D:
162 if (obj->foo) {
163 LOG_INF("%s received EVENT_D and acted upon it", __func__);
164 obj->foo = false;
165 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S1]);
166 } else {
167 LOG_INF("%s received EVENT_D and ignored it", __func__);
168 }
169 break;
170 case EVENT_G:
171 LOG_INF("%s received EVENT_G", __func__);
172 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S21]);
173 break;
174 case EVENT_H:
175 LOG_INF("%s received EVENT_H", __func__);
176 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S]);
177 break;
178 }
179 }
180
s11_exit(void * o)181 static void s11_exit(void *o)
182 {
183 LOG_INF("%s", __func__);
184 }
185
186 /********* STATE_S2 *********/
s2_entry(void * o)187 static void s2_entry(void *o)
188 {
189 LOG_INF("%s", __func__);
190 }
191
s2_run(void * o)192 static void s2_run(void *o)
193 {
194 LOG_INF("%s", __func__);
195 struct s_object *obj = (struct s_object *)o;
196
197 switch (obj->event.event_id) {
198 case EVENT_C:
199 LOG_INF("%s received EVENT_C", __func__);
200 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S1]);
201 break;
202 case EVENT_F:
203 LOG_INF("%s received EVENT_F", __func__);
204 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S11]);
205 break;
206 case EVENT_I:
207 if (!obj->foo) {
208 LOG_INF("%s received EVENT_I and set foo true", __func__);
209 obj->foo = true;
210 smf_set_handled(SMF_CTX(obj));
211 } else {
212 LOG_INF("%s received EVENT_I and did nothing", __func__);
213 }
214 break;
215 }
216 }
217
s2_exit(void * o)218 static void s2_exit(void *o)
219 {
220 LOG_INF("%s", __func__);
221 }
222
223 /********* STATE_S21 *********/
s21_entry(void * o)224 static void s21_entry(void *o)
225 {
226 LOG_INF("%s", __func__);
227 }
228
s21_run(void * o)229 static void s21_run(void *o)
230 {
231 LOG_INF("%s", __func__);
232 struct s_object *obj = (struct s_object *)o;
233
234 switch (obj->event.event_id) {
235 case EVENT_A:
236 LOG_INF("%s received EVENT_A", __func__);
237 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S21]);
238 break;
239 case EVENT_B:
240 LOG_INF("%s received EVENT_B", __func__);
241 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S211]);
242 break;
243 case EVENT_G:
244 LOG_INF("%s received EVENT_G", __func__);
245 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S1]);
246 break;
247 }
248 }
249
s21_exit(void * o)250 static void s21_exit(void *o)
251 {
252 LOG_INF("%s", __func__);
253 }
254
255 /********* STATE_S211 *********/
s211_entry(void * o)256 static void s211_entry(void *o)
257 {
258 LOG_INF("%s", __func__);
259 }
260
s211_run(void * o)261 static void s211_run(void *o)
262 {
263 LOG_INF("%s", __func__);
264 struct s_object *obj = (struct s_object *)o;
265
266 switch (obj->event.event_id) {
267 case EVENT_D:
268 LOG_INF("%s received EVENT_D", __func__);
269 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S21]);
270 break;
271 case EVENT_H:
272 LOG_INF("%s received EVENT_H", __func__);
273 smf_set_state(SMF_CTX(obj), &demo_states[STATE_S]);
274 break;
275 }
276 }
277
s211_exit(void * o)278 static void s211_exit(void *o)
279 {
280 LOG_INF("%s", __func__);
281 }
282
283 /* State storage: handler functions, parent states and initial transition states */
284 static const struct smf_state demo_states[] = {
285 [STATE_INITIAL] = SMF_CREATE_STATE(initial_entry, initial_run, initial_exit, NULL,
286 &demo_states[STATE_S2]),
287 [STATE_S] = SMF_CREATE_STATE(s_entry, s_run, s_exit, &demo_states[STATE_INITIAL],
288 &demo_states[STATE_S11]),
289 [STATE_S1] = SMF_CREATE_STATE(s1_entry, s1_run, s1_exit, &demo_states[STATE_S],
290 &demo_states[STATE_S11]),
291 [STATE_S2] = SMF_CREATE_STATE(s2_entry, s2_run, s2_exit, &demo_states[STATE_S],
292 &demo_states[STATE_S211]),
293 [STATE_S11] = SMF_CREATE_STATE(s11_entry, s11_run, s11_exit, &demo_states[STATE_S1], NULL),
294 [STATE_S21] = SMF_CREATE_STATE(s21_entry, s21_run, s21_exit, &demo_states[STATE_S2],
295 &demo_states[STATE_S211]),
296 [STATE_S211] =
297 SMF_CREATE_STATE(s211_entry, s211_run, s211_exit, &demo_states[STATE_S21], NULL),
298 };
299
300 K_THREAD_STACK_DEFINE(hsm_psicc2_thread_stack, HSM_PSICC2_THREAD_STACK_SIZE);
301 K_MSGQ_DEFINE(hsm_psicc2_msgq, sizeof(struct hsm_psicc2_event), HSM_PSICC2_THREAD_EVENT_QUEUE_SIZE,
302 1);
303
304 static struct k_thread hsm_psicc2_thread_data;
305 static k_tid_t hsm_psicc2_thread_tid;
306
hsm_psicc2_thread(void * arg1,void * arg2,void * arg3)307 static void hsm_psicc2_thread(void *arg1, void *arg2, void *arg3)
308 {
309 smf_set_initial(SMF_CTX(&s_obj), &demo_states[STATE_INITIAL]);
310 while (1) {
311 int rc = k_msgq_get(&hsm_psicc2_msgq, &s_obj.event, K_FOREVER);
312
313 if (rc == 0) {
314 /* Run state machine with given message */
315 rc = smf_run_state(SMF_CTX(&s_obj));
316
317 if (rc) {
318 /* State machine terminates if a non-zero value is returned */
319 LOG_INF("%s terminating state machine thread", __func__);
320 break;
321 }
322 } else {
323 LOG_ERR("Waiting for event failed, code %d", rc);
324 }
325 }
326 }
327
hsm_psicc2_thread_run(void)328 void hsm_psicc2_thread_run(void)
329 {
330 hsm_psicc2_thread_tid =
331 k_thread_create(&hsm_psicc2_thread_data, hsm_psicc2_thread_stack,
332 K_THREAD_STACK_SIZEOF(hsm_psicc2_thread_stack), hsm_psicc2_thread,
333 NULL, NULL, NULL, HSM_PSICC2_THREAD_PRIORITY, 0, K_NO_WAIT);
334
335 k_thread_name_set(hsm_psicc2_thread_tid, "psicc2_thread");
336 }
337