From f40cff59f3da1ad2cc262ab83ad316a15b8b1f8f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 24 Nov 2014 14:03:20 -0800 Subject: [PATCH 01/24] 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 6398f4161..741a85bdb 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 710b1f792..39ef38130 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 d2fb418fb..862ed3847 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 78f7148b1..1d8d1b1fb 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 fb2ddbfff..981efdb60 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/24] 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 862ed3847..10a4e6b1c 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/24] 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 10a4e6b1c..5d465f47a 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/24] 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 5d465f47a..cf0b5176a 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/24] 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 6398f4161..741a85bdb 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 710b1f792..39ef38130 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 d2fb418fb..862ed3847 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 78f7148b1..1d8d1b1fb 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 734c859d0..89cec4c48 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/24] 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 862ed3847..10a4e6b1c 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/24] 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 10a4e6b1c..5d465f47a 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/24] 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 5d465f47a..cf0b5176a 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/24] # 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 6398f4161..741a85bdb 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 710b1f792..39ef38130 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 d2fb418fb..cf0b5176a 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 550b9cb0b..513f493bb 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/24] 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 cf0b5176a..c02b35403 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/24] 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 741a85bdb..13dfe2b44 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 fd8635a5b..f3af6da5b 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 7a01bccb6..199809200 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 ee42481be..3c2eecacf 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 7883c7999..7151459d0 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/24] 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 13dfe2b44..748156ebd 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 199809200..10fbe9b31 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 3c2eecacf..6c9d56886 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 7151459d0..312b2b964 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: From 0cbbba08bdb3ba61e960d230ec64499439fa3847 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 24 Nov 2014 14:03:20 -0800 Subject: [PATCH 13/24] 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 bce45851d..219bebf23 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -292,6 +292,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 710b1f792..39ef38130 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 d2fb418fb..862ed3847 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 78f7148b1..1d8d1b1fb 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 550b9cb0b..40e0b97a9 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.diveFilename); + } + else { + MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.diveFilename); } }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 785143a01305d21fdda8682e923df33bc182be08 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 24 Nov 2014 20:26:27 -0800 Subject: [PATCH 14/24] 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 862ed3847..10a4e6b1c 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 ae081d0fe01b91680586077a9a68f313a0c3493b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 26 Nov 2014 07:17:47 -0800 Subject: [PATCH 15/24] 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 10a4e6b1c..5d465f47a 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 16/24] 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 5d465f47a..cf0b5176a 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 17/24] 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/cardreader.cpp | 6 +++--- Marlin/cardreader.h | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index cf0b5176a..c02b35403 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] != '.') diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index fd8635a5b..494a315f2 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -46,7 +46,11 @@ public: #ifdef SDCARD_SORT_ALPHA void presort(); void flush_presort(); +<<<<<<< HEAD void getfilename_sorted(const uint16_t nr); +======= + void getfilename_sorted(const uint8_t nr); +>>>>>>> SD Card Alpha Sorting #endif @@ -60,22 +64,37 @@ public: public: bool saving; bool logging; +<<<<<<< HEAD bool sdprinting; bool cardOK; char filename[FILENAME_LENGTH]; char longFilename[LONG_FILENAME_LENGTH]; +======= + bool sdprinting ; + bool cardOK; + char filename[FILENAME_LENGTH]; + char diveFilename[LONG_FILENAME_LENGTH]; +>>>>>>> SD Card Alpha Sorting 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 +<<<<<<< HEAD uint16_t sort_count; uint8_t *sort_order; #if SORT_USES_MORE_RAM char **sortshort; char **sortnames; uint8_t *isDir; +======= + #if SORT_USES_MORE_RAM + uint16_t sort_count; + char **sortnames; + #else + uint8_t sort_order[SORT_LIMIT]; +>>>>>>> SD Card Alpha Sorting #endif #endif Sd2Card card; From b6ffea612a360e377b3e89404ca79e92470d0624 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 24 Nov 2014 20:26:27 -0800 Subject: [PATCH 18/24] Expand on More RAM concept, address minor bugs --- Marlin/cardreader.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index 494a315f2..fd8635a5b 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -46,11 +46,7 @@ public: #ifdef SDCARD_SORT_ALPHA void presort(); void flush_presort(); -<<<<<<< HEAD void getfilename_sorted(const uint16_t nr); -======= - void getfilename_sorted(const uint8_t nr); ->>>>>>> SD Card Alpha Sorting #endif @@ -64,37 +60,22 @@ public: public: bool saving; bool logging; -<<<<<<< HEAD bool sdprinting; bool cardOK; char filename[FILENAME_LENGTH]; char longFilename[LONG_FILENAME_LENGTH]; -======= - bool sdprinting ; - bool cardOK; - char filename[FILENAME_LENGTH]; - char diveFilename[LONG_FILENAME_LENGTH]; ->>>>>>> SD Card Alpha Sorting 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 -<<<<<<< HEAD uint16_t sort_count; uint8_t *sort_order; #if SORT_USES_MORE_RAM char **sortshort; char **sortnames; uint8_t *isDir; -======= - #if SORT_USES_MORE_RAM - uint16_t sort_count; - char **sortnames; - #else - uint8_t sort_order[SORT_LIMIT]; ->>>>>>> SD Card Alpha Sorting #endif #endif Sd2Card card; From c9486ebb8558e8863bb59209dc039d8ca3c458dd Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 26 Nov 2014 07:17:47 -0800 Subject: [PATCH 19/24] 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 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index c02b35403..cf0b5176a 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, diveFilename) > 0) + while (parent.readDir(p, longFilename) > 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 (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] != '.') From a12eec33e2fd5dccbfa8e2631ab3a274a177e81b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 30 Nov 2014 21:28:16 -0800 Subject: [PATCH 20/24] 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 cf0b5176a..c02b35403 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 6599adc184b9561777159397c0f477549070ccba Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 6 Dec 2014 03:40:39 -0800 Subject: [PATCH 21/24] 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 219bebf23..b916d9297 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -292,7 +292,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 fd8635a5b..f3af6da5b 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 7a01bccb6..199809200 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 ee42481be..3c2eecacf 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 7883c7999..7151459d0 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 29e854c535c4e1a25e365acf1a028983390b04e1 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 6 Dec 2014 04:16:45 -0800 Subject: [PATCH 22/24] 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 b916d9297..d0f988c17 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -292,7 +292,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 199809200..10fbe9b31 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 3c2eecacf..6c9d56886 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 7151459d0..312b2b964 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: From 1fad8e6a8123419bfe10ce7a65211e56e4f2c926 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 13 Dec 2014 06:17:00 -0800 Subject: [PATCH 23/24] Proper long file name var --- Marlin/cardreader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index c02b35403..cf0b5176a 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, diveFilename) > 0) + while (parent.readDir(p, longFilename) > 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 (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] != '.') From d088b5f30f2951bb47afe6c693c9e51fc98210cd Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 13 Dec 2014 06:33:12 -0800 Subject: [PATCH 24/24] Remove debug echo --- Marlin/cardreader.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp index cf0b5176a..57a91040b 100644 --- a/Marlin/cardreader.cpp +++ b/Marlin/cardreader.cpp @@ -715,9 +715,6 @@ void CardReader::presort() #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;