From f40cff59f3da1ad2cc262ab83ad316a15b8b1f8f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 24 Nov 2014 14:03:20 -0800 Subject: [PATCH 1/8] 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. --- Marlin/Configuration_adv.h | 1 + Marlin/SdFatConfig.h | 4 +- Marlin/cardreader.cpp | 187 ++++++++++++++++++++++++++++++++----- Marlin/cardreader.h | 28 +++++- Marlin/ultralcd.cpp | 29 +++--- 5 files changed, 208 insertions(+), 41 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 6398f4161b..741a85bdb2 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -290,6 +290,7 @@ #define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. +#define SDCARD_SORT_ALPHA // Sort in ASCII order by pre-reading the folder and making a lookup table! #define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the file system block order. // if a file is deleted, it frees a block. hence, the order is not purely chronological. To still have auto0.g accessible, there is again the option to do that. // using: diff --git a/Marlin/SdFatConfig.h b/Marlin/SdFatConfig.h index 710b1f7924..39ef381300 100644 --- a/Marlin/SdFatConfig.h +++ b/Marlin/SdFatConfig.h @@ -111,10 +111,12 @@ uint8_t const SOFT_SPI_SCK_PIN = 13; /** * Defines for long (vfat) filenames */ +/** Number of UTF-16 characters per entry */ +#define FILENAME_LENGTH 13 /** Number of VFAT entries used. Every entry has 13 UTF-16 characters */ #define MAX_VFAT_ENTRIES (2) /** Total size of the buffer used to store the long filenames */ -#define LONG_FILENAME_LENGTH (13*MAX_VFAT_ENTRIES+1) +#define LONG_FILENAME_LENGTH (FILENAME_LENGTH*MAX_VFAT_ENTRIES+1) #endif // SdFatConfig_h diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index d2fb418fba..862ed38475 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -11,6 +11,10 @@ CardReader::CardReader() { + #if SORT_USES_MORE_RAM + sortnames = NULL; + sort_count = 0; + #endif filesize = 0; sdpos = 0; sdprinting = false; @@ -53,15 +57,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) + while (parent.readDir(p, diveFilename) > 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,25 +91,22 @@ void CardReader::lsDive(const char *prepend,SdFile parent) } lsDive(path,dir); //close done automatically by destructor of SdFile - - } else { if (p.name[0] == DIR_NAME_FREE) break; if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue; - if (longFilename[0] != '\0' && - (longFilename[0] == '.' || longFilename[0] == '_')) continue; + if (diveFilename[0] != '\0' && + (diveFilename[0] == '.' || diveFilename[0] == '_')) continue; if ( p.name[0] == '.') { 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 +125,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 +135,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 +173,9 @@ void CardReader::initsd() } workDir=root; curDir=&root; + #ifdef SDCARD_SORT_ALPHA + presort(); + #endif /* if(!workDir.openRoot(&volume)) { @@ -193,8 +192,10 @@ void CardReader::setroot() SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL); }*/ workDir=root; - curDir=&workDir; + #ifdef SDCARD_SORT_ALPHA + presort(); + #endif } void CardReader::release() { @@ -235,7 +236,7 @@ void CardReader::getAbsFilename(char *t) while(*t!=0 && cnt< MAXPATHNAMELENGTH) {t++;cnt++;} //crawl counter forward. } - if(cnt0 && 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 +402,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 +440,9 @@ void CardReader::removeFile(char* name) SERIAL_PROTOCOLPGM("File deleted:"); SERIAL_PROTOCOLLN(fname); sdpos = 0; + #ifdef SDCARD_SORT_ALPHA + presort(); + #endif } else { @@ -577,7 +581,7 @@ void CardReader::chdir(const char * relpath) { SdFile newfile; SdFile *parent=&root; - + if(workDir.isOpen()) parent=&workDir; @@ -595,21 +599,156 @@ 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 uint8_t nr) { + #if SORT_USES_MORE_RAM + getfilename(nr < sort_count ? sort_order[nr] : nr); + #else + getfilename(nr < SORT_LIMIT ? sort_order[nr] : nr); + #endif +} + +/** + * 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() +{ + #if SORT_USES_MORE_RAM + flush_presort(); + #endif + + uint16_t fileCnt = getnrfilenames(); + if (fileCnt > 0) { + + if (fileCnt > SORT_LIMIT) fileCnt = SORT_LIMIT; + + #if SORT_USES_MORE_RAM + sortnames = malloc(fileCnt * sizeof(char*)); + sort_count = fileCnt; + #elif SORT_USES_RAM + char *sortnames[fileCnt]; + #if FOLDER_SORTING != 0 + uint8_t isdir[fileCnt]; + #endif + #else + char sortname[LONG_FILENAME_LENGTH+1]; + #endif + + if (fileCnt > 1) { + + // Init sort order [and get filenames] + for (int i=0; i 0) : isdir[FOLDER_SORTING > 0 ? o1 : o2]; + #else + cmp = strcasecmp(sortnames[o1], sortnames[o2]) > 0); + #endif + #else + getfilename(o1); + #if FOLDER_SORTING != 0 + bool dir1 = filenameIsDir; + #endif + char *name = diveFilename[0] ? diveFilename : filename; + strcpy(sortname, name); + getfilename(o2); + name = diveFilename[0] ? diveFilename : filename; + #if FOLDER_SORTING != 0 + cmp = (dir1 == filenameIsDir) ? (strcasecmp(sortname, name) > 0) : (FOLDER_SORTING > 0 ? dir1 : !dir1); + #else + cmp = strcasecmp(sortname, name) > 0); + #endif + #endif + if (cmp) { + // SERIAL_ECHOPGM("Swap "); + // SERIAL_ECHOLN(sortnames[o1]); + // SERIAL_ECHOPGM(" for "); + // SERIAL_ECHOLN(sortnames[o2]); + sort_order[s1] = o2; + sort_order[s2] = o1; + didSwap = true; + } + } + if (!didSwap) break; + } + + #if SORT_USES_RAM && !SORT_USES_MORE_RAM + for (int i=0; i < fileCnt; ++i) free(sortnames[i]); + #endif + } + else { + sort_order[0] = 0; + } + + } +} + +void CardReader::flush_presort() { + #if SORT_USES_MORE_RAM + if (sort_count > 0) { + for (int i=0; i < sort_count; ++i) { + free(sortnames[i]); + sort_order[i] = i; + } + free(sortnames); + sortnames = NULL; + sort_count = 0; + } + #else + for (int i=SORT_LIMIT; --i;) sort_order[i] = i; + #endif +} + +#endif void CardReader::printingHasFinished() { diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index 78f7148b1f..1d8d1b1fb6 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -3,7 +3,11 @@ #ifdef SDSUPPORT -#define MAX_DIR_DEPTH 10 +#define MAX_DIR_DEPTH 10 // Maximum folder depth +#define SORT_USES_RAM false // Buffer while sorting, else re-read from SD +#define SORT_USES_MORE_RAM false // Always keep the directory in RAM +#define SORT_LIMIT 256 // Maximum number of sorted items +#define FOLDER_SORTING -1 // -1=above 0=none 1=below #include "SdFile.h" enum LsAction {LS_SerialPrint,LS_Count,LS_GetFilename}; @@ -39,6 +43,12 @@ public: void updir(); void setroot(); +#ifdef SDCARD_SORT_ALPHA + void presort(); + void flush_presort(); + void getfilename_sorted(const uint8_t nr); +#endif + FORCE_INLINE bool isFileOpen() { return file.isOpen(); } FORCE_INLINE bool eof() { return sdpos>=filesize ;}; @@ -51,19 +61,27 @@ public: bool saving; bool logging; bool sdprinting ; - bool cardOK ; - char filename[13]; - char longFilename[LONG_FILENAME_LENGTH]; + bool cardOK; + char filename[FILENAME_LENGTH]; + char diveFilename[LONG_FILENAME_LENGTH]; bool filenameIsDir; int lastnr; //last number of the autostart; private: SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH]; uint16_t workDirDepth; +#ifdef SDCARD_SORT_ALPHA + #if SORT_USES_MORE_RAM + uint16_t sort_count; + char **sortnames; + #else + uint8_t sort_order[SORT_LIMIT]; + #endif +#endif Sd2Card card; SdVolume volume; SdFile file; #define SD_PROCEDURE_DEPTH 1 - #define MAXPATHNAMELENGTH (13*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1) + #define MAXPATHNAMELENGTH (FILENAME_LENGTH*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1) uint8_t file_subcall_ctr; uint32_t filespos[SD_PROCEDURE_DEPTH]; char filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH]; diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index fb2ddbfffa..981efdb606 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -946,9 +946,9 @@ void lcd_sdcard_menu() card.getWorkDirName(); if(card.filename[0]=='/') { -#if SDCARDDETECT == -1 + #if SDCARDDETECT == -1 MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh); -#endif + #endif }else{ MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir); } @@ -957,16 +957,23 @@ void lcd_sdcard_menu() { if (_menuItemNr == _lineNr) { - #ifndef SDCARD_RATHERRECENTFIRST - card.getfilename(i); + #if defined(SDCARD_RATHERRECENTFIRST) && !defined(SDCARD_SORT_ALPHA) + int nr = fileCnt-1-i; #else - card.getfilename(fileCnt-1-i); + int nr = i; #endif - if (card.filenameIsDir) - { - MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename); - }else{ - MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename); + + #ifdef SDCARD_SORT_ALPHA + card.getfilename_sorted(nr); + #else + card.getfilename(nr); + #endif + + if (card.filenameIsDir) { + MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.diveFilename); + } + else { + MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.diveFilename); } }else{ MENU_ITEM_DUMMY(); @@ -1172,7 +1179,7 @@ void lcd_init() #endif // SR_LCD_2W_NL #endif//!NEWPANEL -#if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0) +#if defined(SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0) pinMode(SDCARDDETECT,INPUT); WRITE(SDCARDDETECT, HIGH); lcd_oldcardstatus = IS_SD_INSERTED; From 87fc00c182c2a3241081310f31084341ad8eea6b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 24 Nov 2014 20:26:27 -0800 Subject: [PATCH 2/8] Expand on More RAM concept, address minor bugs --- Marlin/cardreader.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 862ed38475..10a4e6b1cf 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -11,7 +11,7 @@ CardReader::CardReader() { - #if SORT_USES_MORE_RAM + #if defined(SDCARD_SORT_ALPHA) && SORT_USES_MORE_RAM sortnames = NULL; sort_count = 0; #endif @@ -558,6 +558,13 @@ void CardReader::closefile(bool store_location) void CardReader::getfilename(const uint8_t nr) { + #if defined(SDCARD_SORT_ALPHA) && SORT_USES_MORE_RAM + if (nr < sort_count) { + strcpy(diveFilename, sortnames[nr]); + return; + } + #endif + curDir=&workDir; lsAction=LS_GetFilename; nrFiles=nr; @@ -642,9 +649,7 @@ void CardReader::getfilename_sorted(const uint8_t nr) { */ void CardReader::presort() { - #if SORT_USES_MORE_RAM - flush_presort(); - #endif + flush_presort(); uint16_t fileCnt = getnrfilenames(); if (fileCnt > 0) { @@ -652,7 +657,7 @@ void CardReader::presort() if (fileCnt > SORT_LIMIT) fileCnt = SORT_LIMIT; #if SORT_USES_MORE_RAM - sortnames = malloc(fileCnt * sizeof(char*)); + sortnames = (char**)malloc(fileCnt * sizeof(char*)); sort_count = fileCnt; #elif SORT_USES_RAM char *sortnames[fileCnt]; @@ -748,7 +753,7 @@ void CardReader::flush_presort() { #endif } -#endif +#endif // SDCARD_SORT_ALPHA void CardReader::printingHasFinished() { From 6901445592dd9e9b164b00b4ff432f0e89f63511 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 26 Nov 2014 07:17:47 -0800 Subject: [PATCH 3/8] 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. --- Marlin/cardreader.cpp | 137 +++++++++++++++++++++--------------------- Marlin/cardreader.h | 18 +++--- Marlin/ultralcd.cpp | 4 +- 3 files changed, 78 insertions(+), 81 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 10a4e6b1cf..5d465f47a4 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -11,8 +11,7 @@ CardReader::CardReader() { - #if defined(SDCARD_SORT_ALPHA) && SORT_USES_MORE_RAM - sortnames = NULL; + #ifdef SDCARD_SORT_ALPHA sort_count = 0; #endif filesize = 0; @@ -37,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; } @@ -59,7 +54,7 @@ void CardReader::lsDive(const char *prepend,SdFile parent) dir_t p; uint8_t cnt=0; - while (parent.readDir(p, diveFilename) > 0) + while (parent.readDir(p, longFilename) > 0) { if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint { @@ -96,8 +91,8 @@ void CardReader::lsDive(const char *prepend,SdFile parent) { if (p.name[0] == DIR_NAME_FREE) break; if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue; - if (diveFilename[0] != '\0' && - (diveFilename[0] == '.' || diveFilename[0] == '_')) continue; + if (longFilename[0] != '\0' && + (longFilename[0] == '.' || longFilename[0] == '_')) continue; if ( p.name[0] == '.') { if ( p.name[1] != '.') @@ -556,21 +551,20 @@ 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_MORE_RAM + #if defined(SDCARD_SORT_ALPHA) && SORT_USES_RAM && SORT_USES_MORE_RAM if (nr < sort_count) { - strcpy(diveFilename, sortnames[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() @@ -631,12 +625,8 @@ void CardReader::updir() /** * Get the name of a file in the current directory by sort-index */ -void CardReader::getfilename_sorted(const uint8_t nr) { - #if SORT_USES_MORE_RAM - getfilename(nr < sort_count ? sort_order[nr] : nr); - #else - getfilename(nr < SORT_LIMIT ? sort_order[nr] : nr); - #endif +void CardReader::getfilename_sorted(const uint16_t nr) { + getfilename(nr < sort_count ? sort_order[nr] : nr); } /** @@ -656,68 +646,73 @@ void CardReader::presort() if (fileCnt > SORT_LIMIT) fileCnt = SORT_LIMIT; - #if SORT_USES_MORE_RAM - sortnames = (char**)malloc(fileCnt * sizeof(char*)); - sort_count = fileCnt; - #elif SORT_USES_RAM - char *sortnames[fileCnt]; - #if FOLDER_SORTING != 0 - uint8_t isdir[fileCnt]; + #if SORT_USES_RAM + #if SORT_USES_MORE_RAM + sortnames = (char**)calloc(fileCnt, sizeof(char*)); + #else + char *sortnames[fileCnt]; #endif #else - char sortname[LONG_FILENAME_LENGTH+1]; + 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_count = fileCnt; + sort_order = new uint8_t[fileCnt]; + if (fileCnt > 1) { - // Init sort order [and get filenames] - for (int i=0; i 0) : isdir[FOLDER_SORTING > 0 ? o1 : o2]; + 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); + 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 - char *name = diveFilename[0] ? diveFilename : filename; - strcpy(sortname, name); getfilename(o2); - name = diveFilename[0] ? diveFilename : filename; + char *name2 = longFilename[0] ? longFilename : filename; #if FOLDER_SORTING != 0 - cmp = (dir1 == filenameIsDir) ? (strcasecmp(sortname, name) > 0) : (FOLDER_SORTING > 0 ? dir1 : !dir1); + cmp = (dir1 == filenameIsDir) ? (strcasecmp(name1, name2) > 0) : (FOLDER_SORTING > 0 ? dir1 : !dir1); #else - cmp = strcasecmp(sortname, name) > 0); + cmp = strcasecmp(name1, name2) > 0; #endif #endif if (cmp) { - // SERIAL_ECHOPGM("Swap "); - // SERIAL_ECHOLN(sortnames[o1]); - // SERIAL_ECHOPGM(" for "); - // SERIAL_ECHOLN(sortnames[o2]); + // 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; @@ -727,30 +722,32 @@ void CardReader::presort() } #if SORT_USES_RAM && !SORT_USES_MORE_RAM - for (int i=0; i < fileCnt; ++i) free(sortnames[i]); + for (uint16_t i=0; i 0) { - for (int i=0; i < sort_count; ++i) { - free(sortnames[i]); - sort_order[i] = i; - } + if (sort_count > 0) { + #if SORT_USES_RAM && SORT_USES_MORE_RAM + for (uint8_t i=0; i Date: Wed, 26 Nov 2014 08:51:31 -0800 Subject: [PATCH 4/8] 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. --- Marlin/cardreader.cpp | 19 +++++++++++++++++-- Marlin/cardreader.h | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 5d465f47a4..cf0b5176a0 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -203,6 +203,7 @@ void CardReader::startFileprint() if(cardOK) { sdprinting = true; + flush_presort(); } } @@ -555,6 +556,7 @@ 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; @@ -648,6 +650,7 @@ void CardReader::presort() #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]; @@ -664,7 +667,6 @@ void CardReader::presort() #endif #endif - sort_count = fileCnt; sort_order = new uint8_t[fileCnt]; if (fileCnt > 1) { @@ -675,6 +677,9 @@ void CardReader::presort() #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); @@ -729,20 +734,27 @@ void CardReader::presort() 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 Date: Mon, 24 Nov 2014 14:03:20 -0800 Subject: [PATCH 5/8] 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. --- Marlin/Configuration_adv.h | 1 + Marlin/SdFatConfig.h | 4 +- Marlin/cardreader.cpp | 187 ++++++++++++++++++++++++++++++++----- Marlin/cardreader.h | 28 +++++- Marlin/ultralcd.cpp | 29 +++--- 5 files changed, 208 insertions(+), 41 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 6398f4161b..741a85bdb2 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -290,6 +290,7 @@ #define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers? #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place. +#define SDCARD_SORT_ALPHA // Sort in ASCII order by pre-reading the folder and making a lookup table! #define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the file system block order. // if a file is deleted, it frees a block. hence, the order is not purely chronological. To still have auto0.g accessible, there is again the option to do that. // using: diff --git a/Marlin/SdFatConfig.h b/Marlin/SdFatConfig.h index 710b1f7924..39ef381300 100644 --- a/Marlin/SdFatConfig.h +++ b/Marlin/SdFatConfig.h @@ -111,10 +111,12 @@ uint8_t const SOFT_SPI_SCK_PIN = 13; /** * Defines for long (vfat) filenames */ +/** Number of UTF-16 characters per entry */ +#define FILENAME_LENGTH 13 /** Number of VFAT entries used. Every entry has 13 UTF-16 characters */ #define MAX_VFAT_ENTRIES (2) /** Total size of the buffer used to store the long filenames */ -#define LONG_FILENAME_LENGTH (13*MAX_VFAT_ENTRIES+1) +#define LONG_FILENAME_LENGTH (FILENAME_LENGTH*MAX_VFAT_ENTRIES+1) #endif // SdFatConfig_h diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index d2fb418fba..862ed38475 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -11,6 +11,10 @@ CardReader::CardReader() { + #if SORT_USES_MORE_RAM + sortnames = NULL; + sort_count = 0; + #endif filesize = 0; sdpos = 0; sdprinting = false; @@ -53,15 +57,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) + while (parent.readDir(p, diveFilename) > 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,25 +91,22 @@ void CardReader::lsDive(const char *prepend,SdFile parent) } lsDive(path,dir); //close done automatically by destructor of SdFile - - } else { if (p.name[0] == DIR_NAME_FREE) break; if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue; - if (longFilename[0] != '\0' && - (longFilename[0] == '.' || longFilename[0] == '_')) continue; + if (diveFilename[0] != '\0' && + (diveFilename[0] == '.' || diveFilename[0] == '_')) continue; if ( p.name[0] == '.') { 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 +125,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 +135,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 +173,9 @@ void CardReader::initsd() } workDir=root; curDir=&root; + #ifdef SDCARD_SORT_ALPHA + presort(); + #endif /* if(!workDir.openRoot(&volume)) { @@ -193,8 +192,10 @@ void CardReader::setroot() SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL); }*/ workDir=root; - curDir=&workDir; + #ifdef SDCARD_SORT_ALPHA + presort(); + #endif } void CardReader::release() { @@ -235,7 +236,7 @@ void CardReader::getAbsFilename(char *t) while(*t!=0 && cnt< MAXPATHNAMELENGTH) {t++;cnt++;} //crawl counter forward. } - if(cnt0 && 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 +402,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 +440,9 @@ void CardReader::removeFile(char* name) SERIAL_PROTOCOLPGM("File deleted:"); SERIAL_PROTOCOLLN(fname); sdpos = 0; + #ifdef SDCARD_SORT_ALPHA + presort(); + #endif } else { @@ -577,7 +581,7 @@ void CardReader::chdir(const char * relpath) { SdFile newfile; SdFile *parent=&root; - + if(workDir.isOpen()) parent=&workDir; @@ -595,21 +599,156 @@ 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 uint8_t nr) { + #if SORT_USES_MORE_RAM + getfilename(nr < sort_count ? sort_order[nr] : nr); + #else + getfilename(nr < SORT_LIMIT ? sort_order[nr] : nr); + #endif +} + +/** + * 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() +{ + #if SORT_USES_MORE_RAM + flush_presort(); + #endif + + uint16_t fileCnt = getnrfilenames(); + if (fileCnt > 0) { + + if (fileCnt > SORT_LIMIT) fileCnt = SORT_LIMIT; + + #if SORT_USES_MORE_RAM + sortnames = malloc(fileCnt * sizeof(char*)); + sort_count = fileCnt; + #elif SORT_USES_RAM + char *sortnames[fileCnt]; + #if FOLDER_SORTING != 0 + uint8_t isdir[fileCnt]; + #endif + #else + char sortname[LONG_FILENAME_LENGTH+1]; + #endif + + if (fileCnt > 1) { + + // Init sort order [and get filenames] + for (int i=0; i 0) : isdir[FOLDER_SORTING > 0 ? o1 : o2]; + #else + cmp = strcasecmp(sortnames[o1], sortnames[o2]) > 0); + #endif + #else + getfilename(o1); + #if FOLDER_SORTING != 0 + bool dir1 = filenameIsDir; + #endif + char *name = diveFilename[0] ? diveFilename : filename; + strcpy(sortname, name); + getfilename(o2); + name = diveFilename[0] ? diveFilename : filename; + #if FOLDER_SORTING != 0 + cmp = (dir1 == filenameIsDir) ? (strcasecmp(sortname, name) > 0) : (FOLDER_SORTING > 0 ? dir1 : !dir1); + #else + cmp = strcasecmp(sortname, name) > 0); + #endif + #endif + if (cmp) { + // SERIAL_ECHOPGM("Swap "); + // SERIAL_ECHOLN(sortnames[o1]); + // SERIAL_ECHOPGM(" for "); + // SERIAL_ECHOLN(sortnames[o2]); + sort_order[s1] = o2; + sort_order[s2] = o1; + didSwap = true; + } + } + if (!didSwap) break; + } + + #if SORT_USES_RAM && !SORT_USES_MORE_RAM + for (int i=0; i < fileCnt; ++i) free(sortnames[i]); + #endif + } + else { + sort_order[0] = 0; + } + + } +} + +void CardReader::flush_presort() { + #if SORT_USES_MORE_RAM + if (sort_count > 0) { + for (int i=0; i < sort_count; ++i) { + free(sortnames[i]); + sort_order[i] = i; + } + free(sortnames); + sortnames = NULL; + sort_count = 0; + } + #else + for (int i=SORT_LIMIT; --i;) sort_order[i] = i; + #endif +} + +#endif void CardReader::printingHasFinished() { diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index 78f7148b1f..1d8d1b1fb6 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -3,7 +3,11 @@ #ifdef SDSUPPORT -#define MAX_DIR_DEPTH 10 +#define MAX_DIR_DEPTH 10 // Maximum folder depth +#define SORT_USES_RAM false // Buffer while sorting, else re-read from SD +#define SORT_USES_MORE_RAM false // Always keep the directory in RAM +#define SORT_LIMIT 256 // Maximum number of sorted items +#define FOLDER_SORTING -1 // -1=above 0=none 1=below #include "SdFile.h" enum LsAction {LS_SerialPrint,LS_Count,LS_GetFilename}; @@ -39,6 +43,12 @@ public: void updir(); void setroot(); +#ifdef SDCARD_SORT_ALPHA + void presort(); + void flush_presort(); + void getfilename_sorted(const uint8_t nr); +#endif + FORCE_INLINE bool isFileOpen() { return file.isOpen(); } FORCE_INLINE bool eof() { return sdpos>=filesize ;}; @@ -51,19 +61,27 @@ public: bool saving; bool logging; bool sdprinting ; - bool cardOK ; - char filename[13]; - char longFilename[LONG_FILENAME_LENGTH]; + bool cardOK; + char filename[FILENAME_LENGTH]; + char diveFilename[LONG_FILENAME_LENGTH]; bool filenameIsDir; int lastnr; //last number of the autostart; private: SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH]; uint16_t workDirDepth; +#ifdef SDCARD_SORT_ALPHA + #if SORT_USES_MORE_RAM + uint16_t sort_count; + char **sortnames; + #else + uint8_t sort_order[SORT_LIMIT]; + #endif +#endif Sd2Card card; SdVolume volume; SdFile file; #define SD_PROCEDURE_DEPTH 1 - #define MAXPATHNAMELENGTH (13*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1) + #define MAXPATHNAMELENGTH (FILENAME_LENGTH*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1) uint8_t file_subcall_ctr; uint32_t filespos[SD_PROCEDURE_DEPTH]; char filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH]; diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 734c859d02..89cec4c48f 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -972,9 +972,9 @@ void lcd_sdcard_menu() card.getWorkDirName(); if(card.filename[0]=='/') { -#if SDCARDDETECT == -1 + #if SDCARDDETECT == -1 MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh); -#endif + #endif }else{ MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir); } @@ -983,16 +983,23 @@ void lcd_sdcard_menu() { if (_menuItemNr == _lineNr) { - #ifndef SDCARD_RATHERRECENTFIRST - card.getfilename(i); + #if defined(SDCARD_RATHERRECENTFIRST) && !defined(SDCARD_SORT_ALPHA) + int nr = fileCnt-1-i; #else - card.getfilename(fileCnt-1-i); + int nr = i; #endif - if (card.filenameIsDir) - { - MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename); - }else{ - MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename); + + #ifdef SDCARD_SORT_ALPHA + card.getfilename_sorted(nr); + #else + card.getfilename(nr); + #endif + + if (card.filenameIsDir) { + MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.diveFilename); + } + else { + MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.diveFilename); } }else{ MENU_ITEM_DUMMY(); @@ -1198,7 +1205,7 @@ void lcd_init() #endif // SR_LCD_2W_NL #endif//!NEWPANEL -#if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0) +#if defined(SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0) pinMode(SDCARDDETECT,INPUT); WRITE(SDCARDDETECT, HIGH); lcd_oldcardstatus = IS_SD_INSERTED; From 2b54eeb89717111f55510e17d7b6c5bc1b7c44b8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 24 Nov 2014 20:26:27 -0800 Subject: [PATCH 6/8] Expand on More RAM concept, address minor bugs --- Marlin/cardreader.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 862ed38475..10a4e6b1cf 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -11,7 +11,7 @@ CardReader::CardReader() { - #if SORT_USES_MORE_RAM + #if defined(SDCARD_SORT_ALPHA) && SORT_USES_MORE_RAM sortnames = NULL; sort_count = 0; #endif @@ -558,6 +558,13 @@ void CardReader::closefile(bool store_location) void CardReader::getfilename(const uint8_t nr) { + #if defined(SDCARD_SORT_ALPHA) && SORT_USES_MORE_RAM + if (nr < sort_count) { + strcpy(diveFilename, sortnames[nr]); + return; + } + #endif + curDir=&workDir; lsAction=LS_GetFilename; nrFiles=nr; @@ -642,9 +649,7 @@ void CardReader::getfilename_sorted(const uint8_t nr) { */ void CardReader::presort() { - #if SORT_USES_MORE_RAM - flush_presort(); - #endif + flush_presort(); uint16_t fileCnt = getnrfilenames(); if (fileCnt > 0) { @@ -652,7 +657,7 @@ void CardReader::presort() if (fileCnt > SORT_LIMIT) fileCnt = SORT_LIMIT; #if SORT_USES_MORE_RAM - sortnames = malloc(fileCnt * sizeof(char*)); + sortnames = (char**)malloc(fileCnt * sizeof(char*)); sort_count = fileCnt; #elif SORT_USES_RAM char *sortnames[fileCnt]; @@ -748,7 +753,7 @@ void CardReader::flush_presort() { #endif } -#endif +#endif // SDCARD_SORT_ALPHA void CardReader::printingHasFinished() { From 725ba8d01e2b013c03d15bd947b0ef0a5fb99d07 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 26 Nov 2014 07:17:47 -0800 Subject: [PATCH 7/8] 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. --- Marlin/cardreader.cpp | 137 +++++++++++++++++++++--------------------- Marlin/cardreader.h | 18 +++--- Marlin/ultralcd.cpp | 4 +- 3 files changed, 78 insertions(+), 81 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 10a4e6b1cf..5d465f47a4 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -11,8 +11,7 @@ CardReader::CardReader() { - #if defined(SDCARD_SORT_ALPHA) && SORT_USES_MORE_RAM - sortnames = NULL; + #ifdef SDCARD_SORT_ALPHA sort_count = 0; #endif filesize = 0; @@ -37,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; } @@ -59,7 +54,7 @@ void CardReader::lsDive(const char *prepend,SdFile parent) dir_t p; uint8_t cnt=0; - while (parent.readDir(p, diveFilename) > 0) + while (parent.readDir(p, longFilename) > 0) { if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint { @@ -96,8 +91,8 @@ void CardReader::lsDive(const char *prepend,SdFile parent) { if (p.name[0] == DIR_NAME_FREE) break; if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue; - if (diveFilename[0] != '\0' && - (diveFilename[0] == '.' || diveFilename[0] == '_')) continue; + if (longFilename[0] != '\0' && + (longFilename[0] == '.' || longFilename[0] == '_')) continue; if ( p.name[0] == '.') { if ( p.name[1] != '.') @@ -556,21 +551,20 @@ 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_MORE_RAM + #if defined(SDCARD_SORT_ALPHA) && SORT_USES_RAM && SORT_USES_MORE_RAM if (nr < sort_count) { - strcpy(diveFilename, sortnames[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() @@ -631,12 +625,8 @@ void CardReader::updir() /** * Get the name of a file in the current directory by sort-index */ -void CardReader::getfilename_sorted(const uint8_t nr) { - #if SORT_USES_MORE_RAM - getfilename(nr < sort_count ? sort_order[nr] : nr); - #else - getfilename(nr < SORT_LIMIT ? sort_order[nr] : nr); - #endif +void CardReader::getfilename_sorted(const uint16_t nr) { + getfilename(nr < sort_count ? sort_order[nr] : nr); } /** @@ -656,68 +646,73 @@ void CardReader::presort() if (fileCnt > SORT_LIMIT) fileCnt = SORT_LIMIT; - #if SORT_USES_MORE_RAM - sortnames = (char**)malloc(fileCnt * sizeof(char*)); - sort_count = fileCnt; - #elif SORT_USES_RAM - char *sortnames[fileCnt]; - #if FOLDER_SORTING != 0 - uint8_t isdir[fileCnt]; + #if SORT_USES_RAM + #if SORT_USES_MORE_RAM + sortnames = (char**)calloc(fileCnt, sizeof(char*)); + #else + char *sortnames[fileCnt]; #endif #else - char sortname[LONG_FILENAME_LENGTH+1]; + 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_count = fileCnt; + sort_order = new uint8_t[fileCnt]; + if (fileCnt > 1) { - // Init sort order [and get filenames] - for (int i=0; i 0) : isdir[FOLDER_SORTING > 0 ? o1 : o2]; + 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); + 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 - char *name = diveFilename[0] ? diveFilename : filename; - strcpy(sortname, name); getfilename(o2); - name = diveFilename[0] ? diveFilename : filename; + char *name2 = longFilename[0] ? longFilename : filename; #if FOLDER_SORTING != 0 - cmp = (dir1 == filenameIsDir) ? (strcasecmp(sortname, name) > 0) : (FOLDER_SORTING > 0 ? dir1 : !dir1); + cmp = (dir1 == filenameIsDir) ? (strcasecmp(name1, name2) > 0) : (FOLDER_SORTING > 0 ? dir1 : !dir1); #else - cmp = strcasecmp(sortname, name) > 0); + cmp = strcasecmp(name1, name2) > 0; #endif #endif if (cmp) { - // SERIAL_ECHOPGM("Swap "); - // SERIAL_ECHOLN(sortnames[o1]); - // SERIAL_ECHOPGM(" for "); - // SERIAL_ECHOLN(sortnames[o2]); + // 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; @@ -727,30 +722,32 @@ void CardReader::presort() } #if SORT_USES_RAM && !SORT_USES_MORE_RAM - for (int i=0; i < fileCnt; ++i) free(sortnames[i]); + for (uint16_t i=0; i 0) { - for (int i=0; i < sort_count; ++i) { - free(sortnames[i]); - sort_order[i] = i; - } + if (sort_count > 0) { + #if SORT_USES_RAM && SORT_USES_MORE_RAM + for (uint8_t i=0; i Date: Wed, 26 Nov 2014 08:51:31 -0800 Subject: [PATCH 8/8] 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. --- Marlin/cardreader.cpp | 19 +++++++++++++++++-- Marlin/cardreader.h | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index 5d465f47a4..cf0b5176a0 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -203,6 +203,7 @@ void CardReader::startFileprint() if(cardOK) { sdprinting = true; + flush_presort(); } } @@ -555,6 +556,7 @@ 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; @@ -648,6 +650,7 @@ void CardReader::presort() #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]; @@ -664,7 +667,6 @@ void CardReader::presort() #endif #endif - sort_count = fileCnt; sort_order = new uint8_t[fileCnt]; if (fileCnt > 1) { @@ -675,6 +677,9 @@ void CardReader::presort() #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); @@ -729,20 +734,27 @@ void CardReader::presort() 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