diff --git a/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp b/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp index ae9600038a..124f0b7c43 100644 --- a/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp +++ b/Marlin/src/HAL/shared/cpu_exception/exception_arm.cpp @@ -320,8 +320,8 @@ void hook_cpu_exceptions() { // So we'll simply mask the top 8 bits of the first handler as an hint of being in the flash or not -that's poor and will // probably break if the flash happens to be more than 128MB, but in this case, we are not magician, we need help from outside. - unsigned long * vecAddr = (unsigned long*)get_vtor(); - SERIAL_ECHO("Vector table addr: "); + unsigned long *vecAddr = (unsigned long*)get_vtor(); + SERIAL_ECHOPGM("Vector table addr: "); SERIAL_PRINTLN(get_vtor(), HEX); #ifdef VECTOR_TABLE_SIZE @@ -348,7 +348,7 @@ void hook_cpu_exceptions() { // 128 bytes alignement is required for writing the VTOR register alignas(128) static unsigned long vectable[VECTOR_TABLE_SENTINEL]; - SERIAL_ECHO("Detected vector table size: "); + SERIAL_ECHOPGM("Detected vector table size: "); SERIAL_PRINTLN(vec_size, HEX); #endif @@ -372,7 +372,7 @@ void hook_cpu_exceptions() { HW_REG(0xE000ED08) = (unsigned long)vectable | _BV32(29); // 29th bit is for telling the CPU the table is now in SRAM (should be present already) - SERIAL_ECHOLN("Installed fault handlers"); + SERIAL_ECHOLNPGM("Installed fault handlers"); #endif } diff --git a/Marlin/src/core/bug_on.h b/Marlin/src/core/bug_on.h index 3c9dec0f96..cc745f259b 100644 --- a/Marlin/src/core/bug_on.h +++ b/Marlin/src/core/bug_on.h @@ -28,11 +28,11 @@ // This is used like SERIAL_ECHOPAIR, that is: a key-value call of the local variables you want // to dump to the serial port before stopping the CPU. // \/ Don't replace by SERIAL_ECHOPAIR since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building - #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLN(": "); SERIAL_ECHOLNPAIR(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0) + #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLNPGM(": "); SERIAL_ECHOLNPAIR(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0) #elif ENABLED(MARLIN_DEV_MODE) // Don't stop the CPU here, but at least dump the bug on the serial port // \/ Don't replace by SERIAL_ECHOPAIR since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building - #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLN(": BUG!"); SERIAL_ECHOLNPAIR(V); SERIAL_FLUSHTX(); } while(0) + #define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLNPGM(": BUG!"); SERIAL_ECHOLNPAIR(V); SERIAL_FLUSHTX(); } while(0) #else // Release mode, let's ignore the bug #define BUG_ON(V...) NOOP diff --git a/Marlin/src/lcd/dogm/u8g_dev_ssd1309_12864.cpp b/Marlin/src/lcd/dogm/u8g_dev_ssd1309_12864.cpp index 8ba19216b1..7b4c470afe 100644 --- a/Marlin/src/lcd/dogm/u8g_dev_ssd1309_12864.cpp +++ b/Marlin/src/lcd/dogm/u8g_dev_ssd1309_12864.cpp @@ -88,7 +88,7 @@ static const uint8_t u8g_dev_ssd13xx_sleep_off[] PROGMEM = { }; uint8_t u8g_dev_ssd1309_128x64_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) { - switch(msg) { + switch (msg) { case U8G_DEV_MSG_INIT: u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS); u8g_WriteEscSeqP(u8g, dev, u8g_dev_ssd1309_128x64_init_seq); diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h index 8e03614a46..c709415879 100644 --- a/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h @@ -35,22 +35,27 @@ using namespace ExtUI; namespace Anycubic { - class FileNavigator { - public: - FileNavigator(); - void reset(); - void getFiles(uint16_t); - void upDIR(); - void changeDIR(char *); - void sendFile(); - void refresh(); - char * getCurrentFolderName(); - private: - static FileList filelist; - static char currentfoldername[MAX_PATH_LEN]; - static uint16_t lastindex; - static uint8_t folderdepth; - static uint16_t currentindex; - }; - extern FileNavigator filenavigator; + +class FileNavigator { + public: + FileNavigator(); + void reset(); + void getFiles(uint16_t, panel_type_t, uint8_t filesneeded=4); + void upDIR(); + void changeDIR(const char *); + void sendFile(panel_type_t); + void refresh(); + void skiptofileindex(uint16_t); + + static FileList filelist; + private: + static uint16_t lastpanelindex; + static uint16_t currentindex; + static uint8_t currentfolderdepth; + static uint16_t currentfolderindex[MAX_FOLDER_DEPTH]; + static char currentfoldername[MAX_PATH_LEN]; +}; + +extern FileNavigator filenavigator; + } diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp index 5eb8611b5e..065e4e1789 100644 --- a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp @@ -43,843 +43,843 @@ namespace Anycubic { - printer_state_t ChironTFT::printer_state; - paused_state_t ChironTFT::pause_state; - heater_state_t ChironTFT::hotend_state; - heater_state_t ChironTFT::hotbed_state; - xy_uint8_t ChironTFT::selectedmeshpoint; - char ChironTFT::selectedfile[MAX_PATH_LEN]; - char ChironTFT::panel_command[MAX_CMND_LEN]; - uint8_t ChironTFT::command_len; - float ChironTFT::live_Zoffset; - file_menu_t ChironTFT::file_menu; +printer_state_t ChironTFT::printer_state; +paused_state_t ChironTFT::pause_state; +heater_state_t ChironTFT::hotend_state; +heater_state_t ChironTFT::hotbed_state; +xy_uint8_t ChironTFT::selectedmeshpoint; +char ChironTFT::selectedfile[MAX_PATH_LEN]; +char ChironTFT::panel_command[MAX_CMND_LEN]; +uint8_t ChironTFT::command_len; +float ChironTFT::live_Zoffset; +file_menu_t ChironTFT::file_menu; - ChironTFT Chiron; +ChironTFT Chiron; - ChironTFT::ChironTFT(){} +ChironTFT::ChironTFT(){} - void ChironTFT::Startup() { - selectedfile[0] = '\0'; - panel_command[0] = '\0'; - command_len = 0; - printer_state = AC_printer_idle; - pause_state = AC_paused_idle; - hotend_state = AC_heater_off; - hotbed_state = AC_heater_off; - live_Zoffset = 0.0; - file_menu = AC_menu_file; +void ChironTFT::Startup() { + selectedfile[0] = '\0'; + panel_command[0] = '\0'; + command_len = 0; + printer_state = AC_printer_idle; + pause_state = AC_paused_idle; + hotend_state = AC_heater_off; + hotbed_state = AC_heater_off; + live_Zoffset = 0.0; + file_menu = AC_menu_file; - // Setup pins for powerloss detection - // Two IO pins are connected on the Trigorilla Board - // On a power interruption the OUTAGECON_PIN goes low. + // Setup pins for powerloss detection + // Two IO pins are connected on the Trigorilla Board + // On a power interruption the OUTAGECON_PIN goes low. - #if ENABLED(POWER_LOSS_RECOVERY) - OUT_WRITE(OUTAGECON_PIN, HIGH); - #endif + #if ENABLED(POWER_LOSS_RECOVERY) + OUT_WRITE(OUTAGECON_PIN, HIGH); + #endif - // Filament runout is handled by Marlin settings in Configuration.h - // opt_set FIL_RUNOUT_STATE HIGH // Pin state indicating that filament is NOT present. - // opt_enable FIL_RUNOUT_PULLUP + // Filament runout is handled by Marlin settings in Configuration.h + // opt_set FIL_RUNOUT_STATE HIGH // Pin state indicating that filament is NOT present. + // opt_enable FIL_RUNOUT_PULLUP - TFTSer.begin(115200); + TFTSer.begin(115200); - // Signal Board has reset - SendtoTFTLN(AC_msg_main_board_has_reset); + // Signal Board has reset + SendtoTFTLN(AC_msg_main_board_has_reset); - safe_delay(200); + safe_delay(200); - // Enable leveling and Disable end stops during print - // as Z home places nozzle above the bed so we need to allow it past the end stops - injectCommands_P(AC_cmnd_enable_leveling); + // Enable leveling and Disable end stops during print + // as Z home places nozzle above the bed so we need to allow it past the end stops + injectCommands_P(AC_cmnd_enable_leveling); - // Startup tunes are defined in Tunes.h - //PlayTune(BEEPER_PIN, Anycubic_PowerOn, 1); - PlayTune(BEEPER_PIN, GB_PowerOn, 1); - #if ACDEBUGLEVEL - SERIAL_ECHOLNPAIR("AC Debug Level ", ACDEBUGLEVEL); - #endif - SendtoTFTLN(AC_msg_ready); + // Startup tunes are defined in Tunes.h + //PlayTune(BEEPER_PIN, Anycubic_PowerOn, 1); + PlayTune(BEEPER_PIN, GB_PowerOn, 1); + #if ACDEBUGLEVEL + SERIAL_ECHOLNPAIR("AC Debug Level ", ACDEBUGLEVEL); + #endif + SendtoTFTLN(AC_msg_ready); +} + +void ChironTFT::IdleLoop() { + if (ReadTFTCommand()) { + ProcessPanelRequest(); + command_len = 0; } + CheckHeaters(); +} - void ChironTFT::IdleLoop() { - if (ReadTFTCommand()) { - ProcessPanelRequest(); - command_len = 0; - } - CheckHeaters(); +void ChironTFT::PrinterKilled(PGM_P error,PGM_P component) { + SendtoTFTLN(AC_msg_kill_lcd); + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("PrinterKilled()\nerror: ", error , "\ncomponent: ", component); + #endif +} + +void ChironTFT::MediaEvent(media_event_t event) { + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("ProcessMediaStatus() ", event); + #endif + switch (event) { + case AC_media_inserted: + SendtoTFTLN(AC_msg_sd_card_inserted); + break; + + case AC_media_removed: + SendtoTFTLN(AC_msg_sd_card_removed); + break; + + case AC_media_error: + SendtoTFTLN(AC_msg_no_sd_card); + break; } +} - void ChironTFT::PrinterKilled(PGM_P error,PGM_P component) { - SendtoTFTLN(AC_msg_kill_lcd); - #if ACDEBUG(AC_MARLIN) - SERIAL_ECHOLNPAIR("PrinterKilled()\nerror: ", error , "\ncomponent: ", component); - #endif +void ChironTFT::TimerEvent(timer_event_t event) { + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("TimerEvent() ", event); + SERIAL_ECHOLNPAIR("Printer State: ", printer_state); + #endif + + switch (event) { + case AC_timer_started: { + live_Zoffset = 0.0; // reset print offset + setSoftEndstopState(false); // disable endstops to print + printer_state = AC_printer_printing; + SendtoTFTLN(AC_msg_print_from_sd_card); + } break; + + case AC_timer_paused: { + printer_state = AC_printer_paused; + pause_state = AC_paused_idle; + SendtoTFTLN(AC_msg_paused); + } break; + + case AC_timer_stopped: { + if (printer_state != AC_printer_idle) { + printer_state = AC_printer_stopping; + SendtoTFTLN(AC_msg_print_complete); + } + setSoftEndstopState(true); // enable endstops + } break; } +} - void ChironTFT::MediaEvent(media_event_t event) { - #if ACDEBUG(AC_MARLIN) - SERIAL_ECHOLNPAIR("ProcessMediaStatus() ", event); - #endif - switch (event) { - case AC_media_inserted: - SendtoTFTLN(AC_msg_sd_card_inserted); - break; +void ChironTFT::FilamentRunout() { + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("FilamentRunout() printer_state ", printer_state); + #endif + // 1 Signal filament out + SendtoTFTLN(isPrintingFromMedia() ? AC_msg_filament_out_alert : AC_msg_filament_out_block); + //printer_state = AC_printer_filament_out; + PlayTune(BEEPER_PIN, FilamentOut, 1); +} - case AC_media_removed: - SendtoTFTLN(AC_msg_sd_card_removed); - break; - - case AC_media_error: - SendtoTFTLN(AC_msg_no_sd_card); - break; - } - } - - void ChironTFT::TimerEvent(timer_event_t event) { - #if ACDEBUG(AC_MARLIN) - SERIAL_ECHOLNPAIR("TimerEvent() ", event); - SERIAL_ECHOLNPAIR("Printer State: ", printer_state); - #endif - - switch (event) { - case AC_timer_started: { - live_Zoffset = 0.0; // reset print offset - setSoftEndstopState(false); // disable endstops to print - printer_state = AC_printer_printing; - SendtoTFTLN(AC_msg_print_from_sd_card); - } break; - - case AC_timer_paused: { +void ChironTFT::ConfirmationRequest(const char * const msg) { + // M108 continue + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("ConfirmationRequest() ", msg, " printer_state:", printer_state); + #endif + switch (printer_state) { + case AC_printer_pausing: { + if (strcmp_P(msg, MARLIN_msg_print_paused) == 0 || strcmp_P(msg, MARLIN_msg_nozzle_parked) == 0) { + SendtoTFTLN(AC_msg_paused); // enable continue button printer_state = AC_printer_paused; - pause_state = AC_paused_idle; + } + } break; + + case AC_printer_resuming_from_power_outage: + case AC_printer_printing: + case AC_printer_paused: { + // Heater timout, send acknowledgement + if (strcmp_P(msg, MARLIN_msg_heater_timeout) == 0) { + pause_state = AC_paused_heater_timed_out; + SendtoTFTLN(AC_msg_paused); // enable continue button + PlayTune(BEEPER_PIN,Heater_Timedout,1); + } + // Reheat finished, send acknowledgement + else if (strcmp_P(msg, MARLIN_msg_reheat_done) == 0) { + pause_state = AC_paused_idle; + SendtoTFTLN(AC_msg_paused); // enable continue button + } + // Filament Purging, send acknowledgement enter run mode + else if (strcmp_P(msg, MARLIN_msg_filament_purging) == 0) { + pause_state = AC_paused_purging_filament; + SendtoTFTLN(AC_msg_paused); // enable continue button + } + } break; + default: + break; + } +} + +void ChironTFT::StatusChange(const char * const msg) { + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("StatusChange() ", msg); + SERIAL_ECHOLNPAIR("printer_state:", printer_state); + #endif + bool msg_matched = false; + // The only way to get printer status is to parse messages + // Use the state to minimise the work we do here. + switch (printer_state) { + case AC_printer_probing: { + // If probing completes ok save the mesh and park + // Ignore the custom machine name + if (strcmp_P(msg + strlen(CUSTOM_MACHINE_NAME), MARLIN_msg_ready) == 0) { + injectCommands_P(PSTR("M500\nG27")); + SendtoTFTLN(AC_msg_probing_complete); + printer_state = AC_printer_idle; + msg_matched = true; + } + // If probing fails dont save the mesh raise the probe above the bad point + if (strcmp_P(msg, MARLIN_msg_probing_failed) == 0) { + PlayTune(BEEPER_PIN, BeepBeepBeeep, 1); + injectCommands_P(PSTR("G1 Z50 F500")); + SendtoTFTLN(AC_msg_probing_complete); + printer_state = AC_printer_idle; + msg_matched = true; + } + } break; + + case AC_printer_printing: { + if (strcmp_P(msg, MARLIN_msg_reheating) == 0) { + SendtoTFTLN(AC_msg_paused); // enable continue button + msg_matched = true; + } + } break; + + case AC_printer_pausing: { + if (strcmp_P(msg, MARLIN_msg_print_paused) == 0) { SendtoTFTLN(AC_msg_paused); - } break; + printer_state = AC_printer_paused; + pause_state = AC_paused_idle; + msg_matched = true; + } + } break; - case AC_timer_stopped: { - if (printer_state != AC_printer_idle) { - printer_state = AC_printer_stopping; - SendtoTFTLN(AC_msg_print_complete); - } - setSoftEndstopState(true); // enable endstops - } break; + case AC_printer_stopping: { + if (strcmp_P(msg, MARLIN_msg_print_aborted) == 0) { + SendtoTFTLN(AC_msg_stop); + printer_state = AC_printer_idle; + msg_matched = true; + } + } break; + default: + break; + } + + // If not matched earlier see if this was a heater message + if (!msg_matched) { + if (strcmp_P(msg, MARLIN_msg_extruder_heating) == 0) { + SendtoTFTLN(AC_msg_nozzle_heating); + hotend_state = AC_heater_temp_set; + } + else if (strcmp_P(msg, MARLIN_msg_bed_heating) == 0) { + SendtoTFTLN(AC_msg_bed_heating); + hotbed_state = AC_heater_temp_set; } } +} - void ChironTFT::FilamentRunout() { - #if ACDEBUG(AC_MARLIN) - SERIAL_ECHOLNPAIR("FilamentRunout() printer_state ", printer_state); +void ChironTFT::PowerLossRecovery() { + printer_state = AC_printer_resuming_from_power_outage; // Play tune to notify user we can recover. + PlayTune(BEEPER_PIN, SOS, 1); + SERIAL_ECHOLNPGM("Resuming from power outage..."); + SERIAL_ECHOLNPGM("Select SD file then press resume"); +} + +void ChironTFT::SendtoTFT(PGM_P str) { // A helper to print PROGMEM string to the panel + #if ACDEBUG(AC_SOME) + SERIAL_ECHOPGM_P(str); + #endif + while (const char c = pgm_read_byte(str++)) TFTSer.write(c); +} + +void ChironTFT::SendtoTFTLN(PGM_P str = nullptr) { + if (str) { + #if ACDEBUG(AC_SOME) + SERIAL_ECHOPGM("> "); + #endif + SendtoTFT(str); + #if ACDEBUG(AC_SOME) + SERIAL_EOL(); #endif - // 1 Signal filament out - SendtoTFTLN(isPrintingFromMedia() ? AC_msg_filament_out_alert : AC_msg_filament_out_block); - //printer_state = AC_printer_filament_out; - PlayTune(BEEPER_PIN, FilamentOut, 1); } + TFTSer.println(); +} - void ChironTFT::ConfirmationRequest(const char * const msg) { - // M108 continue - #if ACDEBUG(AC_MARLIN) - SERIAL_ECHOLNPAIR("ConfirmationRequest() ", msg, " printer_state:", printer_state); - #endif - switch (printer_state) { - case AC_printer_pausing: { - if (strcmp_P(msg, MARLIN_msg_print_paused) == 0 || strcmp_P(msg, MARLIN_msg_nozzle_parked) == 0) { - SendtoTFTLN(AC_msg_paused); // enable continue button - printer_state = AC_printer_paused; - } - } break; - - case AC_printer_resuming_from_power_outage: - case AC_printer_printing: - case AC_printer_paused: { - // Heater timout, send acknowledgement - if (strcmp_P(msg, MARLIN_msg_heater_timeout) == 0) { - pause_state = AC_paused_heater_timed_out; - SendtoTFTLN(AC_msg_paused); // enable continue button - PlayTune(BEEPER_PIN,Heater_Timedout,1); - } - // Reheat finished, send acknowledgement - else if (strcmp_P(msg, MARLIN_msg_reheat_done) == 0) { - pause_state = AC_paused_idle; - SendtoTFTLN(AC_msg_paused); // enable continue button - } - // Filament Purging, send acknowledgement enter run mode - else if (strcmp_P(msg, MARLIN_msg_filament_purging) == 0) { - pause_state = AC_paused_purging_filament; - SendtoTFTLN(AC_msg_paused); // enable continue button - } - } break; - default: +bool ChironTFT::ReadTFTCommand() { + bool command_ready = false; + while (TFTSer.available() > 0 && command_len < MAX_CMND_LEN) { + panel_command[command_len] = TFTSer.read(); + if (panel_command[command_len] == '\n') { + command_ready = true; break; } + command_len++; } - void ChironTFT::StatusChange(const char * const msg) { - #if ACDEBUG(AC_MARLIN) - SERIAL_ECHOLNPAIR("StatusChange() ", msg); - SERIAL_ECHOLNPAIR("printer_state:", printer_state); + if (command_ready) { + panel_command[command_len] = 0x00; + #if ACDEBUG(AC_ALL) + SERIAL_ECHOLNPAIR("< ", panel_command); #endif - bool msg_matched = false; - // The only way to get printer status is to parse messages - // Use the state to minimise the work we do here. - switch (printer_state) { - case AC_printer_probing: { - // If probing completes ok save the mesh and park - // Ignore the custom machine name - if (strcmp_P(msg + strlen(CUSTOM_MACHINE_NAME), MARLIN_msg_ready) == 0) { - injectCommands_P(PSTR("M500\nG27")); - SendtoTFTLN(AC_msg_probing_complete); - printer_state = AC_printer_idle; - msg_matched = true; - } - // If probing fails dont save the mesh raise the probe above the bad point - if (strcmp_P(msg, MARLIN_msg_probing_failed) == 0) { - PlayTune(BEEPER_PIN, BeepBeepBeeep, 1); - injectCommands_P(PSTR("G1 Z50 F500")); - SendtoTFTLN(AC_msg_probing_complete); - printer_state = AC_printer_idle; - msg_matched = true; - } - } break; + #if ACDEBUG(AC_SOME) + // Ignore status request commands + uint8_t req = atoi(&panel_command[1]); + if (req > 7 && req != 20) { + SERIAL_ECHOLNPAIR("> ", panel_command); + SERIAL_ECHOLNPAIR("printer_state:", printer_state); + } + #endif + } + return command_ready; +} - case AC_printer_printing: { - if (strcmp_P(msg, MARLIN_msg_reheating) == 0) { - SendtoTFTLN(AC_msg_paused); // enable continue button - msg_matched = true; - } - } break; +int8_t ChironTFT::Findcmndpos(const char * buff, char q) { + int8_t pos = 0; + do { if (buff[pos] == q) return pos; } while (++pos < MAX_CMND_LEN); + return -1; +} - case AC_printer_pausing: { - if (strcmp_P(msg, MARLIN_msg_print_paused) == 0) { - SendtoTFTLN(AC_msg_paused); - printer_state = AC_printer_paused; - pause_state = AC_paused_idle; - msg_matched = true; - } - } break; +void ChironTFT::CheckHeaters() { + uint8_t faultDuration = 0; + float temp = 0; - case AC_printer_stopping: { - if (strcmp_P(msg, MARLIN_msg_print_aborted) == 0) { - SendtoTFTLN(AC_msg_stop); - printer_state = AC_printer_idle; - msg_matched = true; - } - } break; - default: + // if the hotend temp is abnormal, confirm state before signalling panel + temp = getActualTemp_celsius(E0); + while (!WITHIN(temp, HEATER_0_MINTEMP, HEATER_0_MAXTEMP)) { + faultDuration++; + if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) { + SendtoTFTLN(AC_msg_nozzle_temp_abnormal); + SERIAL_ECHOLNPAIR("Extruder temp abnormal! : ", temp); break; } + delay_ms(500); + temp = getActualTemp_celsius(E0); + } - // If not matched earlier see if this was a heater message - if (!msg_matched) { - if (strcmp_P(msg, MARLIN_msg_extruder_heating) == 0) { - SendtoTFTLN(AC_msg_nozzle_heating); + // If the hotbed temp is abnormal, confirm state before signaling panel + faultDuration = 0; + temp = getActualTemp_celsius(BED); + while (!WITHIN(temp, BED_MINTEMP, BED_MAXTEMP)) { + faultDuration++; + if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) { + SendtoTFTLN(AC_msg_nozzle_temp_abnormal); + SERIAL_ECHOLNPAIR("Bed temp abnormal! : ", temp); + break; + } + delay_ms(500); + temp = getActualTemp_celsius(E0); + } + + // Update panel with hotend heater status + if (hotend_state != AC_heater_temp_reached) { + if (WITHIN(getActualTemp_celsius(E0) - getTargetTemp_celsius(E0), -1, 1)) { + SendtoTFTLN(AC_msg_nozzle_heating_done); + hotend_state = AC_heater_temp_reached; + } + } + + // Update panel with bed heater status + if (hotbed_state != AC_heater_temp_reached) { + if (WITHIN(getActualTemp_celsius(BED) - getTargetTemp_celsius(BED), -0.5, 0.5)) { + SendtoTFTLN(AC_msg_bed_heating_done); + hotbed_state = AC_heater_temp_reached; + } + } +} + +void ChironTFT::SendFileList(int8_t startindex) { + // Respond to panel request for 4 files starting at index + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("## SendFileList ## ", startindex); + #endif + SendtoTFTLN(PSTR("FN ")); + filenavigator.getFiles(startindex); + SendtoTFTLN(PSTR("END")); +} + +void ChironTFT::SelectFile() { + strncpy(selectedfile, panel_command + 4, command_len - 4); + selectedfile[command_len - 5] = '\0'; + #if ACDEBUG(AC_FILE) + SERIAL_ECHOLNPAIR_F(" Selected File: ",selectedfile); + #endif + switch (selectedfile[0]) { + case '/': // Valid file selected + SendtoTFTLN(AC_msg_sd_file_open_success); + break; + + case '<': // .. (go up folder level) + filenavigator.upDIR(); + SendtoTFTLN(AC_msg_sd_file_open_failed); + SendFileList( 0 ); + break; + default: // enter sub folder + filenavigator.changeDIR(selectedfile); + SendtoTFTLN(AC_msg_sd_file_open_failed); + SendFileList( 0 ); + break; + } +} + +void ChironTFT::InjectCommandandWait(PGM_P cmd) { + //injectCommands_P(cmnd); queue.enqueue_now_P(cmd); + //SERIAL_ECHOLN(PSTR("Inject>")); +} + +void ChironTFT::ProcessPanelRequest() { + // Break these up into logical blocks // as its easier to navigate than one huge switch case! + int8_t req = atoi(&panel_command[1]); + + // Information requests A0 - A8 and A33 + if (req <= 8 || req == 33) PanelInfo(req); + + // Simple Actions A9 - A28 + else if ( req <= 28) PanelAction(req); + + // Process Initiation + else if (req <= 34) PanelProcess(req); + + else SendtoTFTLN(); +} + +void ChironTFT::PanelInfo(uint8_t req) { + // information requests A0-A8 and A33 + switch (req) { + case 0: // A0 Get HOTEND Temp + SendtoTFT(PSTR("A0V ")); + TFTSer.println(getActualTemp_celsius(E0)); + break; + + case 1: // A1 Get HOTEND Target Temp + SendtoTFT(PSTR("A1V ")); + TFTSer.println(getTargetTemp_celsius(E0)); + break; + + case 2: // A2 Get BED Temp + SendtoTFT(PSTR("A2V ")); + TFTSer.println(getActualTemp_celsius(BED)); + break; + + case 3: // A3 Get BED Target Temp + SendtoTFT(PSTR("A3V ")); + TFTSer.println(getTargetTemp_celsius(BED)); + break; + + case 4: // A4 Get FAN Speed + SendtoTFT(PSTR("A4V ")); + TFTSer.println(getActualFan_percent(FAN0)); + break; + + case 5: // A5 Get Current Coordinates + SendtoTFT(PSTR("A5V X: ")); + TFTSer.print(getAxisPosition_mm(X)); + SendtoTFT(PSTR(" Y: ")); + TFTSer.print(getAxisPosition_mm(Y)); + SendtoTFT(PSTR(" Z: ")); + TFTSer.println(getAxisPosition_mm(Z)); + break; + + case 6: // A6 Get printing progress + if (isPrintingFromMedia()) { + SendtoTFT(PSTR("A6V ")); + TFTSer.println(ui8tostr2(getProgress_percent())); + } + else + SendtoTFTLN(PSTR("A6V ---")); + break; + + case 7: { // A7 Get Printing Time + uint32_t time = getProgress_seconds_elapsed() / 60; + SendtoTFT(PSTR("A7V ")); + TFTSer.print(ui8tostr2(time / 60)); + SendtoTFT(PSTR(" H ")); + TFTSer.print(ui8tostr2(time % 60)); + SendtoTFT(PSTR(" M")); + #if ACDEBUG(AC_ALL) + SERIAL_ECHOLNPAIR("Print time ", ui8tostr2(time / 60), ":", ui8tostr2(time % 60)); + #endif + } break; + + case 8: // A8 Get SD Card list A8 S0 + if (!isMediaInserted()) safe_delay(500); + if (!isMediaInserted()) // Make sure the card is removed + SendtoTFTLN(AC_msg_no_sd_card); + else if (panel_command[3] == 'S') + SendFileList( atoi( &panel_command[4] ) ); + break; + + case 33: // A33 Get firmware info + SendtoTFT(PSTR("J33 ")); + SendtoTFTLN(PSTR(SHORT_BUILD_VERSION)); + break; + } +} + +void ChironTFT::PanelAction(uint8_t req) { + switch (req) { + case 9: // A9 Pause SD print + if (isPrintingFromMedia()) { + SendtoTFTLN(AC_msg_pause); + pausePrint(); + printer_state = AC_printer_pausing; + } + else + SendtoTFTLN(AC_msg_stop); + break; + + case 10: // A10 Resume SD Print + if (pause_state == AC_paused_idle || printer_state == AC_printer_resuming_from_power_outage) + resumePrint(); + else + setUserConfirmed(); + break; + + case 11: // A11 Stop SD print + if (isPrintingFromMedia()) { + printer_state = AC_printer_stopping; + stopPrint(); + } + else { + if (printer_state == AC_printer_resuming_from_power_outage) + injectCommands_P(PSTR("M1000 C")); // Cancel recovery + SendtoTFTLN(AC_msg_stop); + printer_state = AC_printer_idle; + } + break; + + case 12: // A12 Kill printer + kill(); // from marlincore.h + break; + + case 13: // A13 Select file + SelectFile(); + break; + + case 14: { // A14 Start Printing + // Allows printer to restart the job if we dont want to recover + if (printer_state == AC_printer_resuming_from_power_outage) { + injectCommands_P(PSTR("M1000 C")); // Cancel recovery + printer_state = AC_printer_idle; + } + #if ACDebugLevel >= 1 + SERIAL_ECHOLNPAIR_F("Print: ", selectedfile); + #endif + // the card library needs a path starting // but the File api doesn't... + char file[MAX_PATH_LEN]; + file[0] = '/'; + strcpy(file + 1, selectedfile); + printFile(file); + SendtoTFTLN(AC_msg_print_from_sd_card); + } break; + + case 15: // A15 Resuming from outage + if (printer_state == AC_printer_resuming_from_power_outage) { + // Need to home here to restore the Z position + injectCommands_P(AC_cmnd_power_loss_recovery); + injectCommands_P(PSTR("M1000")); // home and start recovery + } + break; + + case 16: { // A16 Set HotEnd temp A17 S170 + const float set_Htemp = atof(&panel_command[5]); + hotend_state = set_Htemp ? AC_heater_temp_set : AC_heater_off; + switch ((char)panel_command[4]) { + // Set Temp + case 'S': case 'C': setTargetTemp_celsius(set_Htemp, E0); + } + } break; + + case 17: { // A17 Set bed temp + const float set_Btemp = atof(&panel_command[5]); + hotbed_state = set_Btemp ? AC_heater_temp_set : AC_heater_off; + if (panel_command[4] == 'S') + setTargetTemp_celsius(set_Btemp, BED); + } break; + + case 18: // A18 Set Fan Speed + if (panel_command[4] == 'S') + setTargetFan_percent(atof(&panel_command[5]), FAN0); + break; + + case 19: // A19 Motors off + if (!isPrinting()) { + disable_all_steppers(); // from marlincore.h + SendtoTFTLN(AC_msg_ready); + } + break; + + case 20: // A20 Read/write print speed + if (panel_command[4] == 'S') + setFeedrate_percent(atoi(&panel_command[5])); + else { + SendtoTFT(PSTR("A20V ")); + TFTSer.println(getFeedrate_percent()); + } + break; + + case 21: // A21 Home Axis A21 X + if (!isPrinting()) { + switch ((char)panel_command[4]) { + case 'X': injectCommands_P(PSTR("G28X")); break; + case 'Y': injectCommands_P(PSTR("G28Y")); break; + case 'Z': injectCommands_P(PSTR("G28Z")); break; + case 'C': injectCommands_P(G28_STR); break; + } + } + break; + + case 22: // A22 Move Axis A22 Y +10F3000 + // Ignore request if printing + if (!isPrinting()) { + // setAxisPosition_mm() uses pre defined manual feedrates so ignore the feedrate from the panel + setSoftEndstopState(true); // enable endstops + float newposition = atof(&panel_command[6]); + + #if ACDEBUG(AC_ACTION) + SERIAL_ECHOLNPAIR("Nudge ", AS_CHAR(panel_command[4]), " axis ", newposition); + #endif + + switch (panel_command[4]) { + case 'X': setAxisPosition_mm(getAxisPosition_mm(X) + newposition, X); break; + case 'Y': setAxisPosition_mm(getAxisPosition_mm(Y) + newposition, Y); break; + case 'Z': setAxisPosition_mm(getAxisPosition_mm(Z) + newposition, Z); break; + case 'E': // The only time we get this command is from the filament load/unload menu + // the standard movement is too slow so we will use the load unlod GCode to speed it up a bit + if (canMove(E0) && !commandsInQueue()) + injectCommands_P(newposition > 0 ? AC_cmnd_manual_load_filament : AC_cmnd_manual_unload_filament); + break; + } + } + break; + + case 23: // A23 Preheat PLA + // Ignore request if printing + if (!isPrinting()) { + // Temps defined in configuration.h + setTargetTemp_celsius(PREHEAT_1_TEMP_BED, BED); + setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, E0); + SendtoTFTLN(); + hotbed_state = AC_heater_temp_set; hotend_state = AC_heater_temp_set; } - else if (strcmp_P(msg, MARLIN_msg_bed_heating) == 0) { - SendtoTFTLN(AC_msg_bed_heating); - hotbed_state = AC_heater_temp_set; - } - } - } + break; - void ChironTFT::PowerLossRecovery() { - printer_state = AC_printer_resuming_from_power_outage; // Play tune to notify user we can recover. - PlayTune(BEEPER_PIN, SOS, 1); - SERIAL_ECHOLNPGM("Resuming from power outage..."); - SERIAL_ECHOLNPGM("Select SD file then press resume"); - } - - void ChironTFT::SendtoTFT(PGM_P str) { // A helper to print PROGMEM string to the panel - #if ACDEBUG(AC_SOME) - SERIAL_ECHOPGM_P(str); - #endif - while (const char c = pgm_read_byte(str++)) TFTSer.write(c); - } - - void ChironTFT::SendtoTFTLN(PGM_P str = nullptr) { - if (str) { - #if ACDEBUG(AC_SOME) - SERIAL_ECHOPGM("> "); - #endif - SendtoTFT(str); - #if ACDEBUG(AC_SOME) - SERIAL_EOL(); - #endif - } - TFTSer.println(); - } - - bool ChironTFT::ReadTFTCommand() { - bool command_ready = false; - while (TFTSer.available() > 0 && command_len < MAX_CMND_LEN) { - panel_command[command_len] = TFTSer.read(); - if (panel_command[command_len] == '\n') { - command_ready = true; - break; - } - command_len++; - } - - if (command_ready) { - panel_command[command_len] = 0x00; - #if ACDEBUG(AC_ALL) - SERIAL_ECHOLNPAIR("< ", panel_command); - #endif - #if ACDEBUG(AC_SOME) - // Ignore status request commands - uint8_t req = atoi(&panel_command[1]); - if (req > 7 && req != 20) { - SERIAL_ECHOLNPAIR("> ", panel_command); - SERIAL_ECHOLNPAIR("printer_state:", printer_state); - } - #endif - } - return command_ready; - } - - int8_t ChironTFT::Findcmndpos(const char * buff, char q) { - int8_t pos = 0; - do { if (buff[pos] == q) return pos; } while (++pos < MAX_CMND_LEN); - return -1; - } - - void ChironTFT::CheckHeaters() { - uint8_t faultDuration = 0; - float temp = 0; - - // if the hotend temp is abnormal, confirm state before signalling panel - temp = getActualTemp_celsius(E0); - while (!WITHIN(temp, HEATER_0_MINTEMP, HEATER_0_MAXTEMP)) { - faultDuration++; - if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) { - SendtoTFTLN(AC_msg_nozzle_temp_abnormal); - SERIAL_ECHOLNPAIR("Extruder temp abnormal! : ", temp); - break; - } - delay_ms(500); - temp = getActualTemp_celsius(E0); - } - - // If the hotbed temp is abnormal, confirm state before signaling panel - faultDuration = 0; - temp = getActualTemp_celsius(BED); - while (!WITHIN(temp, BED_MINTEMP, BED_MAXTEMP)) { - faultDuration++; - if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) { - SendtoTFTLN(AC_msg_nozzle_temp_abnormal); - SERIAL_ECHOLNPAIR("Bed temp abnormal! : ", temp); - break; - } - delay_ms(500); - temp = getActualTemp_celsius(E0); - } - - // Update panel with hotend heater status - if (hotend_state != AC_heater_temp_reached) { - if (WITHIN(getActualTemp_celsius(E0) - getTargetTemp_celsius(E0), -1, 1)) { - SendtoTFTLN(AC_msg_nozzle_heating_done); - hotend_state = AC_heater_temp_reached; - } - } - - // Update panel with bed heater status - if (hotbed_state != AC_heater_temp_reached) { - if (WITHIN(getActualTemp_celsius(BED) - getTargetTemp_celsius(BED), -0.5, 0.5)) { - SendtoTFTLN(AC_msg_bed_heating_done); - hotbed_state = AC_heater_temp_reached; - } - } - } - - void ChironTFT::SendFileList(int8_t startindex) { - // Respond to panel request for 4 files starting at index - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("## SendFileList ## ", startindex); - #endif - SendtoTFTLN(PSTR("FN ")); - filenavigator.getFiles(startindex); - SendtoTFTLN(PSTR("END")); - } - - void ChironTFT::SelectFile() { - strncpy(selectedfile, panel_command + 4, command_len - 4); - selectedfile[command_len - 5] = '\0'; - #if ACDEBUG(AC_FILE) - SERIAL_ECHOLNPAIR_F(" Selected File: ",selectedfile); - #endif - switch (selectedfile[0]) { - case '/': // Valid file selected - SendtoTFTLN(AC_msg_sd_file_open_success); - break; - - case '<': // .. (go up folder level) - filenavigator.upDIR(); - SendtoTFTLN(AC_msg_sd_file_open_failed); - SendFileList( 0 ); - break; - default: // enter sub folder - filenavigator.changeDIR(selectedfile); - SendtoTFTLN(AC_msg_sd_file_open_failed); - SendFileList( 0 ); - break; - } - } - - void ChironTFT::InjectCommandandWait(PGM_P cmd) { - //injectCommands_P(cmnd); queue.enqueue_now_P(cmd); - //SERIAL_ECHOLN(PSTR("Inject>")); - } - - void ChironTFT::ProcessPanelRequest() { - // Break these up into logical blocks // as its easier to navigate than one huge switch case! - int8_t req = atoi(&panel_command[1]); - - // Information requests A0 - A8 and A33 - if (req <= 8 || req == 33) PanelInfo(req); - - // Simple Actions A9 - A28 - else if ( req <= 28) PanelAction(req); - - // Process Initiation - else if (req <= 34) PanelProcess(req); - - else SendtoTFTLN(); - } - - void ChironTFT::PanelInfo(uint8_t req) { - // information requests A0-A8 and A33 - switch (req) { - case 0: // A0 Get HOTEND Temp - SendtoTFT(PSTR("A0V ")); - TFTSer.println(getActualTemp_celsius(E0)); - break; - - case 1: // A1 Get HOTEND Target Temp - SendtoTFT(PSTR("A1V ")); - TFTSer.println(getTargetTemp_celsius(E0)); - break; - - case 2: // A2 Get BED Temp - SendtoTFT(PSTR("A2V ")); - TFTSer.println(getActualTemp_celsius(BED)); - break; - - case 3: // A3 Get BED Target Temp - SendtoTFT(PSTR("A3V ")); - TFTSer.println(getTargetTemp_celsius(BED)); - break; - - case 4: // A4 Get FAN Speed - SendtoTFT(PSTR("A4V ")); - TFTSer.println(getActualFan_percent(FAN0)); - break; - - case 5: // A5 Get Current Coordinates - SendtoTFT(PSTR("A5V X: ")); - TFTSer.print(getAxisPosition_mm(X)); - SendtoTFT(PSTR(" Y: ")); - TFTSer.print(getAxisPosition_mm(Y)); - SendtoTFT(PSTR(" Z: ")); - TFTSer.println(getAxisPosition_mm(Z)); - break; - - case 6: // A6 Get printing progress - if (isPrintingFromMedia()) { - SendtoTFT(PSTR("A6V ")); - TFTSer.println(ui8tostr2(getProgress_percent())); - } - else - SendtoTFTLN(PSTR("A6V ---")); - break; - - case 7: { // A7 Get Printing Time - uint32_t time = getProgress_seconds_elapsed() / 60; - SendtoTFT(PSTR("A7V ")); - TFTSer.print(ui8tostr2(time / 60)); - SendtoTFT(PSTR(" H ")); - TFTSer.print(ui8tostr2(time % 60)); - SendtoTFT(PSTR(" M")); - #if ACDEBUG(AC_ALL) - SERIAL_ECHOLNPAIR("Print time ", ui8tostr2(time / 60), ":", ui8tostr2(time % 60)); - #endif - } break; - - case 8: // A8 Get SD Card list A8 S0 - if (!isMediaInserted()) safe_delay(500); - if (!isMediaInserted()) // Make sure the card is removed - SendtoTFTLN(AC_msg_no_sd_card); - else if (panel_command[3] == 'S') - SendFileList( atoi( &panel_command[4] ) ); - break; - - case 33: // A33 Get firmware info - SendtoTFT(PSTR("J33 ")); - SendtoTFTLN(PSTR(SHORT_BUILD_VERSION)); - break; - } - } - - void ChironTFT::PanelAction(uint8_t req) { - switch (req) { - case 9: // A9 Pause SD print - if (isPrintingFromMedia()) { - SendtoTFTLN(AC_msg_pause); - pausePrint(); - printer_state = AC_printer_pausing; - } - else - SendtoTFTLN(AC_msg_stop); - break; - - case 10: // A10 Resume SD Print - if (pause_state == AC_paused_idle || printer_state == AC_printer_resuming_from_power_outage) - resumePrint(); - else - setUserConfirmed(); - break; - - case 11: // A11 Stop SD print - if (isPrintingFromMedia()) { - printer_state = AC_printer_stopping; - stopPrint(); - } - else { - if (printer_state == AC_printer_resuming_from_power_outage) - injectCommands_P(PSTR("M1000 C")); // Cancel recovery - SendtoTFTLN(AC_msg_stop); - printer_state = AC_printer_idle; - } - break; - - case 12: // A12 Kill printer - kill(); // from marlincore.h - break; - - case 13: // A13 Select file - SelectFile(); - break; - - case 14: { // A14 Start Printing - // Allows printer to restart the job if we dont want to recover - if (printer_state == AC_printer_resuming_from_power_outage) { - injectCommands_P(PSTR("M1000 C")); // Cancel recovery - printer_state = AC_printer_idle; - } - #if ACDebugLevel >= 1 - SERIAL_ECHOLNPAIR_F("Print: ", selectedfile); - #endif - // the card library needs a path starting // but the File api doesn't... - char file[MAX_PATH_LEN]; - file[0] = '/'; - strcpy(file + 1, selectedfile); - printFile(file); - SendtoTFTLN(AC_msg_print_from_sd_card); - } break; - - case 15: // A15 Resuming from outage - if (printer_state == AC_printer_resuming_from_power_outage) { - // Need to home here to restore the Z position - injectCommands_P(AC_cmnd_power_loss_recovery); - injectCommands_P(PSTR("M1000")); // home and start recovery - } - break; - - case 16: { // A16 Set HotEnd temp A17 S170 - const float set_Htemp = atof(&panel_command[5]); - hotend_state = set_Htemp ? AC_heater_temp_set : AC_heater_off; - switch ((char)panel_command[4]) { - // Set Temp - case 'S': case 'C': setTargetTemp_celsius(set_Htemp, E0); - } - } break; - - case 17: { // A17 Set bed temp - const float set_Btemp = atof(&panel_command[5]); - hotbed_state = set_Btemp ? AC_heater_temp_set : AC_heater_off; - if (panel_command[4] == 'S') - setTargetTemp_celsius(set_Btemp, BED); - } break; - - case 18: // A18 Set Fan Speed - if (panel_command[4] == 'S') - setTargetFan_percent(atof(&panel_command[5]), FAN0); - break; - - case 19: // A19 Motors off - if (!isPrinting()) { - disable_all_steppers(); // from marlincore.h - SendtoTFTLN(AC_msg_ready); - } - break; - - case 20: // A20 Read/write print speed - if (panel_command[4] == 'S') - setFeedrate_percent(atoi(&panel_command[5])); - else { - SendtoTFT(PSTR("A20V ")); - TFTSer.println(getFeedrate_percent()); - } - break; - - case 21: // A21 Home Axis A21 X - if (!isPrinting()) { - switch ((char)panel_command[4]) { - case 'X': injectCommands_P(PSTR("G28X")); break; - case 'Y': injectCommands_P(PSTR("G28Y")); break; - case 'Z': injectCommands_P(PSTR("G28Z")); break; - case 'C': injectCommands_P(G28_STR); break; - } - } - break; - - case 22: // A22 Move Axis A22 Y +10F3000 - // Ignore request if printing - if (!isPrinting()) { - // setAxisPosition_mm() uses pre defined manual feedrates so ignore the feedrate from the panel - setSoftEndstopState(true); // enable endstops - float newposition = atof(&panel_command[6]); - - #if ACDEBUG(AC_ACTION) - SERIAL_ECHOLNPAIR("Nudge ", AS_CHAR(panel_command[4]), " axis ", newposition); - #endif - - switch (panel_command[4]) { - case 'X': setAxisPosition_mm(getAxisPosition_mm(X) + newposition, X); break; - case 'Y': setAxisPosition_mm(getAxisPosition_mm(Y) + newposition, Y); break; - case 'Z': setAxisPosition_mm(getAxisPosition_mm(Z) + newposition, Z); break; - case 'E': // The only time we get this command is from the filament load/unload menu - // the standard movement is too slow so we will use the load unlod GCode to speed it up a bit - if (canMove(E0) && !commandsInQueue()) - injectCommands_P(newposition > 0 ? AC_cmnd_manual_load_filament : AC_cmnd_manual_unload_filament); - break; - } - } - break; - - case 23: // A23 Preheat PLA - // Ignore request if printing - if (!isPrinting()) { - // Temps defined in configuration.h - setTargetTemp_celsius(PREHEAT_1_TEMP_BED, BED); - setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, E0); - SendtoTFTLN(); - hotbed_state = AC_heater_temp_set; - hotend_state = AC_heater_temp_set; - } - break; - - case 24: // A24 Preheat ABS - // Ignore request if printing - if (!isPrinting()) { - setTargetTemp_celsius(PREHEAT_2_TEMP_BED, BED); - setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, E0); - SendtoTFTLN(); - hotbed_state = AC_heater_temp_set; - hotend_state = AC_heater_temp_set; - } - break; - - case 25: // A25 Cool Down - // Ignore request if printing - if (!isPrinting()) { - setTargetTemp_celsius(0, E0); - setTargetTemp_celsius(0, BED); - SendtoTFTLN(AC_msg_ready); - hotbed_state = AC_heater_off; - hotend_state = AC_heater_off; - } - break; - - case 26: // A26 Refresh SD - // M22 M21 maybe needed here to reset sd card - filenavigator.reset(); - break; - - case 27: // A27 Servo Angles adjust - break; - - case 28: // A28 Filament set A28 O/C - // Ignore request if printing - if (isPrinting()) break; + case 24: // A24 Preheat ABS + // Ignore request if printing + if (!isPrinting()) { + setTargetTemp_celsius(PREHEAT_2_TEMP_BED, BED); + setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, E0); SendtoTFTLN(); - break; - } - } + hotbed_state = AC_heater_temp_set; + hotend_state = AC_heater_temp_set; + } + break; - void ChironTFT::PanelProcess(uint8_t req) { - switch (req) { - case 29: { // A29 Read Mesh Point A29 X1 Y1 + case 25: // A25 Cool Down + // Ignore request if printing + if (!isPrinting()) { + setTargetTemp_celsius(0, E0); + setTargetTemp_celsius(0, BED); + SendtoTFTLN(AC_msg_ready); + hotbed_state = AC_heater_off; + hotend_state = AC_heater_off; + } + break; + + case 26: // A26 Refresh SD + // M22 M21 maybe needed here to reset sd card + filenavigator.reset(); + break; + + case 27: // A27 Servo Angles adjust + break; + + case 28: // A28 Filament set A28 O/C + // Ignore request if printing + if (isPrinting()) break; + SendtoTFTLN(); + break; + } +} + +void ChironTFT::PanelProcess(uint8_t req) { + switch (req) { + case 29: { // A29 Read Mesh Point A29 X1 Y1 + xy_uint8_t pos; + float pos_z; + pos.x = atoi(&panel_command[5]); + pos.y = atoi(&panel_command[8]); + pos_z = getMeshPoint(pos); + + SendtoTFT(PSTR("A29V ")); + TFTSer.println(pos_z * 100); + if (!isPrinting()) { + setSoftEndstopState(true); // disable endstops + // If the same meshpoint is selected twice in a row, move the head to that ready for adjustment + if ((selectedmeshpoint.x == pos.x) && (selectedmeshpoint.y == pos.y)) { + if (!isPositionKnown()) + injectCommands_P(G28_STR); // home + + if (isPositionKnown()) { + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Moving to mesh point at x: ", pos.x, " y: ", pos.y, " z: ", pos_z); + #endif + // Go up before moving + setAxisPosition_mm(3.0,Z); + + setAxisPosition_mm(17 + (93 * pos.x), X); + setAxisPosition_mm(20 + (93 * pos.y), Y); + setAxisPosition_mm(0.0, Z); + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Current Z: ", getAxisPosition_mm(Z)); + #endif + } + } + selectedmeshpoint.x = pos.x; + selectedmeshpoint.y = pos.y; + } + } break; + + case 30: { // A30 Auto leveling + if (panel_command[3] == 'S') { // Start probing + // Ignore request if printing + if (isPrinting()) + SendtoTFTLN(AC_msg_probing_not_allowed); // forbid auto leveling + else { + injectCommands_P(PSTR("G28O\nG29")); + printer_state = AC_printer_probing; + SendtoTFTLN(AC_msg_start_probing); + } + } + else SendtoTFTLN(AC_msg_start_probing); + } break; + + case 31: { // A31 Adjust all Probe Points + switch (panel_command[3]) { + case 'C': // Restore and apply original offsets + if (!isPrinting()) { + injectCommands_P(PSTR("M501\nM420 S1")); + selectedmeshpoint.x = selectedmeshpoint.y = 99; + } + break; + case 'D': // Save Z Offset tables and restore leveling state + if (!isPrinting()) { + setAxisPosition_mm(1.0,Z); + injectCommands_P(PSTR("M500")); + selectedmeshpoint.x = selectedmeshpoint.y = 99; + } + break; + case 'G': // Get current offset + SendtoTFT(PSTR("A31V ")); + // When printing use the live z Offset position + // we will use babystepping to move the print head + if (isPrinting()) + TFTSer.println(live_Zoffset); + else { + TFTSer.println(getZOffset_mm()); + selectedmeshpoint.x = selectedmeshpoint.y = 99; + } + break; + case 'S': { // Set offset (adjusts all points by value) + float Zshift = atof(&panel_command[4]); + setSoftEndstopState(false); // disable endstops + // Allow temporary Z position nudging during print + // From the leveling panel use the all points UI to adjust the print pos. + if (isPrinting()) { + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Change Zoffset from:", live_Zoffset, " to ", live_Zoffset + Zshift); + #endif + if (isAxisPositionKnown(Z)) { + #if ACDEBUG(AC_INFO) + const float currZpos = getAxisPosition_mm(Z); + SERIAL_ECHOLNPAIR("Nudge Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05)); + #endif + // Use babystepping to adjust the head position + int16_t steps = mmToWholeSteps(constrain(Zshift,-0.05,0.05), Z); + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Steps to move Z: ", steps); + #endif + babystepAxis_steps(steps, Z); + live_Zoffset += Zshift; + } + SendtoTFT(PSTR("A31V ")); + TFTSer.println(live_Zoffset); + } + else { + GRID_LOOP(x, y) { + const xy_uint8_t pos { x, y }; + const float currval = getMeshPoint(pos); + setMeshPoint(pos, constrain(currval + Zshift, AC_LOWEST_MESHPOINT_VAL, 2)); + } + const float currZOffset = getZOffset_mm(); + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Change probe offset from ", currZOffset, " to ", currZOffset + Zshift); + #endif + + setZOffset_mm(currZOffset + Zshift); + SendtoTFT(PSTR("A31V ")); + TFTSer.println(getZOffset_mm()); + + if (isAxisPositionKnown(Z)) { + // Move Z axis + const float currZpos = getAxisPosition_mm(Z); + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05)); + #endif + setAxisPosition_mm(currZpos+constrain(Zshift,-0.05,0.05),Z); + } + } + } + } + } break; + + case 32: { // A32 clean leveling beep flag + // Ignore request if printing + //if (isPrinting()) break; + //injectCommands_P(PSTR("M500\nM420 S1\nG1 Z10 F240\nG1 X0 Y0 F6000")); + //TFTSer.println(); + } break; + + // A33 firmware info request see PanelInfo() + + case 34: { // A34 Adjust single mesh point A34 C/S X1 Y1 V123 + if (panel_command[3] == 'C') { // Restore original offsets + injectCommands_P(PSTR("M501\nM420 S1")); + selectedmeshpoint.x = selectedmeshpoint.y = 99; + //printer_state = AC_printer_idle; + } + else { xy_uint8_t pos; - float pos_z; pos.x = atoi(&panel_command[5]); pos.y = atoi(&panel_command[8]); - pos_z = getMeshPoint(pos); - SendtoTFT(PSTR("A29V ")); - TFTSer.println(pos_z * 100); - if (!isPrinting()) { - setSoftEndstopState(true); // disable endstops - // If the same meshpoint is selected twice in a row, move the head to that ready for adjustment - if ((selectedmeshpoint.x == pos.x) && (selectedmeshpoint.y == pos.y)) { - if (!isPositionKnown()) - injectCommands_P(G28_STR); // home - - if (isPositionKnown()) { - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("Moving to mesh point at x: ", pos.x, " y: ", pos.y, " z: ", pos_z); - #endif - // Go up before moving - setAxisPosition_mm(3.0,Z); - - setAxisPosition_mm(17 + (93 * pos.x), X); - setAxisPosition_mm(20 + (93 * pos.y), Y); - setAxisPosition_mm(0.0, Z); - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("Current Z: ", getAxisPosition_mm(Z)); - #endif - } - } - selectedmeshpoint.x = pos.x; - selectedmeshpoint.y = pos.y; - } - } break; - - case 30: { // A30 Auto leveling - if (panel_command[3] == 'S') { // Start probing - // Ignore request if printing - if (isPrinting()) - SendtoTFTLN(AC_msg_probing_not_allowed); // forbid auto leveling - else { - injectCommands_P(PSTR("G28O\nG29")); - printer_state = AC_printer_probing; - SendtoTFTLN(AC_msg_start_probing); + float currmesh = getMeshPoint(pos); + float newval = atof(&panel_command[11])/100; + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Change mesh point x:", pos.x, " y:", pos.y); + SERIAL_ECHOLNPAIR("from ", currmesh, " to ", newval); + #endif + // Update Meshpoint + setMeshPoint(pos,newval); + if (printer_state == AC_printer_idle || printer_state == AC_printer_probing /*!isPrinting()*/) { + // if we are at the current mesh point indicated on the panel Move Z pos +/- 0.05mm + // (The panel changes the mesh value by +/- 0.05mm on each button press) + if (selectedmeshpoint.x == pos.x && selectedmeshpoint.y == pos.y) { + setSoftEndstopState(false); + float currZpos = getAxisPosition_mm(Z); + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(newval - currmesh, -0.05, 0.05)); + #endif + setAxisPosition_mm(currZpos + constrain(newval - currmesh, -0.05, 0.05), Z); } } - else SendtoTFTLN(AC_msg_start_probing); - } break; - - case 31: { // A31 Adjust all Probe Points - switch (panel_command[3]) { - case 'C': // Restore and apply original offsets - if (!isPrinting()) { - injectCommands_P(PSTR("M501\nM420 S1")); - selectedmeshpoint.x = selectedmeshpoint.y = 99; - } - break; - case 'D': // Save Z Offset tables and restore leveling state - if (!isPrinting()) { - setAxisPosition_mm(1.0,Z); - injectCommands_P(PSTR("M500")); - selectedmeshpoint.x = selectedmeshpoint.y = 99; - } - break; - case 'G': // Get current offset - SendtoTFT(PSTR("A31V ")); - // When printing use the live z Offset position - // we will use babystepping to move the print head - if (isPrinting()) - TFTSer.println(live_Zoffset); - else { - TFTSer.println(getZOffset_mm()); - selectedmeshpoint.x = selectedmeshpoint.y = 99; - } - break; - case 'S': { // Set offset (adjusts all points by value) - float Zshift = atof(&panel_command[4]); - setSoftEndstopState(false); // disable endstops - // Allow temporary Z position nudging during print - // From the leveling panel use the all points UI to adjust the print pos. - if (isPrinting()) { - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("Change Zoffset from:", live_Zoffset, " to ", live_Zoffset + Zshift); - #endif - if (isAxisPositionKnown(Z)) { - #if ACDEBUG(AC_INFO) - const float currZpos = getAxisPosition_mm(Z); - SERIAL_ECHOLNPAIR("Nudge Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05)); - #endif - // Use babystepping to adjust the head position - int16_t steps = mmToWholeSteps(constrain(Zshift,-0.05,0.05), Z); - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("Steps to move Z: ", steps); - #endif - babystepAxis_steps(steps, Z); - live_Zoffset += Zshift; - } - SendtoTFT(PSTR("A31V ")); - TFTSer.println(live_Zoffset); - } - else { - GRID_LOOP(x, y) { - const xy_uint8_t pos { x, y }; - const float currval = getMeshPoint(pos); - setMeshPoint(pos, constrain(currval + Zshift, AC_LOWEST_MESHPOINT_VAL, 2)); - } - const float currZOffset = getZOffset_mm(); - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("Change probe offset from ", currZOffset, " to ", currZOffset + Zshift); - #endif - - setZOffset_mm(currZOffset + Zshift); - SendtoTFT(PSTR("A31V ")); - TFTSer.println(getZOffset_mm()); - - if (isAxisPositionKnown(Z)) { - // Move Z axis - const float currZpos = getAxisPosition_mm(Z); - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05)); - #endif - setAxisPosition_mm(currZpos+constrain(Zshift,-0.05,0.05),Z); - } - } - } break; - } // end switch - } break; - - case 32: { // A32 clean leveling beep flag - // Ignore request if printing - //if (isPrinting()) break; - //injectCommands_P(PSTR("M500\nM420 S1\nG1 Z10 F240\nG1 X0 Y0 F6000")); - //TFTSer.println(); - } break; - - // A33 firmware info request seet PanelInfo() - - case 34: { // A34 Adjust single mesh point A34 C/S X1 Y1 V123 - if (panel_command[3] == 'C') { // Restore original offsets - injectCommands_P(PSTR("M501\nM420 S1")); - selectedmeshpoint.x = selectedmeshpoint.y = 99; - //printer_state = AC_printer_idle; - } - else { - xy_uint8_t pos; - pos.x = atoi(&panel_command[5]); - pos.y = atoi(&panel_command[8]); - - float currmesh = getMeshPoint(pos); - float newval = atof(&panel_command[11])/100; - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("Change mesh point x:", pos.x, " y:", pos.y); - SERIAL_ECHOLNPAIR("from ", currmesh, " to ", newval); - #endif - // Update Meshpoint - setMeshPoint(pos,newval); - if (printer_state == AC_printer_idle || printer_state == AC_printer_probing /*!isPrinting()*/) { - // if we are at the current mesh point indicated on the panel Move Z pos +/- 0.05mm - // (The panel changes the mesh value by +/- 0.05mm on each button press) - if (selectedmeshpoint.x == pos.x && selectedmeshpoint.y == pos.y) { - setSoftEndstopState(false); - float currZpos = getAxisPosition_mm(Z); - #if ACDEBUG(AC_INFO) - SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(newval - currmesh, -0.05, 0.05)); - #endif - setAxisPosition_mm(currZpos + constrain(newval - currmesh, -0.05, 0.05), Z); - } - } - } - } break; - } + } + } break; } +} } // Anycubic diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h index e7bbd3cbbf..3c26cc0aec 100644 --- a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h @@ -35,46 +35,46 @@ namespace Anycubic { - class ChironTFT { - private: - static printer_state_t printer_state; - static paused_state_t pause_state; - static heater_state_t hotend_state; - static heater_state_t hotbed_state; - static xy_uint8_t selectedmeshpoint; - static char panel_command[MAX_CMND_LEN]; - static uint8_t command_len; - static char selectedfile[MAX_PATH_LEN]; - static float live_Zoffset; - static file_menu_t file_menu; +class ChironTFT { + private: + static printer_state_t printer_state; + static paused_state_t pause_state; + static heater_state_t hotend_state; + static heater_state_t hotbed_state; + static xy_uint8_t selectedmeshpoint; + static char panel_command[MAX_CMND_LEN]; + static uint8_t command_len; + static char selectedfile[MAX_PATH_LEN]; + static float live_Zoffset; + static file_menu_t file_menu; - public: - ChironTFT(); - static void Startup(); - static void IdleLoop(); - static void PrinterKilled(PGM_P,PGM_P); - static void MediaEvent(media_event_t); - static void TimerEvent(timer_event_t); - static void FilamentRunout(); - static void ConfirmationRequest(const char * const ); - static void StatusChange(const char * const ); - static void PowerLossRecovery(); + public: + ChironTFT(); + static void Startup(); + static void IdleLoop(); + static void PrinterKilled(PGM_P,PGM_P); + static void MediaEvent(media_event_t); + static void TimerEvent(timer_event_t); + static void FilamentRunout(); + static void ConfirmationRequest(const char * const ); + static void StatusChange(const char * const ); + static void PowerLossRecovery(); - private: - static void SendtoTFT(PGM_P); - static void SendtoTFTLN(PGM_P); - static bool ReadTFTCommand(); - static int8_t Findcmndpos(const char *, char); - static void CheckHeaters(); - static void SendFileList(int8_t); - static void SelectFile(); - static void InjectCommandandWait(PGM_P); - static void ProcessPanelRequest(); - static void PanelInfo(uint8_t); - static void PanelAction(uint8_t); - static void PanelProcess(uint8_t); - }; + private: + static void SendtoTFT(PGM_P); + static void SendtoTFTLN(PGM_P); + static bool ReadTFTCommand(); + static int8_t Findcmndpos(const char *, char); + static void CheckHeaters(); + static void SendFileList(int8_t); + static void SelectFile(); + static void InjectCommandandWait(PGM_P); + static void ProcessPanelRequest(); + static void PanelInfo(uint8_t); + static void PanelAction(uint8_t); + static void PanelProcess(uint8_t); +}; - extern ChironTFT Chiron; +extern ChironTFT Chiron; } // Anycubic diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h index 3087d83801..a8ebe9c776 100644 --- a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h @@ -109,19 +109,16 @@ #define AC_cmnd_power_loss_recovery PSTR("G28XYR5\nG28Z") // Lift, home X and Y then home Z when in 'safe' position namespace Anycubic { - enum heater_state_t : uint8_t { AC_heater_off, AC_heater_temp_set, AC_heater_temp_reached }; - enum paused_state_t : uint8_t { AC_paused_heater_timed_out, AC_paused_purging_filament, AC_paused_idle }; - enum printer_state_t : uint8_t { AC_printer_idle, AC_printer_probing, @@ -131,13 +128,11 @@ namespace Anycubic { AC_printer_stopping, AC_printer_resuming_from_power_outage }; - enum timer_event_t : uint8_t { AC_timer_started, AC_timer_paused, AC_timer_stopped }; - enum media_event_t : uint8_t { AC_media_inserted, AC_media_removed, @@ -149,5 +144,4 @@ namespace Anycubic { AC_menu_change_to_file, AC_menu_change_to_command }; - } // Anycubic