3

I am writing a C++ code to handle my temperature controller. I have decided to learn more object oriented programming and learn more about classes therefore I have chose C++ this time ( I usually code in C ). I have created a simple Controller class where I have my public and private functions. In my controller.h file:


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

#ifdef __cplusplus
extern "C" {
#endif

class Controller
{
    private://only accesible for class
        int test1;
   

    public: 
    //accesible outside class
    
        Controller();                                                   // INIT OBJECT
        void begin();                                                   // DECLARE DEFAULT 
        e_thermostat_state Get_state();    
        void normal_operation_task(void *argument);    // FREERTOS TASK FUNCTION PROTOTYPE     
};


#ifdef __cplusplus
}
#endif

#endif

And in my controller.c:

#include "Controller.h"


Controller controller_obj;
uint8_t app_temp = 10;

Controller::Controller(){
    printf("Controller object created \n");
}

void Controller::begin(){
    printf("Initialise the object with the default values \n");
    xTaskCreate(this->normal_operation_task,"controller normal operation task",10000,NULL,1,NULL);
    
        
}

void Controller::normal_operation_task(void *argument){
    for(;;)
    {   
        printf("normal_operation_task\n");
        vTaskDelay(1000/portTICK_RATE_MS);
    }
}

As you can see when I call begin method, I want to simply start the task. The reason why I want the freertos task to be a part of my controller class is because inside that task I will need access to variables and functions of my controller class.

The error that I am getting:

../components/Controller/Controller.cpp: In member function 'void Controller::begin()':
../components/Controller/Controller.cpp:20:98: error: invalid use of non-static member function 'void Controller::normal_operation_task(void*)'
     xTaskCreate(this->normal_operation_task,"thermostat normal operation task",10000,NULL,1,NULL); // receiving commands from main uart

Could someone give me some advice regarding this? I think I have 2 options:

  1. In my class, declare all variables and methods as public so I can access them even if the freertos task is not part of the class.

  2. Create task as part of Controller class so It can use private methods and variables.

UPDATE

I have managed to do it when declared the static function normal_operation_task as been suggested for me. in my controller.h I have declared:

static void Thermostat::normal_operation_task2(Thermostat* thermostat_obj){
    for(;;)
    {   
        printf("normal_operation_task\n");
        vTaskDelay(1000/portTICK_RATE_MS);
    }
}

I am now trying to understand the following:

  1. Why this function must be declared the static
  2. Why do I need to pass the pointer to my controller object? Since it is declared as class method, it automatically has access to class function and variables

ISSUE

What is the issue with the following and why is this wrong?

