Program Listing for File base_fsm.hpp

Return to documentation for file (rcppsw/patterns/fsm/base_fsm.hpp)

#pragma once

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <cstdio>
#include <cstddef>
#include <string>
#include <memory>
#include <utility>
#include <array>

#include "rcppsw/rcppsw.hpp"
#include "rcppsw/er/client.hpp"
#include "rcppsw/patterns/fsm/event.hpp"
#include "rcppsw/patterns/fsm/state_action.hpp"
#include "rcppsw/patterns/fsm/state_entry_action.hpp"
#include "rcppsw/patterns/fsm/state_exit_action.hpp"
#include "rcppsw/patterns/fsm/state_guard_action.hpp"
#include "rcppsw/patterns/fsm/state_map_ex_row.hpp"
#include "rcppsw/patterns/fsm/state_map_row.hpp"

/*******************************************************************************
 * Namespaces/Decls
 ******************************************************************************/
namespace rcppsw::patterns::fsm {

/*******************************************************************************
 * Class Definitions
 ******************************************************************************/
class base_fsm : public er::client<base_fsm> {
 public:
  explicit base_fsm(uint8_t max_states, uint8_t initial_state = 0);
  ~base_fsm(void) override = default;

  base_fsm(const base_fsm& other);

  base_fsm& operator=(const base_fsm& other);

  uint8_t current_state(void) const { return m_current_state; }

  uint8_t max_states(void) const { return mc_max_states; }

  uint8_t previous_state(void) const { return m_previous_state; }

  uint8_t last_state(void) const { return m_last_state; }

  void inject_event(int signal, int type);

  void inject_event(std::unique_ptr<event_data> event);

  virtual void init(void);

 protected:
  const class event_data* event_data(void) const { return m_event_data.get(); }
  class event_data* event_data(void) { return m_event_data.get(); }
  std::unique_ptr<class event_data> event_data_release(void) {
    return std::move(m_event_data);
  }
  void generated_event(bool b) { m_event_generated = b; }
  bool has_generated_event(void) { return m_event_generated; }

  void event_data_hold(bool b) { m_event_data_hold = b; }
  bool event_data_hold(void) const { return m_event_data_hold; }

  virtual void external_event(uint8_t new_state,
                              std::unique_ptr<class event_data> data);
  void external_event(uint8_t new_state) {
    external_event(new_state, nullptr);
  }

  void internal_event(uint8_t new_state, std::unique_ptr<class event_data> data);
  void internal_event(uint8_t new_state) {
    internal_event(new_state, std::move(m_event_data));
  }

  /*
   * \brief State machine engine that executes the external event and,
   * optionally, all internal events generated during state execution.
   */
  void state_engine(void);

  uint8_t next_state(void) const { return m_next_state; }
  uint8_t initial_state(void) const { return m_initial_state; }
  void next_state(uint8_t next_state) { m_next_state = next_state; }
  void update_state(uint8_t new_state);

  virtual const state_map_row* state_map(RCPPSW_UNUSED size_t) {
    return nullptr;
  }

  virtual const state_map_ex_row* state_map_ex(RCPPSW_UNUSED size_t) {
    return nullptr;
  }

  virtual void state_engine_step(const state_map_row* c_row);

  virtual void state_engine_step(const state_map_ex_row* c_row_ex);

 private:
  void state_engine_map(void);
  void state_engine_map_ex(void);
  void event_data(std::unique_ptr<class event_data> event_data) {
    m_event_data = std::move(event_data);
  }

  /* clang-format off */
  const uint8_t                     mc_max_states;
  uint8_t                           m_current_state;
  uint8_t                           m_next_state{0};
  uint8_t                           m_initial_state;
  uint8_t                           m_previous_state{0};
  uint8_t                           m_last_state{0};

  bool                              m_event_generated{false};
  bool                              m_event_data_hold{false};
  std::unique_ptr<class event_data> m_event_data{nullptr};
  /* clang-format on */
};

} /* namespace rcppsw::patterns::fsm */

/*******************************************************************************
 * State Macros With Data
 ******************************************************************************/
#define RCPPSW_FSM_STATE_DECLARE(FSM, state_name, event_data)      \
  int ST_##state_name(event_data*);                   \
  rcppsw::patterns::fsm::                         \
      state_action1<FSM, event_data, &FSM::ST_##state_name> \
  state_name{}

