Using BluetoothAD2PSink in FreeRTOS class in C++ #629
-
I am trying to use the BluetoothA2DPSink object inside a class who contains my task function in C++. My intention is to create an App class who handles the Bluetooth device but also the amplifiers, the DSP, etc... I have tried to create a pointer to this class but each time a get a kernel panic. I have to tried to create BluetoothA2DPSink inside task class using pointers, in class attributes or in setup function but the result is still the same. How can I create correctly the object to use it in other methods in the class (so not only in task function) ? |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 3 replies
-
I don't understand: can you share a minimal sketch that highlits your problem ? |
Beta Was this translation helpful? Give feedback.
-
Current sketchmain.cpp#include "main.hpp"
void setup()
{
App app;
Serial.begin(9600);
while (!Serial);
Serial.println("Start");
// Queues
serialQueue = xQueueCreate(1, sizeof(Serial_Message_t));
// Tasks
xTaskCreate(vtaskSerial, "TaskSerial", SERIAL_STACK_SIZE, NULL, 3, NULL);
xTaskCreate(App::taskWrapper, "TaskApp", APP_STACK_SIZE, NULL, 2, NULL);
Serial.println("Created tasks");
}
// Nothing here, everything is done in tasks
void loop()
{
} app.hpp#pragma once
/* Static libraries */
#include <Arduino.h>
/* Dynamic libraries */
// Audio Bluetooth
#include "AudioTools.h"
#include "BluetoothA2DPSink.h"
// Internal libraries
#include "config.hpp"
#include "shared_ressources.hpp"
#include "flash.hpp"
#include "serial.hpp"
class App
{
public:
App(void);
static void taskWrapper(void* pvParameters);
void task(void* pvParameters);
private:
I2SStream* i2s;
BluetoothA2DPSink* a2dp_sink;
}; app.cpp#include "app.hpp"
App::App(void)
{
}
void App::taskWrapper(void* pvParameters)
{
static_cast<App*>(pvParameters)->task(pvParameters);
}
void App::task(void* pvParameters)
{
FlashHandle_t flash;
Serial_Message_t serialMessage;
// Start flash handler
i2s = new I2SStream;
a2dp_sink = new BluetoothA2DPSink(*i2s);
flash.init();
// Start bluetooth receiver
a2dp_sink->set_auto_reconnect(true, AUTOCONNECT_TRY_NUM);
a2dp_sink->start(SPEAKER_NAME);
// Loop
while (1)
{
// To get value, cast the void* pointer into type
// example with a double :
// double val
// val = *((double*)serialMessage.value)
if (xQueueReceive(serialQueue, &serialMessage, portMAX_DELAY) == pdPASS)
{
}
vTaskDelay(pdTICKS_TO_MS(50));
}
} I guess that not declaring it in setup() function is a problem, but I have already tried to do it and to pass it through a pointer to the object in the class, and I get the same kernel panic. |
Beta Was this translation helpful? Give feedback.
-
I think the problem is, like I stated above, that you allocate App on the stack and as soon as setup() is left, it does not exist any more ! This is crashing when you try to access it from the FreeRTOS task. Move it out to a global variable or allocate it with new on the heap! I also suggest that you replace the pointers in your App class with regular class objects: use I2SStream i2s; |
Beta Was this translation helpful? Give feedback.
-
You are right that allocating App in the setup() function was an issue. I tried to declare it as global, but still have the same problem Updated sketchmain.hpp#include "main.hpp"
I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);
App app(&a2dp_sink);
void setup()
{
Serial.begin(9600);
while (!Serial);
Serial.println("Start");
// Queues
serialQueue = xQueueCreate(1, sizeof(Serial_Message_t));
// Tasks
xTaskCreate(vtaskSerial, "TaskSerial", SERIAL_STACK_SIZE, NULL, 3, NULL);
xTaskCreate(App::taskWrapper, "TaskApp", APP_STACK_SIZE, NULL, 4, NULL);
Serial.println("Created tasks");
}
// Nothing here, everything is done in tasks
void loop()
{
} app.hpp#pragma once
/* Static libraries */
#include <Arduino.h>
/* Dynamic libraries */
// Audio Bluetooth
#include "AudioTools.h"
#include "BluetoothA2DPSink.h"
// Internal libraries
#include "config.hpp"
#include "shared_ressources.hpp"
#include "flash.hpp"
#include "serial.hpp"
class App
{
public:
App(BluetoothA2DPSink* sink);
static void taskWrapper(void* pvParameters);
void task(void* pvParameters);
private:
BluetoothA2DPSink* a2dp_sink;
}; app.cpp#include "app.hpp"
App::App(BluetoothA2DPSink* sink) : a2dp_sink(sink)
{
}
void App::taskWrapper(void* pvParameters)
{
static_cast<App*>(pvParameters)->task(pvParameters);
}
void App::task(void* pvParameters)
{
FlashHandle_t flash;
Serial_Message_t serialMessage;
// Start flash handler
flash.init();
// Start bluetooth receiver
a2dp_sink->set_auto_reconnect(true, AUTOCONNECT_TRY_NUM);
a2dp_sink->start(SPEAKER_NAME);
// Loop
while (1)
{
// To get value, cast the void* pointer into type
// example with a double :
// double val
// val = *((double*)serialMessage.value)
if (xQueueReceive(serialQueue, &serialMessage, portMAX_DELAY) == pdPASS)
{
}
vTaskDelay(pdTICKS_TO_MS(50));
}
} I guess that to make it work, I need to work with BluetoothA2DPSink as a global object and not using a reference to it. So it is not possible to use it in a function passing BluetoothA2DPSink as a parameter ? |
Beta Was this translation helpful? Give feedback.
-
As I was writing above, I would define the BluetoothA2DPSink, I2SStream and BufferRTOS or QueueRTOS (from the AudioTools) as variables of your APP class. Or you can just read the queue in your loop and write to the APP class. I am not sure if a queue is needed at all, so I would first try w/o it. Just read from serial in the loop and interpet the read string in the APP class You don't need to define another task Try to keep things as simple as possible: this will reduce the risk of errors... |
Beta Was this translation helpful? Give feedback.
-
Hello again, I have tried a lot a different things to make it work but I stil didn't manage to do it. Now I have created objects as global, but I still get the Guru Mediation Error. Here is my updated code, maybe you will see what I couldn't find Updated sketchmain.hpp#include "main.hpp"
I2SStream i2s;
BluetoothA2DPSink a2dp_sink(i2s);
App app(&a2dp_sink);
void setup()
{
Serial.begin(9600);
while (!Serial);
Serial.println("Start");
// Queues
displayQueue = xQueueCreate(1, sizeof(uint8_t));
serialQueue = xQueueCreate(1, sizeof(Serial_Message_t));
// Tasks
xTaskCreate(vtaskSerial, "TaskSerial", SERIAL_STACK_SIZE, NULL, 1, NULL);
if (xTaskCreate(App::taskWrapper, "TaskApp", APP_STACK_SIZE, NULL, 2, NULL))
Serial.println("App success");
else
Serial.println("App failed");
Serial.println("Created tasks");
}
// Nothing here, everything is done in tasks
void loop()
{
} app.cpp#include "app.hpp"
App::App(BluetoothA2DPSink* sink): a2dp_sink(sink)
{
Serial.println("Created app");
}
void App::taskWrapper(void* pvParameters)
{
Serial.println("launching wrapper");
static_cast<App*>(pvParameters)->task(pvParameters);
Serial.println("Created Wrapper");
}
void App::task(void* pvParameters)
{
FlashHandle_t flash;
Serial_Message_t serialMessage;
// Start flash handler
flash.init();
// Start bluetooth receiver
Serial.println("Config sink");
a2dp_sink->set_auto_reconnect(true, AUTOCONNECT_TRY_NUM);
Serial.println("config auto reconnect sink");
a2dp_sink->start(SPEAKER_NAME);
Serial.println("started sink");
// Loop
while (1)
{
// To get value, cast the void* pointer into type
// example with a double :
// double val
// val = *((double*)serialMessage.value)
if (xQueueReceive(serialQueue, &serialMessage, portMAX_DELAY) == pdPASS)
{
Serial.println("alive");
}
vTaskDelay(pdTICKS_TO_MS(50));
}
} From the beginning I get this error Error (the same from the beginning)Guru Meditation Error: Core 1 panic'ed (Unhandled debug exception).
Debug exception reason: BREAK instr
Core 1 register dump:
PC : 0x400849d8 PS : 0x00000016 A0 : 0x40080306 A1 : 0x3ffcb6d0
A2 : 0x00000003 A3 : 0x00060923 A4 : 0x0000abab A5 : 0x3ffd0b60
A6 : 0x007bf358 A7 : 0x00000000 A8 : 0x00000000 A9 : 0x3ffcb6a0
A10 : 0x3ffc455c A11 : 0x3ffc455c A12 : 0xb33fffff A13 : 0x00060923
A14 : 0x00060923 A15 : 0x00000001 SAR : 0x00000016 EXCCAUSE: 0x00000001
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0xbaad5678 LCOUNT : 0xffffffff
Backtrace: 0x400849d5:0x3ffcb6d0 0x40080303:0x3ffcb720 0x400d3b5e:0x3ffcb770 0x400d8a5a:0x3ffcb7a0
ELF file SHA256: 84934ab834b3e18d
E (983) esp_core_dump_flash: Core dump flash config is corrupted! CRC=0x7bd5c66f instead of 0x0 I have tried to increase the stack size for this task, thinking that I was producing a stack overflow, but it didn't fix anything |
Beta Was this translation helpful? Give feedback.
-
Ok so I have finally managed to make it work correctly, so I am happy to share with you a working code. It seems that the task wrapper used to allow a method as task function was creating the problem. It is working with FreeRTOS in C currently, but I guess that inheriting from the task class from freeRTOS-addons to create App class would be an improvement. I wanted to have the Bluetooth class in app to handle it in a specified location so I am happy with this structure. Working sketchmain.cpp#include "main.hpp"
void setup()
{
Serial.begin(9600);
while (!Serial);
Serial.println("Start");
// Queues
serialQueue = xQueueCreate(1, sizeof(Serial_Message_t));
// Tasks
xTaskCreate(vtaskSerial, "TaskSerial", SERIAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vtaskApp, "TaskApp", APP_STACK_SIZE, NULL, 2, NULL);
Serial.println("Created tasks");
}
// Nothing here, everything is done in tasks
void loop()
{
} app.hpp#pragma once
/* Static libraries */
#include <Arduino.h>
/* Dynamic libraries */
// Audio Bluetooth
#include "AudioTools.h"
#include "BluetoothA2DPSink.h"
// Internal libraries
#include "config.hpp"
#include "shared_ressources.hpp"
#include "flash.hpp"
#include "serial.hpp"
// Task functiion
void vtaskApp(void* pvParameters);
// App class
class App
{
public:
App(void);
void start(void);
private:
I2SStream i2s;
BluetoothA2DPSink a2dp_sink;
FlashHandle_t flash;
Serial_Message_t serialMessage;
}; app.cpp#include "app.hpp"
void vtaskApp(void* pvParameters)
{
App app;
// Start app
app.start();
}
// App class
App::App(void): a2dp_sink(i2s)
{
}
void App::start(void)
{
// Start flash handler
flash.init();
// Start bluetooth receiver
Serial.println("Config sink");
a2dp_sink.set_auto_reconnect(true, AUTOCONNECT_TRY_NUM);
Serial.println("config auto reconnect sink");
a2dp_sink.start(SPEAKER_NAME);
Serial.println("started sink");
// Loop
while (1)
{
// To get value, cast the void* pointer into type
// example with a double :
// double val
// val = *((double*)serialMessage.value)
if (xQueueReceive(serialQueue, &serialMessage, portMAX_DELAY) == pdPASS)
{
}
// Serial.println("app task");
vTaskDelay(pdTICKS_TO_MS(500));
}
} I would share an updated code if I manage to achieve a better architecture |
Beta Was this translation helpful? Give feedback.
I think the problem is, like I stated above, that you allocate App on the stack and as soon as setup() is left, it does not exist any more ! This is crashing when you try to access it from the FreeRTOS task.
Move it out to a global variable or allocate it with new on the heap!
I also suggest that you replace the pointers in your App class with regular class objects: use I2SStream i2s;
BluetoothA2DPSink a2dp_sink: this way the destruction of the object will not lead to any memory leaks