Lilypad Mp3 - Probleme bei langen Dateinamen

Hallo,
ich bin dabei ein MP3 Player zu programmieren dieser durch Button in verschiedenen Ordner springen soll und dort MP3s abspielen soll.

Nun habe ich gemerkt dass bei zu langen Namen ca. an 30 Zeichen, das Programm auf dem Arduino hängen bleibt und es tut sich nicht.
Meine Vermutung ist dass die Ansteuerung der MP3 Dateien durch den Dateinamen wohl viel Speicher verbraucht wird, so dass es ab bestimmten länge wohl überläuft.

Ich würde ungern Dateinamen dafür verkürzen und lieber die originale Bezeichnung der Dateien beibehalten.

Meinen gesamten Code habe ich im gitlab frei zugänglich gemacht und der folgender Link führt direkt zur der Funktion in dieser ich das Problem vermute. Denn in dieser Funktion lese und übergebe die Dateinamen.

Kann mir da jemand weiter helfen wir ich dies eventuell lösen könnte?
Eventuell mache ich irgend einen Fehler beim Daten Typen so dass der Speicher nicht richtig aufgeräumt wird?

Ist es möglich, das Du den Code bitte hier einfügst?
Lies: Wie man dieses Forum benutzt - bitte lesen
Danke.

@my_xy_projekt Hallo ja, ich kann meinen Code auch hier einfügen, jedoch ist dieser bereits so weit angewachsen und mit einigen Bibliotheken inkludiert dass ich dachte es wäre besser wen ich einen Link zum gitlab poste dieser eben alles beinhaltet.

In dem Sinn werde ich nur die eine Funktion hier hinterlegen, um es kurz zu halten.


void playNext(const char*Dir) {
  char Name[50];
  //uint8_t dirIndex = 0;
  bool bIsEnd = 1;
  //SdFile fileX;
  //char * Name;
    MP3player.pauseMusic(); // setze Pause
    Serial.println( F("playNext() "));
    while (fileX.openNext(&rootX, O_RDONLY)) {
      Serial.println( F("openNext() "));
        fileX.getName(Name,sizeof(Name));
        Serial.print( Dir );Serial.print( fileX.dirIndex() );Serial.print(F(":"));
        Serial.println( Name );
        if (fileX.isFile() && Name[0] != '.') {
            
            //char* DirName = Dir;// = conCat2((char*)Dir,(char*)&Name);
            char DirName[10] = {"\0"};
            strcpy(DirName,Dir);
            strcat(DirName,Name);
            
            Serial.print(F(" toPlay:"));Serial.println( DirName );
            if(isPlayable(DirName)){
              fileX.close(); // Schließe Datei
              if(MP3player.isPlaying()) {
                MP3player.stopTrack();//MP3player.resumeMusic();
              }
              
              MP3player.playMP3(DirName,0);
              bIsEnd = 0;
              break;//soll nur nächste MP3 abspielen
            }
        }
        fileX.close(); // Schließe Datei
    }
    
    if(bIsEnd) { //Begine Verzeichnis von vorne
      Serial.println(F("reset Ordner"));
      //fileX.close();
      if(MP3player.isPlaying()) {
        MP3player.stopTrack();
      }
      rootX.close();Serial.println(F("rootX.close()"));
      rootX.open(Dir);Serial.println(F("rootX.open()"));
      delay(50);
    }
    if(!bIsPause) {
      MP3player.resumeMusic(); // play 
    }
  
}

Um es kurz zu halten: Wer nicht will, der hat schon.

Ich bin raus.

@my_xy_projekt also ich bin nicht geizig, hier ist der gesamte Code. Falls dies zur besseren Verständnis führt.

// Required libraries:

#include <SPI.h>
//#include <SD.h>
#include <SdFat.h>
//#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
#include <PinChangeInt.h>

#include "PCF8575.h" //Buttons

//RGB Ring
//#include <Adafruit_NeoPixel.h>
//Adafruit_NeoPixel pixels(8, 10, NEO_GRB + NEO_KHZ800);

