|
@@ -26,6 +26,7 @@
|
26
|
26
|
#include "language.h"
|
27
|
27
|
#include "cardreader.h"
|
28
|
28
|
#include "temperature.h"
|
|
29
|
+#include "planner.h"
|
29
|
30
|
#include "stepper.h"
|
30
|
31
|
#include "configuration_store.h"
|
31
|
32
|
#include "utility.h"
|
|
@@ -43,6 +44,11 @@
|
43
|
44
|
#include "endstops.h"
|
44
|
45
|
#endif
|
45
|
46
|
|
|
47
|
+#if ENABLED(AUTO_BED_LEVELING_UBL)
|
|
48
|
+ #include "ubl.h"
|
|
49
|
+ bool ubl_lcd_map_control = false;
|
|
50
|
+#endif
|
|
51
|
+
|
46
|
52
|
int lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2], lcd_preheat_fan_speed[2];
|
47
|
53
|
|
48
|
54
|
#if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT)
|
|
@@ -102,9 +108,6 @@ uint16_t max_display_update_time = 0;
|
102
|
108
|
extern bool powersupply_on;
|
103
|
109
|
#endif
|
104
|
110
|
|
105
|
|
- #if ENABLED(AUTO_BED_LEVELING_UBL)
|
106
|
|
- #include "ubl.h"
|
107
|
|
- #endif
|
108
|
111
|
|
109
|
112
|
////////////////////////////////////////////
|
110
|
113
|
///////////////// Menu Tree ////////////////
|
|
@@ -1044,6 +1047,7 @@ void kill_screen(const char* lcd_msg) {
|
1044
|
1047
|
|
1045
|
1048
|
float lcd_mesh_edit() {
|
1046
|
1049
|
lcd_goto_screen(_lcd_mesh_edit_NOP);
|
|
1050
|
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
|
1047
|
1051
|
_lcd_mesh_fine_tune(PSTR("Mesh Editor"));
|
1048
|
1052
|
return mesh_edit_value;
|
1049
|
1053
|
}
|
|
@@ -1795,8 +1799,10 @@ void kill_screen(const char* lcd_msg) {
|
1795
|
1799
|
custom_hotend_temp = 190,
|
1796
|
1800
|
side_points = 3,
|
1797
|
1801
|
ubl_fillin_amount = 5,
|
1798
|
|
- ubl_height_amount,
|
1799
|
|
- map_type;
|
|
1802
|
+ ubl_height_amount = 1,
|
|
1803
|
+ n_edit_pts = 1,
|
|
1804
|
+ x_plot = 0,
|
|
1805
|
+ y_plot = 0;
|
1800
|
1806
|
|
1801
|
1807
|
/**
|
1802
|
1808
|
* UBL Build Custom Mesh Command
|
|
@@ -1856,8 +1862,7 @@ void kill_screen(const char* lcd_msg) {
|
1856
|
1862
|
void _lcd_ubl_edit_mesh() {
|
1857
|
1863
|
START_MENU();
|
1858
|
1864
|
MENU_BACK(MSG_UBL_TOOLS);
|
1859
|
|
- MENU_BACK(MSG_UBL_LEVEL_BED);
|
1860
|
|
- MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R T"));
|
|
1865
|
+ MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T"));
|
1861
|
1866
|
MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_CLOSEST, PSTR("G29 P4 T"));
|
1862
|
1867
|
MENU_ITEM(submenu, MSG_UBL_MESH_HEIGHT_ADJUST, _lcd_ubl_height_adjust_menu);
|
1863
|
1868
|
MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
|
|
@@ -1944,7 +1949,7 @@ void kill_screen(const char* lcd_msg) {
|
1944
|
1949
|
*/
|
1945
|
1950
|
void _lcd_ubl_smart_fillin_cmd() {
|
1946
|
1951
|
char UBL_LCD_GCODE[12];
|
1947
|
|
- sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 T%i"), map_type);
|
|
1952
|
+ sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 T0"));
|
1948
|
1953
|
enqueue_and_echo_command(UBL_LCD_GCODE);
|
1949
|
1954
|
}
|
1950
|
1955
|
|
|
@@ -2045,12 +2050,219 @@ void kill_screen(const char* lcd_msg) {
|
2045
|
2050
|
}
|
2046
|
2051
|
|
2047
|
2052
|
/**
|
2048
|
|
- * UBL Output map Command
|
|
2053
|
+ * UBL LCD "radar" map homing
|
2049
|
2054
|
*/
|
2050
|
|
- void _lcd_ubl_output_map_cmd() {
|
2051
|
|
- char UBL_LCD_GCODE[10];
|
2052
|
|
- sprintf_P(UBL_LCD_GCODE, PSTR("G29 T%i"), map_type);
|
2053
|
|
- enqueue_and_echo_command(UBL_LCD_GCODE);
|
|
2055
|
+ void _lcd_ubl_output_map_lcd();
|
|
2056
|
+
|
|
2057
|
+ void _lcd_ubl_map_homing() {
|
|
2058
|
+ if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_HOMING), NULL);
|
|
2059
|
+ lcdDrawUpdate = LCDVIEW_CALL_NO_REDRAW;
|
|
2060
|
+ if (axis_homed[X_AXIS] && axis_homed[Y_AXIS] && axis_homed[Z_AXIS])
|
|
2061
|
+ lcd_goto_screen(_lcd_ubl_output_map_lcd);
|
|
2062
|
+ }
|
|
2063
|
+
|
|
2064
|
+ /**
|
|
2065
|
+ * UBL LCD "radar" map point editing
|
|
2066
|
+ */
|
|
2067
|
+ void _lcd_ubl_map_lcd_edit_cmd() {
|
|
2068
|
+ char ubl_lcd_gcode [50], str[10], str2[10];
|
|
2069
|
+
|
|
2070
|
+ ubl_lcd_map_control = true; // Used for returning to the map screen
|
|
2071
|
+
|
|
2072
|
+ dtostrf(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]), 0, 2, str);
|
|
2073
|
+ dtostrf(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]), 0, 2, str2);
|
|
2074
|
+ snprintf_P(ubl_lcd_gcode, sizeof(ubl_lcd_gcode), PSTR("G29 P4 X%s Y%s R%i"), str, str2, n_edit_pts);
|
|
2075
|
+ enqueue_and_echo_command(ubl_lcd_gcode);
|
|
2076
|
+ }
|
|
2077
|
+
|
|
2078
|
+ #ifdef DOGLCD
|
|
2079
|
+
|
|
2080
|
+ /**
|
|
2081
|
+ * UBL LCD "radar" map data
|
|
2082
|
+ */
|
|
2083
|
+ #define MAP_UPPER_LEFT_CORNER_X 35 // These probably should be moved to the .h file But for now,
|
|
2084
|
+ #define MAP_UPPER_LEFT_CORNER_Y 8 // it is easier to play with things having them here
|
|
2085
|
+ #define MAP_MAX_PIXELS_X 53
|
|
2086
|
+ #define MAP_MAX_PIXELS_Y 49
|
|
2087
|
+
|
|
2088
|
+ void _lcd_ubl_plot_drawing_prep() {
|
|
2089
|
+ uint8_t i, j, x_offset, y_offset, x_map_pixels, y_map_pixels;
|
|
2090
|
+ uint8_t pixels_per_X_mesh_pnt, pixels_per_Y_mesh_pnt, inverted_y;
|
|
2091
|
+
|
|
2092
|
+ /*********************************************************/
|
|
2093
|
+ /************ Scale the box pixels appropriately *********/
|
|
2094
|
+ /*********************************************************/
|
|
2095
|
+ x_map_pixels = ((MAP_MAX_PIXELS_X - 4) / GRID_MAX_POINTS_X) * GRID_MAX_POINTS_X;
|
|
2096
|
+ y_map_pixels = ((MAP_MAX_PIXELS_Y - 4) / GRID_MAX_POINTS_Y) * GRID_MAX_POINTS_Y;
|
|
2097
|
+
|
|
2098
|
+ pixels_per_X_mesh_pnt = x_map_pixels / GRID_MAX_POINTS_X;
|
|
2099
|
+ pixels_per_Y_mesh_pnt = y_map_pixels / GRID_MAX_POINTS_Y;
|
|
2100
|
+
|
|
2101
|
+ x_offset = MAP_UPPER_LEFT_CORNER_X + 1 + (MAP_MAX_PIXELS_X-x_map_pixels-2)/2;
|
|
2102
|
+ y_offset = MAP_UPPER_LEFT_CORNER_Y + 1 + (MAP_MAX_PIXELS_Y-y_map_pixels-2)/2;
|
|
2103
|
+
|
|
2104
|
+ /*********************************************************/
|
|
2105
|
+ /************ Clear the Mesh Map Box**********************/
|
|
2106
|
+ /*********************************************************/
|
|
2107
|
+
|
|
2108
|
+ u8g.setColorIndex(1); // First draw the bigger box in White so we have a border around the mesh map box
|
|
2109
|
+ u8g.drawBox(x_offset-2, y_offset-2, x_map_pixels+4, y_map_pixels+4);
|
|
2110
|
+
|
|
2111
|
+ u8g.setColorIndex(0); // Now actually clear the mesh map box
|
|
2112
|
+ u8g.drawBox(x_offset, y_offset, x_map_pixels, y_map_pixels);
|
|
2113
|
+
|
|
2114
|
+ /*********************************************************/
|
|
2115
|
+ /************ Display Mesh Point Locations ***************/
|
|
2116
|
+ /*********************************************************/
|
|
2117
|
+
|
|
2118
|
+ u8g.setColorIndex(1);
|
|
2119
|
+ for (i = 0; i < GRID_MAX_POINTS_X; i++) {
|
|
2120
|
+ for (j = 0; j < GRID_MAX_POINTS_Y; j++) {
|
|
2121
|
+ u8g.drawBox(x_offset+i*pixels_per_X_mesh_pnt+pixels_per_X_mesh_pnt/2,
|
|
2122
|
+ y_offset+j*pixels_per_Y_mesh_pnt+pixels_per_Y_mesh_pnt/2, 1, 1);
|
|
2123
|
+ }
|
|
2124
|
+ }
|
|
2125
|
+
|
|
2126
|
+ /*********************************************************/
|
|
2127
|
+ /************ Fill in the Specified Mesh Point ***********/
|
|
2128
|
+ /*********************************************************/
|
|
2129
|
+
|
|
2130
|
+ inverted_y = GRID_MAX_POINTS_Y - y_plot - 1; // The origin is typically in the lower right corner. We need to
|
|
2131
|
+ // invert the Y to get it to plot in the right location.
|
|
2132
|
+ u8g.drawBox(x_offset+x_plot*pixels_per_X_mesh_pnt, y_offset+inverted_y*pixels_per_Y_mesh_pnt,
|
|
2133
|
+ pixels_per_X_mesh_pnt, pixels_per_Y_mesh_pnt);
|
|
2134
|
+
|
|
2135
|
+ /*********************************************************/
|
|
2136
|
+ /************** Put Relevent Text on Display *************/
|
|
2137
|
+ /*********************************************************/
|
|
2138
|
+
|
|
2139
|
+ // Show X and Y positions at top of screen
|
|
2140
|
+ u8g.setColorIndex(1);
|
|
2141
|
+ u8g.setPrintPos(5, 7);
|
|
2142
|
+ lcd_print("X:");
|
|
2143
|
+ lcd_print(ftostr32(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]))));
|
|
2144
|
+ u8g.setPrintPos(74, 7);
|
|
2145
|
+ lcd_print("Y:");
|
|
2146
|
+ lcd_print(ftostr32(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]))));
|
|
2147
|
+
|
|
2148
|
+ // Print plot position
|
|
2149
|
+ u8g.setPrintPos(5, 64);
|
|
2150
|
+ lcd_print("(");
|
|
2151
|
+ u8g.print(x_plot);
|
|
2152
|
+ lcd_print(",");
|
|
2153
|
+ u8g.print(y_plot);
|
|
2154
|
+ lcd_print(")");
|
|
2155
|
+
|
|
2156
|
+ // Show the location value
|
|
2157
|
+ u8g.setPrintPos(74, 64);
|
|
2158
|
+ lcd_print("Z:");
|
|
2159
|
+ if (!isnan(ubl.z_values[x_plot][y_plot])) {
|
|
2160
|
+ lcd_print(ftostr43sign(ubl.z_values[x_plot][y_plot]));
|
|
2161
|
+ }
|
|
2162
|
+ else {
|
|
2163
|
+ lcd_print(" -----");
|
|
2164
|
+ }
|
|
2165
|
+ }
|
|
2166
|
+
|
|
2167
|
+ #endif // DOGLCD
|
|
2168
|
+
|
|
2169
|
+ /**
|
|
2170
|
+ * UBL LCD Map Movement
|
|
2171
|
+ */
|
|
2172
|
+ void ubl_map_move_to_xy() {
|
|
2173
|
+ current_position[X_AXIS] = LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]));
|
|
2174
|
+ current_position[Y_AXIS] = LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]));
|
|
2175
|
+ planner.buffer_line_kinematic(current_position, MMM_TO_MMS(XY_PROBE_SPEED), active_extruder);
|
|
2176
|
+ }
|
|
2177
|
+
|
|
2178
|
+ /**
|
|
2179
|
+ * UBL LCD "radar" map
|
|
2180
|
+ */
|
|
2181
|
+ void set_current_from_steppers_for_axis(const AxisEnum axis);
|
|
2182
|
+ void sync_plan_position();
|
|
2183
|
+
|
|
2184
|
+ void _lcd_ubl_output_map_lcd() {
|
|
2185
|
+ static int step_scaler=0;
|
|
2186
|
+ int32_t signed_enc_pos;
|
|
2187
|
+
|
|
2188
|
+ defer_return_to_status = true;
|
|
2189
|
+
|
|
2190
|
+ if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS]) {
|
|
2191
|
+
|
|
2192
|
+ if (lcd_clicked) { return _lcd_ubl_map_lcd_edit_cmd(); }
|
|
2193
|
+ ENCODER_DIRECTION_NORMAL();
|
|
2194
|
+
|
|
2195
|
+ if (encoderPosition != 0) {
|
|
2196
|
+ signed_enc_pos = (int32_t)encoderPosition;
|
|
2197
|
+ step_scaler += signed_enc_pos;
|
|
2198
|
+ x_plot = (x_plot + step_scaler / ENCODER_STEPS_PER_MENU_ITEM);
|
|
2199
|
+
|
|
2200
|
+ if (abs(step_scaler) >= ENCODER_STEPS_PER_MENU_ITEM)
|
|
2201
|
+ step_scaler = 0;
|
|
2202
|
+ refresh_cmd_timeout();
|
|
2203
|
+
|
|
2204
|
+ lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
|
|
2205
|
+ }
|
|
2206
|
+
|
|
2207
|
+ encoderPosition = 0;
|
|
2208
|
+
|
|
2209
|
+ // Encoder to the right (++)
|
|
2210
|
+ if (x_plot >= GRID_MAX_POINTS_X) { x_plot = 0; y_plot++; }
|
|
2211
|
+ if (y_plot >= GRID_MAX_POINTS_Y) y_plot = 0;
|
|
2212
|
+
|
|
2213
|
+ // Encoder to the left (--)
|
|
2214
|
+ if (x_plot <= GRID_MAX_POINTS_X - (GRID_MAX_POINTS_X + 1)) { x_plot = GRID_MAX_POINTS_X - 1; y_plot--; }
|
|
2215
|
+ if (y_plot <= GRID_MAX_POINTS_Y - (GRID_MAX_POINTS_Y + 1)) y_plot = GRID_MAX_POINTS_Y - 1;
|
|
2216
|
+
|
|
2217
|
+ // Prevent underrun/overrun of plot numbers
|
|
2218
|
+ x_plot = constrain(x_plot, GRID_MAX_POINTS_X - (GRID_MAX_POINTS_X + 1), GRID_MAX_POINTS_X + 1);
|
|
2219
|
+ y_plot = constrain(y_plot, GRID_MAX_POINTS_Y - (GRID_MAX_POINTS_Y + 1), GRID_MAX_POINTS_Y + 1);
|
|
2220
|
+
|
|
2221
|
+ // Determine number of points to edit
|
|
2222
|
+ #if IS_KINEMATIC
|
|
2223
|
+ n_edit_pts = 9; //TODO: Delta accessible edit points
|
|
2224
|
+ #else
|
|
2225
|
+ if (x_plot < 1 || x_plot >= GRID_MAX_POINTS_X - 1)
|
|
2226
|
+ if (y_plot < 1 || y_plot >= GRID_MAX_POINTS_Y - 1) n_edit_pts = 4; // Corners
|
|
2227
|
+ else n_edit_pts = 6;
|
|
2228
|
+ else if (y_plot < 1 || y_plot >= GRID_MAX_POINTS_Y - 1) n_edit_pts = 6; // Edges
|
|
2229
|
+ else n_edit_pts = 9; // Field
|
|
2230
|
+ #endif
|
|
2231
|
+
|
|
2232
|
+ if (lcdDrawUpdate) {
|
|
2233
|
+ #if ENABLED(DOGLCD)
|
|
2234
|
+ _lcd_ubl_plot_drawing_prep();
|
|
2235
|
+ #else
|
|
2236
|
+ _lcd_ubl_output_char_lcd();
|
|
2237
|
+ #endif
|
|
2238
|
+
|
|
2239
|
+ ubl_map_move_to_xy(); // Move to current location
|
|
2240
|
+
|
|
2241
|
+ if (planner.movesplanned()>1) { // if the nozzle is moving, cancel the move. There is a new location
|
|
2242
|
+ #define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A)
|
|
2243
|
+ #define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A)
|
|
2244
|
+ DISABLE_STEPPER_DRIVER_INTERRUPT();
|
|
2245
|
+ while (planner.blocks_queued()) planner.discard_current_block();
|
|
2246
|
+ stepper.current_block = NULL;
|
|
2247
|
+ planner.clear_block_buffer_runtime();
|
|
2248
|
+ ENABLE_STEPPER_DRIVER_INTERRUPT();
|
|
2249
|
+ set_current_from_steppers_for_axis(ALL_AXES);
|
|
2250
|
+ sync_plan_position();
|
|
2251
|
+ ubl_map_move_to_xy(); // Move to new location
|
|
2252
|
+ }
|
|
2253
|
+ }
|
|
2254
|
+ safe_delay(10);
|
|
2255
|
+ }
|
|
2256
|
+ else lcd_goto_screen(_lcd_ubl_map_homing);
|
|
2257
|
+ }
|
|
2258
|
+
|
|
2259
|
+ /**
|
|
2260
|
+ * UBL Homing before LCD map
|
|
2261
|
+ */
|
|
2262
|
+ void _lcd_ubl_output_map_lcd_cmd() {
|
|
2263
|
+ if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS]))
|
|
2264
|
+ enqueue_and_echo_commands_P(PSTR("G28"));
|
|
2265
|
+ lcd_goto_screen(_lcd_ubl_map_homing);
|
2054
|
2266
|
}
|
2055
|
2267
|
|
2056
|
2268
|
/**
|
|
@@ -2059,9 +2271,10 @@ void kill_screen(const char* lcd_msg) {
|
2059
|
2271
|
void _lcd_ubl_output_map() {
|
2060
|
2272
|
START_MENU();
|
2061
|
2273
|
MENU_BACK(MSG_UBL_LEVEL_BED);
|
2062
|
|
- MENU_ITEM_EDIT(int3, MSG_UBL_MAP_TYPE, &map_type, 0, 1);
|
2063
|
|
- if (map_type == 0) MENU_ITEM(function, MSG_UBL_OUTPUT_MAP_HOST, _lcd_ubl_output_map_cmd);
|
2064
|
|
- if (map_type == 1) MENU_ITEM(function, MSG_UBL_OUTPUT_MAP_CSV, _lcd_ubl_output_map_cmd);
|
|
2274
|
+ MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_HOST, PSTR("G29 T0"));
|
|
2275
|
+ MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_CSV, PSTR("G29 T1"));
|
|
2276
|
+ MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_BACKUP, PSTR("G29 S-1"));
|
|
2277
|
+ MENU_ITEM(function, MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map_lcd_cmd);
|
2065
|
2278
|
END_MENU();
|
2066
|
2279
|
}
|
2067
|
2280
|
|
|
@@ -2091,8 +2304,10 @@ void kill_screen(const char* lcd_msg) {
|
2091
|
2304
|
* Load Bed Mesh
|
2092
|
2305
|
* Save Bed Mesh
|
2093
|
2306
|
* - Output Map
|
2094
|
|
- * Map Type:
|
2095
|
|
- * Output Bed Mesh Host / Output Bed Mesh CSV
|
|
2307
|
+ * Topography to Host
|
|
2308
|
+ * CSV for Spreadsheet
|
|
2309
|
+ * Mesh Output Backup
|
|
2310
|
+ * Output to LCD Grid
|
2096
|
2311
|
* - UBL Tools
|
2097
|
2312
|
* - Build Mesh
|
2098
|
2313
|
* Build PLA Mesh
|
|
@@ -4035,7 +4250,7 @@ void lcd_update() {
|
4035
|
4250
|
int32_t encoderMovementSteps = abs(encoderDiff) / ENCODER_PULSES_PER_STEP;
|
4036
|
4251
|
|
4037
|
4252
|
if (lastEncoderMovementMillis != 0) {
|
4038
|
|
- // Note that the rate is always calculated between to passes through the
|
|
4253
|
+ // Note that the rate is always calculated between two passes through the
|
4039
|
4254
|
// loop and that the abs of the encoderDiff value is tracked.
|
4040
|
4255
|
float encoderStepRate = (float)(encoderMovementSteps) / ((float)(ms - lastEncoderMovementMillis)) * 1000.0;
|
4041
|
4256
|
|