Browse Source

Merge pull request #2405 from leptun/MK3_NEW_SD_COMPILATION

⚡️New SD menu
DRracer 3 years ago
parent
commit
c1849f5cc2

+ 3 - 13
Firmware/Configuration_adv.h

@@ -231,33 +231,23 @@
 * SD sorting uses static allocation (as set by SDSORT_LIMIT), allowing the
 * compiler to calculate the worst-case usage and throw an error if the SRAM
 * limit is exceeded.
-*
-*  - SDSORT_USES_RAM provides faster sorting via a static directory buffer.
-*  - SDSORT_USES_STACK does the same, but uses a local stack-based buffer.
-*  - SDSORT_CACHE_NAMES will retain the sorted file listing in RAM. (Expensive!)
-*  - SDSORT_DYNAMIC_RAM only uses RAM when the SD menu is visible. (Use with caution!)
 */
 	#define SDCARD_SORT_ALPHA //Alphabetical sorting of SD files menu
 	
 	// SD Card Sorting options
-	// In current firmware Prusa Firmware version,
-	// SDSORT_CACHE_NAMES and SDSORT_DYNAMIC_RAM is not supported and must be set to 0.
 	#ifdef SDCARD_SORT_ALPHA
 	  #define SD_SORT_TIME 0
 	  #define SD_SORT_ALPHA 1
 	  #define SD_SORT_NONE 2
+	  // #define SHELLSORT
+	  // #define SORTING_DUMP
 	
 	  #define SDSORT_LIMIT       100    // Maximum number of sorted items (10-256).
 	  #define FOLDER_SORTING     -1     // -1=above  0=none  1=below
-	  #define SDSORT_GCODE       0  // Allow turning sorting on/off with LCD and M34 g-code.
-	  #define SDSORT_USES_RAM    0  // Pre-allocate a static array for faster pre-sorting.
-	  #define SDSORT_USES_STACK  0  // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.)
-	  #define SDSORT_CACHE_NAMES 0  // Keep sorted items in RAM longer for speedy performance. Most expensive option.
-	  #define SDSORT_DYNAMIC_RAM 0  // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use!
 	#endif
 	
 	#if defined(SDCARD_SORT_ALPHA)
-	  #define HAS_FOLDER_SORTING (FOLDER_SORTING || SDSORT_GCODE)
+	  #define HAS_FOLDER_SORTING (FOLDER_SORTING)
 	#endif
 
 // Enable the option to stop SD printing when hitting and endstops, needs to be enabled from the LCD menu when this option is enabled.

+ 7 - 22
Firmware/Marlin_main.cpp

@@ -766,31 +766,16 @@ static void factory_reset(char level)
 #endif //FILAMENT_SENSOR
 		break;
 
-	case 3:{ // Level 3: erase everything, whole EEPROM will be set to 0xFF
-		lcd_puts_P(PSTR("Factory RESET"));
-		lcd_puts_at_P(1, 2, PSTR("ERASING all data"));
-		uint16_t er_progress = 0;
-		lcd_set_cursor(3, 3);
-		lcd_space(6);
-		lcd_set_cursor(3, 3);
-		lcd_print(er_progress);
-
+	case 3:
+		menu_progressbar_init(EEPROM_TOP, PSTR("ERASING all data"));
 		// Erase EEPROM
-		for (uint16_t i = 0; i < 4096; i++) {
+		for (uint16_t i = 0; i < EEPROM_TOP; i++) {
 			eeprom_update_byte((uint8_t*)i, 0xFF);
-
-			if (i % 41 == 0) {
-				er_progress++;
-				lcd_set_cursor(3, 3);
-				lcd_space(6);
-				lcd_set_cursor(3, 3);
-				lcd_print(er_progress);
-				lcd_puts_P(PSTR("%"));
-			}
-
+			menu_progressbar_update(i);
 		}
+		menu_progressbar_finish();
 		softReset();
-		}break;
+		break;
 
 
 #ifdef SNMM
@@ -11272,7 +11257,7 @@ void restore_print_from_eeprom(bool mbl_was_active) {
 		}
 		dir_name[8] = '\0';
 		MYSERIAL.println(dir_name);
-		// strcpy(dir_names[i], dir_name);
+		// strcpy(card.dir_names[i], dir_name);
 		card.chdir(dir_name, false);
 	}
 

+ 175 - 189
Firmware/cardreader.cpp

@@ -15,11 +15,6 @@ CardReader::CardReader()
 
    #ifdef SDCARD_SORT_ALPHA
      sort_count = 0;
-     #if SDSORT_GCODE
-       sort_alpha = true;
-     sort_folders = FOLDER_SORTING;
-     //sort_reverse = false;
-     #endif
    #endif
 
    filesize = 0;
@@ -82,7 +77,7 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
 	dir_t p;
 	uint8_t cnt = 0;
 		// Read the next entry from a directory
