My Marlin configs for Fabrikator Mini and CTC i3 Pro B
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

DGUSScreenHandler.cpp 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  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. DGUSScreenHandlerClass 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. ExtUI::FileList filelist;
  49. #endif
  50. #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
  51. filament_data_t filament_data;
  52. #endif
  53. void DGUSScreenHandler::sendinfoscreen(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const 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. #ifdef VP_MSGSTR4
  68. if (populate_VPVar(VP_MSGSTR4, &ramcopy)) {
  69. ramcopy.memadr = (void*) line4;
  70. l4inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
  71. }
  72. #endif
  73. }
  74. void DGUSScreenHandler::HandleUserConfirmationPopUp(uint16_t VP, PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1, bool l2, bool l3, bool l4) {
  75. if (current_screen == DGUSLCD_SCREEN_CONFIRM) // Already showing a pop up, so we need to cancel that first.
  76. PopToOldScreen();
  77. ConfirmVP = VP;
  78. sendinfoscreen(line1, line2, line3, line4, l1, l2, l3, l4);
  79. GotoScreen(DGUSLCD_SCREEN_CONFIRM);
  80. }
  81. void DGUSScreenHandler::setstatusmessage(const char *msg) {
  82. DGUS_VP_Variable ramcopy;
  83. if (populate_VPVar(VP_M117, &ramcopy)) {
  84. ramcopy.memadr = (void*) msg;
  85. DGUSLCD_SendStringToDisplay(ramcopy);
  86. }
  87. }
  88. void DGUSScreenHandler::setstatusmessagePGM(PGM_P const msg) {
  89. DGUS_VP_Variable ramcopy;
  90. if (populate_VPVar(VP_M117, &ramcopy)) {
  91. ramcopy.memadr = (void*) msg;
  92. DGUSLCD_SendStringToDisplayPGM(ramcopy);
  93. }
  94. }
  95. // Send an 8 bit or 16 bit value to the display.
  96. void DGUSScreenHandler::DGUSLCD_SendWordValueToDisplay(DGUS_VP_Variable &var) {
  97. if (var.memadr) {
  98. //DEBUG_ECHOPGM(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
  99. //DEBUG_ECHOLNPGM(" data ", *(uint16_t *)var.memadr);
  100. if (var.size > 1)
  101. dgusdisplay.WriteVariable(var.VP, *(int16_t*)var.memadr);
  102. else
  103. dgusdisplay.WriteVariable(var.VP, *(int8_t*)var.memadr);
  104. }
  105. }
  106. // Send an uint8_t between 0 and 255 to the display, but scale to a percentage (0..100)
  107. void DGUSScreenHandler::DGUSLCD_SendPercentageToDisplay(DGUS_VP_Variable &var) {
  108. if (var.memadr) {
  109. //DEBUG_ECHOPGM(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
  110. //DEBUG_ECHOLNPGM(" data ", *(uint16_t *)var.memadr);
  111. uint16_t tmp = *(uint8_t *) var.memadr + 1; // +1 -> avoid rounding issues for the display.
  112. tmp = map(tmp, 0, 255, 0, 100);
  113. dgusdisplay.WriteVariable(var.VP, tmp);
  114. }
  115. }
  116. // Send the current print progress to the display.
  117. void DGUSScreenHandler::DGUSLCD_SendPrintProgressToDisplay(DGUS_VP_Variable &var) {
  118. //DEBUG_ECHOPGM(" DGUSLCD_SendPrintProgressToDisplay ", var.VP);
  119. uint16_t tmp = ExtUI::getProgress_percent();
  120. //DEBUG_ECHOLNPGM(" data ", tmp);
  121. dgusdisplay.WriteVariable(var.VP, tmp);
  122. }
  123. // Send the current print time to the display.
  124. // It is using a hex display for that: It expects BSD coded data in the format xxyyzz
  125. void DGUSScreenHandler::DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var) {
  126. duration_t elapsed = print_job_timer.duration();
  127. char buf[32];
  128. elapsed.toString(buf);
  129. dgusdisplay.WriteVariable(VP_PrintTime, buf, var.size, true);
  130. }
  131. // Send an uint8_t between 0 and 100 to a variable scale to 0..255
  132. void DGUSScreenHandler::DGUSLCD_PercentageToUint8(DGUS_VP_Variable &var, void *val_ptr) {
  133. if (var.memadr) {
  134. const uint16_t value = BE16_P(val_ptr);
  135. DEBUG_ECHOLNPGM("Got percent:", value);
  136. *(uint8_t*)var.memadr = map(constrain(value, 0, 100), 0, 100, 0, 255);
  137. DEBUG_ECHOLNPGM("Set uint8:", *(uint8_t*)var.memadr);
  138. }
  139. }
  140. // Sends a (RAM located) string to the DGUS Display
  141. // (Note: The DGUS Display does not clear after the \0, you have to
  142. // overwrite the remainings with spaces.// var.size has the display buffer size!
  143. void DGUSScreenHandler::DGUSLCD_SendStringToDisplay(DGUS_VP_Variable &var) {
  144. char *tmp = (char*) var.memadr;
  145. dgusdisplay.WriteVariable(var.VP, tmp, var.size, true);
  146. }
  147. // Sends a (flash located) string to the DGUS Display
  148. // (Note: The DGUS Display does not clear after the \0, you have to
  149. // overwrite the remainings with spaces.// var.size has the display buffer size!
  150. void DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(DGUS_VP_Variable &var) {
  151. char *tmp = (char*) var.memadr;
  152. dgusdisplay.WriteVariablePGM(var.VP, tmp, var.size, true);
  153. }
  154. #if HAS_PID_HEATING
  155. void DGUSScreenHandler::DGUSLCD_SendTemperaturePID(DGUS_VP_Variable &var) {
  156. float value = *(float *)var.memadr;
  157. value /= 10;
  158. float valuesend = 0;
  159. switch (var.VP) {
  160. default: return;
  161. #if HAS_HOTEND
  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 HAS_MULTI_HOTEND
  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[22];
  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[10];
  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_ECHOPGM(" DGUSLCD_SendFanStatusToDisplay ", var.VP);
  208. DEBUG_ECHOLNPGM(" 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_ECHOPGM(" DGUSLCD_SendHeaterStatusToDisplay ", var.VP);
  219. DEBUG_ECHOLNPGM(" 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_ECHOPGM(" DGUSLCD_SendWaitingStatusToDisplay ", var.VP);
  231. //DEBUG_ECHOLNPGM(" data ", BE16_P(&index));
  232. if (period++ > DGUS_UI_WAITING_STATUS_PERIOD) {
  233. dgusdisplay.WriteVariable(var.VP, index);
  234. //DEBUG_ECHOLNPGM(" data ", BE16_P(&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)BE16_P(val_ptr);
  268. if (scroll) {
  269. top_file += scroll;
  270. DEBUG_ECHOPGM("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_ECHOPGM("new topfile adjusted:", top_file);
  281. }
  282. else if (!filelist.isAtRootDir()) {
  283. IF_DISABLED(DGUS_LCD_UI_MKS, filelist.upDir());
  284. top_file = 0;
  285. ForceCompleteUpdate();
  286. }
  287. if (old_top != top_file) ForceCompleteUpdate();
  288. }
  289. void DGUSScreenHandler::DGUSLCD_SD_ReallyAbort(DGUS_VP_Variable &var, void *val_ptr) {
  290. ExtUI::stopPrint();
  291. GotoScreen(DGUSLCD_SCREEN_MAIN);
  292. }
  293. void DGUSScreenHandler::DGUSLCD_SD_PrintTune(DGUS_VP_Variable &var, void *val_ptr) {
  294. if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
  295. GotoScreen(DGUSLCD_SCREEN_SDPRINTTUNE);
  296. }
  297. void DGUSScreenHandler::SDCardError() {
  298. DGUSScreenHandler::SDCardRemoved();
  299. sendinfoscreen(F("NOTICE"), nullptr, F("SD card error"), nullptr, true, true, true, true);
  300. SetupConfirmAction(nullptr);
  301. GotoScreen(DGUSLCD_SCREEN_POPUP);
  302. }
  303. #endif // SDSUPPORT
  304. void DGUSScreenHandler::ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr) {
  305. DGUS_VP_Variable ramcopy;
  306. if (!populate_VPVar(ConfirmVP, &ramcopy)) return;
  307. if (ramcopy.set_by_display_handler) ramcopy.set_by_display_handler(ramcopy, val_ptr);
  308. }
  309. const uint16_t* DGUSLCD_FindScreenVPMapList(uint8_t screen) {
  310. const uint16_t *ret;
  311. const struct VPMapping *map = VPMap;
  312. while ((ret = (uint16_t*) pgm_read_ptr(&(map->VPList)))) {
  313. if (pgm_read_byte(&(map->screen)) == screen) return ret;
  314. map++;
  315. }
  316. return nullptr;
  317. }
  318. const DGUS_VP_Variable* DGUSLCD_FindVPVar(const uint16_t vp) {
  319. const DGUS_VP_Variable *ret = ListOfVP;
  320. do {
  321. const uint16_t vpcheck = pgm_read_word(&(ret->VP));
  322. if (vpcheck == 0) break;
  323. if (vpcheck == vp) return ret;
  324. ++ret;
  325. } while (1);
  326. DEBUG_ECHOLNPGM("FindVPVar NOT FOUND ", vp);
  327. return nullptr;
  328. }
  329. void DGUSScreenHandler::ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr) {
  330. if (!ExtUI::isPrinting()) {
  331. ScreenChangeHook(var, val_ptr);
  332. dgusdisplay.RequestScreen(current_screen);
  333. }
  334. }
  335. void DGUSScreenHandler::HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr) {
  336. thermalManager.disable_all_heaters();
  337. ForceCompleteUpdate(); // hint to send all data.
  338. }
  339. void DGUSScreenHandler::HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr) {
  340. celsius_t newvalue = BE16_P(val_ptr);
  341. celsius_t acceptedvalue;
  342. switch (var.VP) {
  343. default: return;
  344. #if HAS_HOTEND
  345. case VP_T_E0_Set:
  346. NOMORE(newvalue, HEATER_0_MAXTEMP);
  347. thermalManager.setTargetHotend(newvalue, 0);
  348. acceptedvalue = thermalManager.degTargetHotend(0);
  349. break;
  350. #endif
  351. #if HAS_MULTI_HOTEND
  352. case VP_T_E1_Set:
  353. NOMORE(newvalue, HEATER_1_MAXTEMP);
  354. thermalManager.setTargetHotend(newvalue, 1);
  355. acceptedvalue = thermalManager.degTargetHotend(1);
  356. break;
  357. #endif
  358. #if HAS_HEATED_BED
  359. case VP_T_Bed_Set:
  360. NOMORE(newvalue, BED_MAXTEMP);
  361. thermalManager.setTargetBed(newvalue);
  362. acceptedvalue = thermalManager.degTargetBed();
  363. break;
  364. #endif
  365. }
  366. // reply to display the new value to update the view if the new value was rejected by the Thermal Manager.
  367. if (newvalue != acceptedvalue && var.send_to_display_handler) var.send_to_display_handler(var);
  368. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  369. }
  370. void DGUSScreenHandler::HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr) {
  371. #if HAS_EXTRUDERS
  372. const uint16_t newvalue = BE16_P(val_ptr);
  373. uint8_t target_extruder;
  374. switch (var.VP) {
  375. default: return;
  376. case VP_Flowrate_E0: target_extruder = 0; break;
  377. #if HAS_MULTI_EXTRUDER
  378. case VP_Flowrate_E1: target_extruder = 1; break;
  379. #endif
  380. }
  381. planner.set_flow(target_extruder, newvalue);
  382. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  383. #else
  384. UNUSED(var); UNUSED(val_ptr);
  385. #endif
  386. }
  387. void DGUSScreenHandler::HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr) {
  388. DEBUG_ECHOLNPGM("HandleManualExtrude");
  389. const int16_t movevalue = BE16_P(val_ptr);
  390. float target = movevalue * 0.01f;
  391. ExtUI::extruder_t target_extruder;
  392. switch (var.VP) {
  393. #if HAS_HOTEND
  394. case VP_MOVE_E0: target_extruder = ExtUI::extruder_t::E0; break;
  395. #if HAS_MULTI_EXTRUDER
  396. case VP_MOVE_E1: target_extruder = ExtUI::extruder_t::E1; break;
  397. #endif
  398. #endif
  399. default: return;
  400. }
  401. target += ExtUI::getAxisPosition_mm(target_extruder);
  402. ExtUI::setAxisPosition_mm(target, target_extruder);
  403. skipVP = var.VP;
  404. }
  405. #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
  406. void DGUSScreenHandler::HandleManualMoveOption(DGUS_VP_Variable &var, void *val_ptr) {
  407. DEBUG_ECHOLNPGM("HandleManualMoveOption");
  408. *(uint16_t*)var.memadr = BE16_P(val_ptr);
  409. }
  410. #endif
  411. void DGUSScreenHandler::HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr) {
  412. DEBUG_ECHOLNPGM("HandleMotorLockUnlock");
  413. const int16_t lock = BE16_P(val_ptr);
  414. queue.enqueue_one_now(lock ? F("M18") : F("M17"));
  415. }
  416. void DGUSScreenHandler::HandleSettings(DGUS_VP_Variable &var, void *val_ptr) {
  417. DEBUG_ECHOLNPGM("HandleSettings");
  418. const uint16_t value = BE16_P(val_ptr);
  419. switch (value) {
  420. default: break;
  421. case 1:
  422. TERN_(PRINTCOUNTER, print_job_timer.initStats());
  423. settings.reset();
  424. settings.save();
  425. break;
  426. case 2: settings.load(); break;
  427. case 3: settings.save(); break;
  428. }
  429. }
  430. void DGUSScreenHandler::HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr) {
  431. const uint16_t value_raw = BE16_P(val_ptr);
  432. DEBUG_ECHOLNPGM("HandleStepPerMMChanged:", value_raw);
  433. const float value = (float)value_raw / 10;
  434. ExtUI::axis_t axis;
  435. switch (var.VP) {
  436. case VP_X_STEP_PER_MM: axis = ExtUI::axis_t::X; break;
  437. case VP_Y_STEP_PER_MM: axis = ExtUI::axis_t::Y; break;
  438. case VP_Z_STEP_PER_MM: axis = ExtUI::axis_t::Z; break;
  439. default: return;
  440. }
  441. DEBUG_ECHOLNPGM("value:", value);
  442. ExtUI::setAxisSteps_per_mm(value, axis);
  443. DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisSteps_per_mm(axis));
  444. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  445. }
  446. void DGUSScreenHandler::HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr) {
  447. const uint16_t value_raw = BE16_P(val_ptr);
  448. DEBUG_ECHOLNPGM("HandleStepPerMMExtruderChanged:", value_raw);
  449. const float value = (float)value_raw / 10;
  450. ExtUI::extruder_t extruder;
  451. switch (var.VP) {
  452. default: return;
  453. #if HAS_EXTRUDERS
  454. case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break;
  455. #if HAS_MULTI_EXTRUDER
  456. case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break;
  457. #endif
  458. #endif
  459. }
  460. DEBUG_ECHOLNPGM("value:", value);
  461. ExtUI::setAxisSteps_per_mm(value, extruder);
  462. DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisSteps_per_mm(extruder));
  463. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  464. }
  465. #if HAS_PID_HEATING
  466. void DGUSScreenHandler::HandlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr) {
  467. DEBUG_ECHOLNPGM("HandlePIDAutotune");
  468. char buf[32] = {0};
  469. switch (var.VP) {
  470. default: break;
  471. #if ENABLED(PIDTEMP)
  472. #if HAS_HOTEND
  473. case VP_PID_AUTOTUNE_E0: // Autotune Extruder 0
  474. sprintf_P(buf, PSTR("M303 E%d C5 S210 U1"), ExtUI::extruder_t::E0);
  475. queue.enqueue_one_now(buf);
  476. break;
  477. #endif
  478. #if HAS_MULTI_HOTEND
  479. case VP_PID_AUTOTUNE_E1:
  480. sprintf_P(buf, PSTR("M303 E%d C5 S210 U1"), ExtUI::extruder_t::E1);
  481. queue.enqueue_one_now(buf);
  482. break;
  483. #endif
  484. #endif
  485. #if ENABLED(PIDTEMPBED)
  486. case VP_PID_AUTOTUNE_BED:
  487. queue.enqueue_one_now(F("M303 E-1 C5 S70 U1"));
  488. break;
  489. #endif
  490. }
  491. #if ENABLED(DGUS_UI_WAITING)
  492. sendinfoscreen(F("PID is autotuning"), F("please wait"), NUL_STR, NUL_STR, true, true, true, true);
  493. GotoScreen(DGUSLCD_SCREEN_WAITING);
  494. #endif
  495. }
  496. #endif // HAS_PID_HEATING
  497. #if HAS_BED_PROBE
  498. void DGUSScreenHandler::HandleProbeOffsetZChanged(DGUS_VP_Variable &var, void *val_ptr) {
  499. DEBUG_ECHOLNPGM("HandleProbeOffsetZChanged");
  500. const float offset = float(int16_t(BE16_P(val_ptr))) / 100.0f;
  501. ExtUI::setZOffset_mm(offset);
  502. skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
  503. return;
  504. }
  505. #endif
  506. #if HAS_FAN
  507. void DGUSScreenHandler::HandleFanControl(DGUS_VP_Variable &var, void *val_ptr) {
  508. DEBUG_ECHOLNPGM("HandleFanControl");
  509. *(uint8_t*)var.memadr = *(uint8_t*)var.memadr > 0 ? 0 : 255;
  510. }
  511. #endif
  512. void DGUSScreenHandler::HandleHeaterControl(DGUS_VP_Variable &var, void *val_ptr) {
  513. DEBUG_ECHOLNPGM("HandleHeaterControl");
  514. uint8_t preheat_temp = 0;
  515. switch (var.VP) {
  516. #if HAS_HOTEND
  517. case VP_E0_CONTROL:
  518. #if HAS_MULTI_HOTEND
  519. case VP_E1_CONTROL:
  520. #if HOTENDS >= 3
  521. case VP_E2_CONTROL:
  522. #endif
  523. #endif
  524. preheat_temp = PREHEAT_1_TEMP_HOTEND;
  525. break;
  526. #endif
  527. #if HAS_HEATED_BED
  528. case VP_BED_CONTROL:
  529. preheat_temp = PREHEAT_1_TEMP_BED;
  530. break;
  531. #endif
  532. }
  533. *(int16_t*)var.memadr = *(int16_t*)var.memadr > 0 ? 0 : preheat_temp;
  534. }
  535. #if ENABLED(DGUS_PREHEAT_UI)
  536. void DGUSScreenHandler::HandlePreheat(DGUS_VP_Variable &var, void *val_ptr) {
  537. DEBUG_ECHOLNPGM("HandlePreheat");
  538. const uint16_t preheat_option = BE16_P(val_ptr);
  539. switch (preheat_option) {
  540. default:
  541. switch (var.VP) {
  542. default: return;
  543. case VP_E0_BED_PREHEAT: TERN_(HAS_HOTEND, ui.preheat_all(0)); break;
  544. #if DISABLED(DGUS_LCD_UI_HIPRECY) && HAS_MULTI_HOTEND
  545. case VP_E1_BED_PREHEAT: ui.preheat_all(1); break;
  546. #endif
  547. }
  548. case 7: break; // Custom preheat
  549. case 9: thermalManager.cooldown(); break; // Cool down
  550. }
  551. // Go to the preheat screen to show the heating progress
  552. GotoScreen(DGUSLCD_SCREEN_PREHEAT);
  553. }
  554. #endif // DGUS_PREHEAT_UI
  555. #if ENABLED(POWER_LOSS_RECOVERY)
  556. void DGUSScreenHandler::HandlePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr) {
  557. uint16_t value = BE16_P(val_ptr);
  558. if (value) {
  559. queue.inject(F("M1000"));
  560. dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), 32, true);
  561. GotoScreen(PLR_SCREEN_RECOVER);
  562. }
  563. else {
  564. recovery.cancel();
  565. GotoScreen(PLR_SCREEN_CANCEL);
  566. }
  567. }
  568. #endif
  569. void DGUSScreenHandler::UpdateNewScreen(DGUSLCD_Screens newscreen, bool popup) {
  570. DEBUG_ECHOLNPGM("SetNewScreen: ", newscreen);
  571. if (!popup) {
  572. memmove(&past_screens[1], &past_screens[0], sizeof(past_screens) - 1);
  573. past_screens[0] = current_screen;
  574. }
  575. current_screen = newscreen;
  576. skipVP = 0;
  577. ForceCompleteUpdate();
  578. }
  579. void DGUSScreenHandler::PopToOldScreen() {
  580. DEBUG_ECHOLNPGM("PopToOldScreen s=", past_screens[0]);
  581. GotoScreen(past_screens[0], true);
  582. memmove(&past_screens[0], &past_screens[1], sizeof(past_screens) - 1);
  583. past_screens[sizeof(past_screens) - 1] = DGUSLCD_SCREEN_MAIN;
  584. }
  585. void DGUSScreenHandler::UpdateScreenVPData() {
  586. DEBUG_ECHOPGM(" UpdateScreenVPData Screen: ", current_screen);
  587. const uint16_t *VPList = DGUSLCD_FindScreenVPMapList(current_screen);
  588. if (!VPList) {
  589. DEBUG_ECHOLNPGM(" NO SCREEN FOR: ", current_screen);
  590. ScreenComplete = true;
  591. return; // nothing to do, likely a bug or boring screen.
  592. }
  593. // Round-robin updating of all VPs.
  594. VPList += update_ptr;
  595. bool sent_one = false;
  596. do {
  597. uint16_t VP = pgm_read_word(VPList);
  598. DEBUG_ECHOPGM(" VP: ", VP);
  599. if (!VP) {
  600. update_ptr = 0;
  601. DEBUG_ECHOLNPGM(" UpdateScreenVPData done");
  602. ScreenComplete = true;
  603. return; // Screen completed.
  604. }
  605. if (VP == skipVP) { skipVP = 0; continue; }
  606. DGUS_VP_Variable rcpy;
  607. if (populate_VPVar(VP, &rcpy)) {
  608. uint8_t expected_tx = 6 + rcpy.size; // expected overhead is 6 bytes + payload.
  609. // Send the VP to the display, but try to avoid overrunning the Tx Buffer.
  610. // But send at least one VP, to avoid getting stalled.
  611. if (rcpy.send_to_display_handler && (!sent_one || expected_tx <= dgusdisplay.GetFreeTxBuffer())) {
  612. //DEBUG_ECHOPGM(" calling handler for ", rcpy.VP);
  613. sent_one = true;
  614. rcpy.send_to_display_handler(rcpy);
  615. }
  616. else {
  617. // auto x=dgusdisplay.GetFreeTxBuffer();
  618. //DEBUG_ECHOLNPGM(" tx almost full: ", x);
  619. //DEBUG_ECHOPGM(" update_ptr ", update_ptr);
  620. ScreenComplete = false;
  621. return; // please call again!
  622. }
  623. }
  624. } while (++update_ptr, ++VPList, true);
  625. }
  626. void DGUSScreenHandler::GotoScreen(DGUSLCD_Screens screen, bool ispopup) {
  627. dgusdisplay.RequestScreen(screen);
  628. UpdateNewScreen(screen, ispopup);
  629. }
  630. void DGUSDisplay::RequestScreen(DGUSLCD_Screens screen) {
  631. DEBUG_ECHOLNPGM("GotoScreen ", screen);
  632. const unsigned char gotoscreen[] = { 0x5A, 0x01, (unsigned char) (screen >> 8U), (unsigned char) (screen & 0xFFU) };
  633. WriteVariable(0x84, gotoscreen, sizeof(gotoscreen));
  634. }
  635. #endif // HAS_DGUS_LCD_CLASSIC