From 344d7f402461d9b128ef267665d6731b84b40c22 Mon Sep 17 00:00:00 2001 From: dario Date: Fri, 22 Sep 2023 15:07:15 +0200 Subject: [PATCH] Added reworked manager / statemachine tasks, thread implementation and new directory layout --- .cproject | 12 ++- App/Inc/sta/config.hpp | 5 ++ App/Inc/tasks/statemachine.hpp | 13 ++++ App/Src/tasks/manager.cpp | 68 +++++++++++----- App/Src/tasks/statemachine.cpp | 4 +- Tacos/include/sta/tacos/manager.hpp | 86 ++++++++++++++++++++ Tacos/include/sta/tacos/startup.hpp | 31 ++++++++ Tacos/include/sta/tacos/statemachine.hpp | 73 +++++++++++++++++ Tacos/include/sta/tacos/thread.hpp | 78 +++++++++++++++++++ Tacos/src/manager.cpp | 99 ++++++++++++++++++++++++ Tacos/src/startup.cpp | 91 ++++++++++++++++++++++ Tacos/src/statemachine.cpp | 32 ++++++++ Tacos/src/thread.cpp | 86 ++++++++++++++++++++ 13 files changed, 652 insertions(+), 26 deletions(-) create mode 100644 Tacos/include/sta/tacos/manager.hpp create mode 100644 Tacos/include/sta/tacos/startup.hpp create mode 100644 Tacos/include/sta/tacos/statemachine.hpp create mode 100644 Tacos/include/sta/tacos/thread.hpp create mode 100644 Tacos/src/manager.cpp create mode 100644 Tacos/src/startup.cpp create mode 100644 Tacos/src/statemachine.cpp create mode 100644 Tacos/src/thread.cpp diff --git a/.cproject b/.cproject index 97a996a..528a81e 100644 --- a/.cproject +++ b/.cproject @@ -54,6 +54,7 @@ + @@ -77,6 +78,7 @@ + @@ -100,10 +102,11 @@ - - + + + @@ -197,10 +200,10 @@ - - + + @@ -228,4 +231,5 @@ + \ No newline at end of file diff --git a/App/Inc/sta/config.hpp b/App/Inc/sta/config.hpp index 9db0927..f132634 100644 --- a/App/Inc/sta/config.hpp +++ b/App/Inc/sta/config.hpp @@ -27,4 +27,9 @@ #define STA_RTOS_SYSTEM_WATCHDOG_ENABLE #define STA_RTOS_WATCHDOG_ENABLE + +// Settings for TACOS +#define STA_TACOS_MANAGER_PRIORITY osPriorityNormal +#define STA_TACOS_NUM_STATES 4 + #endif /* INC_STA_CONFIG_HPP_ */ diff --git a/App/Inc/tasks/statemachine.hpp b/App/Inc/tasks/statemachine.hpp index e045353..0adc089 100644 --- a/App/Inc/tasks/statemachine.hpp +++ b/App/Inc/tasks/statemachine.hpp @@ -29,4 +29,17 @@ enum tacos_states_t }; +namespace tacos +{ + class StateMachine + { + public: + + + private: + + }; +} + + #endif /* INC_TASKS_STATEMACHINE_HPP_ */ diff --git a/App/Src/tasks/manager.cpp b/App/Src/tasks/manager.cpp index 868f51b..8a286b0 100644 --- a/App/Src/tasks/manager.cpp +++ b/App/Src/tasks/manager.cpp @@ -6,42 +6,70 @@ */ +#include +#include + #include #include #include #include -#include -#include + #include +#include -#define STATE_CHANGED_MSK 0x01 -#define STATE_CHANGED_TIMOUT_MSK 0x02 -// The state changed event defined somewhere else. -extern osEventFlagsId_t stateChangeEvent_id; +namespace tacos +{ + + // The data structure representing a TACOS task. + struct tacos_task_t + { + // The code to be executed for this task. + osThreadFunc_t func; + + // The attributes for the task. + osThreadAttr_t attribs; + + // A list of currently running instances of this task. + std::list running; + + // A list of states for which this task should be running. + std::list states; + }; + + +} // namespace tacos + // The current state defined somewhere else. extern tacos_states_t currentState; -// The data structure representing a TACOS task. -struct tacos_task_t +extern "C" { - // The code to be executed for this task. - osThreadFunc_t func; + void managerTask(void *) + { + STA_DEBUG_PRINTLN("INITIALIZED MANAGER TASK"); + + while (true) + { + // Wait until the state machine triggers an event signaling a state-change. + uint32_t flags = osEventFlagsWait(stateChangeEvent_id, STATE_CHANGED_MSK, osFlagsWaitAll, osWaitForever); + + + } + } +} + + + + - // The attributes for the task. - osThreadAttr_t attribs; - // A list of currently running instances of this task. - std::list running; - // A list of states for which this task should be running. - std::list states; -}; std::list tasks; @@ -111,12 +139,12 @@ extern "C" void startManagerTask(void *) { if (!task.running.empty()) { - osThreadCreate(thread_def, argument); + osThreadDef (task.attribs.name, task.attribs.priority, 1, 0); + + osThreadCreate(osTh, argument); } } } - - STA_DEBUG_PRINTLN("STARTING NEW TASKS DUE TO STATE CHANGE!"); } osThreadExit(); diff --git a/App/Src/tasks/statemachine.cpp b/App/Src/tasks/statemachine.cpp index e3326bb..e06e9c4 100644 --- a/App/Src/tasks/statemachine.cpp +++ b/App/Src/tasks/statemachine.cpp @@ -46,8 +46,8 @@ void changeState(uint8_t flag) osEventFlagsSet(stateChangeEvent_id, flag); osEventFlagsClear(stateChangeEvent_id, TACOS_STATE_CHG_ALL); - uint8_t lockoutCycles = 0; - uint8_t failsafeCycles = 0; + uint32_t lockoutCycles = 0; + uint32_t failsafeCycles = 0; switch (currentState) { case tacos_states_t::init: diff --git a/Tacos/include/sta/tacos/manager.hpp b/Tacos/include/sta/tacos/manager.hpp new file mode 100644 index 0000000..3de94c7 --- /dev/null +++ b/Tacos/include/sta/tacos/manager.hpp @@ -0,0 +1,86 @@ +/* + * manager.hpp + * + * Created on: Sep 19, 2023 + * Author: Dario + */ + +#ifndef INCLUDE_STA_TACOS_MANAGER_HPP_ +#define INCLUDE_STA_TACOS_MANAGER_HPP_ + + +#include + +#ifndef STA_TACOS_MANAGER_PRIORITY +# error "Manger task priority not specified in config.hpp" +#else + +#include +#include +#include + +namespace sta +{ + namespace tacos + { + class Manager : public TacosThread + { + public: + static Manager* instance() + { + static CGuard g; + + if (!_instance) + { + // Create a the manager singleton instance. + Manager::_instance = new Manager(); + + // Start the manager task as a tacos task. + Manager::_instance->start(); + } + + return _instance; + } + + void registerThread(TacosThread thread, std::list states); + + void init() override; + + void func() override; + + private: + class CGuard + { + public: + ~CGuard() + { + if( NULL != Manager::_instance ) + { + delete Manager::_instance; + Manager::_instance = NULL; + } + } + }; + + static Manager* _instance; + + Manager(); + + Manager(const Manager&); + + ~Manager() {} + + void updateThreads(); + + void startThreads(uint16_t state); + + void stopThreads(uint16_t state); + + std::set threads_[STA_TACOS_NUM_STATES]; + }; + } // namespace tacos +} // namespace sta + +#endif // STA_TACOS_MANAGER_PRIORITY + +#endif /* INCLUDE_STA_TACOS_MANAGER_HPP_ */ diff --git a/Tacos/include/sta/tacos/startup.hpp b/Tacos/include/sta/tacos/startup.hpp new file mode 100644 index 0000000..f108f85 --- /dev/null +++ b/Tacos/include/sta/tacos/startup.hpp @@ -0,0 +1,31 @@ +/* + * startup.hpp + * + * Created on: 22 Sep 2023 + * Author: Dario + */ + +#ifndef INCLUDE_STA_TACOS_STARTUP_HPP_ +#define INCLUDE_STA_TACOS_STARTUP_HPP_ + +namespace sta +{ + namespace tacos + { + /** + * @brief Function that is called before the statemachine task is started. + * Override it to adjust the statemachine to your specifications. + */ + void onStatemachineInit(); + + /** + * @brief Function that is called before the manager task is started. + * Override it to adjust the manager to your specifications. + */ + void onManagerInit(); + } // namespace tacos +} // namespace sta + + + +#endif /* INCLUDE_STA_TACOS_STARTUP_HPP_ */ diff --git a/Tacos/include/sta/tacos/statemachine.hpp b/Tacos/include/sta/tacos/statemachine.hpp new file mode 100644 index 0000000..363776b --- /dev/null +++ b/Tacos/include/sta/tacos/statemachine.hpp @@ -0,0 +1,73 @@ +/* + * statemachine.hpp + * + * Created on: Sep 14, 2023 + * Author: Dario + */ + +#ifndef INCLUDE_TACOS_STATEMACHINE_HPP_ +#define INCLUDE_TACOS_STATEMACHINE_HPP_ + +#include + +#include + +namespace sta +{ + namespace tacos + { + class Statemachine : public TacosThread + { + public: + static Statemachine* instance() + { + static CGuard g; + + if (!_instance) + { + // Create a the manager singleton instance. + Statemachine::_instance = new Statemachine(); + + // Start the manager task as a tacos task. + Statemachine::_instance->start(); + } + + return _instance; + } + + void init() override; + + void func() override; + + uint16_t getCurrentState(); + + private: + class CGuard + { + public: + ~CGuard() + { + if( NULL != Statemachine::_instance ) + { + delete Statemachine::_instance; + Statemachine::_instance = NULL; + } + } + }; + + Statemachine(); + + Statemachine(const Statemachine&); + + ~Statemachine() {} + + static Statemachine * _instance; + + uint16_t currentState_; + }; + } // namespace tacos +} // namespace sta + + + +#endif /* INCLUDE_TACOS_STATEMACHINE_HPP_ */ diff --git a/Tacos/include/sta/tacos/thread.hpp b/Tacos/include/sta/tacos/thread.hpp new file mode 100644 index 0000000..94d1a1a --- /dev/null +++ b/Tacos/include/sta/tacos/thread.hpp @@ -0,0 +1,78 @@ +/* + * task.hpp + * + * Created on: Sep 14, 2023 + * Author: Dario + */ + +#ifndef INCLUDE_TACOS_TASK_HPP_ +#define INCLUDE_TACOS_TASK_HPP_ + +#include + +#include + + +namespace sta +{ + namespace tacos + { + class TacosThread : public RtosThread + { + public: + /** + * + */ + TacosThread(const char* name, osPriority_t prio); + + virtual ~TacosThread(); + + /** + * @brief Start the execution of this thread. + */ + void start(); + + /** + * @brief Checks if this thread is currently running. + */ + bool isRunning(); + + /** + * @brief Get the currently running instance. + */ + osThreadId_t getInstance(); + + /** + * + */ + const char* getName() const; + + bool operator==(const TacosThread& other) const; + bool operator<(const TacosThread& other) const; + + /** + * @brief A function that wraps this task's functionality in a loop. This loop will run until + * termination is requested. + */ + void loop(); + + virtual void init(); + + /** + * @brief The body of the thread's loop. Has to be implemented by the user. + */ + virtual void func(); + private: + /** + * @brief Static function to pass to RTOS to run as a thread. Calls the loop function implemented here. + */ + static void entry_point(void* arg); + + osThreadId_t instance_; + osThreadAttr_t attribs_; + }; + } +} + + +#endif /* INCLUDE_TACOS_TASK_HPP_ */ diff --git a/Tacos/src/manager.cpp b/Tacos/src/manager.cpp new file mode 100644 index 0000000..f95054f --- /dev/null +++ b/Tacos/src/manager.cpp @@ -0,0 +1,99 @@ +/* + * manager.cpp + * + * Created on: Sep 19, 2023 + * Author: Dario + */ + +#include +#include + + +namespace sta +{ + namespace tacos + { + void Manager::registerThread(TacosThread thread, std::list states) + { + for (uint16_t state : states) + { + STA_ASSERT(state < STA_TACOS_NUM_STATES); + + threads_[state].emplace(thread); + } + } + + void Manager::startThreads(uint16_t state) + { + STA_ASSERT(state < STA_TACOS_NUM_STATES); + + for (TacosThread thread : threads_[state]) + { + if (!thread.isRunning()) + { + thread.start(); + } + } + } + + void Manager::stopThreads(uint16_t state) + { + uint16_t currentState = Statemachine::instance()->getCurrentState(); + + for (uint16_t state = 0; state < STA_TACOS_NUM_STATES; ++state) + { + if (state == currentState) + { + continue; + } + + for (TacosThread thread : threads_[state]) + { + // If the thread is currently running but not part of the set of threads that should be running... + if (thread.isRunning() && threads_[currentState].count(thread) == 0) + { + // ...politely request termination. + thread.requestTermination(); + } + } + } + } + + void Manager::updateThreads() + { + uint16_t state = Statemachine::instance()->getCurrentState(); + + startThreads(state); + stopThreads(state); + } + + void Manager::init() + { + startThreads(Statemachine::instance()->getCurrentState()); + } + + void Manager::func() + { + // Wait for either the termination request or the state change flag. + uint32_t flags = osEventFlagsWait(getInstance(), STA_RTOS_THREAD_FLAG_TERMINATE, osFlagsWaitAny, osWaitForever); + + if ((flags & STA_RTOS_THREAD_FLAG_TERMINATE) != 0) + { + // The loop implemented by the TacosThread class should handle termination. + return; + } + + // Start all new tasks and stop all the tasks that aren't supposed to be running. + updateThreads(); + } + + Manager::Manager() + : TacosThread{"Manager", STA_TACOS_MANAGER_PRIORITY} + { + + } + + } // namespace tacos +} // namespace sta + + diff --git a/Tacos/src/startup.cpp b/Tacos/src/startup.cpp new file mode 100644 index 0000000..51e7670 --- /dev/null +++ b/Tacos/src/startup.cpp @@ -0,0 +1,91 @@ +/* + * startup.cpp + * + * Created on: 22 Sep 2023 + * Author: Dario + */ + + +#include +#include +#include + +// sta-core-specific imports. +#include +#include +#include +#include + +// Tacos-specific includes. +#include +#include +#include + + +// The UART mutex defined in freertos.c +extern osMutexId_t uartMutexHandle; + + +namespace sta +{ + // Here the printable used for debugging is defined. + Printable * Debug; + + namespace tacos + { + void initPrintable() + { + // Initialize the mutex for UART communication. + RtosMutex * mutex = new RtosMutex(&uartMutexHandle); + + // Initialize the UART interface and printable object. + UARTSettings settings = { .mode = UARTMode::RX_TX }; + STM32UART * intf_ptr = new STM32UART(&huart2, settings, mutex); + Debug = new PrintableUART(intf_ptr); + + STA_DEBUG_PRINTLN("UART SUCCESSFULLY INITIALIZED"); + } + + + STA_WEAK + void onStatemachineInit() + {} + + + void initStatemachine() + { + onStatemachineInit(); + + Statemachine::instance()->start(); + } + + + STA_WEAK + void onManagerInit() + {} + + + void initManager() + { + onManagerInit(); + + Statemachine::instance()->start(); + } + } // namespace tacos + + + namespace rtos + { + // Override the weak implementation of startupExtras provided in rtos2-utils. + void startupExtras(void * argument) + { + tacos::initPrintable(); + + tacos::initStatemachine(); + + tacos::initManager(); + } + } // namespace rtos +} // namespace sta + + diff --git a/Tacos/src/statemachine.cpp b/Tacos/src/statemachine.cpp new file mode 100644 index 0000000..9388863 --- /dev/null +++ b/Tacos/src/statemachine.cpp @@ -0,0 +1,32 @@ +/* + * statemachine.cpp + * + * Created on: 21 Sep 2023 + * Author: Dario + */ + +#include + +namespace sta +{ + namespace tacos + { + void Statemachine::init() + { + + } + + void Statemachine::func() + { + + } + + uint16_t Statemachine::getCurrentState() + { + return currentState_; + } + } // namespace tacos +} // namespace sta + + + diff --git a/Tacos/src/thread.cpp b/Tacos/src/thread.cpp new file mode 100644 index 0000000..4a8e94b --- /dev/null +++ b/Tacos/src/thread.cpp @@ -0,0 +1,86 @@ +/* + * thread.cpp + * + * Created on: Sep 14, 2023 + * Author: Dario + */ + + +#include +#include + +#include +#include + + +namespace sta +{ + namespace tacos + { + TacosThread::TacosThread(const char* name, osPriority_t prio) + : RtosThread(RtosHandle(Handle::Deferred(&instance_))), + attribs_{ .name = name, .priority = prio } + { + + } + + static void entry_point(void* arg) + { + STA_ASSERT(arg != nullptr); + + TacosThread* instance = reinterpret_cast(arg) ; + instance->loop(); + } + + void TacosThread::start() + { + STA_ASSERT(!isRunning()); + + instance_ = osThreadNew(entry_point, this, &attribs_); + + STA_ASSERT(instance_ != NULL); + } + + bool TacosThread::isRunning() + { + return instance_ != NULL; + } + + osThreadId_t TacosThread::getInstance() + { + STA_ASSERT(isRunning()); + + return instance_; + } + + const char* TacosThread::getName() const + { + return attribs_.name; + } + + void TacosThread::loop() + { + init(); + + while ((osEventFlagsGet(instance_) & STA_RTOS_THREAD_FLAG_TERMINATE) == 0) + { + func(); + } + + instance_ = NULL; + + osThreadExit(); + } + + bool TacosThread::operator==(const TacosThread& other) const + { + return std::strcmp(this->getName(), other.getName()) == 0; + } + + bool TacosThread::operator<(const TacosThread& other) const + { + return std::strcmp(this->getName(), other.getName()) < 0; + } + } // namespace tacos +} // namespace sta +