#ifndef FREERTOS_CPP_TASK_STORAGE_HPP #define FREERTOS_CPP_TASK_STORAGE_HPP #include #include #include extern "C" { #include "FreeRTOS.h" #include "task.h" } #ifndef FREERTOS_STORAGE_CHECKPOINT #define FREERTOS_STORAGE_CHECKPOINT( point, object ) \ do \ { \ ( void ) ( point ); \ ( void ) ( object ); \ } while( 0 ) #endif namespace freertos { enum class StorageTaskState : uint8_t { constructed, ready, running, completed, start_failed }; template< typename Derived > class DynamicTask { public: constexpr DynamicTask( const char * name, configSTACK_DEPTH_TYPE stack_words, UBaseType_t priority ) noexcept : name_ { name }, stack_words_ { stack_words }, priority_ { priority } { } DynamicTask( const DynamicTask & ) = delete; DynamicTask & operator=( const DynamicTask & ) = delete; DynamicTask( DynamicTask && ) = delete; DynamicTask & operator=( DynamicTask && ) = delete; bool start() noexcept { static_assert( std::is_base_of< DynamicTask< Derived >, Derived >::value ); if( state_ != StorageTaskState::constructed ) { return false; } state_ = StorageTaskState::ready; const BaseType_t result = xTaskCreate( &DynamicTask::trampoline, name_, stack_words_, static_cast< Derived * >( this ), priority_, &handle_ ); if( result != pdPASS ) { handle_ = nullptr; state_ = StorageTaskState::start_failed; return false; } FREERTOS_STORAGE_CHECKPOINT( 2U, this ); return true; } TaskHandle_t native_handle() const noexcept { return handle_; } StorageTaskState state() const noexcept { return state_; } private: static void trampoline( void * context ) { auto * const derived = static_cast< Derived * >( context ); auto & base = *static_cast< DynamicTask * >( derived ); base.state_ = StorageTaskState::running; FREERTOS_STORAGE_CHECKPOINT( 5U, derived ); derived->run(); base.state_ = StorageTaskState::completed; base.handle_ = nullptr; FREERTOS_STORAGE_CHECKPOINT( 7U, derived ); vTaskDelete( nullptr ); for( ;; ) {} } TaskHandle_t handle_ {}; const char * const name_; const configSTACK_DEPTH_TYPE stack_words_; const UBaseType_t priority_; volatile StorageTaskState state_ { StorageTaskState::constructed }; }; template< size_t StackWords > struct StaticTaskStorage final { StaticTask_t tcb {}; StackType_t stack[ StackWords ] {}; }; template< typename Derived, size_t StackWords > class StaticTask { public: static_assert( StackWords > 0U, "static task needs stack storage" ); constexpr StaticTask( const char * name, UBaseType_t priority, StaticTaskStorage< StackWords > & storage ) noexcept : name_ { name }, priority_ { priority }, storage_ { storage } { } StaticTask( const StaticTask & ) = delete; StaticTask & operator=( const StaticTask & ) = delete; StaticTask( StaticTask && ) = delete; StaticTask & operator=( StaticTask && ) = delete; bool start() noexcept { static_assert( std::is_base_of< StaticTask< Derived, StackWords >, Derived >::value ); if( state_ != StorageTaskState::constructed ) { return false; } state_ = StorageTaskState::ready; handle_ = xTaskCreateStatic( &StaticTask::trampoline, name_, static_cast< configSTACK_DEPTH_TYPE >( StackWords ), static_cast< Derived * >( this ), priority_, storage_.stack, &storage_.tcb ); if( handle_ == nullptr ) { state_ = StorageTaskState::start_failed; return false; } FREERTOS_STORAGE_CHECKPOINT( 4U, this ); return true; } TaskHandle_t native_handle() const noexcept { return handle_; } StorageTaskState state() const noexcept { return state_; } const StaticTask_t * tcb_storage() const noexcept { return &storage_.tcb; } const StackType_t * stack_storage() const noexcept { return storage_.stack; } static constexpr size_t stack_words() noexcept { return StackWords; } static constexpr size_t stack_bytes() noexcept { return StackWords * sizeof( StackType_t ); } private: static void trampoline( void * context ) { auto * const derived = static_cast< Derived * >( context ); auto & base = *static_cast< StaticTask * >( derived ); base.state_ = StorageTaskState::running; FREERTOS_STORAGE_CHECKPOINT( 6U, derived ); derived->run(); base.state_ = StorageTaskState::completed; base.handle_ = nullptr; FREERTOS_STORAGE_CHECKPOINT( 8U, derived ); vTaskDelete( nullptr ); for( ;; ) {} } TaskHandle_t handle_ {}; const char * const name_; const UBaseType_t priority_; StaticTaskStorage< StackWords > & storage_; volatile StorageTaskState state_ { StorageTaskState::constructed }; }; } // namespace freertos #endif