//Button
PCF8575 PCF[3] = {PCF8575(0x20),PCF8575(0x21),PCF8575(0x22)};

//SD Card
SdFat sd;
SdFile rootX;
SdFile fileX;

//MP3 Player
SFEMP3Shield MP3player;


 // Turn off amplifier chip / turn on MP3 mode:
 #define SHDN_GPIO1 A2
 

unsigned long myTimer;
unsigned long myTimer2;
//======Button Class Start ==============
class CButton {

  public:
  byte Id; //Button Nummer 0-12
  byte bRGB[3] = {0,0,0};
  const char* Dir; //Pfad
  
  void begin(byte id) {
    Id = id;
  }
   
 void setLed(bool r, bool g, bool b) {
  //Button/Farben/ControlerID:Port
  bRGB[0] = r;
  bRGB[1] = g;
  bRGB[2] = b;
  byte bCode[13][3][2] = {
    {{1,11},{1,12},{1,13}}, //Button 0
    {{1, 8},{1, 9},{1,10}}, //Button 1
    {{1, 3},{1, 4},{1,5}},
    {{1, 0},{1, 1},{1, 2}},
    {{0, 3},{0, 4},{0, 5}},
    {{0, 0},{0, 1},{0, 2}},
    {{2,13},{2,14},{2,15}},
    {{2,10},{2,11},{2,12}},
    {{2, 7},{2, 8},{2, 9}},
    {{2, 4},{2, 5},{2, 6}},
    {{2, 1},{2, 2},{2, 3}},
    {{1,14},{1,15},{2, 0}},
    {{0, 6},{1, 6},{1, 7}}
  };
  
  PCF[ bCode[Id][0][0] ].write(bCode[Id][0][1],r);
  PCF[ bCode[Id][1][0] ].write(bCode[Id][1][1],g);
  PCF[ bCode[Id][2][0] ].write(bCode[Id][2][1],b);
 }

  bool isPressed() {
    bool bReturn = 0;
 
    byte bCode[16][2] = {
     {14, 9},{14, 8},{13,11},{13,10},
     {13, 9},{13, 8},{15,11},{15,10},
     {15, 9},{15, 8},{14,11},{14,10},
     {12, 8},{12, 9},{12,10},{12,11}
    };
    PCF[0].write(bCode[Id][0],0);
    if(PCF[0].readButton(bCode[Id][1]) == 0 && (millis() - myTimer) > 500) {
      myTimer = millis();
      Serial.print(F("Button: ") );
      Serial.println( Id );
      bReturn = 1;
      byte rgb[3] = {bRGB[0],bRGB[1],bRGB[2]};//Stellt die ursprüngliche Farbe beim nächsten durchlauf wieder her
      setLed(1,0,0);
      bRGB[0] = rgb[0];
      bRGB[1] = rgb[1];
      bRGB[2] = rgb[2];
    }
    else {
      setLed(bRGB[0],bRGB[1],bRGB[2]);
    }

    PCF[0].write(bCode[Id][0],1);
    return bReturn;
  }



 
};
CButton Button[13];
//======Button Class End =================
//char dir[] = "/Geschichten/Bibi/";

byte iCurrentGroup = 0; //Ordner Gruppe (0-9)
byte iCurrentButton = 0; // aktiver Button (0-12)
byte bCurrentVolume = 0; //0-100
bool bIsPause = 0;

