From f40cff59f3da1ad2cc262ab83ad316a15b8b1f8f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 24 Nov 2014 14:03:20 -0800 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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 04/12] 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 05/12] 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 06/12] 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 07/12] 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 08/12] 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 09/12] # 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. --- Marlin/Configuration_adv.h | 1 + Marlin/SdFatConfig.h | 4 +- Marlin/cardreader.cpp | 222 +++++++++++++++++++++++++++++++------ Marlin/cardreader.h | 33 ++++-- Marlin/ultralcd.cpp | 29 +++-- 5 files changed, 237 insertions(+), 52 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..cf0b5176a0 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -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(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 +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 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 0) { + #if SORT_USES_RAM && SORT_USES_MORE_RAM + for (uint8_t i=0; i=filesize ;}; @@ -50,20 +60,29 @@ public: public: bool saving; bool logging; - bool sdprinting ; - bool cardOK ; - char filename[13]; + bool sdprinting; + bool cardOK; + char filename[FILENAME_LENGTH]; char longFilename[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 + uint16_t sort_count; + uint8_t *sort_order; + #if SORT_USES_MORE_RAM + char **sortshort; + char **sortnames; + uint8_t *isDir; + #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]; @@ -75,7 +94,7 @@ private: bool autostart_stilltocheck; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware. LsAction lsAction; //stored for recursion. - int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory. + uint16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory. char* diveDirName; void lsDive(const char *prepend,SdFile parent); }; diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 550b9cb0b0..513f493bb6 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -993,9 +993,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); } @@ -1004,16 +1004,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.longFilename); + } + else { + MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename); } }else{ MENU_ITEM_DUMMY(); @@ -1219,7 +1226,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 b4e287fe8ed5c297a8acb2df3527f3bbfdf0b610 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 30 Nov 2014 21:28:16 -0800 Subject: [PATCH 10/12] 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 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index cf0b5176a0..c02b354037 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -54,7 +54,7 @@ void CardReader::lsDive(const char *prepend,SdFile parent) dir_t p; 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 { @@ -91,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 (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] != '.') From 599530902dd122fb83f8f4f8c77daa409272a6ec Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 6 Dec 2014 03:40:39 -0800 Subject: [PATCH 11/12] Polish up a little... --- Marlin/Configuration_adv.h | 2 +- Marlin/cardreader.h | 11 +++++++---- .../example_configurations/SCARA/Configuration_adv.h | 1 + .../example_configurations/delta/Configuration_adv.h | 1 + .../makibox/Configuration_adv.h | 1 + 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 741a85bdb2..13dfe2b441 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -290,7 +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_SORT_ALPHA // Sort SD file listings in ASCII order. Find additional options in cardreader.h #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/cardreader.h b/Marlin/cardreader.h index fd8635a5bd..f3af6da5b5 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -4,10 +4,13 @@ #ifdef SDSUPPORT #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 64 // Maximum number of sorted items -#define FOLDER_SORTING -1 // -1=above 0=none 1=below + +#ifdef SDCARD_SORT_ALPHA + #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 +#endif #include "SdFile.h" enum LsAction {LS_SerialPrint,LS_Count,LS_GetFilename}; diff --git a/Marlin/example_configurations/SCARA/Configuration_adv.h b/Marlin/example_configurations/SCARA/Configuration_adv.h index 7a01bccb6c..1998092002 100644 --- a/Marlin/example_configurations/SCARA/Configuration_adv.h +++ b/Marlin/example_configurations/SCARA/Configuration_adv.h @@ -295,6 +295,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 SD file listings in ASCII order. Find additional options in cardreader.h #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/example_configurations/delta/Configuration_adv.h b/Marlin/example_configurations/delta/Configuration_adv.h index ee42481be1..3c2eecacf6 100644 --- a/Marlin/example_configurations/delta/Configuration_adv.h +++ b/Marlin/example_configurations/delta/Configuration_adv.h @@ -287,6 +287,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 SD file listings in ASCII order. Find additional options in cardreader.h #define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the filesystem block order. // if a file is deleted, it frees a block. hence, the order is not purely cronological. To still have auto0.g accessible, there is again the option to do that. // using: diff --git a/Marlin/example_configurations/makibox/Configuration_adv.h b/Marlin/example_configurations/makibox/Configuration_adv.h index 7883c79996..7151459d01 100644 --- a/Marlin/example_configurations/makibox/Configuration_adv.h +++ b/Marlin/example_configurations/makibox/Configuration_adv.h @@ -291,6 +291,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 SD file listings in ASCII order. Find additional options in cardreader.h #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: From 485ca10bc366f8744afc30b1cbb422ba54d71709 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 6 Dec 2014 04:16:45 -0800 Subject: [PATCH 12/12] Disable SDCARD_SORT_ALPHA by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For legacy boards it’s better if this option is disabled. --- Marlin/Configuration_adv.h | 2 +- Marlin/example_configurations/SCARA/Configuration_adv.h | 2 +- Marlin/example_configurations/delta/Configuration_adv.h | 2 +- Marlin/example_configurations/makibox/Configuration_adv.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 13dfe2b441..748156ebd5 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -290,7 +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 SD file listings in ASCII order. Find additional options in cardreader.h +//#define SDCARD_SORT_ALPHA // Sort SD file listings in ASCII order. Find additional options in cardreader.h #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/example_configurations/SCARA/Configuration_adv.h b/Marlin/example_configurations/SCARA/Configuration_adv.h index 1998092002..10fbe9b316 100644 --- a/Marlin/example_configurations/SCARA/Configuration_adv.h +++ b/Marlin/example_configurations/SCARA/Configuration_adv.h @@ -295,7 +295,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 SD file listings in ASCII order. Find additional options in cardreader.h +//#define SDCARD_SORT_ALPHA // Sort SD file listings in ASCII order. Find additional options in cardreader.h #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/example_configurations/delta/Configuration_adv.h b/Marlin/example_configurations/delta/Configuration_adv.h index 3c2eecacf6..6c9d56886d 100644 --- a/Marlin/example_configurations/delta/Configuration_adv.h +++ b/Marlin/example_configurations/delta/Configuration_adv.h @@ -287,7 +287,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 SD file listings in ASCII order. Find additional options in cardreader.h +//#define SDCARD_SORT_ALPHA // Sort SD file listings in ASCII order. Find additional options in cardreader.h #define SDCARD_RATHERRECENTFIRST //reverse file order of sd card menu display. Its sorted practically after the filesystem block order. // if a file is deleted, it frees a block. hence, the order is not purely cronological. To still have auto0.g accessible, there is again the option to do that. // using: diff --git a/Marlin/example_configurations/makibox/Configuration_adv.h b/Marlin/example_configurations/makibox/Configuration_adv.h index 7151459d01..312b2b9647 100644 --- a/Marlin/example_configurations/makibox/Configuration_adv.h +++ b/Marlin/example_configurations/makibox/Configuration_adv.h @@ -291,7 +291,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 SD file listings in ASCII order. Find additional options in cardreader.h +//#define SDCARD_SORT_ALPHA // Sort SD file listings in ASCII order. Find additional options in cardreader.h #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: