zephyr/include/zephyr/smf.h
Glenn Andrews 94084e5aba Lib: SMF: Add return code to signal event propagation
See Discussion https://github.com/zephyrproject-rtos/zephyr/discussions/83659
for information about the purpose of this change.

Modifies run actions of hierarchical state machines
to return a value indicating if the event was handled
by the run action or should be propagated up to the
parent run action. Flat state machines are not affected,
and their run action returns void.

smf_set_handled() has been removed and replaced by
this return value. smf_set_state() will not propagate
events regardless of the return value as the transition
is considered to have occurred.

Documentation, tests, samples, has been updated.
USB-C and hawkBit use SMF and have been updated to use
the new return codes.

Signed-off-by: Glenn Andrews <glenn.andrews.42@gmail.com>
2025-06-17 16:04:04 +02:00

191 lines
5.4 KiB
C

/*
* Copyright 2021 The Chromium OS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
*
* @brief State Machine Framework header file
*/
#ifndef ZEPHYR_INCLUDE_SMF_H_
#define ZEPHYR_INCLUDE_SMF_H_
#include <zephyr/sys/util.h>
/**
* @brief State Machine Framework API
* @defgroup smf State Machine Framework API
* @version 0.1.0
* @ingroup os_services
* @{
*/
/**
* @brief Macro to create a hierarchical state with initial transitions.
*
* @param _entry State entry function or NULL
* @param _run State run function or NULL
* @param _exit State exit function or NULL
* @param _parent State parent object or NULL
* @param _initial State initial transition object or NULL
*/
/* clang-format off */
#define SMF_CREATE_STATE(_entry, _run, _exit, _parent, _initial) \
{ \
.entry = _entry, \
.run = _run, \
.exit = _exit, \
IF_ENABLED(CONFIG_SMF_ANCESTOR_SUPPORT, (.parent = _parent,)) \
IF_ENABLED(CONFIG_SMF_INITIAL_TRANSITION, (.initial = _initial,)) \
}
/* clang-format on */
/**
* @brief Macro to cast user defined object to state machine
* context.
*
* @param o A pointer to the user defined object
*/
#define SMF_CTX(o) ((struct smf_ctx *)o)
#ifdef __cplusplus
extern "C" {
#endif
#include <zephyr/kernel.h>
/**
* @brief enum for the return value of a state_execution function
*/
enum smf_state_result {
SMF_EVENT_HANDLED,
SMF_EVENT_PROPAGATE,
};
/**
* @brief Function pointer that implements a entry and exit actions
* of a state
*
* @param obj pointer user defined object
*/
typedef void (*state_method)(void *obj);
/**
* @brief Function pointer that implements a the run action of a state
*
* @param obj pointer user defined object
* @return If the event should be propagated to parent states or not
* (Ignored when CONFIG_SMF_ANCESTOR_SUPPORT not defined)
*/
typedef enum smf_state_result (*state_execution)(void *obj);
/** General state that can be used in multiple state machines. */
struct smf_state {
/** Optional method that will be run when this state is entered */
const state_method entry;
/**
* Optional method that will be run repeatedly during state machine
* loop.
*/
const state_execution run;
/** Optional method that will be run when this state exists */
const state_method exit;
#ifdef CONFIG_SMF_ANCESTOR_SUPPORT
/**
* Optional parent state that contains common entry/run/exit
* implementation among various child states.
* entry: Parent function executes BEFORE child function.
* run: Parent function executes AFTER child function.
* exit: Parent function executes AFTER child function.
*
* Note: When transitioning between two child states with a shared
* parent, that parent's exit and entry functions do not execute.
*/
const struct smf_state *parent;
#ifdef CONFIG_SMF_INITIAL_TRANSITION
/**
* Optional initial transition state. NULL for leaf states.
*/
const struct smf_state *initial;
#endif /* CONFIG_SMF_INITIAL_TRANSITION */
#endif /* CONFIG_SMF_ANCESTOR_SUPPORT */
};
/** Defines the current context of the state machine. */
struct smf_ctx {
/** Current state the state machine is executing. */
const struct smf_state *current;
/** Previous state the state machine executed */
const struct smf_state *previous;
#ifdef CONFIG_SMF_ANCESTOR_SUPPORT
/** Currently executing state (which may be a parent) */
const struct smf_state *executing;
#endif /* CONFIG_SMF_ANCESTOR_SUPPORT */
/**
* This value is set by the set_terminate function and
* should terminate the state machine when its set to a
* value other than zero when it's returned by the
* run_state function.
*/
int32_t terminate_val;
/**
* The state machine casts this to a "struct internal_ctx" and it's
* used to track state machine context
*/
uint32_t internal;
};
/**
* @brief Initializes the state machine and sets its initial state.
*
* @param ctx State machine context
* @param init_state Initial state the state machine starts in.
*/
void smf_set_initial(struct smf_ctx *ctx, const struct smf_state *init_state);
/**
* @brief Changes a state machines state. This handles exiting the previous
* state and entering the target state. For HSMs the entry and exit
* actions of the Least Common Ancestor will not be run.
*
* @param ctx State machine context
* @param new_state State to transition to (NULL is valid and exits all states)
*/
void smf_set_state(struct smf_ctx *ctx, const struct smf_state *new_state);
/**
* @brief Terminate a state machine
*
* @param ctx State machine context
* @param val Non-Zero termination value that's returned by the smf_run_state
* function.
*/
void smf_set_terminate(struct smf_ctx *ctx, int32_t val);
/**
* @brief Runs one iteration of a state machine (including any parent states)
*
* @param ctx State machine context
* @return A non-zero value should terminate the state machine. This
* non-zero value could represent a terminal state being reached
* or the detection of an error that should result in the
* termination of the state machine.
*/
int32_t smf_run_state(struct smf_ctx *ctx);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_SMF_H_ */