From 43c78c69d8f5574e688a0e279b180d536d24b9bb Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Mon, 13 Jan 2025 20:20:43 +0100 Subject: [PATCH] Thread, Timer and flash.sh improvements (#165) - Various improvements to Thread and Timer: - Remove "mark as static" option as it is unused - Implemented core pinning for ESP32 platforms - Use `TickType_t` consistently (instead of `uint32_t`) - Use `enum class` instead of `enum` - Fix for `flash.sh` not working when using `pip` to install `esptool` --- Boards/LilygoTdeck/Source/Lvgl.cpp | 2 +- Boards/M5stackCore2/Source/InitLvgl.cpp | 2 +- Boards/M5stackCoreS3/Source/InitLvgl.cpp | 2 +- Boards/Simulator/Source/LvglTask.cpp | 2 +- Boards/Simulator/Source/Main.cpp | 2 +- Boards/YellowBoard/Source/Lvgl.cpp | 2 +- Buildscripts/Flashing/flash.sh | 31 ++++-- Documentation/ideas.md | 5 +- TactilityC/Source/tt_init.cpp | 2 - TactilityC/Source/tt_thread.cpp | 8 -- TactilityC/Source/tt_thread.h | 18 ++-- TactilityC/Source/tt_timer.cpp | 4 +- TactilityC/Source/tt_timer.h | 8 +- TactilityCore/Source/DispatcherThread.cpp | 2 +- TactilityCore/Source/Thread.cpp | 121 ++++++++++------------ TactilityCore/Source/Thread.h | 80 +++++--------- TactilityCore/Source/Timer.cpp | 26 ++--- TactilityCore/Source/Timer.h | 22 ++-- Tests/TactilityCore/MutexTest.cpp | 4 +- Tests/TactilityCore/ThreadTest.cpp | 6 +- 20 files changed, 151 insertions(+), 198 deletions(-) diff --git a/Boards/LilygoTdeck/Source/Lvgl.cpp b/Boards/LilygoTdeck/Source/Lvgl.cpp index 3f012424..e9fb8acc 100644 --- a/Boards/LilygoTdeck/Source/Lvgl.cpp +++ b/Boards/LilygoTdeck/Source/Lvgl.cpp @@ -14,7 +14,7 @@ bool tdeck_init_lvgl() { static lv_disp_t* display = nullptr; const lvgl_port_cfg_t lvgl_cfg = { - .task_priority = tt::THREAD_PRIORITY_RENDER, + .task_priority = static_cast(tt::THREAD_PRIORITY_RENDER), .task_stack = TDECK_LVGL_TASK_STACK_DEPTH, .task_affinity = -1, // core pinning .task_max_sleep_ms = 500, diff --git a/Boards/M5stackCore2/Source/InitLvgl.cpp b/Boards/M5stackCore2/Source/InitLvgl.cpp index dd362b62..0d4aed8d 100644 --- a/Boards/M5stackCore2/Source/InitLvgl.cpp +++ b/Boards/M5stackCore2/Source/InitLvgl.cpp @@ -12,7 +12,7 @@ bool initLvgl() { const lvgl_port_cfg_t lvgl_cfg = { - .task_priority = tt::THREAD_PRIORITY_RENDER, + .task_priority = static_cast(tt::THREAD_PRIORITY_RENDER), .task_stack = CORE2_LVGL_TASK_STACK_DEPTH, .task_affinity = -1, // core pinning .task_max_sleep_ms = 500, diff --git a/Boards/M5stackCoreS3/Source/InitLvgl.cpp b/Boards/M5stackCoreS3/Source/InitLvgl.cpp index dd362b62..0d4aed8d 100644 --- a/Boards/M5stackCoreS3/Source/InitLvgl.cpp +++ b/Boards/M5stackCoreS3/Source/InitLvgl.cpp @@ -12,7 +12,7 @@ bool initLvgl() { const lvgl_port_cfg_t lvgl_cfg = { - .task_priority = tt::THREAD_PRIORITY_RENDER, + .task_priority = static_cast(tt::THREAD_PRIORITY_RENDER), .task_stack = CORE2_LVGL_TASK_STACK_DEPTH, .task_affinity = -1, // core pinning .task_max_sleep_ms = 500, diff --git a/Boards/Simulator/Source/LvglTask.cpp b/Boards/Simulator/Source/LvglTask.cpp index d023bbcf..e0189cf2 100644 --- a/Boards/Simulator/Source/LvglTask.cpp +++ b/Boards/Simulator/Source/LvglTask.cpp @@ -65,7 +65,7 @@ void lvgl_task_start() { "lvgl", 8192, nullptr, - tt::Thread::PriorityHigh, // Should be higher than main app task + static_cast(tt::Thread::Priority::High), // Should be higher than main app task nullptr ); diff --git a/Boards/Simulator/Source/Main.cpp b/Boards/Simulator/Source/Main.cpp index bd559e39..a93fb1ed 100644 --- a/Boards/Simulator/Source/Main.cpp +++ b/Boards/Simulator/Source/Main.cpp @@ -29,7 +29,7 @@ void freertosMain() { "main", 8192, nullptr, - tt::Thread::PriorityNormal, + static_cast(tt::Thread::Priority::Normal), nullptr ); diff --git a/Boards/YellowBoard/Source/Lvgl.cpp b/Boards/YellowBoard/Source/Lvgl.cpp index eae5c552..ab8983c7 100644 --- a/Boards/YellowBoard/Source/Lvgl.cpp +++ b/Boards/YellowBoard/Source/Lvgl.cpp @@ -7,7 +7,7 @@ bool twodotfour_lvgl_init() { const lvgl_port_cfg_t lvgl_cfg = { - .task_priority = tt::THREAD_PRIORITY_RENDER, + .task_priority = static_cast(tt::THREAD_PRIORITY_RENDER), .task_stack = 8096, .task_affinity = -1, // core pinning .task_max_sleep_ms = 500, diff --git a/Buildscripts/Flashing/flash.sh b/Buildscripts/Flashing/flash.sh index 084a558f..fa0f2897 100755 --- a/Buildscripts/Flashing/flash.sh +++ b/Buildscripts/Flashing/flash.sh @@ -21,22 +21,35 @@ function is_bin_in_path { function require_bin { program=$1 - tip=$2 if ! is_bin_in_path $program; then - echo -e "\e[31m⚠️ $program not found!\n\t$tip\e[0m" + exit 1 + else + exit 0 fi } -require_bin esptool.py "install esptool from your package manager or install python and run 'pip install esptool'" -require_bin jq "install jq from your package manager or install python and run 'pip install jq'" +# Find either esptool (installed via system package manager) or esptool.py (installed via pip) +if ! is_bin_in_path esptool; then + if ! is_bin_in_path esptool.py; then + echo "\e[31m⚠️ esptool not found! Install it from your package manager or install python and run 'pip install esptool'\e[0m" + exit 1 + else + esptoolPath=esptool.py + fi +else + esptoolPath=esptool +fi -if [[ $1 -eq 0 ]]; then +# Ensure the port was specified +if [ -z "$1" ]; then echo -e "\e[31m⚠️ Must Specify port as argument. For example:\n\tflash.sh /dev/ttyACM0\n\tflash.sh /dev/ttyUSB0\e[0m" exit -1 fi +# Take the flash_arg file contents and join each line in the file into a single line +flash_args=`grep \n Binaries/flash_args | awk '{print}' ORS=' '` cd Binaries -# Create flash command based on partitions -KEY_VALUES=`jq -r '.flash_files | keys[] as $k | "\($k) \(.[$k])"' flasher_args.json | tr "\n" " "` -esptool.py --port $1 erase_flash -esptool.py --port $1 --connect-attempts 10 -b 460800 write_flash $KEY_VALUES +$esptoolPath --port $1 erase_flash +$esptoolPath --port $1 write_flash $flash_args +cd - + diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 56804e08..3109432d 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -28,12 +28,9 @@ - Attach ELF data to wrapper app (as app data) (check that app state is "running"!) so you can run more than 1 external apps at a time. We'll need to keep track of all manifest instances, so that the wrapper can look up the relevant manifest for the relevant callbacks. - T-Deck: Clear screen before turning on blacklight -- Audio player app -- Audio recording app - T-Deck: Use knob for UI selection - Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state) - AppContext's onResult should pass the app id (or launch request id!) that was started, so we can differentiate between multiple types of apps being launched -- Loader: Use main dispatcher instead of Thread - Create more unit tests for `tactility-core` and `tactility` (PC-only for now) - Show a warning screen if firmware encryption or secure boot are off when saving WiFi credentials. - Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot. @@ -45,6 +42,8 @@ - Support hot-plugging SD card # Nice-to-haves +- Audio player app +- Audio recording app - OTA updates - Web flasher - T-Deck Plus: Create separate board config? diff --git a/TactilityC/Source/tt_init.cpp b/TactilityC/Source/tt_init.cpp index 36564048..5a7828da 100644 --- a/TactilityC/Source/tt_init.cpp +++ b/TactilityC/Source/tt_init.cpp @@ -74,8 +74,6 @@ const struct esp_elfsym elf_symbols[] { ESP_ELFSYM_EXPORT(tt_thread_alloc_ext), ESP_ELFSYM_EXPORT(tt_thread_free), ESP_ELFSYM_EXPORT(tt_thread_set_name), - ESP_ELFSYM_EXPORT(tt_thread_mark_as_static), - ESP_ELFSYM_EXPORT(tt_thread_is_marked_as_static), ESP_ELFSYM_EXPORT(tt_thread_set_stack_size), ESP_ELFSYM_EXPORT(tt_thread_set_callback), ESP_ELFSYM_EXPORT(tt_thread_set_priority), diff --git a/TactilityC/Source/tt_thread.cpp b/TactilityC/Source/tt_thread.cpp index 1263c4fb..ae87d46d 100644 --- a/TactilityC/Source/tt_thread.cpp +++ b/TactilityC/Source/tt_thread.cpp @@ -31,14 +31,6 @@ void tt_thread_set_name(ThreadHandle handle, const char* name) { HANDLE_AS_THREAD(handle)->setName(name); } -void tt_thread_mark_as_static(ThreadHandle handle) { - HANDLE_AS_THREAD(handle)->markAsStatic(); -} - -bool tt_thread_is_marked_as_static(ThreadHandle handle) { - return HANDLE_AS_THREAD(handle)->isMarkedAsStatic(); -} - void tt_thread_set_stack_size(ThreadHandle handle, size_t size) { HANDLE_AS_THREAD(handle)->setStackSize(size); } diff --git a/TactilityC/Source/tt_thread.h b/TactilityC/Source/tt_thread.h index d21cc7e3..cb7164a3 100644 --- a/TactilityC/Source/tt_thread.h +++ b/TactilityC/Source/tt_thread.h @@ -38,14 +38,14 @@ typedef int32_t (*ThreadCallback)(void* context); typedef void (*ThreadStateCallback)(ThreadState state, void* context); typedef enum { - ThreadPriorityNone = 0, /**< Uninitialized, choose system default */ - ThreadPriorityIdle = 1, - ThreadPriorityLowest = 2, - ThreadPriorityLow = 3, - ThreadPriorityNormal = 4, - ThreadPriorityHigh = 5, - ThreadPriorityHigher = 6, - ThreadPriorityHighest = 7 + ThreadPriorityNone = 0U, /**< Uninitialized, choose system default */ + ThreadPriorityIdle = 1U, + ThreadPriorityLowest = 2U, + ThreadPriorityLow = 3U, + ThreadPriorityNormal = 4U, + ThreadPriorityHigh = 5U, + ThreadPriorityHigher = 6U, + ThreadPriorityHighest = 7U } ThreadPriority; ThreadHandle tt_thread_alloc(); @@ -57,8 +57,6 @@ ThreadHandle tt_thread_alloc_ext( ); void tt_thread_free(ThreadHandle handle); void tt_thread_set_name(ThreadHandle handle, const char* name); -void tt_thread_mark_as_static(ThreadHandle handle); -bool tt_thread_is_marked_as_static(ThreadHandle handle); void tt_thread_set_stack_size(ThreadHandle handle, size_t size); void tt_thread_set_callback(ThreadHandle handle, ThreadCallback callback, void* _Nullable callbackContext); void tt_thread_set_priority(ThreadHandle handle, ThreadPriority priority); diff --git a/TactilityC/Source/tt_timer.cpp b/TactilityC/Source/tt_timer.cpp index 533eb585..3d513f4d 100644 --- a/TactilityC/Source/tt_timer.cpp +++ b/TactilityC/Source/tt_timer.cpp @@ -58,8 +58,8 @@ bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback call ); } -void tt_timer_set_thread_priority(TimerHandle handle, TimerThreadPriority priority) { - ((TimerWrapper*)handle)->timer->setThreadPriority((tt::Timer::ThreadPriority)priority); +void tt_timer_set_thread_priority(TimerHandle handle, ThreadPriority priority) { + ((TimerWrapper*)handle)->timer->setThreadPriority((tt::Thread::Priority)priority); } } diff --git a/TactilityC/Source/tt_timer.h b/TactilityC/Source/tt_timer.h index 15b79047..8c1842ae 100644 --- a/TactilityC/Source/tt_timer.h +++ b/TactilityC/Source/tt_timer.h @@ -1,5 +1,6 @@ #pragma once +#include "tt_thread.h" #include #ifdef __cplusplus @@ -16,11 +17,6 @@ typedef enum { TimerTypePeriodic = 1 ///< Repeating timer. } TimerType; -typedef enum { - TimerThreadPriorityNormal, /**< Lower then other threads */ - TimerThreadPriorityElevated, /**< Same as other threads */ -} TimerThreadPriority; - typedef void (*TimerCallback)(void* context); typedef void (*TimerPendingCallback)(void* context, uint32_t arg); @@ -32,7 +28,7 @@ bool tt_timer_stop(TimerHandle handle); bool tt_timer_is_running(TimerHandle handle); uint32_t tt_timer_get_expire_time(TimerHandle handle); bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeoutTicks); -void tt_timer_set_thread_priority(TimerHandle handle, TimerThreadPriority priority); +void tt_timer_set_thread_priority(TimerHandle handle, ThreadPriority priority); #ifdef __cplusplus } diff --git a/TactilityCore/Source/DispatcherThread.cpp b/TactilityCore/Source/DispatcherThread.cpp index 09f92f5a..6186a095 100644 --- a/TactilityCore/Source/DispatcherThread.cpp +++ b/TactilityCore/Source/DispatcherThread.cpp @@ -18,7 +18,7 @@ DispatcherThread::DispatcherThread(const std::string& threadName, size_t threadS } DispatcherThread::~DispatcherThread() { - if (thread->getState() != Thread::StateStopped) { + if (thread->getState() != Thread::State::Stopped) { stop(); } } diff --git a/TactilityCore/Source/Thread.cpp b/TactilityCore/Source/Thread.cpp index 699cffbf..abaeb539 100644 --- a/TactilityCore/Source/Thread.cpp +++ b/TactilityCore/Source/Thread.cpp @@ -19,7 +19,7 @@ namespace tt { #define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U)) #define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U)) -static_assert(Thread::PriorityHighest <= TT_CONFIG_THREAD_MAX_PRIORITIES, "highest thread priority is higher than max priority"); +static_assert(static_cast(Thread::Priority::Critical) <= TT_CONFIG_THREAD_MAX_PRIORITIES, "highest thread priority is higher than max priority"); static_assert(TT_CONFIG_THREAD_MAX_PRIORITIES <= configMAX_PRIORITIES, "highest tactility priority is higher than max FreeRTOS priority"); void setState(Thread::Data* data, Thread::State state) { @@ -29,6 +29,8 @@ void setState(Thread::Data* data, Thread::State state) { } } +static_assert(configSUPPORT_DYNAMIC_ALLOCATION == 1); + /** Catch threads that are trying to exit wrong way */ __attribute__((__noreturn__)) void thread_catch() { //-V1082 // If you're here it means you're probably doing something wrong @@ -47,20 +49,12 @@ static void thread_body(void* context) { tt_assert(pvTaskGetThreadLocalStoragePointer(nullptr, 0) == nullptr); vTaskSetThreadLocalStoragePointer(nullptr, 0, data->thread); - tt_assert(data->state == Thread::StateStarting); - setState(data, Thread::StateRunning); + tt_assert(data->state == Thread::State::Starting); + setState(data, Thread::State::Running); data->callbackResult = data->callback(data->callbackContext); - tt_assert(data->state == Thread::StateRunning); + tt_assert(data->state == Thread::State::Running); - if (data->isStatic) { - TT_LOG_I( - TAG, - "%s static task memory will not be reclaimed", - data->name.empty() ? "" : data->name.c_str() - ); - } - - setState(data, Thread::StateStopped); + setState(data, Thread::State::Stopped); vTaskSetThreadLocalStoragePointer(nullptr, 0, nullptr); data->taskHandle = nullptr; @@ -73,15 +67,14 @@ Thread::Thread() : data({ .thread = nullptr, .taskHandle = nullptr, - .state = StateStopped, + .state = State::Stopped, .callback = nullptr, .callbackContext = nullptr, .callbackResult = 0, .stateCallback = nullptr, .stateCallbackContext = nullptr, .name = std::string(), - .priority = PriorityNormal, - .isStatic = false, + .priority = Priority::Normal, .stackSize = 0, }) { } @@ -89,64 +82,56 @@ Thread::Thread( const std::string& name, configSTACK_DEPTH_TYPE stackSize, Callback callback, - _Nullable void* callbackContext) : + _Nullable void* callbackContext, + portBASE_TYPE affinity +) : data({ .thread = nullptr, .taskHandle = nullptr, - .state = StateStopped, + .state = State::Stopped, .callback = callback, .callbackContext = callbackContext, .callbackResult = 0, .stateCallback = nullptr, .stateCallbackContext = nullptr, .name = name, - .priority = PriorityNormal, - .isStatic = false, + .priority = Priority::Normal, .stackSize = stackSize, + .affinity = affinity }) { } Thread::~Thread() { // Ensure that use join before free - tt_assert(data.state == StateStopped); + tt_assert(data.state == State::Stopped); tt_assert(data.taskHandle == nullptr); } void Thread::setName(const std::string& newName) { - tt_assert(data.state == StateStopped); + tt_assert(data.state == State::Stopped); data.name = newName; } - -void Thread::markAsStatic() { - data.isStatic = true; -} - -bool Thread::isMarkedAsStatic() const { - return data.isStatic; -} - void Thread::setStackSize(size_t stackSize) { - tt_assert(data.state == StateStopped); + tt_assert(data.state == State::Stopped); tt_assert(stackSize % 4 == 0); data.stackSize = stackSize; } void Thread::setCallback(Callback callback, _Nullable void* callbackContext) { - tt_assert(data.state == StateStopped); + tt_assert(data.state == State::Stopped); data.callback = callback; data.callbackContext = callbackContext; } void Thread::setPriority(Priority priority) { - tt_assert(data.state == StateStopped); - tt_assert(priority >= 0 && priority <= TT_CONFIG_THREAD_MAX_PRIORITIES); + tt_assert(data.state == State::Stopped); data.priority = priority; } void Thread::setStateCallback(StateCallback callback, _Nullable void* callbackContext) { - tt_assert(data.state == StateStopped); + tt_assert(data.state == State::Stopped); data.stateCallback = callback; data.stateCallbackContext = callbackContext; } @@ -157,38 +142,49 @@ Thread::State Thread::getState() const { void Thread::start() { tt_assert(data.callback); - tt_assert(data.state == StateStopped); - tt_assert(data.stackSize > 0 && data.stackSize < (UINT16_MAX * sizeof(StackType_t))); + tt_assert(data.state == State::Stopped); + tt_assert(data.stackSize > 0U && data.stackSize < (UINT16_MAX * sizeof(StackType_t))); - setState(&data, StateStarting); + setState(&data, State::Starting); uint32_t stack_depth = data.stackSize / sizeof(StackType_t); - if (data.isStatic) { -#if configSUPPORT_STATIC_ALLOCATION == 1 - data.taskHandle = xTaskCreateStatic( + + BaseType_t result; + if (data.affinity != -1) { +#ifdef ESP_PLATFORM + result = xTaskCreatePinnedToCore( thread_body, data.name.c_str(), stack_depth, - &data, - data.priority, - static_cast(malloc(sizeof(StackType_t) * stack_depth)), - static_cast(malloc(sizeof(StaticTask_t))) + this, + static_cast(data.priority), + &(data.taskHandle), + data.affinity ); #else - TT_LOG_E(TAG, "static tasks are not supported by current FreeRTOS config/platform - creating regular one"); - BaseType_t result = xTaskCreate( - thread_body, data.name.c_str(), stack_depth, this, data.priority, &(data.taskHandle) + TT_LOG_W(TAG, "Pinned tasks are not supported by current FreeRTOS platform - creating regular one"); + result = xTaskCreate( + thread_body, + data.name.c_str(), + stack_depth, + this, + static_cast(data.priority), + &(data.taskHandle) ); - tt_check(result == pdPASS); #endif } else { - BaseType_t result = xTaskCreate( - thread_body, data.name.c_str(), stack_depth, this, data.priority, &(data.taskHandle) + result = xTaskCreate( + thread_body, + data.name.c_str(), + stack_depth, + this, + static_cast(data.priority), + &(data.taskHandle) ); - tt_check(result == pdPASS); } - tt_check(data.state == StateStopped || data.taskHandle); + tt_check(result == pdPASS); + tt_check(data.state == State::Stopped || data.taskHandle); } bool Thread::join() { @@ -205,12 +201,12 @@ bool Thread::join() { return true; } -ThreadId Thread::getId() { +ThreadId Thread::getId() const { return data.taskHandle; } -int32_t Thread::getReturnCode() { - tt_assert(data.state == StateStopped); +int32_t Thread::getReturnCode() const { + tt_assert(data.state == State::Stopped); return data.callbackResult; } @@ -224,8 +220,7 @@ Thread* thread_get_current() { } void thread_set_current_priority(Thread::Priority priority) { - UBaseType_t new_priority = priority ? priority : Thread::PriorityNormal; - vTaskPrioritySet(nullptr, new_priority); + vTaskPrioritySet(nullptr, static_cast(priority)); } Thread::Priority thread_get_current_priority() { @@ -237,14 +232,6 @@ void thread_yield() { taskYIELD(); } -bool thread_mark_is_static(ThreadId thread_id) { - auto hTask = (TaskHandle_t)thread_id; - assert(!TT_IS_IRQ_MODE() && (hTask != nullptr)); - auto* thread = (Thread*)pvTaskGetThreadLocalStoragePointer(hTask, 0); - assert(thread != nullptr); - return thread->isMarkedAsStatic(); -} - uint32_t thread_flags_set(ThreadId thread_id, uint32_t flags) { auto hTask = (TaskHandle_t)thread_id; uint32_t rflags; diff --git a/TactilityCore/Source/Thread.h b/TactilityCore/Source/Thread.h index b8538b8d..8d6434e8 100644 --- a/TactilityCore/Source/Thread.h +++ b/TactilityCore/Source/Thread.h @@ -16,24 +16,23 @@ typedef TaskHandle_t ThreadId; class Thread { public: - typedef enum { - StateStopped, - StateStarting, - StateRunning, - } State; + enum class State{ + Stopped, + Starting, + Running, + }; /** ThreadPriority */ - typedef enum { - PriorityNone = 0, /**< Uninitialized, choose system default */ - PriorityIdle = 1, - PriorityLowest = 2, - PriorityLow = 3, - PriorityNormal = 4, - PriorityHigh = 5, - PriorityHigher = 6, - PriorityHighest = 7 - } Priority; - + enum class Priority : UBaseType_t { + None = 0U, /**< Uninitialized, choose system default */ + Idle = 1U, + Lower = 2U, + Low = 3U, + Normal = 4U, + High = 5U, + Higher = 6U, + Critical = 7U + }; /** ThreadCallback Your callback to run in new thread * @warning never use osThreadExit in Thread @@ -55,41 +54,33 @@ public: typedef struct { Thread* thread; TaskHandle_t taskHandle; - State state; - Callback callback; void* callbackContext; int32_t callbackResult; - StateCallback stateCallback; void* stateCallbackContext; - std::string name; - Priority priority; - - // Keep all non-alignable byte types in one place, - // this ensures that the size of this structure is minimal - bool isStatic; - configSTACK_DEPTH_TYPE stackSize; + portBASE_TYPE affinity; } Data; Thread(); /** Allocate Thread, shortcut version - * @param[in] name - * @param[in] stack_size + * @param[in] name the name of the thread + * @param[in] stackSize in bytes * @param[in] callback * @param[in] callbackContext - * @return Thread* + * @param[in] affinity Which CPU core to pin this task to, -1 means unpinned (only works on ESP32) */ Thread( const std::string& name, configSTACK_DEPTH_TYPE stackSize, Callback callback, - _Nullable void* callbackContext + _Nullable void* callbackContext, + portBASE_TYPE affinity = -1 ); ~Thread(); @@ -99,16 +90,6 @@ public: */ void setName(const std::string& name); - /** Mark thread as service - * The service cannot be stopped or removed, and cannot exit from the thread body - */ - void markAsStatic(); - - /** Check if thread is as service - * If true, the service cannot be stopped or removed, and cannot exit from the thread body - */ - bool isMarkedAsStatic() const; - /** Set Thread stack size * @param[in] stackSize stack size in bytes */ @@ -137,8 +118,7 @@ public: */ State getState() const; - /** Start Thread - */ + /** Start Thread */ void start(); /** Join Thread @@ -150,10 +130,10 @@ public: /** Get FreeRTOS ThreadId for Thread instance * @return ThreadId or nullptr */ - ThreadId getId(); + ThreadId getId() const; /** @return thread return code */ - int32_t getReturnCode(); + int32_t getReturnCode() const; private: @@ -161,9 +141,9 @@ private: }; #define THREAD_PRIORITY_APP Thread::PriorityNormal -#define THREAD_PRIORITY_SERVICE Thread::PriorityHigh -#define THREAD_PRIORITY_RENDER Thread::PriorityHigher -#define THREAD_PRIORITY_ISR (TT_CONFIG_THREAD_MAX_PRIORITIES - 1) +#define THREAD_PRIORITY_SERVICE Thread::Priority::High +#define THREAD_PRIORITY_RENDER Thread::Priority::Higher +#define THREAD_PRIORITY_ISR Thread::Priority::Critical /** Set current thread priority * @param[in] priority ThreadPriority value @@ -220,10 +200,4 @@ void thread_resume(ThreadId threadId); */ bool thread_is_suspended(ThreadId threadId); -/** Check if the thread was created with static memory - * @param[in] threadId thread id - * @return true if thread memory is static - */ -bool thread_mark_is_static(ThreadId threadId); - } // namespace diff --git a/TactilityCore/Source/Timer.cpp b/TactilityCore/Source/Timer.cpp index 8daea062..7fbf41e8 100644 --- a/TactilityCore/Source/Timer.cpp +++ b/TactilityCore/Source/Timer.cpp @@ -36,16 +36,16 @@ Timer::~Timer() { tt_check(xTimerDelete(timerHandle, portMAX_DELAY) == pdPASS); } -bool Timer::start(uint32_t intervalTicks) { +bool Timer::start(TickType_t interval) { tt_assert(!TT_IS_ISR()); - tt_assert(intervalTicks < portMAX_DELAY); - return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS; + tt_assert(interval < portMAX_DELAY); + return xTimerChangePeriod(timerHandle, interval, portMAX_DELAY) == pdPASS; } -bool Timer::restart(uint32_t intervalTicks) { +bool Timer::restart(TickType_t interval) { tt_assert(!TT_IS_ISR()); - tt_assert(intervalTicks < portMAX_DELAY); - return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS && + tt_assert(interval < portMAX_DELAY); + return xTimerChangePeriod(timerHandle, interval, portMAX_DELAY) == pdPASS && xTimerReset(timerHandle, portMAX_DELAY) == pdPASS; } @@ -59,9 +59,9 @@ bool Timer::isRunning() { return xTimerIsTimerActive(timerHandle) == pdTRUE; } -uint32_t Timer::getExpireTime() { +TickType_t Timer::getExpireTime() { tt_assert(!TT_IS_ISR()); - return (uint32_t)xTimerGetExpiryTime(timerHandle); + return xTimerGetExpiryTime(timerHandle); } bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout) { @@ -73,19 +73,13 @@ bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, } } -void Timer::setThreadPriority(ThreadPriority priority) { +void Timer::setThreadPriority(Thread::Priority priority) { tt_assert(!TT_IS_ISR()); TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle(); tt_assert(task_handle); // Don't call this method before timer task start - if (priority == TimerThreadPriorityNormal) { - vTaskPrioritySet(task_handle, configTIMER_TASK_PRIORITY); - } else if (priority == TimerThreadPriorityElevated) { - vTaskPrioritySet(task_handle, configMAX_PRIORITIES - 1); - } else { - tt_crash("Unsupported timer priority"); - } + vTaskPrioritySet(task_handle, static_cast(priority)); } } // namespace diff --git a/TactilityCore/Source/Timer.h b/TactilityCore/Source/Timer.h index 803bd6ec..0534d6f1 100644 --- a/TactilityCore/Source/Timer.h +++ b/TactilityCore/Source/Timer.h @@ -3,6 +3,7 @@ #include "CoreTypes.h" #include "RtosCompatTimers.h" +#include "Thread.h" #include namespace tt { @@ -34,17 +35,17 @@ public: /** Start timer * @warning This is asynchronous call, real operation will happen as soon as timer service process this request. - * @param[in] ticks The interval in ticks + * @param[in] interval The interval in ticks * @return success result */ - bool start(uint32_t intervalTicks); + bool start(TickType_t interval); /** Restart timer with previous timeout value * @warning This is asynchronous call, real operation will happen as soon as timer service process this request. - * @param[in] ticks The interval in ticks + * @param[in] interval The interval in ticks * @return success result */ - bool restart(uint32_t intervalTicks); + bool restart(TickType_t interval); /** Stop timer * @warning This is asynchronous call, real operation will happen as soon as timer service process this request. @@ -61,7 +62,7 @@ public: /** Get timer expire time * @return expire tick */ - uint32_t getExpireTime(); + TickType_t getExpireTime(); /** * Calls xTimerPendFunctionCall internally. @@ -69,18 +70,19 @@ public: * @param[in] callbackContext the first function argument * @param[in] callbackArg the second function argument * @param[in] timeout the function timeout (must set to 0 in ISR mode) + * @return true on success */ bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout); - typedef enum { - TimerThreadPriorityNormal, /**< Lower then other threads */ - TimerThreadPriorityElevated, /**< Same as other threads */ - } ThreadPriority; + enum class Priority{ + Normal, /**< Lower then other threads */ + Elevated, /**< Same as other threads */ + }; /** Set Timer thread priority * @param[in] priority The priority */ - void setThreadPriority(ThreadPriority priority); + void setThreadPriority(Thread::Priority priority); }; } // namespace diff --git a/Tests/TactilityCore/MutexTest.cpp b/Tests/TactilityCore/MutexTest.cpp index f9e852b5..6a461485 100644 --- a/Tests/TactilityCore/MutexTest.cpp +++ b/Tests/TactilityCore/MutexTest.cpp @@ -23,12 +23,12 @@ TEST_CASE("a mutex can block a thread") { thread.start(); kernel::delayMillis(5); - CHECK_EQ(thread.getState(), Thread::StateRunning); + CHECK_EQ(thread.getState(), Thread::State::Running); mutex.unlock(); kernel::delayMillis(5); - CHECK_EQ(thread.getState(), Thread::StateStopped); + CHECK_EQ(thread.getState(), Thread::State::Stopped); thread.join(); } diff --git a/Tests/TactilityCore/ThreadTest.cpp b/Tests/TactilityCore/ThreadTest.cpp index 193d8470..7ec7cb84 100644 --- a/Tests/TactilityCore/ThreadTest.cpp +++ b/Tests/TactilityCore/ThreadTest.cpp @@ -78,13 +78,13 @@ TEST_CASE("thread state should be correct") { &interruptable_thread, &interrupted ); - CHECK_EQ(thread->getState(), Thread::StateStopped); + CHECK_EQ(thread->getState(), Thread::State::Stopped); thread->start(); Thread::State state = thread->getState(); - CHECK((state == Thread::StateStarting || state == Thread::StateRunning)); + CHECK((state == Thread::State::Starting || state == Thread::State::Running)); interrupted = true; thread->join(); - CHECK_EQ(thread->getState(), Thread::StateStopped); + CHECK_EQ(thread->getState(), Thread::State::Stopped); delete thread; }