Bladeren bron

Move heater output to Temperature class

Scott Lahteine 7 jaren geleden
bovenliggende
commit
71aefc2e22

+ 1
- 76
Marlin/src/Marlin.cpp Bestand weergeven

@@ -2392,81 +2392,6 @@ static bool pin_is_protected(const int8_t pin) {
2392 2392
   #include "gcode/stats/M78.h"
2393 2393
 #endif
2394 2394
 
2395
-#if HAS_TEMP_HOTEND || HAS_TEMP_BED
2396
-
2397
-  void print_heater_state(const float &c, const float &t,
2398
-    #if ENABLED(SHOW_TEMP_ADC_VALUES)
2399
-      const float r,
2400
-    #endif
2401
-    const int8_t e=-2
2402
-  ) {
2403
-    #if !(HAS_TEMP_BED && HAS_TEMP_HOTEND) && HOTENDS <= 1
2404
-      UNUSED(e);
2405
-    #endif
2406
-
2407
-    SERIAL_PROTOCOLCHAR(' ');
2408
-    SERIAL_PROTOCOLCHAR(
2409
-      #if HAS_TEMP_BED && HAS_TEMP_HOTEND
2410
-        e == -1 ? 'B' : 'T'
2411
-      #elif HAS_TEMP_HOTEND
2412
-        'T'
2413
-      #else
2414
-        'B'
2415
-      #endif
2416
-    );
2417
-    #if HOTENDS > 1
2418
-      if (e >= 0) SERIAL_PROTOCOLCHAR('0' + e);
2419
-    #endif
2420
-    SERIAL_PROTOCOLCHAR(':');
2421
-    SERIAL_PROTOCOL(c);
2422
-    SERIAL_PROTOCOLPAIR(" /" , t);
2423
-    #if ENABLED(SHOW_TEMP_ADC_VALUES)
2424
-      SERIAL_PROTOCOLPAIR(" (", r / OVERSAMPLENR);
2425
-      SERIAL_PROTOCOLCHAR(')');
2426
-    #endif
2427
-  }
2428
-
2429
-  void print_heaterstates() {
2430
-    #if HAS_TEMP_HOTEND
2431
-      print_heater_state(thermalManager.degHotend(gcode.target_extruder), thermalManager.degTargetHotend(gcode.target_extruder)
2432
-        #if ENABLED(SHOW_TEMP_ADC_VALUES)
2433
-          , thermalManager.rawHotendTemp(gcode.target_extruder)
2434
-        #endif
2435
-      );
2436
-    #endif
2437
-    #if HAS_TEMP_BED
2438
-      print_heater_state(thermalManager.degBed(), thermalManager.degTargetBed(),
2439
-        #if ENABLED(SHOW_TEMP_ADC_VALUES)
2440
-          thermalManager.rawBedTemp(),
2441
-        #endif
2442
-        -1 // BED
2443
-      );
2444
-    #endif
2445
-    #if HOTENDS > 1
2446
-      HOTEND_LOOP() print_heater_state(thermalManager.degHotend(e), thermalManager.degTargetHotend(e),
2447
-        #if ENABLED(SHOW_TEMP_ADC_VALUES)
2448
-          thermalManager.rawHotendTemp(e),
2449
-        #endif
2450
-        e
2451
-      );
2452
-    #endif
2453
-    SERIAL_PROTOCOLPGM(" @:");
2454
-    SERIAL_PROTOCOL(thermalManager.getHeaterPower(gcode.target_extruder));
2455
-    #if HAS_TEMP_BED
2456
-      SERIAL_PROTOCOLPGM(" B@:");
2457
-      SERIAL_PROTOCOL(thermalManager.getHeaterPower(-1));
2458
-    #endif
2459
-    #if HOTENDS > 1
2460
-      HOTEND_LOOP() {
2461
-        SERIAL_PROTOCOLPAIR(" @", e);
2462
-        SERIAL_PROTOCOLCHAR(':');
2463
-        SERIAL_PROTOCOL(thermalManager.getHeaterPower(e));
2464
-      }
2465
-    #endif
2466
-  }
2467
-
2468
-#endif // HAS_TEMP_HOTEND || HAS_TEMP_BED
2469
-
2470 2395
 #include "gcode/temperature/M105.h"
2471 2396
 
2472 2397
 #if ENABLED(AUTO_REPORT_TEMPERATURES) && (HAS_TEMP_HOTEND || HAS_TEMP_BED)
@@ -2477,7 +2402,7 @@ static bool pin_is_protected(const int8_t pin) {
2477 2402
   inline void auto_report_temperatures() {
2478 2403
     if (auto_report_temp_interval && ELAPSED(millis(), next_temp_report_ms)) {
2479 2404
       next_temp_report_ms = millis() + 1000UL * auto_report_temp_interval;
2480
-      print_heaterstates();
2405
+      thermalManager.print_heaterstates();
2481 2406
       SERIAL_EOL();
2482 2407
     }
2483 2408
   }

+ 0
- 4
Marlin/src/Marlin.h Bestand weergeven

@@ -300,10 +300,6 @@ extern float soft_endstop_min[XYZ], soft_endstop_max[XYZ];
300 300
   extern Stopwatch print_job_timer;
301 301
 #endif
302 302
 
303
-#if HAS_TEMP_HOTEND || HAS_TEMP_BED
304
-  void print_heaterstates();
305
-#endif
306
-
307 303
 #if ENABLED(MIXING_EXTRUDER)
308 304
   extern float mixing_factor[MIXING_STEPPERS];
309 305
   #if MIXING_VIRTUAL_TOOLS > 1

+ 895
- 0
Marlin/src/feature/bedlevel/ubl/G26_Mesh_Validation_Tool.cpp Bestand weergeven

@@ -0,0 +1,895 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+/**
24
+ * Marlin Firmware -- G26 - Mesh Validation Tool
25
+ */
26
+
27
+#include "../../../inc/MarlinConfig.h"
28
+
29
+#if ENABLED(UBL_G26_MESH_VALIDATION)
30
+
31
+#include "ubl.h"
32
+
33
+#include "../../../Marlin.h"
34
+#include "../../../module/planner.h"
35
+#include "../../../module/stepper.h"
36
+#include "../../../module/motion.h"
37
+#include "../../../module/temperature.h"
38
+#include "../../../lcd/ultralcd.h"
39
+#include "../../../gcode/parser.h"
40
+#include "../../bedlevel/bedlevel.h"
41
+
42
+#define EXTRUSION_MULTIPLIER 1.0
43
+#define RETRACTION_MULTIPLIER 1.0
44
+#define NOZZLE 0.4
45
+#define FILAMENT 1.75
46
+#define LAYER_HEIGHT 0.2
47
+#define PRIME_LENGTH 10.0
48
+#define BED_TEMP 60.0
49
+#define HOTEND_TEMP 205.0
50
+#define OOZE_AMOUNT 0.3
51
+
52
+#define SIZE_OF_INTERSECTION_CIRCLES 5
53
+#define SIZE_OF_CROSSHAIRS 3
54
+
55
+#if SIZE_OF_CROSSHAIRS >= SIZE_OF_INTERSECTION_CIRCLES
56
+  #error "SIZE_OF_CROSSHAIRS must be less than SIZE_OF_INTERSECTION_CIRCLES."
57
+#endif
58
+
59
+/**
60
+ *   G26 Mesh Validation Tool
61
+ *
62
+ *   G26 is a Mesh Validation Tool intended to provide support for the Marlin Unified Bed Leveling System.
63
+ *   In order to fully utilize and benefit from the Marlin Unified Bed Leveling System an accurate Mesh must
64
+ *   be defined. G29 is designed to allow the user to quickly validate the correctness of her Mesh. It will
65
+ *   first heat the bed and nozzle. It will then print lines and circles along the Mesh Cell boundaries and
66
+ *   the intersections of those lines (respectively).
67
+ *
68
+ *   This action allows the user to immediately see where the Mesh is properly defined and where it needs to
69
+ *   be edited. The command will generate the Mesh lines closest to the nozzle's starting position. Alternatively
70
+ *   the user can specify the X and Y position of interest with command parameters. This allows the user to
71
+ *   focus on a particular area of the Mesh where attention is needed.
72
+ *
73
+ *   B #  Bed         Set the Bed Temperature. If not specified, a default of 60 C. will be assumed.
74
+ *
75
+ *   C    Current     When searching for Mesh Intersection points to draw, use the current nozzle location
76
+ *                    as the base for any distance comparison.
77
+ *
78
+ *   D    Disable     Disable the Unified Bed Leveling System. In the normal case the user is invoking this
79
+ *                    command to see how well a Mesh as been adjusted to match a print surface. In order to do
80
+ *                    this the Unified Bed Leveling System is turned on by the G26 command. The D parameter
81
+ *                    alters the command's normal behaviour and disables the Unified Bed Leveling System even if
82
+ *                    it is on.
83
+ *
84
+ *   H #  Hotend      Set the Nozzle Temperature. If not specified, a default of 205 C. will be assumed.
85
+ *
86
+ *   F #  Filament    Used to specify the diameter of the filament being used. If not specified
87
+ *                    1.75mm filament is assumed. If you are not getting acceptable results by using the
88
+ *                    'correct' numbers, you can scale this number up or down a little bit to change the amount
89
+ *                    of filament that is being extruded during the printing of the various lines on the bed.
90
+ *
91
+ *   K    Keep-On     Keep the heaters turned on at the end of the command.
92
+ *
93
+ *   L #  Layer       Layer height. (Height of nozzle above bed)  If not specified .20mm will be used.
94
+ *
95
+ *   O #  Ooooze      How much your nozzle will Ooooze filament while getting in position to print. This
96
+ *                    is over kill, but using this parameter will let you get the very first 'circle' perfect
97
+ *                    so you have a trophy to peel off of the bed and hang up to show how perfectly you have your
98
+ *                    Mesh calibrated. If not specified, a filament length of .3mm is assumed.
99
+ *
100
+ *   P #  Prime       Prime the nozzle with specified length of filament. If this parameter is not
101
+ *                    given, no prime action will take place. If the parameter specifies an amount, that much
102
+ *                    will be purged before continuing. If no amount is specified the command will start
103
+ *                    purging filament until the user provides an LCD Click and then it will continue with
104
+ *                    printing the Mesh. You can carefully remove the spent filament with a needle nose
105
+ *                    pliers while holding the LCD Click wheel in a depressed state. If you do not have
106
+ *                    an LCD, you must specify a value if you use P.
107
+ *
108
+ *   Q #  Multiplier  Retraction Multiplier. Normally not needed. Retraction defaults to 1.0mm and
109
+ *                    un-retraction is at 1.2mm   These numbers will be scaled by the specified amount
110
+ *
111
+ *   R #  Repeat      Prints the number of patterns given as a parameter, starting at the current location.
112
+ *                    If a parameter isn't given, every point will be printed unless G26 is interrupted.
113
+ *                    This works the same way that the UBL G29 P4 R parameter works.
114
+ *
115
+ *                    NOTE:  If you do not have an LCD, you -must- specify R. This is to ensure that you are
116
+ *                    aware that there's some risk associated with printing without the ability to abort in
117
+ *                    cases where mesh point Z value may be inaccurate. As above, if you do not include a
118
+ *                    parameter, every point will be printed.
119
+ *
120
+ *   S #  Nozzle      Used to control the size of nozzle diameter. If not specified, a .4mm nozzle is assumed.
121
+ *
122
+ *   U #  Random      Randomize the order that the circles are drawn on the bed. The search for the closest
123
+ *                    undrawn cicle is still done. But the distance to the location for each circle has a
124
+ *                    random number of the size specified added to it. Specifying S50 will give an interesting
125
+ *                    deviation from the normal behaviour on a 10 x 10 Mesh.
126
+ *
127
+ *   X #  X Coord.    Specify the starting location of the drawing activity.
128
+ *
129
+ *   Y #  Y Coord.    Specify the starting location of the drawing activity.
130
+ */
131
+
132
+// External references
133
+
134
+#if ENABLED(ULTRA_LCD)
135
+  extern char lcd_status_message[];
136
+#endif
137
+
138
+// Remove this if all is well with Teensy compile:
139
+#if 0
140
+#if AVR_AT90USB1286_FAMILY  // Teensyduino & Printrboard IDE extensions have compile errors without this
141
+  inline void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_AXIS]); }
142
+  inline void set_current_to_destination() { COPY(current_position, destination); }
143
+#else
144
+  extern void sync_plan_position_e();
145
+  extern void set_current_to_destination();
146
+#endif
147
+#endif
148
+
149
+#if ENABLED(NEWPANEL)
150
+  void lcd_setstatusPGM(const char* const message, const int8_t level);
151
+  void chirp_at_user();
152
+#endif
153
+
154
+// Private functions
155
+
156
+static uint16_t circle_flags[16], horizontal_mesh_line_flags[16], vertical_mesh_line_flags[16];
157
+float g26_e_axis_feedrate = 0.020,
158
+      random_deviation = 0.0;
159
+
160
+static bool g26_retracted = false; // Track the retracted state of the nozzle so mismatched
161
+                                   // retracts/recovers won't result in a bad state.
162
+
163
+float valid_trig_angle(float);
164
+
165
+float unified_bed_leveling::g26_extrusion_multiplier,
166
+      unified_bed_leveling::g26_retraction_multiplier,
167
+      unified_bed_leveling::g26_nozzle,
168
+      unified_bed_leveling::g26_filament_diameter,
169
+      unified_bed_leveling::g26_layer_height,
170
+      unified_bed_leveling::g26_prime_length,
171
+      unified_bed_leveling::g26_x_pos,
172
+      unified_bed_leveling::g26_y_pos,
173
+      unified_bed_leveling::g26_ooze_amount;
174
+
175
+int16_t unified_bed_leveling::g26_bed_temp,
176
+        unified_bed_leveling::g26_hotend_temp;
177
+
178
+int8_t unified_bed_leveling::g26_prime_flag;
179
+
180
+bool unified_bed_leveling::g26_continue_with_closest,
181
+     unified_bed_leveling::g26_keep_heaters_on;
182
+
183
+int16_t unified_bed_leveling::g26_repeats;
184
+
185
+void unified_bed_leveling::G26_line_to_destination(const float &feed_rate) {
186
+  const float save_feedrate = feedrate_mm_s;
187
+  feedrate_mm_s = feed_rate;      // use specified feed rate
188
+  prepare_move_to_destination();  // will ultimately call ubl.line_to_destination_cartesian or ubl.prepare_linear_move_to for UBL_DELTA
189
+  feedrate_mm_s = save_feedrate;  // restore global feed rate
190
+}
191
+
192
+#if ENABLED(NEWPANEL)
193
+  /**
194
+   * Detect ubl_lcd_clicked, debounce it, and return true for cancel
195
+   */
196
+  bool user_canceled() {
197
+    if (!ubl_lcd_clicked()) return false;
198
+    safe_delay(10);                       // Wait for click to settle
199
+
200
+    #if ENABLED(ULTRA_LCD)
201
+      lcd_setstatusPGM(PSTR("Mesh Validation Stopped."), 99);
202
+      lcd_quick_feedback();
203
+    #endif
204
+
205
+    while (!ubl_lcd_clicked()) idle();    // Wait for button release
206
+
207
+    // If the button is suddenly pressed again,
208
+    // ask the user to resolve the issue
209
+    lcd_setstatusPGM(PSTR("Release button"), 99); // will never appear...
210
+    while (ubl_lcd_clicked()) idle();             // unless this loop happens
211
+    lcd_reset_status();
212
+
213
+    return true;
214
+  }
215
+#endif
216
+
217
+/**
218
+ * G26: Mesh Validation Pattern generation.
219
+ *
220
+ * Used to interactively edit UBL's Mesh by placing the
221
+ * nozzle in a problem area and doing a G29 P4 R command.
222
+ */
223
+void unified_bed_leveling::G26() {
224
+  SERIAL_ECHOLNPGM("G26 command started. Waiting for heater(s).");
225
+  float tmp, start_angle, end_angle;
226
+  int   i, xi, yi;
227
+  mesh_index_pair location;
228
+
229
+  // Don't allow Mesh Validation without homing first,
230
+  // or if the parameter parsing did not go OK, abort
231
+  if (axis_unhomed_error() || parse_G26_parameters()) return;
232
+
233
+  if (current_position[Z_AXIS] < Z_CLEARANCE_BETWEEN_PROBES) {
234
+    do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
235
+    stepper.synchronize();
236
+    set_current_to_destination();
237
+  }
238
+
239
+  if (turn_on_heaters()) goto LEAVE;
240
+
241
+  current_position[E_AXIS] = 0.0;
242
+  sync_plan_position_e();
243
+
244
+  if (g26_prime_flag && prime_nozzle()) goto LEAVE;
245
+
246
+  /**
247
+   *  Bed is preheated
248
+   *
249
+   *  Nozzle is at temperature
250
+   *
251
+   *  Filament is primed!
252
+   *
253
+   *  It's  "Show Time" !!!
254
+   */
255
+
256
+  ZERO(circle_flags);
257
+  ZERO(horizontal_mesh_line_flags);
258
+  ZERO(vertical_mesh_line_flags);
259
+
260
+  // Move nozzle to the specified height for the first layer
261
+  set_destination_to_current();
262
+  destination[Z_AXIS] = g26_layer_height;
263
+  move_to(destination, 0.0);
264
+  move_to(destination, g26_ooze_amount);
265
+
266
+  has_control_of_lcd_panel = true;
267
+  //debug_current_and_destination(PSTR("Starting G26 Mesh Validation Pattern."));
268
+
269
+  /**
270
+   * Declare and generate a sin() & cos() table to be used during the circle drawing. This will lighten
271
+   * the CPU load and make the arc drawing faster and more smooth
272
+   */
273
+  float sin_table[360 / 30 + 1], cos_table[360 / 30 + 1];
274
+  for (i = 0; i <= 360 / 30; i++) {
275
+    cos_table[i] = SIZE_OF_INTERSECTION_CIRCLES * cos(RADIANS(valid_trig_angle(i * 30.0)));
276
+    sin_table[i] = SIZE_OF_INTERSECTION_CIRCLES * sin(RADIANS(valid_trig_angle(i * 30.0)));
277
+  }
278
+
279
+  do {
280
+    location = g26_continue_with_closest
281
+      ? find_closest_circle_to_print(current_position[X_AXIS], current_position[Y_AXIS])
282
+      : find_closest_circle_to_print(g26_x_pos, g26_y_pos); // Find the closest Mesh Intersection to where we are now.
283
+
284
+    if (location.x_index >= 0 && location.y_index >= 0) {
285
+      const float circle_x = mesh_index_to_xpos(location.x_index),
286
+                  circle_y = mesh_index_to_ypos(location.y_index);
287
+
288
+      // If this mesh location is outside the printable_radius, skip it.
289
+
290
+      if (!position_is_reachable_raw_xy(circle_x, circle_y)) continue;
291
+
292
+      xi = location.x_index;  // Just to shrink the next few lines and make them easier to understand
293
+      yi = location.y_index;
294
+
295
+      if (g26_debug_flag) {
296
+        SERIAL_ECHOPAIR("   Doing circle at: (xi=", xi);
297
+        SERIAL_ECHOPAIR(", yi=", yi);
298
+        SERIAL_CHAR(')');
299
+        SERIAL_EOL();
300
+      }
301
+
302
+      start_angle = 0.0;    // assume it is going to be a full circle
303
+      end_angle   = 360.0;
304
+      if (xi == 0) {       // Check for bottom edge
305
+        start_angle = -90.0;
306
+        end_angle   =  90.0;
307
+        if (yi == 0)        // it is an edge, check for the two left corners
308
+          start_angle = 0.0;
309
+        else if (yi == GRID_MAX_POINTS_Y - 1)
310
+          end_angle = 0.0;
311
+      }
312
+      else if (xi == GRID_MAX_POINTS_X - 1) { // Check for top edge
313
+        start_angle =  90.0;
314
+        end_angle   = 270.0;
315
+        if (yi == 0)                  // it is an edge, check for the two right corners
316
+          end_angle = 180.0;
317
+        else if (yi == GRID_MAX_POINTS_Y - 1)
318
+          start_angle = 180.0;
319
+      }
320
+      else if (yi == 0) {
321
+        start_angle =   0.0;         // only do the top   side of the cirlce
322
+        end_angle   = 180.0;
323
+      }
324
+      else if (yi == GRID_MAX_POINTS_Y - 1) {
325
+        start_angle = 180.0;         // only do the bottom side of the cirlce
326
+        end_angle   = 360.0;
327
+      }
328
+
329
+      for (tmp = start_angle; tmp < end_angle - 0.1; tmp += 30.0) {
330
+
331
+        #if ENABLED(NEWPANEL)
332
+          if (user_canceled()) goto LEAVE;              // Check if the user wants to stop the Mesh Validation
333
+        #endif
334
+
335
+        int tmp_div_30 = tmp / 30.0;
336
+        if (tmp_div_30 < 0) tmp_div_30 += 360 / 30;
337
+        if (tmp_div_30 > 11) tmp_div_30 -= 360 / 30;
338
+
339
+        float x = circle_x + cos_table[tmp_div_30],    // for speed, these are now a lookup table entry
340
+              y = circle_y + sin_table[tmp_div_30],
341
+              xe = circle_x + cos_table[tmp_div_30 + 1],
342
+              ye = circle_y + sin_table[tmp_div_30 + 1];
343
+        #if IS_KINEMATIC
344
+          // Check to make sure this segment is entirely on the bed, skip if not.
345
+          if (!position_is_reachable_raw_xy(x, y) || !position_is_reachable_raw_xy(xe, ye)) continue;
346
+        #else                                              // not, we need to skip
347
+          x  = constrain(x, X_MIN_POS + 1, X_MAX_POS - 1); // This keeps us from bumping the endstops
348
+          y  = constrain(y, Y_MIN_POS + 1, Y_MAX_POS - 1);
349
+          xe = constrain(xe, X_MIN_POS + 1, X_MAX_POS - 1);
350
+          ye = constrain(ye, Y_MIN_POS + 1, Y_MAX_POS - 1);
351
+        #endif
352
+
353
+        //if (g26_debug_flag) {
354
+        //  char ccc, *cptr, seg_msg[50], seg_num[10];
355
+        //  strcpy(seg_msg, "   segment: ");
356
+        //  strcpy(seg_num, "    \n");
357
+        //  cptr = (char*) "01234567890ABCDEF????????";
358
+        //  ccc = cptr[tmp_div_30];
359
+        //  seg_num[1] = ccc;
360
+        //  strcat(seg_msg, seg_num);
361
+        //  debug_current_and_destination(seg_msg);
362
+        //}
363
+
364
+        print_line_from_here_to_there(LOGICAL_X_POSITION(x), LOGICAL_Y_POSITION(y), g26_layer_height, LOGICAL_X_POSITION(xe), LOGICAL_Y_POSITION(ye), g26_layer_height);
365
+
366
+      }
367
+      if (look_for_lines_to_connect())
368
+        goto LEAVE;
369
+    }
370
+  } while (--g26_repeats && location.x_index >= 0 && location.y_index >= 0);
371
+
372
+  LEAVE:
373
+  lcd_setstatusPGM(PSTR("Leaving G26"), -1);
374
+
375
+  retract_filament(destination);
376
+  destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES;
377
+
378
+  //debug_current_and_destination(PSTR("ready to do Z-Raise."));
379
+  move_to(destination, 0); // Raise the nozzle
380
+  //debug_current_and_destination(PSTR("done doing Z-Raise."));
381
+
382
+  destination[X_AXIS] = g26_x_pos;                                               // Move back to the starting position
383
+  destination[Y_AXIS] = g26_y_pos;
384
+  //destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES;                        // Keep the nozzle where it is
385
+
386
+  move_to(destination, 0); // Move back to the starting position
387
+  //debug_current_and_destination(PSTR("done doing X/Y move."));
388
+
389
+  has_control_of_lcd_panel = false;     // Give back control of the LCD Panel!
390
+
391
+  if (!g26_keep_heaters_on) {
392
+    #if HAS_TEMP_BED
393
+      thermalManager.setTargetBed(0);
394
+    #endif
395
+    thermalManager.setTargetHotend(0, 0);
396
+  }
397
+}
398
+
399
+float valid_trig_angle(float d) {
400
+  while (d > 360.0) d -= 360.0;
401
+  while (d < 0.0) d += 360.0;
402
+  return d;
403
+}
404
+
405
+mesh_index_pair unified_bed_leveling::find_closest_circle_to_print(const float &X, const float &Y) {
406
+  float closest = 99999.99;
407
+  mesh_index_pair return_val;
408
+
409
+  return_val.x_index = return_val.y_index = -1;
410
+
411
+  for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
412
+    for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++) {
413
+      if (!is_bit_set(circle_flags, i, j)) {
414
+        const float mx = mesh_index_to_xpos(i),  // We found a circle that needs to be printed
415
+                    my = mesh_index_to_ypos(j);
416
+
417
+        // Get the distance to this intersection
418
+        float f = HYPOT(X - mx, Y - my);
419
+
420
+        // It is possible that we are being called with the values
421
+        // to let us find the closest circle to the start position.
422
+        // But if this is not the case, add a small weighting to the
423
+        // distance calculation to help it choose a better place to continue.
424
+        f += HYPOT(g26_x_pos - mx, g26_y_pos - my) / 15.0;
425
+
426
+        // Add in the specified amount of Random Noise to our search
427
+        if (random_deviation > 1.0)
428
+          f += random(0.0, random_deviation);
429
+
430
+        if (f < closest) {
431
+          closest = f;              // We found a closer location that is still
432
+          return_val.x_index = i;   // un-printed  --- save the data for it
433
+          return_val.y_index = j;
434
+          return_val.distance = closest;
435
+        }
436
+      }
437
+    }
438
+  }
439
+  bit_set(circle_flags, return_val.x_index, return_val.y_index);   // Mark this location as done.
440
+  return return_val;
441
+}
442
+
443
+bool unified_bed_leveling::look_for_lines_to_connect() {
444
+  float sx, sy, ex, ey;
445
+
446
+  for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
447
+    for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++) {
448
+
449
+      #if ENABLED(NEWPANEL)
450
+        if (user_canceled()) return true;     // Check if the user wants to stop the Mesh Validation
451
+      #endif
452
+
453
+      if (i < GRID_MAX_POINTS_X) { // We can't connect to anything to the right than GRID_MAX_POINTS_X.
454
+                                   // This is already a half circle because we are at the edge of the bed.
455
+
456
+        if (is_bit_set(circle_flags, i, j) && is_bit_set(circle_flags, i + 1, j)) { // check if we can do a line to the left
457
+          if (!is_bit_set(horizontal_mesh_line_flags, i, j)) {
458
+
459
+            //
460
+            // We found two circles that need a horizontal line to connect them
461
+            // Print it!
462
+            //
463
+            sx = mesh_index_to_xpos(  i  ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // right edge
464
+            ex = mesh_index_to_xpos(i + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // left edge
465
+
466
+            sx = constrain(sx, X_MIN_POS + 1, X_MAX_POS - 1);
467
+            sy = ey = constrain(mesh_index_to_ypos(j), Y_MIN_POS + 1, Y_MAX_POS - 1);
468
+            ex = constrain(ex, X_MIN_POS + 1, X_MAX_POS - 1);
469
+
470
+            if (position_is_reachable_raw_xy(sx, sy) && position_is_reachable_raw_xy(ex, ey)) {
471
+
472
+              if (g26_debug_flag) {
473
+                SERIAL_ECHOPAIR(" Connecting with horizontal line (sx=", sx);
474
+                SERIAL_ECHOPAIR(", sy=", sy);
475
+                SERIAL_ECHOPAIR(") -> (ex=", ex);
476
+                SERIAL_ECHOPAIR(", ey=", ey);
477
+                SERIAL_CHAR(')');
478
+                SERIAL_EOL();
479
+                //debug_current_and_destination(PSTR("Connecting horizontal line."));
480
+              }
481
+
482
+              print_line_from_here_to_there(LOGICAL_X_POSITION(sx), LOGICAL_Y_POSITION(sy), g26_layer_height, LOGICAL_X_POSITION(ex), LOGICAL_Y_POSITION(ey), g26_layer_height);
483
+            }
484
+            bit_set(horizontal_mesh_line_flags, i, j);   // Mark it as done so we don't do it again, even if we skipped it
485
+          }
486
+        }
487
+
488
+        if (j < GRID_MAX_POINTS_Y) { // We can't connect to anything further back than GRID_MAX_POINTS_Y.
489
+                                         // This is already a half circle because we are at the edge  of the bed.
490
+
491
+          if (is_bit_set(circle_flags, i, j) && is_bit_set(circle_flags, i, j + 1)) { // check if we can do a line straight down
492
+            if (!is_bit_set( vertical_mesh_line_flags, i, j)) {
493
+              //
494
+              // We found two circles that need a vertical line to connect them
495
+              // Print it!
496
+              //
497
+              sy = mesh_index_to_ypos(  j  ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // top edge
498
+              ey = mesh_index_to_ypos(j + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // bottom edge
499
+
500
+              sx = ex = constrain(mesh_index_to_xpos(i), X_MIN_POS + 1, X_MAX_POS - 1);
501
+              sy = constrain(sy, Y_MIN_POS + 1, Y_MAX_POS - 1);
502
+              ey = constrain(ey, Y_MIN_POS + 1, Y_MAX_POS - 1);
503
+
504
+              if (position_is_reachable_raw_xy(sx, sy) && position_is_reachable_raw_xy(ex, ey)) {
505
+
506
+                if (g26_debug_flag) {
507
+                  SERIAL_ECHOPAIR(" Connecting with vertical line (sx=", sx);
508
+                  SERIAL_ECHOPAIR(", sy=", sy);
509
+                  SERIAL_ECHOPAIR(") -> (ex=", ex);
510
+                  SERIAL_ECHOPAIR(", ey=", ey);
511
+                  SERIAL_CHAR(')');
512
+                  SERIAL_EOL();
513
+                  debug_current_and_destination(PSTR("Connecting vertical line."));
514
+                }
515
+                print_line_from_here_to_there(LOGICAL_X_POSITION(sx), LOGICAL_Y_POSITION(sy), g26_layer_height, LOGICAL_X_POSITION(ex), LOGICAL_Y_POSITION(ey), g26_layer_height);
516
+              }
517
+              bit_set(vertical_mesh_line_flags, i, j);   // Mark it as done so we don't do it again, even if skipped
518
+            }
519
+          }
520
+        }
521
+      }
522
+    }
523
+  }
524
+  return false;
525
+}
526
+
527
+void unified_bed_leveling::move_to(const float &x, const float &y, const float &z, const float &e_delta) {
528
+  float feed_value;
529
+  static float last_z = -999.99;
530
+
531
+  bool has_xy_component = (x != current_position[X_AXIS] || y != current_position[Y_AXIS]); // Check if X or Y is involved in the movement.
532
+
533
+  if (z != last_z) {
534
+    last_z = z;
535
+    feed_value = planner.max_feedrate_mm_s[Z_AXIS]/(3.0);  // Base the feed rate off of the configured Z_AXIS feed rate
536
+
537
+    destination[X_AXIS] = current_position[X_AXIS];
538
+    destination[Y_AXIS] = current_position[Y_AXIS];
539
+    destination[Z_AXIS] = z;                          // We know the last_z==z or we wouldn't be in this block of code.
540
+    destination[E_AXIS] = current_position[E_AXIS];
541
+
542
+    G26_line_to_destination(feed_value);
543
+
544
+    stepper.synchronize();
545
+    set_destination_to_current();
546
+  }
547
+
548
+  // Check if X or Y is involved in the movement.
549
+  // Yes: a 'normal' movement. No: a retract() or recover()
550
+  feed_value = has_xy_component ? PLANNER_XY_FEEDRATE() / 10.0 : planner.max_feedrate_mm_s[E_AXIS] / 1.5;
551
+
552
+  if (g26_debug_flag) SERIAL_ECHOLNPAIR("in move_to() feed_value for XY:", feed_value);
553
+
554
+  destination[X_AXIS] = x;
555
+  destination[Y_AXIS] = y;
556
+  destination[E_AXIS] += e_delta;
557
+
558
+  G26_line_to_destination(feed_value);
559
+
560
+  stepper.synchronize();
561
+  set_destination_to_current();
562
+
563
+}
564
+
565
+void unified_bed_leveling::retract_filament(const float where[XYZE]) {
566
+  if (!g26_retracted) { // Only retract if we are not already retracted!
567
+    g26_retracted = true;
568
+    move_to(where, -1.0 * g26_retraction_multiplier);
569
+  }
570
+}
571
+
572
+void unified_bed_leveling::recover_filament(const float where[XYZE]) {
573
+  if (g26_retracted) { // Only un-retract if we are retracted.
574
+    move_to(where, 1.2 * g26_retraction_multiplier);
575
+    g26_retracted = false;
576
+  }
577
+}
578
+
579
+/**
580
+ * print_line_from_here_to_there() takes two cartesian coordinates and draws a line from one
581
+ * to the other. But there are really three sets of coordinates involved. The first coordinate
582
+ * is the present location of the nozzle. We don't necessarily want to print from this location.
583
+ * We first need to move the nozzle to the start of line segment where we want to print. Once
584
+ * there, we can use the two coordinates supplied to draw the line.
585
+ *
586
+ * Note:  Although we assume the first set of coordinates is the start of the line and the second
587
+ * set of coordinates is the end of the line, it does not always work out that way. This function
588
+ * optimizes the movement to minimize the travel distance before it can start printing. This saves
589
+ * a lot of time and eliminates a lot of nonsensical movement of the nozzle. However, it does
590
+ * cause a lot of very little short retracement of th nozzle when it draws the very first line
591
+ * segment of a 'circle'. The time this requires is very short and is easily saved by the other
592
+ * cases where the optimization comes into play.
593
+ */
594
+void unified_bed_leveling::print_line_from_here_to_there(const float &sx, const float &sy, const float &sz, const float &ex, const float &ey, const float &ez) {
595
+  const float dx_s = current_position[X_AXIS] - sx,   // find our distance from the start of the actual line segment
596
+              dy_s = current_position[Y_AXIS] - sy,
597
+              dist_start = HYPOT2(dx_s, dy_s),        // We don't need to do a sqrt(), we can compare the distance^2
598
+                                                      // to save computation time
599
+              dx_e = current_position[X_AXIS] - ex,   // find our distance from the end of the actual line segment
600
+              dy_e = current_position[Y_AXIS] - ey,
601
+              dist_end = HYPOT2(dx_e, dy_e),
602
+
603
+              line_length = HYPOT(ex - sx, ey - sy);
604
+
605
+  // If the end point of the line is closer to the nozzle, flip the direction,
606
+  // moving from the end to the start. On very small lines the optimization isn't worth it.
607
+  if (dist_end < dist_start && (SIZE_OF_INTERSECTION_CIRCLES) < FABS(line_length)) {
608
+    return print_line_from_here_to_there(ex, ey, ez, sx, sy, sz);
609
+  }
610
+
611
+  // Decide whether to retract & bump
612
+
613
+  if (dist_start > 2.0) {
614
+    retract_filament(destination);
615
+    //todo:  parameterize the bump height with a define
616
+    move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + 0.500, 0.0);  // Z bump to minimize scraping
617
+    move_to(sx, sy, sz + 0.500, 0.0); // Get to the starting point with no extrusion while bumped
618
+  }
619
+
620
+  move_to(sx, sy, sz, 0.0); // Get to the starting point with no extrusion / un-Z bump
621
+
622
+  const float e_pos_delta = line_length * g26_e_axis_feedrate * g26_extrusion_multiplier;
623
+
624
+  recover_filament(destination);
625
+  move_to(ex, ey, ez, e_pos_delta);  // Get to the ending point with an appropriate amount of extrusion
626
+}
627
+
628
+/**
629
+ * This function used to be inline code in G26. But there are so many
630
+ * parameters it made sense to turn them into static globals and get
631
+ * this code out of sight of the main routine.
632
+ */
633
+bool unified_bed_leveling::parse_G26_parameters() {
634
+
635
+  g26_extrusion_multiplier  = EXTRUSION_MULTIPLIER;
636
+  g26_retraction_multiplier = RETRACTION_MULTIPLIER;
637
+  g26_nozzle                = NOZZLE;
638
+  g26_filament_diameter     = FILAMENT;
639
+  g26_layer_height          = LAYER_HEIGHT;
640
+  g26_prime_length          = PRIME_LENGTH;
641
+  g26_bed_temp              = BED_TEMP;
642
+  g26_hotend_temp           = HOTEND_TEMP;
643
+  g26_prime_flag            = 0;
644
+
645
+  g26_ooze_amount           = parser.linearval('O', OOZE_AMOUNT);
646
+  g26_keep_heaters_on       = parser.boolval('K');
647
+  g26_continue_with_closest = parser.boolval('C');
648
+
649
+  if (parser.seenval('B')) {
650
+    g26_bed_temp = parser.value_celsius();
651
+    if (!WITHIN(g26_bed_temp, 15, 140)) {
652
+      SERIAL_PROTOCOLLNPGM("?Specified bed temperature not plausible.");
653
+      return UBL_ERR;
654
+    }
655
+  }
656
+
657
+  if (parser.seenval('L')) {
658
+    g26_layer_height = parser.value_linear_units();
659
+    if (!WITHIN(g26_layer_height, 0.0, 2.0)) {
660
+      SERIAL_PROTOCOLLNPGM("?Specified layer height not plausible.");
661
+      return UBL_ERR;
662
+    }
663
+  }
664
+
665
+  if (parser.seen('Q')) {
666
+    if (parser.has_value()) {
667
+      g26_retraction_multiplier = parser.value_float();
668
+      if (!WITHIN(g26_retraction_multiplier, 0.05, 15.0)) {
669
+        SERIAL_PROTOCOLLNPGM("?Specified Retraction Multiplier not plausible.");
670
+        return UBL_ERR;
671
+      }
672
+    }
673
+    else {
674
+      SERIAL_PROTOCOLLNPGM("?Retraction Multiplier must be specified.");
675
+      return UBL_ERR;
676
+    }
677
+  }
678
+
679
+  if (parser.seenval('S')) {
680
+    g26_nozzle = parser.value_float();
681
+    if (!WITHIN(g26_nozzle, 0.1, 1.0)) {
682
+      SERIAL_PROTOCOLLNPGM("?Specified nozzle size not plausible.");
683
+      return UBL_ERR;
684
+    }
685
+  }
686
+
687
+  if (parser.seen('P')) {
688
+    if (!parser.has_value()) {
689
+      #if ENABLED(NEWPANEL)
690
+        g26_prime_flag = -1;
691
+      #else
692
+        SERIAL_PROTOCOLLNPGM("?Prime length must be specified when not using an LCD.");
693
+        return UBL_ERR;
694
+      #endif
695
+    }
696
+    else {
697
+      g26_prime_flag++;
698
+      g26_prime_length = parser.value_linear_units();
699
+      if (!WITHIN(g26_prime_length, 0.0, 25.0)) {
700
+        SERIAL_PROTOCOLLNPGM("?Specified prime length not plausible.");
701
+        return UBL_ERR;
702
+      }
703
+    }
704
+  }
705
+
706
+  if (parser.seenval('F')) {
707
+    g26_filament_diameter = parser.value_linear_units();
708
+    if (!WITHIN(g26_filament_diameter, 1.0, 4.0)) {
709
+      SERIAL_PROTOCOLLNPGM("?Specified filament size not plausible.");
710
+      return UBL_ERR;
711
+    }
712
+  }
713
+  g26_extrusion_multiplier *= sq(1.75) / sq(g26_filament_diameter); // If we aren't using 1.75mm filament, we need to
714
+                                                                    // scale up or down the length needed to get the
715
+                                                                    // same volume of filament
716
+
717
+  g26_extrusion_multiplier *= g26_filament_diameter * sq(g26_nozzle) / sq(0.3); // Scale up by nozzle size
718
+
719
+  if (parser.seenval('H')) {
720
+    g26_hotend_temp = parser.value_celsius();
721
+    if (!WITHIN(g26_hotend_temp, 165, 280)) {
722
+      SERIAL_PROTOCOLLNPGM("?Specified nozzle temperature not plausible.");
723
+      return UBL_ERR;
724
+    }
725
+  }
726
+
727
+  if (parser.seen('U')) {
728
+    randomSeed(millis());
729
+    // This setting will persist for the next G26
730
+    random_deviation = parser.has_value() ? parser.value_float() : 50.0;
731
+  }
732
+
733
+  #if ENABLED(NEWPANEL)
734
+    g26_repeats = parser.intval('R', GRID_MAX_POINTS + 1);
735
+  #else
736
+    if (!parser.seen('R')) {
737
+      SERIAL_PROTOCOLLNPGM("?(R)epeat must be specified when not using an LCD.");
738
+      return UBL_ERR;
739
+    }
740
+    else
741
+      g26_repeats = parser.has_value() ? parser.value_int() : GRID_MAX_POINTS + 1;
742
+  #endif
743
+  if (g26_repeats < 1) {
744
+    SERIAL_PROTOCOLLNPGM("?(R)epeat value not plausible; must be at least 1.");
745
+    return UBL_ERR;
746
+  }
747
+
748
+  g26_x_pos = parser.linearval('X', current_position[X_AXIS]);
749
+  g26_y_pos = parser.linearval('Y', current_position[Y_AXIS]);
750
+  if (!position_is_reachable_xy(g26_x_pos, g26_y_pos)) {
751
+    SERIAL_PROTOCOLLNPGM("?Specified X,Y coordinate out of bounds.");
752
+    return UBL_ERR;
753
+  }
754
+
755
+  /**
756
+   * Wait until all parameters are verified before altering the state!
757
+   */
758
+  set_bed_leveling_enabled(!parser.seen('D'));
759
+
760
+  return UBL_OK;
761
+}
762
+
763
+#if ENABLED(NEWPANEL)
764
+  bool unified_bed_leveling::exit_from_g26() {
765
+    lcd_setstatusPGM(PSTR("Leaving G26"), -1);
766
+    while (ubl_lcd_clicked()) idle();
767
+    return UBL_ERR;
768
+  }
769
+#endif
770
+
771
+/**
772
+ * Turn on the bed and nozzle heat and
773
+ * wait for them to get up to temperature.
774
+ */
775
+bool unified_bed_leveling::turn_on_heaters() {
776
+  millis_t next = millis() + 5000UL;
777
+  #if HAS_TEMP_BED
778
+    #if ENABLED(ULTRA_LCD)
779
+      if (g26_bed_temp > 25) {
780
+        lcd_setstatusPGM(PSTR("G26 Heating Bed."), 99);
781
+        lcd_quick_feedback();
782
+    #endif
783
+        has_control_of_lcd_panel = true;
784
+        thermalManager.setTargetBed(g26_bed_temp);
785
+        while (abs(thermalManager.degBed() - g26_bed_temp) > 3) {
786
+
787
+          #if ENABLED(NEWPANEL)
788
+            if (ubl_lcd_clicked()) return exit_from_g26();
789
+          #endif
790
+
791
+          if (ELAPSED(millis(), next)) {
792
+            next = millis() + 5000UL;
793
+            thermalManager.print_heaterstates();
794
+            SERIAL_EOL();
795
+          }
796
+          idle();
797
+        }
798
+    #if ENABLED(ULTRA_LCD)
799
+      }
800
+      lcd_setstatusPGM(PSTR("G26 Heating Nozzle."), 99);
801
+      lcd_quick_feedback();
802
+    #endif
803
+  #endif
804
+
805
+  // Start heating the nozzle and wait for it to reach temperature.
806
+  thermalManager.setTargetHotend(g26_hotend_temp, 0);
807
+  while (abs(thermalManager.degHotend(0) - g26_hotend_temp) > 3) {
808
+
809
+    #if ENABLED(NEWPANEL)
810
+      if (ubl_lcd_clicked()) return exit_from_g26();
811
+    #endif
812
+
813
+    if (ELAPSED(millis(), next)) {
814
+      next = millis() + 5000UL;
815
+      thermalManager.print_heaterstates();
816
+      SERIAL_EOL();
817
+    }
818
+    idle();
819
+  }
820
+
821
+  #if ENABLED(ULTRA_LCD)
822
+    lcd_reset_status();
823
+    lcd_quick_feedback();
824
+  #endif
825
+
826
+  return UBL_OK;
827
+}
828
+
829
+/**
830
+ * Prime the nozzle if needed. Return true on error.
831
+ */
832
+bool unified_bed_leveling::prime_nozzle() {
833
+
834
+  #if ENABLED(NEWPANEL)
835
+    float Total_Prime = 0.0;
836
+
837
+    if (g26_prime_flag == -1) {  // The user wants to control how much filament gets purged
838
+
839
+      has_control_of_lcd_panel = true;
840
+      lcd_setstatusPGM(PSTR("User-Controlled Prime"), 99);
841
+      chirp_at_user();
842
+
843
+      set_destination_to_current();
844
+
845
+      recover_filament(destination); // Make sure G26 doesn't think the filament is retracted().
846
+
847
+      while (!ubl_lcd_clicked()) {
848
+        chirp_at_user();
849
+        destination[E_AXIS] += 0.25;
850
+        #ifdef PREVENT_LENGTHY_EXTRUDE
851
+          Total_Prime += 0.25;
852
+          if (Total_Prime >= EXTRUDE_MAXLENGTH) return UBL_ERR;
853
+        #endif
854
+        G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);
855
+
856
+        stepper.synchronize();    // Without this synchronize, the purge is more consistent,
857
+                                  // but because the planner has a buffer, we won't be able
858
+                                  // to stop as quickly. So we put up with the less smooth
859
+                                  // action to give the user a more responsive 'Stop'.
860
+        set_destination_to_current();
861
+        idle();
862
+      }
863
+
864
+      while (ubl_lcd_clicked()) idle();           // Debounce Encoder Wheel
865
+
866
+      #if ENABLED(ULTRA_LCD)
867
+        strcpy_P(lcd_status_message, PSTR("Done Priming")); // We can't do lcd_setstatusPGM() without having it continue;
868
+                                                            // So... We cheat to get a message up.
869
+        lcd_setstatusPGM(PSTR("Done Priming"), 99);
870
+        lcd_quick_feedback();
871
+      #endif
872
+
873
+      has_control_of_lcd_panel = false;
874
+
875
+    }
876
+    else {
877
+  #else
878
+  {
879
+  #endif
880
+    #if ENABLED(ULTRA_LCD)
881
+      lcd_setstatusPGM(PSTR("Fixed Length Prime."), 99);
882
+      lcd_quick_feedback();
883
+    #endif
884
+    set_destination_to_current();
885
+    destination[E_AXIS] += g26_prime_length;
886
+    G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);
887
+    stepper.synchronize();
888
+    set_destination_to_current();
889
+    retract_filament(destination);
890
+  }
891
+
892
+  return UBL_OK;
893
+}
894
+
895
+#endif // UBL_G26_MESH_VALIDATION