//char CurrentTrack[255] = "";
void setup()
{
  byte result;

  Serial.begin(9600);
  Serial.println(F("MP3 Player Start"));
  //Serial.print("Free RAM = "); Serial.println(FreeRam(), DEC);

  //Button LED
  for(byte i=0; i<3; i++) {
    PCF[i].begin();
    PCF[i].write16(LOW);
  }

  //Button
  for(byte i=0; i < 13; i++) {
    Button[i].begin(i);
  }
    
    //SD Karte Vorhanden und kann gelesen werden 1=grün oder 1=rot = fehler
    result = sd.begin(SD_SEL, SPI_HALF_SPEED);
    /*
    if (result != 1)
      Button[0].setLed(1,0,0);
    else 
      Button[0].setLed(0,1,0);
      */
      
    //MP3 Player vorhanden
    result = MP3player.begin();
    /*
    if((result != 0) && (result != 6))
      Button[1].setLed(1,0,0);
    else 
      Button[1].setLed(0,1,0);
      */
  for(byte i=0; i < 13; i++) {
    Button[i].setLed(0,1,0);
    delay(50);
  }
  //MP3 Player Start
  //MP3player.begin();
  MP3player.setVolume(80,80);



/*      
    //SD einlesen ToDo: Muss ordner öffnen und MP3 darin zählen können
    if (!root.open("/")) {
     Serial.println("Fehler beim Öffnen der SD");
    }
Serial.print("Anzahl: ");
 Serial.println( getDir("/") );

    char csvName[100];
    while (file.openNext(&root, O_RDONLY)) {
      if (!file.isHidden()) {
      }
      
      if (file.isFile()) {
        Serial.print("ist Datei: ");
        file.getName(csvName,sizeof(csvName));
        Serial.println(csvName);
       }
       if (file.isDir()) {
        Serial.print("ist Ordner: ");
        file.getName(csvName,sizeof(csvName));
        Serial.println(csvName);

        if(!root.open(csvName)) {
          while (file.openNext(&root, O_RDONLY)) {
            if (file.isFile()) {
            Serial.print("ist Datei: ");
            file.getName(csvName,sizeof(csvName));
            Serial.println(csvName);
            }
          }
        }
        
       }
      file.close();
    }
*/
    
    //sd.ls(,LS_R);
  // Turn on amplifier chip
  pinMode(SHDN_GPIO1, OUTPUT);
  digitalWrite(SHDN_GPIO1, LOW);
  digitalWrite(SHDN_GPIO1, HIGH);
  delay(2);


 /// CurrentFolder = "/00/";
 /// rootX.open(CurrentFolder);
 // rootX.open("/");

 //checkAllButton2Folder("/");

 //RGB Ring
  //pixels.begin(); 
  //pixels.show();            // Turn OFF all pixels ASAP
  //pixels.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
  //pixels.setPixelColor(0, pixels.Color(0, 0, 100));
      
    
} // END setup





//######LOOP====================================================
void loop()
{

    //Volumen
    int8_t vol = ControlVolume(); //gibt auktuellen Stand vom Volumen Regler
    if(vol > 5) {
      //short val_1 = map(vol,0,100, 100,0); //Muss wert drehen
      byte val_1 = map(vol,0,100, 100,0); //Muss wert drehen
      MP3player.setVolume(val_1,val_1);
      MP3player.resumeMusic(); // play 
      bIsPause = 0;
      Button[iCurrentButton].setLed(0,0,1); // blau
    
    } else {
      MP3player.pauseMusic(); // Pause
       bIsPause = 1;
      Button[iCurrentButton].setLed(1,0,0); // rot
     
    }


    
    //changeVolume(vol);
 /* 
   if(MP3player.isPlaying() && iCurrentVolume == 0) {
     stopPlaying();
   }
   else if(!MP3player.isPlaying() && iCurrentVolume > 0 ) {
     startPlaying();
   }
 */

/*
for(byte i = 0; i< 13;i++) {
  //Button[i].setLed(0,0,0);
  
  if(Button[i].isPressed()) {
    //Button[i].setLed(1,0,0);
    Serial.print( " Open: '" ); Serial.print( Button[i].Dir );Serial.println( "'" );
    loadDir(Button[i].Dir,i);

  }
}
*/

  //Press Button 0-12
  for(byte i = 0; i <13;i++) {
    if(Button[i].isPressed()) {
      Button[iCurrentButton].setLed(0,1,0);
      iCurrentButton = i;
      if( i<12) { // nur Playbare Buttons 0-11
        const char* DirName = ButtonDir(i);
        //const char DirName[] = "/01/";
        playNext(DirName);
      }
      
    }
  }

 if(iCurrentButton < 12) {
   if(!MP3player.isPlaying()) { // spielt nicht, dann fang an!
    //const char* DirName = ButtonDir(iCurrentButton);
     playNext(ButtonDir(iCurrentButton));
   }
   else {
    Button[iCurrentButton].setLed(0,0,1);
   }
 }
 else { //ToDo: MENU
   //ToDo: reload Buttons
   for(byte i=0; i < 13; i++) {
        Button[i].setLed(0,0,0);
   }
    for(byte i=0; i < 13; i++) {
        Button[i].setLed(0,1,0);
        delay(50);
    }
    iCurrentButton = 0;
    playNext(ButtonDir(iCurrentButton));
 }




  /*
  //Button Auslesen
  byte bButton = bbutton(); //Button Check
  if (bButton > 0) {
    Serial.print("Button: "); Serial.println(bButton);
    if(bButton == 1) {
      
//       startPlaying();
       LEDButton(bButton,0,1,0);
    }
  }
  **/
  
  

//openFolder("aa");
//openFolder("bbb"); 
}

