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.

status_screen.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*********************
  2. * status_screen.cpp *
  3. *********************/
  4. /****************************************************************************
  5. * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
  6. * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
  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. * To view a copy of the GNU General Public License, go to the following *
  19. * location: <https://www.gnu.org/licenses/>. *
  20. ****************************************************************************/
  21. #include "../config.h"
  22. #include "../screens.h"
  23. #include "../screen_data.h"
  24. #ifdef FTDI_STATUS_SCREEN
  25. #include "../archim2-flash/flash_storage.h"
  26. using namespace FTDI;
  27. using namespace Theme;
  28. #define GRID_COLS 3
  29. #define GRID_ROWS 16
  30. void StatusScreen::draw_axis_position(draw_mode_t what) {
  31. CommandProcessor cmd;
  32. #if ENABLED(TOUCH_UI_PORTRAIT)
  33. #define X_LBL_POS BTN_POS(1, 9), BTN_SIZE(1,2)
  34. #define Y_LBL_POS BTN_POS(1,11), BTN_SIZE(1,2)
  35. #define Z_LBL_POS BTN_POS(1,13), BTN_SIZE(1,2)
  36. #define X_VAL_POS BTN_POS(2, 9), BTN_SIZE(2,2)
  37. #define Y_VAL_POS BTN_POS(2,11), BTN_SIZE(2,2)
  38. #define Z_VAL_POS BTN_POS(2,13), BTN_SIZE(2,2)
  39. #else
  40. #define X_LBL_POS BTN_POS(1, 9), BTN_SIZE(1,2)
  41. #define Y_LBL_POS BTN_POS(2, 9), BTN_SIZE(1,2)
  42. #define Z_LBL_POS BTN_POS(3, 9), BTN_SIZE(1,2)
  43. #define X_VAL_POS BTN_POS(1,11), BTN_SIZE(1,2)
  44. #define Y_VAL_POS BTN_POS(2,11), BTN_SIZE(1,2)
  45. #define Z_VAL_POS BTN_POS(3,11), BTN_SIZE(1,2)
  46. #endif
  47. #define _UNION_POS(x1,y1,w1,h1,x2,y2,w2,h2) x1,y1,max(x1+w1,x2+w2)-x1,max(y1+h1,y2+h2)-y1
  48. #define UNION_POS(p1, p2) _UNION_POS(p1, p2)
  49. if (what & BACKGROUND) {
  50. cmd.tag(6)
  51. .fgcolor(Theme::axis_label)
  52. .font(Theme::font_large)
  53. .button(UNION_POS(X_LBL_POS, X_VAL_POS), F(""), OPT_FLAT)
  54. .button(UNION_POS(Y_LBL_POS, Y_VAL_POS), F(""), OPT_FLAT)
  55. .button(UNION_POS(Z_LBL_POS, Z_VAL_POS), F(""), OPT_FLAT)
  56. .font(Theme::font_medium)
  57. .fgcolor(Theme::x_axis) .button(X_VAL_POS, F(""), OPT_FLAT)
  58. .fgcolor(Theme::y_axis) .button(Y_VAL_POS, F(""), OPT_FLAT)
  59. .fgcolor(Theme::z_axis) .button(Z_VAL_POS, F(""), OPT_FLAT)
  60. .font(Theme::font_small)
  61. .text ( X_LBL_POS, GET_TEXT_F(MSG_AXIS_X))
  62. .text ( Y_LBL_POS, GET_TEXT_F(MSG_AXIS_Y))
  63. .text ( Z_LBL_POS, GET_TEXT_F(MSG_AXIS_Z))
  64. .colors(normal_btn);
  65. }
  66. if (what & FOREGROUND) {
  67. using namespace ExtUI;
  68. char x_str[15];
  69. char y_str[15];
  70. char z_str[15];
  71. if (isAxisPositionKnown(X))
  72. format_position(x_str, getAxisPosition_mm(X));
  73. else
  74. strcpy_P(x_str, PSTR("?"));
  75. if (isAxisPositionKnown(Y))
  76. format_position(y_str, getAxisPosition_mm(Y));
  77. else
  78. strcpy_P(y_str, PSTR("?"));
  79. if (isAxisPositionKnown(Z))
  80. format_position(z_str, getAxisPosition_mm(Z), 2);
  81. else
  82. strcpy_P(z_str, PSTR("?"));
  83. cmd.tag(6)
  84. .font(Theme::font_medium)
  85. .text(X_VAL_POS, x_str)
  86. .text(Y_VAL_POS, y_str)
  87. .text(Z_VAL_POS, z_str);
  88. }
  89. }
  90. #undef GRID_COLS
  91. #define GRID_COLS TERN(TOUCH_UI_PORTRAIT, 8, 12)
  92. void StatusScreen::draw_temperature(draw_mode_t what) {
  93. using namespace Theme;
  94. #define TEMP_RECT_1 BTN_POS(1,1), BTN_SIZE(4,4)
  95. #define TEMP_RECT_2 BTN_POS(1,1), BTN_SIZE(8,2)
  96. #define NOZ_1_POS BTN_POS(1,1), BTN_SIZE(4,2)
  97. #define NOZ_2_POS BTN_POS(5,1), BTN_SIZE(4,2)
  98. #define BED_POS BTN_POS(1,3), BTN_SIZE(4,2)
  99. #define FAN_POS BTN_POS(5,3), BTN_SIZE(4,2)
  100. #define _ICON_POS(x,y,w,h) x, y, w/4, h
  101. #define _TEXT_POS(x,y,w,h) x + w/4, y, w - w/4, h
  102. #define ICON_POS(pos) _ICON_POS(pos)
  103. #define TEXT_POS(pos) _TEXT_POS(pos)
  104. CommandProcessor cmd;
  105. if (what & BACKGROUND) {
  106. cmd.font(Theme::font_small)
  107. .tag(5)
  108. .fgcolor(temp) .button(TEMP_RECT_1, F(""), OPT_FLAT)
  109. .button(TEMP_RECT_2, F(""), OPT_FLAT)
  110. .fgcolor(fan_speed).button(FAN_POS, F(""), OPT_FLAT)
  111. .tag(0);
  112. // Draw Extruder Bitmap on Extruder Temperature Button
  113. cmd.tag(5)
  114. .cmd (BITMAP_SOURCE(Extruder_Icon_Info))
  115. .cmd (BITMAP_LAYOUT(Extruder_Icon_Info))
  116. .cmd (BITMAP_SIZE (Extruder_Icon_Info))
  117. .icon(ICON_POS(NOZ_1_POS), Extruder_Icon_Info, icon_scale)
  118. .icon(ICON_POS(NOZ_2_POS), Extruder_Icon_Info, icon_scale);
  119. // Draw Bed Heat Bitmap on Bed Heat Button
  120. cmd.cmd (BITMAP_SOURCE(Bed_Heat_Icon_Info))
  121. .cmd (BITMAP_LAYOUT(Bed_Heat_Icon_Info))
  122. .cmd (BITMAP_SIZE (Bed_Heat_Icon_Info))
  123. .icon(ICON_POS(BED_POS), Bed_Heat_Icon_Info, icon_scale);
  124. // Draw Fan Percent Bitmap on Bed Heat Button
  125. cmd.cmd (BITMAP_SOURCE(Fan_Icon_Info))
  126. .cmd (BITMAP_LAYOUT(Fan_Icon_Info))
  127. .cmd (BITMAP_SIZE (Fan_Icon_Info))
  128. .icon(ICON_POS(FAN_POS), Fan_Icon_Info, icon_scale);
  129. TERN_(TOUCH_UI_USE_UTF8, load_utf8_bitmaps(cmd)); // Restore font bitmap handles
  130. }
  131. if (what & FOREGROUND) {
  132. using namespace ExtUI;
  133. char e0_str[20], e1_str[20], bed_str[20], fan_str[20];
  134. sprintf_P(fan_str, PSTR("%-3d %%"), int8_t(getActualFan_percent(FAN0)));
  135. if (isHeaterIdle(BED))
  136. format_temp_and_idle(bed_str, getActualTemp_celsius(BED));
  137. else
  138. format_temp_and_temp(bed_str, getActualTemp_celsius(BED), getTargetTemp_celsius(BED));
  139. if (isHeaterIdle(H0))
  140. format_temp_and_idle(e0_str, getActualTemp_celsius(H0));
  141. else
  142. format_temp_and_temp(e0_str, getActualTemp_celsius(H0), getTargetTemp_celsius(H0));
  143. #if HAS_MULTI_EXTRUDER
  144. if (isHeaterIdle(H1))
  145. format_temp_and_idle(e1_str, getActualTemp_celsius(H1));
  146. else
  147. format_temp_and_temp(e1_str, getActualTemp_celsius(H1), getTargetTemp_celsius(H1));
  148. #else
  149. strcpy_P(e1_str, PSTR("-"));
  150. #endif
  151. cmd.tag(5)
  152. .font(font_medium)
  153. .text(TEXT_POS(NOZ_1_POS), e0_str)
  154. .text(TEXT_POS(NOZ_2_POS), e1_str)
  155. .text(TEXT_POS(BED_POS), bed_str)
  156. .text(TEXT_POS(FAN_POS), fan_str);
  157. }
  158. }
  159. void StatusScreen::_format_time(char *outstr, uint32_t time) {
  160. const uint8_t hrs = time / 3600,
  161. min = (time / 60) % 60,
  162. sec = time % 60;
  163. if (hrs)
  164. sprintf_P(outstr, PSTR("%02d:%02d"), hrs, min);
  165. else
  166. sprintf_P(outstr, PSTR("%02d:%02ds"), min, sec);
  167. }
  168. void StatusScreen::draw_progress(draw_mode_t what) {
  169. using namespace ExtUI;
  170. using namespace Theme;
  171. CommandProcessor cmd;
  172. #undef GRID_COLS
  173. #if ENABLED(TOUCH_UI_PORTRAIT)
  174. #define GRID_COLS 3
  175. #define PROGRESSZONE_POS BTN_POS(1,5), BTN_SIZE(3,2)
  176. #define TIME_POS_X BTN_X(1)
  177. #define TIME_POS_W BTN_W(1)
  178. #define REMAINING_POS_X BTN_X(2)
  179. #define REMAINING_POS_W BTN_W(1)
  180. #define PROGRESS_POS_X BTN_X(3)
  181. #define PROGRESS_POS_W BTN_W(1)
  182. #define PROGRESSZONE_FIRSTLINE_Y BTN_Y(5)
  183. #define PROGRESSBAR_POS BTN_POS(1,6), BTN_SIZE(3,1)
  184. #else
  185. #define GRID_COLS 6
  186. #define PROGRESSZONE_POS BTN_POS(5,1), BTN_SIZE(2,4)
  187. #if ENABLED(SHOW_REMAINING_TIME)
  188. #define TIME_POS BTN_POS(5,1), BTN_SIZE(1,2)
  189. #define REMAINING_POS BTN_POS(6,1), BTN_SIZE(1,2)
  190. #else
  191. #define TIME_POS BTN_POS(5,1), BTN_SIZE(2,2)
  192. #endif
  193. #define PROGRESS_POS BTN_POS(5,3), BTN_SIZE(2,2)
  194. #define PROGRESSBAR_POS BTN_POS(5,2), BTN_SIZE(2,2)
  195. #endif
  196. if (what & BACKGROUND) {
  197. cmd.tag(0).font(font_medium)
  198. .fgcolor(progress).button(PROGRESSZONE_POS, F(""), OPT_FLAT);
  199. }
  200. if (what & FOREGROUND) {
  201. const uint32_t elapsed = getProgress_seconds_elapsed();
  202. char elapsed_str[10];
  203. _format_time(elapsed_str, elapsed);
  204. #if ENABLED(SHOW_REMAINING_TIME)
  205. const uint32_t remaining = getProgress_seconds_remaining();
  206. char remaining_str[10];
  207. _format_time(remaining_str, remaining);
  208. #endif
  209. const uint16_t current_progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, getProgress_permyriad(), getProgress_percent() * 100);
  210. constexpr uint16_t progress_range = 10000U;
  211. const bool show_progress_bar = current_progress > 0 && current_progress < progress_range + 1;
  212. if (show_progress_bar) {
  213. cmd.tag(0).font(font_medium)
  214. .bgcolor(progress)
  215. .progress(PROGRESSBAR_POS, current_progress, progress_range, OPT_FLAT);
  216. }
  217. char progress_str[10];
  218. sprintf_P(progress_str,
  219. #if ENABLED(PRINT_PROGRESS_SHOW_DECIMALS)
  220. PSTR("%3d.%02d%%"), uint8_t(current_progress / 100), current_progress % 100
  221. #else
  222. PSTR("%3d%%"), uint8_t(current_progress / 100)
  223. #endif
  224. );
  225. #if ENABLED(TOUCH_UI_PORTRAIT)
  226. const uint16_t texts_pos_h = show_progress_bar ? (BTN_H(1)) : (BTN_H(2));
  227. cmd.font(font_medium)
  228. .tag(7).text(TIME_POS_X, PROGRESSZONE_FIRSTLINE_Y, TIME_POS_W, texts_pos_h, elapsed_str)
  229. #if ENABLED(SHOW_REMAINING_TIME)
  230. .text(REMAINING_POS_X, PROGRESSZONE_FIRSTLINE_Y, REMAINING_POS_W, texts_pos_h, remaining_str)
  231. #endif
  232. .text(PROGRESS_POS_X, PROGRESSZONE_FIRSTLINE_Y, PROGRESS_POS_W, texts_pos_h, progress_str);
  233. #else
  234. cmd.font(font_medium)
  235. .tag(7).text(TIME_POS, elapsed_str)
  236. #if ENABLED(SHOW_REMAINING_TIME)
  237. .text(REMAINING_POS, remaining_str)
  238. #endif
  239. .text(PROGRESS_POS, progress_str);
  240. #endif
  241. }
  242. }
  243. void StatusScreen::draw_interaction_buttons(draw_mode_t what) {
  244. #undef GRID_COLS
  245. #define GRID_COLS 4
  246. if (what & FOREGROUND) {
  247. using namespace ExtUI;
  248. #if ENABLED(TOUCH_UI_PORTRAIT)
  249. #define MEDIA_BTN_POS BTN_POS(1,15), BTN_SIZE(2,2)
  250. #define MENU_BTN_POS BTN_POS(3,15), BTN_SIZE(2,2)
  251. #else
  252. #define MEDIA_BTN_POS BTN_POS(1,13), BTN_SIZE(2,4)
  253. #define MENU_BTN_POS BTN_POS(3,13), BTN_SIZE(2,4)
  254. #endif
  255. const bool has_media = isMediaInserted() && !isPrintingFromMedia();
  256. CommandProcessor cmd;
  257. cmd.colors(normal_btn)
  258. .font(Theme::font_medium)
  259. .colors(has_media ? action_btn : normal_btn)
  260. .enabled(has_media && !isPrinting())
  261. .tag(3).button(MEDIA_BTN_POS, isPrinting() ? GET_TEXT_F(MSG_PRINTING) : GET_TEXT_F(MSG_BUTTON_MEDIA))
  262. .colors(!has_media ? action_btn : normal_btn)
  263. .tag(4).button(MENU_BTN_POS, GET_TEXT_F(MSG_BUTTON_MENU));
  264. }
  265. }
  266. void StatusScreen::draw_status_message(draw_mode_t what, const char *message) {
  267. #undef GRID_COLS
  268. #define GRID_COLS 1
  269. #if ENABLED(TOUCH_UI_PORTRAIT)
  270. #define STATUS_POS BTN_POS(1,7), BTN_SIZE(1,2)
  271. #else
  272. #define STATUS_POS BTN_POS(1,5), BTN_SIZE(1,4)
  273. #endif
  274. if (what & BACKGROUND) {
  275. CommandProcessor cmd;
  276. cmd.fgcolor(Theme::status_msg)
  277. .tag(0)
  278. .button(STATUS_POS, F(""), OPT_FLAT);
  279. draw_text_box(cmd, STATUS_POS, message, OPT_CENTER, font_large);
  280. }
  281. }
  282. void StatusScreen::setStatusMessage(FSTR_P fmsg) {
  283. #ifdef __AVR__
  284. char buff[strlen_P(FTOP(fmsg)) + 1];
  285. strcpy_P(buff, FTOP(fmsg));
  286. setStatusMessage((const char *)buff);
  287. #else
  288. setStatusMessage(FTOP(fmsg));
  289. #endif
  290. }
  291. void StatusScreen::setStatusMessage(const char *message) {
  292. if (CommandProcessor::is_processing()) {
  293. #if ENABLED(TOUCH_UI_DEBUG)
  294. SERIAL_ECHO_MSG("Cannot update status message, command processor busy");
  295. #endif
  296. return;
  297. }
  298. CommandProcessor cmd;
  299. cmd.cmd(CMD_DLSTART)
  300. .cmd(CLEAR_COLOR_RGB(Theme::bg_color))
  301. .cmd(CLEAR(true,true,true));
  302. draw_temperature(BACKGROUND);
  303. draw_status_message(BACKGROUND, message);
  304. draw_interaction_buttons(BACKGROUND);
  305. draw_progress(BACKGROUND);
  306. draw_axis_position(BACKGROUND);
  307. storeBackground();
  308. #if ENABLED(TOUCH_UI_DEBUG)
  309. SERIAL_ECHO_MSG("New status message: ", message);
  310. #endif
  311. if (AT_SCREEN(StatusScreen)) {
  312. current_screen.onRefresh();
  313. }
  314. }
  315. void StatusScreen::loadBitmaps() {
  316. // Load the bitmaps for the status screen
  317. using namespace Theme;
  318. constexpr uint32_t base = ftdi_memory_map::RAM_G;
  319. CLCD::mem_write_pgm(base + TD_Icon_Info.RAMG_offset, TD_Icon, sizeof(TD_Icon));
  320. CLCD::mem_write_pgm(base + Extruder_Icon_Info.RAMG_offset, Extruder_Icon, sizeof(Extruder_Icon));
  321. CLCD::mem_write_pgm(base + Bed_Heat_Icon_Info.RAMG_offset, Bed_Heat_Icon, sizeof(Bed_Heat_Icon));
  322. CLCD::mem_write_pgm(base + Fan_Icon_Info.RAMG_offset, Fan_Icon, sizeof(Fan_Icon));
  323. // Load fonts for internationalization
  324. #if ENABLED(TOUCH_UI_USE_UTF8)
  325. load_utf8_data(base + UTF8_FONT_OFFSET);
  326. #endif
  327. }
  328. void StatusScreen::onStartup() {
  329. UIFlashStorage::initialize();
  330. }
  331. void StatusScreen::onRedraw(draw_mode_t what) {
  332. if (what & FOREGROUND) {
  333. draw_temperature(FOREGROUND);
  334. draw_progress(FOREGROUND);
  335. draw_axis_position(FOREGROUND);
  336. draw_interaction_buttons(FOREGROUND);
  337. }
  338. }
  339. void StatusScreen::onEntry() {
  340. BaseScreen::onEntry();
  341. onRefresh();
  342. }
  343. void StatusScreen::onIdle() {
  344. if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
  345. onRefresh();
  346. refresh_timer.start();
  347. }
  348. BaseScreen::onIdle();
  349. }
  350. bool StatusScreen::onTouchEnd(uint8_t tag) {
  351. using namespace ExtUI;
  352. switch (tag) {
  353. #if ENABLED(SDSUPPORT)
  354. case 3: GOTO_SCREEN(FilesScreen); break;
  355. #endif
  356. case 4:
  357. if (isPrinting()) {
  358. GOTO_SCREEN(TuneMenu);
  359. }
  360. else {
  361. GOTO_SCREEN(MainMenu);
  362. }
  363. break;
  364. case 5: GOTO_SCREEN(TemperatureScreen); break;
  365. case 6:
  366. if (isPrinting()) {
  367. #if ENABLED(BABYSTEPPING)
  368. GOTO_SCREEN(NudgeNozzleScreen);
  369. #elif HAS_BED_PROBE
  370. GOTO_SCREEN(ZOffsetScreen);
  371. #else
  372. return false;
  373. #endif
  374. }
  375. else {
  376. GOTO_SCREEN(MoveAxisScreen);
  377. }
  378. break;
  379. case 7: GOTO_SCREEN(FeedratePercentScreen); break;
  380. default:
  381. return true;
  382. }
  383. // If a passcode is enabled, the LockScreen will prevent the
  384. // user from proceeding.
  385. LockScreen::check_passcode();
  386. return true;
  387. }
  388. void StatusScreen::onMediaInserted() {
  389. if (AT_SCREEN(StatusScreen))
  390. setStatusMessage(GET_TEXT_F(MSG_MEDIA_INSERTED));
  391. }
  392. void StatusScreen::onMediaRemoved() {
  393. if (AT_SCREEN(StatusScreen) || ExtUI::isPrintingFromMedia())
  394. setStatusMessage(GET_TEXT_F(MSG_MEDIA_REMOVED));
  395. }
  396. #endif // FTDI_STATUS_SCREEN