# 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:
Scott Lahteine
2014-11-24 14:03:20 -08:00
parent 1977b4490f
commit de725bd408
5 changed files with 237 additions and 52 deletions

View File

@@ -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