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

touch.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. *
  18. */
  19. #include "../../inc/MarlinConfig.h"
  20. #if ENABLED(TOUCH_SCREEN)
  21. #include "touch.h"
  22. #include "../ultralcd.h" // for ui methods
  23. #include "../menu/menu_item.h" // for touch_screen_calibration
  24. #include "../../module/temperature.h"
  25. #include "../../module/planner.h"
  26. #if ENABLED(AUTO_BED_LEVELING_UBL)
  27. #include "../../feature/bedlevel/bedlevel.h"
  28. #endif
  29. #include "tft.h"
  30. bool Touch::enabled = true;
  31. int16_t Touch::x, Touch::y;
  32. touch_control_t Touch::controls[];
  33. touch_control_t *Touch::current_control;
  34. uint16_t Touch::controls_count;
  35. millis_t Touch::now = 0;
  36. millis_t Touch::time_to_hold;
  37. millis_t Touch::repeat_delay;
  38. millis_t Touch::touch_time;
  39. TouchControlType Touch::touch_control_type = NONE;
  40. touch_calibration_t Touch::calibration;
  41. #if ENABLED(TOUCH_SCREEN_CALIBRATION)
  42. calibrationState Touch::calibration_state = CALIBRATION_NONE;
  43. touch_calibration_point_t Touch::calibration_points[4];
  44. #endif
  45. void Touch::init() {
  46. calibration_reset();
  47. reset();
  48. io.Init();
  49. enable();
  50. }
  51. void Touch::add_control(TouchControlType type, uint16_t x, uint16_t y, uint16_t width, uint16_t height, int32_t data) {
  52. if (controls_count == MAX_CONTROLS) return;
  53. controls[controls_count].type = type;
  54. controls[controls_count].x = x;
  55. controls[controls_count].y = y;
  56. controls[controls_count].width = width;
  57. controls[controls_count].height = height;
  58. controls[controls_count].data = data;
  59. controls_count++;
  60. }
  61. void Touch::idle() {
  62. uint16_t i;
  63. int16_t _x, _y;
  64. if (!enabled) return;
  65. if (now == millis()) return;
  66. now = millis();
  67. if (get_point(&_x, &_y)) {
  68. #if LCD_TIMEOUT_TO_STATUS
  69. ui.return_to_status_ms = now + LCD_TIMEOUT_TO_STATUS;
  70. #endif
  71. if (touch_time) {
  72. #if ENABLED(TOUCH_SCREEN_CALIBRATION)
  73. if (touch_control_type == NONE && ELAPSED(now, touch_time + TOUCH_SCREEN_HOLD_TO_CALIBRATE_MS) && ui.on_status_screen())
  74. ui.goto_screen(touch_screen_calibration);
  75. #endif
  76. return;
  77. }
  78. if (time_to_hold == 0) time_to_hold = now + MINIMUM_HOLD_TIME;
  79. if (PENDING(now, time_to_hold)) return;
  80. if (x != 0 && y != 0) {
  81. if (current_control) {
  82. 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)) {
  83. NOLESS(x, current_control->x);
  84. NOMORE(x, current_control->x + current_control->width);
  85. NOLESS(y, current_control->y);
  86. NOMORE(y, current_control->y + current_control->height);
  87. touch(current_control);
  88. }
  89. else {
  90. current_control = NULL;
  91. }
  92. }
  93. else {
  94. for (i = 0; i < controls_count; i++) {
  95. 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))) {
  96. touch_control_type = controls[i].type;
  97. touch(&controls[i]);
  98. break;
  99. }
  100. }
  101. }
  102. if (current_control == NULL)
  103. touch_time = now;
  104. }
  105. x = _x;
  106. y = _y;
  107. }
  108. else {
  109. x = y = 0;
  110. current_control = NULL;
  111. touch_time = 0;
  112. touch_control_type = NONE;
  113. time_to_hold = 0;
  114. repeat_delay = TOUCH_REPEAT_DELAY;
  115. }
  116. }
  117. void Touch::touch(touch_control_t *control) {
  118. switch (control->type) {
  119. #if ENABLED(TOUCH_SCREEN_CALIBRATION)
  120. case CALIBRATE:
  121. ui.refresh();
  122. if (calibration_state < CALIBRATION_SUCCESS) {
  123. calibration_points[calibration_state].x = int16_t(control->data >> 16);
  124. calibration_points[calibration_state].y = int16_t(control->data & 0xFFFF);
  125. calibration_points[calibration_state].raw_x = x;
  126. calibration_points[calibration_state].raw_y = y;
  127. }
  128. switch (calibration_state) {
  129. case CALIBRATION_POINT_1: calibration_state = CALIBRATION_POINT_2; break;
  130. case CALIBRATION_POINT_2: calibration_state = CALIBRATION_POINT_3; break;
  131. case CALIBRATION_POINT_3: calibration_state = CALIBRATION_POINT_4; break;
  132. case CALIBRATION_POINT_4:
  133. if (validate_precision_x(0, 1) && validate_precision_x(2, 3) && validate_precision_y(0, 2) && validate_precision_y(1, 3)) {
  134. calibration_state = CALIBRATION_SUCCESS;
  135. calibration.x = ((calibration_points[2].x - calibration_points[0].x) << 17) / (calibration_points[3].raw_x + calibration_points[2].raw_x - calibration_points[1].raw_x - calibration_points[0].raw_x);
  136. calibration.y = ((calibration_points[1].y - calibration_points[0].y) << 17) / (calibration_points[3].raw_y - calibration_points[2].raw_y + calibration_points[1].raw_y - calibration_points[0].raw_y);
  137. calibration.offset_x = calibration_points[0].x - int16_t(((calibration_points[0].raw_x + calibration_points[1].raw_x) * calibration.x) >> 17);
  138. calibration.offset_y = calibration_points[0].y - int16_t(((calibration_points[0].raw_y + calibration_points[2].raw_y) * calibration.y) >> 17);
  139. calibration.orientation = TOUCH_LANDSCAPE;
  140. }
  141. else if (validate_precision_y(0, 1) && validate_precision_y(2, 3) && validate_precision_x(0, 2) && validate_precision_x(1, 3)) {
  142. calibration_state = CALIBRATION_SUCCESS;
  143. calibration.x = ((calibration_points[2].x - calibration_points[0].x) << 17) / (calibration_points[3].raw_y + calibration_points[2].raw_y - calibration_points[1].raw_y - calibration_points[0].raw_y);
  144. calibration.y = ((calibration_points[1].y - calibration_points[0].y) << 17) / (calibration_points[3].raw_x - calibration_points[2].raw_x + calibration_points[1].raw_x - calibration_points[0].raw_x);
  145. calibration.offset_x = calibration_points[0].x - int16_t(((calibration_points[0].raw_y + calibration_points[1].raw_y) * calibration.x) >> 17);
  146. calibration.offset_y = calibration_points[0].y - int16_t(((calibration_points[0].raw_x + calibration_points[2].raw_x) * calibration.y) >> 17);
  147. calibration.orientation = TOUCH_PORTRAIT;
  148. }
  149. else {
  150. calibration_state = CALIBRATION_FAIL;
  151. calibration_reset();
  152. }
  153. if (calibration_state == CALIBRATION_SUCCESS) {
  154. SERIAL_ECHOLN("Touch screen calibration completed");
  155. SERIAL_ECHOLNPAIR("TOUCH_CALIBRATION_X ", calibration.x);
  156. SERIAL_ECHOLNPAIR("TOUCH_CALIBRATION_Y ", calibration.y);
  157. SERIAL_ECHOLNPAIR("TOUCH_OFFSET_X ", calibration.offset_x);
  158. SERIAL_ECHOLNPAIR("TOUCH_OFFSET_Y ", calibration.offset_y);
  159. SERIAL_ECHO("TOUCH_ORIENTATION "); if (calibration.orientation == TOUCH_LANDSCAPE) SERIAL_ECHOLN("TOUCH_LANDSCAPE"); else SERIAL_ECHOLN("TOUCH_PORTRAIT");
  160. }
  161. break;
  162. default: break;
  163. }
  164. break;
  165. #endif // TOUCH_SCREEN_CALIBRATION
  166. case MENU_SCREEN: ui.goto_screen((screenFunc_t)control->data); break;
  167. case BACK: ui.goto_previous_screen(); break;
  168. case CLICK: ui.lcd_clicked = true; break;
  169. #if HAS_RESUME_CONTINUE
  170. case RESUME_CONTINUE: extern bool wait_for_user; wait_for_user = false; break;
  171. #endif
  172. case CANCEL: ui.encoderPosition = 0; ui.selection = false; ui.lcd_clicked = true; break;
  173. case CONFIRM: ui.encoderPosition = 1; ui.selection = true; ui.lcd_clicked = true; break;
  174. case MENU_ITEM: ui.encoderPosition = control->data; ui.refresh(); break;
  175. case PAGE_UP:
  176. encoderTopLine = encoderTopLine > LCD_HEIGHT ? encoderTopLine - LCD_HEIGHT : 0;
  177. ui.encoderPosition = ui.encoderPosition > LCD_HEIGHT ? ui.encoderPosition - LCD_HEIGHT : 0;
  178. ui.refresh();
  179. break;
  180. case PAGE_DOWN:
  181. encoderTopLine = encoderTopLine + 2 * LCD_HEIGHT < screen_items ? encoderTopLine + LCD_HEIGHT : screen_items - LCD_HEIGHT;
  182. ui.encoderPosition = ui.encoderPosition + LCD_HEIGHT < (uint32_t)screen_items ? ui.encoderPosition + LCD_HEIGHT : screen_items;
  183. ui.refresh();
  184. break;
  185. case SLIDER: hold(control); ui.encoderPosition = (x - control->x) * control->data / control->width; break;
  186. case INCREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? ubl.encoder_diff++ : ui.encoderPosition++, ui.encoderPosition++); break;
  187. case DECREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? ubl.encoder_diff-- : ui.encoderPosition--, ui.encoderPosition--); break;
  188. case HEATER:
  189. int8_t heater;
  190. heater = control->data;
  191. ui.clear_lcd();
  192. if (heater >= 0) { // HotEnd
  193. #if HOTENDS == 1
  194. MenuItem_int3::action((const char *)GET_TEXT_F(MSG_NOZZLE), &thermalManager.temp_hotend[0].target, 0, thermalManager.heater_maxtemp[0] - 15, []{ thermalManager.start_watching_hotend(0); });
  195. #else
  196. MenuItemBase::itemIndex = heater;
  197. MenuItem_int3::action((const char *)GET_TEXT_F(MSG_NOZZLE_N), &thermalManager.temp_hotend[heater].target, 0, thermalManager.heater_maxtemp[heater] - 15, []{ thermalManager.start_watching_hotend(MenuItemBase::itemIndex); });
  198. #endif
  199. }
  200. #if HAS_HEATED_BED
  201. else if (heater == H_BED) {
  202. MenuItem_int3::action((const char *)GET_TEXT_F(MSG_BED), &thermalManager.temp_bed.target, 0, BED_MAXTEMP - 10, thermalManager.start_watching_bed);
  203. }
  204. #endif
  205. #if HAS_HEATED_CHAMBER
  206. else if (heater == H_CHAMBER) {
  207. MenuItem_int3::action((const char *)GET_TEXT_F(MSG_CHAMBER), &thermalManager.temp_chamber.target, 0, CHAMBER_MAXTEMP - 10, thermalManager.start_watching_chamber);
  208. }
  209. #endif
  210. break;
  211. case FAN:
  212. ui.clear_lcd();
  213. static uint8_t fan, fan_speed;
  214. fan = 0;
  215. fan_speed = thermalManager.fan_speed[fan];
  216. MenuItem_percent::action((const char *)GET_TEXT_F(MSG_FIRST_FAN_SPEED), &fan_speed, 0, 255, []{ thermalManager.set_fan_speed(fan, fan_speed); });
  217. break;
  218. case FEEDRATE:
  219. ui.clear_lcd();
  220. MenuItem_int3::action((const char *)GET_TEXT_F(MSG_SPEED), &feedrate_percentage, 10, 999);
  221. break;
  222. case FLOWRATE:
  223. ui.clear_lcd();
  224. MenuItemBase::itemIndex = control->data;
  225. #if EXTRUDERS == 1
  226. MenuItem_int3::action((const char *)GET_TEXT_F(MSG_FLOW), &planner.flow_percentage[MenuItemBase::itemIndex], 10, 999, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); });
  227. #else
  228. MenuItem_int3::action((const char *)GET_TEXT_F(MSG_FLOW_N), &planner.flow_percentage[MenuItemBase::itemIndex], 10, 999, []{ planner.refresh_e_factor(MenuItemBase::itemIndex); });
  229. #endif
  230. break;
  231. #if ENABLED(AUTO_BED_LEVELING_UBL)
  232. case UBL: hold(control, UBL_REPEAT_DELAY); ui.encoderPosition += control->data; break;
  233. #endif
  234. case MOVE_AXIS:
  235. ui.goto_screen((screenFunc_t)ui.move_axis_screen);
  236. break;
  237. // TODO: TOUCH could receive data to pass to the callback
  238. case BUTTON: ((screenFunc_t)control->data)(); break;
  239. default: break;
  240. }
  241. }
  242. void Touch::hold(touch_control_t *control, millis_t delay) {
  243. current_control = control;
  244. if (delay) {
  245. repeat_delay = delay > MIN_REPEAT_DELAY ? delay : MIN_REPEAT_DELAY;
  246. time_to_hold = now + repeat_delay;
  247. }
  248. ui.refresh();
  249. }
  250. bool Touch::get_point(int16_t *x, int16_t *y) {
  251. bool is_touched = (calibration.orientation == TOUCH_PORTRAIT ? io.getRawPoint(y, x) : io.getRawPoint(x, y));
  252. if (is_touched && calibration.orientation != TOUCH_ORIENTATION_NONE) {
  253. *x = int16_t((int32_t(*x) * calibration.x) >> 16) + calibration.offset_x;
  254. *y = int16_t((int32_t(*y) * calibration.y) >> 16) + calibration.offset_y;
  255. #if (TFT_ROTATION & TFT_ROTATE_180)
  256. *x = TFT_WIDTH - *x;
  257. *y = TFT_HEIGHT - *y;
  258. #endif
  259. }
  260. return is_touched;
  261. }
  262. Touch touch;
  263. bool MarlinUI::touch_pressed() {
  264. return touch.is_clicked();
  265. }
  266. void add_control(uint16_t x, uint16_t y, TouchControlType control_type, int32_t data, MarlinImage image, bool is_enabled, uint16_t color_enabled, uint16_t color_disabled) {
  267. uint16_t width = Images[image].width;
  268. uint16_t height = Images[image].height;
  269. tft.canvas(x, y, width, height);
  270. tft.add_image(0, 0, image, is_enabled ? color_enabled : color_disabled);
  271. if (is_enabled)
  272. touch.add_control(control_type, x, y, width, height, data);
  273. }
  274. #endif // TOUCH_SCREEN