const char* ButtonDir (byte BtnID) {
       if (BtnID == 0) return "/01/";
  else if (BtnID == 1) return "/02/";
  else if (BtnID == 2) return "/03/";
  else if (BtnID == 3) return "/04/";
  else if (BtnID == 4) return "/05/";
  else if (BtnID == 5) return "/06/";
  else if (BtnID == 6) return "/07/";
  else if (BtnID == 7) return "/08/";
  else if (BtnID == 8) return "/09/";
  else if (BtnID == 9) return "/10/";
  else if (BtnID == 10) return "/11/";
  else return "/12/";
}


void playNext(const char*Dir) {
  char Name[50];
  //uint8_t dirIndex = 0;
  bool bIsEnd = 1;
  //SdFile fileX;
  //char * Name;
    MP3player.pauseMusic(); // setze Pause
    Serial.println( F("playNext() "));
    while (fileX.openNext(&rootX, O_RDONLY)) {
      Serial.println( F("openNext() "));
        fileX.getName(Name,sizeof(Name));
        Serial.print( Dir );Serial.print( fileX.dirIndex() );Serial.print(F(":"));
        Serial.println( Name );
        if (fileX.isFile() && Name[0] != '.') {
            
            //char* DirName = Dir;// = conCat2((char*)Dir,(char*)&Name);
            char DirName[10] = {"\0"};
            strcpy(DirName,Dir);
            strcat(DirName,Name);
            
            Serial.print(F(" toPlay:"));Serial.println( DirName );
            if(isPlayable(DirName)){
              fileX.close(); // Schließe Datei
              if(MP3player.isPlaying()) {
                MP3player.stopTrack();//MP3player.resumeMusic();
              }
              
              MP3player.playMP3(DirName,0);
              bIsEnd = 0;
              break;//soll nur nächste MP3 abspielen
            }
        }
        fileX.close(); // Schließe Datei
    }
    
    if(bIsEnd) { //begine Verzeichnis von vorne
      Serial.println(F("reset Ordner"));
      //fileX.close();
      if(MP3player.isPlaying()) {
        MP3player.stopTrack(); // Muss vorher gestoppt werden, weil sonnst kann nicht immer root richtig reopen werden
      }
      rootX.close();Serial.println(F("rootX.close()"));
      rootX.open(Dir);Serial.println(F("rootX.open()"));
      delay(50);
    }
    if(!bIsPause) {
      MP3player.resumeMusic(); // play 
    }
  
}


//Überprüft ob für jeden Button ein Ordner vorhanden ist, ja = grün; nein = schwarz
bool checkAllButton2Folder(const char* Dir) {
  char Name[2];
  for(byte i=0;i<12;i++) { // Deaktiviere alle Buttons
    Button[i].setLed(0,0,0);
  }
  
  rootX.open(Dir);
  while (fileX.openNext(&rootX, O_RDONLY)) {
        if (fileX.isDir()) {
          fileX.getName(Name,sizeof(Name));
          Serial.print(F("CheckButton: "));Serial.println(Name);
            if(Name == "03") { //aktiviere nur die Buttons zur diesen die Zuordnung verfügbar ist.
               Button[3].setLed(0,1,0);
            }
        }
        fileX.close(); // Schließe Datei
    }
  rootX.close(); //schließe Ordner
}