void Controller::begin(){

    printf("Initialise the object with the default values \n");
    xTaskCreate(this->normal_operation_task3,"thermostat normal operation task",10000,&controller_obj,1,NULL); //receiving commands from main uart
}

 void Controller::normal_operation_task3(void* parameters)
 {
            Controller controller_obj = *((Controller*)parameters);
            for(;;)
            {   
                printf("normal_operation_task\n");
                vTaskDelay(1000/portTICK_RATE_MS);
            }
}
TheBestPlayer
  • 324
  • 2
  • 13
  • Non-static member functions are not the same as a non-member function. You need to make `normal_operation_task` a **`static`** member function. And pass a pointer to a `Controller` object as argument. Then the function could call a (non-static) member function to perform the actual task. – Some programmer dude Aug 30 '21 at 05:42
  • Create a static member function that receives the class pointer and so call a class member as usual. Btw c++ class inside *.c file is a bad practice. – folibis Aug 30 '21 at 05:42
  • By the way your `#ifdef __cplusplus` and `extern "C"` are not needed. The header file *must* be compiled with a C++ compiler, or you wouldn't be able to compile it anyway. And `extern "C"` doesn't do anything for classes anyway. – Some programmer dude Aug 30 '21 at 05:46
  • I had some problem with using C and C++ source files together and I have found out that adding ```#ifdef __cplusplus``` in all header files fix the problem. Also, my controller source file is cpp not c, sorry for the confusion @folibis. I can compile this without any issues. I will try to make the static function and pass a pointer to the object as you have suggested and post back the results. – TheBestPlayer Aug 30 '21 at 05:50
  • 1
    Well as @folibis says, you're writing C++ code in C source files, that will lead to many problems. Use e.g. `.cpp` as suffix for C++ source files. And don't include C++ header files in C source files. – Some programmer dude Aug 30 '21 at 06:00
  • What if my program is a mixture of C and C++? I am programming in ESP32 and most ready to use libraries I include are C but when i write my own components I write them in C++. Sometimes I need to include C headers to my C++ components because they have some dependancies or I need to call some functions and etc.. – TheBestPlayer Aug 30 '21 at 06:02
  • Including C headers in C++ source files should work fine (using `extern "C"` if you have function declarations, it's not needed otherwise). It's the opposite that's the problem. And you really need to separate the source files, using a different suffix for C and C++ source files. If possible set up your project directory structure to separate C and C++ even more, and learn how to create (static) libraries so you can more easily separate modules into their own libraries. – Some programmer dude Aug 30 '21 at 06:09
  • Does this answer your question? [c++: Difference between member and non member functions](https://stackoverflow.com/questions/5920916/c-difference-between-member-and-non-member-functions) – Ulrich Eckhardt Aug 30 '21 at 06:09
  • I have managed to get some good results. I have updated my initial questions. I am still learning about static member functions and trying to understand why I need to do that – TheBestPlayer Aug 30 '21 at 06:34
  • @UlrichEckhardt I am aware of differences between member and non member class functions. I have initially had my task function as a member function but it did not work for some reason. For some reason it works when declared as static. I am trying to understand why and learn more. – TheBestPlayer Aug 30 '21 at 06:39
  • `static` functions are like (free) non-member functions. – Ulrich Eckhardt Aug 30 '21 at 06:44
  • @UlrichEckhardt Oh okay I see now! So what is the difference declaring a static method vs declaring non member method? – TheBestPlayer Aug 30 '21 at 06:49
  • @TheBestPlayer Scoping is a major factor. It seems to me that you might need to invest in [some good C++ books](https://stackoverflow.com/a/388282/440558). – Some programmer dude Aug 30 '21 at 06:52
  • Yes you are probabaly right, having a good book on hand could be very useful. I am still reading on how to decide when to use non member functions vs static member functions. – TheBestPlayer Aug 30 '21 at 07:05
  • I have also updated my initial question once again and would be very happy if you could explain why I cannot declare my task function as a class member – TheBestPlayer Aug 30 '21 at 07:38
  • @Someprogrammerdude Could you recommend a single decent easily accessible book for beginner-intermediate – TheBestPlayer Aug 30 '21 at 08:06

2 Answers2

0

In regard to "Why do I need to pass the pointer to my controller object? Since it is declared as class method, it automatically has access to class function and variables", static methods only have access to static members of a class. In other words, static methods and members belong to the class, not to instances of the class. You need to pass your static method a pointer to your instance so access the instance and its members.

As to why it must be a static method, I wonder that myself.

0

The FreeRTOS headers have the needed code (the conditional extern “C”) to make them interface with C++ code - but any callback that FreeRTOS calls by name will also need to be declared as extern “C”. So calling xTaskCreate from C++ works, but FreeRTOS cannot call your class method as it is not declared with extern "C". You declared the class as extern "C", but not the methods (which you cannot declare as extern "C"). The compiler "detects" this mismatch via name mangling (google this for further details).

You could make a bridging function outside the class (e.g. as part of a C-struct) which holds the pointer to your controller class and which calls your member-methods with the help of the pointer whenever FreeRTOS calls this bridging function. You could also use the argument passed to xTaskCreate to hold the instance pointer.

Jens
  • 6,173
  • 2
  • 24
  • 43