diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 7a9a4929a..ee12716e6 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -338,6 +338,11 @@ const unsigned int dropsegments=5; //everything with less than this number of st // Control heater 0 and heater 1 in parallel. //#define HEATERS_PARALLEL +//LCD status clock interval timer to switch between +// remaining print time +// and time to change/pause/interaction +#define CLOCK_INTERVAL_TIME 5 + //=========================================================================== //=============================Buffers ============================ //=========================================================================== diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h index 1ed5e0bd3..a1b6fe4eb 100755 --- a/Firmware/Marlin.h +++ b/Firmware/Marlin.h @@ -350,10 +350,6 @@ extern unsigned long t_fan_rising_edge; extern bool mesh_bed_leveling_flag; extern bool mesh_bed_run_from_menu; -extern bool sortAlpha; - -extern char dir_names[][9]; - extern int8_t lcd_change_fil_state; // save/restore printing extern bool saved_printing; @@ -370,6 +366,8 @@ extern uint8_t print_percent_done_normal; extern uint16_t print_time_remaining_normal; extern uint8_t print_percent_done_silent; extern uint16_t print_time_remaining_silent; +extern uint16_t print_time_to_change_normal; +extern uint16_t print_time_to_change_silent; #define PRINT_TIME_REMAINING_INIT 0xffff @@ -441,7 +439,6 @@ extern void cancel_saved_printing(); //estimated time to end of the print -extern uint16_t print_time_remaining(); extern uint8_t calc_percent_done(); diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index c8297b374..e43501994 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -228,10 +228,6 @@ bool fan_state[2]; int fan_edge_counter[2]; int fan_speed[2]; -char dir_names[MAX_DIR_DEPTH][9]; - -bool sortAlpha = false; - float extruder_multiplier[EXTRUDERS] = {1.0 #if EXTRUDERS > 1 @@ -320,6 +316,8 @@ uint8_t print_percent_done_normal = PRINT_PERCENT_DONE_INIT; uint16_t print_time_remaining_normal = PRINT_TIME_REMAINING_INIT; //estimated remaining print time in minutes uint8_t print_percent_done_silent = PRINT_PERCENT_DONE_INIT; uint16_t print_time_remaining_silent = PRINT_TIME_REMAINING_INIT; //estimated remaining print time in minutes +uint16_t print_time_to_change_normal = PRINT_TIME_REMAINING_INIT; //estimated remaining time to next change in minutes +uint16_t print_time_to_change_silent = PRINT_TIME_REMAINING_INIT; //estimated remaining time to next change in minutes uint32_t IP_address = 0; @@ -711,124 +709,98 @@ void softReset() #endif +static void factory_reset_stats(){ + eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); + eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); + + eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_X, 0); + eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_Y, 0); + eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, 0); + eeprom_update_byte((uint8_t *)EEPROM_POWER_COUNT, 0); + + eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_X_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_Y_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_POWER_COUNT_TOT, 0); + + eeprom_update_word((uint16_t *)EEPROM_MMU_FAIL_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_MMU_LOAD_FAIL_TOT, 0); + eeprom_update_byte((uint8_t *)EEPROM_MMU_FAIL, 0); + eeprom_update_byte((uint8_t *)EEPROM_MMU_LOAD_FAIL, 0); +} + // Factory reset function // This function is used to erase parts or whole EEPROM memory which is used for storing calibration and and so on. // Level input parameter sets depth of reset -int er_progress = 0; static void factory_reset(char level) -{ +{ lcd_clear(); - switch (level) { - - // Level 0: Language reset - case 0: - Sound_MakeCustom(100,0,false); - lang_reset(); - break; - - //Level 1: Reset statistics - case 1: - Sound_MakeCustom(100,0,false); - eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); - eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); + Sound_MakeCustom(100,0,false); + switch (level) { - eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_X, 0); - eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_Y, 0); - eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, 0); - eeprom_update_byte((uint8_t *)EEPROM_POWER_COUNT, 0); + case 0: // Level 0: Language reset + lang_reset(); + break; - eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_X_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_Y_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_POWER_COUNT_TOT, 0); + case 1: //Level 1: Reset statistics + factory_reset_stats(); + lcd_menu_statistics(); + break; - eeprom_update_word((uint16_t *)EEPROM_MMU_FAIL_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_MMU_LOAD_FAIL_TOT, 0); - eeprom_update_byte((uint8_t *)EEPROM_MMU_FAIL, 0); - eeprom_update_byte((uint8_t *)EEPROM_MMU_LOAD_FAIL, 0); + case 2: // Level 2: Prepare for shipping + factory_reset_stats(); + // [[fallthrough]] // there is no break intentionally - - lcd_menu_statistics(); - - break; - - // Level 2: Prepare for shipping - case 2: - //lcd_puts_P(PSTR("Factory RESET")); - //lcd_puts_at_P(1,2,PSTR("Shipping prep")); - - // Force language selection at the next boot up. - lang_reset(); - // Force the "Follow calibration flow" message at the next boot up. - calibration_status_store(CALIBRATION_STATUS_Z_CALIBRATION); - eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); //run wizard - farm_mode = false; - eeprom_update_byte((uint8_t*)EEPROM_FARM_MODE, farm_mode); - - eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); - eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); - - eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_X, 0); - eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_Y, 0); - eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, 0); - eeprom_update_byte((uint8_t *)EEPROM_POWER_COUNT, 0); - - eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_X_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_Y_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_POWER_COUNT_TOT, 0); - - eeprom_update_word((uint16_t *)EEPROM_MMU_FAIL_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_MMU_LOAD_FAIL_TOT, 0); - eeprom_update_byte((uint8_t *)EEPROM_MMU_FAIL, 0); - eeprom_update_byte((uint8_t *)EEPROM_MMU_LOAD_FAIL, 0); + case 4: // Level 4: Preparation after being serviced + // Force language selection at the next boot up. + lang_reset(); + // Force the "Follow calibration flow" message at the next boot up. + calibration_status_store(CALIBRATION_STATUS_Z_CALIBRATION); + eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); //run wizard + farm_mode = false; + eeprom_update_byte((uint8_t*)EEPROM_FARM_MODE, farm_mode); #ifdef FILAMENT_SENSOR - fsensor_enable(); - fsensor_autoload_set(true); + fsensor_enable(); + fsensor_autoload_set(true); #endif //FILAMENT_SENSOR - Sound_MakeCustom(100,0,false); - //_delay_ms(2000); - break; + break; - // Level 3: erase everything, whole EEPROM will be set to 0xFF + 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: - lcd_puts_P(PSTR("Factory RESET")); - lcd_puts_at_P(1, 2, PSTR("ERASING all data")); - - Sound_MakeCustom(100,0,false); - er_progress = 0; - lcd_puts_at_P(3, 3, PSTR(" ")); - lcd_set_cursor(3, 3); - lcd_print(er_progress); - - // Erase EEPROM - for (int i = 0; i < 4096; i++) { - eeprom_update_byte((uint8_t*)i, 0xFF); - - if (i % 41 == 0) { - er_progress++; - lcd_puts_at_P(3, 3, PSTR(" ")); - lcd_set_cursor(3, 3); - lcd_print(er_progress); - lcd_puts_P(PSTR("%")); - } + // Erase EEPROM + for (uint16_t i = 0; i < 4096; 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("%")); } - softReset(); + + } + softReset(); + }break; - break; - case 4: - bowden_menu(); - break; - - default: - break; - } - - +#ifdef SNMM + case 5: + bowden_menu(); + break; +#endif + default: + break; + } } extern "C" { @@ -859,30 +831,27 @@ void factory_reset() { lcd_clear(); - lcd_puts_P(PSTR("Factory RESET")); - SET_OUTPUT(BEEPER); - if(eSoundMode!=e_SOUND_MODE_SILENT) - WRITE(BEEPER, HIGH); + if(eSoundMode!=e_SOUND_MODE_SILENT) + WRITE(BEEPER, HIGH); while (!READ(BTN_ENC)); WRITE(BEEPER, LOW); - - _delay_ms(2000); char level = reset_menu(); factory_reset(level); switch (level) { - case 0: _delay_ms(0); break; - case 1: _delay_ms(0); break; - case 2: _delay_ms(0); break; - case 3: _delay_ms(0); break; + case 0: + case 1: + case 2: + case 3: + case 4: _delay_ms(0); break; } } @@ -3801,31 +3770,90 @@ void process_commands() float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; int8_t SilentMode; #endif - /*! + /*! + + --------------------------------------------------------------------------------- + ### M117 - Display Message M117: Display Message + This causes the given message to be shown in the status line on an attached LCD. + It is processed early as to allow printing messages that contain G, M, N or T. + + --------------------------------------------------------------------------------- + ### Special internal commands + These are used by internal functions to process certain actions in the right order. Some of these are also usable by the user. + They are processed early as the commands are complex (strings). + These are only available on the MK3(S) as these require TMC2130 drivers: + - CRASH DETECTED + - CRASH RECOVER + - CRASH_CANCEL + - TMC_SET_WAVE + - TMC_SET_STEP + - TMC_SET_CHOP + */ + if (code_seen_P(PSTR("M117"))) //moved to highest priority place to be able to to print strings which includes "G", "PRUSA" and "^" + { + starpos = (strchr(strchr_pointer + 5, '*')); + if (starpos != NULL) + *(starpos) = '\0'; + lcd_setstatus(strchr_pointer + 5); + custom_message_type = CustomMsg::MsgUpdate; + } + + /*! + ### M0, M1 - Stop the printer M0: Stop or Unconditional stop + #### Usage + + M0 [P] [string] + M1 [P] [S] [string] + + #### Parameters - --------------------------------------------------------------------------------- - ### M117 - Display Message M117: Display Message - This causes the given message to be shown in the status line on an attached LCD. - It is processed early as to allow printing messages that contain G, M, N or T. - - --------------------------------------------------------------------------------- - ### Special internal commands - These are used by internal functions to process certain actions in the right order. Some of these are also usable by the user. - They are processed early as the commands are complex (strings). - These are only available on the MK3(S) as these require TMC2130 drivers: - - CRASH DETECTED - - CRASH RECOVER - - CRASH_CANCEL - - TMC_SET_WAVE - - TMC_SET_STEP - - TMC_SET_CHOP - */ - if (code_seen_P(PSTR("M117"))) { //moved to highest priority place to be able to to print strings which includes "G", "PRUSA" and "^" - starpos = (strchr(strchr_pointer + 5, '*')); - if (starpos != NULL) - *(starpos) = '\0'; - lcd_setstatus(strchr_pointer + 5); - } + - `P` - Expire time, in milliseconds + - `S` - Expire time, in seconds + - `string` - Must for M1 and optional for M0 message to display on the LCD + */ + + else if (code_seen_P(PSTR("M0")) || code_seen_P(PSTR("M1 "))) {// M0 and M1 - (Un)conditional stop - Wait for user button press on LCD + char *src = strchr_pointer + 2; + codenum = 0; + bool hasP = false, hasS = false; + if (code_seen('P')) { + codenum = code_value(); // milliseconds to wait + hasP = codenum > 0; + } + if (code_seen('S')) { + codenum = code_value() * 1000; // seconds to wait + hasS = codenum > 0; + } + starpos = strchr(src, '*'); + if (starpos != NULL) *(starpos) = '\0'; + while (*src == ' ') ++src; + custom_message_type = CustomMsg::M0Wait; + if (!hasP && !hasS && *src != '\0') { + lcd_setstatus(src); + } else { + LCD_MESSAGERPGM(_i("Wait for user..."));////MSG_USERWAIT + } + lcd_ignore_click(); //call lcd_ignore_click aslo for else ??? + st_synchronize(); + previous_millis_cmd = _millis(); + if (codenum > 0) { + codenum += _millis(); // keep track of when we started waiting + KEEPALIVE_STATE(PAUSED_FOR_USER); + while(_millis() < codenum && !lcd_clicked()) { + manage_heater(); + manage_inactivity(true); + lcd_update(0); + } + KEEPALIVE_STATE(IN_HANDLER); + lcd_ignore_click(false); + } else { + marlin_wait_for_click(); + } + if (IS_SD_PRINTING) + custom_message_type = CustomMsg::Status; + else + LCD_MESSAGERPGM(_T(WELCOME_MSG)); + } #ifdef TMC2130 else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("CRASH_"), 6) == 0) @@ -4006,9 +4034,9 @@ void process_commands() }else if (code_seen_P("fv")) { // PRUSA fv // get file version #ifdef SDSUPPORT - card.openFile(strchr_pointer + 3,true); + card.openFileReadFilteredGcode(strchr_pointer + 3,true); while (true) { - uint16_t readByte = card.get(); + uint16_t readByte = card.getFilteredGcodeChar(); MYSERIAL.write(readByte); if (readByte=='\n') { break; @@ -4021,7 +4049,7 @@ void process_commands() } else if (code_seen_P(PSTR("M28"))) { // PRUSA M28 trace(); prusa_sd_card_upload = true; - card.openFile(strchr_pointer+4,false); + card.openFileWrite(strchr_pointer+4); } else if (code_seen_P(PSTR("SN"))) { // PRUSA SN char SN[20]; @@ -5684,60 +5712,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) switch(mcode_in_progress) { - /*! - ### M0, M1 - Stop the printer M0: Stop or Unconditional stop - */ - case 0: // M0 - Unconditional stop - Wait for user button press on LCD - case 1: // M1 - Conditional stop - Wait for user button press on LCD - { - char *src = strchr_pointer + 2; - - codenum = 0; - - bool hasP = false, hasS = false; - if (code_seen('P')) { - codenum = code_value(); // milliseconds to wait - hasP = codenum > 0; - } - if (code_seen('S')) { - codenum = code_value() * 1000; // seconds to wait - hasS = codenum > 0; - } - starpos = strchr(src, '*'); - if (starpos != NULL) *(starpos) = '\0'; - while (*src == ' ') ++src; - if (!hasP && !hasS && *src != '\0') { - lcd_setstatus(src); - } else { - LCD_MESSAGERPGM(_i("Wait for user..."));////MSG_USERWAIT - } - - lcd_ignore_click(); //call lcd_ignore_click aslo for else ??? - st_synchronize(); - previous_millis_cmd = _millis(); - if (codenum > 0){ - codenum += _millis(); // keep track of when we started waiting - KEEPALIVE_STATE(PAUSED_FOR_USER); - while(_millis() < codenum && !lcd_clicked()){ - manage_heater(); - manage_inactivity(true); - lcd_update(0); - } - KEEPALIVE_STATE(IN_HANDLER); - lcd_ignore_click(false); - }else{ - marlin_wait_for_click(); - } - if (IS_SD_PRINTING) - LCD_MESSAGERPGM(_T(MSG_RESUMING_PRINT)); - else - LCD_MESSAGERPGM(_T(WELCOME_MSG)); - } - break; - /*! ### M17 - Enable all axes M17: Enable/Power all stepper motors */ + case 17: LCD_MESSAGERPGM(_i("No move."));////MSG_NO_MOVE enable_x(); @@ -5790,7 +5768,7 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) starpos = (strchr(strchr_pointer + 4,'*')); if(starpos!=NULL) *(starpos)='\0'; - card.openFile(strchr_pointer + 4,true); + card.openFileReadFilteredGcode(strchr_pointer + 4); break; /*! @@ -5860,7 +5838,7 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) strchr_pointer = strchr(npos,' ') + 1; *(starpos) = '\0'; } - card.openFile(strchr_pointer+4,false); + card.openFileWrite(strchr_pointer+4); break; /*! ### M29 - Stop SD write M29: Stop writing to SD card @@ -5921,7 +5899,7 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) if( card.cardOK ) { - card.openFile(namestartpos,true,!call_procedure); + card.openFileReadFilteredGcode(namestartpos,!call_procedure); if(code_seen('S')) if(strchr_pointerM73: Set/Get build percentage - #### Usage + /*! + ### M73 - Set/get print progress M73: Set/Get build percentage + #### Usage - M73 [ P | R | Q | S ] - - #### Parameters - - `P` - Percent in normal mode - - `R` - Time remaining in normal mode - - `Q` - Percent in silent mode - - `S` - Time in silent mode - */ - case 73: //M73 show percent done and time remaining - if(code_seen('P')) print_percent_done_normal = code_value(); - if(code_seen('R')) print_time_remaining_normal = code_value(); - if(code_seen('Q')) print_percent_done_silent = code_value(); - if(code_seen('S')) print_time_remaining_silent = code_value(); + M73 [ P | R | Q | S | C | D ] - { - const char* _msg_mode_done_remain = _N("%S MODE: Percent done: %d; print time remaining in mins: %d\n"); - printf_P(_msg_mode_done_remain, _N("NORMAL"), int(print_percent_done_normal), print_time_remaining_normal); - printf_P(_msg_mode_done_remain, _N("SILENT"), int(print_percent_done_silent), print_time_remaining_silent); - } - break; + #### Parameters + - `P` - Percent in normal mode + - `R` - Time remaining in normal mode + - `Q` - Percent in silent mode + - `S` - Time in silent mode + - `C` - Time to change/pause/user interaction in normal mode + - `D` - Time to change/pause/user interaction in silent mode + */ + //!@todo update RepRap Gcode wiki + case 73: //M73 show percent done, time remaining and time to change/pause + { + if(code_seen('P')) print_percent_done_normal = code_value(); + if(code_seen('R')) print_time_remaining_normal = code_value(); + if(code_seen('Q')) print_percent_done_silent = code_value(); + if(code_seen('S')) print_time_remaining_silent = code_value(); + if(code_seen('C')) print_time_to_change_normal = code_value(); + if(code_seen('D')) print_time_to_change_silent = code_value(); + { + const char* _msg_mode_done_remain = _N("%S MODE: Percent done: %d; print time remaining in mins: %d; Change in mins: %d\n"); + printf_P(_msg_mode_done_remain, _N("NORMAL"), int(print_percent_done_normal), print_time_remaining_normal, print_time_to_change_normal); + printf_P(_msg_mode_done_remain, _N("SILENT"), int(print_percent_done_silent), print_time_remaining_silent, print_time_to_change_silent); + } + break; + } /*! ### M104 - Set hotend temperature M104: Set Extruder Temperature #### Usage @@ -8135,35 +8119,34 @@ Sigma_Exit: /*! ### M25 - Pause SD print M25: Pause SD print */ - case 25: - case 601: - { - if (!isPrintPaused) - { + case 25: + case 601: + { + if (!isPrintPaused) { st_synchronize(); ClearToSend(); //send OK even before the command finishes executing because we want to make sure it is not skipped because of cmdqueue_pop_front(); cmdqueue_pop_front(); //trick because we want skip this command (M601) after restore lcd_pause_print(); } - } - break; + } + break; /*! - ### M602 - Resume print M602: Resume print + ### M602 - Resume print M602: Resume print */ - case 602: { - if (isPrintPaused) - lcd_resume_print(); - } - break; + case 602: { + if (isPrintPaused) + lcd_resume_print(); + } + break; /*! ### M603 - Stop print M603: Stop print */ - case 603: { - lcd_print_stop(); - } - break; + case 603: { + lcd_print_stop(); + } + break; #ifdef PINDA_THERMISTOR /*! @@ -9707,7 +9690,7 @@ void manage_inactivity_IR_ANALOG_Check(uint16_t &nFSCheckCount, ClFsensorPCB isV void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument set in Marlin.h { #ifdef FILAMENT_SENSOR -bool bInhibitFlag; +bool bInhibitFlag = false; #ifdef IR_SENSOR_ANALOG static uint16_t nFSCheckCount=0; #endif // IR_SENSOR_ANALOG @@ -9715,16 +9698,11 @@ static uint16_t nFSCheckCount=0; if (mmu_enabled == false) { //-// if (mcode_in_progress != 600) //M600 not in progress -#ifdef PAT9125 - bInhibitFlag=(menu_menu==lcd_menu_extruder_info); // Support::ExtruderInfo menu active -#endif // PAT9125 -#ifdef IR_SENSOR - bInhibitFlag=(menu_menu==lcd_menu_show_sensors_state); // Support::SensorInfo menu active + if (!PRINTER_ACTIVE) bInhibitFlag=(menu_menu==lcd_menu_show_sensors_state); //Block Filament sensor actions if PRINTER is not active and Support::SensorInfo menu active #ifdef IR_SENSOR_ANALOG - bInhibitFlag=bInhibitFlag||bMenuFSDetect; // Settings::HWsetup::FSdetect menu active + bInhibitFlag=bInhibitFlag||bMenuFSDetect; // Block Filament sensor actions if Settings::HWsetup::FSdetect menu active #endif // IR_SENSOR_ANALOG -#endif // IR_SENSOR - if ((mcode_in_progress != 600) && (eFilamentAction != FilamentAction::AutoLoad) && (!bInhibitFlag) && (menu_menu != lcd_move_e)) //M600 not in progress, preHeat @ autoLoad menu not active, Support::ExtruderInfo/SensorInfo menu not active + if ((mcode_in_progress != 600) && (eFilamentAction != FilamentAction::AutoLoad) && (!bInhibitFlag) && (menu_menu != lcd_move_e)) //M600 not in progress, preHeat @ autoLoad menu not active { if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal) && ! eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE)) { @@ -11281,8 +11259,8 @@ void restore_print_from_eeprom(bool mbl_was_active) { } dir_name[8] = '\0'; MYSERIAL.println(dir_name); - strcpy(dir_names[i], dir_name); - card.chdir(dir_name); + // strcpy(dir_names[i], dir_name); + card.chdir(dir_name, false); } for (int i = 0; i < 8; i++) { @@ -11657,46 +11635,40 @@ void print_mesh_bed_leveling_table() SERIAL_ECHOLN(); } -uint16_t print_time_remaining() { - uint16_t print_t = PRINT_TIME_REMAINING_INIT; -#ifdef TMC2130 - if (SilentModeMenu == SILENT_MODE_OFF) print_t = print_time_remaining_normal; - else print_t = print_time_remaining_silent; -#else - print_t = print_time_remaining_normal; -#endif //TMC2130 - if ((print_t != PRINT_TIME_REMAINING_INIT) && (feedmultiply != 0)) print_t = 100ul * print_t / feedmultiply; - return print_t; -} - uint8_t calc_percent_done() { - //in case that we have information from M73 gcode return percentage counted by slicer, else return percentage counted as byte_printed/filesize - uint8_t percent_done = 0; + //in case that we have information from M73 gcode return percentage counted by slicer, else return percentage counted as byte_printed/filesize + uint8_t percent_done = 0; #ifdef TMC2130 - if (SilentModeMenu == SILENT_MODE_OFF && print_percent_done_normal <= 100) { - percent_done = print_percent_done_normal; - } - else if (print_percent_done_silent <= 100) { - percent_done = print_percent_done_silent; - } + if (SilentModeMenu == SILENT_MODE_OFF && print_percent_done_normal <= 100) + { + percent_done = print_percent_done_normal; + } + else if (print_percent_done_silent <= 100) + { + percent_done = print_percent_done_silent; + } #else - if (print_percent_done_normal <= 100) { - percent_done = print_percent_done_normal; - } + if (print_percent_done_normal <= 100) + { + percent_done = print_percent_done_normal; + } #endif //TMC2130 - else { - percent_done = card.percentDone(); - } - return percent_done; + else + { + percent_done = card.percentDone(); + } + return percent_done; } static void print_time_remaining_init() { - print_time_remaining_normal = PRINT_TIME_REMAINING_INIT; - print_time_remaining_silent = PRINT_TIME_REMAINING_INIT; - print_percent_done_normal = PRINT_PERCENT_DONE_INIT; - print_percent_done_silent = PRINT_PERCENT_DONE_INIT; + print_time_remaining_normal = PRINT_TIME_REMAINING_INIT; + print_percent_done_normal = PRINT_PERCENT_DONE_INIT; + print_time_remaining_silent = PRINT_TIME_REMAINING_INIT; + print_percent_done_silent = PRINT_PERCENT_DONE_INIT; + print_time_to_change_normal = PRINT_TIME_REMAINING_INIT; + print_time_to_change_silent = PRINT_TIME_REMAINING_INIT; } void load_filament_final_feed() diff --git a/Firmware/SdBaseFile.cpp b/Firmware/SdBaseFile.cpp index b9e881ef2..e3b1c18c8 100644 --- a/Firmware/SdBaseFile.cpp +++ b/Firmware/SdBaseFile.cpp @@ -530,9 +530,9 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) { * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ - bool SdBaseFile::open(const char* path, uint8_t oflag) { - return open(cwd_, path, oflag); - } +bool SdBaseFile::open(const char* path, uint8_t oflag) { + return open(cwd_, path, oflag); +} //------------------------------------------------------------------------------ /** Open a file or directory by name. * diff --git a/Firmware/SdBaseFile.h b/Firmware/SdBaseFile.h index 923a391dd..a6bd311fe 100644 --- a/Firmware/SdBaseFile.h +++ b/Firmware/SdBaseFile.h @@ -281,8 +281,10 @@ class SdBaseFile { static void printFatDate(uint16_t fatDate); static void printFatTime( uint16_t fatTime); bool printName(); +protected: int16_t read(); int16_t read(void* buf, uint16_t nbyte); +public: int8_t readDir(dir_t* dir, char* longFilename); static bool remove(SdBaseFile* dirFile, const char* path); bool remove(); @@ -321,7 +323,7 @@ class SdBaseFile { SdVolume* volume() const {return vol_;} int16_t write(const void* buf, uint16_t nbyte); //------------------------------------------------------------------------------ - private: + protected: // allow SdFat to set cwd_ friend class SdFat; // global pointer to cwd dir diff --git a/Firmware/SdFile.cpp b/Firmware/SdFile.cpp index 2fb4d5943..1bad4319f 100644 --- a/Firmware/SdFile.cpp +++ b/Firmware/SdFile.cpp @@ -30,6 +30,191 @@ */ SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) { } + +bool SdFile::openFilteredGcode(SdBaseFile* dirFile, const char* path){ + if( open(dirFile, path, O_READ) ){ + // compute the block to start with + if( ! gfComputeNextFileBlock() ) + return false; + gfReset(); + return true; + } else { + return false; + } +} + +bool SdFile::seekSetFilteredGcode(uint32_t pos){ + if(! seekSet(pos) )return false; + if(! gfComputeNextFileBlock() )return false; + gfReset(); + return true; +} + +const uint8_t *SdFile::gfBlockBuffBegin() const { + return vol_->cache()->data; // this is constant for the whole time, so it should be fast and sleek +} + +void SdFile::gfReset(){ + // reset cache read ptr to its begin + gfReadPtr = gfBlockBuffBegin() + gfOffset; +} + +// think twice before allowing this to inline - manipulating 4B longs is costly +// moreover - this function has its parameters in registers only, so no heavy stack usage besides the call/ret +void __attribute__((noinline)) SdFile::gfUpdateCurrentPosition(uint16_t inc){ + curPosition_ += inc; +} + +#define find_endl(resultP, startP) \ +__asm__ __volatile__ ( \ +"cycle: \n" \ +"ld r22, Z+ \n" \ +"cpi r22, 0x0A \n" \ +"brne cycle \n" \ +: "=z" (resultP) /* result of the ASM code - in our case the Z register (R30:R31) */ \ +: "z" (startP) /* input of the ASM code - in our case the Z register as well (R30:R31) */ \ +: "r22" /* modifying register R22 - so that the compiler knows */ \ +) + +// avoid calling the default heavy-weight read() for just one byte +int16_t SdFile::readFilteredGcode(){ + if( ! gfEnsureBlock() ){ + goto eof_or_fail; // this is unfortunate :( ... other calls are using the cache and we can loose the data block of our gcode file + } + // assume, we have the 512B block cache filled and terminated with a '\n' + { + const uint8_t *start = gfReadPtr; + + // It may seem unreasonable to copy the variable into a local one and copy it back at the end of this method, + // but there is an important point of view: the compiler is unsure whether it can optimize the reads/writes + // to gfReadPtr within this method, because it is a class member variable. + // The compiler cannot see, if omitting read/write won't have any incorrect side-effects to the rest of the whole FW. + // So this trick explicitly states, that rdPtr is a local variable limited to the scope of this method, + // therefore the compiler can omit read/write to it (keep it in registers!) as it sees fit. + // And it does! Codesize dropped by 68B! + const uint8_t *rdPtr = gfReadPtr; + + // the same applies to gfXBegin, codesize dropped another 100B! + const uint8_t *blockBuffBegin = gfBlockBuffBegin(); + + uint8_t consecutiveCommentLines = 0; + while( *rdPtr == ';' ){ + for(;;){ + + //while( *(++gfReadPtr) != '\n' ); // skip until a newline is found - suboptimal code! + // Wondering, why this "nice while cycle" is done in such a weird way using a separate find_endl() function? + // Have a look at the ASM code GCC produced! + + // At first - a separate find_endl() makes the compiler understand, + // that I don't need to store gfReadPtr every time, I'm only interested in the final address where the '\n' was found + // - the cycle can run on CPU registers only without touching memory besides reading the character being compared. + // Not only makes the code run considerably faster, but is also 40B shorter! + // This was the generated code: + //FORCE_INLINE const uint8_t * find_endl(const uint8_t *p){ + // while( *(++p) != '\n' ); // skip until a newline is found + // return p; } + // 11c5e: movw r30, r18 + // 11c60: subi r18, 0xFF ; 255 + // 11c62: sbci r19, 0xFF ; 255 + // 11c64: ld r22, Z + // 11c66: cpi r22, 0x0A ; 10 + // 11c68: brne .-12 ; 0x11c5e + + // Still, even that was suboptimal as the compiler seems not to understand the usage of ld r22, Z+ (the plus is important) + // aka automatic increment of the Z register (R30:R31 pair) + // There is no other way than pure ASM! + find_endl(rdPtr, rdPtr); + + // found a newline, prepare the next block if block cache end reached + if( rdPtr - blockBuffBegin > 512 ){ + // at the end of block cache, fill new data in + gfUpdateCurrentPosition( rdPtr - start - 1 ); + if( ! gfComputeNextFileBlock() )goto eof_or_fail; + if( ! gfEnsureBlock() )goto eof_or_fail; // fetch it into RAM + rdPtr = start = blockBuffBegin; + } else { + if(consecutiveCommentLines >= 250){ + --rdPtr; // unget the already consumed newline + goto emit_char; + } + // peek the next byte - we are inside the block at least at 511th index - still safe + if( *rdPtr == ';' ){ + // consecutive comment + ++consecutiveCommentLines; + } else { + --rdPtr; // unget the already consumed newline + goto emit_char; + } + break; // found the real end of the line even across many blocks + } + } + } +emit_char: + { + gfUpdateCurrentPosition( rdPtr - start + 1 ); + int16_t rv = *rdPtr++; + + if( curPosition_ >= fileSize_ ){ + // past the end of file + goto eof_or_fail; + } else if( rdPtr - blockBuffBegin >= 512 ){ + // past the end of current bufferred block - prepare the next one... + if( ! gfComputeNextFileBlock() )goto eof_or_fail; + // don't need to force fetch the block here, it will get loaded on the next call + rdPtr = blockBuffBegin; + } + + // save the current read ptr for the next run + gfReadPtr = rdPtr; + return rv; + } + +} + +eof_or_fail: + // make the rdptr point to a safe location - end of file + gfReadPtr = gfBlockBuffBegin() + 512; + return -1; +} + +bool SdFile::gfEnsureBlock(){ + if ( vol_->cacheRawBlock(gfBlock, SdVolume::CACHE_FOR_READ)){ + // terminate with a '\n' + const uint16_t terminateOfs = fileSize_ - gfOffset; + vol_->cache()->data[ terminateOfs < 512 ? terminateOfs : 512 ] = '\n'; + return true; + } else { + return false; + } +} + +bool SdFile::gfComputeNextFileBlock() { + // error if not open or write only + if (!isOpen() || !(flags_ & O_READ)) return false; + + gfOffset = curPosition_ & 0X1FF; // offset in block + if (type_ == FAT_FILE_TYPE_ROOT_FIXED) { + // SHR by 9 means skip the last byte and shift just 3 bytes by 1 + // -> should be 8 instructions... and not the horrible loop shifting 4 bytes at once + // still need to get some work on this + gfBlock = vol_->rootDirStart() + (curPosition_ >> 9); + } else { + uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); + if (gfOffset == 0 && blockOfCluster == 0) { + // start of new cluster + if (curPosition_ == 0) { + // use first cluster in file + curCluster_ = firstCluster_; + } else { + // get next cluster from FAT + if (!vol_->fatGet(curCluster_, &curCluster_)) return false; + } + } + gfBlock = vol_->clusterStartBlock(curCluster_) + blockOfCluster; + } + return true; +} + //------------------------------------------------------------------------------ /** Write data to an open file. * diff --git a/Firmware/SdFile.h b/Firmware/SdFile.h index 60e2f5deb..465224623 100644 --- a/Firmware/SdFile.h +++ b/Firmware/SdFile.h @@ -34,7 +34,24 @@ * \brief SdBaseFile with Print. */ class SdFile : public SdBaseFile/*, public Print*/ { - public: + // GCode filtering vars and methods - due to optimization reasons not wrapped in a separate class + + // beware - this read ptr is manipulated inside just 2 methods - readFilteredGcode and gfReset + // If you even want to call gfReset from readFilteredGcode, you must make sure + // to update gfReadPtr inside readFilteredGcode from a local copy (see explanation of this trick in readFilteredGcode) + const uint8_t *gfReadPtr; + + uint32_t gfBlock; // remember the current file block to be kept in cache - due to reuse of the memory, the block may fall out a must be read back + uint16_t gfOffset; + + const uint8_t *gfBlockBuffBegin()const; + + void gfReset(); + + bool gfEnsureBlock(); + bool gfComputeNextFileBlock(); + void gfUpdateCurrentPosition(uint16_t inc); +public: SdFile() {} SdFile(const char* name, uint8_t oflag); #if ARDUINO >= 100 @@ -43,6 +60,9 @@ class SdFile : public SdBaseFile/*, public Print*/ { void write(uint8_t b); #endif + bool openFilteredGcode(SdBaseFile* dirFile, const char* path); + int16_t readFilteredGcode(); + bool seekSetFilteredGcode(uint32_t pos); int16_t write(const void* buf, uint16_t nbyte); void write(const char* str); void write_P(PGM_P str); @@ -51,4 +71,4 @@ class SdFile : public SdBaseFile/*, public Print*/ { #endif // SdFile_h -#endif \ No newline at end of file +#endif diff --git a/Firmware/SdVolume.h b/Firmware/SdVolume.h index 2ff2b6eb9..17699190e 100644 --- a/Firmware/SdVolume.h +++ b/Firmware/SdVolume.h @@ -36,7 +36,7 @@ */ union cache_t { /** Used to access cached file data blocks. */ - uint8_t data[512]; + uint8_t data[512 + 1]; // abuse the last byte for saving '\n' - ugly optimization of read_filtered's inner skipping loop /** Used to access cached FAT16 entries. */ uint16_t fat16[256]; /** Used to access cached FAT32 entries. */ @@ -119,6 +119,7 @@ class SdVolume { bool dbgFat(uint32_t n, uint32_t* v) {return fatGet(n, v);} //------------------------------------------------------------------------------ private: + friend class SdFile; // Allow SdBaseFile access to SdVolume private data. friend class SdBaseFile; @@ -211,4 +212,4 @@ class SdVolume { #endif // ALLOW_DEPRECATED_FUNCTIONS }; #endif // SdVolume -#endif \ No newline at end of file +#endif diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp index a96268972..6fe890095 100644 --- a/Firmware/cardreader.cpp +++ b/Firmware/cardreader.cpp @@ -32,6 +32,7 @@ CardReader::CardReader() workDirDepth = 0; file_subcall_ctr=0; memset(workDirParents, 0, sizeof(workDirParents)); + presort_flag = false; autostart_stilltocheck=true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software. lastnr=0; @@ -69,12 +70,23 @@ char *createFilename(char *buffer,const dir_t &p) //buffer>12characters +*/ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) { + static uint8_t recursionCnt = 0; + // RAII incrementer for the recursionCnt + class _incrementer + { + public: + _incrementer() {recursionCnt++;} + ~_incrementer() {recursionCnt--;} + } recursionCntIncrementer; + dir_t p; uint8_t cnt = 0; // Read the next entry from a directory while (parent.readDir(p, longFilename) > 0) { - // If the entry is a directory and the action is LS_SerialPrint - if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { + 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 + // Get the short name for the item, which we know is a folder char lfilename[FILENAME_LENGTH]; createFilename(lfilename, p); @@ -241,18 +253,18 @@ void CardReader::initsd() } -void CardReader::setroot() +void CardReader::setroot(bool doPresort) { - /*if(!workDir.openRoot(&volume)) - { - SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL); - }*/ workDir=root; + workDirDepth = 0; curDir=&workDir; - #ifdef SDCARD_SORT_ALPHA - presort(); - #endif +#ifdef SDCARD_SORT_ALPHA + if (doPresort) + presort(); + else + presort_flag = true; +#endif } void CardReader::release() { @@ -277,7 +289,7 @@ void CardReader::startFileprint() void CardReader::openLogFile(const char* name) { logging = true; - openFile(name, false); + openFileWrite(name); } void CardReader::getDirName(char* name, uint8_t level) @@ -304,6 +316,18 @@ void CardReader::getAbsFilename(char *t) else t[0]=0; } + +void CardReader::printAbsFilenameFast() +{ + SERIAL_PROTOCOL('/'); + for (uint8_t i = 0; i < getWorkDirDepth(); i++) + { + SERIAL_PROTOCOL(dir_names[i]); + SERIAL_PROTOCOL('/'); + } + SERIAL_PROTOCOL(LONGEST_FILENAME); +} + /** * @brief Dive into subfolder * @@ -317,19 +341,17 @@ void CardReader::getAbsFilename(char *t) * @param[in,out] fileName * expects file name including path * in case of absolute path, file name without path is returned - * @param[in,out] dir SdFile object to operate with, - * in case of absolute path, curDir is modified to point to dir, - * so it is not possible to create on stack inside this function, - * as curDir would point to destroyed object. */ -void CardReader::diveSubfolder (const char *fileName, SdFile& dir) +bool CardReader::diveSubfolder (const char *&fileName) { curDir=&root; - if (!fileName) return; + if (!fileName) + return 1; const char *dirname_start, *dirname_end; if (fileName[0] == '/') // absolute path { + setroot(false); dirname_start = fileName + 1; while (*dirname_start) { @@ -340,23 +362,13 @@ void CardReader::diveSubfolder (const char *fileName, SdFile& dir) { const size_t maxLen = 12; char subdirname[maxLen+1]; - subdirname[maxLen] = 0; const size_t len = ((static_cast(dirname_end-dirname_start))>maxLen) ? maxLen : (dirname_end-dirname_start); strncpy(subdirname, dirname_start, len); - SERIAL_ECHOLN(subdirname); - if (!dir.open(curDir, subdirname, O_READ)) - { - SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL); - SERIAL_PROTOCOL(subdirname); - SERIAL_PROTOCOLLN('.'); - return; - } - else - { - //SERIAL_ECHOLN("dive ok"); - } + subdirname[len] = 0; + if (!chdir(subdirname, false)) + return 0; - curDir = &dir; + curDir = &workDir; dirname_start = dirname_end + 1; } else // the reminder after all /fsa/fdsa/ is the filename @@ -373,100 +385,142 @@ void CardReader::diveSubfolder (const char *fileName, SdFile& dir) { curDir = &workDir; } + return 1; } -void CardReader::openFile(const char* name,bool read, bool replace_current/*=true*/) -{ - if(!cardOK) - return; - if(file.isOpen()) //replacing current file by new file, or subfile call - { - if(!replace_current) - { - if((int)file_subcall_ctr>(int)SD_PROCEDURE_DEPTH-1) - { - // SERIAL_ERROR_START; - // SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:"); - // SERIAL_ERRORLN(SD_PROCEDURE_DEPTH); - kill(_n("trying to call sub-gcode files with too many levels."), 1); - return; - } - - SERIAL_ECHO_START; - SERIAL_ECHOPGM("SUBROUTINE CALL target:\""); - SERIAL_ECHO(name); - SERIAL_ECHOPGM("\" parent:\""); - - //store current filename and position - getAbsFilename(filenames[file_subcall_ctr]); - - SERIAL_ECHO(filenames[file_subcall_ctr]); - SERIAL_ECHOPGM("\" pos"); - SERIAL_ECHOLN(sdpos); - filespos[file_subcall_ctr]=sdpos; - file_subcall_ctr++; - } - else - { - SERIAL_ECHO_START; - SERIAL_ECHOPGM("Now doing file: "); - SERIAL_ECHOLN(name); - } - file.close(); - } - else //opening fresh file - { - file_subcall_ctr=0; //resetting procedure depth in case user cancels print while in procedure - SERIAL_ECHO_START; - SERIAL_ECHOPGM("Now fresh file: "); - SERIAL_ECHOLN(name); - } - sdprinting = false; +static const char ofKill[] PROGMEM = "trying to call sub-gcode files with too many levels."; +static const char ofSubroutineCallTgt[] PROGMEM = "SUBROUTINE CALL target:\""; +static const char ofParent[] PROGMEM = "\" parent:\""; +static const char ofPos[] PROGMEM = "\" pos"; +static const char ofNowDoingFile[] PROGMEM = "Now doing file: "; +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 ofWritingToFile[] PROGMEM = "Writing to file: "; - SdFile myDir; - const char *fname=name; - diveSubfolder(fname,myDir); - - if(read) - { - if (file.open(curDir, fname, O_READ)) - { - filesize = file.fileSize(); - SERIAL_PROTOCOLRPGM(_N("File opened: "));////MSG_SD_FILE_OPENED - SERIAL_PROTOCOL(fname); - SERIAL_PROTOCOLRPGM(_n(" Size: "));////MSG_SD_SIZE - SERIAL_PROTOCOLLN(filesize); - sdpos = 0; - - SERIAL_PROTOCOLLNRPGM(_N("File selected"));////MSG_SD_FILE_SELECTED - getfilename(0, fname); - lcd_setstatus(longFilename[0] ? longFilename : fname); - lcd_setstatuspgm(PSTR("SD-PRINTING")); +void CardReader::openFileReadFilteredGcode(const char* name, bool replace_current/* = false*/){ + if(!cardOK) + return; + + if(file.isOpen()){ //replacing current file by new file, or subfile call + if(!replace_current){ + if((int)file_subcall_ctr>(int)SD_PROCEDURE_DEPTH-1){ + // SERIAL_ERROR_START; + // SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:"); + // SERIAL_ERRORLN(SD_PROCEDURE_DEPTH); + kill(ofKill, 1); + return; + } + + SERIAL_ECHO_START; + SERIAL_ECHORPGM(ofSubroutineCallTgt); + SERIAL_ECHO(name); + SERIAL_ECHORPGM(ofParent); + + //store current filename and position + getAbsFilename(filenames[file_subcall_ctr]); + + SERIAL_ECHO(filenames[file_subcall_ctr]); + SERIAL_ECHORPGM(ofPos); + SERIAL_ECHOLN(sdpos); + filespos[file_subcall_ctr]=sdpos; + file_subcall_ctr++; + } else { + SERIAL_ECHO_START; + SERIAL_ECHORPGM(ofNowDoingFile); + SERIAL_ECHOLN(name); + } + file.close(); + } else { //opening fresh file + file_subcall_ctr=0; //resetting procedure depth in case user cancels print while in procedure + SERIAL_ECHO_START; + SERIAL_ECHORPGM(ofNowFreshFile); + SERIAL_ECHOLN(name); } - else - { - SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL); - SERIAL_PROTOCOL(fname); - SERIAL_PROTOCOLLN('.'); - } - } - else - { //write - if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) - { - SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL); - SERIAL_PROTOCOL(fname); - SERIAL_PROTOCOLLN('.'); - } - else - { - saving = true; - SERIAL_PROTOCOLRPGM(_N("Writing to file: "));////MSG_SD_WRITE_TO_FILE - SERIAL_PROTOCOLLN(name); - lcd_setstatus(fname); - } - } + sdprinting = false; + const char *fname=name; + if (!diveSubfolder(fname)) + return; + + if (file.openFilteredGcode(curDir, fname)) { + filesize = file.fileSize(); + SERIAL_PROTOCOLRPGM(ofFileOpened);////MSG_SD_FILE_OPENED + SERIAL_PROTOCOL(fname); + 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); + } else { + SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL); + SERIAL_PROTOCOL(fname); + SERIAL_PROTOCOLLN('.'); + } +} + +void CardReader::openFileWrite(const char* name) +{ + if(!cardOK) + return; + if(file.isOpen()){ //replacing current file by new file, or subfile call +#if 0 + // I doubt chained files support is necessary for file saving: + // Intentionally disabled because it takes a lot of code size while being not used + + if((int)file_subcall_ctr>(int)SD_PROCEDURE_DEPTH-1){ + // SERIAL_ERROR_START; + // SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:"); + // SERIAL_ERRORLN(SD_PROCEDURE_DEPTH); + kill(ofKill, 1); + return; + } + + SERIAL_ECHO_START; + SERIAL_ECHORPGM(ofSubroutineCallTgt); + SERIAL_ECHO(name); + SERIAL_ECHORPGM(ofParent); + + //store current filename and position + getAbsFilename(filenames[file_subcall_ctr]); + + SERIAL_ECHO(filenames[file_subcall_ctr]); + SERIAL_ECHORPGM(ofPos); + SERIAL_ECHOLN(sdpos); + filespos[file_subcall_ctr]=sdpos; + file_subcall_ctr++; + file.close(); +#else + SERIAL_ECHOLNPGM("File already opened"); +#endif + } else { //opening fresh file + file_subcall_ctr=0; //resetting procedure depth in case user cancels print while in procedure + SERIAL_ECHO_START; + SERIAL_ECHORPGM(ofNowFreshFile); + SERIAL_ECHOLN(name); + } + sdprinting = false; + + const char *fname=name; + if (!diveSubfolder(fname)) + return; + + //write + if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)){ + SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL); + SERIAL_PROTOCOL(fname); + SERIAL_PROTOCOLLN('.'); + } else { + saving = true; + SERIAL_PROTOCOLRPGM(ofWritingToFile);////MSG_SD_WRITE_TO_FILE + SERIAL_PROTOCOLLN(fname); + lcd_setstatus(fname); + } } void CardReader::removeFile(const char* name) @@ -475,9 +529,9 @@ void CardReader::removeFile(const char* name) file.close(); sdprinting = false; - SdFile myDir; const char *fname=name; - diveSubfolder(fname,myDir); + if (!diveSubfolder(fname)) + return; if (file.remove(curDir, fname)) { @@ -515,10 +569,8 @@ void CardReader::getStatus(bool arg_P) { if (arg_P) { - SERIAL_PROTOCOL('/'); - for (uint8_t i = 0; i < getWorkDirDepth(); i++) - printf_P(PSTR("%s/"), dir_names[i]); - puts(filename); + printAbsFilenameFast(); + SERIAL_PROTOCOLLN(); } else SERIAL_PROTOCOLLN(LONGEST_FILENAME); @@ -670,7 +722,7 @@ uint16_t CardReader::getnrfilenames() return nrFiles; } -void CardReader::chdir(const char * relpath) +bool CardReader::chdir(const char * relpath, bool doPresort) { SdFile newfile; SdFile *parent=&root; @@ -678,23 +730,32 @@ void CardReader::chdir(const char * relpath) if(workDir.isOpen()) parent=&workDir; - if(!newfile.open(*parent,relpath, O_READ)) + if(!newfile.open(*parent,relpath, O_READ) || ((workDirDepth + 1) >= MAX_DIR_DEPTH)) { SERIAL_ECHO_START; SERIAL_ECHORPGM(_n("Cannot enter subdir: "));////MSG_SD_CANT_ENTER_SUBDIR SERIAL_ECHOLN(relpath); + return 0; } else { + strcpy(dir_names[workDirDepth], relpath); + puts(relpath); + if (workDirDepth < MAX_DIR_DEPTH) { for (int d = ++workDirDepth; d--;) workDirParents[d+1] = workDirParents[d]; workDirParents[0]=*parent; } workDir=newfile; - #ifdef SDCARD_SORT_ALPHA + +#ifdef SDCARD_SORT_ALPHA + if (doPresort) presort(); - #endif + else + presort_flag = true; +#endif + return 1; } } @@ -1011,7 +1072,7 @@ void CardReader::printingHasFinished() { file.close(); file_subcall_ctr--; - openFile(filenames[file_subcall_ctr],true,true); + openFileReadFilteredGcode(filenames[file_subcall_ctr],true); setIndex(filespos[file_subcall_ctr]); startFileprint(); } diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h index 9bf9bd0a6..c79420737 100644 --- a/Firmware/cardreader.h +++ b/Firmware/cardreader.h @@ -1,6 +1,8 @@ #ifndef CARDREADER_H #define CARDREADER_H +#define SDSUPPORT + #ifdef SDSUPPORT #define MAX_DIR_DEPTH 6 @@ -19,7 +21,8 @@ public: //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset void checkautostart(bool x); - void openFile(const char* name,bool read,bool replace_current=true); + void openFileWrite(const char* name); + void openFileReadFilteredGcode(const char* name, bool replace_current = false); void openLogFile(const char* name); void removeFile(const char* name); void closefile(bool store_location=false); @@ -34,14 +37,15 @@ public: uint16_t getnrfilenames(); void getAbsFilename(char *t); + void printAbsFilenameFast(); void getDirName(char* name, uint8_t level); uint16_t getWorkDirDepth(); void ls(bool printLFN); - void chdir(const char * relpath); + bool chdir(const char * relpath, bool doPresort); void updir(); - void setroot(); + void setroot(bool doPresort); #ifdef SDCARD_SORT_ALPHA void presort(); @@ -58,9 +62,11 @@ public: #endif FORCE_INLINE bool isFileOpen() { return file.isOpen(); } - FORCE_INLINE bool eof() { return sdpos>=filesize ;}; - FORCE_INLINE int16_t get() { sdpos = file.curPosition();return (int16_t)file.read();}; - FORCE_INLINE void setIndex(long index) {sdpos = index;file.seekSet(index);}; + bool eof() { return sdpos>=filesize; } + // There may be a potential performance problem - when the comment reading fails, sdpos points to the last correctly read character. + // However, repeated reading (e.g. after power panic) the comment will be read again - it should survive correctly, it will just take a few moments to skip + FORCE_INLINE int16_t getFilteredGcodeChar() { sdpos = file.curPosition();return (int16_t)file.readFilteredGcode();}; + void setIndex(long index) {sdpos = index;file.seekSetFilteredGcode(index);}; FORCE_INLINE uint8_t percentDone(){if(!isFileOpen()) return 0; if(filesize) return sdpos/((filesize+99)/100); else return 0;}; FORCE_INLINE char* getWorkDirName(){workDir.getFilename(filename);return filename;}; FORCE_INLINE uint32_t get_sdpos() { if (!isFileOpen()) return 0; else return(sdpos); }; @@ -82,6 +88,10 @@ public: char longFilename[LONG_FILENAME_LENGTH]; bool filenameIsDir; int lastnr; //last number of the autostart; +#ifdef SDCARD_SORT_ALPHA + bool presort_flag; + char dir_names[MAX_DIR_DEPTH][9]; +#endif // SDCARD_SORT_ALPHA private: SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH]; uint16_t workDirDepth; @@ -155,7 +165,7 @@ private: int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory. char* diveDirName; - void diveSubfolder (const char *fileName, SdFile& dir); + bool diveSubfolder (const char *&fileName); void lsDive(const char *prepend, SdFile parent, const char * const match=NULL); #ifdef SDCARD_SORT_ALPHA void flush_presort(); diff --git a/Firmware/cmdqueue.cpp b/Firmware/cmdqueue.cpp index afdddfba2..9c822dab5 100755 --- a/Firmware/cmdqueue.cpp +++ b/Firmware/cmdqueue.cpp @@ -584,13 +584,14 @@ void get_command() sd_count.value = 0; // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer. while( !card.eof() && !stop_buffering) { - int16_t n=card.get(); + int16_t n=card.getFilteredGcodeChar(); char serial_char = (char)n; - if(serial_char == '\n' || - serial_char == '\r' || - ((serial_char == '#' || serial_char == ':') && comment_mode == false) || - serial_count >= (MAX_CMD_SIZE - 1) || n==-1) - { + if( serial_char == '\n' + || serial_char == '\r' + || ((serial_char == '#' || serial_char == ':') ) + || serial_count >= (MAX_CMD_SIZE - 1) + || n==-1 + ){ if(serial_char=='#') stop_buffering=true; @@ -601,8 +602,7 @@ void get_command() // read from the sdcard into sd_count, // so that the lenght of the already read empty lines and comments will be added // to the following non-empty line. - comment_mode = false; - continue; //if empty line + return; // prevent cycling indefinitely - let manage_heaters do their job } // The new command buffer could be updated non-atomically, because it is not yet considered // to be inside the active queue. @@ -618,10 +618,10 @@ void get_command() // MYSERIAL.print(sd_count.value, DEC); // SERIAL_ECHOPGM(") "); // SERIAL_ECHOLN(cmdbuffer+bufindw+CMDHDRSIZE); -// SERIAL_ECHOPGM("cmdbuffer:"); -// MYSERIAL.print(cmdbuffer); -// SERIAL_ECHOPGM("buflen:"); -// MYSERIAL.print(buflen+1); +// SERIAL_ECHOPGM("cmdbuffer:"); +// MYSERIAL.print(cmdbuffer); +// SERIAL_ECHOPGM("buflen:"); +// MYSERIAL.print(buflen+1); sd_count.value = 0; cli(); @@ -640,15 +640,15 @@ void get_command() serial_count = 0; //clear buffer if(card.eof()) break; - + // The following line will reserve buffer space if available. if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true)) return; } else { - if(serial_char == ';') comment_mode = true; - else if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; + // there are no comments coming from the filtered file + cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; } } if(card.eof()) diff --git a/Firmware/mesh_bed_calibration.cpp b/Firmware/mesh_bed_calibration.cpp index a0efc3aae..fb79022ff 100644 --- a/Firmware/mesh_bed_calibration.cpp +++ b/Firmware/mesh_bed_calibration.cpp @@ -944,7 +944,7 @@ static inline void update_current_position_z() // At the current position, find the Z stop. -inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int +bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int #ifdef SUPPORT_VERBOSITY verbosity_level #endif //SUPPORT_VERBOSITY @@ -1065,7 +1065,7 @@ error: } #ifdef NEW_XYZCAL -extern bool xyzcal_find_bed_induction_sensor_point_xy(); +bool xyzcal_find_bed_induction_sensor_point_xy(); #endif //NEW_XYZCAL // Search around the current_position[X,Y], // look for the induction sensor response. @@ -1081,7 +1081,7 @@ extern bool xyzcal_find_bed_induction_sensor_point_xy(); #endif //HEATBED_V2 #ifdef HEATBED_V2 -inline bool find_bed_induction_sensor_point_xy(int +bool find_bed_induction_sensor_point_xy(int #if !defined (NEW_XYZCAL) && defined (SUPPORT_VERBOSITY) verbosity_level #endif @@ -1335,7 +1335,7 @@ inline bool find_bed_induction_sensor_point_xy(int #endif //NEW_XYZCAL } #else //HEATBED_V2 -inline bool find_bed_induction_sensor_point_xy(int verbosity_level) +bool find_bed_induction_sensor_point_xy(int verbosity_level) { #ifdef NEW_XYZCAL return xyzcal_find_bed_induction_sensor_point_xy(); diff --git a/Firmware/mesh_bed_calibration.h b/Firmware/mesh_bed_calibration.h index 8adc1c119..7ca93c953 100644 --- a/Firmware/mesh_bed_calibration.h +++ b/Firmware/mesh_bed_calibration.h @@ -146,9 +146,9 @@ inline bool world2machine_clamp(float &x, float &y) return clamped; } -extern bool find_bed_induction_sensor_point_z(float minimum_z = -10.f, uint8_t n_iter = 3, int verbosity_level = 0); -extern bool find_bed_induction_sensor_point_xy(int verbosity_level = 0); -extern void go_home_with_z_lift(); +bool find_bed_induction_sensor_point_z(float minimum_z = -10.f, uint8_t n_iter = 3, int verbosity_level = 0); +bool find_bed_induction_sensor_point_xy(int verbosity_level = 0); +void go_home_with_z_lift(); /** * @brief Bed skew and offest detection result diff --git a/Firmware/messages.c b/Firmware/messages.c index 0b1d58e04..aa05ad990 100644 --- a/Firmware/messages.c +++ b/Firmware/messages.c @@ -16,7 +16,7 @@ const char MSG_BED_DONE[] PROGMEM_I1 = ISTR("Bed done"); //// const char MSG_BED_HEATING[] PROGMEM_I1 = ISTR("Bed Heating"); //// const char MSG_BED_LEVELING_FAILED_POINT_LOW[] PROGMEM_I1 = ISTR("Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset."); ////c=20 r=5 const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED[] PROGMEM_I1 = ISTR("XYZ calibration failed. Please consult the manual."); ////c=20 r=8 -const char MSG_BELT_STATUS[] PROGMEM_I1 = ISTR("Belt Status");////c=18 +const char MSG_BELT_STATUS[] PROGMEM_I1 = ISTR("Belt status");////c=18 const char MSG_CALIBRATE_Z_AUTO[] PROGMEM_I1 = ISTR("Calibrating Z"); ////c=20 r=2 const char MSG_CARD_MENU[] PROGMEM_I1 = ISTR("Print from SD"); //// const char MSG_CHECKING_X[] PROGMEM_I1 = ISTR("Checking X axis"); ////c=20 @@ -29,7 +29,7 @@ const char MSG_CRASHDETECT[] PROGMEM_I1 = ISTR("Crash det."); ////c=13 const char MSG_ERROR[] PROGMEM_I1 = ISTR("ERROR:"); //// const char MSG_EXTRUDER[] PROGMEM_I1 = ISTR("Extruder"); ////c=17 const char MSG_FANS_CHECK[] PROGMEM_I1 = ISTR("Fans check"); ////c=13 -const char MSG_FIL_RUNOUTS[] PROGMEM_I1 = ISTR("Fil. runouts"); ////c=14 +const char MSG_FIL_RUNOUTS[] PROGMEM_I1 = ISTR("Fil. runouts"); ////c=15 const char MSG_FILAMENT[] PROGMEM_I1 = ISTR("Filament"); ////c=17 r=1 const char MSG_FAN_SPEED[] PROGMEM_I1 = ISTR("Fan speed"); ////c=14 const char MSG_FILAMENT_CLEAN[] PROGMEM_I1 = ISTR("Filament extruding & with correct color?"); ////c=20 r=2 @@ -65,14 +65,14 @@ const char MSG_STEEL_SHEETS[] PROGMEM_I1 = ISTR("Steel sheets"); ////c=18 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1[] PROGMEM_I1 = ISTR("Measuring reference height of calibration point"); ////c=60 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2[] PROGMEM_I1 = ISTR(" of 9"); ////c=14 const char MSG_MENU_CALIBRATION[] PROGMEM_I1 = ISTR("Calibration"); //// -const char MSG_MMU_FAILS[] PROGMEM_I1 = ISTR("MMU fails"); ////c=14 -const char MSG_MMU_LOAD_FAILS[] PROGMEM_I1 = ISTR("MMU load fails"); ////c=14 +const char MSG_MMU_FAILS[] PROGMEM_I1 = ISTR("MMU fails"); ////c=15 +const char MSG_MMU_LOAD_FAILS[] PROGMEM_I1 = ISTR("MMU load fails"); ////c=15 const char MSG_NO[] PROGMEM_I1 = ISTR("No"); //// const char MSG_NOZZLE[] PROGMEM_I1 = ISTR("Nozzle"); //// const char MSG_PAPER[] PROGMEM_I1 = ISTR("Place a sheet of paper under the nozzle during the calibration of first 4 points. If the nozzle catches the paper, power off the printer immediately."); ////c=20 r=10 const char MSG_PLACE_STEEL_SHEET[] PROGMEM_I1 = ISTR("Please place steel sheet on heatbed."); ////c=20 r=4 const char MSG_PLEASE_WAIT[] PROGMEM_I1 = ISTR("Please wait"); ////c=20 -const char MSG_POWER_FAILURES[] PROGMEM_I1 = ISTR("Power failures"); ////c=14 +const char MSG_POWER_FAILURES[] PROGMEM_I1 = ISTR("Power failures"); ////c=15 const char MSG_PREHEAT_NOZZLE[] PROGMEM_I1 = ISTR("Preheat the nozzle!"); ////c=20 const char MSG_PRESS_TO_UNLOAD[] PROGMEM_I1 = ISTR("Please press the knob to unload filament"); ////c=20 r=4 const char MSG_PRINT_ABORTED[] PROGMEM_I1 = ISTR("Print aborted"); ////c=20 @@ -131,7 +131,7 @@ const char MSG_MODEL[] PROGMEM_I1 = ISTR("Model"); //// const char MSG_FIRMWARE[] PROGMEM_I1 = ISTR("Firmware"); //// const char MSG_GCODE[] PROGMEM_I1 = ISTR("Gcode"); //// const char MSG_GCODE_DIFF_PRINTER_CONTINUE[] PROGMEM_I1 = ISTR("G-code sliced for a different printer type. Continue?"); ////c=20 r=5 -const char MSG_GCODE_DIFF_PRINTER_CANCELLED[] PROGMEM_I1 =ISTR("G-code sliced for a different printer type. Please re-slice the model again. Print cancelled."); ////c=20 r=6 +const char MSG_GCODE_DIFF_PRINTER_CANCELLED[] PROGMEM_I1 =ISTR("G-code sliced for a different printer type. Please re-slice the model again. Print cancelled."); ////c=20 r=7 const char MSG_NOZZLE_DIAMETER[] PROGMEM_I1 = ISTR("Nozzle d."); //// const char MSG_MMU_MODE[] PROGMEM_I1 = ISTR("MMU Mode"); //// const char MSG_SD_CARD[] PROGMEM_I1 = ISTR("SD card"); //// @@ -197,3 +197,4 @@ 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 0a05c58f5..a5b672fa2 100644 --- a/Firmware/messages.h +++ b/Firmware/messages.h @@ -197,6 +197,7 @@ 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 c2b6600fb..7e5054fff 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -57,7 +57,7 @@ int scrollstuff = 0; char longFilenameOLD[LONG_FILENAME_LENGTH]; - +int clock_interval = 0; static void lcd_sd_updir(); static void lcd_mesh_bed_leveling_settings(); @@ -75,11 +75,6 @@ int8_t FSensorStateMenu = 1; bool bMenuFSDetect=false; #endif //IR_SENSOR_ANALOG - -#ifdef SDCARD_SORT_ALPHA -bool presort_flag = false; -#endif - LcdCommands lcd_commands_type = LcdCommands::Idle; static uint8_t lcd_commands_step = 0; @@ -676,185 +671,219 @@ void lcdui_print_cmd_diag(void) // Print time (8 chars total) void lcdui_print_time(void) { - //if remaining print time estimation is available print it else print elapsed time - uint16_t print_t = 0; - if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) - print_t = print_time_remaining(); - else if(starttime != 0) - print_t = _millis() / 60000 - starttime / 60000; - int chars = 0; - if ((PRINTER_ACTIVE) && ((print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) || (starttime != 0))) - { - char suff = ' '; - char suff_doubt = ' '; - if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) - { - suff = 'R'; - if (feedmultiply != 100) - suff_doubt = '?'; - } - if (print_t < 6000) //time<100h - chars = lcd_printf_P(_N("%c%02u:%02u%c%c"), LCD_STR_CLOCK[0], print_t / 60, print_t % 60, suff, suff_doubt); - else //time>=100h - chars = lcd_printf_P(_N("%c%3uh %c%c"), LCD_STR_CLOCK[0], print_t / 60, suff, suff_doubt); - } - else - chars = lcd_printf_P(_N("%c--:-- "), LCD_STR_CLOCK[0]); - lcd_space(8 - chars); + //if remaining print time estimation is available print it else print elapsed time + int chars = 0; + if ((PRINTER_ACTIVE) && (starttime != 0)) + { + uint16_t print_t = 0; + uint16_t print_tr = 0; + uint16_t print_tc = 0; + char suff = ' '; + char suff_doubt = ' '; + +#ifdef TMC2130 + if (SilentModeMenu != SILENT_MODE_OFF) + { + if (print_time_remaining_silent != PRINT_TIME_REMAINING_INIT) + { + print_tr = print_time_remaining_silent; + } +//#ifdef CLOCK_INTERVAL_TIME + if (print_time_to_change_silent != PRINT_TIME_REMAINING_INIT) + { + print_tc = print_time_to_change_silent; + } +//#endif //CLOCK_INTERVAL_TIME + } + else + { +#endif //TMC2130 + if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) + { + print_tr = print_time_remaining_normal; + } +//#ifdef CLOCK_INTERVAL_TIME + if (print_time_to_change_normal != PRINT_TIME_REMAINING_INIT) + { + print_tc = print_time_to_change_normal; + } +//#endif //CLOCK_INTERVAL_TIME +#ifdef TMC2130 + } +#endif //TMC2130 + +//#ifdef CLOCK_INTERVAL_TIME + if (clock_interval == CLOCK_INTERVAL_TIME*2) + { + clock_interval = 0; + } + clock_interval++; + + if (print_tc != 0 && clock_interval > CLOCK_INTERVAL_TIME) + { + print_t = print_tc; + suff = 'C'; + } + else +//#endif //CLOCK_INTERVAL_TIME + if (print_tr != 0) + { + print_t = print_tr; + suff = 'R'; + } + else + { + print_t = _millis() / 60000 - starttime / 60000; + } + + if (feedmultiply != 100 && (print_t == print_tr || print_t == print_tc)) + { + suff_doubt = '?'; + print_t = 100ul * print_t / feedmultiply; + } + + if (print_t < 6000) //time<100h + chars = lcd_printf_P(_N("%c%02u:%02u%c%c"), LCD_STR_CLOCK[0], print_t / 60, print_t % 60, suff, suff_doubt); + else //time>=100h + chars = lcd_printf_P(_N("%c%3uh %c%c"), LCD_STR_CLOCK[0], print_t / 60, suff, suff_doubt); + } + else + chars = lcd_printf_P(_N("%c--:-- "), LCD_STR_CLOCK[0]); + lcd_space(8 - chars); } -//Print status line on status screen +//! @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 (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) - { - heating_status_counter = 0; - } - lcd_set_cursor(7, 3); - lcd_space(13); + if (heating_status) { // If heating flag, show progress of heating + heating_status_counter++; + if (heating_status_counter > 13) { + heating_status_counter = 0; + } + lcd_set_cursor(7, 3); + lcd_space(13); + + for (unsigned int dots = 0; dots < heating_status_counter; dots++) { + lcd_putc_at(7 + dots, 3, '.'); + } + switch (heating_status) { + case 1: + lcd_puts_at_P(0, 3, _T(MSG_HEATING)); + break; + case 2: + lcd_puts_at_P(0, 3, _T(MSG_HEATING_COMPLETE)); + heating_status = 0; + heating_status_counter = 0; + break; + case 3: + lcd_puts_at_P(0, 3, _T(MSG_BED_HEATING)); + break; + case 4: + lcd_puts_at_P(0, 3, _T(MSG_BED_DONE)); + heating_status = 0; + heating_status_counter = 0; + break; + default: + break; + } + } + else if ((IS_SD_PRINTING) && (custom_message_type == CustomMsg::Status)) { // If printing from SD, show what we are printing + if(strlen(longFilenameOLD) > LCD_WIDTH) { + int inters = 0; + int gh = scrollstuff; + while (((gh - scrollstuff) < LCD_WIDTH) && (inters == 0)) { + if (longFilenameOLD[gh] == '\0') { + lcd_set_cursor(gh - scrollstuff, 3); + lcd_print(longFilenameOLD[gh - 1]); + scrollstuff = 0; + gh = scrollstuff; + inters = 1; + } else { + lcd_set_cursor(gh - scrollstuff, 3); + lcd_print(longFilenameOLD[gh - 1]); + gh++; + } + } + scrollstuff++; + } else { + lcd_printf_P(PSTR("%-20s"), longFilenameOLD); + } + } else { // Otherwise check for other special events + switch (custom_message_type) { + case CustomMsg::MsgUpdate: //Short message even while printing from SD + case CustomMsg::Status: // Nothing special, print status message normally + case CustomMsg::M0Wait: // M0/M1 Wait command working even from SD + lcd_print(lcd_status_message); + break; + case CustomMsg::MeshBedLeveling: // If mesh bed leveling in progress, show the status + if (custom_message_state > 10) { + lcd_set_cursor(0, 3); + lcd_space(20); + lcd_puts_at_P(0, 3, _T(MSG_CALIBRATE_Z_AUTO)); + lcd_puts_P(PSTR(" : ")); + lcd_print(custom_message_state-10); + } else { + if (custom_message_state == 3) + { + lcd_puts_P(_T(WELCOME_MSG)); + lcd_setstatuspgm(_T(WELCOME_MSG)); + custom_message_type = CustomMsg::Status; + } + if (custom_message_state > 3 && custom_message_state <= 10 ) { + lcd_set_cursor(0, 3); + lcd_space(19); + lcd_puts_at_P(0, 3, _i("Calibration done"));////MSG_HOMEYZ_DONE + custom_message_state--; + } + } + break; + case CustomMsg::FilamentLoading: // If loading filament, print status + lcd_print(lcd_status_message); + break; + case CustomMsg::PidCal: // PID tuning in progress + lcd_print(lcd_status_message); + if (pid_cycle <= pid_number_of_cycles && custom_message_state > 0) { + lcd_set_cursor(10, 3); + lcd_print(itostr3(pid_cycle)); + lcd_print('/'); + lcd_print(itostr3left(pid_number_of_cycles)); + } + break; + case CustomMsg::TempCal: // PINDA temp calibration in progress + char statusLine[LCD_WIDTH + 1]; + sprintf_P(statusLine, PSTR("%-20S"), _T(MSG_TEMP_CALIBRATION)); + char progress[4]; + sprintf_P(progress, PSTR("%d/6"), custom_message_state); + memcpy(statusLine + 12, progress, sizeof(progress) - 1); + lcd_set_cursor(0, 3); + lcd_print(statusLine); + break; + case CustomMsg::TempCompPreheat: // temp compensation preheat + lcd_puts_at_P(0, 3, _i("PINDA Heating"));////MSG_PINDA_PREHEAT c=20 r=1 + if (custom_message_state <= PINDA_HEAT_T) { + lcd_puts_P(PSTR(": ")); + lcd_print(custom_message_state); //seconds + lcd_print(' '); + } + break; + case CustomMsg::Resuming: //Resuming + lcd_puts_at_P(0, 3, _T(MSG_RESUMING_PRINT)); + break; + } + } - for (unsigned int dots = 0; dots < heating_status_counter; dots++) - { - lcd_putc_at(7 + dots, 3, '.'); - } - switch (heating_status) - { - case 1: - lcd_puts_at_P(0, 3, _T(MSG_HEATING)); - break; - case 2: - lcd_puts_at_P(0, 3, _T(MSG_HEATING_COMPLETE)); - heating_status = 0; - heating_status_counter = 0; - break; - case 3: - lcd_puts_at_P(0, 3, _T(MSG_BED_HEATING)); - break; - case 4: - lcd_puts_at_P(0, 3, _T(MSG_BED_DONE)); - heating_status = 0; - heating_status_counter = 0; - break; - default: - break; - } - } - else if ((IS_SD_PRINTING) && (custom_message_type == CustomMsg::Status)) - { // If printing from SD, show what we are printing - if(strlen(longFilenameOLD) > LCD_WIDTH) - { - int inters = 0; - int gh = scrollstuff; - while (((gh - scrollstuff) < LCD_WIDTH) && (inters == 0)) - { - if (longFilenameOLD[gh] == '\0') - { - lcd_set_cursor(gh - scrollstuff, 3); - lcd_print(longFilenameOLD[gh - 1]); - scrollstuff = 0; - gh = scrollstuff; - inters = 1; - } - else - { - lcd_set_cursor(gh - scrollstuff, 3); - lcd_print(longFilenameOLD[gh - 1]); - gh++; - } - } - scrollstuff++; - } - else - { - lcd_printf_P(PSTR("%-20s"), longFilenameOLD); - } - } - else - { // Otherwise check for other special events - switch (custom_message_type) - { - case CustomMsg::Status: // Nothing special, print status message normally - lcd_print(lcd_status_message); - break; - case CustomMsg::MeshBedLeveling: // If mesh bed leveling in progress, show the status - if (custom_message_state > 10) - { - lcd_set_cursor(0, 3); - lcd_space(20); - lcd_puts_at_P(0, 3, _T(MSG_CALIBRATE_Z_AUTO)); - lcd_puts_P(PSTR(" : ")); - lcd_print(custom_message_state-10); - } - else - { - if (custom_message_state == 3) - { - lcd_puts_P(_T(WELCOME_MSG)); - lcd_setstatuspgm(_T(WELCOME_MSG)); - custom_message_type = CustomMsg::Status; - } - if (custom_message_state > 3 && custom_message_state <= 10 ) - { - lcd_set_cursor(0, 3); - lcd_space(19); - lcd_puts_at_P(0, 3, _i("Calibration done"));////MSG_HOMEYZ_DONE - custom_message_state--; - } - } - break; - case CustomMsg::FilamentLoading: // If loading filament, print status - lcd_print(lcd_status_message); - break; - case CustomMsg::PidCal: // PID tuning in progress - lcd_print(lcd_status_message); - if (pid_cycle <= pid_number_of_cycles && custom_message_state > 0) - { - lcd_set_cursor(10, 3); - lcd_print(itostr3(pid_cycle)); - lcd_print('/'); - lcd_print(itostr3left(pid_number_of_cycles)); - } - break; - case CustomMsg::TempCal: // PINDA temp calibration in progress - { - char statusLine[LCD_WIDTH + 1]; - sprintf_P(statusLine, PSTR("%-20S"), _T(MSG_TEMP_CALIBRATION)); - char progress[4]; - sprintf_P(progress, PSTR("%d/6"), custom_message_state); - memcpy(statusLine + 12, progress, sizeof(progress) - 1); - lcd_set_cursor(0, 3); - lcd_print(statusLine); - } - break; - case CustomMsg::TempCompPreheat: // temp compensation preheat - lcd_puts_at_P(0, 3, _i("PINDA Heating"));////MSG_PINDA_PREHEAT c=20 r=1 - if (custom_message_state <= PINDA_HEAT_T) - { - lcd_puts_P(PSTR(": ")); - lcd_print(custom_message_state); //seconds - lcd_print(' '); - } - break; - } - } - // Fill the rest of line to have nice and clean output - for(int fillspace = 0; fillspace < 20; fillspace++) - if ((lcd_status_message[fillspace] <= 31 )) - lcd_print(' '); + for(int fillspace = 0; fillspace < 20; fillspace++) + if ((lcd_status_message[fillspace] <= 31 )) + lcd_print(' '); } //! @brief Show Status Screen @@ -1584,8 +1613,8 @@ static void pgmtext_with_colon(const char *ipgmLabel, char *dst, uint8_t dstSize //! |01234567890123456789| //! |Nozzle FAN: 0000 RPM| FAN c=10 r=1 SPEED c=3 r=1 //! |Print FAN: 0000 RPM| FAN c=10 r=1 SPEED c=3 r=1 -//! |Fil. Xd:000 Yd:000 | Fil. c=4 r=1 -//! |Int: 000 Shut: 000 | Int: c=4 r=1 Shut: c=4 r=1 +//! | | +//! | | //! ---------------------- //! @endcode //! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations. @@ -1599,37 +1628,7 @@ void lcd_menu_extruder_info() // NOT static due to using ins char nozzle[maxChars], print[maxChars]; pgmtext_with_colon(_i("Nozzle FAN"), nozzle, maxChars); ////c=10 r=1 pgmtext_with_colon(_i("Print FAN"), print, maxChars); ////c=10 r=1 - lcd_printf_P(_N("%s %4d RPM\n" "%s %4d RPM\n"), nozzle, 60*fan_speed[0], print, 60*fan_speed[1] ); - -#ifdef PAT9125 - // Display X and Y difference from Filament sensor - // Display Light intensity from Filament sensor - // Frame_Avg register represents the average brightness of all pixels within a frame (324 pixels). This - // value ranges from 0(darkest) to 255(brightest). - // Display LASER shutter time from Filament sensor - // Shutter register is an index of LASER shutter time. It is automatically controlled by the chip's internal - // auto-exposure algorithm. When the chip is tracking on a good reflection surface, the Shutter is small. - // When the chip is tracking on a poor reflection surface, the Shutter is large. Value ranges from 0 to 46. - if (mmu_enabled == false) - { - if (!fsensor_enabled) - lcd_puts_P(_N("Filament sensor\n" "is disabled.")); - else - { - if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal)) - pat9125_update(); - lcd_printf_P(_N( - "Fil. Xd:%3d Yd:%3d\n" ////c=4 r=1 - "Int: %3d " ////c=4 r=1 - "Shut: %3d" ////c=4 r=1 - ), - pat9125_x, pat9125_y, - pat9125_b, pat9125_s - ); - } - } -#endif //PAT9125 - + lcd_printf_P(_N("%s %4d RPM\n" "%s %4d RPM\n"), nozzle, 60*fan_speed[0], print, 60*fan_speed[1] ); menu_back_if_clicked(); } @@ -1661,8 +1660,8 @@ static void lcd_menu_fails_stats_mmu() //! @code{.unparsed} //! |01234567890123456789| //! |Last print failures | MSG_LAST_PRINT_FAILURES c=20 -//! | MMU fails: 000| MSG_MMU_FAILS c=14 -//! | MMU load fails: 000| MSG_MMU_LOAD_FAILS c=14 +//! | MMU fails 000| MSG_MMU_FAILS c=15 +//! | MMU load fails 000| MSG_MMU_LOAD_FAILS c=15 //! | | //! ---------------------- //! @endcode @@ -1683,9 +1682,9 @@ static void lcd_menu_fails_stats_mmu_print() //! @code{.unparsed} //! |01234567890123456789| //! |Total failures | MSG_TOTAL_FAILURES c=20 -//! | MMU fails: 000| MSG_MMU_FAILS c=14 -//! | MMU load fails: 000| MSG_MMU_LOAD_FAILS c=14 -//! | MMU power fails:000| c=14 r=1 +//! | MMU fails 000| MSG_MMU_FAILS c=15 +//! | MMU load fails 000| MSG_MMU_LOAD_FAILS c=15 +//! | MMU power fails 000| c=15 //! ---------------------- //! @endcode //! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations. @@ -1710,8 +1709,8 @@ static const char failStatsFmt[] PROGMEM = "%S\n" " %-16.16S%-3d\n" " %-16.16S%- //! @code{.unparsed} //! |01234567890123456789| //! |Total failures | MSG_TOTAL_FAILURES c=20 -//! | Power failures: 000| MSG_POWER_FAILURES c=14 -//! | Fil. runouts : 000| MSG_FIL_RUNOUTS c=14 +//! | Power failures 000| MSG_POWER_FAILURES c=15 +//! | Fil. runouts 000| MSG_FIL_RUNOUTS c=15 //! | Crash X:000 Y:000| MSG_CRASH c=7 //! ---------------------- //! @endcode @@ -1735,9 +1734,9 @@ static void lcd_menu_fails_stats_total() //! @code{.unparsed} //! |01234567890123456789| //! |Last print failures | MSG_LAST_PRINT_FAILURES c=20 -//! | Power failures 000| MSG_POWER_FAILURES c=14 -//! | Fil. runouts 000| MSG_FIL_RUNOUTS c=14 -//! | Crash X:000 Y:000| MSG_CRASH c=7 +//! | Power failures 000| MSG_POWER_FAILURES c=15 +//! | Fil. runouts 000| MSG_FIL_RUNOUTS c=15 +//! | Crash X 000 Y 000| MSG_CRASH c=7 //! ---------------------- //! @endcode //! @brief Show Last Print Failures Statistics with PAT9125 @@ -1763,8 +1762,8 @@ static void lcd_menu_fails_stats_print() #ifndef PAT9125 lcd_printf_P(failStatsFmt, _T(MSG_LAST_PRINT_FAILURES), ////c=20 - _T(MSG_POWER_FAILURES), power, ////c=14 - _T(MSG_FIL_RUNOUTS), filam, ////c=14 + _T(MSG_POWER_FAILURES), power, ////c=15 + _T(MSG_FIL_RUNOUTS), filam, ////c=15 _T(MSG_CRASH), crashX, crashY); ////c=7 #else // On the MK3 include detailed PAT9125 statistics about soft failures @@ -1773,7 +1772,7 @@ static void lcd_menu_fails_stats_print() " %-7.7S H %-3d S %-3d\n" " %-7.7S X %-3d Y %-3d"), _T(MSG_LAST_PRINT_FAILURES), ////c=20 - _T(MSG_POWER_FAILURES), power, ////c=14 + _T(MSG_POWER_FAILURES), power, ////c=15 _i("Runouts"), filam, fsensor_softfail, //c=7 _T(MSG_CRASH), crashX, crashY); ////c=7 #endif @@ -1816,9 +1815,9 @@ static const char failStatsFmt[] PROGMEM = "%S\n" " %-16.16S%-3d\n" "%S\n" " %-1 //! @code{.unparsed} //! |01234567890123456789| //! |Last print failures | MSG_LAST_PRINT_FAILURES c=20 -//! | Fil. runouts 000| MSG_FIL_RUNOUTS c=14 +//! | Fil. runouts 000| MSG_FIL_RUNOUTS c=15 //! |Total failures | MSG_TOTAL_FAILURES c=20 -//! | Fil. runouts 000| MSG_FIL_RUNOUTS c=14 +//! | Fil. runouts 000| MSG_FIL_RUNOUTS c=15 //! ---------------------- //! @endcode //! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations. @@ -1830,9 +1829,9 @@ static void lcd_menu_fails_stats() lcd_home(); lcd_printf_P(failStatsFmt, _T(MSG_LAST_PRINT_FAILURES), ////c=20 - _T(MSG_FIL_RUNOUTS), filamentLast, ////c=14 + _T(MSG_FIL_RUNOUTS), filamentLast, ////c=15 _T(MSG_TOTAL_FAILURES), ////c=20 - _T(MSG_FIL_RUNOUTS), filamentTotal); ////c=14 + _T(MSG_FIL_RUNOUTS), filamentTotal); ////c=15 menu_back_if_clicked(); } @@ -3920,6 +3919,16 @@ static void lcd_print_state(uint8_t state) } } +//! @brief Show sensor state +//! +//! @code{.unparsed} +//! |01234567890123456789| +//! |PINDA N/A FINDA N/A| MSG_PINDA c=6 MSG_FINDA c=6 +//! |Fil. sensor N/A| MSG_FSENSOR +//! |Xd 000 Yd 000| MSG_XD +//! |Int 000 Shut 000| +//! ---------------------- +//! @endcode static void lcd_show_sensors_state() { //0: N/A; 1: OFF; 2: ON @@ -3932,21 +3941,56 @@ static void lcd_show_sensors_state() { finda_state = mmu_finda; } - if (ir_sensor_detected) { - idler_state = !READ(IR_SENSOR_PIN); - } - lcd_puts_at_P(0, 0, _i("Sensor state")); - lcd_puts_at_P(1, 1, _i("PINDA:")); - lcd_set_cursor(LCD_WIDTH - 4, 1); + //lcd_puts_at_P(0, 0, _i("Sensor state")); + lcd_puts_at_P(0, 0, _i("PINDA")); + lcd_set_cursor(LCD_WIDTH - 14, 0); lcd_print_state(pinda_state); - lcd_puts_at_P(1, 2, _i("FINDA:")); - lcd_set_cursor(LCD_WIDTH - 4, 2); - lcd_print_state(finda_state); + if (mmu_enabled == true) + { + lcd_puts_at_P(10, 0, _i("FINDA")); + lcd_set_cursor(LCD_WIDTH - 3, 0); + lcd_print_state(finda_state); + } - lcd_puts_at_P(1, 3, _i("IR:")); - lcd_set_cursor(LCD_WIDTH - 4, 3); - lcd_print_state(idler_state); + if (ir_sensor_detected) { + idler_state = !READ(IR_SENSOR_PIN); + lcd_puts_at_P(0, 1, _i("Fil. sensor")); + lcd_set_cursor(LCD_WIDTH - 3, 1); + lcd_print_state(idler_state); + } + + +#ifdef PAT9125 + // Display X and Y difference from Filament sensor + // Display Light intensity from Filament sensor + // Frame_Avg register represents the average brightness of all pixels within a frame (324 pixels). This + // value ranges from 0(darkest) to 255(brightest). + // Display LASER shutter time from Filament sensor + // Shutter register is an index of LASER shutter time. It is automatically controlled by the chip's internal + // auto-exposure algorithm. When the chip is tracking on a good reflection surface, the Shutter is small. + // When the chip is tracking on a poor reflection surface, the Shutter is large. Value ranges from 0 to 46. + if (mmu_enabled == false) + { + //if (!fsensor_enabled) + // lcd_puts_P(_N("Filament sensor\n" "is disabled.")); + //else + //{ + if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal)) + pat9125_update(); + lcd_set_cursor(0, 2); + lcd_printf_P(_N( + "Xd: %3d " + "Yd: %3d\n" ////c=4 r=1 + "Int: %3d " ////c=4 r=1 + "Shut: %3d" ////c=4 r=1 + ), + pat9125_x, pat9125_y, + pat9125_b, pat9125_s + ); + //} + } +#endif //PAT9125 } void lcd_menu_show_sensors_state() // NOT static due to using inside "Marlin_main" module ("manage_inactivity()") @@ -4326,7 +4370,7 @@ static void lcd_sort_type_set() { default: sdSort = SD_SORT_TIME; } eeprom_update_byte((unsigned char *)EEPROM_SD_SORT, sdSort); - presort_flag = true; + card.presort_flag = true; } #endif //SDCARD_SORT_ALPHA @@ -6096,15 +6140,15 @@ uint8_t choose_menu_P(const char *header, const char *item, const char *last_ite char reset_menu() { const uint8_t items_no = #ifdef SNMM - 5; + 6; #else - 4; + 5; #endif static int8_t first = 0; int8_t enc_dif = 0; char cursor_pos = 0; - const char *const item[items_no] PROGMEM = {PSTR("Language"), PSTR("Statistics"), PSTR("Shipping prep"), PSTR("All Data") + const char *const item[items_no] PROGMEM = {PSTR("Language"), PSTR("Statistics"), PSTR("Shipping prep"), PSTR("All Data"), PSTR("Service prep") #ifdef SNMM , PSTR("Bowden length") #endif @@ -6495,12 +6539,13 @@ void lcd_resume_print() lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS)); st_synchronize(); - lcd_setstatuspgm(_T(MSG_RESUMING_PRINT)); ////MSG_RESUMING_PRINT c=20 + custom_message_type = CustomMsg::Resuming; isPrintPaused = false; restore_print_from_ram_and_continue(default_retraction); pause_time += (_millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation refresh_cmd_timeout(); SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_RESUMED); //resume octoprint + custom_message_type = CustomMsg::Status; } static void change_sheet() @@ -7189,8 +7234,8 @@ void lcd_sdcard_menu() { uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT); - if (presort_flag == true) { - presort_flag = false; + if (card.presort_flag == true) { + card.presort_flag = false; card.presort(); } if (lcd_draw_update == 0 && LCD_CLICKED == 0) @@ -8403,7 +8448,7 @@ static int lcd_selftest_screen(TestScreen screen, int _progress, int _progress_s if (screen == TestScreen::EndStops) lcd_puts_P(_i("Checking endstops"));////MSG_SELFTEST_CHECK_ENDSTOPS c=20 if (screen == TestScreen::AxisX) lcd_puts_P(_T(MSG_CHECKING_X)); if (screen == TestScreen::AxisY) lcd_puts_P(_T(MSG_CHECKING_Y)); - if (screen == TestScreen::AxisZ) lcd_puts_P(_i("Checking Z axis "));////MSG_SELFTEST_CHECK_Z c=20 + if (screen == TestScreen::AxisZ) lcd_puts_P(_i("Checking Z axis"));////MSG_SELFTEST_CHECK_Z c=20 if (screen == TestScreen::Bed) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED)); if (screen == TestScreen::Hotend || screen == TestScreen::HotendOk) lcd_puts_P(_i("Checking hotend "));////MSG_SELFTEST_CHECK_HOTEND c=20 @@ -8487,7 +8532,7 @@ static void lcd_selftest_screen_step(int _row, int _col, int _state, const char static bool check_file(const char* filename) { if (farm_mode) return true; - card.openFile((char*)filename, true); + card.openFileReadFilteredGcode(filename, true); bool result = false; const uint32_t filesize = card.getFileSize(); uint32_t startPos = 0; @@ -8554,7 +8599,7 @@ static void menu_action_sdfile(const char* filename) for (uint_least8_t i = 0; i < depth; i++) { for (uint_least8_t j = 0; j < 8; j++) { - eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, dir_names[i][j]); + eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, card.dir_names[i][j]); } } @@ -8572,12 +8617,8 @@ static void menu_action_sdfile(const char* filename) void menu_action_sddirectory(const char* filename) { - uint8_t depth = (uint8_t)card.getWorkDirDepth(); - - strcpy(dir_names[depth], filename); - MYSERIAL.println(dir_names[depth]); - card.chdir(filename); - lcd_encoder = 0; + card.chdir(filename, true); + lcd_encoder = 0; } /** LCD API **/ diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h index 62aed6dff..ac8178cbc 100755 --- a/Firmware/ultralcd.h +++ b/Firmware/ultralcd.h @@ -114,12 +114,15 @@ extern int8_t FSensorStateMenu; enum class CustomMsg : uint_least8_t { - Status, //!< status message from lcd_status_message variable - MeshBedLeveling, //!< Mesh bed leveling in progress - FilamentLoading, //!< Loading filament in progress - PidCal, //!< PID tuning in progress - TempCal, //!< PINDA temperature calibration - TempCompPreheat, //!< Temperature compensation preheat + Status, //!< status message from lcd_status_message variable + MeshBedLeveling, //!< Mesh bed leveling in progress + FilamentLoading, //!< Loading filament in progress + PidCal, //!< PID tuning in progress + TempCal, //!< PINDA temperature calibration + TempCompPreheat, //!< Temperature compensation preheat + M0Wait, //!< M0/M1 Wait command working even from SD + MsgUpdate, //!< Short message even while printing from SD + Resuming, //!< Resuming message }; extern CustomMsg custom_message_type; diff --git a/lang/lang_en.txt b/lang/lang_en.txt index 8c0e6eb9d..79848fe87 100644 --- a/lang/lang_en.txt +++ b/lang/lang_en.txt @@ -253,8 +253,8 @@ #MSG_FSENSOR "Fil. sensor" -#MSG_FIL_RUNOUTS c=14 -"Fil. runouts " +#MSG_FIL_RUNOUTS c=15 +"Fil. runouts" #MSG_FILAMENT_CLEAN c=20 r=2 "Filament extruding & with correct color?" @@ -448,13 +448,13 @@ # "Measured skew" -#MSG_MMU_FAILS c=14 +#MSG_MMU_FAILS c=15 "MMU fails" # "MMU load failed " -#MSG_MMU_LOAD_FAILS c=14 +#MSG_MMU_LOAD_FAILS c=15 "MMU load fails" #MSG_MMU_OK_RESUMING c=20 r=4 @@ -625,7 +625,7 @@ #MSG_FS_PAUSE c=5 "Pause" -#MSG_POWER_FAILURES c=14 +#MSG_POWER_FAILURES c=15 "Power failures" #MSG_PRINT_ABORTED c=20 @@ -1048,7 +1048,7 @@ #MSG_GCODE_DIFF_PRINTER_CONTINUE c=20 r=5 "G-code sliced for a different printer type. Continue?" -#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=6 +#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=7 "G-code sliced for a different printer type. Please re-slice the model again. Print cancelled." # diff --git a/lang/lang_en_cz.txt b/lang/lang_en_cz.txt index 2c0bc664b..ea2dbc83d 100644 --- a/lang/lang_en_cz.txt +++ b/lang/lang_en_cz.txt @@ -338,8 +338,8 @@ "Fil. sensor" "Fil. senzor" -#MSG_FIL_RUNOUTS c=14 -"Fil. runouts " +#MSG_FIL_RUNOUTS c=15 +"Fil. runouts" "Vypadky filam." #MSG_FILAMENT_CLEAN c=20 r=2 @@ -598,7 +598,7 @@ "Measured skew" "Merene zkoseni" -#MSG_MMU_FAILS c=14 +#MSG_MMU_FAILS c=15 "MMU fails" "Selhani MMU" @@ -606,7 +606,7 @@ "MMU load failed " "Zavedeni MMU selhalo" -#MSG_MMU_LOAD_FAILS c=14 +#MSG_MMU_LOAD_FAILS c=15 "MMU load fails" "MMU selhani zavadeni" @@ -834,7 +834,7 @@ "Pause" "\x00" -#MSG_POWER_FAILURES c=14 +#MSG_POWER_FAILURES c=15 "Power failures" "Vypadky proudu" @@ -1398,7 +1398,7 @@ "G-code sliced for a different printer type. Continue?" "G-code je pripraven pro jiny typ tiskarny. Pokracovat?" -#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=6 +#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=7 "G-code sliced for a different printer type. Please re-slice the model again. Print cancelled." "G-code je pripraven pro jiny typ tiskarny. Prosim preslicujte model znovu. Tisk zrusen." diff --git a/lang/lang_en_de.txt b/lang/lang_en_de.txt index e6fd5bccc..ffc35678e 100644 --- a/lang/lang_en_de.txt +++ b/lang/lang_en_de.txt @@ -338,9 +338,9 @@ "Fil. sensor" "Fil. Sensor" -#MSG_FIL_RUNOUTS c=14 -"Fil. runouts " -"Fil. Maengel " +#MSG_FIL_RUNOUTS c=15 +"Fil. runouts" +"Fil. Maengel" #MSG_FILAMENT_CLEAN c=20 r=2 "Filament extruding & with correct color?" @@ -598,7 +598,7 @@ "Measured skew" "Schraeglauf" -#MSG_MMU_FAILS c=14 +#MSG_MMU_FAILS c=15 "MMU fails" "MMU Fehler" @@ -606,7 +606,7 @@ "MMU load failed " "MMU Ladefehler" -#MSG_MMU_LOAD_FAILS c=14 +#MSG_MMU_LOAD_FAILS c=15 "MMU load fails" "MMU Ladefehler" @@ -834,7 +834,7 @@ "Pause" "\x00" -#MSG_POWER_FAILURES c=14 +#MSG_POWER_FAILURES c=15 "Power failures" "Netzfehler" @@ -1398,7 +1398,7 @@ "G-code sliced for a different printer type. Continue?" "G-Code ist fuer einen anderen Drucker geslict. Fortfahren?" -#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=6 +#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=7 "G-code sliced for a different printer type. Please re-slice the model again. Print cancelled." "G-Code ist fuer einen anderen Drucker geslict. Bitte slicen Sie das Modell erneut. Druck abgebrochen." diff --git a/lang/lang_en_es.txt b/lang/lang_en_es.txt index 4e622ebb9..b5bca7656 100644 --- a/lang/lang_en_es.txt +++ b/lang/lang_en_es.txt @@ -338,9 +338,9 @@ "Fil. sensor" "Sensor Fil." -#MSG_FIL_RUNOUTS c=14 -"Fil. runouts " -"Fil. acabado " +#MSG_FIL_RUNOUTS c=15 +"Fil. runouts" +"Fil. acabado" #MSG_FILAMENT_CLEAN c=20 r=2 "Filament extruding & with correct color?" @@ -598,7 +598,7 @@ "Measured skew" "Desviacion med:" -#MSG_MMU_FAILS c=14 +#MSG_MMU_FAILS c=15 "MMU fails" "Fallos MMU" @@ -606,7 +606,7 @@ "MMU load failed " "Carga MMU fallida" -#MSG_MMU_LOAD_FAILS c=14 +#MSG_MMU_LOAD_FAILS c=15 "MMU load fails" "Carga MMU falla" @@ -834,9 +834,9 @@ "Pause" "Pausa" -#MSG_POWER_FAILURES c=14 +#MSG_POWER_FAILURES c=15 "Power failures" -"Cortes de energia" +"Fallas energia" #MSG_PRINT_ABORTED c=20 "Print aborted" @@ -1398,7 +1398,7 @@ "G-code sliced for a different printer type. Continue?" "Codigo G laminado para un tipo de impresora diferente. ?Continuar?" -#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=6 +#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=7 "G-code sliced for a different printer type. Please re-slice the model again. Print cancelled." "Codigo G laminado para una impresora diferente. Por favor relamina el modelo de nuevo. Impresion cancelada." diff --git a/lang/lang_en_fr.txt b/lang/lang_en_fr.txt index edf2bb8b4..7bd47294e 100644 --- a/lang/lang_en_fr.txt +++ b/lang/lang_en_fr.txt @@ -338,9 +338,9 @@ "Fil. sensor" "Capteur Fil." -#MSG_FIL_RUNOUTS c=14 -"Fil. runouts " -"Fins filament " +#MSG_FIL_RUNOUTS c=15 +"Fil. runouts" +"Fins filament" #MSG_FILAMENT_CLEAN c=20 r=2 "Filament extruding & with correct color?" @@ -598,7 +598,7 @@ "Measured skew" "Deviat.mesuree" -#MSG_MMU_FAILS c=14 +#MSG_MMU_FAILS c=15 "MMU fails" "Echecs MMU" @@ -606,7 +606,7 @@ "MMU load failed " "Echec chargement MMU" -#MSG_MMU_LOAD_FAILS c=14 +#MSG_MMU_LOAD_FAILS c=15 "MMU load fails" "Echecs charg. MMU" @@ -834,7 +834,7 @@ "Pause" "\x00" -#MSG_POWER_FAILURES c=14 +#MSG_POWER_FAILURES c=15 "Power failures" "Coup.de courant" @@ -1398,7 +1398,7 @@ "G-code sliced for a different printer type. Continue?" "Le G-code a ete prepare pour une autre version de l'imprimante. Continuer?" -#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=6 +#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=7 "G-code sliced for a different printer type. Please re-slice the model again. Print cancelled." "Le G-code a ete prepare pour une autre version de l'imprimante. Veuillez decouper le modele a nouveau. L'impression a ete annulee." diff --git a/lang/lang_en_it.txt b/lang/lang_en_it.txt index 043d1141b..d4cac7620 100644 --- a/lang/lang_en_it.txt +++ b/lang/lang_en_it.txt @@ -338,9 +338,9 @@ "Fil. sensor" "Sensore fil." -#MSG_FIL_RUNOUTS c=14 -"Fil. runouts " -"Fil. esauriti " +#MSG_FIL_RUNOUTS c=15 +"Fil. runouts" +"Fil. esauriti" #MSG_FILAMENT_CLEAN c=20 r=2 "Filament extruding & with correct color?" @@ -598,7 +598,7 @@ "Measured skew" "Deviazione mis" -#MSG_MMU_FAILS c=14 +#MSG_MMU_FAILS c=15 "MMU fails" "Fallimenti MMU" @@ -606,7 +606,7 @@ "MMU load failed " "Caricamento MMU fallito" -#MSG_MMU_LOAD_FAILS c=14 +#MSG_MMU_LOAD_FAILS c=15 "MMU load fails" "Caricamenti MMU falliti" @@ -834,7 +834,7 @@ "Pause" "Pausa" -#MSG_POWER_FAILURES c=14 +#MSG_POWER_FAILURES c=15 "Power failures" "Mancanza corrente" @@ -1398,7 +1398,7 @@ "G-code sliced for a different printer type. Continue?" "G-code processato per una stampante diversa. Continuare?" -#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=6 +#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=7 "G-code sliced for a different printer type. Please re-slice the model again. Print cancelled." "G-code processato per una stampante diversa. Per favore esegui nuovamente lo slice del modello. Stampa annullata." diff --git a/lang/lang_en_pl.txt b/lang/lang_en_pl.txt index 4e6be18e0..bbdf0aca1 100644 --- a/lang/lang_en_pl.txt +++ b/lang/lang_en_pl.txt @@ -338,8 +338,8 @@ "Fil. sensor" "Czuj. filam." -#MSG_FIL_RUNOUTS c=14 -"Fil. runouts " +#MSG_FIL_RUNOUTS c=15 +"Fil. runouts" "Konc.filamentu" #MSG_FILAMENT_CLEAN c=20 r=2 @@ -598,7 +598,7 @@ "Measured skew" "Zmierzony skos" -#MSG_MMU_FAILS c=14 +#MSG_MMU_FAILS c=15 "MMU fails" "Bledy MMU" @@ -606,7 +606,7 @@ "MMU load failed " "Blad ladowania MMU" -#MSG_MMU_LOAD_FAILS c=14 +#MSG_MMU_LOAD_FAILS c=15 "MMU load fails" "Bledy ladow. MMU" @@ -834,7 +834,7 @@ "Pause" "Pauza" -#MSG_POWER_FAILURES c=14 +#MSG_POWER_FAILURES c=15 "Power failures" "Zaniki zasilania" @@ -1398,7 +1398,7 @@ "G-code sliced for a different printer type. Continue?" "G-code pociety dla innej drukarki. Kontynuowac?" -#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=6 +#MSG_GCODE_DIFF_PRINTER_CANCELLED c=20 r=7 "G-code sliced for a different printer type. Please re-slice the model again. Print cancelled." "G-code pociety dla drukarki innego typu. Potnij model ponownie. Druk anulowany."