byte getDirCount(const char* Root) {
  byte bReturn = 0;
  SdFile root1;
  SdFile file1;
  char Name[100];
  if (!root1.open(Root)) {
     Serial.println(F("Fehler beim Öffnen der SD"));
   }
 
   while (file1.openNext(&root1, O_RDONLY)) {
    Serial.print("root1: ");
          Serial.println(root1);
      if (file1.isDir()) {
        file1.getName(Name,sizeof(Name));
        if(Name[0] != '.') {
          bReturn++;
          Serial.print(F("ist Ordner: "));
          Serial.println(Name);
        }
      }
      /*
      if (file1.isFile()) {
          Serial.print("ist Datei: ");
          file1.getName(Name,sizeof(Name));
          Serial.println(Name);
       }*/
      file1.close();
   }
   
  return bReturn;
}




const char* conCat(const char* Aa, const char* Bb) {
  return conCat(Aa,Bb,"","");
}
const char* conCat(const char* Aa, const char* Bb, const char* Cc) {
  char* New = new char [ strlen(Aa) + strlen(Bb) + strlen(Cc) ];
  strcpy(New,Aa);
  strcat(New,Bb);
  strcat(New,Cc);
  return New;
}
const char* conCat(const char* Aa, const char* Bb, const char* Cc, const char* Dd) {
  //CurrentFolder = Folder;
  char* New = new char [ strlen(Aa) + strlen(Bb) + strlen(Cc) + strlen(Dd) ];
  strcpy(New,Aa);
  strcat(New,Bb);
  strcat(New,Cc);
  strcat(New,Dd);
  return New;
}

char* conCat2(char* Aa, char* Bb) {
  //CurrentFolder = Folder;
  char* New = new char [ strlen(Aa) + strlen(Bb)  ];
  strcpy(New,Aa);
  strcat(New,Bb);
  return New;
}


//Prüft ob die Datei Abspielbar ist
boolean isPlayable(const char* track)
{
  char *extension;
  
  extension = strrchr(track,'.');
  extension++;
  if (
    (strcasecmp(extension,"MP3") == 0) 
   // || (strcasecmp(extension,"WAV") == 0) ||
   // (strcasecmp(extension,"MID") == 0) ||
   // (strcasecmp(extension,"MP4") == 0) ||
   // (strcasecmp(extension,"WMA") == 0) ||
   // (strcasecmp(extension,"FLA") == 0) ||
   // (strcasecmp(extension,"OGG") == 0) ||
   // (strcasecmp(extension,"AAC") == 0)
  )
    return true;
  else
    return false;
}



short val_1 = -1;
int8_t val_2 = -1;
int8_t ControlVolume()
{
  short v = analogRead(3);
  byte v2 = map(v,20,1010, 0,100);
 
  if(val_1 != v && val_1 != v+5 && val_1 != v-5 && val_2 != v2)
  {
      val_1 = v;
      val_2 = v2;
      
      Serial.print(F(" analogRead: "));Serial.println(v);
  }
  return val_2;
}

Keiner Eine Idee?

Ich habe nun das ganze genauer analysiert.

Und es scheint so dass ich per sdFat durchaus langen Namen (bis zur 50 Zeichen) auslesen kann.
Dass sehe ich wenn ich per Serial.print( DirName ); diesen dann ausgeben lasse.
Jedoch scheint dann aber auch Schluß zu sein.

Denn an dieser Stelle wird ja der Pfad und Dateinamen übergeben:
MP3player.playMP3(DirName,0);
An dieser Stelle tritt das Problem dann auf.

Ich habe bereits mit kürzeren Dateinamen ausprobiert. Es gehen z.b. 32 Zeichen + 5 Zeichen wegen Pfand Angabe.
Ausgabe Beispiel des Pfades.
/000/Das ist meine mp3 Datei.mp3

