Skip to content

Augtons/ESP-FreeRTOS-Cpp

Repository files navigation

FreeRTOS Binging For ESP-IDF

This is a FreeRTOS C++ binding. Supports some advanced C++ features.

The current supported FreeRTOS features: Task, Queue, Semaphores and Mutex.

Contents

Installation

# idf_component.yml
dependencies:
  freertos-cpp:
    git: https://github.com/Augtons/ESP-FreeRTOS-Cpp

Getting Started

1. Tasks

Please refer to examples:

(1) Creating

a) Without Arguments:

task<> your_task = task_builder<>("task name")
    .stack(2048)
    .priority(0)
    .bind([] {
        while (true) {
            ESP_LOGI("TAG", "Task is running.");
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    });
task<> your_task = task_factory<>::create("task name", 2048, 0, [] {
    while (true) {
        ESP_LOGI("TAG", "Task is running.");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
});

Also Supports function.

void task_function() {
    while (true) {
        ESP_LOGI("TAG", "Task is running.");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

task<> your_task = task_factory<>::create("task name", 2048, 0, task_function);

b) With Arguments:

Next, using C++ reference types as an example, please note that during the task execution, the reference must remain valid (for example, int a = 0 in the following example must not go out of scope)

int a = 123;
task<int&> your_task = task_builder<int&>("task name")
    .stack(2048)
    .priority(0)
    .bind(a, [](int& args) { // variable `a` will be passed as a int&
        while (true) {
            ESP_LOGI("TAG", "Task is running, a = %d.", arg);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    });

You can also use lambda to capture variables in scope.

int a = 123;
task<> your_task = task_builder<>("task name")
    .stack(2048)
    .priority(0)
    .bind([&a]() { // variable `a` captured as reference.
        while (true) {
            ESP_LOGI("TAG", "Task is running, a = %d.", a);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    });

task_factory<Type> also ok!

int a = 123;
task<int&> your_task = task_factory<int&>::create("task name", 2048, 0, a, [](int& arg) {
    while (true) {
        ESP_LOGI("TAG", "Task is running, a = %d.", arg);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
});

(2) Deleting.

Delete itself

It will be deleted automatically when its task function returns.

The Safe Way:

task<> your_task = task_factory<>::create("task name", 2048, 0, [] {
    ESP_LOGI("TAG", "Start.");
    vTaskDelay(pdMS_TO_TICKS(1000));
    ESP_LOGI("TAG", "Will be deleted.");
});

Note: Don't use vTaskDelete(NULL) to delete it! Memory leaks will occur.

Delete by task<...> object

The Safe Way:

your_task.delete_task();

Note: Don't use vTaskDelete((TaskHandle_t)your_task) to delete it. Memory leaks will occur.

(3) Get Native Task Handle (TaskHandle_t)

// The first way.
auto handle = (TaskHandle_t)your_task;
// Equals to the first way.
auto handle = your_task.native_handle();

// Get native handle but `abort()` when your_task is null.
auto handle = your_task.native_handle_not_null();

Examples

// 1.
task<> t1;
auto handle = (TaskHandle_t)t1; // handle is nullptr.
auto handle = t1.native_handle(); //handle is nullptr.

// 2.
task<> t2;
task<> t3 = task_builder<>(...)...;   // Create Task

auto handle = t2.native_handle_not_null();  // Error, abort().
auto handle = t3.native_handle_not_null();  // Handle of t3.
auto handle = (TaskHandle_t)t2;             // nullptr

(4) Reference count.

When the reference count of a task<> object is 0, the FreeRTOS Task will be deleted.

It has some features similar to std::shared_ptr.

task<> t1;
t1.use_count();   // use_count of null object it always 1.

task<> t2 = task_builder<>("task").stack(2048).priority(0).bind([]() {
    while (true) {
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
});
t2.use_count();   // 1
t1 = t2;
t2.use_count();   // 2
t1.use_count();   // 2

task<> t3 = task_builder<>("task2").stack(2048).priority(0).bind([]() {
    while (true) {
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
});

t1 = t3;
t3.use_count();   // 2
t2.use_count();   // 1

task<> t4 = task_builder<>("task2").stack(2048).priority(0).bind([]() {
    while (true) {
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
});
t1 = std::move(t4);
t1.use_count();   // 1

2. Queue

Please refer to examples queue, Click Here

3. Semaphores and Mutex

Please refer to examples semaphore, Click Here