Object Oriented tasks - variables going out of scope?

I’m trying to use C++ objects as tasks and am having trouble getting member data passed into a new instance.

For example I have a button monitor that reports presses to a seat manager but none of the instance variables populate inside my task loop.

Edit: this is code for an ESP32 with their implementation of FreeRTOS.

Here’s the base class for a task object

class TaskBase {
  public:

    TaskBase(const char* name, UBaseType_t priority, configSTACK_DEPTH_TYPE stackDepth=configMINIMAL_STACK_SIZE) {
      xTaskCreate(&taskLoop, name, stackDepth, this, priority, &handle);
    }

  protected:
    virtual void task() = 0;

  private:
    TaskHandle_t handle;

    static void taskLoop(void* param) {
      TaskBase* obj = const_cast<TaskBase*>(static_cast<const TaskBase*>(param));
      obj->task();
    }
};

A button monitor derived from it

class ButtonMonitor : public TaskBase {
  public:
    ButtonMonitor( uint8_t pin,
                   QueueHandle_t queue,
                   touch_value_t capThreshold = 40000,
                   const char* name = "Button Monitor",
                   UBaseType_t priority = PRIO_MEDIUM,
                   configSTACK_DEPTH_TYPE stackDepth = 2000 );

  protected:
    void task();

  private:
    static const TickType_t xDebounceDuration      = pdMS_TO_TICKS(50);
    static const TickType_t xLongPressDuration     = pdMS_TO_TICKS(700);
    static const TickType_t xPressDuration         = pdMS_TO_TICKS(250);
    static const TickType_t xSequentialTapDuration = pdMS_TO_TICKS(250);
    static const TickType_t xWaitDuration          = pdMS_TO_TICKS(20);

    uint8_t _pin;
    touch_value_t _capThreshold;
    QueueHandle_t _sendQueue;

};

Button monitor implementation

ButtonMonitor::ButtonMonitor( uint8_t pin,
                              QueueHandle_t queue,
                              touch_value_t capThreshold,
                              const char* name,
                              UBaseType_t priority,
                              configSTACK_DEPTH_TYPE stackDepth ) :
  TaskBase( name, priority, stackDepth ), _pin(pin), _sendQueue(queue), _capThreshold(capThreshold) {

}

void ButtonMonitor::task() {
  log_i("pin %d", _pin);
  log_i("cap threshold %d", _capThreshold);
  while(1) {
    // FIXME use _pin and _capThreshold
    bCurrPressed = touchRead(10) > 40000;

    // a bunch of correctly working button code

    log_i("Queue %d Seat %2d Touches %d", _sendQueue, sensorData.seat, sensorData.reading);
    xQueueSend(_sendQueue, &sensorData, portMAX_DELAY);

    // more button code
    vTaskDelay(20);  // FIXME use xWaitDuration
  }
}

main (edited for clarity)

void setup() {
  SemaphoreHandle_t xBoardStateChangedSemaphore = xSemaphoreCreateBinary();
  QueueHandle_t xSeatManagerReceiveQueue = xQueueCreate(2, sizeof(SensorData_t));

  vTaskDelay(500);
  ButtonMonitor b( 10, xSeatManagerReceiveQueue, 40000 );
  log_i("Button monitor go");

  vTaskDelay(500);
  SeatManager s( xSeatManagerReceiveQueue, xBoardStateChangedSemaphore );
  log_i("Seat manager go");
}

Run log

[    95][I][esp32-hal-psram.c:96] psramInit(): PSRAM enabled
[  1100][I][main.cpp:16] setup(): Blarkey Blark & The Blunky Funch in the house!!!!
o  1600][I][mutton_monitor.cpp[: 1 71]6 0t0a]s[kI(])[:b uptitno n1_0m
t␀i
or.cpp:17] task(): pin 10
[  1600][I][button_monitor.cpp:18] task(): cap threshold 40000
[  2100][I][main.cpp:27] setup(): Seat manager go
[  3764][I][button_monitor.cpp:81] task(): Queue 0 Seat  0 Touches 2

assert failed: xQueueGenericSend queue.c:820 (pxQueue)


Backtrace: 0x40377332:0x3fcec880 0x4037aab5:0x3fcec8a0 0x403803d1:0x3fcec8c0 0x4037b2e3:0x3fcec9f0 0x420017cb:0x3fceca30 0x4201f649:0x3fceca80

  #0  0x40377332:0x3fcec880 in panic_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/panic.c:408
  #1  0x4037aab5:0x3fcec8a0 in esp_system_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:137
  #2  0x403803d1:0x3fcec8c0 in __assert_func at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/assert.c:85
  #3  0x4037b2e3:0x3fcec9f0 in xQueueGenericSend at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/queue.c:821 (discriminator 2)
  #4  0x420017cb:0x3fceca30 in ButtonMonitor::task() at src/button_monitor.cpp:82
  #5  0x4201f649:0x3fceca80 in TaskBase::taskLoop(void*) at src/task_base.h:33

As you can see, the log shows the ButtonManager instance correctly assigns _pin and _capThreshold but when I reference them in the while loop I get zeros instead. The panic happens when writing data to the queue.

Seems I’m missing some variable scope concept here. Any suggestions? Thanks.

also, you can not use vTaskDelay() in main(), only in tasks.

Probably this might be the problem resp. the solution: Task-class cast in callback method not working - #9 by hs2

This might be the case. I’ll look deeper today. Thank you.

I forgot to mention that this is ESP32 code. setup() is already running in a task.

You are declaring object instances in the function setup, which will be destroyed when that function returns.

1 Like

This is the answer. Thank you.