I want to list all filles and directorys an subdirectorys on the sd card with an mcu.
The problem I have is that it forget what he was previous doing when I call the same function in that function. The SdFat library doesn't have a namespace so I can not use that like the example I use with the SD library.
The library I want to use
listDir(audio_SD, file.name(), levels - 1); //"can not be referenced -- it is a deleting function"
The complete void I try modify ...
//void listDir(fs::FS& fs, const char* dirname, uint8_t levels) {
void listDir(SdFat audio_SD, const char* dirname, uint8_t levels) {
Serial.printf("Listing directory: %s\n", dirname);
File root = audio_SD.open(dirname);
if (!root) {
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels) {
listDir(audio_SD, file.name(), levels - 1);
}
}
else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.print(file.size());
}
file = root.openNextFile();
}
}
Note: I know that the memory will be an issue with larger amount of data on the SD card. But the data I have is not that big soo I will suppress that.
This is how I do it for now. It can be done better, but It will do the job for files that only contain numbers. Even 01 files when the are mixed together with 002's... what I have added to the function. It's not complete debugged but yeah, that's what I got for now.
String* sortArrayNumber(String* a, int n)
{
int i, j;
for (i = 0; i < n - 1; i++) {
// Last i elements are already in place
for (j = 0; j < n - i - 1; j++) {
if (RemoveExtension(GetFileName(a[j])).toInt() > RemoveExtension(GetFileName(a[j+1])).toInt()) {
String temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
return a;
}
/*FOLDER AND FILES*/
String GetFileName(String path) {
path = path.substring(path.lastIndexOf("/") + 1, path.length());
return path;
}
String RemoveExtension(String path) {
//String Filename = path;
if (path.lastIndexOf(".") > 0 && path.lastIndexOf(".") < 5) {
path = path.substring(0, path.lastIndexOf("."));
return path;
}
return "";
}
Soo I converted the strings to characters, but now I am outputting two pointers. Can I get rid of it?
char** sortArrayNumber(char* a[40], int n)
{
char** char2dArray = NULL;
char2dArray = new char* [40];
int i, j, k;
for (i = 0; i < n - 1; i++) {
// Last i elements are already in place
for (j = 0; j < n - i - 1; j++) {
int size = sizeof(a) / sizeof(a[0]);
char* charArray = NULL;
charArray = new char[size];
charArray = a[j];
GetFileName(charArray);
if (atoi(RemoveExtension(a[j])) > atoi(RemoveExtension(a[j + 1]))) {//string to number
char* temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
Serial.println("array");
Serial.println(a[j + 1]);
}
}
}
return a;
}
Ok. I think I know now. I just to remove the procedure and place it where I am calling it. If I would use 2D fix arrays it would be even beter for memorie perpeces.
you create space for 40 pointers, but no space for the content
the content space is indeed created with the
charArray = new char[size];
but the size is not calculated right. It should be the size of the filename you want to store.
going fixed size will (at the cost of wasted memory possibly) solve the issue. if memory becomes an issue later on, you could then revert to some dynamic allocation.
void SortPlaylist(char* dirPath, char* Dbfilename) {
if (!openDbFile(dirPath, Dbfilename)) {
error("opening file in folder failed");
}
else
{
Serial.println("read db lines for sorting csv file");
DbFile.rewind();
int cnt = 0;
//char line[MaxTitleLength];
//size_t len = 0;
//char* str;
//char* StrTitleArray[MaxTitleLength];
char chr;
byte byt;
char Title[TitleIndex][MaxTitleLength];//TitleIndex//MaxTitleLength
uint16_t intCelIndex = 0;
uint16_t intEndIndex = MaxTitleLength;
uint16_t cntLetter = 0;
uint16_t cntTitle = 0;
while (DbFile.available()) {
byt = DbFile.read();
Serial.println(byt);
//byte = 59 = ;
//Serial.println(cnt);
if (byt == 59) intCelIndex = cnt;//Serial.println("test");//
if (byt == 10) intEndIndex = cnt;
if ((cnt > intCelIndex) && (cnt < intEndIndex-2)) {
chr = byt;
Title[cntTitle][cntLetter] = chr;
Serial.println(chr);
cntLetter++;
}
if (byt == 10) {
cnt = 0;
Title[cntTitle][cntLetter] = '\0';
cntTitle++;
cntLetter = 0;
intCelIndex = 100;
intEndIndex = MaxTitleLength;
}
else{
cnt++;
}
}
//print values
//for (int i = 0; i < cntTitle;i ++) {
// Serial.println(Title[i]);
//}
Serial.println("sort lines csv file");
int i, j;
for (i = 0; i < cntTitle- 1; i++) {
for (j = 0; j < cntTitle- i - 1; j++) {
if (atoi(RemoveExtension(Title[j])) > atoi(RemoveExtension(Title[j + 1]))) {//string to number
char temp[MaxTitleLength];
for (int x = 0; x < MaxTitleLength; x++) {
temp[x] = Title[j][x];
}
for (int x = 0; x < MaxTitleLength; x++) {
//Title[j] = Title[j + 1];
Title[j][x] = Title[j + 1][x];
}
for (int x = 0; x < MaxTitleLength; x++) {
//Title[j + 1] = temp;
Title[j + 1][x] = temp[x];
}
}
}
}
//for (int i = 0; i < cntTitle; i++) {
// Serial.println(Title[i]);
//}
Serial.println("write sorted lines to csv file");
DbFile.rewind();
for (int i = 0; i < cntTitle;i ++) {
//Serial.println(StrTitleArray[i]);
WriteSongToPlaylist(i, dirPath, Title[i], Dbfilename);
}
DbFile.close();
}
}
It will save you a day. It will cost you a minut to read this topic complety to understand how come to this. I have made also an other topic to understand 2D array's and how to use them in a small ram environment.
You can code , as well as ; to delimit fields. Then you have a Comma Separated Fields format.
Since before I've been here the big lesson is Do Many Things At Once that starts with leds and buttons and using millis() or micros() to avoid blocking code like delay.
This allows writing cooperative tasks and IPO, Input, Process, Output modular tasks. Nick Gammon's clear tutorial with breakfast-making explanation.
State Machines ROCK! They allow the state of a process to select which code runs, and that code may change the state. I have put state machines inside of state machines to do text hacking in game files before, to find certain lines of original file and change them in a mod file else copy input.
When I set const int TitleIndex = 200; I get an overflow. Not sure why, because I have 160kb ram and the title array is only 40 characters long.
If I do...
if (Title[cntTitle] != "") or if (Title[cntTitle] != nullptr) or Serial.println(Title[i]) when it is set to 200 it get stuck. I am loosing my mind over this. When I print evry byt I store nothing seems wrong.
Why use an int to count to less than 200? Oh right, 160kb RAM.
On memory devices a 32kb device is 32768 bits, 8192 bytes, 8KB, cheap SPI RAM.
File on SD, I would make a file with title0title0title0.... and another of offsets to each title that ends with 0.
And then I can make a file of sorted offsets into the data. Keep a bit array table to mark already selected titles (8 bits per byte) and through successive reads of unselected titles the sorted index order can be written directly to file. The index tells which offset to use, index 1 may be anywhere but the end of file.
Sorting indexes is faster than sorting text. One data file can be index-sorted 12 ways and still may be no bigger than twice the data. Take this to heart with SD, never sort -on- SD!