diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index ee12716e6..75ac0be96 100644 --- a/Firmware/Configuration_adv.h +++ b/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. diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 069eb5bbc..547f4e211 100755 --- a/Firmware/Marlin_main.cpp +++ b/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); } diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp index 6fe890095..673e88c17 100644 --- a/Firmware/cardreader.cpp +++ b/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); +#elif defined(SHELLSORT) - // 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)) +#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)) - #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 - #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 + 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; } } diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h index c79420737..715d82fa5 100644 --- a/Firmware/cardreader.h +++ b/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 diff --git a/Firmware/lcd.cpp b/Firmware/lcd.cpp index 0212a9dfe..c3f2921d1 100644 --- a/Firmware/lcd.cpp +++ b/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, diff --git a/Firmware/lcd.h b/Firmware/lcd.h index 6b1e42b71..12b162e75 100644 --- a/Firmware/lcd.h +++ b/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); diff --git a/Firmware/menu.cpp b/Firmware/menu.cpp index efa880734..fe58686cf 100755 --- a/Firmware/menu.cpp +++ b/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(const char* str, int16_t *pval, int16_t min_val, int16_t max_val); template uint8_t menu_item_edit_P(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); +} diff --git a/Firmware/menu.h b/Firmware/menu.h index c255393d1..54c8a2cbb 100755 --- a/Firmware/menu.h +++ b/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 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 diff --git a/Firmware/messages.c b/Firmware/messages.c index 028870970..684cfa080 100644 --- a/Firmware/messages.c +++ b/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 diff --git a/Firmware/messages.h b/Firmware/messages.h index 140754b31..f38a4b260 100644 --- a/Firmware/messages.h +++ b/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) } diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index cc62510ab..00d2f9190 100755 --- a/Firmware/ultralcd.cpp +++ b/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_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_selected(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++; - n--; - } - lcd_space(n); -} -static void lcd_implementation_drawmenu_sddirectory(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_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)?'>':' '); + lcd_implementation_drawmenu_sdfile(menu_row, (str_fnl[0] == '\0') ? str_fn : str_fnl); } 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); - } - 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(); - menu_top = 0; -} +#else + card.presort(); #endif + menu_top = 0; + lcd_encoder = 0; + menu_data_reset(); //Forces reloading of cached variables. +} + 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] == '/') - { -#if SDCARDDETECT == -1 - MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh); -#endif - } else { - MENU_ITEM_FUNCTION_P(PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir); - } - - 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 + 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) - 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(); + _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); +#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); //Show the updir button if in a subdir. + + 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 (_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); } diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h index b4ec04bad..008a106e6 100755 --- a/Firmware/ultralcd.h +++ b/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();