# This is a combination of 4 commits.
# The first commit's message is: SD Card Alpha Sorting First iteration of alphabetical sorting for SD cards, both slow+efficient and fast+rammy. Option for folders to sort first, last, or not at all. # This is the 2nd commit message: Expand on More RAM concept, address minor bugs # This is the 3rd commit message: Improvements, more SORT_USES_MORE_RAM With this option, always keeps the dir in RAM, doubling as a cache for getfilename. A board with only 8K of SRAM is cutting it very close. # This is the 4th commit message: Completed SORT_USES_MORE_RAM implementation For the MORE_RAM option we need to buffer both the short and long names, even though long names are sometimes redundant. Worst case, all the names are max length. We can save some RAM by not storing these. We could save more RAM by only storing the visible part of the long name.
This commit is contained in:
@@ -11,6 +11,9 @@
|
||||
|
||||
CardReader::CardReader()
|
||||
{
|
||||
#ifdef SDCARD_SORT_ALPHA
|
||||
sort_count = 0;
|
||||
#endif
|
||||
filesize = 0;
|
||||
sdpos = 0;
|
||||
sdprinting = false;
|
||||
@@ -33,19 +36,15 @@ CardReader::CardReader()
|
||||
autostart_atmillis=millis()+5000;
|
||||
}
|
||||
|
||||
char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
|
||||
char *createFilename(char *buffer, const dir_t &p) //buffer>12characters
|
||||
{
|
||||
char *pos=buffer;
|
||||
for (uint8_t i = 0; i < 11; i++)
|
||||
{
|
||||
if (p.name[i] == ' ')continue;
|
||||
if (i == 8)
|
||||
{
|
||||
*pos++='.';
|
||||
}
|
||||
*pos++=p.name[i];
|
||||
for (uint8_t i = 0; i < 11; i++) {
|
||||
if (p.name[i] == ' ') continue;
|
||||
if (i == 8) *pos++ = '.';
|
||||
*pos++ = p.name[i];
|
||||
}
|
||||
*pos++=0;
|
||||
*pos++ = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -53,15 +52,15 @@ char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
|
||||
void CardReader::lsDive(const char *prepend,SdFile parent)
|
||||
{
|
||||
dir_t p;
|
||||
uint8_t cnt=0;
|
||||
uint8_t cnt=0;
|
||||
|
||||
while (parent.readDir(p, longFilename) > 0)
|
||||
{
|
||||
if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint
|
||||
{
|
||||
|
||||
char path[13*2];
|
||||
char lfilename[13];
|
||||
char path[FILENAME_LENGTH*2];
|
||||
char lfilename[FILENAME_LENGTH];
|
||||
createFilename(lfilename,p);
|
||||
|
||||
path[0]=0;
|
||||
@@ -87,8 +86,6 @@ void CardReader::lsDive(const char *prepend,SdFile parent)
|
||||
}
|
||||
lsDive(path,dir);
|
||||
//close done automatically by destructor of SdFile
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -101,11 +98,10 @@ void CardReader::lsDive(const char *prepend,SdFile parent)
|
||||
if ( p.name[1] != '.')
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
|
||||
filenameIsDir=DIR_IS_SUBDIR(&p);
|
||||
|
||||
|
||||
|
||||
if(!filenameIsDir)
|
||||
{
|
||||
if(p.name[8]!='G') continue;
|
||||
@@ -124,10 +120,8 @@ void CardReader::lsDive(const char *prepend,SdFile parent)
|
||||
}
|
||||
else if(lsAction==LS_GetFilename)
|
||||
{
|
||||
if(cnt==nrFiles)
|
||||
return;
|
||||
if (cnt == nrFiles) return;
|
||||
cnt++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,9 +130,6 @@ void CardReader::lsDive(const char *prepend,SdFile parent)
|
||||
void CardReader::ls()
|
||||
{
|
||||
lsAction=LS_SerialPrint;
|
||||
if(lsAction==LS_Count)
|
||||
nrFiles=0;
|
||||
|
||||
root.rewind();
|
||||
lsDive("",root);
|
||||
}
|
||||
@@ -177,6 +168,9 @@ void CardReader::initsd()
|
||||
}
|
||||
workDir=root;
|
||||
curDir=&root;
|
||||
#ifdef SDCARD_SORT_ALPHA
|
||||
presort();
|
||||
#endif
|
||||
/*
|
||||
if(!workDir.openRoot(&volume))
|
||||
{
|
||||
@@ -193,8 +187,10 @@ void CardReader::setroot()
|
||||
SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
|
||||
}*/
|
||||
workDir=root;
|
||||
|
||||
curDir=&workDir;
|
||||
#ifdef SDCARD_SORT_ALPHA
|
||||
presort();
|
||||
#endif
|
||||
}
|
||||
void CardReader::release()
|
||||
{
|
||||
@@ -207,6 +203,7 @@ void CardReader::startFileprint()
|
||||
if(cardOK)
|
||||
{
|
||||
sdprinting = true;
|
||||
flush_presort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +232,7 @@ void CardReader::getAbsFilename(char *t)
|
||||
while(*t!=0 && cnt< MAXPATHNAMELENGTH)
|
||||
{t++;cnt++;} //crawl counter forward.
|
||||
}
|
||||
if(cnt<MAXPATHNAMELENGTH-13)
|
||||
if(cnt<MAXPATHNAMELENGTH-FILENAME_LENGTH)
|
||||
file.getFilename(t);
|
||||
else
|
||||
t[0]=0;
|
||||
@@ -305,7 +302,7 @@ void CardReader::openFile(char* name,bool read, bool replace_current/*=true*/)
|
||||
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
|
||||
if(dirname_end>0 && dirname_end>dirname_start)
|
||||
{
|
||||
char subdirname[13];
|
||||
char subdirname[FILENAME_LENGTH];
|
||||
strncpy(subdirname, dirname_start, dirname_end-dirname_start);
|
||||
subdirname[dirname_end-dirname_start]=0;
|
||||
SERIAL_ECHOLN(subdirname);
|
||||
@@ -401,7 +398,7 @@ void CardReader::removeFile(char* name)
|
||||
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
|
||||
if(dirname_end>0 && dirname_end>dirname_start)
|
||||
{
|
||||
char subdirname[13];
|
||||
char subdirname[FILENAME_LENGTH];
|
||||
strncpy(subdirname, dirname_start, dirname_end-dirname_start);
|
||||
subdirname[dirname_end-dirname_start]=0;
|
||||
SERIAL_ECHOLN(subdirname);
|
||||
@@ -439,6 +436,9 @@ void CardReader::removeFile(char* name)
|
||||
SERIAL_PROTOCOLPGM("File deleted:");
|
||||
SERIAL_PROTOCOLLN(fname);
|
||||
sdpos = 0;
|
||||
#ifdef SDCARD_SORT_ALPHA
|
||||
presort();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -552,14 +552,21 @@ void CardReader::closefile(bool store_location)
|
||||
|
||||
}
|
||||
|
||||
void CardReader::getfilename(const uint8_t nr)
|
||||
void CardReader::getfilename(const uint16_t nr)
|
||||
{
|
||||
#if defined(SDCARD_SORT_ALPHA) && SORT_USES_RAM && SORT_USES_MORE_RAM
|
||||
if (nr < sort_count) {
|
||||
strcpy(filename, sortshort[nr]);
|
||||
strcpy(longFilename, sortnames[nr]);
|
||||
filenameIsDir = isDir[nr];
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
curDir=&workDir;
|
||||
lsAction=LS_GetFilename;
|
||||
nrFiles=nr;
|
||||
curDir->rewind();
|
||||
lsDive("",*curDir);
|
||||
|
||||
}
|
||||
|
||||
uint16_t CardReader::getnrfilenames()
|
||||
@@ -577,7 +584,7 @@ void CardReader::chdir(const char * relpath)
|
||||
{
|
||||
SdFile newfile;
|
||||
SdFile *parent=&root;
|
||||
|
||||
|
||||
if(workDir.isOpen())
|
||||
parent=&workDir;
|
||||
|
||||
@@ -595,21 +602,167 @@ void CardReader::chdir(const char * relpath)
|
||||
workDirParents[0]=*parent;
|
||||
}
|
||||
workDir=newfile;
|
||||
#ifdef SDCARD_SORT_ALPHA
|
||||
presort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CardReader::updir()
|
||||
{
|
||||
if(workDirDepth > 0)
|
||||
if (workDirDepth > 0)
|
||||
{
|
||||
--workDirDepth;
|
||||
workDir = workDirParents[0];
|
||||
int d;
|
||||
for (int d = 0; d < workDirDepth; d++)
|
||||
workDirParents[d] = workDirParents[d+1];
|
||||
#ifdef SDCARD_SORT_ALPHA
|
||||
presort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDCARD_SORT_ALPHA
|
||||
|
||||
/**
|
||||
* Get the name of a file in the current directory by sort-index
|
||||
*/
|
||||
void CardReader::getfilename_sorted(const uint16_t nr) {
|
||||
getfilename(nr < sort_count ? sort_order[nr] : nr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all the files and produce a sort key
|
||||
*
|
||||
* We can do this in 3 ways...
|
||||
* - Minimal RAM: Read two filenames at a time sorting along...
|
||||
* - Some RAM: Buffer the directory and return filenames from RAM
|
||||
* - Some RAM: Buffer the directory just for this sort
|
||||
*/
|
||||
void CardReader::presort()
|
||||
{
|
||||
flush_presort();
|
||||
|
||||
uint16_t fileCnt = getnrfilenames();
|
||||
if (fileCnt > 0) {
|
||||
|
||||
if (fileCnt > SORT_LIMIT) fileCnt = SORT_LIMIT;
|
||||
|
||||
#if SORT_USES_RAM
|
||||
#if SORT_USES_MORE_RAM
|
||||
sortshort = (char**)calloc(fileCnt, sizeof(char*));
|
||||
sortnames = (char**)calloc(fileCnt, sizeof(char*));
|
||||
#else
|
||||
char *sortnames[fileCnt];
|
||||
#endif
|
||||
#else
|
||||
char name1[LONG_FILENAME_LENGTH+1];
|
||||
#endif
|
||||
|
||||
#if FOLDER_SORTING != 0
|
||||
#if SORT_USES_RAM && SORT_USES_MORE_RAM
|
||||
isDir = (uint8_t*)calloc(fileCnt, sizeof(uint8_t));
|
||||
#else
|
||||
uint8_t isDir[fileCnt];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
sort_order = new uint8_t[fileCnt];
|
||||
|
||||
if (fileCnt > 1) {
|
||||
|
||||
// Init sort order. If using RAM then read all filenames now.
|
||||
for (uint16_t i=0; i<fileCnt; i++) {
|
||||
sort_order[i] = i;
|
||||
#if SORT_USES_RAM
|
||||
getfilename(i);
|
||||
sortnames[i] = strdup(longFilename[0] ? longFilename : filename);
|
||||
#if SORT_USES_MORE_RAM
|
||||
sortshort[i] = strdup(filename);
|
||||
#endif
|
||||
// char out[30];
|
||||
// sprintf_P(out, PSTR("---- %i %s %s"), i, filenameIsDir ? "D" : " ", sortnames[i]);
|
||||
// SERIAL_ECHOLN(out);
|
||||
#if FOLDER_SORTING != 0
|
||||
isDir[i] = filenameIsDir;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// Bubble Sort
|
||||
for (uint16_t i=fileCnt; --i;) {
|
||||
bool cmp, didSwap = false;
|
||||
for (uint16_t j=0; j<i; ++j) {
|
||||
uint16_t s1 = j, s2 = j+1, o1 = sort_order[s1], o2 = sort_order[s2];
|
||||
#if SORT_USES_RAM
|
||||
#if FOLDER_SORTING != 0
|
||||
cmp = (isDir[o1] == isDir[o2]) ? (strcasecmp(sortnames[o1], sortnames[o2]) > 0) : isDir[FOLDER_SORTING > 0 ? o1 : o2];
|
||||
#else
|
||||
cmp = strcasecmp(sortnames[o1], sortnames[o2]) > 0;
|
||||
#endif
|
||||
#else
|
||||
getfilename(o1);
|
||||
strcpy(name1, longFilename[0] ? longFilename : filename);
|
||||
#if FOLDER_SORTING != 0
|
||||
bool dir1 = filenameIsDir;
|
||||
#endif
|
||||
getfilename(o2);
|
||||
char *name2 = longFilename[0] ? longFilename : filename;
|
||||
#if FOLDER_SORTING != 0
|
||||
cmp = (dir1 == filenameIsDir) ? (strcasecmp(name1, name2) > 0) : (FOLDER_SORTING > 0 ? dir1 : !dir1);
|
||||
#else
|
||||
cmp = strcasecmp(name1, name2) > 0;
|
||||
#endif
|
||||
#endif
|
||||
if (cmp) {
|
||||
// char out[LONG_FILENAME_LENGTH*2+20];
|
||||
// sprintf_P(out, PSTR("Swap %i %s for %i %s"), o1, sortnames[o1], o2, sortnames[o2]);
|
||||
// SERIAL_ECHOLN(out);
|
||||
sort_order[s1] = o2;
|
||||
sort_order[s2] = o1;
|
||||
didSwap = true;
|
||||
}
|
||||
}
|
||||
if (!didSwap) break;
|
||||
}
|
||||
|
||||
#if SORT_USES_RAM && !SORT_USES_MORE_RAM
|
||||
for (uint16_t i=0; i<fileCnt; ++i) free(sortnames[i]);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
sort_order[0] = 0;
|
||||
#if SORT_USES_RAM && SORT_USES_MORE_RAM
|
||||
sortnames = (char**)malloc(sizeof(char*));
|
||||
sortshort = (char**)malloc(sizeof(char*));
|
||||
isDir = (uint8_t*)malloc(sizeof(uint8_t));
|
||||
getfilename(0);
|
||||
sortnames[0] = strdup(longFilename[0] ? longFilename : filename);
|
||||
sortshort[0] = strdup(filename);
|
||||
isDir[0] = filenameIsDir;
|
||||
#endif
|
||||
}
|
||||
|
||||
sort_count = fileCnt;
|
||||
}
|
||||
}
|
||||
|
||||
void CardReader::flush_presort() {
|
||||
if (sort_count > 0) {
|
||||
#if SORT_USES_RAM && SORT_USES_MORE_RAM
|
||||
for (uint8_t i=0; i<sort_count; ++i) {
|
||||
free(sortshort[i]);
|
||||
free(sortnames[i]);
|
||||
}
|
||||
free(sortshort);
|
||||
free(sortnames);
|
||||
#endif
|
||||
delete sort_order;
|
||||
sort_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDCARD_SORT_ALPHA
|
||||
|
||||
void CardReader::printingHasFinished()
|
||||
{
|
||||
@@ -633,6 +786,9 @@ void CardReader::printingHasFinished()
|
||||
enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND));
|
||||
}
|
||||
autotempShutdown();
|
||||
#ifdef SDCARD_SORT_ALPHA
|
||||
presort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif //SDSUPPORT
|
||||
|
||||
Reference in New Issue
Block a user