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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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/MarlinConfig.h"
  23. #if ENABLED(TOUCH_SCREEN)
  24. #include "touch.h"
  25. #include "../marlinui.h" // for ui methods
  26. #include "../menu/menu_item.h" // for touch_screen_calibration
  27. #include "../../module/temperature.h"
  28. #include "../../module/planner.h"
  29. #if ENABLED(AUTO_BED_LEVELING_UBL)
  30. #include "../../feature/bedlevel/bedlevel.h"
  31. #endif
  32. #include "tft.h"
  33. bool Touch::enabled = true;
  34. int16_t Touch::x, Touch::y;
  35. touch_control_t Touch::controls[];
  36. touch_control_t *Touch::current_control;
  37. uint16_t Touch::controls_count;
  38. millis_t Touch::last_touch_ms = 0,
  39. Touch::time_to_hold,
  40. Touch::repeat_delay,
  41. Touch::touch_time;
  42. TouchControlType Touch::touch_control_type = NONE;
  43. #if HAS_TOUCH_SLEEP
  44. millis_t Touch::next_sleep_ms; // = 0
  45. #endif
  46. #if HAS_RESUME_CONTINUE
  47. extern bool wait_for_user;
  48. #endif
  49. void Touch::init() {
  50. TERN_(TOUCH_SCREEN_CALIBRATION, touch_calibration.calibration_reset());
  51. reset();
  52. io.Init();
  53. TERN_(HAS_TOUCH_SLEEP, wakeUp());
  54. enable();
  55. }
  56. void Touch::add_control(TouchControlType type, uint16_t x, uint16_t y, uint16_t width, uint16_t height, intptr_t data) {
  57. if (controls_count == MAX_CONTROLS) return;
  58. controls[controls_count].type = type;
  59. controls[controls_count].x = x;
  60. controls[controls_count].y = y;
  61. controls[controls_count].width = width;
  62. controls[controls_count].height = height;
  63. controls[controls_count].data = data;
  64. controls_count++;
  65. }
  66. void Touch::idle() {
  67. uint16_t i;
  68. int16_t _x, _y;
  69. if (!enabled) return;
  70. // Return if Touch::idle is called within the same millisecond
  71. const millis_t now = millis();
  72. if (last_touch_ms == now) return;
  73. last_touch_ms = now;
  74. if (get_point(&_x, &_y)) {
  75. #if HAS_RESUME_CONTINUE
  76. // UI is waiting for a click anywhere?
  77. if (wait_for_user) {
  78. touch_control_type = CLICK;
  79. ui.lcd_clicked = true;
  80. if (ui.external_control) wait_for_user = false;
  81. return;
  82. }
  83. #endif
  84. ui.reset_status_timeout(last_touch_ms);
  85. if (touch_time) {
  86. #if ENABLED(TOUCH_SCREEN_CALIBRATION)
  87. if (touch_control_type == NONE && ELAPSED(last_touch_ms, touch_time + TOUCH_SCREEN_HOLD_TO_CALIBRATE_MS) && ui.on_status_screen())
  88. ui.goto_screen(touch_screen_calibration);
  89. #endif
  90. return;
  91. }
  92. if (time_to_hold == 0) time_to_hold = last_touch_ms + MINIMUM_HOLD_TIME;
  93. if (PENDING(last_touch_ms, time_to_hold)) return;
  94. if (x != 0 && y != 0) {
  95. if (current_control) {
  96. if (WITHIN(x, current_control->x - FREE_MOVE_RANGE, current_control->x + current_control->width + FREE_MOVE_RANGE) && WITHIN(y, current_control->y - FREE_MOVE_RANGE, current_control->y + current_control->height + FREE_MOVE_RANGE)) {
  97. NOLESS(x, current_control->x);
  98. NOMORE(x, current_control->x + current_control->width);
  99. NOLESS(y, current_control->y);
  100. NOMORE(y, current_control->y + current_control->height);
  101. touch(current_control);
  102. }
  103. else
  104. current_control = nullptr;
  105. }
  106. else {
  107. for (i = 0; i < controls_count; i++) {
  108. if ((WITHIN(x, controls[i].x, controls[i].x + controls[i].width) && WITHIN(y, controls[i].y, controls[i].y + controls[i].height)) || (TERN(TOUCH_SCREEN_CALIBRATION, controls[i].type == CALIBRATE, false))) {
  109. touch_control_type = controls[i].type;
  110. touch(&controls[i]);
  111. break;
  112. }
  113. }
  114. }
  115. if (!current_control)
  116. touch_time = last_touch_ms;
  117. }
  118. x = _x;
  119. y = _y;
  120. }
  121. else {
  122. x = y = 0;
  123. current_control = nullptr;
  124. touch_time = 0;
  125. touch_control_type = NONE;
  126. time_to_hold = 0;
  127. repeat_delay = TOUCH_REPEAT_DELAY;
  128. }
  129. }
  130. void Touch::touch(touch_control_t *control) {
  131. switch (control->type) {
  132. #if ENABLED(TOUCH_SCREEN_CALIBRATION)
  133. case CALIBRATE:
  134. if (touch_calibration.handleTouch(x, y)) ui.refresh();
  135. break;
  136. #endif // TOUCH_SCREEN_CALIBRATION
  137. case MENU_SCREEN: ui.goto_screen((screenFunc_t)control->data); break;
  138. case BACK: ui.goto_previous_screen(); break;
  139. case MENU_CLICK:
  140. TERN_(SINGLE_TOUCH_NAVIGATION, ui.encoderPosition = control->data);
  141. ui.lcd_clicked = true;
  142. break;
  143. case CLICK: ui.lcd_clicked = true; break;
  144. #if HAS_RESUME_CONTINUE
  145. case RESUME_CONTINUE: extern bool wait_for_user; wait_for_user = false; break;
  146. #endif
  147. case CANCEL: ui.encoderPosition = 0; ui.selection = false; ui.lcd_clicked = true; break;
  148. case CONFIRM: ui.encoderPosition = 1; ui.selection = true; ui.lcd_clicked = true; break;
  149. case MENU_ITEM: ui.encoderPosition = control->data; ui.refresh(); break;
  150. case PAGE_UP:
  151. encoderTopLine = encoderTopLine > LCD_HEIGHT ? encoderTopLine - LCD_HEIGHT : 0;
  152. ui.encoderPosition = ui.encoderPosition > LCD_HEIGHT ? ui.encoderPosition - LCD_HEIGHT : 0;
  153. ui.refresh();
  154. break;
  155. case PAGE_DOWN:
  156. encoderTopLine = (encoderTopLine + 2 * LCD_HEIGHT < screen_items) ? encoderTopLine + LCD_HEIGHT : screen_items - LCD_HEIGHT;
  157. ui.encoderPosition = ui.encoderPosition + LCD_HEIGHT < (uint32_t)screen_items ? ui.encoderPosition + LCD_HEIGHT : screen_items;
  158. ui.refresh();
  159. break;
  160. case SLIDER: hold(control); ui.encoderPosition = (x - control->x) * control->data / control->width; break;
  161. case INCREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff++ : ui.encoderPosition++, ui.encoderPosition++); break;
  162. case DECREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff-- : ui.encoderPosition--, ui.encoderPosition--); break;
  163. case HEATER:
  164. int8_t heater;
  165. heater = control->data;
  166. ui.clear_lcd();
  167. #if HAS_HOTEND
  168. if (heater >= 0) { // HotEnd
  169. #if HOTENDS == 1
  170. MenuItem_int3::action(GET_TEXT_F(MSG_NOZZLE), &thermalManager.temp_hotend[0].target, 0, thermalManager.hotend_max_target(0), []{ thermalManager.start_watching_hotend(0); });
  171. #else
  172. MenuItemBase::itemIndex = heater;
  173. MenuItem_int3::action(GET_TEXT_F(MSG_NOZZLE_N), &thermalManager.temp_hotend[heater].target, 0, thermalManager.hotend_max_target(heater), []{ thermalManager.start_watching_hotend(MenuItemBase::itemIndex); });
  174. #endif
  175. }
  176. #endif
  177. #if HAS_HEATED_BED
  178. else if (heater == H_BED) {
  179. MenuItem_int3::action(GET_TEXT_F(MSG_BED), &thermalManager.temp_bed.target, 0, BED_MAX_TARGET, thermalManager.start_watching_bed);
  180. }
  181. #endif
  182. #if HAS_HEATED_CHAMBER
  183. else if (heater == H_CHAMBER) {
  184. MenuItem_int3::action(GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAX_TARGET, thermalManager.start_watching_chamber);
  185. }
  186. #endif
  187. #if HAS_COOLER
  188. else if (heater == H_COOLER) {
  189. MenuItem_int3::action(GET_TEXT_F(MSG_COOLER), &thermalManager.temp_cooler.target, 0, COOLER_MAX_TARGET, thermalManager.start_watching_cooler);
  190. }
  191. #endif
  192. break;
  193. case FAN:
  194. ui.clear_lcd();
  195. static uint8_t fan, fan_speed;
  196. fan = 0;
  197. fan_speed = thermalManager.fan_speed[fan];
  198. MenuItem_percent::action(GET_TEXT_F(MSG_FIRST_FAN_SPEED), &fan_speed, 0, 255, []{ thermalManager.set_fan_speed(fan, fan_speed); });
  199. break;
  200. case FEEDRATE:
  201. ui.clear_lcd();
  202. MenuItem_int3::action(GET_TEXT_F(MSG_SPEED), &feedrate_percentage, 10, 999);
  203. break;
  204. case FLOWRATE:
  205. ui.clear_lcd();
  206. MenuItemBase::itemIndex = control->data;
  207. #if EXTRUDERS == 1
  208. MenuItem_int3::action(GET_TEXT_F(MSG_FLOW), &planner.flow_percentage[MenuItemBase::itemIndex], 10, 999, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); });
  209. #else
  210. MenuItem_int3::action(GET_TEXT_F(MSG_FLOW_N), &planner.flow_percentage[MenuItemBase::itemIndex], 10, 999, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); });
  211. #endif
  212. break;
  213. #if ENABLED(AUTO_BED_LEVELING_UBL)
  214. case UBL: hold(control, UBL_REPEAT_DELAY); ui.encoderPosition += control->data; break;
  215. #endif
  216. case MOVE_AXIS:
  217. ui.goto_screen((screenFunc_t)ui.move_axis_screen);
  218. break;
  219. // TODO: TOUCH could receive data to pass to the callback
  220. case BUTTON: ((screenFunc_t)control->data)(); break;
  221. default: break;
  222. }
  223. }
  224. void Touch::hold(touch_control_t *control, millis_t delay) {
  225. current_control = control;
  226. if (delay) {
  227. repeat_delay = delay > MIN_REPEAT_DELAY ? delay : MIN_REPEAT_DELAY;
  228. time_to_hold = last_touch_ms + repeat_delay;
  229. }
  230. ui.refresh();
  231. }
  232. bool Touch::get_point(int16_t *x, int16_t *y) {
  233. #if ENABLED(TFT_TOUCH_DEVICE_XPT2046)
  234. #if ENABLED(TOUCH_SCREEN_CALIBRATION)
  235. bool is_touched = (touch_calibration.calibration.orientation == TOUCH_PORTRAIT ? io.getRawPoint(y, x) : io.getRawPoint(x, y));
  236. if (is_touched && touch_calibration.calibration.orientation != TOUCH_ORIENTATION_NONE) {
  237. *x = int16_t((int32_t(*x) * touch_calibration.calibration.x) >> 16) + touch_calibration.calibration.offset_x;
  238. *y = int16_t((int32_t(*y) * touch_calibration.calibration.y) >> 16) + touch_calibration.calibration.offset_y;
  239. }
  240. #else
  241. bool is_touched = (TOUCH_ORIENTATION == TOUCH_PORTRAIT ? io.getRawPoint(y, x) : io.getRawPoint(x, y));
  242. *x = uint16_t((uint32_t(*x) * TOUCH_CALIBRATION_X) >> 16) + TOUCH_OFFSET_X;
  243. *y = uint16_t((uint32_t(*y) * TOUCH_CALIBRATION_Y) >> 16) + TOUCH_OFFSET_Y;
  244. #endif
  245. #elif ENABLED(TFT_TOUCH_DEVICE_GT911)
  246. bool is_touched = (TOUCH_ORIENTATION == TOUCH_PORTRAIT ? io.getPoint(y, x) : io.getPoint(x, y));
  247. #endif
  248. #if HAS_TOUCH_SLEEP
  249. if (is_touched)
  250. wakeUp();
  251. else if (!isSleeping() && ELAPSED(millis(), next_sleep_ms) && ui.on_status_screen())
  252. sleepTimeout();
  253. #endif
  254. return is_touched;
  255. }
  256. #if HAS_TOUCH_SLEEP
  257. void Touch::sleepTimeout() {
  258. #if HAS_LCD_BRIGHTNESS
  259. ui.set_brightness(0);
  260. #elif PIN_EXISTS(TFT_BACKLIGHT)
  261. WRITE(TFT_BACKLIGHT_PIN, LOW);
  262. #endif
  263. next_sleep_ms = TSLP_SLEEPING;
  264. }
  265. void Touch::wakeUp() {
  266. if (isSleeping()) {
  267. #if HAS_LCD_BRIGHTNESS
  268. ui.set_brightness(ui.brightness);
  269. #elif PIN_EXISTS(TFT_BACKLIGHT)
  270. WRITE(TFT_BACKLIGHT_PIN, HIGH);
  271. #endif
  272. }
  273. next_sleep_ms = millis() + SEC_TO_MS(ui.sleep_timeout_minutes * 60);
  274. }
  275. #endif // HAS_TOUCH_SLEEP
  276. Touch touch;
  277. bool MarlinUI::touch_pressed() {
  278. return touch.is_clicked();
  279. }
  280. void add_control(uint16_t x, uint16_t y, TouchControlType control_type, intptr_t data, MarlinImage image, bool is_enabled, uint16_t color_enabled, uint16_t color_disabled) {
  281. uint16_t width = Images[image].width;
  282. uint16_t height = Images[image].height;
  283. tft.canvas(x, y, width, height);
  284. tft.add_image(0, 0, image, is_enabled ? color_enabled : color_disabled);
  285. if (is_enabled)
  286. touch.add_control(control_type, x, y, width, height, data);
  287. }
  288. #endif // TOUCH_SCREEN