Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 55 additions & 42 deletions components/task/example/main/task_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -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
Expand All @@ -71,18 +74,24 @@ 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)
task.stop();
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]
}
Expand All @@ -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<std::mutex> lk(m);
// note our sleep here is longer than the watchdog timeout, so we should
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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]
}
Expand All @@ -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.
Expand All @@ -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();
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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
{
Expand All @@ -364,7 +377,7 @@ extern "C" void app_main(void) {
now = std::chrono::high_resolution_clock::now();
elapsed = std::chrono::duration<float>(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();
Expand Down Expand Up @@ -424,7 +437,7 @@ extern "C" void app_main(void) {
auto elapsed = std::chrono::duration<float>(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;
}
Expand All @@ -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);
Expand All @@ -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<float>(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
{
Expand All @@ -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
Expand Down Expand Up @@ -523,15 +536,15 @@ 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<float>(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
{
std::unique_lock<std::mutex> lk(m);
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
Expand Down Expand Up @@ -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]
}

Expand All @@ -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);
Expand Down
Loading