byte iCurrentDir = 0;
void playNext(byte iDir) {

  //Ordner Selektieren
  static char Dir[6];
  snprintf(Dir, sizeof(Dir), "/%03u/", iDir );
  Serial.print( F("ButtonDir: "));Serial.println(Dir);
  
  //const char* Dir = ButtonDir(iDir);
  char Name[50];
  //uint8_t dirIndex = 0;
  bool bIsEnd = 1;

  if(iCurrentDir != iDir) { // Bei Ordner Wechsel
    if(MP3player.isPlaying()) {
        MP3player.stopTrack(); // Muss vorher gestoppt werden, weil sonnst kann nicht immer root richtig reopen werden
      }
    rootX.close();
    rootX.open(Dir);
    iCurrentDir = iDir;
  }
  
  //SdFile fileX;
  //char * Name;
    MP3player.pauseMusic(); // setze Pause
    Serial.println( F("playNext() "));
    while (fileX.openNext(&rootX, O_RDONLY)) {
      Serial.println( F("openNext() "));
        fileX.getName(Name,sizeof(Name));
        Serial.print( fileX.dirIndex() );Serial.print(F(":"));
        if (fileX.isFile() && Name[0] != '.') {
            
            //char* DirName = Dir;// = conCat2((char*)Dir,(char*)&Name);
            char DirName[5] = {"\0"};
            //char* DirName;
            strcpy(DirName,Dir);
            strcat(DirName,Name);
            Serial.print( DirName );Serial.println(F(": Play"));
            
            if(isPlayable(DirName)){
              fileX.close(); // Schließe Datei
              if(MP3player.isPlaying()) {
                MP3player.stopTrack();//MP3player.resumeMusic();
              }
              
              MP3player.playMP3(DirName,0);
              bIsEnd = 0;
              break;//soll nur nächste MP3 abspielen
            }
        }
        
        fileX.close(); // Schließe Datei
    }
    
    if(bIsEnd) { //begine Verzeichnis von vorne ToDo: Dass muss beim Verzeichniswechsel durchgeführt werden!!!
      Serial.println(F("reset Ordner"));
      //fileX.close();
      if(MP3player.isPlaying()) {
        MP3player.stopTrack(); // Muss vorher gestoppt werden, weil sonnst kann nicht immer root richtig reopen werden
      }
      rootX.close();Serial.println(F("rootX.close()"));
      rootX.open(Dir);Serial.println(F("rootX.open()"));
      delay(50);
    }
    if(!bIsPause) {
      MP3player.resumeMusic(); // play 
    }
  
}

Ne, ich noch nicht wirklich.
Welche Version der sdfat benutzt Du?

@my_xy_projekt ich nutze die aktuelle SDFat ich glaube es liegt nicht am SDFat sondern eher an der <SFEMP3Shield.h> Bibliothek.

So das die Funktion an diese ich den Pfad übergebe eventuell eine Kopie der Variable erstellt und dadurch dann den Speicher zum überlauf bringt, oder ist da eine irgend welche Limitierung die ich nicht erkenne und man darf an diese Funktion dann nur gewisse Länge übergeben.

MP3player.playMP3()

Das ist diese Funktion aus der Bibliothek:

Vielleicht kann jemand die Ursache besser deuten als ich wenn ich mir diese Funktion anschaue.

Ich bin noch am testen und herauszufinden ab welcher länge es knallt. Aber e scheint dass es mit Pfad Angabe bereits ca. 30-32 Zeichen sein muss.

Nicht Zeile 1066, sondern 111!
HA!

@my_xy_projekt
Also ich habe nun weiter untersucht.
Es schient so wenn die Datei mit überläge kommt dass es an dieser Funktion aussteigt.

Die oben angegebene Funktion habe ich ebenfalls untersucht und es steigt dann an der attachInterupt(...) aus.

Diese Funktion kann ich wiederum nicht mehr finden um es weiter zu untersuchen.