1

I am writing an embedded application using freeRTOS and I'm trying to do it in a neat, object-oriented fashion.

To start a FreeRTOS task from within an object, you need to give it a static function. In order to make it possible to use non-static variables inside that function, I've been implementing it in the following way:

void ModeSwitcher::loop(){
    // Can use any member of the ModeSwitcher class here
}

void ModeSwitcher::runner(void* parameter){ // declared as static in header
    ModeSwitcher* ref = static_cast< ModeSwitcher *>(parameter);

    while(1){
        ref->loop();
    }
}

void FlightMode::start(uint8_t core_id) {
    xTaskCreatePinnedToCore(
    runner,           // Task function
    "switcher",       // String with name of task
    2000,             // Stack size in bytes
    this,             // Parameter passed as input of the task
    1,                // Priority of the task
    &this->xHandle,   // Task handle
    core_id           // The cpu core to use
    );
}

As you can see, the static runner is passed to rtos, which can on the other hand pass 'this' pointer back to runner. Thanks to that I can put all my code neatly in the loop and just call it by reference.

However, now I have two almost identical classes. The only difference is the code inside the 'loop'. So I would like to put my start and runner methods in a base class and the loop in a derived class. I imagine it can most likely be written in a similar way. However I can't get it to work. In my had it looks somewhat like that:

base_mode.cpp :

BaseMode::BaseMode(const char* name, void* ref) : task_name(name), reference(ref) {

}

void BaseMode::start(uint8_t core_id) {
    xTaskCreatePinnedToCore(
        runner,           // Task function
        task_name,        // String with name of task (by default max 16 characters long)
        2000,             // Stack size in bytes
        reference,        // Parameter passed as input of the task
        1,                // Priority of the task
        &this->xHandle,   // Task handle
        core_id 
    );
}

void BaseMode::runner(void* parameter){
    BaseMode* ref = static_cast<BaseMode *>(parameter);

    while(1){
        ref->loop();
    }
}

ground_mode.cpp :

void GroundMode::loop(){
    // Again, should be able to do whatever is desired here
}

GroundMode::GroundMode() : BaseMode("ground_mode", this){
    
}

It doesn't work, because there's no loop function declared in base class. If I declared one, it would be used instead of the one inside the derived class. So how can I fix this? Thanks in advance.

  • 5
    Do you know about [virtual functions](https://en.cppreference.com/w/cpp/language/virtual)? – Paul Sanders Jan 17 '22 at 22:57
  • 2
    You can also avoid overhead of the virtual function dispatch by using the Curiously Recurring Template Pattern. – Ben Voigt Jan 17 '22 at 23:00
  • See https://stackoverflow.com/a/262984/103167 the first example in the accepted answer is a call trampoline almost exactly like what you are needing. – Ben Voigt Jan 17 '22 at 23:02
  • An alternative to using virtual functions, is to simply define your `runner` function as a static member of your derived class. – selbie Jan 18 '22 at 02:26

1 Answers1

0

Declaring a virtual loop function in BaseMode worked. Forgot these even existed.