My Marlin configs for Fabrikator Mini and CTC i3 Pro B
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.

DGUSScreenHandler.cpp 38KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include "../../../../inc/MarlinConfigPre.h"
  23. #if HAS_DGUS_LCD
  24. #include "DGUSScreenHandler.h"
  25. #include "DGUSDisplay.h"
  26. #include "DGUSVPVariable.h"
  27. #include "DGUSDisplayDef.h"
  28. #include "../../ui_api.h"
  29. #include "../../../../MarlinCore.h"
  30. #include "../../../../module/temperature.h"
  31. #include "../../../../module/motion.h"
  32. #include "../../../../gcode/queue.h"
  33. #include "../../../../module/planner.h"
  34. #include "../../../../sd/cardreader.h"
  35. #include "../../../../libs/duration_t.h"
  36. #include "../../../../module/printcounter.h"
  37. #if ENABLED(POWER_LOSS_RECOVERY)
  38. #include "../../../../feature/powerloss.h"
  39. #endif
  40. uint16_t DGUSScreenHandler::ConfirmVP;
  41. #if ENABLED(SDSUPPORT)
  42. int16_t DGUSScreenHandler::top_file = 0;
  43. int16_t DGUSScreenHandler::file_to_print = 0;
  44. static ExtUI::FileList filelist;
  45. #endif
  46. void (*DGUSScreenHandler::confirm_action_cb)() = nullptr;
  47. //DGUSScreenHandler ScreenHandler;
  48. DGUSLCD_Screens DGUSScreenHandler::current_screen;
  49. DGUSLCD_Screens DGUSScreenHandler::past_screens[NUM_PAST_SCREENS];
  50. uint8_t DGUSScreenHandler::update_ptr;
  51. uint16_t DGUSScreenHandler::skipVP;
  52. bool DGUSScreenHandler::ScreenComplete;
  53. //DGUSDisplay dgusdisplay;
  54. // endianness swap
  55. uint16_t swap16(const uint16_t value) { return (value & 0xffU) << 8U | (value >> 8U); }
  56. void DGUSScreenHandler::sendinfoscreen(const char* line1, const char* line2, const char* line3, const char* line4, bool l1inflash, bool l2inflash, bool l3inflash, bool l4inflash) {
  57. DGUS_VP_Variable ramcopy;
  58. if (populate_VPVar(VP_MSGSTR1, &ramcopy)) {
  59. ramcopy.memadr = (void*) line1;
  60. l1inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  61. }
  62. if (populate_VPVar(VP_MSGSTR2, &ramcopy)) {
  63. ramcopy.memadr = (void*) line2;
  64. l2inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  65. }
  66. if (populate_VPVar(VP_MSGSTR3, &ramcopy)) {
  67. ramcopy.memadr = (void*) line3;
  68. l3inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  69. }
  70. if (populate_VPVar(VP_MSGSTR4, &ramcopy)) {
  71. ramcopy.memadr = (void*) line4;
  72. l4inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  73. }
  74. }
  75. void DGUSScreenHandler::HandleUserConfirmationPopUp(uint16_t VP, const char* line1, const char* line2, const char* line3, const char* line4, bool l1, bool l2, bool l3, bool l4) {
  76. if (current_screen == DGUSLCD_SCREEN_CONFIRM) {
  77. // Already showing a pop up, so we need to cancel that first.
  78. PopToOldScreen();
  79. }
  80. ConfirmVP = VP;
  81. sendinfoscreen(line1, line2, line3, line4, l1, l2, l3, l4);
  82. ScreenHandler.GotoScreen(DGUSLCD_SCREEN_CONFIRM);
  83. }
  84. void DGUSScreenHandler::setstatusmessage(const char *msg) {
  85. DGUS_VP_Variable ramcopy;
  86. if (populate_VPVar(VP_M117, &ramcopy)) {
  87. ramcopy.memadr = (void*) msg;
  88. DGUSLCD_SendStringToDisplay(ramcopy);
  89. }
  90. }
  91. void DGUSScreenHandler::setstatusmessagePGM(PGM_P const msg) {
  92. DGUS_VP_Variable ramcopy;
  93. if (populate_VPVar(VP_M117, &ramcopy)) {
  94. ramcopy.memadr = (void*) msg;
  95. DGUSLCD_SendStringToDisplayPGM(ramcopy);
  96. }
  97. }
  98. // Send an 8 bit or 16 bit value to the display.
  99. void DGUSScreenHandler::DGUSLCD_SendWordValueToDisplay(DGUS_VP_Variable &var) {
  100. if (var.memadr) {
  101. //DEBUG_ECHOPAIR(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
  102. //DEBUG_ECHOLNPAIR(" data ", *(uint16_t *)var.memadr);
  103. if (var.size > 1)
  104. dgusdisplay.WriteVariable(var.VP, *(int16_t*)var.memadr);
  105. else
  106. dgusdisplay.WriteVariable(var.VP, *(int8_t*)var.memadr);
  107. }
  108. }
  109. // Send an uint8_t between 0 and 255 to the display, but scale to a percentage (0..100)
  110. void DGUSScreenHandler::DGUSLCD_SendPercentageToDisplay(DGUS_VP_Variable &var) {
  111. if (var.memadr) {
  112. //DEBUG_ECHOPAIR(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
  113. //DEBUG_ECHOLNPAIR(" data ", *(uint16_t *)var.memadr);
  114. uint16_t tmp = *(uint8_t *) var.memadr +1 ; // +1 -> avoid rounding issues for the display.
  115. tmp = map(tmp, 0, 255, 0, 100);
  116. dgusdisplay.WriteVariable(var.VP, tmp);
  117. }
  118. }
  119. // Send the current print progress to the display.
  120. void DGUSScreenHandler::DGUSLCD_SendPrintProgressToDisplay(DGUS_VP_Variable &var) {
  121. //DEBUG_ECHOPAIR(" DGUSLCD_SendPrintProgressToDisplay ", var.VP);
  122. uint16_t tmp = ExtUI::getProgress_percent();
  123. //DEBUG_ECHOLNPAIR(" data ", tmp);
  124. dgusdisplay.WriteVariable(var.VP, tmp);
  125. }
  126. // Send the current print time to the display.
  127. // It is using a hex display for that: It expects BSD coded data in the format xxyyzz
  128. void DGUSScreenHandler::DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var) {
  129. duration_t elapsed = print_job_timer.duration();
  130. char buf[32];
  131. elapsed.toString(buf);
  132. dgusdisplay.WriteVariable(VP_PrintTime, buf, var.size, true);
  133. }
  134. // Send an uint8_t between 0 and 100 to a variable scale to 0..255
  135. void DGUSScreenHandler::DGUSLCD_PercentageToUint8(DGUS_VP_Variable &var, void *val_ptr) {
  136. if (var.memadr) {
  137. uint16_t value = swap16(*(uint16_t*)val_ptr);
  138. *(uint8_t*)var.memadr = map(constrain(value, 0, 100), 0, 100, 0, 255);
  139. }
  140. }
  141. // Sends a (RAM located) string to the DGUS Display
  142. // (Note: The DGUS Display does not clear after the \0, you have to
  143. // overwrite the remainings with spaces.// var.size has the display buffer size!
  144. void DGUSScreenHandler::DGUSLCD_SendStringToDisplay(DGUS_VP_Variable &var) {
  145. char *tmp = (char*) var.memadr;
  146. dgusdisplay.WriteVariable(var.VP, tmp, var.size, true);
  147. }
  148. // Sends a (flash located) string to the DGUS Display
  149. // (Note: The DGUS Display does not clear after the \0, you have to
  150. // overwrite the remainings with spaces.// var.size has the display buffer size!
  151. void DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(DGUS_VP_Variable &var) {
  152. char *tmp = (char*) var.memadr;
  153. dgusdisplay.WriteVariablePGM(var.VP, tmp, var.size, true);
  154. }
  155. #if HAS_PID_HEATING
  156. void DGUSScreenHandler::DGUSLCD_SendTemperaturePID(DGUS_VP_Variable &var) {
  157. float value = *(float *)var.memadr;
  158. float valuesend = 0;
  159. switch (var.VP) {
  160. default: return;
  161. #if HOTENDS >= 1
  162. case VP_E0_PID_P: valuesend = value; break;
  163. case VP_E0_PID_I: valuesend = unscalePID_i(value); break;
  164. case VP_E0_PID_D: valuesend = unscalePID_d(value); break;
  165. #endif
  166. #if HOTENDS >= 2
  167. case VP_E1_PID_P: valuesend = value; break;
  168. case VP_E1_PID_I: valuesend = unscalePID_i(value); break;
  169. case VP_E1_PID_D: valuesend = unscalePID_d(value); break;
  170. #endif
  171. #if HAS_HEATED_BED
  172. case VP_BED_PID_P: valuesend = value; break;
  173. case VP_BED_PID_I: valuesend = unscalePID_i(value); break;
  174. case VP_BED_PID_D: valuesend = unscalePID_d(value); break;
  175. #endif
  176. }
  177. valuesend *= cpow(10, 1);
  178. union { int16_t i; char lb[2]; } endian;
  179. char tmp[2];
  180. endian.i = valuesend;
  181. tmp[0] = endian.lb[1];
  182. tmp[1] = endian.lb[0];
  183. dgusdisplay.WriteVariable(var.VP, tmp, 2);
  184. }
  185. #endif
  186. #if ENABLED(PRINTCOUNTER)
  187. // Send the accumulate print time to the display.
  188. // It is using a hex display for that: It expects BSD coded data in the format xxyyzz
  189. void DGUSScreenHandler::DGUSLCD_SendPrintAccTimeToDisplay(DGUS_VP_Variable &var) {
  190. printStatistics state = print_job_timer.getStats();
  191. char buf[21];
  192. duration_t elapsed = state.printTime;
  193. elapsed.toString(buf);
  194. dgusdisplay.WriteVariable(VP_PrintAccTime, buf, var.size, true);
  195. }
  196. void DGUSScreenHandler::DGUSLCD_SendPrintsTotalToDisplay(DGUS_VP_Variable &var) {
  197. printStatistics state = print_job_timer.getStats();
  198. char buf[21];
  199. sprintf_P(buf, PSTR("%u"), state.totalPrints);
  200. dgusdisplay.WriteVariable(VP_PrintsTotal, buf, var.size, true);
  201. }
  202. #endif
  203. // Send fan status value to the display.
  204. #if HAS_FAN
  205. void DGUSScreenHandler::DGUSLCD_SendFanStatusToDisplay(DGUS_VP_Variable &var) {
  206. if (var.memadr) {
  207. DEBUG_ECHOPAIR(" DGUSLCD_SendFanStatusToDisplay ", var.VP);
  208. DEBUG_ECHOLNPAIR(" data ", *(uint8_t *)var.memadr);
  209. uint16_t data_to_send = 0;
  210. if (*(uint8_t *) var.memadr) data_to_send = 1;
  211. dgusdisplay.WriteVariable(var.VP, data_to_send);
  212. }
  213. }
  214. #endif
  215. // Send heater status value to the display.
  216. void DGUSScreenHandler::DGUSLCD_SendHeaterStatusToDisplay(DGUS_VP_Variable &var) {
  217. if (var.memadr) {
  218. DEBUG_ECHOPAIR(" DGUSLCD_SendHeaterStatusToDisplay ", var.VP);
  219. DEBUG_ECHOLNPAIR(" data ", *(int16_t *)var.memadr);
  220. uint16_t data_to_send = 0;
  221. if (*(int16_t *) var.memadr) data_to_send = 1;
  222. dgusdisplay.WriteVariable(var.VP, data_to_send);
  223. }
  224. }
  225. #if ENABLED(DGUS_UI_WAITING)
  226. void DGUSScreenHandler::DGUSLCD_SendWaitingStatusToDisplay(DGUS_VP_Variable &var) {
  227. // In FYSETC UI design there are 10 statuses to loop
  228. static uint16_t period = 0;
  229. static uint16_t index = 0;
  230. //DEBUG_ECHOPAIR(" DGUSLCD_SendWaitingStatusToDisplay ", var.VP);
  231. //DEBUG_ECHOLNPAIR(" data ", swap16(index));
  232. if (period++ > DGUS_UI_WAITING_STATUS_PERIOD) {
  233. dgusdisplay.WriteVariable(var.VP, index);
  234. //DEBUG_ECHOLNPAIR(" data ", swap16(index));
  235. if (++index >= DGUS_UI_WAITING_STATUS) index = 0;
  236. period = 0;
  237. }
  238. }
  239. #endif
  240. #if ENABLED(SDSUPPORT)
  241. void DGUSScreenHandler::ScreenChangeHookIfSD(DGUS_VP_Variable &var, void *val_ptr) {
  242. // default action executed when there is a SD card, but not printing
  243. if (ExtUI::isMediaInserted() && !ExtUI::isPrintingFromMedia()) {
  244. ScreenChangeHook(var, val_ptr);
  245. dgusdisplay.RequestScreen(current_screen);
  246. return;
  247. }
  248. // if we are printing, we jump to two screens after the requested one.
  249. // This should host e.g a print pause / print abort / print resume dialog.
  250. // This concept allows to recycle this hook for other file
  251. if (ExtUI::isPrintingFromMedia() && !card.flag.abort_sd_printing) {
  252. GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
  253. return;
  254. }
  255. // Don't let the user in the dark why there is no reaction.
  256. if (!ExtUI::isMediaInserted()) {
  257. setstatusmessagePGM(GET_TEXT(MSG_NO_MEDIA));
  258. return;
  259. }
  260. if (card.flag.abort_sd_printing) {
  261. setstatusmessagePGM(GET_TEXT(MSG_MEDIA_ABORTING));
  262. return;
  263. }
  264. }
  265. void DGUSScreenHandler::DGUSLCD_SD_ScrollFilelist(DGUS_VP_Variable& var, void *val_ptr) {
  266. auto old_top = top_file;
  267. const int16_t scroll = (int16_t)swap16(*(uint16_t*)val_ptr);
  268. if (scroll) {
  269. top_file += scroll;
  270. DEBUG_ECHOPAIR("new topfile calculated:", top_file);
  271. if (top_file < 0) {
  272. top_file = 0;
  273. DEBUG_ECHOLNPGM("Top of filelist reached");
  274. }
  275. else {
  276. int16_t max_top = filelist.count() - DGUS_SD_FILESPERSCREEN;
  277. NOLESS(max_top, 0);
  278. NOMORE(top_file, max_top);
  279. }
  280. DEBUG_ECHOPAIR("new topfile adjusted:", top_file);
  281. }
  282. else if (!filelist.isAtRootDir()) {
  283. filelist.upDir();
  284. top_file = 0;
  285. ForceCompleteUpdate();
  286. }
  287. if (old_top != top_file) ForceCompleteUpdate();
  288. }
  289. void DGUSScreenHandler::DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr) {
  290. uint16_t touched_nr = (int16_t)swap16(*(uint16_t*)val_ptr) + top_file;
  291. if (touched_nr > filelist.count()) return;
  292. if (!filelist.seek(touched_nr)) return;
  293. if (filelist.isDir()) {
  294. filelist.changeDir(filelist.filename());
  295. top_file = 0;
  296. ForceCompleteUpdate();
  297. return;
  298. }
  299. #if ENABLED(DGUS_PRINT_FILENAME)
  300. // Send print filename
  301. dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), VP_SD_FileName_LEN, true);
  302. #endif
  303. // Setup Confirmation screen
  304. file_to_print = touched_nr;
  305. HandleUserConfirmationPopUp(VP_SD_FileSelectConfirm, nullptr, PSTR("Print file"), filelist.filename(), PSTR("from SD Card?"), true, true, false, true);
  306. }
  307. void DGUSScreenHandler::DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr) {
  308. if (!filelist.seek(file_to_print)) return;
  309. ExtUI::printFile(filelist.shortFilename());
  310. ScreenHandler.GotoScreen(
  311. #if ENABLED(DGUS_LCD_UI_ORIGIN)
  312. DGUSLCD_SCREEN_STATUS
  313. #else
  314. DGUSLCD_SCREEN_SDPRINTMANIPULATION
  315. #endif
  316. );
  317. }
  318. void DGUSScreenHandler::DGUSLCD_SD_ResumePauseAbort(DGUS_VP_Variable &var, void *val_ptr) {
  319. if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
  320. switch (swap16(*(uint16_t*)val_ptr)) {
  321. case 0: // Resume
  322. if (ExtUI::isPrintingFromMediaPaused()) ExtUI::resumePrint();
  323. break;
  324. case 1: // Pause
  325. if (!ExtUI::isPrintingFromMediaPaused()) ExtUI::pausePrint();
  326. break;
  327. case 2: // Abort
  328. ScreenHandler.HandleUserConfirmationPopUp(VP_SD_AbortPrintConfirmed, nullptr, PSTR("Abort printing"), filelist.filename(), PSTR("?"), true, true, false, true);
  329. break;
  330. }
  331. }
  332. void DGUSScreenHandler::DGUSLCD_SD_ReallyAbort(DGUS_VP_Variable &var, void *val_ptr) {
  333. ExtUI::stopPrint();
  334. GotoScreen(DGUSLCD_SCREEN_MAIN);
  335. }
  336. void DGUSScreenHandler::DGUSLCD_SD_PrintTune(DGUS_VP_Variable &var, void *val_ptr) {
  337. if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
  338. GotoScreen(DGUSLCD_SCREEN_SDPRINTTUNE);
  339. }
  340. void DGUSScreenHandler::DGUSLCD_SD_SendFilename(DGUS_VP_Variable& var) {
  341. uint16_t target_line = (var.VP - VP_SD_FileName0) / VP_SD_FileName_LEN;
  342. if (target_line > DGUS_SD_FILESPERSCREEN) return;
  343. char tmpfilename[VP_SD_FileName_LEN + 1] = "";
  344. var.memadr = (void*)tmpfilename;
  345. if (filelist.seek(top_file + target_line))
  346. snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s%c"), filelist.filename(), filelist.isDir() ? '/' : 0);
  347. DGUSLCD_SendStringToDisplay(var);
  348. }
  349. void DGUSScreenHandler::SDCardInserted() {
  350. top_file = 0;
  351. filelist.refresh();
  352. auto cs = ScreenHandler.getCurrentScreen();
  353. if (cs == DGUSLCD_SCREEN_MAIN || cs == DGUSLCD_SCREEN_STATUS)
  354. ScreenHandler.GotoScreen(DGUSLCD_SCREEN_SDFILELIST);
  355. }
  356. void DGUSScreenHandler::SDCardRemoved() {
  357. if (current_screen == DGUSLCD_SCREEN_SDFILELIST
  358. || (current_screen == DGUSLCD_SCREEN_CONFIRM && (ConfirmVP == VP_SD_AbortPrintConfirmed || ConfirmVP == VP_SD_FileSelectConfirm))
  359. || current_screen == DGUSLCD_SCREEN_SDPRINTMANIPULATION
  360. ) ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN);
  361. }
  362. void DGUSScreenHandler::SDCardError() {
  363. DGUSScreenHandler::SDCardRemoved();
  364. ScreenHandler.sendinfoscreen(PSTR("NOTICE"), nullptr, PSTR("SD card error"), nullptr, true, true, true, true);
  365. ScreenHandler.SetupConfirmAction(nullptr);
  366. ScreenHandler.GotoScreen(DGUSLCD_SCREEN_POPUP);
  367. }
  368. #endif // SDSUPPORT
  369. void DGUSScreenHandler::ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr) {
  370. DGUS_VP_Variable ramcopy;
  371. if (!populate_VPVar(ConfirmVP, &ramcopy)) return;
  372. if (ramcopy.set_by_display_handler) ramcopy.set_by_display_handler(ramcopy, val_ptr);
  373. }
  374. const uint16_t* DGUSLCD_FindScreenVPMapList(uint8_t screen) {
  375. const uint16_t *ret;
  376. const struct VPMapping *map = VPMap;
  377. while (ret = (uint16_t*) pgm_read_ptr(&(map->VPList))) {
  378. if (pgm_read_byte(&(map->screen)) == screen) return ret;
  379. map++;
  380. }
  381. return nullptr;
  382. }
  383. const DGUS_VP_Variable* DGUSLCD_FindVPVar(const uint16_t vp) {
  384. const DGUS_VP_Variable *ret = ListOfVP;
  385. do {
  386. const uint16_t vpcheck = pgm_read_word(&(ret->VP));
  387. if (vpcheck == 0) break;
  388. if (vpcheck == vp) return ret;
  389. ++ret;
  390. } while (1);
  391. DEBUG_ECHOLNPAIR("FindVPVar NOT FOUND ", vp);
  392. return nullptr;
  393. }
  394. void DGUSScreenHandler::ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr) {
  395. if (!ExtUI::isPrinting()) {
  396. ScreenChangeHook(var, val_ptr);
  397. dgusdisplay.RequestScreen(current_screen);
  398. }
  399. }
  400. void DGUSScreenHandler::ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr) {
  401. uint8_t *tmp = (uint8_t*)val_ptr;
  402. // The keycode in target is coded as <from-frame><to-frame>, so 0x0100A means
  403. // from screen 1 (main) to 10 (temperature). DGUSLCD_SCREEN_POPUP is special,
  404. // meaning "return to previous screen"
  405. DGUSLCD_Screens target = (DGUSLCD_Screens)tmp[1];
  406. if (target == DGUSLCD_SCREEN_POPUP) {
  407. // special handling for popup is to return to previous menu
  408. if (current_screen == DGUSLCD_SCREEN_POPUP && confirm_action_cb) confirm_action_cb();
  409. PopToOldScreen();
  410. return;
  411. }
  412. UpdateNewScreen(target);
  413. #ifdef DEBUG_DGUSLCD
  414. if (!DGUSLCD_FindScreenVPMapList(target)) DEBUG_ECHOLNPAIR("WARNING: No screen Mapping found for ", target);
  415. #endif
  416. }
  417. void DGUSScreenHandler::HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr) {
  418. thermalManager.disable_all_heaters();
  419. ScreenHandler.ForceCompleteUpdate(); // hint to send all data.
  420. }
  421. void DGUSScreenHandler::HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr) {
  422. uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
  423. uint16_t acceptedvalue;
  424. switch (var.VP) {
  425. default: return;
  426. #if HOTENDS >= 1
  427. case VP_T_E0_Set:
  428. thermalManager.setTargetHotend(newvalue, 0);
  429. acceptedvalue = thermalManager.temp_hotend[0].target;
  430. break;
  431. #endif
  432. #if HOTENDS >= 2
  433. case VP_T_E1_Set:
  434. thermalManager.setTargetHotend(newvalue, 1);
  435. acceptedvalue = thermalManager.temp_hotend[1].target;
  436. break;
  437. #endif
  438. #if HAS_HEATED_BED
  439. case VP_T_Bed_Set:
  440. thermalManager.setTargetBed(newvalue);
  441. acceptedvalue = thermalManager.temp_bed.target;
  442. break;
  443. #endif
  444. }
  445. // reply to display the new value to update the view if the new value was rejected by the Thermal Manager.
  446. if (newvalue != acceptedvalue && var.send_to_display_handler) var.send_to_display_handler(var);
  447. ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  448. }
  449. void DGUSScreenHandler::HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr) {
  450. #if EXTRUDERS
  451. uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
  452. uint8_t target_extruder;
  453. switch (var.VP) {
  454. default: return;
  455. #if HOTENDS >= 1
  456. case VP_Flowrate_E0: target_extruder = 0; break;
  457. #endif
  458. #if HOTENDS >= 2
  459. case VP_Flowrate_E1: target_extruder = 1; break;
  460. #endif
  461. }
  462. planner.set_flow(target_extruder, newvalue);
  463. ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  464. #else
  465. UNUSED(var); UNUSED(val_ptr);
  466. #endif
  467. }
  468. void DGUSScreenHandler::HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr) {
  469. DEBUG_ECHOLNPGM("HandleManualExtrude");
  470. int16_t movevalue = swap16(*(uint16_t*)val_ptr);
  471. float target = movevalue * 0.01f;
  472. ExtUI::extruder_t target_extruder;
  473. switch (var.VP) {
  474. #if HOTENDS >= 1
  475. case VP_MOVE_E0: target_extruder = ExtUI::extruder_t::E0; break;
  476. #endif
  477. #if HOTENDS >= 2
  478. case VP_MOVE_E1: target_extruder = ExtUI::extruder_t::E1; break;
  479. #endif
  480. default: return;
  481. }
  482. target += ExtUI::getAxisPosition_mm(target_extruder);
  483. ExtUI::setAxisPosition_mm(target, target_extruder);
  484. skipVP = var.VP;
  485. }
  486. #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
  487. void DGUSScreenHandler::HandleManualMoveOption(DGUS_VP_Variable &var, void *val_ptr) {
  488. DEBUG_ECHOLNPGM("HandleManualMoveOption");
  489. *(uint16_t*)var.memadr = swap16(*(uint16_t*)val_ptr);
  490. }
  491. #endif
  492. void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
  493. DEBUG_ECHOLNPGM("HandleManualMove");
  494. int16_t movevalue = swap16(*(uint16_t*)val_ptr);
  495. #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
  496. if (movevalue) {
  497. const uint16_t choice = *(uint16_t*)var.memadr;
  498. movevalue = movevalue < 0 ? -choice : choice;
  499. }
  500. #endif
  501. char axiscode;
  502. unsigned int speed = 1500; //FIXME: get default feedrate for manual moves, dont hardcode.
  503. switch (var.VP) {
  504. default: return;
  505. case VP_MOVE_X:
  506. axiscode = 'X';
  507. if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
  508. break;
  509. case VP_MOVE_Y:
  510. axiscode = 'Y';
  511. if (!ExtUI::canMove(ExtUI::axis_t::Y)) goto cannotmove;
  512. break;
  513. case VP_MOVE_Z:
  514. axiscode = 'Z';
  515. speed = 300; // default to 5mm/s
  516. if (!ExtUI::canMove(ExtUI::axis_t::Z)) goto cannotmove;
  517. break;
  518. case VP_HOME_ALL: // only used for homing
  519. axiscode = '\0';
  520. movevalue = 0; // ignore value sent from display, this VP is _ONLY_ for homing.
  521. break;
  522. }
  523. if (!movevalue) {
  524. // homing
  525. DEBUG_ECHOPAIR(" homing ", axiscode);
  526. char buf[6] = "G28 X";
  527. buf[4] = axiscode;
  528. //DEBUG_ECHOPAIR(" ", buf);
  529. queue.enqueue_one_now(buf);
  530. //DEBUG_ECHOLNPGM(" ✓");
  531. ScreenHandler.ForceCompleteUpdate();
  532. return;
  533. }
  534. else {
  535. //movement
  536. DEBUG_ECHOPAIR(" move ", axiscode);
  537. bool old_relative_mode = relative_mode;
  538. if (!relative_mode) {
  539. //DEBUG_ECHOPGM(" G91");
  540. queue.enqueue_now_P(PSTR("G91"));
  541. //DEBUG_ECHOPGM(" ✓ ");
  542. }
  543. char buf[32]; // G1 X9999.99 F12345
  544. unsigned int backup_speed = MMS_TO_MMM(feedrate_mm_s);
  545. char sign[]="\0";
  546. int16_t value = movevalue / 100;
  547. if (movevalue < 0) { value = -value; sign[0] = '-'; }
  548. int16_t fraction = ABS(movevalue) % 100;
  549. snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed);
  550. //DEBUG_ECHOPAIR(" ", buf);
  551. queue.enqueue_one_now(buf);
  552. //DEBUG_ECHOLNPGM(" ✓ ");
  553. if (backup_speed != speed) {
  554. snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed);
  555. queue.enqueue_one_now(buf);
  556. //DEBUG_ECHOPAIR(" ", buf);
  557. }
  558. //while (!enqueue_and_echo_command(buf)) idle();
  559. //DEBUG_ECHOLNPGM(" ✓ ");
  560. if (!old_relative_mode) {
  561. //DEBUG_ECHOPGM("G90");
  562. queue.enqueue_now_P(PSTR("G90"));
  563. //DEBUG_ECHOPGM(" ✓ ");
  564. }
  565. }
  566. ScreenHandler.ForceCompleteUpdate();
  567. DEBUG_ECHOLNPGM("manmv done.");
  568. return;
  569. cannotmove:
  570. DEBUG_ECHOLNPAIR(" cannot move ", axiscode);
  571. return;
  572. }
  573. void DGUSScreenHandler::HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr) {
  574. DEBUG_ECHOLNPGM("HandleMotorLockUnlock");
  575. char buf[4];
  576. const int16_t lock = swap16(*(uint16_t*)val_ptr);
  577. strcpy_P(buf, lock ? PSTR("M18") : PSTR("M17"));
  578. //DEBUG_ECHOPAIR(" ", buf);
  579. queue.enqueue_one_now(buf);
  580. }
  581. #if ENABLED(POWER_LOSS_RECOVERY)
  582. void DGUSScreenHandler::HandlePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr) {
  583. uint16_t value = swap16(*(uint16_t*)val_ptr);
  584. if (value) {
  585. queue.inject_P(PSTR("M1000"));
  586. ScreenHandler.GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
  587. }
  588. else {
  589. recovery.cancel();
  590. ScreenHandler.GotoScreen(DGUSLCD_SCREEN_STATUS);
  591. }
  592. }
  593. #endif
  594. void DGUSScreenHandler::HandleSettings(DGUS_VP_Variable &var, void *val_ptr) {
  595. DEBUG_ECHOLNPGM("HandleSettings");
  596. uint16_t value = swap16(*(uint16_t*)val_ptr);
  597. switch (value) {
  598. default: break;
  599. case 1:
  600. TERN_(PRINTCOUNTER, print_job_timer.initStats());
  601. queue.inject_P(PSTR("M502\nM500"));
  602. break;
  603. case 2: queue.inject_P(PSTR("M501")); break;
  604. case 3: queue.inject_P(PSTR("M500")); break;
  605. }
  606. }
  607. void DGUSScreenHandler::HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr) {
  608. DEBUG_ECHOLNPGM("HandleStepPerMMChanged");
  609. uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
  610. DEBUG_ECHOLNPAIR("value_raw:", value_raw);
  611. float value = (float)value_raw/10;
  612. ExtUI::axis_t axis;
  613. switch (var.VP) {
  614. case VP_X_STEP_PER_MM: axis = ExtUI::axis_t::X; break;
  615. case VP_Y_STEP_PER_MM: axis = ExtUI::axis_t::Y; break;
  616. case VP_Z_STEP_PER_MM: axis = ExtUI::axis_t::Z; break;
  617. default: return;
  618. }
  619. DEBUG_ECHOLNPAIR_F("value:", value);
  620. ExtUI::setAxisSteps_per_mm(value, axis);
  621. DEBUG_ECHOLNPAIR_F("value_set:", ExtUI::getAxisSteps_per_mm(axis));
  622. ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  623. return;
  624. }
  625. void DGUSScreenHandler::HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr) {
  626. DEBUG_ECHOLNPGM("HandleStepPerMMExtruderChanged");
  627. uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
  628. DEBUG_ECHOLNPAIR("value_raw:", value_raw);
  629. float value = (float)value_raw/10;
  630. ExtUI::extruder_t extruder;
  631. switch (var.VP) {
  632. default: return;
  633. #if HOTENDS >= 1
  634. case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break;
  635. #endif
  636. #if HOTENDS >= 2
  637. case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break;
  638. #endif
  639. }
  640. DEBUG_ECHOLNPAIR_F("value:", value);
  641. ExtUI::setAxisSteps_per_mm(value,extruder);
  642. DEBUG_ECHOLNPAIR_F("value_set:", ExtUI::getAxisSteps_per_mm(extruder));
  643. ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  644. return;
  645. }
  646. #if HAS_PID_HEATING
  647. void DGUSScreenHandler::HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr) {
  648. uint16_t rawvalue = swap16(*(uint16_t*)val_ptr);
  649. DEBUG_ECHOLNPAIR("V1:", rawvalue);
  650. float value = (float)rawvalue / 10;
  651. DEBUG_ECHOLNPAIR("V2:", value);
  652. float newvalue = 0;
  653. switch (var.VP) {
  654. default: return;
  655. #if HOTENDS >= 1
  656. case VP_E0_PID_P: newvalue = value; break;
  657. case VP_E0_PID_I: newvalue = scalePID_i(value); break;
  658. case VP_E0_PID_D: newvalue = scalePID_d(value); break;
  659. #endif
  660. #if HOTENDS >= 2
  661. case VP_E1_PID_P: newvalue = value; break;
  662. case VP_E1_PID_I: newvalue = scalePID_i(value); break;
  663. case VP_E1_PID_D: newvalue = scalePID_d(value); break;
  664. #endif
  665. #if HAS_HEATED_BED
  666. case VP_BED_PID_P: newvalue = value; break;
  667. case VP_BED_PID_I: newvalue = scalePID_i(value); break;
  668. case VP_BED_PID_D: newvalue = scalePID_d(value); break;
  669. #endif
  670. }
  671. DEBUG_ECHOLNPAIR_F("V3:", newvalue);
  672. *(float *)var.memadr = newvalue;
  673. ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  674. }
  675. void DGUSScreenHandler::HandlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr) {
  676. DEBUG_ECHOLNPGM("HandlePIDAutotune");
  677. char buf[32] = {0};
  678. switch (var.VP) {
  679. default: break;
  680. #if ENABLED(PIDTEMP)
  681. #if HOTENDS >= 1
  682. case VP_PID_AUTOTUNE_E0: // Autotune Extruder 0
  683. sprintf(buf, "M303 E%d C5 S210 U1", ExtUI::extruder_t::E0);
  684. break;
  685. #endif
  686. #if HOTENDS >= 2
  687. case VP_PID_AUTOTUNE_E1:
  688. sprintf(buf, "M303 E%d C5 S210 U1", ExtUI::extruder_t::E1);
  689. break;
  690. #endif
  691. #endif
  692. #if ENABLED(PIDTEMPBED)
  693. case VP_PID_AUTOTUNE_BED:
  694. sprintf(buf, "M303 E-1 C5 S70 U1");
  695. break;
  696. #endif
  697. }
  698. if (buf[0]) queue.enqueue_one_now(buf);
  699. #if ENABLED(DGUS_UI_WAITING)
  700. sendinfoscreen(PSTR("PID is autotuning"), PSTR("please wait"), NUL_STR, NUL_STR, true, true, true, true);
  701. GotoScreen(DGUSLCD_SCREEN_WAITING);
  702. #endif
  703. }
  704. #endif
  705. #if HAS_BED_PROBE
  706. void DGUSScreenHandler::HandleProbeOffsetZChanged(DGUS_VP_Variable &var, void *val_ptr) {
  707. DEBUG_ECHOLNPGM("HandleProbeOffsetZChanged");
  708. const float offset = float(int16_t(swap16(*(uint16_t*)val_ptr))) / 100.0f;
  709. ExtUI::setZOffset_mm(offset);
  710. ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  711. return;
  712. }
  713. #endif
  714. #if ENABLED(BABYSTEPPING)
  715. void DGUSScreenHandler::HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) {
  716. DEBUG_ECHOLNPGM("HandleLiveAdjustZ");
  717. int16_t flag = swap16(*(uint16_t*)val_ptr);
  718. int16_t steps = flag ? -20 : 20;
  719. ExtUI::smartAdjustAxis_steps(steps, ExtUI::axis_t::Z, true);
  720. ScreenHandler.ForceCompleteUpdate();
  721. return;
  722. }
  723. #endif
  724. #if HAS_FAN
  725. void DGUSScreenHandler::HandleFanControl(DGUS_VP_Variable &var, void *val_ptr) {
  726. DEBUG_ECHOLNPGM("HandleFanControl");
  727. *(uint8_t*)var.memadr = *(uint8_t*)var.memadr > 0 ? 0 : 255;
  728. }
  729. #endif
  730. void DGUSScreenHandler::HandleHeaterControl(DGUS_VP_Variable &var, void *val_ptr) {
  731. DEBUG_ECHOLNPGM("HandleHeaterControl");
  732. uint8_t preheat_temp = 0;
  733. switch (var.VP) {
  734. #if HOTENDS >= 1
  735. case VP_E0_CONTROL:
  736. #endif
  737. #if HOTENDS >= 2
  738. case VP_E1_CONTROL:
  739. #endif
  740. #if HOTENDS >= 3
  741. case VP_E2_CONTROL:
  742. #endif
  743. preheat_temp = PREHEAT_1_TEMP_HOTEND;
  744. break;
  745. case VP_BED_CONTROL:
  746. preheat_temp = PREHEAT_1_TEMP_BED;
  747. break;
  748. }
  749. *(int16_t*)var.memadr = *(int16_t*)var.memadr > 0 ? 0 : preheat_temp;
  750. }
  751. #if ENABLED(DGUS_PREHEAT_UI)
  752. void DGUSScreenHandler::HandlePreheat(DGUS_VP_Variable &var, void *val_ptr) {
  753. DEBUG_ECHOLNPGM("HandlePreheat");
  754. uint8_t e_temp = 0;
  755. TERN_(HAS_HEATED_BED, uint8_t bed_temp = 0);
  756. const uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
  757. switch (preheat_option) {
  758. default:
  759. case 0: // Preheat PLA
  760. #if defined(PREHEAT_1_TEMP_HOTEND) && defined(PREHEAT_1_TEMP_BED)
  761. e_temp = PREHEAT_1_TEMP_HOTEND;
  762. TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_1_TEMP_BED);
  763. #endif
  764. break;
  765. case 1: // Preheat ABS
  766. #if defined(PREHEAT_2_TEMP_HOTEND) && defined(PREHEAT_2_TEMP_BED)
  767. e_temp = PREHEAT_2_TEMP_HOTEND;
  768. TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_2_TEMP_BED);
  769. #endif
  770. break;
  771. case 2: // Preheat PET
  772. #if defined(PREHEAT_3_TEMP_HOTEND) && defined(PREHEAT_3_TEMP_BED)
  773. e_temp = PREHEAT_3_TEMP_HOTEND;
  774. TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_3_TEMP_BED);
  775. #endif
  776. break;
  777. case 3: // Preheat FLEX
  778. #if defined(PREHEAT_4_TEMP_HOTEND) && defined(PREHEAT_4_TEMP_BED)
  779. e_temp = PREHEAT_4_TEMP_HOTEND;
  780. TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_4_TEMP_BED);
  781. #endif
  782. break;
  783. case 7: break; // Custom preheat
  784. case 9: break; // Cool down
  785. }
  786. switch (var.VP) {
  787. default: return;
  788. #if HOTENDS >= 1
  789. case VP_E0_BED_PREHEAT:
  790. thermalManager.setTargetHotend(e_temp, 0);
  791. TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(bed_temp));
  792. break;
  793. #endif
  794. #if HOTENDS >= 2
  795. case VP_E1_BED_PREHEAT:
  796. thermalManager.setTargetHotend(e_temp, 1);
  797. TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(bed_temp));
  798. break;
  799. #endif
  800. }
  801. // Go to the preheat screen to show the heating progress
  802. GotoScreen(DGUSLCD_SCREEN_PREHEAT);
  803. }
  804. #endif
  805. #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
  806. typedef struct {
  807. ExtUI::extruder_t extruder; // which extruder to operate
  808. uint8_t action; // load or unload
  809. bool heated; // heating done ?
  810. float purge_length; // the length to extrude before unload, prevent filament jam
  811. } filament_data_t;
  812. static filament_data_t filament_data;
  813. void DGUSScreenHandler::HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr) {
  814. DEBUG_ECHOLNPGM("HandleFilamentOption");
  815. uint8_t e_temp = 0;
  816. filament_data.heated = false;
  817. uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
  818. if (preheat_option <= 8) // Load filament type
  819. filament_data.action = 1;
  820. else if (preheat_option >= 10) { // Unload filament type
  821. preheat_option -= 10;
  822. filament_data.action = 2;
  823. filament_data.purge_length = DGUS_FILAMENT_PURGE_LENGTH;
  824. }
  825. else // Cancel filament operation
  826. filament_data.action = 0;
  827. switch (preheat_option) {
  828. case 0: // Load PLA
  829. #ifdef PREHEAT_1_TEMP_HOTEND
  830. e_temp = PREHEAT_1_TEMP_HOTEND;
  831. #endif
  832. break;
  833. case 1: // Load ABS
  834. TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND);
  835. break;
  836. case 2: // Load PET
  837. #ifdef PREHEAT_3_TEMP_HOTEND
  838. e_temp = PREHEAT_3_TEMP_HOTEND;
  839. #endif
  840. break;
  841. case 3: // Load FLEX
  842. #ifdef PREHEAT_4_TEMP_HOTEND
  843. e_temp = PREHEAT_4_TEMP_HOTEND;
  844. #endif
  845. break;
  846. case 9: // Cool down
  847. default:
  848. e_temp = 0;
  849. break;
  850. }
  851. if (filament_data.action == 0) { // Go back to utility screen
  852. #if HOTENDS >= 1
  853. thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0);
  854. #endif
  855. #if HOTENDS >= 2
  856. thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1);
  857. #endif
  858. GotoScreen(DGUSLCD_SCREEN_UTILITY);
  859. }
  860. else { // Go to the preheat screen to show the heating progress
  861. switch (var.VP) {
  862. default: return;
  863. #if HOTENDS >= 1
  864. case VP_E0_FILAMENT_LOAD_UNLOAD:
  865. filament_data.extruder = ExtUI::extruder_t::E0;
  866. thermalManager.setTargetHotend(e_temp, filament_data.extruder);
  867. break;
  868. #endif
  869. #if HOTENDS >= 2
  870. case VP_E1_FILAMENT_LOAD_UNLOAD:
  871. filament_data.extruder = ExtUI::extruder_t::E1;
  872. thermalManager.setTargetHotend(e_temp, filament_data.extruder);
  873. break;
  874. #endif
  875. }
  876. GotoScreen(DGUSLCD_SCREEN_FILAMENT_HEATING);
  877. }
  878. }
  879. void DGUSScreenHandler::HandleFilamentLoadUnload(DGUS_VP_Variable &var) {
  880. DEBUG_ECHOLNPGM("HandleFilamentLoadUnload");
  881. if (filament_data.action <= 0) return;
  882. // If we close to the target temperature, we can start load or unload the filament
  883. if (thermalManager.hotEnoughToExtrude(filament_data.extruder) && \
  884. thermalManager.targetHotEnoughToExtrude(filament_data.extruder)) {
  885. float movevalue = DGUS_FILAMENT_LOAD_LENGTH_PER_TIME;
  886. if (filament_data.action == 1) { // load filament
  887. if (!filament_data.heated) {
  888. GotoScreen(DGUSLCD_SCREEN_FILAMENT_LOADING);
  889. filament_data.heated = true;
  890. }
  891. movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder)+movevalue;
  892. }
  893. else { // unload filament
  894. if (!filament_data.heated) {
  895. GotoScreen(DGUSLCD_SCREEN_FILAMENT_UNLOADING);
  896. filament_data.heated = true;
  897. }
  898. // Before unloading extrude to prevent jamming
  899. if (filament_data.purge_length >= 0) {
  900. movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
  901. filament_data.purge_length -= movevalue;
  902. }
  903. else
  904. movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue;
  905. }
  906. ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder);
  907. }
  908. }
  909. #endif
  910. void DGUSScreenHandler::UpdateNewScreen(DGUSLCD_Screens newscreen, bool popup) {
  911. DEBUG_ECHOLNPAIR("SetNewScreen: ", newscreen);
  912. if (!popup) {
  913. memmove(&past_screens[1], &past_screens[0], sizeof(past_screens) - 1);
  914. past_screens[0] = current_screen;
  915. }
  916. current_screen = newscreen;
  917. skipVP = 0;
  918. ForceCompleteUpdate();
  919. }
  920. void DGUSScreenHandler::PopToOldScreen() {
  921. DEBUG_ECHOLNPAIR("PopToOldScreen s=", past_screens[0]);
  922. GotoScreen(past_screens[0], true);
  923. memmove(&past_screens[0], &past_screens[1], sizeof(past_screens) - 1);
  924. past_screens[sizeof(past_screens) - 1] = DGUSLCD_SCREEN_MAIN;
  925. }
  926. void DGUSScreenHandler::UpdateScreenVPData() {
  927. DEBUG_ECHOPAIR(" UpdateScreenVPData Screen: ", current_screen);
  928. const uint16_t *VPList = DGUSLCD_FindScreenVPMapList(current_screen);
  929. if (!VPList) {
  930. DEBUG_ECHOLNPAIR(" NO SCREEN FOR: ", current_screen);
  931. ScreenComplete = true;
  932. return; // nothing to do, likely a bug or boring screen.
  933. }
  934. // Round-robin updating of all VPs.
  935. VPList += update_ptr;
  936. bool sent_one = false;
  937. do {
  938. uint16_t VP = pgm_read_word(VPList);
  939. DEBUG_ECHOPAIR(" VP: ", VP);
  940. if (!VP) {
  941. update_ptr = 0;
  942. DEBUG_ECHOLNPGM(" UpdateScreenVPData done");
  943. ScreenComplete = true;
  944. return; // Screen completed.
  945. }
  946. if (VP == skipVP) { skipVP = 0; continue; }
  947. DGUS_VP_Variable rcpy;
  948. if (populate_VPVar(VP, &rcpy)) {
  949. uint8_t expected_tx = 6 + rcpy.size; // expected overhead is 6 bytes + payload.
  950. // Send the VP to the display, but try to avoid overrunning the Tx Buffer.
  951. // But send at least one VP, to avoid getting stalled.
  952. if (rcpy.send_to_display_handler && (!sent_one || expected_tx <= dgusdisplay.GetFreeTxBuffer())) {
  953. //DEBUG_ECHOPAIR(" calling handler for ", rcpy.VP);
  954. sent_one = true;
  955. rcpy.send_to_display_handler(rcpy);
  956. }
  957. else {
  958. //auto x=dgusdisplay.GetFreeTxBuffer();
  959. //DEBUG_ECHOLNPAIR(" tx almost full: ", x);
  960. //DEBUG_ECHOPAIR(" update_ptr ", update_ptr);
  961. ScreenComplete = false;
  962. return; // please call again!
  963. }
  964. }
  965. } while (++update_ptr, ++VPList, true);
  966. }
  967. void DGUSScreenHandler::GotoScreen(DGUSLCD_Screens screen, bool ispopup) {
  968. dgusdisplay.RequestScreen(screen);
  969. UpdateNewScreen(screen, ispopup);
  970. }
  971. bool DGUSScreenHandler::loop() {
  972. dgusdisplay.loop();
  973. const millis_t ms = millis();
  974. static millis_t next_event_ms = 0;
  975. if (!IsScreenComplete() || ELAPSED(ms, next_event_ms)) {
  976. next_event_ms = ms + DGUS_UPDATE_INTERVAL_MS;
  977. UpdateScreenVPData();
  978. }
  979. #if ENABLED(SHOW_BOOTSCREEN)
  980. static bool booted = false;
  981. if (!booted && TERN0(POWER_LOSS_RECOVERY, recovery.valid()))
  982. booted = true;
  983. if (!booted && ELAPSED(ms, BOOTSCREEN_TIMEOUT)) {
  984. booted = true;
  985. GotoScreen(DGUSLCD_SCREEN_MAIN);
  986. }
  987. #endif
  988. return IsScreenComplete();
  989. }
  990. void DGUSDisplay::RequestScreen(DGUSLCD_Screens screen) {
  991. DEBUG_ECHOLNPAIR("GotoScreen ", screen);
  992. const unsigned char gotoscreen[] = { 0x5A, 0x01, (unsigned char) (screen >> 8U), (unsigned char) (screen & 0xFFU) };
  993. WriteVariable(0x84, gotoscreen, sizeof(gotoscreen));
  994. }
  995. #endif // HAS_DGUS_LCD