Repeatedly Play Audio on Sony Spresense - arduino

I'm trying to repeatedly play an audio file on the Sony Spresense. I have tested the example sketches provided by Sony and they work fine for playing an audio file. But if I want to replay the file, I get errors. Unfortunately, all sketches only play their file once...
To keep it simple, I have shrunk the source code.
#include <Audio.h>
#include <SDHCI.h>
static void audioErrorCallback(const ErrorAttentionParam *atprm);
bool initializeSound();
SDClass theSD;
AudioClass *theAudio;
File soundFile;
bool soundFinished;
void setup() {
Serial.begin(115200);
while (!Serial);
initializeSound();
soundFinished = true;
}
void loop() {
if (!soundFinished) {
int err = theAudio->writeFrames(AudioClass::Player0, soundFile);
if (err == AUDIOLIB_ECODE_FILEEND) {
soundFinished = true;
stopPlay();
}
} else {
Serial.println("Sleep");
delay(3000);
soundFinished = false;
startPlay();
}
usleep(40000);
}
static void audioErrorCallback(const ErrorAttentionParam *atprm) {
if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
{
Serial.println("Error!");
}
}
bool initializeSound() {
theAudio = AudioClass::getInstance();
theAudio->begin(audioErrorCallback);
theAudio->setRenderingClockMode(AS_CLKMODE_NORMAL);
theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_SPHP, AS_SP_DRV_MODE_LINEOUT);
theAudio->initPlayer(AudioClass::Player0, AS_CODECTYPE_MP3, "/mnt/sd0/BIN", AS_SAMPLINGRATE_AUTO, AS_CHANNEL_STEREO);
soundFile = theSD.open("audioFile.mp3");
theAudio->setVolume(-160);
return true;
}
void startPlay() {
theAudio->writeFrames(AudioClass::Player0, soundFile);
theAudio->startPlayer(AudioClass::Player0);
}
void stopPlay() {
theAudio->stopPlayer(AudioClass::Player0);
// soundFile.close();
}
The audio file is played without problems for the first time. Afterwards, I receive the following error, always:
Attention: module[5] attention id[2]/code[6] (objects/media_player/player_input_device_handler.cpp L220)
Error!
ERROR: Command (0x22) fails. Result code(0xf1) Module id(0x5) Error code(0x2f) Error subcode(0x0)
ERROR: Command (0x23) fails. Result code(0xf1) Module id(0x5) Error code(0x1)
What's missing? Any ideas?

I had a similar issue, and I was able to fix it by closing the File at the end, and creating a new File at the the start of the loop() instead of in the setup() function.

Related

ESP32 FreeRTOS pin interrupt ISR handler core 0 panic (C++)

Currently I am trying to attach a pin interrupt whose ISR is to call xTaskResumeFromISR or xQueueSendFromISR. The ISR gets called correctly, but the code to execute results in a core 0 panic.
Here are the implementation details.
PlatformIO: platform = espressif32 # 6.0.1, framework = arduino, board = esp32dev
Header file (Worker.h)
#pragma once
#include <Arduino.h>
class Worker {
public:
Worker(uint8_t pinExtInterrupt);
bool startTask(void);
protected:
// static wrapper for task creation
static void staticRun(void *arg) {
reinterpret_cast<Worker *>(arg)->run();
}
// actual task's logic
void run(void);
// static interrupt handler
static void staticIsrHandler(void* arg);
// actual interrupt handler
void isrHandler();
TaskHandle_t _taskHandle = nullptr;
uint8_t _pinExtInterrupt;
};
Source file (Worker.cpp)
#include "Worker.h"
Worker::Worker(uint8_t pinExtInterrupt) {
_pinExtInterrupt = pinExtInterrupt;
pinMode(pinExtInterrupt, INPUT);
}
bool Worker::startTask(void) {
BaseType_t xReturned = xTaskCreate(staticRun, "Worker", 2048, this, 5, &_taskHandle);
gpio_set_intr_type(static_cast<gpio_num_t>(_pinExtInterrupt), GPIO_INTR_NEGEDGE);
gpio_install_isr_service(0);
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
return true;
}
void Worker::run(void) {
for (;;) {
vTaskSuspend(NULL);
// LOGIC
}
}
void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
reinterpret_cast<Worker*>(arg)->isrHandler();
}
void IRAM_ATTR Worker::isrHandler() {
xTaskResumeFromISR(_taskHandle); // ###### THIS LINE THROWS THE EXCEPTION ######
}
Error
Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
0x400d1d00:0x3ffbeaac in Worker::isrHandler() at ...
But what works is if you replace xTaskResumeFromISR e.g. with digitalWrite(..).
Need to fix the problem above.
Your call here:
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
assigns a null pointer for the ISR handler's context data. As a result, when your static ISR is called:
void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
reinterpret_cast<Worker*>(arg)->isrHandler();
}
arg is a null pointer, causing the access to _taskHandle to fail here:
void IRAM_ATTR Worker::isrHandler() {
xTaskResumeFromISR(_taskHandle);
}
If you replace your gpio_isr_handler_add call with the following:
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, this);
everything should work.

