0
votes

I am learning FreeRTOS and how to create/manage/delete tasks from another tasks. I have created a simple program for my ESP32 microcontroller. I have serial_message_receive task that is permamently running in the background and waiting for serial messages to come. When serial message is received, I create other FreeRTOS tasks based on the messages:

"task1" - starts task1 "task2" - starts task2

My controller.cpp


#include "Controller.h"


Controller controller_obj;


//static void Thermostat::normal_operation_task2(Thermostat* thermostat_obj);

Controller::Controller(){

    printf("Thermostat object created \n");
}

void Controller::begin(){

    this-> old_state = INITIAL;
    this->main_task_handle = NULL;
    this->secondary_task_handle = NULL;
    printf("Initialise the object with the default values \n");
    //xTaskCreate(task1,"thermostat normal operation task",10000,this,1,NULL); //receiving commands from main uart
}



void Controller::State_change_handle(e_thermostat_state state)
{
    this-> new_state = state;
    if(this-> old_state != this-> new_state ){ // if the new state is different than current state, delete the task
        printf("different state, delete the previous task \n");
        if ( this ->main_task_handle != NULL){
            vTaskDelete(this ->main_task_handle);
        }
    }
    else{
        printf("same task \n"); // the same task is set, dont do anything
        return;
    }
        
    switch(this->new_state) 
    {   
        case MODE1:
            printf("NEW STATE = MODE1 \n");
            this-> old_state = MODE1;
            xTaskCreate(task1,"MODE1",10000,this,1,&this->main_task_handle); // receiving commands from main uart
            break;

        case MODE2:
            printf("NEW STATE = MODE2\n");
            this-> old_state = MODE2;
            xTaskCreate(task2,"MODE2",10000,this,1,&this->main_task_handle); // receiving commands from main uart
            break;


        default:
            printf("state not recognised \n");
    }
}

My controller.h

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include "stdint.h"
#include "stdio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"



enum e_thermostat_state
{
    INITIAL,
    MODE1,
    MODE2,
    MODE3,
    MAX_STATES
};


class Controller
{
    private://only accesible for class
        int test1;
        e_thermostat_state new_state;
        e_thermostat_state old_state;
        TaskHandle_t main_task_handle;
        TaskHandle_t secondary_task_handle;
        

    public: 
    //accesible outside class
        Controller();                                                   // INIT OBJECT
        void begin();
        void State_change_handle(e_thermostat_state state);


        static void task1(void* parameters)
        {
            Controller controller_obj = *((Controller*)parameters);
            //CHECK IF TASK3 IS ACTIVE. IF IT IS ACTIVE, ALWAYS DELETE IT WHEN TASK1 IS STARTED
            if(controller_obj.secondary_task_handle != NULL){
                printf("task3 is active, delete it");
                vTaskDelete(controller_obj.secondary_task_handle);
            }
            for(;;)
            {     
                printf("hello from task 1\n");
                vTaskDelay(1000/portTICK_RATE_MS);
            }
        }


        static void task2(void* parameters)
        {
            Controller controller_obj = *((Controller*)parameters);
            for(;;)
            {   
                printf("hello from task 2\n");
                
                if(controller_obj.secondary_task_handle ==NULL){
                    printf("task3 started from task2");
                    xTaskCreate(task3,"MODE2",10000,&controller_obj,1,&controller_obj.secondary_task_handle); 
                }
                
                vTaskDelay(1000/portTICK_RATE_MS);
            }
        }


        static void task3(void* parameters)
        {
            Controller controller_obj = *((Controller*)parameters);
            for(;;)
            {   
                printf("hello from task 3 which is created from task 2\n");
                vTaskDelay(1000/portTICK_RATE_MS);
            }
        }
        
        //static void normal_operation_task(void *argument);                                 // DECLARE DEFAULT THERMOSTAT STATES AND VARS       
};




#endif

The program logic explained:

When I call class begin method

void Controller::begin(){

    this-> old_state = INITIAL;
    this->main_task_handle = NULL;
    this->secondary_task_handle = NULL;
    printf("Initialise the object with the default values \n");
    //xTaskCreate(task1,"thermostat normal operation task",10000,this,1,NULL); //receiving commands from main uart
}

I initialise 2 task handle variables ( main_task_handle and secondary_task_handle).

  • main_task_handle is used to handle main tasks ( the tasks that are created after the serial message is received)
  • secondary_task_handle is used to handle the secondary task (task3
    which is created inside task2).

Whenever I change between task1 and task2 ( by sending a serial message) , a State_change_handle method is called. This method is going to delete the previous task and create a new one. For example, if task1 is currently running and I send a serial messsage "task2", task1 will be deleted and task2 will be started instead. I have tested this part and it works.

However, I am concerned with task3. Task3 is created from task2 and I pass a secondary_task_handle when creating a task:

xTaskCreate(task3,"MODE2",10000,&controller_obj,1,&controller_obj.secondary_task_handle);

When I can see that both task2 and task3 is running which is correct. Now when I switch back to task1, I check whether controller_obj.secondary_task_handle is != NULL. (if the secondary task exists) and if it exists, delete the secondary task. But the if statement is never executed. I do not understand why. Serial monitor:

Initialise the object with the default values 
task1 selected
different state, delete the previous task 
NEW STATE = MODE1
hello from task 1
hello from task 1
hello from task 1
hello from task 1
task2 selected
different state, delete the previous task 
NEW STATE = MODE2
hello from task 2
task3 started from task2hello from task 3 which is created from task 2
hello from task 3 which is created from task 2
hello from task 2
hello from task 2
hello from task 3 which is created from task 2
hello from task 3 which is created from task 2
hello from task 2
task1 selected
different state, delete the previous task
NEW STATE = MODE1
hello from task 1
hello from task 3 which is created from task 2
hello from task 1
hello from task 3 which is created from task 2
hello from task 1
hello from task 3 which is created from task 2
hello from task 1
hello from task 3 which is created from task 2
hello from task 1
hello from task 3 which is created from task 2

UPDATE

I have managed to find the mistake. Inside a task, I must to cast void* parameter to the class object and was trying to do it as below:

Controller controller_obj = *((Controller*)parameters);

However, above is wrong and I think it is passing obj by value isntead of by reference. The correct way:

Controller* controller_obj = (Controller*)parameters;

Now it is working as expected

1
please share a codebase or github which has these changes, so that we can test locally in our system with esp32Abhishek D K
Hey. Sorry for the late response. I was figuring out how post my code on github this was the first time. Please tell me if you can access it. github.com/krupis/esp32_rtos_test. You should be able to run the code on the esp32 dev board. In the serial terminal just write "task1" or "task2"TheBestPlayer
yes, i am able to accessAbhishek D K
I have managed to find a mistake. I have updated my initial postTheBestPlayer
Please add the solution / fix as an answer. You can answer your own questions.Tagli

1 Answers

0
votes

The problem has been solved and it turned out to be an issue with the following:

Controller controller_obj = *((Controller*)parameters);

From what I understand, this is not correct because my controller_obj will not be the same as my original class object. In order to cast it correctly, the following should be used:

Controller* controller_obj = (Controller*)parameters;