1 /*
2  * Copyright 2021 The Chromium OS Authors
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /* State Machine Framework */
8 
9 #ifndef ZEPHYR_INCLUDE_SMF_H_
10 #define ZEPHYR_INCLUDE_SMF_H_
11 
12 #ifdef CONFIG_SMF_ANCESTOR_SUPPORT
13 /**
14  * @brief Macro to create a hierarchical state.
15  *
16  * @param _entry  State entry function
17  * @param _run    State run function
18  * @param _exit   State exit function
19  * @param _parent State parent object or NULL
20  */
21 #define SMF_CREATE_STATE(_entry, _run, _exit, _parent) \
22 { \
23 	.entry  = _entry, \
24 	.run    = _run,   \
25 	.exit   = _exit,  \
26 	.parent = _parent \
27 }
28 
29 #else
30 
31 /**
32  * @brief Macro to create a flat state.
33  *
34  * @param _entry  State entry function
35  * @param _run  State run function
36  * @param _exit  State exit function
37  */
38 #define SMF_CREATE_STATE(_entry, _run, _exit) \
39 { \
40 	.entry = _entry, \
41 	.run   = _run,   \
42 	.exit  = _exit   \
43 }
44 
45 #endif /* CONFIG_SMF_ANCESTOR_SUPPORT */
46 
47 /**
48  * @brief Macro to cast user defined object to state machine
49  *        context.
50  *
51  * @param o A pointer to the user defined object
52  */
53 #define SMF_CTX(o) ((struct smf_ctx *)o)
54 
55 #ifdef __cplusplus
56 extern "C" {
57 #endif
58 
59 #include <zephyr/kernel.h>
60 
61 /**
62  * @brief Function pointer that implements a portion of a state
63  *
64  * @param obj pointer user defined object
65  */
66 typedef void (*state_execution)(void *obj);
67 
68 /** General state that can be used in multiple state machines. */
69 struct smf_state {
70 	/** Optional method that will be run when this state is entered */
71 	const state_execution entry;
72 	/**
73 	 * Optional method that will be run repeatedly during state machine
74 	 * loop.
75 	 */
76 	const state_execution run;
77 	/** Optional method that will be run when this state exists */
78 	const state_execution exit;
79 	/**
80 	 * Optional parent state that contains common entry/run/exit
81 	 *	implementation among various child states.
82 	 *	entry: Parent function executes BEFORE child function.
83 	 *	run:   Parent function executes AFTER child function.
84 	 *	exit:  Parent function executes AFTER child function.
85 	 *
86 	 *	Note: When transitioning between two child states with a shared parent,
87 	 *	that parent's exit and entry functions do not execute.
88 	 */
89 	const struct smf_state *parent;
90 };
91 
92 /** Defines the current context of the state machine. */
93 struct smf_ctx {
94 	/** Current state the state machine is executing. */
95 	const struct smf_state *current;
96 	/** Previous state the state machine executed */
97 	const struct smf_state *previous;
98 	/**
99 	 * This value is set by the set_terminate function and
100 	 * should terminate the state machine when its set to a
101 	 * value other than zero when it's returned by the
102 	 * run_state function.
103 	 */
104 	int32_t terminate_val;
105 	/**
106 	 * The state machine casts this to a "struct internal_ctx" and it's
107 	 * used to track state machine context
108 	 */
109 	uint32_t internal;
110 };
111 
112 /**
113  * @brief Initializes the state machine and sets its initial state.
114  *
115  * @param ctx        State machine context
116  * @param init_state Initial state the state machine starts in.
117  */
118 void smf_set_initial(struct smf_ctx *ctx, const struct smf_state *init_state);
119 
120 /**
121  * @brief Changes a state machines state. This handles exiting the previous
122  *        state and entering the target state. A common parent state will not
123  *        exited nor be re-entered.
124  *
125  * @param ctx       State machine context
126  * @param new_state State to transition to (NULL is valid and exits all states)
127  */
128 void smf_set_state(struct smf_ctx *ctx, const struct smf_state *new_state);
129 
130 /**
131  * @brief Terminate a state machine
132  *
133  * @param ctx  State machine context
134  * @param val  Non-Zero termination value that's returned by the smf_run_state
135  *             function.
136  */
137 void smf_set_terminate(struct smf_ctx *ctx, int32_t val);
138 
139 /**
140  * @brief Runs one iteration of a state machine (including any parent states)
141  *
142  * @param ctx  State machine context
143  * @return	   A non-zero value should terminate the state machine. This
144  *			   non-zero value could represent a terminal state being reached
145  *			   or the detection of an error that should result in the
146  *			   termination of the state machine.
147  */
148 int32_t smf_run_state(struct smf_ctx *ctx);
149 
150 #ifdef __cplusplus
151 }
152 #endif
153 
154 #endif /* ZEPHYR_INCLUDE_SMF_H_ */
155