Overloading function handling char and String

I'm making a function to handle a message, then print the message using Serial.println(). I have it working, but ran into an issue I can't explain. The first sample code below works, the second (swapping the order of my function declaration) will compile and load, but causes the Teensy 4.1 to crash. I'm using PlatformIO on VSCode.
Can anyone tell me what is wrong with the second code, and why it will compile without error, but not run?
This works:
#include <Arduino.h>
void LogMsg(const char *msg){
Serial.println(msg);
}
void LogMsg(String s){ LogMsg(s.c_str()); }
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("reset");
}
void loop() {
// put your main code here, to run repeatedly:
String str3 = "testing string cat ";
uint32_t var = 12345;
LogMsg(str3 + var);
delay(500);
}
This compiles, loads, but crashes, causing continuous resets:
#include <Arduino.h>
void LogMsg(String s){ LogMsg(s.c_str()); } // <-- swapped order
void LogMsg(const char *msg){ // <-- swapped order
Serial.println(msg);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("reset");
}
void loop() {
// put your main code here, to run repeatedly:
String str3 = "testing string cat ";
uint32_t var = 12345;
LogMsg(str3 + var);
delay(500);
}
Edit: The definition of void LogMsg(String s) was changed to reflect error in original and the simplification suggested by #hcheung. Behavior remains the same. The first instance works, the second crashes.
C strings are terminated with '\0'. So toCharArray() will append a null character to your Ardunio String. Otherwise you would have to provide a length with the char pointer everytime you want to use that string.
Your char array must be big enough to fit this extra character or you will cause an access violation if toCharArray does not throw an exception first.

gtkmm/button.h no such file or directory

