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 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  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_CLASSIC
  24. #include "DGUSScreenHandler.h"
  25. #include "../../../MarlinCore.h"
  26. #include "../../../gcode/queue.h"
  27. #include "../../../libs/duration_t.h"
  28. #include "../../../module/settings.h"
  29. #include "../../../module/temperature.h"
  30. #include "../../../module/motion.h"
  31. #include "../../../module/planner.h"
  32. #include "../../../module/printcounter.h"
  33. #include "../../../sd/cardreader.h"
  34. #if ENABLED(POWER_LOSS_RECOVERY)
  35. #include "../../../feature/powerloss.h"
  36. #endif
  37. DGUSScreenHandler ScreenHandler;
  38. uint16_t DGUSScreenHandler::ConfirmVP;
  39. DGUSLCD_Screens DGUSScreenHandler::current_screen;
  40. DGUSLCD_Screens DGUSScreenHandler::past_screens[NUM_PAST_SCREENS];
  41. uint8_t DGUSScreenHandler::update_ptr;
  42. uint16_t DGUSScreenHandler::skipVP;
  43. bool DGUSScreenHandler::ScreenComplete;
  44. void (*DGUSScreenHandler::confirm_action_cb)() = nullptr;
  45. #if ENABLED(SDSUPPORT)
  46. int16_t DGUSScreenHandler::top_file = 0,
  47. DGUSScreenHandler::file_to_print = 0;
  48. static ExtUI::FileList filelist;
  49. #endif
  50. #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
  51. filament_data_t filament_data;
  52. #endif
  53. void DGUSScreenHandler::sendinfoscreen(const char *line1, const char *line2, const char *line3, const char *line4, bool l1inflash, bool l2inflash, bool l3inflash, bool l4inflash) {
  54. DGUS_VP_Variable ramcopy;
  55. if (populate_VPVar(VP_MSGSTR1, &ramcopy)) {
  56. ramcopy.memadr = (void*) line1;
  57. l1inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  58. }
  59. if (populate_VPVar(VP_MSGSTR2, &ramcopy)) {
  60. ramcopy.memadr = (void*) line2;
  61. l2inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  62. }
  63. if (populate_VPVar(VP_MSGSTR3, &ramcopy)) {
  64. ramcopy.memadr = (void*) line3;
  65. l3inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  66. }
  67. if (populate_VPVar(VP_MSGSTR4, &ramcopy)) {
  68. ramcopy.memadr = (void*) line4;
  69. l4inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  70. }
  71. }
  72. 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) {
  73. if (current_screen == DGUSLCD_SCREEN_CONFIRM) // Already showing a pop up, so we need to cancel that first.
  74. PopToOldScreen();
  75. ConfirmVP = VP;
  76. sendinfoscreen(line1, line2, line3, line4, l1, l2, l3, l4);
  77. GotoScreen(DGUSLCD_SCREEN_CONFIRM);
  78. }
  79. void DGUSScreenHandler::setstatusmessage(const char *msg) {
  80. DGUS_VP_Variable ramcopy;
  81. if (populate_VPVar(VP_M117, &ramcopy)) {
  82. ramcopy.memadr = (void*) msg;
  83. DGUSLCD_SendStringToDisplay(ramcopy);
  84. }
  85. }
  86. void DGUSScreenHandler::setstatusmessagePGM(PGM_P const msg) {
  87. DGUS_VP_Variable ramcopy;
  88. if (populate_VPVar(VP_M117, &ramcopy)) {
  89. ramcopy.memadr = (void*) msg;
  90. DGUSLCD_SendStringToDisplayPGM(ramcopy);
  91. }
  92. }
  93. // Send an 8 bit or 16 bit value to the display.
  94. void DGUSScreenHandler::DGUSLCD_SendWordValueToDisplay(DGUS_VP_Variable &var) {
  95. if (var.memadr) {
  96. //DEBUG_ECHOPAIR(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
  97. //DEBUG_ECHOLNPAIR(" data ", *(uint16_t *)var.memadr);
  98. if (var.size > 1)
  99. dgusdisplay.WriteVariable(var.VP, *(int16_t*)var.memadr);
  100. else
  101. dgusdisplay.WriteVariable(var.VP, *(int8_t*)var.memadr);
  102. }
  103. }
  104. // Send an uint8_t between 0 and 255 to the display, but scale to a percentage (0..100)
  105. void DGUSScreenHandler::DGUSLCD_SendPercentageToDisplay(DGUS_VP_Variable &var) {
  106. if (var.memadr) {
  107. //DEBUG_ECHOPAIR(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
  108. //DEBUG_ECHOLNPAIR(" data ", *(uint16_t *)var.memadr);
  109. uint16_t tmp = *(uint8_t *) var.memadr + 1; // +1 -> avoid rounding issues for the display.
  110. tmp = map(tmp, 0, 255, 0, 100);
  111. dgusdisplay.WriteVariable(var.VP, tmp);
  112. }
  113. }
  114. // Send the current print progress to the display.
  115. void DGUSScreenHandler::DGUSLCD_SendPrintProgressToDisplay(DGUS_VP_Variable &var) {
  116. //DEBUG_ECHOPAIR(" DGUSLCD_SendPrintProgressToDisplay ", var.VP);
  117. uint16_t tmp = ExtUI::getProgress_percent();
  118. //DEBUG_ECHOLNPAIR(" data ", tmp);
  119. dgusdisplay.WriteVariable(var.VP, tmp);
  120. }
  121. // Send the current print time to the display.
  122. // It is using a hex display for that: It expects BSD coded data in the format xxyyzz
  123. void DGUSScreenHandler::DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var) {
  124. duration_t elapsed = print_job_timer.duration();
  125. char buf[32];
  126. elapsed.toString(buf);
  127. dgusdisplay.WriteVariable(VP_PrintTime, buf, var.size, true);
  128. }
  129. // Send an uint8_t between 0 and 100 to a variable scale to 0..255
  130. void DGUSScreenHandler::DGUSLCD_PercentageToUint8(DGUS_VP_Variable &var, void *val_ptr) {
  131. if (var.memadr) {
  132. uint16_t value = swap16(*(uint16_t*)val_ptr);
  133. DEBUG_ECHOLNPAIR("FAN value get:", value);
  134. *(uint8_t*)var.memadr = map(constrain(value, 0, 100), 0, 100, 0, 255);
  135. DEBUG_ECHOLNPAIR("FAN value change:", *(uint8_t*)var.memadr);
  136. }
  137. }
  138. // Sends a (RAM located) string to the DGUS Display
  139. // (Note: The DGUS Display does not clear after the \0, you have to
  140. // overwrite the remainings with spaces.// var.size has the display buffer size!
  141. void DGUSScreenHandler::DGUSLCD_SendStringToDisplay(DGUS_VP_Variable &var) {
  142. char *tmp = (char*) var.memadr;
  143. dgusdisplay.WriteVariable(var.VP, tmp, var.size, true);
  144. }
  145. // Sends a (flash located) string to the DGUS Display
  146. // (Note: The DGUS Display does not clear after the \0, you have to
  147. // overwrite the remainings with spaces.// var.size has the display buffer size!
  148. void DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(DGUS_VP_Variable &var) {
  149. char *tmp = (char*) var.memadr;
  150. dgusdisplay.WriteVariablePGM(var.VP, tmp, var.size, true);
  151. }
  152. #if HAS_PID_HEATING
  153. void DGUSScreenHandler::DGUSLCD_SendTemperaturePID(DGUS_VP_Variable &var) {
  154. float value = *(float *)var.memadr;
  155. value /= 10;
  156. float valuesend = 0;
  157. switch (var.VP) {
  158. default: return;
  159. #if HAS_HOTEND
  160. case VP_E0_PID_P: valuesend = value; break;
  161. case VP_E0_PID_I: valuesend = unscalePID_i(value); break;
  162. case VP_E0_PID_D: valuesend = unscalePID_d(value); break;
  163. #endif
  164. #if HOTENDS >= 2
  165. case VP_E1_PID_P: valuesend = value; break;
  166. case VP_E1_PID_I: valuesend = unscalePID_i(value); break;
  167. case VP_E1_PID_D: valuesend = unscalePID_d(value); break;
  168. #endif
  169. #if HAS_HEATED_BED
  170. case VP_BED_PID_P: valuesend = value; break;
  171. case VP_BED_PID_I: valuesend = unscalePID_i(value); break;
  172. case VP_BED_PID_D: valuesend = unscalePID_d(value); break;
  173. #endif
  174. }
  175. valuesend *= cpow(10, 1);
  176. union { int16_t i; char lb[2]; } endian;
  177. char tmp[2];
  178. endian.i = valuesend;
  179. tmp[0] = endian.lb[1];
  180. tmp[1] = endian.lb[0];
  181. dgusdisplay.WriteVariable(var.VP, tmp, 2);
  182. }
  183. #endif
  184. #if ENABLED(PRINTCOUNTER)
  185. // Send the accumulate print time to the display.
  186. // It is using a hex display for that: It expects BSD coded data in the format xxyyzz
  187. void DGUSScreenHandler::DGUSLCD_SendPrintAccTimeToDisplay(DGUS_VP_Variable &var) {
  188. printStatistics state = print_job_timer.getStats();
  189. char buf[22];
  190. duration_t elapsed = state.printTime;
  191. elapsed.toString(buf);
  192. dgusdisplay.WriteVariable(VP_PrintAccTime, buf, var.size, true);
  193. }
  194. void DGUSScreenHandler::DGUSLCD_SendPrintsTotalToDisplay(DGUS_VP_Variable &var) {
  195. printStatistics state = print_job_timer.getStats();
  196. char buf[10];
  197. sprintf_P(buf, PSTR("%u"), state.totalPrints);
  198. dgusdisplay.WriteVariable(VP_PrintsTotal, buf, var.size, true);
  199. }
  200. #endif
  201. // Send fan status value to the display.
  202. #if HAS_FAN
  203. void DGUSScreenHandler::DGUSLCD_SendFanStatusToDisplay(DGUS_VP_Variable &var) {
  204. if (var.memadr) {
  205. DEBUG_ECHOPAIR(" DGUSLCD_SendFanStatusToDisplay ", var.VP);
  206. DEBUG_ECHOLNPAIR(" data ", *(uint8_t *)var.memadr);
  207. uint16_t data_to_send = 0;
  208. if (*(uint8_t *) var.memadr) data_to_send = 1;
  209. dgusdisplay.WriteVariable(var.VP, data_to_send);
  210. }
  211. }
  212. #endif
  213. // Send heater status value to the display.
  214. void DGUSScreenHandler::DGUSLCD_SendHeaterStatusToDisplay(DGUS_VP_Variable &var) {
  215. if (var.memadr) {
  216. DEBUG_ECHOPAIR(" DGUSLCD_SendHeaterStatusToDisplay ", var.VP);
  217. DEBUG_ECHOLNPAIR(" data ", *(int16_t *)var.memadr);
  218. uint16_t data_to_send = 0;
  219. if (*(int16_t *) var.memadr) data_to_send = 1;
  220. dgusdisplay.WriteVariable(var.VP, data_to_send);
  221. }
  222. }
  223. #if ENABLED(DGUS_UI_WAITING)
  224. void DGUSScreenHandler::DGUSLCD_SendWaitingStatusToDisplay(DGUS_VP_Variable &var) {
  225. // In FYSETC UI design there are 10 statuses to loop
  226. static uint16_t period = 0;
  227. static uint16_t index = 0;
  228. //DEBUG_ECHOPAIR(" DGUSLCD_SendWaitingStatusToDisplay ", var.VP);
  229. //DEBUG_ECHOLNPAIR(" data ", swap16(index));
  230. if (period++ > DGUS_UI_WAITING_STATUS_PERIOD) {
  231. dgusdisplay.WriteVariable(var.VP, index);
  232. //DEBUG_ECHOLNPAIR(" data ", swap16(index));
  233. if (++index >= DGUS_UI_WAITING_STATUS) index = 0;
  234. period = 0;
  235. }
  236. }
  237. #endif
  238. #if ENABLED(SDSUPPORT)
  239. void DGUSScreenHandler::ScreenChangeHookIfSD(DGUS_VP_Variable &var, void *val_ptr) {
  240. // default action executed when there is a SD card, but not printing
  241. if (ExtUI::isMediaInserted() && !ExtUI::isPrintingFromMedia()) {
  242. ScreenChangeHook(var, val_ptr);
  243. dgusdisplay.RequestScreen(current_screen);
  244. return;
  245. }
  246. // if we are printing, we jump to two screens after the requested one.
  247. // This should host e.g a print pause / print abort / print resume dialog.
  248. // This concept allows to recycle this hook for other file
  249. if (ExtUI::isPrintingFromMedia() && !card.flag.abort_sd_printing) {
  250. GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
  251. return;
  252. }
  253. // Don't let the user in the dark why there is no reaction.
  254. if (!ExtUI::isMediaInserted()) {
  255. setstatusmessagePGM(GET_TEXT(MSG_NO_MEDIA));
  256. return;
  257. }
  258. if (card.flag.abort_sd_printing) {
  259. setstatusmessagePGM(GET_TEXT(MSG_MEDIA_ABORTING));
  260. return;
  261. }
  262. }
  263. void DGUSScreenHandler::DGUSLCD_SD_ScrollFilelist(DGUS_VP_Variable& var, void *val_ptr) {
  264. auto old_top = top_file;
  265. const int16_t scroll = (int16_t)swap16(*(uint16_t*)val_ptr);
  266. if (scroll) {
  267. top_file += scroll;
  268. DEBUG_ECHOPAIR("new topfile calculated:", top_file);
  269. if (top_file < 0) {
  270. top_file = 0;
  271. DEBUG_ECHOLNPGM("Top of filelist reached");
  272. }
  273. else {
  274. int16_t max_top = filelist.count() - DGUS_SD_FILESPERSCREEN;
  275. NOLESS(max_top, 0);
  276. NOMORE(top_file, max_top);
  277. }
  278. DEBUG_ECHOPAIR("new topfile adjusted:", top_file);
  279. }
  280. else if (!filelist.isAtRootDir()) {
  281. IF_DISABLED(DGUS_LCD_UI_MKS, filelist.upDir());
  282. top_file = 0;
  283. ForceCompleteUpdate();
  284. }
  285. if (old_top != top_file) ForceCompleteUpdate();
  286. }
  287. void DGUSScreenHandler::DGUSLCD_SD_ReallyAbort(DGUS_VP_Variable &var, void *val_ptr) {
  288. ExtUI::stopPrint();
  289. GotoScreen(DGUSLCD_SCREEN_MAIN);
  290. }
  291. void DGUSScreenHandler::DGUSLCD_SD_PrintTune(DGUS_VP_Variable &var, void *val_ptr) {
  292. if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
  293. GotoScreen(DGUSLCD_SCREEN_SDPRINTTUNE);
  294. }
  295. void DGUSScreenHandler::SDCardError() {
  296. DGUSScreenHandler::SDCardRemoved();
  297. sendinfoscreen(PSTR("NOTICE"), nullptr, PSTR("SD card error"), nullptr, true, true, true, true);
  298. SetupConfirmAction(nullptr);
  299. GotoScreen(DGUSLCD_SCREEN_POPUP);
  300. }
  301. #endif // SDSUPPORT
  302. void DGUSScreenHandler::ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr) {
  303. DGUS_VP_Variable ramcopy;
  304. if (!populate_VPVar(ConfirmVP, &ramcopy)) return;
  305. if (ramcopy.set_by_display_handler) ramcopy.set_by_display_handler(ramcopy, val_ptr);
  306. }
  307. const uint16_t* DGUSLCD_FindScreenVPMapList(uint8_t screen) {
  308. const uint16_t *ret;
  309. const struct VPMapping *map = VPMap;
  310. while ((ret = (uint16_t*) pgm_read_ptr(&(map->VPList)))) {
  311. if (pgm_read_byte(&(map->screen)) == screen) return ret;
  312. map++;
  313. }
  314. return nullptr;
  315. }
  316. const DGUS_VP_Variable* DGUSLCD_FindVPVar(const uint16_t vp) {
  317. const DGUS_VP_Variable *ret = ListOfVP;
  318. do {
  319. const uint16_t vpcheck = pgm_read_word(&(ret->VP));
  320. if (vpcheck == 0) break;
  321. if (vpcheck == vp) return ret;
  322. ++ret;
  323. } while (1);
  324. DEBUG_ECHOLNPAIR("FindVPVar NOT FOUND ", vp);
  325. return nullptr;
  326. }
  327. void DGUSScreenHandler::ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr) {
  328. if (!ExtUI::isPrinting()) {
  329. ScreenChangeHook(var, val_ptr);
  330. dgusdisplay.RequestScreen(current_screen);
  331. }
  332. }
  333. void DGUSScreenHandler::HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr) {
  334. thermalManager.disable_all_heaters();
  335. ForceCompleteUpdate(); // hint to send all data.
  336. }
  337. void DGUSScreenHandler::HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr) {
  338. celsius_t newvalue = swap16(*(uint16_t*)val_ptr);
  339. celsius_t acceptedvalue;
  340. switch (var.VP) {
  341. default: return;
  342. #if HAS_HOTEND
  343. case VP_T_E0_Set:
  344. NOMORE(newvalue, HEATER_0_MAXTEMP);
  345. thermalManager.setTargetHotend(newvalue, 0);
  346. acceptedvalue = thermalManager.degTargetHotend(0);
  347. break;
  348. #endif
  349. #if HOTENDS >= 2
  350. case VP_T_E1_Set:
  351. NOMORE(newvalue, HEATER_1_MAXTEMP);
  352. thermalManager.setTargetHotend(newvalue, 1);
  353. acceptedvalue = thermalManager.degTargetHotend(1);
  354. break;
  355. #endif
  356. #if HAS_HEATED_BED
  357. case VP_T_Bed_Set:
  358. NOMORE(newvalue, BED_MAXTEMP);
  359. thermalManager.setTargetBed(newvalue);
  360. acceptedvalue = thermalManager.degTargetBed();
  361. break;
  362. #endif
  363. }
  364. // reply to display the new value to update the view if the new value was rejected by the Thermal Manager.
  365. if (newvalue != acceptedvalue && var.send_to_display_handler) var.send_to_display_handler(var);
  366. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  367. }
  368. void DGUSScreenHandler::HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr) {
  369. #if HAS_EXTRUDERS
  370. uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
  371. uint8_t target_extruder;
  372. switch (var.VP) {
  373. default: return;
  374. case VP_Flowrate_E0: target_extruder = 0; break;
  375. #if HAS_MULTI_EXTRUDER
  376. case VP_Flowrate_E1: target_extruder = 1; break;
  377. #endif
  378. }
  379. planner.set_flow(target_extruder, newvalue);
  380. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  381. #else
  382. UNUSED(var); UNUSED(val_ptr);
  383. #endif
  384. }
  385. void DGUSScreenHandler::HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr) {
  386. DEBUG_ECHOLNPGM("HandleManualExtrude");
  387. int16_t movevalue = swap16(*(uint16_t*)val_ptr);
  388. float target = movevalue * 0.01f;
  389. ExtUI::extruder_t target_extruder;
  390. switch (var.VP) {
  391. #if HAS_HOTEND
  392. case VP_MOVE_E0: target_extruder = ExtUI::extruder_t::E0; break;
  393. #if HAS_MULTI_EXTRUDER
  394. case VP_MOVE_E1: target_extruder = ExtUI::extruder_t::E1; break;
  395. #endif
  396. #endif
  397. default: return;
  398. }
  399. target += ExtUI::getAxisPosition_mm(target_extruder);
  400. ExtUI::setAxisPosition_mm(target, target_extruder);
  401. skipVP = var.VP;
  402. }
  403. #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
  404. void DGUSScreenHandler::HandleManualMoveOption(DGUS_VP_Variable &var, void *val_ptr) {
  405. DEBUG_ECHOLNPGM("HandleManualMoveOption");
  406. *(uint16_t*)var.memadr = swap16(*(uint16_t*)val_ptr);
  407. }
  408. #endif
  409. void DGUSScreenHandler::HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr) {
  410. DEBUG_ECHOLNPGM("HandleMotorLockUnlock");
  411. char buf[4];
  412. const int16_t lock = swap16(*(uint16_t*)val_ptr);
  413. strcpy_P(buf, lock ? PSTR("M18") : PSTR("M17"));
  414. //DEBUG_ECHOPAIR(" ", buf);
  415. queue.enqueue_one_now(buf);
  416. }
  417. void DGUSScreenHandler::HandleSettings(DGUS_VP_Variable &var, void *val_ptr) {
  418. DEBUG_ECHOLNPGM("HandleSettings");
  419. uint16_t value = swap16(*(uint16_t*)val_ptr);
  420. switch (value) {
  421. default: break;
  422. case 1:
  423. TERN_(PRINTCOUNTER, print_job_timer.initStats());
  424. settings.reset();
  425. settings.save();
  426. break;
  427. case 2: settings.load(); break;
  428. case 3: settings.save(); break;
  429. }
  430. }
  431. void DGUSScreenHandler::HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr) {
  432. DEBUG_ECHOLNPGM("HandleStepPerMMChanged");
  433. uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
  434. DEBUG_ECHOLNPAIR("value_raw:", value_raw);
  435. float value = (float)value_raw / 10;
  436. ExtUI::axis_t axis;
  437. switch (var.VP) {
  438. case VP_X_STEP_PER_MM: axis = ExtUI::axis_t::X; break;
  439. case VP_Y_STEP_PER_MM: axis = ExtUI::axis_t::Y; break;
  440. case VP_Z_STEP_PER_MM: axis = ExtUI::axis_t::Z; break;
  441. default: return;
  442. }
  443. DEBUG_ECHOLNPAIR_F("value:", value);
  444. ExtUI::setAxisSteps_per_mm(value, axis);
  445. DEBUG_ECHOLNPAIR_F("value_set:", ExtUI::getAxisSteps_per_mm(axis));
  446. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  447. return;
  448. }
  449. void DGUSScreenHandler::HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr) {
  450. DEBUG_ECHOLNPGM("HandleStepPerMMExtruderChanged");
  451. uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
  452. DEBUG_ECHOLNPAIR("value_raw:", value_raw);
  453. float value = (float)value_raw / 10;
  454. ExtUI::extruder_t extruder;
  455. switch (var.VP) {
  456. default: return;
  457. #if HAS_EXTRUDERS
  458. case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break;
  459. #if HAS_MULTI_EXTRUDER
  460. case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break;
  461. #endif
  462. #endif
  463. }
  464. DEBUG_ECHOLNPAIR_F("value:", value);
  465. ExtUI::setAxisSteps_per_mm(value, extruder);
  466. DEBUG_ECHOLNPAIR_F("value_set:", ExtUI::getAxisSteps_per_mm(extruder));
  467. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  468. }
  469. #if HAS_PID_HEATING
  470. void DGUSScreenHandler::HandlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr) {
  471. DEBUG_ECHOLNPGM("HandlePIDAutotune");
  472. char buf[32] = {0};
  473. switch (var.VP) {
  474. default: break;
  475. #if ENABLED(PIDTEMP)
  476. #if HAS_HOTEND
  477. case VP_PID_AUTOTUNE_E0: // Autotune Extruder 0
  478. sprintf_P(buf, PSTR("M303 E%d C5 S210 U1"), ExtUI::extruder_t::E0);
  479. break;
  480. #endif
  481. #if HOTENDS >= 2
  482. case VP_PID_AUTOTUNE_E1:
  483. sprintf_P(buf, PSTR("M303 E%d C5 S210 U1"), ExtUI::extruder_t::E1);
  484. break;
  485. #endif
  486. #endif
  487. #if ENABLED(PIDTEMPBED)
  488. case VP_PID_AUTOTUNE_BED:
  489. strcpy_P(buf, PSTR("M303 E-1 C5 S70 U1"));
  490. break;
  491. #endif
  492. }
  493. if (buf[0]) queue.enqueue_one_now(buf);
  494. #if ENABLED(DGUS_UI_WAITING)
  495. sendinfoscreen(PSTR("PID is autotuning"), PSTR("please wait"), NUL_STR, NUL_STR, true, true, true, true);
  496. GotoScreen(DGUSLCD_SCREEN_WAITING);
  497. #endif
  498. }
  499. #endif // HAS_PID_HEATING
  500. #if HAS_BED_PROBE
  501. void DGUSScreenHandler::HandleProbeOffsetZChanged(DGUS_VP_Variable &var, void *val_ptr) {
  502. DEBUG_ECHOLNPGM("HandleProbeOffsetZChanged");
  503. const float offset = float(int16_t(swap16(*(uint16_t*)val_ptr))) / 100.0f;
  504. ExtUI::setZOffset_mm(offset);
  505. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  506. return;
  507. }
  508. #endif
  509. #if HAS_FAN
  510. void DGUSScreenHandler::HandleFanControl(DGUS_VP_Variable &var, void *val_ptr) {
  511. DEBUG_ECHOLNPGM("HandleFanControl");
  512. *(uint8_t*)var.memadr = *(uint8_t*)var.memadr > 0 ? 0 : 255;
  513. }
  514. #endif
  515. void DGUSScreenHandler::HandleHeaterControl(DGUS_VP_Variable &var, void *val_ptr) {
  516. DEBUG_ECHOLNPGM("HandleHeaterControl");
  517. uint8_t preheat_temp = 0;
  518. switch (var.VP) {
  519. #if HAS_HOTEND
  520. case VP_E0_CONTROL:
  521. #if HOTENDS >= 2
  522. case VP_E1_CONTROL:
  523. #if HOTENDS >= 3
  524. case VP_E2_CONTROL:
  525. #endif
  526. #endif
  527. preheat_temp = PREHEAT_1_TEMP_HOTEND;
  528. break;
  529. #endif
  530. case VP_BED_CONTROL:
  531. preheat_temp = PREHEAT_1_TEMP_BED;
  532. break;
  533. }
  534. *(int16_t*)var.memadr = *(int16_t*)var.memadr > 0 ? 0 : preheat_temp;
  535. }
  536. #if ENABLED(DGUS_PREHEAT_UI)
  537. void DGUSScreenHandler::HandlePreheat(DGUS_VP_Variable &var, void *val_ptr) {
  538. DEBUG_ECHOLNPGM("HandlePreheat");
  539. uint8_t e_temp = 0;
  540. #if HAS_HEATED_BED
  541. uint8_t bed_temp = 0;
  542. #endif
  543. const uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
  544. switch (preheat_option) {
  545. default:
  546. case 0: // Preheat PLA
  547. #if defined(PREHEAT_1_TEMP_HOTEND) && defined(PREHEAT_1_TEMP_BED)
  548. e_temp = PREHEAT_1_TEMP_HOTEND;
  549. TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_1_TEMP_BED);
  550. #endif
  551. break;
  552. case 1: // Preheat ABS
  553. #if defined(PREHEAT_2_TEMP_HOTEND) && defined(PREHEAT_2_TEMP_BED)
  554. e_temp = PREHEAT_2_TEMP_HOTEND;
  555. TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_2_TEMP_BED);
  556. #endif
  557. break;
  558. case 2: // Preheat PET
  559. #if defined(PREHEAT_3_TEMP_HOTEND) && defined(PREHEAT_3_TEMP_BED)
  560. e_temp = PREHEAT_3_TEMP_HOTEND;
  561. TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_3_TEMP_BED);
  562. #endif
  563. break;
  564. case 3: // Preheat FLEX
  565. #if defined(PREHEAT_4_TEMP_HOTEND) && defined(PREHEAT_4_TEMP_BED)
  566. e_temp = PREHEAT_4_TEMP_HOTEND;
  567. TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_4_TEMP_BED);
  568. #endif
  569. break;
  570. case 7: break; // Custom preheat
  571. case 9: break; // Cool down
  572. }
  573. switch (var.VP) {
  574. default: return;
  575. #if HAS_HOTEND
  576. case VP_E0_BED_PREHEAT:
  577. thermalManager.setTargetHotend(e_temp, 0);
  578. TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(bed_temp));
  579. break;
  580. #endif
  581. #if HOTENDS >= 2
  582. case VP_E1_BED_PREHEAT:
  583. thermalManager.setTargetHotend(e_temp, 1);
  584. TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(bed_temp));
  585. break;
  586. #endif
  587. }
  588. // Go to the preheat screen to show the heating progress
  589. GotoScreen(DGUSLCD_SCREEN_PREHEAT);
  590. }
  591. #endif // DGUS_PREHEAT_UI
  592. #if ENABLED(POWER_LOSS_RECOVERY)
  593. void DGUSScreenHandler::HandlePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr) {
  594. uint16_t value = swap16(*(uint16_t*)val_ptr);
  595. if (value) {
  596. queue.inject_P(PSTR("M1000"));
  597. dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), 32, true);
  598. GotoScreen(PLR_SCREEN_RECOVER);
  599. }
  600. else {
  601. recovery.cancel();
  602. GotoScreen(PLR_SCREEN_CANCEL);
  603. }
  604. }
  605. #endif
  606. void DGUSScreenHandler::UpdateNewScreen(DGUSLCD_Screens newscreen, bool popup) {
  607. DEBUG_ECHOLNPAIR("SetNewScreen: ", newscreen);
  608. if (!popup) {
  609. memmove(&past_screens[1], &past_screens[0], sizeof(past_screens) - 1);
  610. past_screens[0] = current_screen;
  611. }
  612. current_screen = newscreen;
  613. skipVP = 0;
  614. ForceCompleteUpdate();
  615. }
  616. void DGUSScreenHandler::PopToOldScreen() {
  617. DEBUG_ECHOLNPAIR("PopToOldScreen s=", past_screens[0]);
  618. GotoScreen(past_screens[0], true);
  619. memmove(&past_screens[0], &past_screens[1], sizeof(past_screens) - 1);
  620. past_screens[sizeof(past_screens) - 1] = DGUSLCD_SCREEN_MAIN;
  621. }
  622. void DGUSScreenHandler::UpdateScreenVPData() {
  623. DEBUG_ECHOPAIR(" UpdateScreenVPData Screen: ", current_screen);
  624. const uint16_t *VPList = DGUSLCD_FindScreenVPMapList(current_screen);
  625. if (!VPList) {
  626. DEBUG_ECHOLNPAIR(" NO SCREEN FOR: ", current_screen);
  627. ScreenComplete = true;
  628. return; // nothing to do, likely a bug or boring screen.
  629. }
  630. // Round-robin updating of all VPs.
  631. VPList += update_ptr;
  632. bool sent_one = false;
  633. do {
  634. uint16_t VP = pgm_read_word(VPList);
  635. DEBUG_ECHOPAIR(" VP: ", VP);
  636. if (!VP) {
  637. update_ptr = 0;
  638. DEBUG_ECHOLNPGM(" UpdateScreenVPData done");
  639. ScreenComplete = true;
  640. return; // Screen completed.
  641. }
  642. if (VP == skipVP) { skipVP = 0; continue; }
  643. DGUS_VP_Variable rcpy;
  644. if (populate_VPVar(VP, &rcpy)) {
  645. uint8_t expected_tx = 6 + rcpy.size; // expected overhead is 6 bytes + payload.
  646. // Send the VP to the display, but try to avoid overrunning the Tx Buffer.
  647. // But send at least one VP, to avoid getting stalled.
  648. if (rcpy.send_to_display_handler && (!sent_one || expected_tx <= dgusdisplay.GetFreeTxBuffer())) {
  649. //DEBUG_ECHOPAIR(" calling handler for ", rcpy.VP);
  650. sent_one = true;
  651. rcpy.send_to_display_handler(rcpy);
  652. }
  653. else {
  654. // auto x=dgusdisplay.GetFreeTxBuffer();
  655. //DEBUG_ECHOLNPAIR(" tx almost full: ", x);
  656. //DEBUG_ECHOPAIR(" update_ptr ", update_ptr);
  657. ScreenComplete = false;
  658. return; // please call again!
  659. }
  660. }
  661. } while (++update_ptr, ++VPList, true);
  662. }
  663. void DGUSScreenHandler::GotoScreen(DGUSLCD_Screens screen, bool ispopup) {
  664. dgusdisplay.RequestScreen(screen);
  665. UpdateNewScreen(screen, ispopup);
  666. }
  667. void DGUSDisplay::RequestScreen(DGUSLCD_Screens screen) {
  668. DEBUG_ECHOLNPAIR("GotoScreen ", screen);
  669. const unsigned char gotoscreen[] = { 0x5A, 0x01, (unsigned char) (screen >> 8U), (unsigned char) (screen & 0xFFU) };
  670. WriteVariable(0x84, gotoscreen, sizeof(gotoscreen));
  671. }
  672. #endif // HAS_DGUS_LCD_CLASSIC