From d3eb1b73b6bc5d332eb34cc185bd49998ff6390a Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Sun, 28 Dec 2025 16:57:28 -0600 Subject: [PATCH 1/4] feat(task): Add additional APIs for querying specific characteristics of the task or the current task context --- components/task/example/main/task_example.cpp | 97 +++++++++------- components/task/include/task.hpp | 108 +++++++++++++++++- components/task/src/task.cpp | 4 +- 3 files changed, 164 insertions(+), 45 deletions(-) diff --git a/components/task/example/main/task_example.cpp b/components/task/example/main/task_example.cpp index bbf27dfc8..0366516be 100644 --- a/components/task/example/main/task_example.cpp +++ b/components/task/example/main/task_example.cpp @@ -35,6 +35,8 @@ using namespace std::chrono_literals; */ extern "C" void app_main(void) { espp::Logger logger({.tag = "TaskExample", .level = espp::Logger::Verbosity::DEBUG}); + logger.info("Starting Task example application"); + /** * Set up some variables we'll re-use to control and measure our tests. */ @@ -52,9 +54,10 @@ extern "C" void app_main(void) { logger.info("Basic task example: spawning 1 task for {} seconds!", num_seconds_to_run); //! [Task example] espp::Task::configure_task_watchdog(1000ms); + fmt::println("Main thread task handle = {}", fmt::ptr(espp::Task::get_freertos_handle())); auto task_fn = [](std::mutex &m, std::condition_variable &cv) { static size_t task_iterations{0}; - fmt::print("Task: #iterations = {}\n", task_iterations); + fmt::println("Task: #iterations = {}", task_iterations); task_iterations++; // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed @@ -71,6 +74,12 @@ extern "C" void app_main(void) { task.start(); task.start_watchdog(); // start the watchdog timer for this task std::this_thread::sleep_for(num_seconds_to_run * 1s); + fmt::println("Task HWM: {} bytes", espp::Task::get_high_water_mark(task)); + fmt::println("Task priority: {}", espp::Task::get_priority(task)); + fmt::println("Task Core ID: {}", espp::Task::get_core_id(task)); + fmt::println("Task ID: {}", espp::Task::get_id(task)); + fmt::println("Task Handle: {}", fmt::ptr(espp::Task::get_freertos_handle(task))); + task.stop_watchdog(); // stop the watchdog timer for this task // show explicitly stopping the task (though the destructor called at the // end of this scope would do it for us) @@ -78,11 +87,11 @@ extern "C" void app_main(void) { std::error_code ec; std::string watchdog_info = espp::Task::get_watchdog_info(ec); if (ec) { - fmt::print("Error getting watchdog info: {}\n", ec.message()); + fmt::println("Error getting watchdog info: {}", ec.message()); } else if (!watchdog_info.empty()) { - fmt::print("Watchdog info: {}\n", watchdog_info); + fmt::println("Watchdog info: {}", watchdog_info); } else { - fmt::print("No watchdog info available\n"); + fmt::println("No watchdog info available"); } //! [Task example] } @@ -102,7 +111,7 @@ extern "C" void app_main(void) { espp::Task::configure_task_watchdog(300ms, panic_on_watchdog_timeout); auto task_fn = [](std::mutex &m, std::condition_variable &cv) { static size_t task_iterations{0}; - fmt::print("Task: #iterations = {}\n", task_iterations); + fmt::println("Task: #iterations = {}", task_iterations); task_iterations++; std::unique_lock lk(m); // note our sleep here is longer than the watchdog timeout, so we should @@ -120,11 +129,11 @@ extern "C" void app_main(void) { std::error_code ec; std::string watchdog_info = espp::Task::get_watchdog_info(ec); if (ec) { - fmt::print("Error getting watchdog info: {}\n", ec.message()); + fmt::println("Error getting watchdog info: {}", ec.message()); } else if (!watchdog_info.empty()) { - fmt::print("Watchdog info: {}\n", watchdog_info); + fmt::println("Watchdog info: {}", watchdog_info); } else { - fmt::print("No watchdog info available\n"); + fmt::println("No watchdog info available"); } // NOTE: the task and the watchdog will both automatically get stopped when // the task goes out of scope and is destroyed. @@ -152,7 +161,7 @@ extern "C" void app_main(void) { size_t iterations{0}; // copy the loop variables and indicate that we intend to mutate them! auto task_fn = [i, iterations](std::mutex &m, std::condition_variable &cv) mutable { - fmt::print("Task {}: #iterations = {}\n", i, iterations); + fmt::println("Task {}: #iterations = {}", i, iterations); iterations++; // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed @@ -169,7 +178,7 @@ extern "C" void app_main(void) { tasks[i] = std::move(task); tasks[i]->start(); } - fmt::print("Tasks spawned, waiting for {} seconds!\n", num_seconds_to_run); + fmt::println("Tasks spawned, waiting for {} seconds!", num_seconds_to_run); std::this_thread::sleep_until(start + num_seconds_to_run * 1s); //! [ManyTask example] } @@ -194,7 +203,7 @@ extern "C" void app_main(void) { size_t iterations{0}; // copy the loop variables and indicate that we intend to mutate them! auto task_fn = [i, iterations]() mutable { - fmt::print("Task {}: #iterations = {}\n", i, iterations); + fmt::println("Task {}: #iterations = {}", i, iterations); iterations++; // NOTE: sleeping in this way PREVENTS the sleep / task from early // exiting when the task is being stopped / destroyed. @@ -213,7 +222,7 @@ extern "C" void app_main(void) { tasks[i] = std::move(task); tasks[i]->start(); } - fmt::print("Tasks spawned, waiting for {} seconds!\n", num_seconds_to_run); + fmt::println("Tasks spawned, waiting for {} seconds!", num_seconds_to_run); std::this_thread::sleep_until(start + num_seconds_to_run * 1s); } test_end = std::chrono::high_resolution_clock::now(); @@ -235,7 +244,7 @@ extern "C" void app_main(void) { auto task_fn = [](std::mutex &m, std::condition_variable &cv) { static size_t task_iterations{0}; const size_t num_steps_per_iteration = 10; - fmt::print("Task processing iteration {}...\n", task_iterations); + fmt::println("Task processing iteration {}...", task_iterations); for (size_t i = 0; i < num_steps_per_iteration; i++) { // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed @@ -248,8 +257,8 @@ extern "C" void app_main(void) { if (cv_retval == std::cv_status::no_timeout) { // if there was no timeout, then we were notified, therefore we need // to shut down. - fmt::print("Task stopping early (step {}/{}) on iteration {}\n", i, - num_steps_per_iteration, task_iterations); + fmt::println("Task stopping early (step {}/{}) on iteration {}", i, + num_steps_per_iteration, task_iterations); // NOTE: use this_thread::sleep_for() to fake cleaning up work that // we would do std::this_thread::sleep_for(10ms); @@ -259,7 +268,7 @@ extern "C" void app_main(void) { } } } - fmt::print("Task processing iteration {} complete\n", task_iterations); + fmt::println("Task processing iteration {} complete", task_iterations); task_iterations++; // we don't want to stop, so return false return false; @@ -289,7 +298,7 @@ extern "C" void app_main(void) { auto task_fn = [](std::mutex &m, std::condition_variable &cv, bool &task_notified) { static size_t task_iterations{0}; const size_t num_steps_per_iteration = 10; - fmt::print("Task processing iteration {}...\n", task_iterations); + fmt::println("Task processing iteration {}...", task_iterations); for (size_t i = 0; i < num_steps_per_iteration; i++) { // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed @@ -301,8 +310,8 @@ extern "C" void app_main(void) { auto stop_requested = cv.wait_for(lk, std::chrono::milliseconds(100), [&task_notified] { return task_notified; }); if (stop_requested) { - fmt::print("Task was notified, stopping early (step {}/{}) on iteration {}\n", i, - num_steps_per_iteration, task_iterations); + fmt::println("Task was notified, stopping early (step {}/{}) on iteration {}", i, + num_steps_per_iteration, task_iterations); // NOTE: use this_thread::sleep_for() to fake cleaning up work that // we would do std::this_thread::sleep_for(10ms); @@ -312,7 +321,7 @@ extern "C" void app_main(void) { } } } - fmt::print("Task processing iteration {} complete\n", task_iterations); + fmt::println("Task processing iteration {} complete", task_iterations); task_iterations++; // we don't want to stop, so return false return false; @@ -340,10 +349,14 @@ extern "C" void app_main(void) { task_iterations++; // allocate stack size_t num_bytes = 256 * task_iterations; - char buffer[num_bytes]; + char buffer[num_bytes] = {0}; // do something with the bufer (which also uses stack) - snprintf(buffer, num_bytes, "%.06f\n", (float)task_iterations); - fmt::print("{}\n", espp::Task::get_info()); + snprintf(buffer, num_bytes, "%.06f", (float)task_iterations); + fmt::println("Task iteration {}: buffer = {:s}", task_iterations, (char *)buffer); + fmt::println("{}", espp::Task::get_info()); + fmt::println("Core ID: {}", espp::Task::get_core_id()); + fmt::println("HWM: {} bytes", espp::Task::get_high_water_mark()); + fmt::println("Priority: {}", espp::Task::get_priority()); // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed { @@ -364,7 +377,7 @@ extern "C" void app_main(void) { now = std::chrono::high_resolution_clock::now(); elapsed = std::chrono::duration(now - test_start).count(); } - fmt::print("Final: {}\n", espp::Task::get_info(task)); + fmt::println("Final: {}", espp::Task::get_info(task)); //! [Task Info example] } test_end = std::chrono::high_resolution_clock::now(); @@ -424,7 +437,7 @@ extern "C" void app_main(void) { auto elapsed = std::chrono::duration(now - begin).count(); if (elapsed > num_seconds_to_run) { static int num_times_run{0}; - fmt::print("Task stopping early after {} runs!\n", ++num_times_run); + fmt::println("Task stopping early after {} runs!", ++num_times_run); // we've gone long enough, time to stop our task! return true; } @@ -445,7 +458,7 @@ extern "C" void app_main(void) { std::this_thread::sleep_for(10ms); } // restart the task without explicitly cancelling it - fmt::print("Restarting task...\n"); + fmt::println("Restarting task..."); task.start(); while (task.is_started()) { std::this_thread::sleep_for(10ms); @@ -469,7 +482,7 @@ extern "C" void app_main(void) { static auto begin = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration(now - begin).count(); - fmt::print("Task has run for {:.03f} seconds\n", elapsed); + fmt::println("Task has run for {:.03f} seconds", elapsed); // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed { @@ -491,7 +504,7 @@ extern "C" void app_main(void) { std::this_thread::sleep_for(1s); // NOTE: on ESP-IDF, this is the same as xTaskGetCurrentTaskHandle(); auto thread = espp::Task::get_current_id(); - fmt::print("Stopping task from thread {}...\n", thread); + fmt::println("Stopping task from thread {}...", thread); task.stop(); }; // make vector of threads to stop the task @@ -523,7 +536,7 @@ extern "C" void app_main(void) { static auto begin = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration(now - begin).count(); - fmt::print("Task has run for {:.03f} seconds\n", elapsed); + fmt::println("Task has run for {:.03f} seconds", elapsed); // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed { @@ -531,7 +544,7 @@ extern "C" void app_main(void) { cv.wait_for(lk, 100ms); } if (elapsed > num_seconds_to_run) { - fmt::print("Stopping task from within task...\n"); + fmt::println("Stopping task from within task..."); task.stop(); } // do some other work here which can't be preempted, this helps force the @@ -559,34 +572,34 @@ extern "C" void app_main(void) { // so we're using 3k. // test running a function that returns void on a specific core - auto task_fn = []() -> void { fmt::print("Void Task running on core {}\n", xPortGetCoreID()); }; + auto task_fn = []() -> void { fmt::println("Void Task running on core {}", xPortGetCoreID()); }; espp::task::run_on_core(task_fn, 0, 3 * 1024); - fmt::print("Void Function returned\n"); + fmt::println("Void Function returned"); espp::task::run_on_core(task_fn, 1, 3 * 1024); - fmt::print("Void Function returned\n"); + fmt::println("Void Function returned"); // test running a function that returns bool on a specific core auto task_fn2 = []() -> bool { auto core_id = xPortGetCoreID(); - fmt::print("Bool Task running on core {}\n", core_id); + fmt::println("Bool Task running on core {}", core_id); return core_id == 1; }; auto result0 = espp::task::run_on_core(task_fn2, 0, 3 * 1024); - fmt::print("Bool Function returned {}\n", result0); + fmt::println("Bool Function returned {}", result0); auto result1 = espp::task::run_on_core( task_fn2, {.name = "test", .stack_size_bytes = 3 * 1024, .core_id = 1}); - fmt::print("Bool Function returned {}\n", result1); + fmt::println("Bool Function returned {}", result1); // test running a function that returns esp_err_t on a specific core auto task_fn3 = []() -> esp_err_t { auto core_id = xPortGetCoreID(); - fmt::print("esp_err_t Task running on core {}\n", core_id); + fmt::println("esp_err_t Task running on core {}", core_id); return core_id == 1 ? ESP_OK : ESP_FAIL; }; auto err0 = espp::task::run_on_core(task_fn3, 0, 3 * 1024); - fmt::print("esp_err_t Function returned {}\n", esp_err_to_name(err0)); + fmt::println("esp_err_t Function returned {}", esp_err_to_name(err0)); auto err1 = espp::task::run_on_core(task_fn3, 1, 3 * 1024); - fmt::print("esp_err_t Function returned {}\n", esp_err_to_name(err1)); + fmt::println("esp_err_t Function returned {}", esp_err_to_name(err1)); //! [run on core example] } @@ -600,13 +613,13 @@ extern "C" void app_main(void) { // test running a function which takes a while to complete auto task_fn = []() -> void { - fmt::print("[{0}] Task running on core {0}\n", xPortGetCoreID()); + fmt::println("[{0}] Task running on core {0}", xPortGetCoreID()); std::this_thread::sleep_for(1s); - fmt::print("[{0}] Task done!\n", xPortGetCoreID()); + fmt::println("[{0}] Task done!", xPortGetCoreID()); }; espp::task::run_on_core_non_blocking(task_fn, 0, 3 * 1024); espp::task::run_on_core_non_blocking(task_fn, {.name = "test", .core_id = 1}); - fmt::print("Started tasks on cores 0 and 1\n"); + fmt::println("Started tasks on cores 0 and 1"); // sleep for a bit to let the tasks run std::this_thread::sleep_for(2s); diff --git a/components/task/include/task.hpp b/components/task/include/task.hpp index a2ba82f77..6e932f189 100644 --- a/components/task/include/task.hpp +++ b/components/task/include/task.hpp @@ -352,11 +352,109 @@ class Task : public espp::BaseComponent { * @note This function is only available on ESP */ static std::string get_info(const Task &task); + + /** + * @brief Get the FreeRTOS task handle for the task of the current context. + * @return TaskHandle_t FreeRTOS task handle + * @note This function is only available on ESP + * @note This function is designed to be used in conjunction with FreeRTOS + * APIs which require a TaskHandle_t. + */ + static TaskHandle_t get_freertos_handle() { return xTaskGetCurrentTaskHandle(); } + + /** + * @brief Get the FreeRTOS task handle for the task of the current context. + * @param task Reference to the task for which you want the FreeRTOS handle. + * @return TaskHandle_t FreeRTOS task handle + * @warning This will only return a valid handle if the task is started. + * @note This function is only available on ESP + * @note This function is designed to be used in conjunction with FreeRTOS + * APIs which require a TaskHandle_t. If you're wanting to print or use + * the pointer in other ways, It's recommended to get the void* pointer + * from get_id() instead, which can be directly printed without needing + * fmt::ptr. + */ + static TaskHandle_t get_freertos_handle(const Task &task) { + return static_cast(task.get_id()); + } + + /** + * @brief Get the priority for the task of the current context. + * @return int Priority of the task + * @note This function is only available on ESP + */ + static int get_priority() { return uxTaskPriorityGet(nullptr); } + + /** + * @brief Get the priority for the task of the current context. + * @param task Reference to the task for which you want the priority. + * @return int Priority of the task + * @note This function is only available on ESP + */ + static int get_priority(const Task &task) { return uxTaskPriorityGet(get_freertos_handle(task)); } + + /** + * @brief Get the stack high water mark (minimum free stack space) for the + * task of the current context. + * @return size_t Stack high water mark (bytes). This is the minimum number of + * bytes that have remained unallocated on the stack since the task + * started. Higher values indicate more free stack space, lower values + * indicate less free stack space. + * @note This function is only available on ESP + */ + static size_t get_high_water_mark() { + return uxTaskGetStackHighWaterMark(nullptr) * sizeof(StackType_t); + } + + /** + * @brief Get the stack high water mark (minimum free stack space) for the + * task of the current context. + * @param task Reference to the task for which you want the high water mark. + * @return size_t Stack high water mark (bytes). This is the minimum number of + * bytes that have remained unallocated on the stack since the task + * started. Higher values indicate more free stack space, lower values + * indicate less free stack space. + * @note This function is only available on ESP + */ + static size_t get_high_water_mark(const Task &task) { + return uxTaskGetStackHighWaterMark(get_freertos_handle(task)) * sizeof(StackType_t); + } + + /** + * @brief Get the core ID for the task of the current context. + * @return size_t Core ID of the task. -1 if the task is not pinned to any + * core. + * @note This function is only available on ESP + */ + static int get_core_id() { + auto core_id = xPortGetCoreID(); + if (core_id == tskNO_AFFINITY) { + return -1; + } + return core_id; + } + + /** + * @brief Get the core ID for the task of the current context. + * @param task Reference to the task for which you want the core ID. + * @return size_t Core ID of the task. -1 if the task is not pinned to any + * core. + * @note This function is only available on ESP + */ + static int get_core_id(const Task &task) { + auto core_id = xTaskGetCoreID(get_freertos_handle(task)); + if (core_id == tskNO_AFFINITY) { + return -1; + } + return core_id; + } + #endif // ESP_PLATFORM /** * @brief Get the ID for this Task's thread / task context. * @return ID for this Task's thread / task context. + * @warning This will only return a valid id if the task is started. */ task_id_t get_id() const { #if defined(ESP_PLATFORM) @@ -366,6 +464,14 @@ class Task : public espp::BaseComponent { #endif } + /** + * @brief Get the ID for the Task's thread / task context. + * @param task Reference to the task for which you want the ID. + * @return ID for this Task's thread / task context. + * @warning This will only return a valid id if the task is started. + */ + static task_id_t get_id(const Task &task) { return task.get_id(); } + /** * @brief Get the ID for the current thread / task context. * @return ID for the current thread / task context. @@ -404,7 +510,7 @@ class Task : public espp::BaseComponent { std::thread thread_; #if defined(ESP_PLATFORM) std::atomic watchdog_started_{false}; - task_id_t task_handle_; + task_id_t task_handle_{nullptr}; #endif }; } // namespace espp diff --git a/components/task/src/task.cpp b/components/task/src/task.cpp index 944b8ed21..98b33abea 100644 --- a/components/task/src/task.cpp +++ b/components/task/src/task.cpp @@ -221,13 +221,13 @@ bool Task::is_running() const { return is_started(); } #if defined(ESP_PLATFORM) || defined(_DOXYGEN_) std::string Task::get_info() { - return fmt::format("[T] '{}',{},{},{}\n", pcTaskGetName(nullptr), xPortGetCoreID(), + return fmt::format("[T] '{}',{},{},{}", pcTaskGetName(nullptr), xPortGetCoreID(), uxTaskPriorityGet(nullptr), uxTaskGetStackHighWaterMark(nullptr)); } std::string Task::get_info(const Task &task) { TaskHandle_t freertos_handle = static_cast(task.get_id()); - return fmt::format("[T] '{}',{},{},{}\n", pcTaskGetName(freertos_handle), xPortGetCoreID(), + return fmt::format("[T] '{}',{},{},{}", pcTaskGetName(freertos_handle), get_core_id(task), uxTaskPriorityGet(freertos_handle), uxTaskGetStackHighWaterMark(freertos_handle)); } From aa35faff32be556b220836e16af4fd25ea6e1f7a Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Sun, 28 Dec 2025 17:12:26 -0600 Subject: [PATCH 2/4] fix copy-pasta in docs --- components/task/include/task.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/task/include/task.hpp b/components/task/include/task.hpp index 6e932f189..7399d24ca 100644 --- a/components/task/include/task.hpp +++ b/components/task/include/task.hpp @@ -363,7 +363,7 @@ class Task : public espp::BaseComponent { static TaskHandle_t get_freertos_handle() { return xTaskGetCurrentTaskHandle(); } /** - * @brief Get the FreeRTOS task handle for the task of the current context. + * @brief Get the FreeRTOS task handle for the provided task. * @param task Reference to the task for which you want the FreeRTOS handle. * @return TaskHandle_t FreeRTOS task handle * @warning This will only return a valid handle if the task is started. @@ -386,7 +386,7 @@ class Task : public espp::BaseComponent { static int get_priority() { return uxTaskPriorityGet(nullptr); } /** - * @brief Get the priority for the task of the current context. + * @brief Get the priority for the provided task. * @param task Reference to the task for which you want the priority. * @return int Priority of the task * @note This function is only available on ESP @@ -408,7 +408,7 @@ class Task : public espp::BaseComponent { /** * @brief Get the stack high water mark (minimum free stack space) for the - * task of the current context. + * provided task. * @param task Reference to the task for which you want the high water mark. * @return size_t Stack high water mark (bytes). This is the minimum number of * bytes that have remained unallocated on the stack since the task @@ -435,7 +435,7 @@ class Task : public espp::BaseComponent { } /** - * @brief Get the core ID for the task of the current context. + * @brief Get the core ID for the provided task. * @param task Reference to the task for which you want the core ID. * @return size_t Core ID of the task. -1 if the task is not pinned to any * core. From bb5b6f342fa91e94c577141f6c95978c481382e6 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Sun, 28 Dec 2025 17:12:56 -0600 Subject: [PATCH 3/4] fix incorrect return type in docs --- components/task/include/task.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/task/include/task.hpp b/components/task/include/task.hpp index 7399d24ca..333e7721e 100644 --- a/components/task/include/task.hpp +++ b/components/task/include/task.hpp @@ -422,7 +422,7 @@ class Task : public espp::BaseComponent { /** * @brief Get the core ID for the task of the current context. - * @return size_t Core ID of the task. -1 if the task is not pinned to any + * @return int Core ID of the task. -1 if the task is not pinned to any * core. * @note This function is only available on ESP */ @@ -437,7 +437,7 @@ class Task : public espp::BaseComponent { /** * @brief Get the core ID for the provided task. * @param task Reference to the task for which you want the core ID. - * @return size_t Core ID of the task. -1 if the task is not pinned to any + * @return int Core ID of the task. -1 if the task is not pinned to any * core. * @note This function is only available on ESP */ From f4f5b761eb87976afd6fbc96c05b5eb9f101236f Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Sun, 28 Dec 2025 17:18:11 -0600 Subject: [PATCH 4/4] update xplat libs --- lib/python_bindings/espp/__init__.pyi | 22 ++++++++++++++++++++-- lib/python_bindings/pybind_espp.cpp | 14 +++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/lib/python_bindings/espp/__init__.pyi b/lib/python_bindings/espp/__init__.pyi index b88715e4b..b7f0b6bf3 100644 --- a/lib/python_bindings/espp/__init__.pyi +++ b/lib/python_bindings/espp/__init__.pyi @@ -1224,6 +1224,8 @@ class RangeMapper_int: # Python specialization for RangeMapper * the input center will map to both output_max and output_min * depending on the sign of the input. * + * @tparam T Numeric type to use for the input and output values. + * * @note When inverting the input range, you are introducing a discontinuity * between the input distribution and the output distribution at the * input center. Noise around the input's center value will create @@ -1392,7 +1394,7 @@ class RangeMapper_int: # Python specialization for RangeMapper """* * @brief Unmap a value \p v from the configured output range (centered, * default [-1,1]) back into the input distribution. - * @param T&v Value from the centered output distribution. + * @param v Value from the centered output distribution. * @return Value within the input distribution. """ @@ -1416,6 +1418,8 @@ class RangeMapper_float: # Python specialization for RangeMapper * the input center will map to both output_max and output_min * depending on the sign of the input. * + * @tparam T Numeric type to use for the input and output values. + * * @note When inverting the input range, you are introducing a discontinuity * between the input distribution and the output distribution at the * input center. Noise around the input's center value will create @@ -1584,7 +1588,7 @@ class RangeMapper_float: # Python specialization for RangeMapper """* * @brief Unmap a value \p v from the configured output range (centered, * default [-1,1]) back into the input distribution. - * @param T&v Value from the centered output distribution. + * @param v Value from the centered output distribution. * @return Value within the input distribution. """ @@ -3000,10 +3004,24 @@ class Task: pass + @overload def get_id(self) -> task_id_t: """* * @brief Get the ID for this Task's thread / task context. * @return ID for this Task's thread / task context. + * @warning This will only return a valid id if the task is started. + + """ + pass + + @staticmethod + @overload + def get_id(task: Task) -> task_id_t: + """* + * @brief Get the ID for the Task's thread / task context. + * @param task Reference to the task for which you want the ID. + * @return ID for this Task's thread / task context. + * @warning This will only return a valid id if the task is started. """ pass diff --git a/lib/python_bindings/pybind_espp.cpp b/lib/python_bindings/pybind_espp.cpp index fbef06e1c..e579b8a35 100644 --- a/lib/python_bindings/pybind_espp.cpp +++ b/lib/python_bindings/pybind_espp.cpp @@ -2124,9 +2124,17 @@ void py_init_module_espp(py::module &m) { .def("is_running", &espp::Task::is_running, "*\n * @brief Is the task running?\n *\n * @return True if the task is running, " "False otherwise.\n") - .def("get_id", &espp::Task::get_id, - "*\n * @brief Get the ID for this Task's thread / task context.\n * @return ID for " - "this Task's thread / task context.\n") + .def( + "get_id", [](espp::Task &self) { return self.get_id(); }, + "*\n * @brief Get the ID for this Task's thread / task context.\n * @return ID for " + "this Task's thread / task context.\n * @warning This will only return a valid id if " + "the task is started.\n") + .def_static("get_id", py::overload_cast(&espp::Task::get_id), + py::arg("task"), + "*\n * @brief Get the ID for the Task's thread / task context.\n * @param " + "task Reference to the task for which you want the ID.\n * @return ID for this " + "Task's thread / task context.\n * @warning This will only return a valid id " + "if the task is started.\n") .def_static("get_current_id", &espp::Task::get_current_id, "*\n * @brief Get the ID for the current thread / task context.\n * @return " "ID for the current thread / task context.\n");