Program Listing for File hsm.hpp
↰ Return to documentation for file (include/hsmcpp/hsm.hpp
)
// Copyright (C) 2021 Igor Krechetov
// Distributed under MIT license. See file LICENSE for details
#ifndef HSMCPP_HSM_HPP
#define HSMCPP_HSM_HPP
#include <list>
#include <memory>
#include <string>
#include "HsmTypes.hpp"
#include "variant.hpp"
namespace hsmcpp {
class IHsmEventDispatcher;
class HierarchicalStateMachine {
public:
explicit HierarchicalStateMachine(const StateID_t initialState);
virtual ~HierarchicalStateMachine();
void setInitialState(const StateID_t initialState);
virtual bool initialize(const std::weak_ptr<IHsmEventDispatcher>& dispatcher);
std::weak_ptr<IHsmEventDispatcher> dispatcher() const;
bool isInitialized() const;
void release();
void registerFailedTransitionCallback(HsmTransitionFailedCallback_t onFailedTransition);
template <class HsmHandlerClass>
void registerFailedTransitionCallback(HsmHandlerClass* handler,
HsmTransitionFailedCallbackPtr_t(HsmHandlerClass, onFailedTransition));
void registerState(const StateID_t state,
HsmStateChangedCallback_t onStateChanged = nullptr,
HsmStateEnterCallback_t onEntering = nullptr,
HsmStateExitCallback_t onExiting = nullptr);
template <class HsmHandlerClass>
void registerState(const StateID_t state,
HsmHandlerClass* handler = nullptr,
HsmStateChangedCallbackPtr_t(HsmHandlerClass, onStateChanged) = nullptr,
HsmStateEnterCallbackPtr_t(HsmHandlerClass, onEntering) = nullptr,
HsmStateExitCallbackPtr_t(HsmHandlerClass, onExiting) = nullptr);
void registerFinalState(const StateID_t state,
const EventID_t event = INVALID_HSM_EVENT_ID,
HsmStateChangedCallback_t onStateChanged = nullptr,
HsmStateEnterCallback_t onEntering = nullptr,
HsmStateExitCallback_t onExiting = nullptr);
template <class HsmHandlerClass>
void registerFinalState(const StateID_t state,
const EventID_t event = INVALID_HSM_EVENT_ID,
HsmHandlerClass* handler = nullptr,
HsmStateChangedCallbackPtr_t(HsmHandlerClass, onStateChanged) = nullptr,
HsmStateEnterCallbackPtr_t(HsmHandlerClass, onEntering) = nullptr,
HsmStateExitCallbackPtr_t(HsmHandlerClass, onExiting) = nullptr);
// TODO: check structure and return FALSE?
void registerHistory(const StateID_t parent,
const StateID_t historyState,
const HistoryType type = HistoryType::SHALLOW,
const StateID_t defaultTarget = INVALID_HSM_STATE_ID,
HsmTransitionCallback_t transitionCallback = nullptr);
template <class HsmHandlerClass>
void registerHistory(const StateID_t parent,
const StateID_t historyState,
const HistoryType type = HistoryType::SHALLOW,
const StateID_t defaultTarget = INVALID_HSM_STATE_ID,
HsmHandlerClass* handler = nullptr,
HsmTransitionCallbackPtr_t(HsmHandlerClass, transitionCallback) = nullptr);
bool registerSubstate(const StateID_t parent, const StateID_t substate);
bool registerSubstateEntryPoint(const StateID_t parent,
const StateID_t substate,
const EventID_t onEvent = INVALID_HSM_EVENT_ID,
HsmTransitionConditionCallback_t conditionCallback = nullptr,
const bool expectedConditionValue = true);
template <class HsmHandlerClass>
bool registerSubstateEntryPoint(const StateID_t parent,
const StateID_t substate,
const EventID_t onEvent = INVALID_HSM_EVENT_ID,
HsmHandlerClass* handler = nullptr,
HsmTransitionConditionCallbackPtr_t(HsmHandlerClass, conditionCallback) = nullptr,
const bool expectedConditionValue = true);
void registerTimer(const TimerID_t timerID, const EventID_t event);
// TODO: add support for transition actions
template <typename... Args>
bool registerStateAction(const StateID_t state,
const StateActionTrigger actionTrigger,
const StateAction action,
Args&&... args);
void registerTransition(const StateID_t fromState,
const StateID_t toState,
const EventID_t onEvent,
HsmTransitionCallback_t transitionCallback = nullptr,
HsmTransitionConditionCallback_t conditionCallback = nullptr,
const bool expectedConditionValue = true);
template <class HsmHandlerClass>
void registerTransition(const StateID_t fromState,
const StateID_t toState,
const EventID_t onEvent,
HsmHandlerClass* handler = nullptr,
HsmTransitionCallbackPtr_t(HsmHandlerClass, transitionCallback) = nullptr,
HsmTransitionConditionCallbackPtr_t(HsmHandlerClass, conditionCallback) = nullptr,
const bool expectedConditionValue = true);
void registerSelfTransition(const StateID_t state,
const EventID_t onEvent,
const TransitionType type = TransitionType::EXTERNAL_TRANSITION,
HsmTransitionCallback_t transitionCallback = nullptr,
HsmTransitionConditionCallback_t conditionCallback = nullptr,
const bool expectedConditionValue = true);
template <class HsmHandlerClass>
void registerSelfTransition(const StateID_t state,
const EventID_t onEvent,
const TransitionType type = TransitionType::EXTERNAL_TRANSITION,
HsmHandlerClass* handler = nullptr,
HsmTransitionCallbackPtr_t(HsmHandlerClass, transitionCallback) = nullptr,
HsmTransitionConditionCallbackPtr_t(HsmHandlerClass, conditionCallback) = nullptr,
const bool expectedConditionValue = true);
StateID_t getLastActiveState() const;
const std::list<StateID_t>& getActiveStates() const;
bool isStateActive(const StateID_t state) const;
template <typename... Args>
void transition(const EventID_t event, Args&&... args);
template <typename... Args>
bool transitionEx(const EventID_t event, const bool clearQueue, const bool sync, const int timeoutMs, Args&&... args);
void transitionWithArgsArray(const EventID_t event, VariantVector_t&& args);
bool transitionExWithArgsArray(const EventID_t event,
const bool clearQueue,
const bool sync,
const int timeoutMs,
VariantVector_t&& args);
template <typename... Args>
bool transitionSync(const EventID_t event, const int timeoutMs, Args&&... args);
template <typename... Args>
void transitionWithQueueClear(const EventID_t event, Args&&... args);
bool transitionInterruptSafe(const EventID_t event);
template <typename... Args>
bool isTransitionPossible(const EventID_t event, Args&&... args);
void startTimer(const TimerID_t timerID, const unsigned int intervalMs, const bool isSingleShot);
void restartTimer(const TimerID_t timerID);
void stopTimer(const TimerID_t timerID);
bool isTimerRunning(const TimerID_t timerID);
bool enableHsmDebugging();
bool enableHsmDebugging(const std::string& dumpPath);
void disableHsmDebugging();
protected:
virtual std::string getStateName(const StateID_t state) const;
virtual std::string getEventName(const EventID_t event) const;
private:
template <typename... Args>
void makeVariantList(VariantVector_t& vList, Args&&... args);
bool registerStateActionImpl(const StateID_t state,
const StateActionTrigger actionTrigger,
const StateAction action,
const VariantVector_t& args);
bool isTransitionPossibleImpl(const EventID_t event, const VariantVector_t& args);
private:
class Impl;
std::shared_ptr<Impl> mImpl;
};
// =================================================================================================================
// Template Functions
// =================================================================================================================
template <class HsmHandlerClass>
void HierarchicalStateMachine::registerFailedTransitionCallback(HsmHandlerClass* handler,
HsmTransitionFailedCallbackPtr_t(HsmHandlerClass,
onFailedTransition)) {
registerFailedTransitionCallback(std::bind(onFailedTransition, handler, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}
template <class HsmHandlerClass>
void HierarchicalStateMachine::registerState(const StateID_t state,
HsmHandlerClass* handler,
HsmStateChangedCallbackPtr_t(HsmHandlerClass, onStateChanged),
HsmStateEnterCallbackPtr_t(HsmHandlerClass, onEntering),
HsmStateExitCallbackPtr_t(HsmHandlerClass, onExiting)) {
HsmStateChangedCallback_t funcStateChanged;
HsmStateEnterCallback_t funcEntering;
HsmStateExitCallback_t funcExiting;
if (nullptr != handler) {
if (nullptr != onStateChanged) {
funcStateChanged = std::bind(onStateChanged, handler, std::placeholders::_1);
}
if (nullptr != onEntering) {
funcEntering = std::bind(onEntering, handler, std::placeholders::_1);
}
if (nullptr != onExiting) {
funcExiting = std::bind(onExiting, handler);
}
}
registerState(state, funcStateChanged, funcEntering, funcExiting);
}
template <class HsmHandlerClass>
void HierarchicalStateMachine::registerFinalState(const StateID_t state,
const EventID_t event,
HsmHandlerClass* handler,
HsmStateChangedCallbackPtr_t(HsmHandlerClass, onStateChanged),
HsmStateEnterCallbackPtr_t(HsmHandlerClass, onEntering),
HsmStateExitCallbackPtr_t(HsmHandlerClass, onExiting)) {
HsmStateChangedCallback_t funcStateChanged;
HsmStateEnterCallback_t funcEntering;
HsmStateExitCallback_t funcExiting;
if (nullptr != handler) {
if (nullptr != onStateChanged) {
funcStateChanged = std::bind(onStateChanged, handler, std::placeholders::_1);
}
if (nullptr != onEntering) {
funcEntering = std::bind(onEntering, handler, std::placeholders::_1);
}
if (nullptr != onExiting) {
funcExiting = std::bind(onExiting, handler);
}
}
registerFinalState(state, event, funcStateChanged, funcEntering, funcExiting);
}
template <class HsmHandlerClass>
void HierarchicalStateMachine::registerHistory(const StateID_t parent,
const StateID_t historyState,
const HistoryType type,
const StateID_t defaultTarget,
HsmHandlerClass* handler,
HsmTransitionCallbackPtr_t(HsmHandlerClass, transitionCallback)) {
HsmTransitionCallback_t funcTransitionCallback;
if (nullptr != handler) {
if (nullptr != transitionCallback) {
funcTransitionCallback = std::bind(transitionCallback, handler, std::placeholders::_1);
}
}
registerHistory(parent, historyState, type, defaultTarget, funcTransitionCallback);
}
template <class HsmHandlerClass>
bool HierarchicalStateMachine::registerSubstateEntryPoint(const StateID_t parent,
const StateID_t substate,
const EventID_t onEvent,
HsmHandlerClass* handler,
HsmTransitionConditionCallbackPtr_t(HsmHandlerClass,
conditionCallback),
const bool expectedConditionValue) {
HsmTransitionConditionCallback_t condition;
if ((nullptr != handler) && (nullptr != conditionCallback)) {
condition = std::bind(conditionCallback, handler, std::placeholders::_1);
}
return registerSubstateEntryPoint(parent, substate, onEvent, condition, expectedConditionValue);
}
template <typename... Args>
bool HierarchicalStateMachine::registerStateAction(const StateID_t state,
const StateActionTrigger actionTrigger,
const StateAction action,
Args&&... args) {
VariantVector_t eventArgs;
makeVariantList(eventArgs, std::forward<Args>(args)...);
return registerStateActionImpl(state, actionTrigger, action, eventArgs);
}
template <class HsmHandlerClass>
void HierarchicalStateMachine::registerTransition(const StateID_t fromState,
const StateID_t toState,
const EventID_t onEvent,
HsmHandlerClass* handler,
HsmTransitionCallbackPtr_t(HsmHandlerClass, transitionCallback),
HsmTransitionConditionCallbackPtr_t(HsmHandlerClass, conditionCallback),
const bool expectedConditionValue) {
HsmTransitionCallback_t funcTransitionCallback;
HsmTransitionConditionCallback_t funcConditionCallback;
if (nullptr != handler) {
if (nullptr != transitionCallback) {
funcTransitionCallback = std::bind(transitionCallback, handler, std::placeholders::_1);
}
if (nullptr != conditionCallback) {
funcConditionCallback = std::bind(conditionCallback, handler, std::placeholders::_1);
}
}
registerTransition(fromState, toState, onEvent, funcTransitionCallback, funcConditionCallback, expectedConditionValue);
}
template <class HsmHandlerClass>
void HierarchicalStateMachine::registerSelfTransition(const StateID_t state,
const EventID_t onEvent,
const TransitionType type,
HsmHandlerClass* handler,
HsmTransitionCallbackPtr_t(HsmHandlerClass, transitionCallback),
HsmTransitionConditionCallbackPtr_t(HsmHandlerClass, conditionCallback),
const bool expectedConditionValue) {
HsmTransitionCallback_t funcTransitionCallback;
HsmTransitionConditionCallback_t funcConditionCallback;
if (nullptr != handler) {
if (nullptr != transitionCallback) {
funcTransitionCallback = std::bind(transitionCallback, handler, std::placeholders::_1);
}
if (nullptr != conditionCallback) {
funcConditionCallback = std::bind(conditionCallback, handler, std::placeholders::_1);
}
}
registerSelfTransition(state, onEvent, type, funcTransitionCallback, funcConditionCallback, expectedConditionValue);
}
template <typename... Args>
void HierarchicalStateMachine::transition(const EventID_t event, Args&&... args) {
(void)transitionEx(event, false, false, 0, std::forward<Args>(args)...);
}
template <typename... Args>
bool HierarchicalStateMachine::transitionEx(const EventID_t event,
const bool clearQueue,
const bool sync,
const int timeoutMs,
Args&&... args) {
VariantVector_t eventArgs;
makeVariantList(eventArgs, std::forward<Args>(args)...);
return transitionExWithArgsArray(event, clearQueue, sync, timeoutMs, std::move(eventArgs));
}
template <typename... Args>
bool HierarchicalStateMachine::transitionSync(const EventID_t event, const int timeoutMs, Args&&... args) {
return transitionEx(event, false, true, timeoutMs, std::forward<Args>(args)...);
}
template <typename... Args>
void HierarchicalStateMachine::transitionWithQueueClear(const EventID_t event, Args&&... args) {
// NOTE: async transitions always return true
(void)transitionEx(event, true, false, 0, std::forward<Args>(args)...);
}
template <typename... Args>
bool HierarchicalStateMachine::isTransitionPossible(const EventID_t event, Args&&... args) {
VariantVector_t eventArgs;
makeVariantList(eventArgs, std::forward<Args>(args)...);
return isTransitionPossibleImpl(event, eventArgs);
}
template <typename... Args>
void HierarchicalStateMachine::makeVariantList(VariantVector_t& vList, Args&&... args) {
volatile int make_variant[] = {0, (vList.emplace_back(std::forward<Args>(args)), 0)...};
(void)make_variant;
}
} // namespace hsmcpp
#endif // HSMCPP_HSM_HPP