This program requires me to read an sd card that contains a bunch of folders, I then need to save the names of each folder into an array. After that, I need to display the names on a screen and allow the user to scroll through them and select them.
my current solution is so slow it takes 4 seconds to load the list so I'm looking for an alternative.
Currently, I read each file as a String and combine them all as a single String with each name separated by a ^. These Strings are the String class.
This was the only way I could the list to leave the function, I tried and char[], char*, and a char** but it still didn't work.
Another problem we ran into was that when we tried to read a file name that was over 8 characters it was abbreviate it to 6 characters with a ~1 on the end.
The solution to that was to just store the name of the folder inside a text file, called name.txt, in the folder. But I sure that causes quite a lot of load time.
Here is that code.
String Files::getDirList(char* path)
{
Serial.println("current path: " + String(path));
File dir = SD.open(path);
String list = "";
while (true)
{
File entry = dir.openNextFile();
if(! entry && list == "")
{
Serial.println("empty directory");
return "ERROR";
}
else if (! entry)
{
Serial.println("no more files");
break;
}
if(!entry.isDirectory())
{
Serial.println(String(entry.name()) + " is not a directory");
continue;
}
File oldDir = dir;
String newPath = String(path) + String("/") + (String)entry.name() + String("/name.txt");
File nameFile = SD.open(newPath);
String name = "";
while(nameFile.available())
{
char ch = nameFile.read();
name += ch;
}
list += name + "^";
nameFile.close();
entry.close();
}
Serial.println("list filled");
return list;
}
This is the function I use to pull a name from the long string
String Files::grabFile(String file, int position)
{
int cCount = 0;
String string = "";
for(int i = 0; i <file.length(); i++)
{
if(file[i] == '^')
{
cCount++;
continue;
}
if(cCount == position)
{
string += file[i];
}
}
return string;
}
Here is the function that prints the text.
enum Color {RED, GREEN, BLUE, BLACK, WHITE};// pulled from class definition
void List::displayItem(Ucglib_ST7735_18x128x160_HWSPI* screen, ucg_fntpgm_uint8_t* font, List::Color color, int x, int y, String text)
{
screen->setFont(font);
screen->setPrintPos(x,y);
changeColor(screen,color);// calls the function below
screen->print(text);
}
void List::changeColor(Ucglib_ST7735_18x128x160_HWSPI* screen, List::Color color)
{
switch(color)
{
Serial.println("entering switch");
case BLUE:
screen->setColor(0,0,255);
Serial.println(color);
Serial.println("setting to blue");
break;
case RED:
screen->setColor(255,0,0);
Serial.println("setting to red");
break;
case GREEN:
screen->setColor(0,255,0);
Serial.println("setting to green");
break;
case WHITE:
screen->setColor(255,255,255);
Serial.println("setting to white");
break;
case BLACK:
screen->setColor(0,0,0);
Serial.println("setting to black");
break;
default:
screen->setColor(255,255,255);
Serial.println("Running default");
break;
};
}
Just creating the list string takes a few seconds and printing 15 names to the screen adds up to a total of 4 seconds.
There must be a better way of doing this, one that also fixed the weird abbreviation ~1 problem.
If anyone could give me an idea that would be great. If there is another approach to reading the files, saving the files, and displaying the files, I would love to hear it. I am willing to completely rewrite everything as long as I can lower the load time significantly.