Unable to consume queue from a task in a class

Hello and pardon if this is a stupid question, but Im new to both C++ and FreeRTOS and my Googling is coming up with nothing.

For context Im writing control software[1] that essentially reads a bunch of potentiometers and controls a bunch of other stuff (think led strips, amplifiers etc.).

The way it’s currently implemented is that I have a bunch of tasks and queues.
I have a task that reads my potentiometers and maps and mucks about with the readings and send the values on a queue. I have a multiplexer that reads that queue and writes to n new queues. I have n tasks that reads from those other queues (i.e each task should have the exact same value at the same time) so that I can for instance control a LED strip and update an OLED display and the values used to do that is exactly the same.

It works great but its a bit spaghetti so today I wanted to convert it all to use classes and follow some OOP principles. But I cannot make it work.

Here is a simplified example and its output.

main.cpp

#include <Arduino.h>
#include <printTask.h>

void setup() {
    Serial.begin(115200);

    long a, b, c, d, e;
    a = 1337;
    b = 420;
    c = 666;
    d = 80085;
    e = 12345;
    QueueHandle_t printQueue = xQueueCreate(5, sizeof(long));
    xQueueSend(printQueue, &a, 0);
    xQueueSend(printQueue, &b, 0);
    xQueueSend(printQueue, &c, 0);
    xQueueSend(printQueue, &d, 0);
    xQueueSend(printQueue, &e, 0);

    long qa;
    xQueueReceive(printQueue, &qa, 0);
    log_i("Received from queue: %d", qa);

    Printer p(printQueue);
}

void loop() {}

printTask.h

#ifndef PRINT_TASK
#define PRINT_TASK
#include <Arduino.h>

class Printer {
  private:
    QueueHandle_t queue_;
    static void startLoop(void *pvParams);
    void loop();
    void randomFunction();

  public:
    Printer(QueueHandle_t queue);
};

#endif

printTask.cpp

#include <printTask.h>

void Printer::loop() {
    log_i("Starting loop");
    for (;;) {
        long val;
        if (xQueueReceive(queue_, &val, portMAX_DELAY) == pdPASS) {
            log_i("Received from stored queue in loop: %d", val);
        }
    }
}

void Printer::startLoop(void *_this) {
    // Doesnt work
    // ((Printer *)_this)->loop();

    // Doesn't work either
    static_cast<Printer *>(_this)->loop();
}

void Printer::randomFunction() {
    long val;
    xQueueReceive(queue_, &val, 0);
    log_i("Received from stored queue: %d", val);
}

Printer::Printer(QueueHandle_t queue) {
    queue_ = queue;

    long val;
    xQueueReceive(queue, &val, 0);
    log_i("Received from passed in queue: %d", val);

    xQueueReceive(queue_, &val, 0);
    log_i("Received from stored queue: %d", val);

    this->randomFunction();

    xTaskCreate(Printer::startLoop, "", 2048, this, 1, NULL);
}

The output I get when I run is

[    21][I][main.cpp:31] setup(): Received from queue: 1337
[    21][I][printTask.cpp:43] Printer(): Received from passed in queue: 420
[    22][I][printTask.cpp:46] Printer(): Received from stored queue: 666
[    28][I][printTask.cpp:35] randomFunction(): Received from stored queue: 80085
[    36][I][printTask.cpp:15] loop(): Starting loop

assert failed: spinlock_acquire spinlock.h:122 (result == core_id || result == SPINLOCK_FREE)


Backtrace:0x400833d1:0x3ffb96d00x40087cfd:0x3ffb96f0 0x4008ca49:0x3ffb9710 0x4008a767:0x3ffb9840 0x400889d2:0x3ffb9880 0x400d133f:0x3ffb98c0 0x400d1381:0x3ffb9900 




ELF file SHA256: 0000000000000000

Rebooting...

How come I cannot use the queue in my loop?

Thanks, and have a nice weekend.

Simon.

[1] simonjohansson/dreamHouse on github.

Not positive, but you are defining the object p of class Printer as a local in your setup function, and then immediately returning from the function, which will destroy that object, and it space will get reclaimed and used by other objects.

Thus, when the task runs, it has been given a pointer to an object that no longer exists.

@richard-damon aaah yes! Declaring Printer outside of setup and

printer = new Printer(printQueue);

in setup solves the problem.

Thanks!

Not an uncommon problem.

Personally, I would have used a wrapper for the Queue and declared at global scope:

Queue<long> printQueue;
Printer p(printQueue);

Where Queue is a wrapper class for a FreeRTOS Queue that makes a queue to handle object of its template parameter type. Making it at global scope says it is automatically made before the main program starts. (but make sure your logging is setup before that).

1 Like