+ 1
- 1
Marlin/src/gcode/temperature/M105.h Bestand weergeven

@@ -28,7 +28,7 @@ void gcode_M105() {
28 28
 
29 29
   #if HAS_TEMP_HOTEND || HAS_TEMP_BED
30 30
     SERIAL_PROTOCOLPGM(MSG_OK);
31
-    print_heaterstates();
31
+    thermalManager.print_heaterstates();
32 32
   #else // !HAS_TEMP_HOTEND && !HAS_TEMP_BED
33 33
     SERIAL_ERROR_START();
34 34
     SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS);

+ 1
- 1
Marlin/src/gcode/temperature/M109.cpp Bestand weergeven

@@ -127,7 +127,7 @@ void GcodeSuite::M109() {
127 127
     now = millis();
128 128
     if (ELAPSED(now, next_temp_ms)) { //Print temp & remaining time every 1s while waiting
129 129
       next_temp_ms = now + 1000UL;
130
-      print_heaterstates();
130
+      thermalManager.print_heaterstates();
131 131
       #if TEMP_RESIDENCY_TIME > 0
132 132
         SERIAL_PROTOCOLPGM(" W:");
133 133
         if (residency_start_ms)

+ 1
- 1
Marlin/src/gcode/temperature/M190.h Bestand weergeven

@@ -85,7 +85,7 @@ void gcode_M190() {
85 85
     now = millis();
86 86
     if (ELAPSED(now, next_temp_ms)) { //Print Temp Reading every 1 second while heating up.
87 87
       next_temp_ms = now + 1000UL;
88
-      print_heaterstates();
88
+      thermalManager.print_heaterstates();
89 89
       #if TEMP_BED_RESIDENCY_TIME > 0
90 90
         SERIAL_PROTOCOLPGM(" W:");
91 91
         if (residency_start_ms)

+ 77
- 0
Marlin/src/module/temperature.cpp Bestand weergeven

@@ -2179,3 +2179,80 @@ void Temperature::isr() {
2179 2179
   in_temp_isr = false;
2180 2180
   ENABLE_TEMPERATURE_INTERRUPT(); //re-enable Temperature ISR
2181 2181
 }
2182
+
2183
+#if HAS_TEMP_HOTEND || HAS_TEMP_BED
2184
+
2185
+  #include "../gcode/gcode.h"
2186
+
2187
+  void print_heater_state(const float &c, const float &t,
2188
+    #if ENABLED(SHOW_TEMP_ADC_VALUES)
2189
+      const float r,
2190
+    #endif
2191
+    const int8_t e=-2
2192
+  ) {
2193
+    #if !(HAS_TEMP_BED && HAS_TEMP_HOTEND) && HOTENDS <= 1
2194
+      UNUSED(e);
2195
+    #endif
2196
+
2197
+    SERIAL_PROTOCOLCHAR(' ');
2198
+    SERIAL_PROTOCOLCHAR(
2199
+      #if HAS_TEMP_BED && HAS_TEMP_HOTEND
2200
+        e == -1 ? 'B' : 'T'
2201
+      #elif HAS_TEMP_HOTEND
2202
+        'T'
2203
+      #else
2204
+        'B'
2205
+      #endif
2206
+    );
2207
+    #if HOTENDS > 1
2208
+      if (e >= 0) SERIAL_PROTOCOLCHAR('0' + e);
2209
+    #endif
2210
+    SERIAL_PROTOCOLCHAR(':');
2211
+    SERIAL_PROTOCOL(c);
2212
+    SERIAL_PROTOCOLPAIR(" /" , t);
2213
+    #if ENABLED(SHOW_TEMP_ADC_VALUES)
2214
+      SERIAL_PROTOCOLPAIR(" (", r / OVERSAMPLENR);
2215
+      SERIAL_PROTOCOLCHAR(')');
2216
+    #endif
2217
+  }
2218
+
2219
+  void Temperature::print_heaterstates() {
2220
+    #if HAS_TEMP_HOTEND
2221
+      print_heater_state(degHotend(gcode.target_extruder), degTargetHotend(gcode.target_extruder)
2222
+        #if ENABLED(SHOW_TEMP_ADC_VALUES)
2223
+          , rawHotendTemp(gcode.target_extruder)
2224
+        #endif
2225
+      );
2226
+    #endif
2227
+    #if HAS_TEMP_BED
2228
+      print_heater_state(degBed(), degTargetBed(),
2229
+        #if ENABLED(SHOW_TEMP_ADC_VALUES)
2230
+          rawBedTemp(),
2231
+        #endif
2232
+        -1 // BED
2233
+      );
2234
+    #endif
2235
+    #if HOTENDS > 1
2236
+      HOTEND_LOOP() print_heater_state(degHotend(e), degTargetHotend(e),
2237
+        #if ENABLED(SHOW_TEMP_ADC_VALUES)
2238
+          rawHotendTemp(e),
2239
+        #endif
2240
+        e
2241
+      );
2242
+    #endif
2243
+    SERIAL_PROTOCOLPGM(" @:");
2244
+    SERIAL_PROTOCOL(getHeaterPower(gcode.target_extruder));
2245
+    #if HAS_TEMP_BED
2246
+      SERIAL_PROTOCOLPGM(" B@:");
2247
+      SERIAL_PROTOCOL(getHeaterPower(-1));
2248
+    #endif
2249
+    #if HOTENDS > 1
2250
+      HOTEND_LOOP() {
2251
+        SERIAL_PROTOCOLPAIR(" @", e);
2252
+        SERIAL_PROTOCOLCHAR(':');
2253
+        SERIAL_PROTOCOL(getHeaterPower(e));
2254
+      }
2255
+    #endif
2256
+  }
2257
+
2258
+#endif // HAS_TEMP_HOTEND || HAS_TEMP_BED

+ 4
- 0
Marlin/src/module/temperature.h Bestand weergeven

@@ -525,6 +525,10 @@ class Temperature {
525 525
       #endif
526 526
     #endif
527 527
 
528
+    #if HAS_TEMP_HOTEND || HAS_TEMP_BED
529
+      static void print_heaterstates();
530
+    #endif
531
+
528 532
   private:
529 533
 
530 534
     #if ENABLED(FAST_PWM_FAN)

Laden…
Annuleren
Opslaan