My Marlin configs for Fabrikator Mini and CTC i3 Pro B
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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