-		while (parent.readDir(p, longFilename) > 0) {
+		for (position = parent.curPosition(); parent.readDir(p, longFilename) > 0; position = parent.curPosition()) {
 			if (recursionCnt > MAX_DIR_DEPTH)
 				return;
 			else if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { // If the entry is a directory and the action is LS_SerialPrint
@@ -149,10 +144,10 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
 						break;
 				
 					case LS_GetFilename:
-						//SERIAL_ECHOPGM("File: ");				
+						//SERIAL_ECHOPGM("File: ");
 						createFilename(filename, p);
-						cluster = parent.curCluster();
-						position = parent.curPosition();
+						// cluster = parent.curCluster();
+						// position = parent.curPosition();
 						/*MYSERIAL.println(filename);
 						SERIAL_ECHOPGM("Write date: ");
 						writeDate = p.lastWriteDate;
@@ -397,7 +392,7 @@ static const char ofNowFreshFile[] PROGMEM = "Now fresh file: ";
 static const char ofFileOpened[] PROGMEM = "File opened: ";
 static const char ofSize[] PROGMEM = " Size: ";
 static const char ofFileSelected[] PROGMEM = "File selected";
-static const char ofSDPrinting[] PROGMEM = "SD-PRINTING         ";
+static const char ofSDPrinting[] PROGMEM = "SD-PRINTING";
 static const char ofWritingToFile[] PROGMEM = "Writing to file: ";
 
 void CardReader::openFileReadFilteredGcode(const char* name, bool replace_current/* = false*/){
@@ -446,17 +441,17 @@ void CardReader::openFileReadFilteredGcode(const char* name, bool replace_curren
       return;
   
     if (file.openFilteredGcode(curDir, fname)) {
+        getfilename(0, fname);
         filesize = file.fileSize();
         SERIAL_PROTOCOLRPGM(ofFileOpened);////MSG_SD_FILE_OPENED
-        SERIAL_PROTOCOL(fname);
+        printAbsFilenameFast();
         SERIAL_PROTOCOLRPGM(ofSize);////MSG_SD_SIZE
         SERIAL_PROTOCOLLN(filesize);
         sdpos = 0;
         
         SERIAL_PROTOCOLLNRPGM(ofFileSelected);////MSG_SD_FILE_SELECTED
-        getfilename(0, fname);
-        lcd_setstatus(longFilename[0] ? longFilename : fname);
-        lcd_setstatuspgm(ofSDPrinting);
+        lcd_setstatuspgm(ofFileSelected);
+        scrollstuff = 0;
       } else {
         SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL);
         SERIAL_PROTOCOL(fname);
@@ -517,9 +512,14 @@ void CardReader::openFileWrite(const char* name)
         SERIAL_PROTOCOLLN('.');
     } else {
         saving = true;
+        getfilename(0, fname);
         SERIAL_PROTOCOLRPGM(ofWritingToFile);////MSG_SD_WRITE_TO_FILE
-        SERIAL_PROTOCOLLN(fname);
-        lcd_setstatus(fname);
+        printAbsFilenameFast();
+        SERIAL_PROTOCOLLN();
+        
+        SERIAL_PROTOCOLLNRPGM(ofFileSelected);////MSG_SD_FILE_SELECTED
+        lcd_setstatuspgm(ofFileSelected);
+        scrollstuff = 0;
     }
 }
 
@@ -711,6 +711,15 @@ void CardReader::getfilename_simple(uint32_t position, const char * const match/
 	lsDive("", *curDir, match);
 }
 
+void CardReader::getfilename_next(uint32_t position, const char * const match/*=NULL*/)
+{
+	curDir = &workDir;
+	lsAction = LS_GetFilename;
+	nrFiles = 1;
+	curDir->seekSet(position);
+	lsDive("", *curDir, match);
+}
+
 uint16_t CardReader::getnrfilenames()
 {
   curDir=&workDir;
@@ -780,13 +789,11 @@ void CardReader::updir()
 /**
 * Get the name of a file in the current directory by sort-index
 */
-void CardReader::getfilename_sorted(const uint16_t nr) {
-	getfilename(
-	#if SDSORT_GCODE
-		sort_alpha &&
-	#endif
-		(nr < sort_count) ? sort_order[nr] : nr
-	);
+void CardReader::getfilename_sorted(const uint16_t nr, uint8_t sdSort) {
+    if (nr < sort_count)
+        getfilename_simple(sort_positions[(sdSort == SD_SORT_ALPHA) ? (sort_count - nr - 1) : nr]);
+    else
+        getfilename(nr);
 }
 
 /**
@@ -803,9 +810,6 @@ void CardReader::presort() {
 
 	if (sdSort == SD_SORT_NONE) return; //sd sort is turned off
 
-	#if SDSORT_GCODE
-	if (!sort_alpha) return;
-	#endif
 	KEEPALIVE_STATE(IN_HANDLER);
 
 	// Throw away old sort index
@@ -821,177 +825,170 @@ void CardReader::presort() {
 			lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=6
 			fileCnt = SDSORT_LIMIT;
 		}
-		lcd_clear();
-		#if !SDSORT_USES_RAM
-			lcd_set_progress();
-		#endif
-		lcd_puts_at_P(0, 1, _i("Sorting files"));////MSG_SORTING c=20 r=1
-
-		// Sort order is always needed. May be static or dynamic.
-		#if SDSORT_DYNAMIC_RAM
-		sort_order = new uint8_t[fileCnt];
-		#endif
-
-		// Use RAM to store the entire directory during pre-sort.
-		// SDSORT_LIMIT should be set to prevent over-allocation.
-		#if SDSORT_USES_RAM
-
-		// If using dynamic ram for names, allocate on the heap.
-		#if SDSORT_CACHE_NAMES
-		#if SDSORT_DYNAMIC_RAM
-		sortshort = new char*[fileCnt];
-		sortnames = new char*[fileCnt];
-		#endif
-		#elif SDSORT_USES_STACK
-		char sortnames[fileCnt][LONG_FILENAME_LENGTH];
-		uint16_t modification_time[fileCnt];
-		uint16_t modification_date[fileCnt];
-		#endif
-
-		// Folder sorting needs 1 bit per entry for flags.
-		#if HAS_FOLDER_SORTING
-		#if SDSORT_DYNAMIC_RAM
-		isDir = new uint8_t[(fileCnt + 7) >> 3];
-		#elif SDSORT_USES_STACK
-		uint8_t isDir[(fileCnt + 7) >> 3];
-		#endif
-		#endif
-
-		#else // !SDSORT_USES_RAM
-
-		uint32_t positions[fileCnt];
 
 		// By default re-read the names from SD for every compare
 		// retaining only two filenames at a time. This is very
 		// slow but is safest and uses minimal RAM.
-		char name1[LONG_FILENAME_LENGTH + 1];
+		char name1[LONG_FILENAME_LENGTH];
 		uint16_t crmod_time_bckp;
 		uint16_t crmod_date_bckp;
 
+		#if HAS_FOLDER_SORTING
+		uint16_t dirCnt = 0;
 		#endif
-		position = 0;
+
 		if (fileCnt > 1) {
 			// Init sort order.
+			uint8_t sort_order[fileCnt];
 			for (uint16_t i = 0; i < fileCnt; i++) {
 				if (!IS_SD_INSERTED) return;
 				manage_heater();
+				if (i == 0)
+					getfilename(0);
+				else
+					getfilename_next(position);
 				sort_order[i] = i;
-				positions[i] = position;
-				getfilename(i);
-				// If using RAM then read all filenames now.
-				#if SDSORT_USES_RAM
-				getfilename(i);
-				#if SDSORT_DYNAMIC_RAM
-				// Use dynamic method to copy long filename
-				sortnames[i] = strdup(LONGEST_FILENAME);
-				#if SDSORT_CACHE_NAMES
-				// When caching also store the short name, since
-				// we're replacing the getfilename() behavior.
-				sortshort[i] = strdup(filename);
-				#endif
-				#else
-				// Copy filenames into the static array
-				strcpy(sortnames[i], LONGEST_FILENAME);
-				modification_time[i] = crmodTime;
-				modification_date[i] = crmodDate;
-				#if SDSORT_CACHE_NAMES
-				strcpy(sortshort[i], filename);
-				#endif
-				#endif
-				// char out[30];
-				// sprintf_P(out, PSTR("---- %i %s %s"), i, filenameIsDir ? "D" : " ", sortnames[i]);
-				// SERIAL_ECHOLN(out);
+				sort_positions[i] = position;
 				#if HAS_FOLDER_SORTING
-				const uint16_t bit = i & 0x07, ind = i >> 3;
-				if (bit == 0) isDir[ind] = 0x00;
-				if (filenameIsDir) isDir[ind] |= _BV(bit);
-				#endif
+				if (filenameIsDir) dirCnt++;
 				#endif
 			}
 
 #ifdef QUICKSORT
 			quicksort(0, fileCnt - 1);
-#else //Qicksort not defined, use Bubble Sort
-			uint32_t counter = 0;
-			uint16_t total = 0.5*(fileCnt - 1)*(fileCnt);
-
-			// Compare names from the array or just the two buffered names
-			#if SDSORT_USES_RAM
-			#define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0)
-			#define _SORT_CMP_TIME_NODIR() (((modification_date[o1] == modification_date[o2]) && (modification_time[o1] < modification_time[o2])) || \
-																	(modification_date[o1] < modification_date [o2]))
-			#else
-			#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0) //true if lowercase(name1) > lowercase(name2)
-			#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp > crmodTime)) || \
-																	(crmod_date_bckp > crmodDate))
+#elif defined(SHELLSORT)
 
-			#endif
+#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2)
+#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp < crmodTime)) || (crmod_date_bckp < crmodDate))
 
-			#if HAS_FOLDER_SORTING
-			#if SDSORT_USES_RAM
-			// Folder sorting needs an index and bit to test for folder-ness.
-			const uint8_t ind1 = o1 >> 3, bit1 = o1 & 0x07,
-				ind2 = o2 >> 3, bit2 = o2 & 0x07;
-			#define _SORT_CMP_DIR(fs) \
-										  (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \
-											? _SORT_CMP_NODIR() \
-											: (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0)
-			#define _SORT_CMP_TIME_DIR(fs) \
-										  (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \
-											? _SORT_CMP_TIME_NODIR() \
-											: (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0)
-			#else
-			#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
-			#define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
-			#endif
-			#endif
+#if HAS_FOLDER_SORTING
+#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs < 0 ? dir1 : !dir1))
+#define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
+#endif
+
+			for (uint8_t runs = 0; runs < 2; runs++)
+			{
+				//run=0: sorts all files and moves folders to the beginning
+				//run=1: assumes all folders are at the beginning of the list and sorts them
+				uint16_t sortCountFiles = 0;
+				if (runs == 0)
+				{
+					sortCountFiles = fileCnt;
+				}
+				#if HAS_FOLDER_SORTING
+				else
+				{
+					sortCountFiles = dirCnt;
+				}
+				#endif
+				
+				uint16_t counter = 0;
+				uint16_t total = 0;
+				for (uint16_t i = sortCountFiles/2; i > 0; i /= 2) total += sortCountFiles - i; //total runs for progress bar
+				menu_progressbar_init(total, (runs == 0)?_i("Sorting files"):_i("Sorting folders"));
+				
+				for (uint16_t gap = sortCountFiles/2; gap > 0; gap /= 2)
+				{
+					for (uint16_t i = gap; i < sortCountFiles; i++)
+					{
+						if (!IS_SD_INSERTED) return;
+						
+						menu_progressbar_update(counter);
+						counter++;
+						
+						manage_heater();
+						uint8_t orderBckp = sort_order[i];
+						getfilename_simple(sort_positions[orderBckp]);
+						strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
+						crmod_date_bckp = crmodDate;
+						crmod_time_bckp = crmodTime;
+						#if HAS_FOLDER_SORTING
+						bool dir1 = filenameIsDir;
+						#endif
+						
+						uint16_t j = i;
+						getfilename_simple(sort_positions[sort_order[j - gap]]);
+						char *name2 = LONGEST_FILENAME; // use the string in-place
+						#if HAS_FOLDER_SORTING
+						while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_DIR(FOLDER_SORTING):_SORT_CMP_DIR(FOLDER_SORTING)))
+						#else
+						while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_NODIR():_SORT_CMP_NODIR()))
+						#endif
+						{
+							sort_order[j] = sort_order[j - gap];
+							j -= gap;
+							#ifdef SORTING_DUMP
+							for (uint16_t z = 0; z < sortCountFiles; z++)
+							{
+								printf_P(PSTR("%2u "), sort_order[z]);
+							}
+							printf_P(PSTR("i%2d j%2d gap%2d orderBckp%2d\n"), i, j, gap, orderBckp);
+							#endif
+							if (j < gap) break;
+							getfilename_simple(sort_positions[sort_order[j - gap]]);
+							name2 = LONGEST_FILENAME; // use the string in-place
+						}
+						sort_order[j] = orderBckp;
+					}
+				}
+			}
+
+#else //Bubble Sort
+
+#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2)
+#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp > crmodTime)) || (crmod_date_bckp > crmodDate))
+
+#if HAS_FOLDER_SORTING
+#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs < 0 ? dir1 : !dir1))
+#define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
+#endif
+
+			uint16_t counter = 0;
+			menu_progressbar_init(0.5*(fileCnt - 1)*(fileCnt), _i("Sorting files"));
 
 			for (uint16_t i = fileCnt; --i;) {
 				if (!IS_SD_INSERTED) return;
 				bool didSwap = false;
 
-				#if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used
-				int8_t percent = (counter * 100) / total;//((counter * 100) / pow((fileCnt-1),2));
-				for (int column = 0; column < 20; column++) {
-					if (column < (percent / 5))
-					{
-						lcd_putc_at(column, 2, '\x01'); //simple progress bar
-					}
-				}
+				menu_progressbar_update(counter);
 				counter++;
-				#endif
 
-				//MYSERIAL.println(int(i));
 				for (uint16_t j = 0; j < i; ++j) {
 					if (!IS_SD_INSERTED) return;
+					#ifdef SORTING_DUMP
+					for (uint16_t z = 0; z < fileCnt; z++)
+					{
+						printf_P(PSTR("%2u "), sort_order[z]);
+					}
+					MYSERIAL.println();
+					#endif
 					manage_heater();
 					const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1];
 
-					// The most economical method reads names as-needed
-					// throughout the loop. Slow if there are many.
-					#if !SDSORT_USES_RAM
 					counter++;
-					getfilename_simple(positions[o1]);
+					getfilename_simple(sort_positions[o1]);
 					strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
 					crmod_date_bckp = crmodDate;
 					crmod_time_bckp = crmodTime;
 					#if HAS_FOLDER_SORTING
 					bool dir1 = filenameIsDir;
 					#endif
-					getfilename_simple(positions[o2]);
+					getfilename_simple(sort_positions[o2]);
 					char *name2 = LONGEST_FILENAME; // use the string in-place
 
-					#endif // !SDSORT_USES_RAM
-
 													// Sort the current pair according to settings.
 					if (
 					#if HAS_FOLDER_SORTING
-					(sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_DIR(FOLDER_SORTING))
+						(sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_DIR(FOLDER_SORTING))
 					#else
-						(sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_NODIR())
+						(sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_NODIR())
 					#endif
 						)
 					{
+						#ifdef SORTING_DUMP
+						puts_P(PSTR("swap"));
+						#endif
+						
 						sort_order[j] = o2;
 						sort_order[j + 1] = o1;
 						didSwap = true;
@@ -1000,45 +997,45 @@ void CardReader::presort() {
 				if (!didSwap) break;
 			} //end of bubble sort loop
 #endif
-			  // Using RAM but not keeping names around
-			#if (SDSORT_USES_RAM && !SDSORT_CACHE_NAMES)
-			#if SDSORT_DYNAMIC_RAM
-			for (uint16_t i = 0; i < fileCnt; ++i) free(sortnames[i]);
-			#if HAS_FOLDER_SORTING
-			free(isDir);
-			#endif
-			#endif
+
+			#ifdef SORTING_DUMP
+			for (uint16_t z = 0; z < fileCnt; z++)
+				printf_P(PSTR("%2u "), sort_order[z]);
+			SERIAL_PROTOCOLLN();
 			#endif
+
+			uint8_t sort_order_reverse_index[fileCnt];
+			for (uint8_t i = 0; i < fileCnt; i++)
+				sort_order_reverse_index[sort_order[i]] = i;
+			for (uint8_t i = 0; i < fileCnt; i++)
+			{
+				if (sort_order_reverse_index[i] != i)
+				{
+					uint32_t el = sort_positions[i];
+					uint8_t idx = sort_order_reverse_index[i];
+					while (idx != i)
+					{
+						uint32_t el1 = sort_positions[idx];
+						uint8_t idx1 = sort_order_reverse_index[idx];
+						sort_order_reverse_index[idx] = idx;
+						sort_positions[idx] = el;
+						idx = idx1;
+						el = el1;
+					}
+					sort_order_reverse_index[idx] = idx;
+					sort_positions[idx] = el;
+				}
+			}
+			menu_progressbar_finish();
 		}
 		else {
-			sort_order[0] = 0;
-		#if (SDSORT_USES_RAM && SDSORT_CACHE_NAMES)
 			getfilename(0);
-			#if SDSORT_DYNAMIC_RAM
-			sortnames = new char*[1];
-			sortnames[0] = strdup(LONGEST_FILENAME); // malloc
-			sortshort = new char*[1];
-			sortshort[0] = strdup(filename);         // malloc
-			isDir = new uint8_t[1];
-			#else
-			strcpy(sortnames[0], LONGEST_FILENAME);
-			strcpy(sortshort[0], filename);
-			#endif
-			isDir[0] = filenameIsDir ? 0x01 : 0x00;
-		#endif
+			sort_positions[0] = position;
 		}
 
 		sort_count = fileCnt;
 	}
-#if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used
-	for (int column = 0; column <= 19; column++)
-	{
-		lcd_putc_at(column, 2, '\x01'); //simple progress bar
-	}
-	_delay(300);
-	lcd_set_degree();
-	lcd_clear();
-#endif
+
 	lcd_update(2);
 	KEEPALIVE_STATE(NOT_BUSY);
 	lcd_timeoutToStatus.start();
@@ -1046,17 +1043,6 @@ void CardReader::presort() {
 
 void CardReader::flush_presort() {
 	if (sort_count > 0) {
-		#if SDSORT_DYNAMIC_RAM
-		delete sort_order;
-		#if SDSORT_CACHE_NAMES
-		for (uint8_t i = 0; i < sort_count; ++i) {
-			free(sortshort[i]); // strdup
-			free(sortnames[i]); // strdup
-		}
-		delete sortshort;
-		delete sortnames;
-		#endif
-		#endif
 		sort_count = 0;
 	}
 }

+ 4 - 46
Firmware/cardreader.h

@@ -34,6 +34,7 @@ public:
 
   void getfilename(uint16_t nr, const char* const match=NULL);
   void getfilename_simple(uint32_t position, const char * const match = NULL);
+  void getfilename_next(uint32_t position, const char * const match = NULL);
   uint16_t getnrfilenames();
   
   void getAbsFilename(char *t);
@@ -53,12 +54,7 @@ public:
 		void swap(uint8_t left, uint8_t right);
 		void quicksort(uint8_t left, uint8_t right);
 	 #endif //SDSORT_QUICKSORT
-     void getfilename_sorted(const uint16_t nr);
-     #if SDSORT_GCODE
-	 FORCE_INLINE void setSortOn(bool b) { sort_alpha = b; presort(); }
-     FORCE_INLINE void setSortFolders(int i) { sort_folders = i; presort(); }
-     //FORCE_INLINE void setSortReverse(bool b) { sort_reverse = b; }
-	 #endif
+     void getfilename_sorted(const uint16_t nr, uint8_t sdSort);
   #endif
 
   FORCE_INLINE bool isFileOpen() { return file.isOpen(); }
@@ -84,7 +80,7 @@ public:
   // There are scenarios when simple modification time is not enough (on MS Windows)
   // Therefore these timestamps hold the most recent one of creation/modification date/times
   uint16_t crmodTime, crmodDate;
-  uint32_t cluster, position;
+  uint32_t /* cluster, */ position;
   char longFilename[LONG_FILENAME_LENGTH];
   bool filenameIsDir;
   int lastnr; //last number of the autostart;
@@ -99,45 +95,7 @@ private:
   // Sort files and folders alphabetically.
 #ifdef SDCARD_SORT_ALPHA
   uint16_t sort_count;        // Count of sorted items in the current directory
-  #if SDSORT_GCODE
-  bool sort_alpha;          // Flag to enable / disable the feature
-  int sort_folders;         // Flag to enable / disable folder sorting
-							//bool sort_reverse;      // Flag to enable / disable reverse sorting
-  #endif
-
-							// By default the sort index is static
-  #if SDSORT_DYNAMIC_RAM
-  uint8_t *sort_order;
-  #else
-  uint8_t sort_order[SDSORT_LIMIT];
-  #endif
-  // Cache filenames to speed up SD menus.
-  #if SDSORT_USES_RAM
-
-  // If using dynamic ram for names, allocate on the heap.
-  #if SDSORT_CACHE_NAMES
-    #if SDSORT_DYNAMIC_RAM
-      char **sortshort, **sortnames;
-    #else
-      char sortshort[SDSORT_LIMIT][FILENAME_LENGTH];
-      char sortnames[SDSORT_LIMIT][FILENAME_LENGTH];
-    #endif
-  #elif !SDSORT_USES_STACK
-    char sortnames[SDSORT_LIMIT][FILENAME_LENGTH];
-    uint16_t modification_time[SDSORT_LIMIT];
-    uint16_t modification_date[SDSORT_LIMIT];
-  #endif
-
-  // Folder sorting uses an isDir array when caching items.
-  #if HAS_FOLDER_SORTING
-    #if SDSORT_DYNAMIC_RAM
-      uint8_t *isDir;
-    #elif (SDSORT_CACHE_NAMES) || !(SDSORT_USES_STACK)
-      uint8_t isDir[(SDSORT_LIMIT + 7) >> 3];
-    #endif
-  #endif
-
-  #endif // SDSORT_USES_RAM
+  uint32_t sort_positions[SDSORT_LIMIT];
 
 #endif // SDCARD_SORT_ALPHA
 

+ 0 - 15
Firmware/lcd.cpp

@@ -963,21 +963,6 @@ void lcd_set_custom_characters_arrows(void)
 	lcd_createChar_P(1, lcd_chardata_arrdown);
 }
 
-const uint8_t lcd_chardata_progress[8] PROGMEM = {
-	B11111,
-	B11111,
-	B11111,
-	B11111,
-	B11111,
-	B11111,
-	B11111,
-	B11111};
-
-void lcd_set_custom_characters_progress(void)
-{
-	lcd_createChar_P(1, lcd_chardata_progress);
-}
-
 const uint8_t lcd_chardata_arr2down[8] PROGMEM = {
 	B00000,
 	B00000,

+ 0 - 1
Firmware/lcd.h

@@ -204,7 +204,6 @@ private:
 
 extern void lcd_set_custom_characters(void);
 extern void lcd_set_custom_characters_arrows(void);
-extern void lcd_set_custom_characters_progress(void);
 extern void lcd_set_custom_characters_nextpage(void);
 extern void lcd_set_custom_characters_degree(void);
 

+ 41 - 10
Firmware/menu.cpp

@@ -34,33 +34,35 @@ uint8_t menu_top = 0;
 
 uint8_t menu_clicked = 0;
 
-uint8_t menu_entering = 0;
 uint8_t menu_leaving = 0;
 
 menu_func_t menu_menu = 0;
 
 static_assert(sizeof(menu_data)>= sizeof(menu_data_edit_t),"menu_data_edit_t doesn't fit into menu_data");
 
+void menu_data_reset(void)
+{
+	// Resets the global shared C union.
+	// This ensures, that the menu entered will find out, that it shall initialize itself.
+	memset(&menu_data, 0, sizeof(menu_data));
+}
 
 void menu_goto(menu_func_t menu, const uint32_t encoder, const bool feedback, bool reset_menu_state)
 {
-	asm("cli");
+	CRITICAL_SECTION_START;
 	if (menu_menu != menu)
 	{
 		menu_menu = menu;
 		lcd_encoder = encoder;
 		menu_top = 0; //reset menu view. Needed if menu_back() is called from deep inside a menu, such as Support
-		asm("sei");
+		CRITICAL_SECTION_END;
 		if (reset_menu_state)
-		{
-			// Resets the global shared C union.
-			// This ensures, that the menu entered will find out, that it shall initialize itself.
-			memset(&menu_data, 0, sizeof(menu_data));
-		}
+			menu_data_reset();
+
 		if (feedback) lcd_quick_feedback();
 	}
 	else
-		asm("sei");
+		CRITICAL_SECTION_END;
 }
 
 void menu_start(void)
@@ -551,4 +553,33 @@ uint8_t menu_item_edit_P(const char* str, T pval, int16_t min_val, int16_t max_v
 template uint8_t menu_item_edit_P<int16_t*>(const char* str, int16_t *pval, int16_t min_val, int16_t max_val);
 template uint8_t menu_item_edit_P<uint8_t*>(const char* str, uint8_t *pval, int16_t min_val, int16_t max_val);
 
-#undef _menu_data
+static uint8_t progressbar_block_count = 0;
+static uint16_t progressbar_total = 0;
+void menu_progressbar_init(uint16_t total, const char* title)
+{
+	lcd_clear();
+	progressbar_block_count = 0;
+	progressbar_total = total;
+	
+	lcd_set_cursor(0, 1);
+	lcd_printf_P(PSTR("%-20.20S\n"), title);
+}
+
+void menu_progressbar_update(uint16_t newVal)
+{
+	uint8_t newCnt = (newVal * LCD_WIDTH) / progressbar_total;
+	if (newCnt > LCD_WIDTH)
+		newCnt = LCD_WIDTH;
+	while (newCnt > progressbar_block_count)
+	{
+		lcd_print('\xFF');
+		progressbar_block_count++;
+	}
+}
+
+void menu_progressbar_finish(void)
+{
+	progressbar_total = 1;
+	menu_progressbar_update(1);
+	_delay(300);
+}

+ 4 - 2
Firmware/menu.h

@@ -59,13 +59,12 @@ extern uint8_t menu_top;
 
 extern uint8_t menu_clicked;
 
-extern uint8_t menu_entering;
 extern uint8_t menu_leaving;
 
 //function pointer to the currently active menu
 extern menu_func_t menu_menu;
 
-
+extern void menu_data_reset(void);
 
 extern void menu_goto(menu_func_t menu, const uint32_t encoder, const bool feedback, bool reset_menu_state);
 
@@ -151,5 +150,8 @@ extern void menu_format_sheet_E(const Sheet &sheet_E, SheetFormatBuffer &buffer)
 template <typename T>
 extern uint8_t menu_item_edit_P(const char* str, T pval, int16_t min_val, int16_t max_val);
 
+extern void menu_progressbar_init(uint16_t total, const char* title);
+extern void menu_progressbar_update(uint16_t newVal);
+extern void menu_progressbar_finish(void);
 
 #endif //_MENU_H

+ 1 - 2
Firmware/messages.c

@@ -80,7 +80,7 @@ const char MSG_PRESS_TO_UNLOAD[] PROGMEM_I1 = ISTR("Please press the knob to unl
 const char MSG_PRINT_ABORTED[] PROGMEM_I1 = ISTR("Print aborted"); ////c=20
 const char MSG_PULL_OUT_FILAMENT[] PROGMEM_I1 = ISTR("Please pull out filament immediately"); ////c=20 r=4
 const char MSG_RECOVER_PRINT[] PROGMEM_I1 = ISTR("Blackout occurred. Recover print?"); ////c=20 r=2
-const char MSG_REFRESH[] PROGMEM_I1 = ISTR("\xF8" "Refresh"); ////
+const char MSG_REFRESH[] PROGMEM_I1 = ISTR("\x04" "Refresh"); ////
 const char MSG_REMOVE_STEEL_SHEET[] PROGMEM_I1 = ISTR("Please remove steel sheet from heatbed."); ////c=20 r=4
 const char MSG_RESET[] PROGMEM_I1 = ISTR("Reset"); ////c=14
 const char MSG_RESUME_PRINT[] PROGMEM_I1 = ISTR("Resume print"); ////c=18
@@ -203,4 +203,3 @@ const char MSG_M112_KILL[] PROGMEM_N1 = "M112 called. Emergency Stop."; ////c=20
 const char MSG_ADVANCE_K[] PROGMEM_N1 = "Advance K:"; ////c=13
 const char MSG_POWERPANIC_DETECTED[] PROGMEM_N1 = "POWER PANIC DETECTED"; ////c=20
 const char MSG_LCD_STATUS_CHANGED[] PROGMEM_N1 = "LCD status changed";
-const char MSG_FILE_SELECTED[] PROGMEM_N1 = "File selected"; ////c=20

+ 0 - 1
Firmware/messages.h

@@ -203,7 +203,6 @@ extern const char MSG_M112_KILL[];
 extern const char MSG_ADVANCE_K[];
 extern const char MSG_POWERPANIC_DETECTED[];
 extern const char MSG_LCD_STATUS_CHANGED[];
-extern const char MSG_FILE_SELECTED[];
 
 #if defined(__cplusplus)
 }

+ 185 - 265
Firmware/ultralcd.cpp

@@ -55,8 +55,6 @@
 #endif
 
 
-int scrollstuff = 0;
-char longFilenameOLD[LONG_FILENAME_LENGTH];
 int clock_interval = 0;
 
 static void lcd_sd_updir();
@@ -64,7 +62,7 @@ static void lcd_mesh_bed_leveling_settings();
 static void lcd_backlight_menu();
 
 int8_t ReInitLCD = 0;
-
+uint8_t scrollstuff = 0;
 
 int8_t SilentModeMenu = SILENT_MODE_OFF;
 uint8_t SilentModeMenu_MMU = 1; //activate mmu unit stealth mode
@@ -326,113 +324,31 @@ bool bSettings;                                   // flag (i.e. 'fake parameter'
 
 const char STR_SEPARATOR[] PROGMEM = "------------";
 
-
-static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char* filename, char* longFilename)
-{
-    char c;
-    int enc_dif = lcd_encoder_diff / ENCODER_PULSES_PER_STEP;
-    uint8_t n = LCD_WIDTH - 1;
-
-    for(uint_least8_t g = 0; g<4;g++){
-      lcd_putc_at(0, g, ' ');
-    }
-    lcd_putc_at(0, row, '>');
-
-    if (longFilename[0] == '\0')
-    {
-        longFilename = filename;
-    }
-
-    int i = 1;
-    int j = 0;
-    char* longFilenameTMP = longFilename;
-
-    while((c = *longFilenameTMP) != '\0')
-    {
-        lcd_set_cursor(i, row);
-        lcd_print(c);
-        i++;
-        longFilenameTMP++;
-        if(i==LCD_WIDTH){
-          i=1;
-          j++;
-          longFilenameTMP = longFilename + j;          
-          n = LCD_WIDTH - 1;
-          for(int g = 0; g<300 ;g++){
-			  manage_heater();
-            if(LCD_CLICKED || ( enc_dif != (lcd_encoder_diff / ENCODER_PULSES_PER_STEP))){
-				longFilenameTMP = longFilename;
-				*(longFilenameTMP + LCD_WIDTH - 2) = '\0';
-				i = 1;
-				j = 0;
-				break;
-            }else{
-				if (j == 1) _delay_ms(3);	//wait around 1.2 s to start scrolling text
-				_delay_ms(1);				//then scroll with redrawing every 300 ms 
-            }
-
-          }
-        }
-    }
-    if(c!='\0'){
-        lcd_putc_at(i, row, c);
-        i++;
-    }
-    n=n-i+1;
-    lcd_space(n);
-}
-static void lcd_implementation_drawmenu_sdfile(uint8_t row, const char* filename, char* longFilename)
+static void lcd_implementation_drawmenu_sdfile(uint8_t row, const char* longFilename)
 {
     char c;
     uint8_t n = LCD_WIDTH - 1;
-    lcd_putc_at(0, row, ' ');
-    if (longFilename[0] != '\0')
-    {
-        filename = longFilename;
-        longFilename[LCD_WIDTH-1] = '\0';
-    }
-    while( ((c = *filename) != '\0') && (n>0) )
-    {
-        lcd_print(c);
-        filename++;
-        n--;
-    }
-    lcd_space(n);
-}
-static void lcd_implementation_drawmenu_sddirectory_selected(uint8_t row, const char* filename, char* longFilename)
-{
-    char c;
-    uint8_t n = LCD_WIDTH - 2;
-    lcd_putc_at(0, row, '>');
-    lcd_print(LCD_STR_FOLDER[0]);
-    if (longFilename[0] != '\0')
-    {
-        filename = longFilename;
-        longFilename[LCD_WIDTH-2] = '\0';
-    }
-    while( ((c = *filename) != '\0') && (n>0) )
+    lcd_set_cursor(0, row);
+	lcd_print((lcd_encoder == menu_item)?'>':' ');
+    while( ((c = *longFilename) != '\0') && (n>0) )
     {
         lcd_print(c);
-        filename++;
+        longFilename++;
         n--;
     }
     lcd_space(n);
 }
-static void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* filename, char* longFilename)
+static void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* longFilename)
 {
     char c;
     uint8_t n = LCD_WIDTH - 2;
-    lcd_putc_at(0, row, ' ');
-    lcd_print(LCD_STR_FOLDER[0]);
-    if (longFilename[0] != '\0')
-    {
-        filename = longFilename;
-        longFilename[LCD_WIDTH-2] = '\0';
-    }
-    while( ((c = *filename) != '\0') && (n>0) )
+    lcd_set_cursor(0, row);
+	lcd_print((lcd_encoder == menu_item)?'>':' ');
+	lcd_print(LCD_STR_FOLDER[0]);
+    while( ((c = *longFilename) != '\0') && (n>0) )
     {
         lcd_print(c);
-        filename++;
+        longFilename++;
         n--;
     }
     lcd_space(n);
@@ -441,48 +357,16 @@ static void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* fil
 
 
 #define MENU_ITEM_SDDIR(str_fn, str_fnl) do { if (menu_item_sddir(str_fn, str_fnl)) return; } while (0)
-//#define MENU_ITEM_SDDIR(str, str_fn, str_fnl) MENU_ITEM(sddirectory, str, str_fn, str_fnl)
-//extern uint8_t menu_item_sddir(const char* str, const char* str_fn, char* str_fnl);
-
-#define MENU_ITEM_SDFILE(str, str_fn, str_fnl) do { if (menu_item_sdfile(str, str_fn, str_fnl)) return; } while (0)
-//#define MENU_ITEM_SDFILE(str, str_fn, str_fnl) MENU_ITEM(sdfile, str, str_fn, str_fnl)
-//extern uint8_t menu_item_sdfile(const char* str, const char* str_fn, char* str_fnl);
+#define MENU_ITEM_SDFILE(str_fn, str_fnl) do { if (menu_item_sdfile(str_fn, str_fnl)) return; } while (0)
 
 
 uint8_t menu_item_sddir(const char* str_fn, char* str_fnl)
 {
-#ifdef NEW_SD_MENU
-//	str_fnl[18] = 0;
-//	printf_P(PSTR("menu dir %d '%s' '%s'\n"), menu_row, str_fn, str_fnl);
-	if (menu_item == menu_line)
-	{
-		if (lcd_draw_update)
-		{
-			lcd_set_cursor(0, menu_row);
-			int cnt = lcd_printf_P(PSTR("%c%c%-18s"), (lcd_encoder == menu_item)?'>':' ', LCD_STR_FOLDER[0], str_fnl[0]?str_fnl:str_fn);
-//			int cnt = lcd_printf_P(PSTR("%c%c%-18s"), (lcd_encoder == menu_item)?'>':' ', LCD_STR_FOLDER[0], str_fn);
-		}
-		if (menu_clicked && (lcd_encoder == menu_item))
-		{
-			uint8_t depth = (uint8_t)card.getWorkDirDepth();
-			strcpy(dir_names[depth], str_fn);
-//			printf_P(PSTR("%s\n"), dir_names[depth]);
-			card.chdir(str_fn);
-			lcd_encoder = 0;
-			return menu_item_ret();
-		}
-	}
-	menu_item++;
-	return 0;
-#else //NEW_SD_MENU
 	if (menu_item == menu_line)
 	{
 		if (lcd_draw_update)
 		{
-			if (lcd_encoder == menu_item)
-				lcd_implementation_drawmenu_sddirectory_selected(menu_row, str_fn, str_fnl);
-			else
-				lcd_implementation_drawmenu_sddirectory(menu_row, str_fn, str_fnl);
+			lcd_implementation_drawmenu_sddirectory(menu_row, (str_fnl[0] == '\0') ? str_fn : str_fnl);
 		}
 		if (menu_clicked && (lcd_encoder == menu_item))
 		{
@@ -490,80 +374,32 @@ uint8_t menu_item_sddir(const char* str_fn, char* str_fnl)
 			lcd_update_enabled = 0;
 			menu_action_sddirectory(str_fn);
 			lcd_update_enabled = 1;
-			return menu_item_ret();
+			/* return */ menu_item_ret();
+			return 1;
 		}
 	}
 	menu_item++;
 	return 0;
-
-#endif //NEW_SD_MENU
 }
 
-static uint8_t menu_item_sdfile(const char*
-#ifdef NEW_SD_MENU
-        str
-#endif //NEW_SD_MENU
-         ,const char* str_fn, char* str_fnl)
+static uint8_t menu_item_sdfile(const char* str_fn, char* str_fnl)
 {
-#ifdef NEW_SD_MENU
-//	printf_P(PSTR("menu sdfile\n"));
-//	str_fnl[19] = 0;
-//	printf_P(PSTR("menu file %d '%s' '%s'\n"), menu_row, str_fn, str_fnl);
-	if (menu_item == menu_line)
-	{
-		if (lcd_draw_update)
-		{
-//			printf_P(PSTR("menu file %d %d '%s'\n"), menu_row, menuData.sdcard_menu.viewState, str_fnl[0]?str_fnl:str_fn);
-			lcd_set_cursor(0, menu_row);
-/*			if (lcd_encoder == menu_item)
-			{
-				lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 1);
-				if (menuData.sdcard_menu.viewState == 0)
-				{
-					menuData.sdcard_menu.viewState++;
-					lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 1);
-				}
-				else if (menuData.sdcard_menu.viewState == 1)
-				{
-					lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 2);
-				}
-			}
-			else*/
-			{
-				str_fnl[19] = 0;
-				lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', str_fnl[0]?str_fnl:str_fn);
-			}
-
-//			int cnt = lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', str_fnl);
-//			int cnt = lcd_printf_P(PSTR("%cTESTIK.gcode"), (lcd_encoder == menu_item)?'>':' ');
-		}
-		if (menu_clicked && (lcd_encoder == menu_item))
-		{
-			return menu_item_ret();
-		}
-	}
-	menu_item++;
-	return 0;
-#else //NEW_SD_MENU
 	if (menu_item == menu_line)
 	{
 		if (lcd_draw_update)
 		{
-			if (lcd_encoder == menu_item)
-				lcd_implementation_drawmenu_sdfile_selected(menu_row, str_fn, str_fnl);
-			else
-				lcd_implementation_drawmenu_sdfile(menu_row, str_fn, str_fnl);
+			lcd_implementation_drawmenu_sdfile(menu_row, (str_fnl[0] == '\0') ? str_fn : str_fnl);
 		}
 		if (menu_clicked && (lcd_encoder == menu_item))
 		{
-		    lcd_consume_click();
+			lcd_consume_click();
 			menu_action_sdfile(str_fn);
-			return menu_item_ret();
+			/* return */ menu_item_ret();
+			return 1;
 		}
 	}
 	menu_item++;
 	return 0;
-#endif //NEW_SD_MENU
 }
 
 // Print temperature (nozzle/bed) (9 chars total)
@@ -735,14 +571,6 @@ void lcdui_print_time(void)
 //! @Brief Print status line on status screen
 void lcdui_print_status_line(void)
 {
-    if (IS_SD_PRINTING) {
-        if (strcmp(longFilenameOLD, (card.longFilename[0] ? card.longFilename : card.filename)) != 0) {
-            memset(longFilenameOLD, '\0', strlen(longFilenameOLD));
-            sprintf_P(longFilenameOLD, PSTR("%s"), (card.longFilename[0] ? card.longFilename : card.filename));
-            scrollstuff = 0;
-        }
-    }
-
     if (heating_status) { // If heating flag, show progress of heating
         heating_status_counter++;
         if (heating_status_counter > 13) {
@@ -776,6 +604,7 @@ void lcdui_print_status_line(void)
         }
     }
     else if ((IS_SD_PRINTING) && (custom_message_type == CustomMsg::Status)) { // If printing from SD, show what we are printing
+		const char* longFilenameOLD = (card.longFilename[0] ? card.longFilename : card.filename);
         if(strlen(longFilenameOLD) > LCD_WIDTH) {
             int inters = 0;
             int gh = scrollstuff;
@@ -4196,7 +4025,7 @@ static void prusa_stat_printinfo()
 	SERIAL_ECHOPGM("][FEM:");
 	SERIAL_ECHO(itostr3(feedmultiply));
 	SERIAL_ECHOPGM("][FNM:");
-	SERIAL_ECHO(longFilenameOLD);
+	SERIAL_ECHO(card.longFilename[0] ? card.longFilename : card.filename);
 	SERIAL_ECHOPGM("][TIM:");
 	if (starttime != 0)
 	{
@@ -4511,17 +4340,10 @@ static void lcd_fsensor_state_set()
 }
 #endif //FILAMENT_SENSOR
 
-
-#if !SDSORT_USES_RAM
 void lcd_set_degree() {
 	lcd_set_custom_characters_degree();
 }
 
-void lcd_set_progress() {
-	lcd_set_custom_characters_progress();
-}
-#endif
-
 #if (LANG_MODE != 0)
 
 void menu_setlang(unsigned char lang)
@@ -7166,17 +6988,25 @@ static void lcd_control_temperature_menu()
 }
 
 
-#if SDCARDDETECT == -1
+
 static void lcd_sd_refresh()
 {
+#if SDCARDDETECT == -1
   card.initsd();
+#else
+  card.presort();
+#endif
   menu_top = 0;
+  lcd_encoder = 0;
+  menu_data_reset(); //Forces reloading of cached variables.
 }
-#endif
+
 static void lcd_sd_updir()
 {
   card.updir();
   menu_top = 0;
+  lcd_encoder = 0;
+  menu_data_reset(); //Forces reloading of cached variables.
 }
 
 void lcd_print_stop()
@@ -7272,57 +7102,156 @@ void lcd_sdcard_stop()
 
 void lcd_sdcard_menu()
 {
-  uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT);
-
-  if (card.presort_flag == true) {
-	  card.presort_flag = false;
-	  card.presort();
-  }
-  if (lcd_draw_update == 0 && LCD_CLICKED == 0)
-    //_delay(100);
-    return; // nothing to do (so don't thrash the SD card)
-  uint16_t fileCnt = card.getnrfilenames();
-
-
-  MENU_BEGIN();
-  MENU_ITEM_BACK_P(_T(bMain?MSG_MAIN:MSG_BACK));  // i.e. default menu-item / menu-item after card insertion
-  card.getWorkDirName();
-  if (card.filename[0] == '/')
-  {
+	enum menuState_t : uint8_t {_uninitialized, _standard, _scrolling};
+	typedef struct
+	{
+		menuState_t menuState = _uninitialized;
+		uint8_t offset;
+		bool isDir;
+		const char* scrollPointer;
+		uint16_t selectedFileID;
+		uint16_t fileCnt;
+		int8_t row;
+		uint8_t sdSort;
+		ShortTimer lcd_scrollTimer;
+	} _menu_data_sdcard_t;
+	static_assert(sizeof(menu_data)>= sizeof(_menu_data_sdcard_t),"_menu_data_sdcard_t doesn't fit into menu_data");
+	_menu_data_sdcard_t* _md = (_menu_data_sdcard_t*)&(menu_data[0]);
+	
+	switch(_md->menuState)
+	{
+		case _uninitialized: //Initialize menu data
+		{
+			if (card.presort_flag == true) //used to force resorting if sorting type is changed.
+			{
+				card.presort_flag = false;
+				card.presort();
+			}
+			_md->fileCnt = card.getnrfilenames();
+			_md->sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT);
+			_md->menuState = _standard;
+			// FALLTHRU
+		}
+		case _standard: //normal menu structure.
+		{
+			if (!_md->lcd_scrollTimer.running()) //if the timer is not running, then the menu state was just switched, so redraw the screen.
+			{
+				_md->lcd_scrollTimer.start();
+				lcd_draw_update = 1;
+			}
+			if (_md->lcd_scrollTimer.expired(500) && (_md->row != -1)) //switch to the scrolling state on timeout if a file/dir is selected.
+			{
+				_md->menuState = _scrolling;
+				_md->offset = 0;
+				_md->scrollPointer = NULL;
+				_md->lcd_scrollTimer.start();
+				lcd_draw_update = 1; //forces last load before switching to scrolling.
+			}
+			if (lcd_draw_update == 0 && !LCD_CLICKED)
+				return; // nothing to do (so don't thrash the SD card)
+			
+			_md->row = -1; // assume that no SD file/dir is currently selected. Once they are rendered, it will be changed to the correct row for the _scrolling state.
+			
+			//if we reached this point it means that the encoder moved or clicked or the state is being switched. Reset the scrollTimer.
+			_md->lcd_scrollTimer.start();
+			
+			MENU_BEGIN();
+			MENU_ITEM_BACK_P(_T(bMain?MSG_MAIN:MSG_BACK));  // i.e. default menu-item / menu-item after card insertion
+			card.getWorkDirName();
+			if (card.filename[0] == '/')
+			{
 #if SDCARDDETECT == -1
-    MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh);
+				MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh);
+#else
+				if (card.ToshibaFlashAir_isEnabled())
+					MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh); //show the refresh option if in flashAir mode.
 #endif
-  } else {
-    MENU_ITEM_FUNCTION_P(PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir);
-  }
+			}
+			else
+				MENU_ITEM_FUNCTION_P(PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir); //Show the updir button if in a subdir.
 
-  for (uint16_t i = 0; i < fileCnt; i++)
-  {
-    if (menu_item == menu_line)
-    {
-		const uint16_t nr = ((sdSort == SD_SORT_NONE) || farm_mode || (sdSort == SD_SORT_TIME)) ? (fileCnt - 1 - i) : i;
-		/*#ifdef SDCARD_RATHERRECENTFIRST
-			#ifndef SDCARD_SORT_ALPHA
-				fileCnt - 1 -
-			#endif
-		#endif
-		i;*/
-		#ifdef SDCARD_SORT_ALPHA
-			if (sdSort == SD_SORT_NONE) card.getfilename(nr);
-			else card.getfilename_sorted(nr);
-		#else
-			 card.getfilename(nr);
-		#endif
+			for (uint16_t i = _md->fileCnt; i-- > 0;) // Every file, from top to bottom.
+			{
+				if (menu_item == menu_line) //If the file is on the screen.
+				{
+					//load filename to memory.
+#ifdef SDCARD_SORT_ALPHA
+					if (_md->sdSort == SD_SORT_NONE)
+						card.getfilename(i);
+					else
+						card.getfilename_sorted(i, _md->sdSort);
+#else
+					card.getfilename(i);
+#endif
+					if (lcd_encoder == menu_item) //If the file is selected.
+					{
+						
+						_md->selectedFileID = i;
+						_md->isDir = card.filenameIsDir;
+						_md->row = menu_row;
+					}
+					if (card.filenameIsDir)
+						MENU_ITEM_SDDIR(card.filename, card.longFilename);
+					else
+						MENU_ITEM_SDFILE(card.filename, card.longFilename);
+				}
+				else MENU_ITEM_DUMMY(); //dummy item that just increments the internal menu counters.
+			}
+			MENU_END();
+		} break;
+		case _scrolling: //scrolling filename
+		{
+			const bool rewindFlag = LCD_CLICKED || lcd_draw_update; //flag that says whether the menu should return to _standard state.
 			
-		if (card.filenameIsDir)
-			MENU_ITEM_SDDIR(card.filename, card.longFilename);
-		else
-			MENU_ITEM_SDFILE(_T(MSG_CARD_MENU), card.filename, card.longFilename);
-    } else {
-      MENU_ITEM_DUMMY();
-    }
-  }
-  MENU_END();
+			if (_md->scrollPointer == NULL)
+			{
+				//load filename to memory.
+#ifdef SDCARD_SORT_ALPHA
+				if (_md->sdSort == SD_SORT_NONE)
+					card.getfilename(_md->selectedFileID);
+				else
+					card.getfilename_sorted(_md->selectedFileID, _md->sdSort);
+#else
+				card.getfilename(_md->selectedFileID);
+#endif
+				_md->scrollPointer = (card.longFilename[0] == '\0') ? card.filename : card.longFilename;
+			}
+			
+			if (rewindFlag == 1)
+				_md->offset = 0; //redraw once again from the beginning.
+			if (_md->lcd_scrollTimer.expired(300) || rewindFlag)
+			{
+				uint8_t i = LCD_WIDTH - ((_md->isDir)?2:1);
+				lcd_set_cursor(0, _md->row);
+				lcd_print('>');
+				if (_md->isDir)
+					lcd_print(LCD_STR_FOLDER[0]);
+				for (; i != 0; i--)
+				{
+					const char* c = (_md->scrollPointer + _md->offset + ((LCD_WIDTH - ((_md->isDir)?2:1)) - i));
+					lcd_print(c[0]);
+					if (c[1])
+						_md->lcd_scrollTimer.start();
+					else
+					{
+						_md->lcd_scrollTimer.stop();
+						break; //stop at the end of the string
+					}
+				}
+				if (i != 0) //adds spaces if string is incomplete or at the end (instead of null).
+				{
+					lcd_space(i);
+				}
+				_md->offset++;
+			}
+			if (rewindFlag) //go back to sd_menu.
+			{
+				_md->lcd_scrollTimer.stop(); //forces redraw in _standard state
+				_md->menuState = _standard;
+			}
+		} break;
+		default: _md->menuState = _uninitialized; //shouldn't ever happen. Anyways, initialize the menu.
+	}
 }
 #ifdef TMC2130
 static void lcd_belttest_v()
