Marlin 2.0 for Flying Bear 4S/5
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

537 lines
14 KiB

/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_RELOADED)
#include "DGUSScreenHandler.h"
#include "DGUSDisplay.h"
#include "definition/DGUS_ScreenAddrList.h"
#include "definition/DGUS_ScreenSetup.h"
#include "../../../gcode/queue.h"
uint8_t DGUSScreenHandler::debug_count = 0;
#if ENABLED(SDSUPPORT)
ExtUI::FileList DGUSScreenHandler::filelist;
uint16_t DGUSScreenHandler::filelist_offset = 0;
int16_t DGUSScreenHandler::filelist_selected = -1;
#endif
DGUS_Data::StepSize DGUSScreenHandler::offset_steps = DGUS_Data::StepSize::MMP1;
DGUS_Data::StepSize DGUSScreenHandler::move_steps = DGUS_Data::StepSize::MM10;
uint16_t DGUSScreenHandler::probing_icons[] = { 0, 0 };
DGUS_Data::Extruder DGUSScreenHandler::filament_extruder = DGUS_Data::Extruder::CURRENT;
uint16_t DGUSScreenHandler::filament_length = DGUS_DEFAULT_FILAMENT_LEN;
char DGUSScreenHandler::gcode[] = "";
DGUS_Data::Heater DGUSScreenHandler::pid_heater = DGUS_Data::Heater::H0;
uint16_t DGUSScreenHandler::pid_temp = DGUS_PLA_TEMP_HOTEND;
uint8_t DGUSScreenHandler::pid_cycles = 5;
bool DGUSScreenHandler::settings_ready = false;
bool DGUSScreenHandler::booted = false;
DGUS_Screen DGUSScreenHandler::current_screen = DGUS_Screen::BOOT;
DGUS_Screen DGUSScreenHandler::new_screen = DGUS_Screen::BOOT;
bool DGUSScreenHandler::full_update = false;
DGUS_Screen DGUSScreenHandler::wait_return_screen = DGUS_Screen::HOME;
bool DGUSScreenHandler::wait_continue = false;
bool DGUSScreenHandler::leveling_active = false;
millis_t DGUSScreenHandler::status_expire = 0;
millis_t DGUSScreenHandler::eeprom_save = 0;
const char DGUS_MSG_HOMING_REQUIRED[] PROGMEM = "Homing required",
DGUS_MSG_BUSY[] PROGMEM = "Busy",
DGUS_MSG_UNDEF[] PROGMEM = "-",
DGUS_MSG_HOMING[] PROGMEM = "Homing...",
DGUS_MSG_FW_OUTDATED[] PROGMEM = "DWIN GUI/OS update required",
DGUS_MSG_ABL_REQUIRED[] PROGMEM = "Auto bed leveling required";
const char DGUS_CMD_HOME[] PROGMEM = "G28",
DGUS_CMD_EEPROM_SAVE[] PROGMEM = "M500";
void DGUSScreenHandler::Init() {
dgus_display.Init();
MoveToScreen(DGUS_Screen::BOOT, true);
}
void DGUSScreenHandler::Ready() {
dgus_display.PlaySound(1);
}
void DGUSScreenHandler::Loop() {
if (!settings_ready || current_screen == DGUS_Screen::KILL) {
return;
}
const millis_t ms = ExtUI::safe_millis();
static millis_t next_event_ms = 0;
if (new_screen != DGUS_Screen::BOOT) {
const DGUS_Screen screen = new_screen;
new_screen = DGUS_Screen::BOOT;
if (current_screen == screen) {
TriggerFullUpdate();
}
else {
MoveToScreen(screen);
}
return;
}
if (!booted && ELAPSED(ms, 3000)) {
booted = true;
if (current_screen == DGUS_Screen::BOOT) {
MoveToScreen(DGUS_Screen::HOME);
}
return;
}
if (ELAPSED(ms, next_event_ms) || full_update) {
next_event_ms = ms + DGUS_UPDATE_INTERVAL_MS;
if (!SendScreenVPData(current_screen, full_update)) {
DEBUG_ECHOLNPGM("SendScreenVPData failed");
}
return;
}
if (current_screen == DGUS_Screen::WAIT
&& ((wait_continue && !wait_for_user)
|| (!wait_continue && IsPrinterIdle()))) {
MoveToScreen(wait_return_screen, true);
return;
}
if (current_screen == DGUS_Screen::LEVELING_PROBING && IsPrinterIdle()) {
dgus_display.PlaySound(3);
SetStatusMessage(ExtUI::getMeshValid() ? F("Probing successful") : F("Probing failed"));
MoveToScreen(DGUS_Screen::LEVELING_AUTOMATIC);
return;
}
if (status_expire > 0 && ELAPSED(ms, status_expire)) {
SetStatusMessage(FPSTR(NUL_STR), 0);
return;
}
if (eeprom_save > 0 && ELAPSED(ms, eeprom_save) && IsPrinterIdle()) {
eeprom_save = 0;
queue.enqueue_now_P(DGUS_CMD_EEPROM_SAVE);
return;
}
dgus_display.Loop();
}
void DGUSScreenHandler::PrinterKilled(PGM_P error, PGM_P component) {
SetMessageLinePGM(error, 1);
SetMessageLinePGM(component, 2);
SetMessageLinePGM(NUL_STR, 3);
SetMessageLinePGM(GET_TEXT(MSG_PLEASE_RESET), 4);
dgus_display.PlaySound(3, 1, 200);
MoveToScreen(DGUS_Screen::KILL, true);
}
void DGUSScreenHandler::UserConfirmRequired(const char * const msg) {
dgus_screen_handler.SetMessageLinePGM(NUL_STR, 1);
dgus_screen_handler.SetMessageLine(msg, 2);
dgus_screen_handler.SetMessageLinePGM(NUL_STR, 3);
dgus_screen_handler.SetMessageLinePGM(NUL_STR, 4);
dgus_display.PlaySound(3);
dgus_screen_handler.ShowWaitScreen(current_screen, true);
}
void DGUSScreenHandler::SettingsReset() {
dgus_display.SetVolume(DGUS_DEFAULT_VOLUME);
dgus_display.SetBrightness(DGUS_DEFAULT_BRIGHTNESS);
if (!settings_ready) {
settings_ready = true;
Ready();
}
SetStatusMessage(F("EEPROM reset"));
}
void DGUSScreenHandler::StoreSettings(char *buff) {
eeprom_data_t data;
static_assert(sizeof(data) <= ExtUI::eeprom_data_size, "sizeof(eeprom_data_t) > eeprom_data_size.");
data.initialized = true;
data.volume = dgus_display.GetVolume();
data.brightness = dgus_display.GetBrightness();
data.abl = (ExtUI::getLevelingActive() && ExtUI::getMeshValid());
memcpy(buff, &data, sizeof(data));
}
void DGUSScreenHandler::LoadSettings(const char *buff) {
eeprom_data_t data;
static_assert(sizeof(data) <= ExtUI::eeprom_data_size, "sizeof(eeprom_data_t) > eeprom_data_size.");
memcpy(&data, buff, sizeof(data));
dgus_display.SetVolume(data.initialized ? data.volume : DGUS_DEFAULT_VOLUME);
dgus_display.SetBrightness(data.initialized ? data.brightness : DGUS_DEFAULT_BRIGHTNESS);
if (data.initialized) {
leveling_active = (data.abl && ExtUI::getMeshValid());
ExtUI::setLevelingActive(leveling_active);
}
}
void DGUSScreenHandler::ConfigurationStoreWritten(bool success) {
if (!success) {
SetStatusMessage(F("EEPROM write failed"));
}
}
void DGUSScreenHandler::ConfigurationStoreRead(bool success) {
if (!success) {
SetStatusMessage(F("EEPROM read failed"));
}
else if (!settings_ready) {
settings_ready = true;
Ready();
}
}
void DGUSScreenHandler::PlayTone(const uint16_t frequency, const uint16_t duration) {
UNUSED(duration);
if (frequency >= 1 && frequency <= 255) {
if (duration >= 1 && duration <= 255) {
dgus_display.PlaySound((uint8_t)frequency, (uint8_t)duration);
}
else {
dgus_display.PlaySound((uint8_t)frequency);
}
}
}
void DGUSScreenHandler::MeshUpdate(const int8_t xpos, const int8_t ypos) {
if (current_screen != DGUS_Screen::LEVELING_PROBING) {
if (current_screen == DGUS_Screen::LEVELING_AUTOMATIC) {
TriggerFullUpdate();
}
return;
}
uint8_t point = ypos * GRID_MAX_POINTS_X + xpos;
probing_icons[point < 16 ? 0 : 1] |= (1U << (point % 16));
if (xpos >= GRID_MAX_POINTS_X - 1
&& ypos >= GRID_MAX_POINTS_Y - 1
&& !ExtUI::getMeshValid()) {
probing_icons[0] = 0;
probing_icons[1] = 0;
}
TriggerFullUpdate();
}
void DGUSScreenHandler::PrintTimerStarted() {
TriggerScreenChange(DGUS_Screen::PRINT_STATUS);
}
void DGUSScreenHandler::PrintTimerPaused() {
dgus_display.PlaySound(3);
TriggerFullUpdate();
}
void DGUSScreenHandler::PrintTimerStopped() {
if (current_screen != DGUS_Screen::PRINT_STATUS
&& current_screen != DGUS_Screen::PRINT_ADJUST) {
return;
}
dgus_display.PlaySound(3);
TriggerScreenChange(DGUS_Screen::PRINT_FINISHED);
}
void DGUSScreenHandler::FilamentRunout(const ExtUI::extruder_t extruder) {
char buffer[21];
snprintf_P(buffer, sizeof(buffer), PSTR("Filament runout E%d"), extruder);
SetStatusMessage(buffer);
dgus_display.PlaySound(3);
}
#if ENABLED(SDSUPPORT)
void DGUSScreenHandler::SDCardInserted() {
if (current_screen == DGUS_Screen::HOME) {
TriggerScreenChange(DGUS_Screen::PRINT);
}
}
void DGUSScreenHandler::SDCardRemoved() {
if (current_screen == DGUS_Screen::PRINT) {
TriggerScreenChange(DGUS_Screen::HOME);
}
}
void DGUSScreenHandler::SDCardError() {
SetStatusMessage(GET_TEXT_F(MSG_MEDIA_READ_ERROR));
if (current_screen == DGUS_Screen::PRINT) {
TriggerScreenChange(DGUS_Screen::HOME);
}
}
#endif // SDSUPPORT
#if ENABLED(POWER_LOSS_RECOVERY)
void DGUSScreenHandler::PowerLossResume() {
MoveToScreen(DGUS_Screen::POWERLOSS, true);
}
#endif // POWER_LOSS_RECOVERY
#if HAS_PID_HEATING
void DGUSScreenHandler::PidTuning(const ExtUI::result_t rst) {
switch (rst) {
case ExtUI::PID_STARTED:
SetStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE));
break;
case ExtUI::PID_BAD_EXTRUDER_NUM:
SetStatusMessage(GET_TEXT_F(MSG_PID_BAD_EXTRUDER_NUM));
break;
case ExtUI::PID_TEMP_TOO_HIGH:
SetStatusMessage(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH));
break;
case ExtUI::PID_TUNING_TIMEOUT:
SetStatusMessage(GET_TEXT_F(MSG_PID_TIMEOUT));
break;
case ExtUI::PID_DONE:
SetStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE_DONE));
break;
default:
return;
}
dgus_display.PlaySound(3);
}
#endif // HAS_PID_HEATING
void DGUSScreenHandler::SetMessageLine(const char* msg, uint8_t line) {
switch (line) {
default: return;
case 1:
dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Line1, msg, DGUS_LINE_LEN, true, true);
break;
case 2:
dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Line2, msg, DGUS_LINE_LEN, true, true);
break;
case 3:
dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Line3, msg, DGUS_LINE_LEN, true, true);
break;
case 4:
dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Line4, msg, DGUS_LINE_LEN, true, true);
break;
}
}
void DGUSScreenHandler::SetMessageLinePGM(PGM_P msg, uint8_t line) {
switch (line) {
default: return;
case 1:
dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Line1, msg, DGUS_LINE_LEN, true, true);
break;
case 2:
dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Line2, msg, DGUS_LINE_LEN, true, true);
break;
case 3:
dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Line3, msg, DGUS_LINE_LEN, true, true);
break;
case 4:
dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Line4, msg, DGUS_LINE_LEN, true, true);
break;
}
}
void DGUSScreenHandler::SetStatusMessage(const char* msg, const millis_t duration) {
dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Status, msg, DGUS_STATUS_LEN, false, true);
status_expire = (duration > 0 ? ExtUI::safe_millis() + duration : 0);
}
void DGUSScreenHandler::SetStatusMessage(FSTR_P const fmsg, const millis_t duration) {
dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Status, FTOP(msg), DGUS_STATUS_LEN, false, true);
status_expire = (duration > 0 ? ExtUI::safe_millis() + duration : 0);
}
void DGUSScreenHandler::ShowWaitScreen(DGUS_Screen return_screen, bool has_continue) {
if (return_screen != DGUS_Screen::WAIT) {
wait_return_screen = return_screen;
}
wait_continue = has_continue;
TriggerScreenChange(DGUS_Screen::WAIT);
}
DGUS_Screen DGUSScreenHandler::GetCurrentScreen() {
return current_screen;
}
void DGUSScreenHandler::TriggerScreenChange(DGUS_Screen screen) {
new_screen = screen;
}
void DGUSScreenHandler::TriggerFullUpdate() {
full_update = true;
}
void DGUSScreenHandler::TriggerEEPROMSave() {
eeprom_save = ExtUI::safe_millis() + 500;
}
bool DGUSScreenHandler::IsPrinterIdle() {
return (!ExtUI::commandsInQueue()
&& !ExtUI::isMoving());
}
const DGUS_Addr* DGUSScreenHandler::FindScreenAddrList(DGUS_Screen screen) {
DGUS_ScreenAddrList list;
const DGUS_ScreenAddrList *map = screen_addr_list_map;
do {
memcpy_P(&list, map, sizeof(*map));
if (!list.addr_list) break;
if (list.screen == screen) {
return list.addr_list;
}
} while (++map);
return nullptr;
}
bool DGUSScreenHandler::CallScreenSetup(DGUS_Screen screen) {
DGUS_ScreenSetup setup;
const DGUS_ScreenSetup *list = screen_setup_list;
do {
memcpy_P(&setup, list, sizeof(*list));
if (!setup.setup_fn) break;
if (setup.screen == screen) {
return setup.setup_fn();
}
} while (++list);
return true;
}
void DGUSScreenHandler::MoveToScreen(DGUS_Screen screen, bool abort_wait) {
if (current_screen == DGUS_Screen::KILL) {
return;
}
if (current_screen == DGUS_Screen::WAIT) {
if (screen != DGUS_Screen::WAIT) {
wait_return_screen = screen;
}
if (!abort_wait) return;
if (wait_continue && wait_for_user) {
ExtUI::setUserConfirmed();
}
}
if (!CallScreenSetup(screen)) return;
if (!SendScreenVPData(screen, true)) {
DEBUG_ECHOLNPGM("SendScreenVPData failed");
return;
}
current_screen = screen;
dgus_display.SwitchScreen(current_screen);
}
bool DGUSScreenHandler::SendScreenVPData(DGUS_Screen screen, bool complete_update) {
if (complete_update) {
full_update = false;
}
const DGUS_Addr *list = FindScreenAddrList(screen);
while (true) {
if (!list) return true; // Nothing left to send
const uint16_t addr = pgm_read_word(list++);
if (!addr) return true; // Nothing left to send
DGUS_VP vp;
if (!DGUS_PopulateVP((DGUS_Addr)addr, &vp)) continue; // Invalid VP
if (!vp.tx_handler) continue; // Nothing to send
if (!complete_update && !(vp.flags & VPFLAG_AUTOUPLOAD)) continue; // Unnecessary VP
uint8_t expected_tx = 6 + vp.size; // 6 bytes header + payload.
const millis_t try_until = ExtUI::safe_millis() + 1000;
while (expected_tx > dgus_display.GetFreeTxBuffer()) {
if (ELAPSED(ExtUI::safe_millis(), try_until)) return false; // Stop trying after 1 second
dgus_display.FlushTx(); // Flush the TX buffer
delay(50);
}
vp.tx_handler(vp);
}
}
#endif // DGUS_LCD_UI_RELOADED