diff --git a/App/Src/startup.cpp b/App/Src/startup.cpp index f4e3274..be10ea9 100644 --- a/App/Src/startup.cpp +++ b/App/Src/startup.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include diff --git a/App/Src/tasks/dummy.cpp b/App/Src/tasks/dummy.cpp index 2e6e131..9b7adb0 100644 --- a/App/Src/tasks/dummy.cpp +++ b/App/Src/tasks/dummy.cpp @@ -31,7 +31,6 @@ namespace demo STA_DEBUG_PRINTLN(this->getName()); // STA_DEBUG_PRINT("Executing "); // STA_DEBUG_PRINTLN(this->getName()); - osDelay(1000); } } // namespace demo diff --git a/Tacos/include/sta/tacos/statemachine.hpp b/Tacos/include/sta/tacos/statemachine.hpp index 8a3ab1f..9ecefd9 100644 --- a/Tacos/include/sta/tacos/statemachine.hpp +++ b/Tacos/include/sta/tacos/statemachine.hpp @@ -20,14 +20,18 @@ # define STA_TACOS_INITIAL_STATE 0 #endif -#define TACOS_STATE_TRANSITION_FLAG 0x00000001U -#define TACOS_STATE_CHANGE_FORCED_FLAG 0x00000002U -#define TACOS_STATE_CHANGE_ALL_FLAG 0x00000003U +// State transition happened because of +#define STA_TACOS_STATE_CHANGE_NORMAL_FLAG ( 0x1U ) +#define STA_TACOS_STATE_CHANGE_FORCED_FLAG ( 0x1U << 1) +#define STA_TACOS_STATE_CHANGE_TIMEOUT ( 0x1U << 2) +#define STA_TACOS_STATE_CHANGE_STARTUP_FLAG ( 0x1U << 3) +#define STA_TACOS_STATE_CHANGE_ALL_FLAG ( 0x15U ) #include #include #include +#include #include #include @@ -37,40 +41,76 @@ namespace sta { namespace tacos { + typedef std::function state_fn; + typedef std::function timer_fn; + + class Statemachine : public TacosThread { public: - static RtosEvent* stateChangeEvent; + enum EventFlags + { + NORMAL = 0x1U, + FORCED = 0x1U << 1, + TIMEOUT = 0x1U << 2, + STARTUP = 0x1U << 3, + ALL = NORMAL | FORCED | TIMEOUT | STARTUP + }; + /** + * @brief The global event signaling a state change. + */ + static RtosEvent stateChangeEvent; + + /** + * @brief Getter function for the singleton instance. + */ static Statemachine* instance() { static CGuard g; if (!_instance) { - // Create a the manager singleton instance. + // Create the manager singleton instance. Statemachine::_instance = new Statemachine(); - Statemachine::stateChangeEvent = new RtosEvent(); } return _instance; } - void init() override; - - void func() override; - /** * @brief Returns the statemachine's current state. */ uint16_t getCurrentState() const; /** - * @brief Registers a new state transition function. + * @brief Registers a new state transition function. This is a function for the user to implement state transition rules. */ - void setStateTransitionFunction(std::function function); + void setStateFunction(state_fn func); + /** + * @brief Registers a new timer function. This is a function for the user to set the timers after a state change. + */ + void setTimerFunction(timer_fn func); + + /** + * @brief Starts the failsafe timer for the desired duration and the desired next state. + */ + void setFailsafeTimer(uint32_t millis, uint16_t nextState); + + /** + * @brief Starts the lockoutTimer for the desired duration. + */ + void setLockoutTimer(uint32_t millis); + + /** + * @brief this function call allows forced state transitions from external and internal sources. + */ void forceStateTransition(uint16_t state); + + void init() override; + void func() override; + private: static Statemachine * _instance; @@ -82,9 +122,7 @@ namespace sta if( NULL != Statemachine::_instance ) { delete Statemachine::_instance; - delete Statemachine::stateChangeEvent; Statemachine::_instance = NULL; - Statemachine::stateChangeEvent = NULL; } } }; @@ -94,11 +132,15 @@ namespace sta Statemachine(const Statemachine&); ~Statemachine() {} + private: uint16_t currentState_; + RtosTimer lockoutTimer_; RtosTimer failsafeTimer_; - std::function transitionFunc_; + + state_fn transitionFunc_; + timer_fn timerFunc_; }; } // namespace tacos } // namespace sta diff --git a/Tacos/src/manager.cpp b/Tacos/src/manager.cpp index 32caca7..d670d2e 100644 --- a/Tacos/src/manager.cpp +++ b/Tacos/src/manager.cpp @@ -78,7 +78,7 @@ namespace sta void Manager::func() { - Statemachine::stateChangeEvent->wait(TACOS_STATE_CHANGE_ALL_FLAG, osWaitForever); + Statemachine::stateChangeEvent.wait(Statemachine::EventFlags::ALL, osWaitForever); STA_DEBUG_PRINTLN("UPDATING THREADS"); diff --git a/Tacos/src/statemachine.cpp b/Tacos/src/statemachine.cpp index 8390f9c..fdb9955 100644 --- a/Tacos/src/statemachine.cpp +++ b/Tacos/src/statemachine.cpp @@ -19,20 +19,15 @@ namespace sta currentState_{STA_TACOS_INITIAL_STATE}, lockoutTimer_{[](void *){}, nullptr}, failsafeTimer_{[](void *){}, nullptr}, - transitionFunc_{[](uint16_t) -> uint16_t { return Statemachine::instance()->getCurrentState(); }} + transitionFunc_{[](uint16_t) -> uint16_t { return Statemachine::instance()->getCurrentState(); }}, + timerFunc_{[](uint16_t, uint16_t, uint16_t) {}} { STA_ASSERT(STA_TACOS_INITIAL_STATE < STA_TACOS_NUM_STATES); } void Statemachine::init() { - lockoutTimer_.setCallback([](void *) { }, nullptr); - lockoutTimer_.start(5000); - - failsafeTimer_.setCallback([](void *) { - Statemachine::instance()->forceStateTransition(1); - }, nullptr); - failsafeTimer_.start(10000); + timerFunc_(0, 0, EventFlags::STARTUP); } void Statemachine::func() @@ -41,14 +36,18 @@ namespace sta STA_ASSERT(next < STA_TACOS_NUM_STATES); - if (next != currentState_) + // Check if a state change is desired. Block if the lockoutTimer is still running. + if (next != currentState_ && !lockoutTimer_.isRunning()) { - currentState_ = next; + // Call user space code to set the timers again. + timerFunc_(next, currentState_, EventFlags::NORMAL); - Statemachine::stateChangeEvent->set(TACOS_STATE_TRANSITION_FLAG); + // Update the state and trigger the global state changed event. + currentState_ = next; + Statemachine::stateChangeEvent.set(EventFlags::NORMAL); } - Statemachine::stateChangeEvent->clear(TACOS_STATE_CHANGE_ALL_FLAG); + Statemachine::stateChangeEvent.clear(EventFlags::ALL); } uint16_t Statemachine::getCurrentState() const @@ -56,24 +55,51 @@ namespace sta return currentState_; } - void Statemachine::setStateTransitionFunction(std::function function) + void Statemachine::setStateFunction(state_fn func) { - STA_ASSERT(function != nullptr); + STA_ASSERT(func != nullptr); - transitionFunc_ = function; + transitionFunc_ = func; + } + + void Statemachine::setTimerFunction(timer_fn func) + { + STA_ASSERT(func != nullptr); + + timerFunc_ = func; + } + + void Statemachine::setFailsafeTimer(uint32_t millis, uint16_t nextState) + { + STA_ASSERT(nextState < STA_TACOS_NUM_STATES); + STA_ASSERT(!failsafeTimer_.isRunning()); + + failsafeTimer_.setCallback([nextState](void *) { + Statemachine::instance()->forceStateTransition(nextState); + }, nullptr); + + failsafeTimer_.start(millis); + } + + void Statemachine::setLockoutTimer(uint32_t millis) + { + STA_ASSERT(!failsafeTimer_.isRunning()); + + lockoutTimer_.setCallback([](void *) { }, nullptr); + lockoutTimer_.start(millis); } void Statemachine::forceStateTransition(uint16_t state) { currentState_ = state; - Statemachine::stateChangeEvent->set(TACOS_STATE_CHANGE_FORCED_FLAG); - Statemachine::stateChangeEvent->clear(TACOS_STATE_CHANGE_ALL_FLAG); + Statemachine::stateChangeEvent.set(EventFlags::FORCED); + Statemachine::stateChangeEvent.clear(EventFlags::ALL); } Statemachine* Statemachine::_instance = nullptr; - RtosEvent* Statemachine::stateChangeEvent = nullptr; + RtosEvent Statemachine::stateChangeEvent; } // namespace tacos } // namespace sta diff --git a/Tacos/src/thread.cpp b/Tacos/src/thread.cpp index 96bcf7d..ececb73 100644 --- a/Tacos/src/thread.cpp +++ b/Tacos/src/thread.cpp @@ -46,6 +46,8 @@ namespace sta instance_ = osThreadNew(entry_point, this, &attribs_); STA_ASSERT(instance_ != NULL); + + // SetFlag(THREAD_START); } bool TacosThread::isRunning() @@ -70,6 +72,8 @@ namespace sta // The thread has to wait until the startup has been completed. rtos::waitForStartupEvent(); + // wait(THREAD_START) + init(); // Run the thread until the termination flag is set.