diff --git a/include/sta/tacos/thread.hpp b/include/sta/tacos/thread.hpp index 391bfdf..94b8aaf 100644 --- a/include/sta/tacos/thread.hpp +++ b/include/sta/tacos/thread.hpp @@ -10,6 +10,7 @@ #include +#include #include /** @@ -22,6 +23,7 @@ namespace sta { namespace tacos { +#ifdef STA_TACOS_WATCHDOG_ENABLED /** * @brief A status flags for the watchdog. * @@ -60,6 +62,7 @@ namespace sta */ WAITING }; +#endif // STA_TACOS_WATCHDOG_ENABLED /** * @brief Abstract class for thread implementations in Tacos. @@ -81,31 +84,11 @@ namespace sta 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. - * - * @return The currently running instance id. - */ - osThreadId_t getInstance(); - - /** - * @brief Get the name of this thread. - */ - const char* getName() const; - - /** - * @brief Compare two threads by their names. - */ bool operator==(const TacosThread& other) const; /** @@ -113,11 +96,7 @@ namespace sta */ 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(); + void loop() override; /** * @brief This function is executed first when this thread is started. @@ -136,15 +115,23 @@ namespace sta */ virtual void cleanup(); + /** + * @brief Sleep for a given number of ticks. Sets itself to WAITING if the watchdog is enabled, preventing + * the watchdog from restarting this thread. + * + * @param ticks + */ + void sleep(uint32_t ticks); + #ifdef STA_TACOS_WATCHDOG_ENABLED - /** - * @brief This macro wraps a given statement into waiting() and heartbeat() to make the code more readable. - * - */ - #define blocking(...) \ - waiting(); \ - __VA_ARGS__ \ - heartbeat(); \ + /** + * @brief This macro wraps a given statement into waiting() and heartbeat() to make the code more readable. + * + */ + #define blocking(...) \ + waiting(); \ + __VA_ARGS__ \ + heartbeat(); \ protected: /** @@ -173,12 +160,22 @@ namespace sta void resetStatus(); #endif // STA_TACOS_WATCHDOG_ENABLED - private: /** - * @brief Static function to pass to RTOS to run as a thread. Calls the loop function implemented here. + * @brief Send termination request to thread. */ - static void entry_point(void* arg); + void requestTermination(); + /** + * @brief Clear the termination request flag for this thread. + */ + void deleteTerminationRequest(); + + /** + * @brief Resets the terminate bool to false. + * + * @return Returns the previous value of this variable. + */ + bool isTerminationRequested(); private: osThreadId_t instance_; osThreadAttr_t attribs_; @@ -186,6 +183,7 @@ namespace sta #ifdef STA_TACOS_WATCHDOG_ENABLED ThreadStatus status_; #endif // STA_TACOS_WATCHDOG_ENABLED + bool terminate_; }; } } diff --git a/include/sta/tacos/watchdog.hpp b/include/sta/tacos/watchdog.hpp index cae13e8..5953c57 100644 --- a/include/sta/tacos/watchdog.hpp +++ b/include/sta/tacos/watchdog.hpp @@ -46,6 +46,13 @@ namespace sta } void func() override; + + /** + * @brief Get the number of thread restarts during the program's runtime. + * + * @return uint16_t The number of thread restarts. + */ + uint16_t getNumRestarts(); private: static Watchdog* _instance; @@ -62,9 +69,13 @@ namespace sta } }; - Watchdog(const Watchdog&); + Watchdog(); - Watchdog(); + Watchdog(const Watchdog&); + + ~Watchdog() {} + private: + uint16_t restarts_; }; } // namespace tacos } // namespace sta diff --git a/src/thread.cpp b/src/thread.cpp index 0cef749..64b967d 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -25,64 +25,19 @@ namespace sta attribs_{ .name=name, .cb_size=cb_size, .stack_size=stack_size, .priority=prio }, running_{false}, #ifdef STA_TACOS_WATCHDOG_ENABLED - , status_{ThreadStatus::STOPPED} + , status_{ThreadStatus::STOPPED}, #endif // STA_TACOS_WATCHDOG_ENABLED + terminate_{false} { STA_ASSERT(stack_size >= 0); STA_ASSERT(cb_size >= 0); } - TacosThread::TacosThread() - : RtosThread(RtosHandle(Handle::Deferred(&instance_))), - instance_{ NULL }, - attribs_{ }, - running_{false} -#ifdef STA_TACOS_WATCHDOG_ENABLED - , status_{ThreadStatus::STOPPED} -#endif // STA_TACOS_WATCHDOG_ENABLED - {} - - void TacosThread::entry_point(void* arg) - { - STA_ASSERT(arg != nullptr); - - TacosThread* instance = reinterpret_cast(arg) ; - instance->loop(); - } - - void TacosThread::start() - { - STA_ASSERT(!isRunning()); - - // If this is the first time starting the thread, it has to be started via rtos first. - if (instance_ == NULL) - { - instance_ = osThreadNew(entry_point, this, &attribs_); - - STA_ASSERT(instance_ != NULL); - } - - // Send a thread start signal. - sysNotify(STA_RTOS_THREAD_FLAG_START); - } - bool TacosThread::isRunning() { return running_; } - osThreadId_t TacosThread::getInstance() - { - STA_ASSERT(isRunning()); - - return instance_; - } - - const char* TacosThread::getName() const - { - return attribs_.name; - } - void TacosThread::init() {} void TacosThread::loop() @@ -128,6 +83,19 @@ namespace sta void TacosThread::cleanup() {} + void TacosThread::sleep(uint32_t ticks) + { +#ifdef STA_TACOS_WATCHDOG_ENABLED + waiting(); +#endif // STA_TACOS_WATCHDOG_ENABLED + + osDelay(ticks); + +#ifdef STA_TACOS_WATCHDOG_ENABLED + heartbeat(); +#endif // STA_TACOS_WATCHDOG_ENABLED + } + #ifdef STA_TACOS_WATCHDOG_ENABLED void TacosThread::heartbeat() { @@ -150,6 +118,21 @@ namespace sta } #endif // STA_TACOS_WATCHDOG_ENABLED + void TacosThread::requestTermination() + { + terminate_ = true; + } + + void TacosThread::deleteTerminationRequest() + { + terminate_ = false; + } + + bool TacosThread::isTerminationRequested() + { + return terminate_; + } + bool TacosThread::operator==(const TacosThread& other) const { return std::strcmp(this->getName(), other.getName()) == 0; diff --git a/src/watchdog.cpp b/src/watchdog.cpp index f82fa89..2550893 100644 --- a/src/watchdog.cpp +++ b/src/watchdog.cpp @@ -15,23 +15,31 @@ namespace sta switch (thread->getStatus()) { case ThreadStatus::UNKNOWN: - // TODO: Try to restart the thread. + // Restart the thread. + thread->kill(); + thread->start(); + + restarts_++; break; case ThreadStatus::RUNNING: // Set the thread's status back to UNKNOWN. thread->resetStatus(); break; - default: break; } - - sleep(STA_TACOS_WATCHDOG_FREQUENCY); } + sleep(STA_TACOS_WATCHDOG_FREQUENCY); + } + + uint16_t Watchdog::getNumRestarts() + { + return restarts_; } Watchdog::Watchdog() - : TacosThread{"Watchdog", STA_TACOS_WATCHDOG_PRIORITY} + : TacosThread{"Watchdog", STA_TACOS_WATCHDOG_PRIORITY}, + restarts_{ 0 } {} Watchdog* Watchdog::_instance = nullptr;