#define RCPPSW_FSM_STATE_DEFINE(FSM, state_name, event_data)     \
  int FSM::ST_##state_name(event_data)

#define RCPPSW_FSM_GUARD_DECLARE(FSM, guard_name, event_data)               \
  bool GD_##guard_name(const event_data*);                           \
  rcppsw::patterns::fsm::                                  \
      state_guard_condition1<FSM, event_data, &FSM::GD_##guard_name> \
  guard_name{}

#define RCPPSW_FSM_GUARD_DEFINE(FSM, guard_name, event_data)     \
  bool FSM::GD_##guard_name(const event_data)


#define RCPPSW_FSM_ENTRY_DECLARE(FSM, entry_name, event_data)            \
  void EN_##entry_name(const event_data*);                        \
  rcppsw::patterns::fsm::                               \
      state_entry_action1<FSM, event_data, &FSM::EN_##entry_name> \
  entry_name{}

#define RCPPSW_FSM_ENTRY_DEFINE(FSM, entry_name, event_data)  \
  void FSM::EN_##entry_name(const event_data)

#define RCPPSW_FSM_EXIT_DECLARE(FSM, exit_name)                                        \
  void EX_##exit_name(void);                                                    \
  rcppsw::patterns::fsm::state_exit_action<FSM, &FSM::EX_##exit_name> \
  exit_name{}

#define RCPPSW_FSM_EXIT_DEFINE(FSM, exit_name) void FSM::EX_##exit_name(void)

/*******************************************************************************
* State Macros Without Data
******************************************************************************/
#define RCPPSW_FSM_STATE_DECLARE_ND(FSM, state_name, ...)                       \
  int ST_##state_name(void) __VA_ARGS__;                                            \
  rcppsw::patterns::fsm::state_action0<FSM, &FSM::ST_##state_name>      \
  state_name{}

#define RCPPSW_FSM_STATE_DEFINE_ND(FSM, state_name) int FSM::ST_##state_name(void)

#define RCPPSW_FSM_GUARD_DECLARE_ND(FSM, guard_name)                                    \
  bool GD_##guard_name(void);                                                    \
  rcppsw::patterns::fsm::state_guard_condition0<FSM,                   \
                                                          &FSM::GD_##guard_name> \
  guard_name{}

#define RCPPSW_FSM_GUARD_DEFINE_ND(FSM, guard_name) bool FSM::GD_##guard_name(void)

#define RCPPSW_FSM_ENTRY_DECLARE_ND(FSM, entry_name)                                      \
  void EN_##entry_name(void);                                                      \
  rcppsw::patterns::fsm::state_entry_action0<FSM, &FSM::EN_##entry_name> \
  entry_name{}

#define RCPPSW_FSM_ENTRY_DEFINE_ND(FSM, entry_name) void FSM::EN_##entry_name(void)

/*******************************************************************************
 * Transition Map Macros
 ******************************************************************************/
#define RCPPSW_FSM_DEFINE_TRANSITION_MAP(name) static const uint8_t name[] =

#define RCPPSW_FSM_VERIFY_TRANSITION_MAP(name, n_entries)                     \
    static_assert((sizeof(name) / sizeof(uint8_t)) == (n_entries),     \
                "Transition map does not cover all states");

/*******************************************************************************
 * State Map Macros
 ******************************************************************************/
#define RCPPSW_FSM_DECLARE_STATE_MAP(type, name, n_entries)                    \
  const std::array<rcppsw::patterns::fsm::RCSW_JOIN(type, _row),              \
                   n_entries> name

#define RCPPSW_FSM_DEFINE_STATE_MAP(name, ...) name {__VA_ARGS__}

#define RCPPSW_FSM_DEFINE_STATE_MAP_ACCESSOR(type, index_var)      \
  const rcppsw::patterns::fsm::RCSW_JOIN(type, _row) * \
  type(size_t index_var)

#define RCPPSW_FSM_STATE_MAP_ENTRY(state_name) \
  rcppsw::patterns::fsm::state_map_row(state_name)

#define RCPPSW_FSM_STATE_MAP_ENTRY_EX(state_name)           \
  rcppsw::patterns::fsm::state_map_ex_row( \
      state_name, NULL, NULL, NULL)

#define RCPPSW_FSM_STATE_MAP_ENTRY_EX_ALL(                  \
    state_name, guard_name, entry_name, exit_name)   \
  rcppsw::patterns::fsm::state_map_ex_row( \
      state_name, guard_name, entry_name, exit_name)