Whenever i try to run my code this error "gtkmm/button.h no such file or directory" pop up in the console i don't know what is this error and this page also pops up every time. This is my code.
#include<iostream>
#include<conio.h>
using namespace std;
class bubble{
private:
arr[5];
public:
void getdata();
void sort();
void display();
};
void bubble::getdata(){
int i;
for(i=0;i<=4;i++)
{
cout<<"enter the element in the array";
cin>>""<<arr[i];
}
}
void bubble::sort(){
int i,j,temp;
for(i=1;i<=4;i++)
{
for(j=0;j<=4;j++)
{
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
void bubble::display(){
int i;
for(i=0;i<=4;i++)
{
cout<<"after sorting the array intto bubble sort: "<<arr[i];
}
}
int main(){
bubble b;
b.getdata();
b.sort();
b.display();
getch();
return 0;
}
Your bubble sorting program doesn't seem to use any GTKMM APIs. It's a pure console program, not a GUI application.
The popup error could be because of your IDE codelite configuration mess up. I don't use codelite so I cannot really know for sure.
Have you tried compiling your C++ program and running it on cmd or terminal prompt?

Arduino error: does not name a type?

I have written a library, but have problem with error does not name a type. I've tryed everything, searched for couple of hours and no luck. Library is placed in the "libraries" folder of the arduino sketch folder. Please help!!! I am using OSX, but the same problem occurs on Windows also.
This is header file of the library:
#ifndef OpticalSensor_h
#define OpticalSensor_h
#include <Arduino.h>
#include <SD.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
#include <String.h>
class OpticalSensor
{
public:
OpticalSensor(int analogPort);
void LCDInit(int columns, int rows);
void SerialInit(int bitRate);
void SDInit();
double& ReadFromAnalogPort();
void SDCreateFile(String fileName);
void SDDeleteFile(String fileName);
void SDWriteToFile(String fileName);
void SDStreamToFile(String Text);
void SDOpenFileToStream(String fileName);
private:
int _analogPort;
bool _displayFlag;
Adafruit_RGBLCDShield _lcd;
File _MainRecFile;
double _voltage;
void _LCDClearAll();
void _LCDWriteInTwoRows(String row1, String row2);
void _DelayAndClearLCD(bool returnStatus);
};
#endif
This is .cpp file of the library:
#include <OpticalSensor.h>
Adafruit_RGBLCDShield _lcd;
File _MainRecFile;
double _voltage;
OpticalSensor::OpticalSensor(int analogPort)
{
_analogPort = analogPort;
}
void OpticalSensor::LCDInit(int columns, int rows)
{
_lcd = Adafruit_RGBLCDShield();
_lcd.begin(columns,rows);
}
void OpticalSensor::SerialInit(int bitRate)
{
Serial.begin(bitRate);
_bitRate = bitRate;
while(!Serial) {
//wait until serial is not open
}
}
void OpticalSensor::SDInit()
{
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
//check if SD can be found and initialized. Print also message to
//Serial if initialized and to _lcd if initialized.
if(!SD.begin(4)) {
if(Serial){
Serial.println("Initialization failed!");
}
if(_lcd){
_lcd.print("Init failed!");
}
_DelayAndClearLCD(true);
}
else {
if(Serial) {
Serial.println("Initialization done!");
}
if(_lcd) {
lcd.print("Init done!");
}
_DelayAndClearLCD(false);
}
}
void OpticalSensor::SDCreateFile(String fileName)
{
//check if file allready exists, if not it creates one
//and writes apropriate response to
//lcd and Serial if they are initialized.
if(SD.exists(fileName)) {
if(Serial) {
Serial.println(fileName + " already exists!");
}
if(_lcd) {
_LCDWriteInTwoLines(fileName,"already exists!");
}
_DelayAndClearLCD(false);
}
else
{
if(Serial) {
Serial.println(fileName + "Creating file " + fileName + "...");
}
if(_lcd) {
_LCDWriteInTwoLines("Creating file", fileName);
}
_MainRecFile = SD.open(fileName + ".txt", FILE_WRITE);
_MainRecFile.close();
_DelayAndClearLCD(false);
//check if file was created successffully and print apropriate response
//to lcd and Serial if they are initialized
if(SD.exists(fileName + ".txt")) {
if(Serial) {
Serial.println(fileName + ".txt" + " created successffully!");
}
if(_lcd) {
_LCDWriteInTwoLines(fileName + ".txt", "created!");
}
_DelayAndClearLCD(false);
}
else {
if(Serial) {
Serial.println("error: failed to create file!");
}
if(_lcd) {
_LCDWriteInTwoLines("error: failed to","create file!");
}
_DelayAndClearLCD(false);
}
}
}
//delete file from SD card
void OpticalSensor::SDDeleteFile(String fileName)
{
}
//open file, write data to it, and close file after.
void OpticalSensor::SDWriteToFile(String fileName, String Text)
{
_MainRecFile = SD.open(fileName + ".txt", FILE_WRITE);
_MainRecFile.println(Text);
_MainRecFile.close();
}
//Open file to stream data to it.
void OpticalSensor::SDOpenFileToStream(String fileName)
{
_MainRecFile = SD.open(fileName + ".txt", FILE_WRITE);
}
//Write data to file while file is open.
//Notice that you can stream data only to one file at a time!!!
//For instance, if you have two sensors that you want to
//write data to two different files, you have to use SDWriteToFile
//function!!!
void OpticalSensor::SDStreamToFile(String Text)
{
if(_MainRecFile) {
_MainRecFile.println(Text);
}
}
//close file that you streamed data too.
void OpticalSensor::SDCloseStreaming(String fileName)
{
_MainRecFile.close();
}
//clear entire LCD
void OpticalSensor::_LCDClearAll()
{
_lcd.clear();
_lcd.setCursor(0,0);
}
void OpticalSensor::_LCDWriteInTwoRows(String row1, String row2)
{
//write first String in row1
_lcd.print(row1);
//set cursor to the beginning of row 2
_lcd.setCursor(0,1);
//write second String to row 2
_lcd.print(row2);
}
void OpticalSensor::_DelayAndClearLCD(bool returnStatus)
{
//if Serial or _lcd are initialized, delay for 2 seconds
//and clear LCD
if(Serial || _lcd) {
delay(2000);
if(_lcd)
_LCDClearAll();
}
//terminate
if(bool == true) {
return;
}
}
double& ReadFromAnalogPort()
{
_voltage = analogRead(_analogPort);
return _voltage;
}
And this is the .ino file where library is included:
#include <OpticalSensor.h>
OpticalSensor sensor(0);
void setup() {
sensor.LCDInit(16,2);
sensor.SerialInit(9600);
sensor.SDInit();
sensor.SDCreateFile("test1");
sensor.SDOpenFileToStream("test1");
}
void loop() {
}
this is the error:
In file included from Test_OpticalSensorLib.ino:1:
/Users/gaspersladic/Documents/Arduino/libraries/OpticalSensor/OpticalSensor.h:34:
error: 'Adafruit_RGBLCDShield' does not name a type
/Users/gaspersladic/Documents/Arduino/libraries/OpticalSensor/OpticalSensor.h:35:
error: 'File' does not name a type
The two includes you mention in your comment are essential. 'does not name a type' just means there is no definition for that identifier visible to the compiler. If there are errors in the LCD library you mention, then those need to be addressed - omitting the #include will definitely not fix it!
Two notes from experience which might be helpful:
You need to add all #include's to the main sketch - irrespective of whether they are included via another #include.
If you add files to the library folder, the Arduino IDE must be restarted before those new files will be visible.
I got the does not name a type error when installing the NeoMatrix library.
Solution: the .cpp and .h files need to be in the top folder when you copy it, e.g:
myArduinoFolder/libraries/Adafruit_NeoMatrix/Adafruit_NeoMatrix.cpp
When I used the default Windows unzip program, it nested the contents inside another folder:
myArduinoFolder/libraries/Adafruit_NeoMatrix/Adafruit_NeoMatrix/Adafruit_NeoMatrix.cpp
I moved the files up, so it was:
myArduinoFolder/libraries/Adafruit_NeoMatrix/Adafruit_NeoMatrix.cpp
This fixed the does not name a type problem.
I found the solution to this problem in a "}". I did some changes to my sketch and forgot to check for "}" and I had an extra one. As soon as I deleted it and compiled everything was fine.
Don't know it this is your problem but it was mine.
Void setup() does not name a type
BUT
void setup() is ok.
I found that the sketch I copied for another project was full of 'wrong case' letters. Onc efixed, it ran smoothly.emphasized text
The only thing you have to do is adding this line to
your sketch
#include <SPI.h>
before #include <Adafruit_MAX31855.h>.
More recently, I have found that other factors will also cause this error. I had an AES.h, AES.cpp containing a AES class and it gave this same unhelpful error. Only when I renamed to Encryption.h, Encryption.cpp and Encryption as the class name did it suddenly start working. There were no other code changes.
My code was out of void setup() or void loop() in Arduino.
Usually Header file syntax start with capital letter.I found that code written all in smaller letter
#ifndef DIAG_H
#define DIAG_H
#endif

File changes handle, QSocketNotifier disables due to invalid socket

I am developing for a touch screen and need to detect touch events to turn the screen back on. I am using Qt and sockets and have run into an interesting issue.
Whenever my QSocketNotifier detects the event it sends me infinite notices about it. Therefore I need to close and open the event file to cycle the notifier (inputNotifier in the below code). The problem usually arises several minutes after the device has been running and the file (inputDevice) suddenly changes it's handle from 24 to something else (usually 17).
I am not sure what to do, because the initial connect statement is linked to the initial Notifier pointer. If I create a new Notifier using the new handle, the connect is invalid. As far as I can tell there is no option to set a new socket value on a running QSocketNotifier. Suggestions? The relevant code is below:
#include "backlightcontroller.h"
#include <QTimer>
#include <QFile>
#include <syslog.h>
#include <QDebug>
#include <QSocketNotifier>
BacklightController::BacklightController(QObject *parent) :
QObject(parent)
{
backlightActive = true;
// setup timer
trigger = new QTimer;
trigger->setSingleShot(false);
connect(trigger, SIGNAL(timeout()), SLOT(deactivateBacklight()));
idleTimer = new QTimer;
idleTimer->setInterval(IDLE_TIME * 1000);
idleTimer->setSingleShot(false);
connect(idleTimer, SIGNAL(timeout()), SIGNAL(idled()));
idleTimer->start();
// setup socket notifier
inputDevice = new QFile(USERINPUT_DEVICE);
if (!inputDevice->open(QIODevice::ReadOnly))
{
syslog (LOG_ERR, "Input file for Backlight controller could not been opened.");
}
else
{
inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
inputNotifier->setEnabled(true);
connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
}
qDebug()<<"backlight socket: "<<inputNotifier->socket();
// read out settings-file
QString intensity = Global::system_settings->getValue("BelatronUS_backlight_intensity");
if (intensity.length() == 0) intensity = "100";
QString duration = Global::system_settings->getValue("BelatronUS_backlight_duration");
if (duration.length() == 0) duration = "180";
QString always_on = Global::system_settings->getValue("BelatronUS_backlight_always_on");
if (always_on.length() == 0) always_on = "0";
setIntensity(intensity.toInt());
setDuration(duration.toInt());
if (always_on == "0")
setAlwaysOn(false);
else
setAlwaysOn(true);
}
BacklightController::~BacklightController()
{
trigger->stop();
inputNotifier->setEnabled(false);
inputDevice->close();
delete trigger;
delete inputDevice;
delete inputNotifier;
}
void BacklightController::setCurrentIntensity(int intensity)
{
// adapt backlight intensity
QFile backlightFile("/sys/class/backlight/atmel-pwm-bl/brightness");
if (!backlightFile.open(QIODevice::WriteOnly))
{
syslog (LOG_ERR, "Backlight intensity file could not been opened.");
}
else
{
QString intensityString = QString::number(TO_BRIGHTNESS(intensity));
if (backlightFile.write(
qPrintable(intensityString), intensityString.length()
) < intensityString.length())
{
syslog (LOG_ERR, "Backlight intensity could not been changed.");
}
backlightFile.close();
}
}
void BacklightController::resetNotifier()
{
inputDevice->close();
if (!inputDevice->open(QIODevice::ReadOnly))
{
syslog (LOG_ERR, "BacklightController::%s: Input file could not been opened.", __FUNCTION__);
}
qDebug()<<"reset, handle: "<<inputDevice->handle();
//inputNotifier=QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
// restart timer after user input
idleTimer->start();
}
void BacklightController::activateBacklight()
{
// only activate backlight, if it's off (avoid to useless fileaccess)
if (!backlightActive)
{
setCurrentIntensity(_intensity);
backlightActive = true;
emit backlightActivated();
}
// restart backlight timeout, but only if we don't want the backlight to shine all the time
if (!_alwaysOn)
trigger->start();
// reset notifier to be able to catch the next userinput
resetNotifier();
}
void BacklightController::deactivateBacklight()
{
// don't turn it off, if it's forced on
if (!_alwaysOn)
{
if (backlightActive)
{
// only deactivate backlight, if it's on (avoid to useless fileaccess)
setCurrentIntensity(BACKLIGHT_INTENSITY_OFF);
backlightActive = false;
emit backlightDeactivated();
}
}
qDebug()<<"trigger stopping";
trigger->stop();
}
void BacklightController::setIntensity(int intensity)
{
if (intensity > 100)
intensity = 100;
else if (intensity < 0)
intensity = 0;
_intensity = intensity;
// write new intensity to file if it's active at the moment
if (backlightActive)
{
setCurrentIntensity(_intensity);
trigger->start();
}
}
void BacklightController::setDuration(int duration)
{
if (duration < 1)
duration = 1;
_duration = duration;
trigger->setInterval(_duration * MS_IN_SEC);
// reset trigger after changing duration
if (backlightActive)
{
trigger->start();
}
}
void BacklightController::setAlwaysOn(bool always_on)
{
_alwaysOn = always_on;
// tell the timer what to to now
if (_alwaysOn)
{
this->activateBacklight();
trigger->stop();
}
else
{
trigger->start();
}
}
I seem to have found a working solution for now. It's not the greatest so if there are better solutions I would be interested to hear them. The reason I did not think of this before is because I thought if I had a new connect statement in a function it would have limited scope as the function ended.
The solution was to simply check for an occurrence of the handle change in the file and then create a new pointer for the notifier using that handle. Then re-enable the notifier because it has likely been disabled by now and then create a new connect statement for the pointer. This is the code I used, added just below the closing and reopening of the event file:
if(inputDevice->handle()!=inputNotifier->socket()){
inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
inputNotifier->setEnabled(true);
connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
}

Resources