@@ -8577,7 +8506,6 @@ static bool check_file(const char* filename) {
 	const uint32_t filesize = card.getFileSize();
 	uint32_t startPos = 0;
 	const uint16_t bytesToCheck = min(END_FILE_SECTION, filesize);
-	uint8_t blocksPrinted = 0;
 	if (filesize > END_FILE_SECTION) {
 		startPos = filesize - END_FILE_SECTION;
 		card.setIndex(startPos);
@@ -8585,22 +8513,15 @@ static bool check_file(const char* filename) {
 	cmdqueue_reset();
 	cmdqueue_serial_disabled = true;
 
-	lcd_clear();
-	lcd_puts_at_P(0, 1, _i("Checking file"));////c=20 r=1
-	lcd_set_cursor(0, 2);
+	menu_progressbar_init(bytesToCheck, _i("Checking file"));
 	while (!card.eof() && !result) {
-		for (; blocksPrinted < (((card.get_sdpos() - startPos) * LCD_WIDTH) / bytesToCheck); blocksPrinted++)
-			lcd_print('\xFF'); //simple progress bar
-
+		menu_progressbar_update(card.get_sdpos() - startPos);
 		card.sdprinting = true;
 		get_command();
 		result = check_commands();
 	}
-
-	for (; blocksPrinted < LCD_WIDTH; blocksPrinted++)
-		lcd_print('\xFF'); //simple progress bar
-	_delay(100); //for the user to see the end of the progress bar.
-
+	
+	menu_progressbar_finish();
 	
 	cmdqueue_serial_disabled = false;
 	card.printingHasFinished();
@@ -8659,6 +8580,7 @@ void menu_action_sddirectory(const char* filename)
 {
 	card.chdir(filename, true);
 	lcd_encoder = 0;
+	menu_data_reset(); //Forces reloading of cached variables.
 }
 
 /** LCD API **/
@@ -8723,7 +8645,6 @@ static void lcd_connect_printer() {
 	
 	int i = 0;
 	int t = 0;
-	lcd_set_custom_characters_progress();
 	lcd_puts_at_P(0, 0, _i("Connect printer to")); 
 	lcd_puts_at_P(0, 1, _i("monitoring or hold"));
 	lcd_puts_at_P(0, 2, _i("the knob to continue"));
@@ -8740,12 +8661,11 @@ static void lcd_connect_printer() {
 			i = 0; 
 			lcd_puts_at_P(0, 3, PSTR("                    "));
 		}
-		if (i!=0) lcd_puts_at_P((i * 20) / (NC_BUTTON_LONG_PRESS * 10), 3, "\x01");
+		if (i!=0) lcd_puts_at_P((i * 20) / (NC_BUTTON_LONG_PRESS * 10), 3, "\xFF");
 		if (i == NC_BUTTON_LONG_PRESS * 10) {
 			no_response = false;
 		}
 	}
-	lcd_set_custom_characters_degree();
 	lcd_update_enable(true);
 	lcd_update(2);
 }

+ 2 - 3
Firmware/ultralcd.h

@@ -155,6 +155,8 @@ extern uint8_t SilentModeMenu_MMU;
 extern bool cancel_heatup;
 extern bool isPrintPaused;
 
+extern uint8_t scrollstuff;
+
 
 void lcd_ignore_click(bool b=true);
 void lcd_commands();
@@ -228,10 +230,7 @@ void lcd_temp_calibration_set();
 
 void display_loading();
 
-#if !SDSORT_USES_RAM
 void lcd_set_degree();
-void lcd_set_progress();
-#endif
 
 #if (LANG_MODE != 0)
 void lcd_language();