Browse Source

Anycubic Chiron full feature support (#19505)

Nick 3 years ago
parent
commit
60155aa442
No account linked to committer's email address

+ 1
- 0
Marlin/Configuration_adv.h View File

@@ -1166,6 +1166,7 @@
1166 1166
   #if ENABLED(POWER_LOSS_RECOVERY)
1167 1167
     #define PLR_ENABLED_DEFAULT   false // Power Loss Recovery enabled by default. (Set with 'M413 Sn' & M500)
1168 1168
     //#define BACKUP_POWER_SUPPLY       // Backup power / UPS to move the steppers on power loss
1169
+    //#define POWER_LOSS_RECOVER_ZHOME  // Z homing is needed for proper recovery. 99.9% of the time this should be disabled!
1169 1170
     //#define POWER_LOSS_ZRAISE       2 // (mm) Z axis raise on resume (on power loss with UPS)
1170 1171
     //#define POWER_LOSS_PIN         44 // Pin to detect power loss. Set to -1 to disable default pin on boards without module.
1171 1172
     //#define POWER_LOSS_STATE     HIGH // State of pin indicating power loss

+ 1
- 1
Marlin/src/HAL/AVR/pinsDebug.h View File

@@ -26,7 +26,7 @@
26 26
 
27 27
 #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS
28 28
 
29
-#if MB(BQ_ZUM_MEGA_3D, MIGHTYBOARD_REVE, MINIRAMBO, SCOOVO_X9H)
29
+#if MB(BQ_ZUM_MEGA_3D, MIGHTYBOARD_REVE, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14)
30 30
   #define AVR_ATmega2560_FAMILY_PLUS_70 1
31 31
 #endif
32 32
 

+ 3
- 6
Marlin/src/HAL/AVR/pinsDebug_plus_70.h View File

@@ -22,15 +22,12 @@
22 22
  * Structures for 2560 family boards that use more than 70 pins
23 23
  */
24 24
 
25
-#undef NUM_DIGITAL_PINS
26
-#if MB(BQ_ZUM_MEGA_3D)
25
+#if MB(BQ_ZUM_MEGA_3D, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14)
26
+  #undef NUM_DIGITAL_PINS
27 27
   #define NUM_DIGITAL_PINS            85
28 28
 #elif MB(MIGHTYBOARD_REVE)
29
+  #undef NUM_DIGITAL_PINS
29 30
   #define NUM_DIGITAL_PINS            80
30
-#elif MB(MINIRAMBO)
31
-  #define NUM_DIGITAL_PINS            85
32
-#elif MB(SCOOVO_X9H)
33
-  #define NUM_DIGITAL_PINS            85
34 31
 #endif
35 32
 
36 33
 #define PA 1

+ 10
- 2
Marlin/src/feature/powerloss.cpp View File

@@ -367,7 +367,9 @@ void PrintJobRecovery::resume() {
367 367
 
368 368
     gcode.process_subcommands_now_P(PSTR(
369 369
       "G28R0"                               // No raise during G28
370
-      TERN_(IS_CARTESIAN, "XY")             // Don't home Z on Cartesian
370
+      #if IS_CARTESIAN && DISABLED(POWER_LOSS_RECOVER_ZHOME)
371
+        "XY"                                // Don't home Z on Cartesian unless overridden
372
+      #endif
371 373
     ));
372 374
 
373 375
   #endif
@@ -375,6 +377,12 @@ void PrintJobRecovery::resume() {
375 377
   // Pretend that all axes are homed
376 378
   set_all_homed();
377 379
 
380
+  #if ENABLED(POWER_LOSS_RECOVER_ZHOME)
381
+    // Z has been homed so restore Z to ZsavedPos + POWER_LOSS_ZRAISE
382
+    sprintf_P(cmd, PSTR("G1 F500 Z%s"), dtostrf(info.current_position.z + POWER_LOSS_ZRAISE, 1, 3, str_1));
383
+    gcode.process_subcommands_now(cmd);
384
+  #endif
385
+
378 386
   // Recover volumetric extrusion state
379 387
   #if DISABLED(NO_VOLUMETRICS)
380 388
     #if HAS_MULTI_EXTRUDER
@@ -481,7 +489,7 @@ void PrintJobRecovery::resume() {
481 489
 
482 490
   // Move back to the saved Z
483 491
   dtostrf(info.current_position.z, 1, 3, str_1);
484
-  #if Z_HOME_DIR > 0
492
+  #if Z_HOME_DIR > 0 || ENABLED(POWER_LOSS_RECOVER_ZHOME)
485 493
     sprintf_P(cmd, PSTR("G1 Z%s F200"), str_1);
486 494
   #else
487 495
     gcode.process_subcommands_now_P(PSTR("G1 Z0 F200"));

+ 56
- 474
Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp View File

@@ -21,7 +21,7 @@
21 21
  */
22 22
 
23 23
 /**
24
- * anycubic_chiron_lcd.cpp
24
+ * lcd/extui/anycubic_chiron_lcd.cpp
25 25
  *
26 26
  * Anycubic Chiron TFT support for Marlin
27 27
  */
@@ -31,508 +31,90 @@
31 31
 #if ENABLED(ANYCUBIC_LCD_CHIRON)
32 32
 
33 33
 #include "ui_api.h"
34
+#include "lib/anycubic_chiron/chiron_tft.h"
34 35
 
35
-#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
36
-  #if GRID_MAX_POINTS_X != 5 || GRID_MAX_POINTS_Y != 5
37
-    #error ANYCUBIC CHIRON LCD requires a 5x5 bed leveling grid (GRID_MAX_POINTS_X and GRID_MAX_POINTS_Y)
38
-  #endif
39
-#else
40
-  #error ANYCUBIC CHIRON LCD requires AUTO_BED_LEVELING_BILINEAR enabled
41
-#endif
42
-
43
-#if DISABLED(FILAMENT_RUNOUT_SENSOR)
44
-  #error ANYCUBIC CHIRON LCD requires FILAMENT_RUNOUT_SENSOR enabled
45
-#endif
46
-
47
-#if ENABLED(POWER_LOSS_RECOVERY)
48
-  #error ANYCUBIC CHIRON LCD does not currently support POWER_LOSS_RECOVERY
49
-#endif
50
-
51
-static bool is_auto_leveling = false;
52
-static bool is_printing_from_sd = false;
53
-static bool is_out_of_filament = false;
54
-
55
-static void sendNewLine(void) {
56
-  LCD_SERIAL.write('\r');
57
-  LCD_SERIAL.write('\n');
58
-}
59
-
60
-static void send(const char *str) {
61
-  LCD_SERIAL.print(str);
62
-}
63
-
64
-static void sendLine(const char *str) {
65
-  send(str);
66
-  sendNewLine();
67
-}
68
-
69
-static void send_P(PGM_P str) {
70
-  while (const char c = pgm_read_byte(str++))
71
-    LCD_SERIAL.write(c);
72
-}
73
-
74
-static void sendLine_P(PGM_P str) {
75
-  send_P(str);
76
-  sendNewLine();
77
-}
78
-
79
-static void sendValue_P(PGM_P prefix, int value) {
80
-  send_P(prefix);
81
-  LCD_SERIAL.print(value);
82
-}
83
-
84
-static void sendValue_P(PGM_P prefix, float value) {
85
-  send_P(prefix);
86
-  LCD_SERIAL.print(value);
87
-}
88
-
89
-static void sendValueLine_P(PGM_P prefix, int value) {
90
-  send_P(prefix);
91
-  LCD_SERIAL.print(value);
92
-  sendNewLine();
93
-}
94
-
95
-static void sendValueLine_P(PGM_P prefix, float value) {
96
-  send_P(prefix);
97
-  LCD_SERIAL.print(value);
98
-  sendNewLine();
99
-}
100
-
101
-static int parseIntArgument(const char *buffer, char letterId) {
102
-  char *p = strchr(buffer, letterId);
103
-  if (!p)
104
-    return -1;
105
-  return atoi(p+1);
106
-}
107
-
108
-static float parseFloatArgument(const char *buffer, char letterId) {
109
-  char *p = strchr(buffer, letterId);
110
-  if (!p)
111
-    return NAN;
112
-  return strtof(p+1, nullptr);
113
-}
114
-
115
-static int mmToHundredths(float x) {
116
-  // Round
117
-  if (x >= 0)
118
-    x += 0.005f;
119
-  else
120
-    x -= 0.005f;
121
-  return (int)(x * 100.0f);
122
-}
123
-
124
-static float hundredthsToMm(int x) {
125
-  return x / 100.0f;
126
-}
127
-
128
-#define SEND_PGM(str)                           send_P(PSTR(str))
129
-#define SENDLINE_PGM(str)                       sendLine_P(PSTR(str))
130
-#define SENDVALUE_PGM(prefix, value)            sendValue_P(PSTR(prefix), value)
131
-#define SENDVALUELINE_PGM(prefix, value)        sendValueLine_P(PSTR(prefix), value)
36
+using namespace Anycubic;
132 37
 
133 38
 namespace ExtUI {
134 39
 
135
-  static void moveAxis(float delta, feedRate_t feedrate, axis_t axis) {
136
-    float pos = getAxisPosition_mm(axis);
137
-    pos += delta;
138
-    setAxisPosition_mm(pos, axis, feedrate);
139
-  }
140
-
141
-  static void handleCmd(const char *rx) {
142
-    static FileList fileList;
143
-    static char selectedFileShortName[8+1+3+1];
40
+  void onStartup() { Chiron.Startup(); }
144 41
 
145
-    if (rx[0] != 'A') {
146
-      SERIAL_ECHOPGM("Unexpected RX: ");
147
-      SERIAL_ECHOLN(rx);
42
+  void onIdle() { Chiron.IdleLoop(); }
148 43
 
149
-      return;
150
-    }
151
-
152
-    const int cmd = atoi(&rx[1]);
153
-
154
-    // Uncomment for debugging RX
155
-    //if (cmd > 7 && cmd != 20) {
156
-    //  SERIAL_ECHOPGM("RX: ");
157
-    //  SERIAL_ECHOLN(rx);
158
-    //}
159
-
160
-    switch (cmd) {
161
-      case 0: // Get Hotend Actual Temperature
162
-        SENDVALUELINE_PGM("A0V ", (int)getActualTemp_celsius(E0));
163
-        break;
164
-      case 1: // Get Hotend Target Temperature
165
-        SENDVALUELINE_PGM("A1V ", (int)getTargetTemp_celsius(E0));
166
-        break;
167
-      case 2: // Get Bed Actual Temperature
168
-        SENDVALUELINE_PGM("A2V ", (int)getActualTemp_celsius(BED));
169
-        break;
170
-      case 3: // Get Bed Target Temperature
171
-        SENDVALUELINE_PGM("A3V ", (int)getTargetTemp_celsius(BED));
172
-        break;
173
-      case 4: // Get Fan Speed
174
-        SENDVALUELINE_PGM("A4V ", (int)getTargetFan_percent(FAN0));
175
-        break;
176
-      case 5: // Get Current Coordinates
177
-        SENDVALUE_PGM("A5V X: ", getAxisPosition_mm(X));
178
-        SENDVALUE_PGM(" Y: ", getAxisPosition_mm(Y));
179
-        SENDVALUE_PGM(" Z: ", getAxisPosition_mm(Z));
180
-        sendNewLine();
181
-        break;
182
-      case 6: // Get SD Card Print Status
183
-        if (isPrintingFromMedia())
184
-          SENDVALUELINE_PGM("A6V ", (int)getProgress_percent());
185
-        else
186
-          SENDLINE_PGM("A6V ---");
187
-        break;
188
-      case 7: // Get Printing Time
189
-        if (isPrinting()) {
190
-          const int totalMinutes = getProgress_seconds_elapsed() / 60;
191
-          SENDVALUE_PGM("A7V ", (int)(totalMinutes/60));
192
-          SENDVALUE_PGM(" H ", (int)(totalMinutes%60));
193
-          SENDLINE_PGM(" M");
194
-        } else {
195
-          SENDLINE_PGM("A7V 999:999");
196
-        }
197
-        break;
198
-      case 8: // Get SD Card File List
199
-        if (isMediaInserted()) {
200
-          const int startIndex = parseIntArgument(rx, 'S');
201
-          SENDLINE_PGM("FN ");
202
-          for (int i = 0, fileIndex = 0, numFiles = 0; i < (int)fileList.count() && numFiles < 4; i++) {
203
-            fileList.seek(i);
204
-            if (!fileList.isDir()) {
205
-              if (fileIndex >= startIndex) {
206
-                sendLine(fileList.shortFilename());
207
-                sendLine(fileList.longFilename());
208
-                numFiles++;
209
-              }
210
-              fileIndex++;
211
-            }
212
-          }
213
-          SENDLINE_PGM("END");
214
-        } else {
215
-          SENDLINE_PGM("J02");
216
-        }
217
-        break;
218
-      case 9: // Pause SD Card Print
219
-        if (isPrintingFromMedia()) {
220
-          pausePrint();
221
-          is_printing_from_sd = false;
222
-          SENDLINE_PGM("J05");
223
-        } else {
224
-          SENDLINE_PGM("J16"); // Print stopped
225
-        }
226
-        break;
227
-      case 10: // Resume SD Card Print
228
-        if (is_out_of_filament) {
229
-          is_out_of_filament = false;
230
-          // Filament change did eject the old filament automatically,
231
-          // now continue and load the new one
232
-          setUserConfirmed();
233
-          SENDLINE_PGM("J04"); // Printing from SD card
234
-        } else if (isPrintingFromMediaPaused()) {
235
-          resumePrint();
236
-          SENDLINE_PGM("J04"); // Printing from SD card
237
-        }
238
-        break;
239
-      case 11: // Stop SD Card Print
240
-        if (isPrintingFromMedia()) {
241
-          stopPrint();
242
-          is_printing_from_sd = false;
243
-          SENDLINE_PGM("J16"); // Print stopped
244
-        }
245
-        break;
246
-      //case 12: // Kill
247
-      //  break;
248
-      case 13: // Select File
249
-        if (!isPrinting()) {
250
-          // Store selected file name
251
-          char *p = strchr(rx, ' ');
252
-          if (p != nullptr && strlen(p+1) < sizeof(selectedFileShortName)) {
253
-            strcpy(selectedFileShortName, p+1);
254
-            SENDLINE_PGM("J20"); // Open succeeded
255
-          }
256
-          else
257
-            SENDLINE_PGM("J21"); // Open failed
258
-        }
259
-        break;
260
-      case 14: // Start Print
261
-        if (!isPrinting() && strcmp(selectedFileShortName, "") != 0) {
262
-          printFile(selectedFileShortName);
263
-          is_printing_from_sd = true;
264
-          SENDLINE_PGM("J04"); // Printing from SD card
265
-        }
266
-        break;
267
-      case 15: // Resume from power outage
268
-        // This is not supported, just report print as completed
269
-        SENDLINE_PGM("J16"); // Print stopped
270
-        break;
271
-      case 16: // Set Hotend Target Temperature
272
-        {
273
-          int temp = parseIntArgument(rx, 'S');
274
-          if (temp >= 0)
275
-            setTargetTemp_celsius(temp, E0);
276
-        }
277
-        break;
278
-      case 17: // Set Bed Target Temperature
279
-        {
280
-          int temp = parseIntArgument(rx, 'S');
281
-          if (temp >= 0)
282
-            setTargetTemp_celsius(temp, BED);
283
-        }
284
-        break;
285
-      case 18: // Set Fan Speed
286
-        {
287
-          int temp = parseIntArgument(rx, 'S');
288
-          if (temp >= 0)
289
-            setTargetFan_percent(temp, FAN0);
290
-        }
291
-        break;
292
-      case 19: // Disable Motors
293
-        injectCommands_P(PSTR("M84"));
294
-        break;
295
-      case 20: // Get/Set Printing Speed
296
-        {
297
-          int newPerc = parseIntArgument(rx, 'S');
298
-          if (newPerc >= 0)
299
-            setFeedrate_percent(newPerc);
300
-          else
301
-            SENDVALUELINE_PGM("A20V ", (int)getFeedrate_percent());
302
-        }
303
-        break;
304
-      case 21: // Home axes
305
-        if (!isPrinting()) {
306
-          const bool hasX = strchr(rx, 'X') != nullptr,
307
-                     hasY = strchr(rx, 'Y') != nullptr,
308
-                     hasZ = strchr(rx, 'Z') != nullptr,
309
-                     hasC = strchr(rx, 'C') != nullptr;
310
-          if (hasX || hasY || hasZ) {
311
-            if (hasX) injectCommands_P(PSTR("G28 X"));
312
-            if (hasY) injectCommands_P(PSTR("G28 Y"));
313
-            if (hasZ) injectCommands_P(PSTR("G28 Z"));
314
-          } else if (hasC) {
315
-            injectCommands_P(PSTR("G28"));
316
-          }
317
-        }
318
-        break;
319
-      case 22: // Move axes
320
-        if (!isPrinting()) {
321
-          const int feedrate = parseIntArgument(rx, 'F') / 60;
322
-          float delta;
323
-          if (!isnan(delta = parseFloatArgument(rx, 'X')))
324
-            moveAxis(delta, feedrate, X);
325
-          else if (!isnan(delta = parseFloatArgument(rx, 'Y')))
326
-            moveAxis(delta, feedrate, Y);
327
-          else if (!isnan(delta = parseFloatArgument(rx, 'Z')))
328
-            moveAxis(delta, feedrate, Z);
329
-        }
330
-        break;
331
-      case 23: // Preheat PLA
332
-        setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, E0);
333
-        setTargetTemp_celsius(PREHEAT_1_TEMP_BED, BED);
334
-        SENDLINE_PGM("OK");
335
-        break;
336
-      case 24: // Preheat ABS
337
-        setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, E0);
338
-        setTargetTemp_celsius(PREHEAT_2_TEMP_BED, BED);
339
-        SENDLINE_PGM("OK");
340
-        break;
341
-      case 25: // Cool down
342
-        setTargetTemp_celsius(0, E0);
343
-        setTargetTemp_celsius(0, BED);
344
-        SENDLINE_PGM("J12");
345
-        break;
346
-      case 26: // Refresh SD Card
347
-        fileList.refresh();
348
-        break;
349
-      //case 27: // Adjust Servo Angles
350
-      //  break;
351
-      //case 28: // Filament Test
352
-      //  break;
353
-      case 29: // Get Bed Autolevel Grid
354
-        {
355
-          int x = parseIntArgument(rx, 'X'),
356
-              y = parseIntArgument(rx, 'Y');
357
-          if (x != -1 && y != -1) {
358
-            xy_uint8_t coord;
359
-            coord.set(x, y);
360
-            const int value = mmToHundredths(getMeshPoint(coord));
361
-            SENDVALUELINE_PGM("A29V ", value);
362
-          }
363
-        }
364
-        break;
365
-      case 30: // Autolevel
366
-        if (strchr(rx, 'S')) { // Autoleveling started by clicking "PROBE" and then "OK"
367
-          // Note:
368
-          //  We check for completion by monitoring the command queue.
369
-          //  Since it will become empty *while* processing the last injected command,
370
-          //  we enqueue an extra 10ms delay so we can the determine when all the others
371
-          //  have completed.
372
-          if (isMachineHomed())
373
-            injectCommands_P(PSTR("G29\nG4 P10"));
374
-          else
375
-            injectCommands_P(PSTR("G28\nG29\nG4 P10"));
376
-          is_auto_leveling = true;
377
-        } else { // Entering Autoleveling screen
378
-          if (isPrinting())
379
-            SENDLINE_PGM("J24"); // Disallow autoleveling
380
-          else
381
-            SENDLINE_PGM("J26"); // Allow autoleveling
382
-        }
383
-        break;
384
-      case 31: // Set Bed Autolevel Z offset
385
-        if (strchr(rx, 'G')) { // Get
386
-          SENDVALUELINE_PGM("A31V ", getZOffset_mm());
387
-        } else if (strchr(rx, 'S')) { // Set
388
-          float delta = parseFloatArgument(rx, 'S');
389
-          delta = constrain(delta, -1.0, 1.0);
390
-          setZOffset_mm(getZOffset_mm() + delta);
391
-
392
-          SENDVALUELINE_PGM("A31V ", getZOffset_mm());
393
-        } else if (strchr(rx, 'D')) { // Save
394
-          injectCommands_P(PSTR("M500"));
395
-        }
396
-        break;
397
-      //case 32: // ?
398
-      //  break;
399
-      case 33: // Get Version Info
400
-        SENDLINE_PGM("J33 " SHORT_BUILD_VERSION);
401
-        break;
402
-      case 34: // Set Bed Autolevel Grid
403
-        {
404
-          int x = parseIntArgument(rx, 'X'),
405
-              y = parseIntArgument(rx, 'Y'),
406
-              v = parseIntArgument(rx, 'V');
407
-          if (x != -1 && y != -1 && v != -1) { // Set new value
408
-            float value = hundredthsToMm(v);
409
-            value = constrain(value, -10, 10);
410
-
411
-            xy_uint8_t coord;
412
-            coord.set(x, y);
413
-            setMeshPoint(coord, value);
414
-          } else if (strchr(rx, 'S')) { // Save (apply new values)
415
-            injectCommands_P(PSTR("M500"));
416
-          } else if (strchr(rx, 'C')) { // Cancel (discard new values)
417
-            injectCommands_P(PSTR("M501"));
418
-          }
419
-        }
420
-        break;
421
-    }
44
+  void onPrinterKilled(PGM_P const error, PGM_P const component) {
45
+    Chiron.PrinterKilled(error,component);
422 46
   }
423 47
 
424
-  #define RX_LEN_MAX 63
425
-  static void parseSerialRx() {
426
-    static char rxBuffer[RX_LEN_MAX+1];
427
-    static uint8_t rxLen = 0;
48
+  void onMediaInserted() { Chiron.MediaEvent(AC_media_inserted); }
49
+  void onMediaError()    { Chiron.MediaEvent(AC_media_error);    }
50
+  void onMediaRemoved()  { Chiron.MediaEvent(AC_media_removed);  }
428 51
 
429
-    while (LCD_SERIAL.available()) {
430
-      const char c = LCD_SERIAL.read();
431
-      switch (c) {
432
-        case '\r': case '\n':
433
-          if (rxLen > 0 && rxLen <= RX_LEN_MAX) {
434
-            rxBuffer[rxLen] = '\0'; // Terminate string
435
-            handleCmd(rxBuffer);
436
-          }
437
-          rxLen = 0;
438
-          break;
439
-        default:
440
-          if (rxLen < RX_LEN_MAX)
441
-            rxBuffer[rxLen++] = c;
442
-          else {
443
-            rxLen = 0xFF; // Overrun
444
-            SERIAL_ECHOPGM("Warning: dropping long received line");
445
-          }
446
-          break;
447
-      }
448
-    }
449
-  }
450
-
451
-  static void detectPrintFromSdCompletion() {
452
-    // Note: printFile() queues some commands that actually start the print, so isPrintingFromMedia()
453
-    //       initially returns false
454
-    if (is_printing_from_sd && !commandsInQueue() && !isPrintingFromMedia()) {
455
-      is_printing_from_sd = false;
456
-      SENDLINE_PGM("J14"); // Print done
457
-    }
458
-  }
459
-
460
-  static void detectAutolevelingCompletion() {
461
-    if (is_auto_leveling && !commandsInQueue()) {
462
-      is_auto_leveling = false;
463
-      injectCommands_P(PSTR("M500"));
464
-      SENDLINE_PGM("J25"); // Autoleveling done
465
-    }
466
-  }
467
-
468
-  void onStartup() {
469
-    #ifndef LCD_BAUDRATE
470
-      #define LCD_BAUDRATE 115200
52
+  void onPlayTone(const uint16_t frequency, const uint16_t duration) {
53
+    #if ENABLED(SPEAKER)
54
+      ::tone(BEEPER_PIN, frequency, duration);
471 55
     #endif
472
-    LCD_SERIAL.begin(LCD_BAUDRATE);
473
-    sendNewLine();
474
-    SENDLINE_PGM("J17"); // Reset
475
-    delay_ms(10);
476
-    SENDLINE_PGM("J12"); // Ready
477 56
   }
478 57
 
479
-  void onIdle() {
480
-    parseSerialRx();
481
-    detectAutolevelingCompletion();
482
-    detectPrintFromSdCompletion();
483
-  }
58
+  void onPrintTimerStarted() { Chiron.TimerEvent(AC_timer_started); }
59
+  void onPrintTimerPaused()  { Chiron.TimerEvent(AC_timer_paused);  }
60
+  void onPrintTimerStopped()                         { Chiron.TimerEvent(AC_timer_stopped); }
61
+  void onFilamentRunout(const extruder_t)            { Chiron.FilamentRunout();             }
62
+  void onUserConfirmRequired(const char * const msg) { Chiron.ConfirmationRequest(msg);     }
63
+  void onStatusChanged(const char * const msg)       { Chiron.StatusChange(msg);            }
64
+
65
+  void onFactoryReset() {}
484 66
 
485
-  void onPrinterKilled(PGM_P const error, PGM_P const component) { }
67
+  void onStoreSettings(char *buff) {
68
+    // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
69
+    // permanent data to be stored, it can write up to eeprom_data_size bytes
70
+    // into buff.
486 71
 
487
-  void onMediaInserted() {
488
-    SENDLINE_PGM("J00"); // SD Inserted
72
+    // Example:
73
+    //  static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
74
+    //  memcpy(buff, &myDataStruct, sizeof(myDataStruct));
489 75
   }
490 76
 
491
-  void onMediaError() { }
77
+  void onLoadSettings(const char *buff) {
78
+    // Called while loading settings from EEPROM. If the ExtUI
79
+    // needs to retrieve data, it should copy up to eeprom_data_size bytes
80
+    // from buff
492 81
 
493
-  void onMediaRemoved() {
494
-    SENDLINE_PGM("J01"); // SD Removed
82
+    // Example:
83
+    //  static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
84
+    //  memcpy(&myDataStruct, buff, sizeof(myDataStruct));
495 85
   }
496 86
 
497
-  void onPlayTone(const uint16_t frequency, const uint16_t duration) {
498
-    tone(BEEPER_PIN, frequency, duration);
87
+  void onConfigurationStoreWritten(bool success) {
88
+    // Called after the entire EEPROM has been written,
89
+    // whether successful or not.
499 90
   }
500 91
 
501
-  void onPrintTimerStarted() { }
502
-
503
-  void onPrintTimerPaused() { }
504
-
505
-  void onPrintTimerStopped() { }
506
-
507
-  void onFilamentRunout(const extruder_t extruder) {
508
-    is_out_of_filament = true;
509
-    SENDLINE_PGM("J23"); // Filament runout
510
-    SENDLINE_PGM("J18"); // Print paused
511
-    // Note: printer will unload filament automatically
92
+  void onConfigurationStoreRead(bool success) {
93
+    // Called after the entire EEPROM has been read,
94
+    // whether successful or not.
512 95
   }
513 96
 
514
-  void onUserConfirmRequired(const char * const msg) { }
515
-
516
-  void onStatusChanged(const char * const msg) { }
517
-
518
-  void onFactoryReset() { }
519
-
520
-  void onStoreSettings(char *buff) { }
521
-
522
-  void onLoadSettings(const char *buff) { }
523
-
524
-  void onConfigurationStoreWritten(bool success) { }
525
-
526
-  void onConfigurationStoreRead(bool success) { }
97
+  #if HAS_MESH
98
+    void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {
99
+      // Called when any mesh points are updated
100
+      //SERIAL_ECHOLNPAIR("onMeshUpdate() x:", xpos, " y:", ypos, " z:", zval);
101
+    }
527 102
 
528
-  void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) { }
103
+    void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) {
104
+      // Called to indicate a special condition
105
+      //SERIAL_ECHOLNPAIR("onMeshUpdate() x:", xpos, " y:", ypos, " state:", state);
106
+    }
107
+  #endif
529 108
 
530 109
   #if ENABLED(POWER_LOSS_RECOVERY)
531
-    void onPowerLossResume() { }
110
+    // Called on resume from power-loss
111
+    void onPowerLossResume() { Chiron.PowerLossRecovery(); }
532 112
   #endif
533 113
 
534 114
   #if HAS_PID_HEATING
535
-    void onPidTuning(const result_t rst) { }
115
+    void onPidTuning(const result_t rst) {
116
+      // Called for temperature PID tuning result
117
+    }
536 118
   #endif
537 119
 }
538 120
 

+ 162
- 0
Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp View File

@@ -0,0 +1,162 @@
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
+
23
+/**
24
+ * lcd/extui/lib/FileNavigator.cpp
25
+ *
26
+ * Extensible_UI implementation for Anycubic Chiron
27
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
28
+ *  (not affiliated with Anycubic, Ltd.)
29
+ */
30
+
31
+/***************************************************************************
32
+ * The AC panel wants files in block of 4 and can only display a flat list *
33
+ * This library allows full folder traversal.                              *
34
+ ***************************************************************************/
35
+
36
+#include "../../../../inc/MarlinConfigPre.h"
37
+
38
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
39
+
40
+#include "FileNavigator.h"
41
+#include "chiron_tft.h"
42
+
43
+using namespace ExtUI;
44
+
45
+namespace Anycubic {
46
+
47
+  FileList  FileNavigator::filelist;                          // Instance of the Marlin file API
48
+  char      FileNavigator::currentfoldername[MAX_PATH_LEN];   // Current folder path
49
+  uint16_t  FileNavigator::lastindex;
50
+  uint8_t   FileNavigator::folderdepth;
51
+  uint16_t  FileNavigator::currentindex;                      // override the panel request
52
+
53
+  FileNavigator::FileNavigator() { reset(); }
54
+
55
+  void FileNavigator::reset() {
56
+    currentfoldername[0] = '\0';
57
+    folderdepth  = 0;
58
+    currentindex = 0;
59
+    lastindex    = 0;
60
+    // Start at root folder
61
+    while (!filelist.isAtRootDir()) filelist.upDir();
62
+    refresh();
63
+  }
64
+
65
+  void FileNavigator::refresh() { filelist.refresh(); }
66
+
67
+  void FileNavigator::getFiles(uint16_t index) {
68
+    uint8_t files = 4;
69
+    if (index == 0) currentindex = 0;
70
+
71
+    // Each time we change folder we reset the file index to 0 and keep track
72
+    // of the current position as the TFT panel isnt aware of folders trees.
73
+    if (index > 0) {
74
+      --currentindex; // go back a file to take account off the .. we added to the root.
75
+      if (index > lastindex)
76
+        currentindex += files;
77
+      else
78
+        currentindex = currentindex < 4 ? 0 : currentindex - files;
79
+    }
80
+    lastindex = index;
81
+
82
+    #if ACDEBUG(AC_FILE)
83
+      SERIAL_ECHOLNPAIR("index=", index, " currentindex=", currentindex);
84
+    #endif
85
+
86
+    if (currentindex == 0 && folderdepth > 0) { // Add a link to go up a folder
87
+      TFTSer.println("<<");
88
+      TFTSer.println("..");
89
+      files--;
90
+    }
91
+
92
+    for (uint16_t seek = currentindex; seek < currentindex + files; seek++) {
93
+      if (filelist.seek(seek)) {
94
+        sendFile();
95
+        #if ACDEBUG(AC_FILE)
96
+          SERIAL_ECHOLNPAIR("-", seek, " '", filelist.longFilename(), "' '", currentfoldername, "", filelist.shortFilename(), "'\n");
97
+        #endif
98
+      }
99
+    }
100
+  }
101
+
102
+  void FileNavigator::sendFile() {
103
+    // send the file and folder info to the panel
104
+    // this info will be returned when the file is selected
105
+    // Permitted special characters in file name -_*#~
106
+    // Panel can display 22 characters per line
107
+    if (filelist.isDir()) {
108
+      //TFTSer.print(currentfoldername);
109
+      TFTSer.println(filelist.shortFilename());
110
+      TFTSer.print(filelist.shortFilename());
111
+      TFTSer.println("/");
112
+    }
113
+    else {
114
+      // Logical Name
115
+      TFTSer.print("/");
116
+      if (folderdepth > 0) TFTSer.print(currentfoldername);
117
+
118
+      TFTSer.println(filelist.shortFilename());
119
+
120
+      // Display Name
121
+      TFTSer.println(filelist.longFilename());
122
+    }
123
+  }
124
+  void FileNavigator::changeDIR(char *folder) {
125
+    #if ACDEBUG(AC_FILE)
126
+      SERIAL_ECHOLNPAIR("currentfolder: ", currentfoldername, "  New: ", folder);
127
+    #endif
128
+    if (folderdepth >= MAX_FOLDER_DEPTH) return; // limit the folder depth
129
+    strcat(currentfoldername, folder);
130
+    strcat(currentfoldername, "/");
131
+    filelist.changeDir(folder);
132
+    refresh();
133
+    folderdepth++;
134
+    currentindex = 0;
135
+  }
136
+
137
+  void FileNavigator::upDIR() {
138
+    filelist.upDir();
139
+    refresh();
140
+    folderdepth--;
141
+    currentindex = 0;
142
+    // Remove the last child folder from the stored path
143
+    if (folderdepth == 0) {
144
+      currentfoldername[0] = '\0';
145
+      reset();
146
+    }
147
+    else {
148
+      char *pos = nullptr;
149
+      for (uint8_t f = 0; f < folderdepth; f++)
150
+        pos = strchr(currentfoldername, '/');
151
+
152
+      *(pos + 1) = '\0';
153
+    }
154
+    #if ACDEBUG(AC_FILE)
155
+      SERIAL_ECHOLNPAIR("depth: ", folderdepth, " currentfoldername: ", currentfoldername);
156
+    #endif
157
+  }
158
+
159
+  char* FileNavigator::getCurrentFolderName() { return currentfoldername; }
160
+}
161
+
162
+#endif // ANYCUBIC_LCD_CHIRON

+ 56
- 0
Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h View File

@@ -0,0 +1,56 @@
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
+#pragma once
23
+
24
+/**
25
+ * lcd/extui/lib/FileNavigator.h
26
+ *
27
+ * Extensible_UI implementation for Anycubic Chiron
28
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
29
+ *  (not affiliated with Anycubic, Ltd.)
30
+ */
31
+
32
+#include "chiron_tft_defs.h"
33
+#include "../../ui_api.h"
34
+
35
+using namespace ExtUI;
36
+
37
+namespace Anycubic {
38
+  class FileNavigator {
39
+    public:
40
+      FileNavigator();
41
+      void   reset();
42
+      void   getFiles(uint16_t);
43
+      void   upDIR();
44
+      void   changeDIR(char *);
45
+      void   sendFile();
46
+      void   refresh();
47
+      char * getCurrentFolderName();
48
+    private:
49
+      static FileList  filelist;
50
+      static char      currentfoldername[MAX_PATH_LEN];
51
+      static uint16_t  lastindex;
52
+      static uint8_t   folderdepth;
53
+      static uint16_t  currentindex;
54
+  };
55
+  extern FileNavigator filenavigator;
56
+}

+ 62
- 0
Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.cpp View File

@@ -0,0 +1,62 @@
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
+
23
+/**
24
+ * lcd/extui/lib/Tunes.cpp
25
+ *
26
+ * Extensible_UI implementation for Anycubic Chiron
27
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
28
+ *  (not affiliated with Anycubic, Ltd.)
29
+ */
30
+
31
+/***********************************************************************
32
+ * A Utility to play tunes using the buzzer in the printer controller. *
33
+ * See Tunes.h for note and tune definitions.                          *
34
+ ***********************************************************************/
35
+
36
+#include "../../../../inc/MarlinConfigPre.h"
37
+
38
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
39
+
40
+#include "Tunes.h"
41
+#include "../../ui_api.h"
42
+
43
+namespace Anycubic {
44
+
45
+  void PlayTune(uint8_t beeperPin, const uint16_t *tune, uint8_t speed=1) {
46
+    uint8_t pos = 1;
47
+    uint16_t wholenotelen = tune[0] / speed;
48
+    do {
49
+      uint16_t freq = tune[pos];
50
+      uint16_t notelen = wholenotelen / tune[pos + 1];
51
+
52
+      ::tone(beeperPin, freq, notelen);
53
+      ExtUI::delay_ms(notelen);
54
+      pos += 2;
55
+
56
+      if (pos >= MAX_TUNE_LENGTH) break;
57
+    } while (tune[pos] != n_END);
58
+  }
59
+
60
+}
61
+
62
+#endif // ANYCUBIC_LCD_CHIRON

+ 224
- 0
Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.h View File

@@ -0,0 +1,224 @@
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
+#pragma once
23
+
24
+/**
25
+ * lcd/extui/lib/Tunes.h
26
+ *
27
+ * Extensible_UI implementation for Anycubic Chiron
28
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
29
+ *  (not affiliated with Anycubic, Ltd.)
30
+ */
31
+
32
+/**************************************************************************
33
+ * Notes definition from https://pages.mtu.edu/~suits/NoteFreqCalcs.html  *
34
+ *                                                                        *
35
+ * The format of a tune is:                                               *
36
+ * {<whole note time>,<note1>,<length1>, <note2>,<length2>, ... <END>}    *
37
+ *                                                                        *
38
+ * 1) The first value is the length of a whole note in milliseconds       *
39
+ * 2) Then a sequence of pitch and duration pairs                         *
40
+ * 3) Finally the END marker so your tunes can be any length up to        *
41
+ *    MAX_TUNE_LEN                                                        *
42
+ *************************************************************************/
43
+
44
+#include <stdint.h>
45
+
46
+#define MAX_TUNE_LENGTH 128
47
+
48
+// Special notes!
49
+#define n_P    0       // silence or pause
50
+#define n_END  10000   // end of tune marker
51
+
52
+// Note duration divisors
53
+#define l_T1   1
54
+#define l_T2   2
55
+#define l_T3   3
56
+#define l_T4   4
57
+#define l_T8   8
58
+#define l_T16 16
59
+
60
+// Note Frequency
61
+#define n_C0     16
62
+#define n_CS0    17
63
+#define n_D0     18
64
+#define n_DS0    19
65
+#define n_E0     21
66
+#define n_F0     22
67
+#define n_FS0    23
68
+#define n_G0     25
69
+#define n_GS0    26
70
+#define n_A0     28
71
+#define n_AS0    29
72
+#define n_B0     31
73
+#define n_C1     33
74
+#define n_CS1    35
75
+#define n_D1     37
76
+#define n_DS1    39
77
+#define n_E1     41
78
+#define n_F1     44
79
+#define n_FS1    46
80
+#define n_G1     49
81
+#define n_GS1    52
82
+#define n_A1     55
83
+#define n_AS1    58
84
+#define n_B1     62
85
+#define n_C2     65
86
+#define n_CS2    69
87
+#define n_D2     73
88
+#define n_DS2    78
89
+#define n_E2     82
90
+#define n_F2     87
91
+#define n_FS2    93
92
+#define n_G2     98
93
+#define n_GS2   104
94
+#define n_A2    110
95
+#define n_AS2   117
96
+#define n_B2    123
97
+#define n_C3    131
98
+#define n_CS3   139
99
+#define n_D3    147
100
+#define n_DS3   156
101
+#define n_E3    165
102
+#define n_F3    175
103
+#define n_FS3   185
104
+#define n_G3    196
105
+#define n_GS3   208
106
+#define n_A3    220
107
+#define n_AS3   233
108
+#define n_B3    247
109
+#define n_C4    262
110
+#define n_CS4   277
111
+#define n_D4    294
112
+#define n_DS4   311
113
+#define n_E4    330
114
+#define n_F4    349
115
+#define n_FS4   370
116
+#define n_G4    392
117
+#define n_GS4   415
118
+#define n_A4    440
119
+#define n_AS4   466
120
+#define n_B4    494
121
+#define n_C5    523
122
+#define n_CS5   554
123
+#define n_D5    587
124
+#define n_DS5   622
125
+#define n_E5    659
126
+#define n_F5    698
127
+#define n_FS5   740
128
+#define n_G5    784
129
+#define n_GS5   831
130
+#define n_A5    880
131
+#define n_AS5   932
132
+#define n_B5    988
133
+#define n_C6   1047
134
+#define n_CS6  1109
135
+#define n_D6   1175
136
+#define n_DS6  1245
137
+#define n_E6   1319
138
+#define n_F6   1397
139
+#define n_FS6  1480
140
+#define n_G6   1568
141
+#define n_GS6  1661
142
+#define n_A6   1760
143
+#define n_AS6  1865
144
+#define n_B6   1976
145
+#define n_C7   2093
146
+#define n_CS7  2217
147
+#define n_D7   2349
148
+#define n_DS7  2489
149
+#define n_E7   2637
150
+#define n_F7   2794
151
+#define n_FS7  2960
152
+#define n_G7   3136
153
+#define n_GS7  3322
154
+#define n_A7   3520
155
+#define n_AS7  3729
156
+#define n_B7   3951
157
+#define n_C8   4186
158
+#define n_CS8  4435
159
+#define n_D8   4699
160
+#define n_DS8  4978
161
+#define n_E8   5274
162
+#define n_F8   5587
163
+#define n_FS8  5920
164
+#define n_G8   6272
165
+#define n_GS8  6645
166
+#define n_A8   7040
167
+#define n_AS8  7459
168
+#define n_B8   7902
169
+
170
+namespace Anycubic {
171
+
172
+  void PlayTune(uint8_t beeperPin, const uint16_t *tune, uint8_t speed);
173
+
174
+  // Only uncomment the tunes you are using to save memory
175
+  // This will help you write tunes!
176
+  // https://www.apronus.com/music/flashpiano.htm
177
+
178
+  const uint16_t SOS[] = {
179
+    250,
180
+    n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T1,
181
+    n_G6,l_T1, n_P,l_T3, n_G6,l_T1, n_P,l_T3, n_G6,l_T1, n_P,l_T1,
182
+    n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T1,
183
+    n_END
184
+  };
185
+
186
+  const uint16_t BeepBeep[] = {
187
+    500,
188
+    n_C7,l_T8, n_P,l_T16, n_C7,l_T8, n_P,l_T8,
189
+    n_END
190
+  };
191
+
192
+  const uint16_t BeepBeepBeeep[] = {
193
+    1000,
194
+    n_G7,l_T4, n_P,l_T16, n_G7,l_T4, n_P,l_T8, n_G7,l_T2,
195
+    n_END
196
+  };
197
+
198
+  const uint16_t Anycubic_PowerOn[] = {
199
+    1000,
200
+    n_F7,l_T8, n_P,l_T8, n_C7,l_T8, n_P,l_T8, n_D7,l_T8, n_P,l_T8,
201
+    n_E7,l_T8, n_P,l_T8, n_D7,l_T4, n_P,l_T4, n_G7,l_T4, n_P,l_T4,
202
+    n_A7,l_T2, n_P,l_T1,
203
+    n_END
204
+  };
205
+
206
+  const uint16_t GB_PowerOn[] = {
207
+    500,
208
+    n_C6,l_T4, n_P,l_T16, n_C7,l_T2, n_P,l_T8,
209
+    n_END
210
+  };
211
+
212
+  const uint16_t Heater_Timedout[] = {
213
+    1000,
214
+    n_C6,l_T1,
215
+    n_END
216
+  };
217
+
218
+  const uint16_t FilamentOut[] = {
219
+    1000,
220
+    n_AS7,l_T4, n_P,l_T16, n_FS7,l_T2,
221
+    n_END
222
+  };
223
+
224
+}

+ 896
- 0
Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp View File

@@ -0,0 +1,896 @@
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
+
23
+/**
24
+ * lcd/extui/lib/chiron_tft.cpp
25
+ *
26
+ * Extensible_UI implementation for Anycubic Chiron
27
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
28
+ *  (not affiliated with Anycubic, Ltd.)
29
+ */
30
+
31
+#include "../../../../inc/MarlinConfigPre.h"
32
+
33
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
34
+
35
+#include "chiron_tft.h"
36
+#include "Tunes.h"
37
+#include "FileNavigator.h"
38
+
39
+#include "../../../../gcode/queue.h"
40
+#include "../../../../sd/cardreader.h"
41
+#include "../../../../libs/numtostr.h"
42
+#include "../../../../MarlinCore.h"
43
+namespace Anycubic {
44
+
45
+  printer_state_t  ChironTFT::printer_state;
46
+  paused_state_t   ChironTFT::pause_state;
47
+  heater_state_t   ChironTFT::hotend_state;
48
+  heater_state_t   ChironTFT::hotbed_state;
49
+  xy_uint8_t       ChironTFT::selectedmeshpoint;
50
+  char             ChironTFT::selectedfile[MAX_PATH_LEN];
51
+  char             ChironTFT::panel_command[MAX_CMND_LEN];
52
+  uint8_t          ChironTFT::command_len;
53
+  float            ChironTFT::live_Zoffset;
54
+  file_menu_t      ChironTFT::file_menu;
55
+
56
+  ChironTFT::ChironTFT(){}
57
+
58
+  void ChironTFT::Startup() {
59
+    selectedfile[0]   = '\0';
60
+    panel_command[0]  = '\0';
61
+    command_len       = 0;
62
+    printer_state     = AC_printer_idle;
63
+    pause_state       = AC_paused_idle;
64
+    hotend_state      = AC_heater_off;
65
+    hotbed_state      = AC_heater_off;
66
+    live_Zoffset      = 0.0;
67
+    file_menu         = AC_menu_file;
68
+
69
+    // Setup pins for powerloss detection
70
+    // Two IO pins are connected on the Trigorilla Board
71
+    // On a power interruption the OUTAGECON_PIN goes low.
72
+
73
+    #if ENABLED(POWER_LOSS_RECOVERY)
74
+      OUT_WRITE(OUTAGECON_PIN, HIGH);
75
+    #endif
76
+
77
+    // Filament runout is handled by Marlin settings in Configuration.h
78
+    // set FIL_RUNOUT_STATE HIGH  // Pin state indicating that filament is NOT present.
79
+    // enable FIL_RUNOUT_PULLUP
80
+
81
+    TFTSer.begin(115200);
82
+
83
+    // Signal Board has reset
84
+    SendtoTFTLN(AC_msg_main_board_has_reset);
85
+
86
+    safe_delay(200);
87
+
88
+    // Enable levelling and Disable end stops during print
89
+    // as Z home places nozzle above the bed so we need to allow it past the end stops
90
+    injectCommands_P(AC_cmnd_enable_levelling); //M211 S0\n"));
91
+
92
+    // Startup tunes are defined in Tunes.h
93
+    //PlayTune(BEEPER_PIN, Anycubic_PowerOn, 1);
94
+    PlayTune(BEEPER_PIN, GB_PowerOn, 1);
95
+    #if ACDEBUGLEVEL
96
+      SERIAL_ECHOLNPAIR("AC Debug Level ", ACDEBUGLEVEL);
97
+    #endif
98
+    SendtoTFTLN(AC_msg_ready);
99
+  }
100
+
101
+  void ChironTFT::IdleLoop()  {
102
+    if (ReadTFTCommand()) {
103
+      ProcessPanelRequest();
104
+      command_len = 0;
105
+    }
106
+    CheckHeaters();
107
+  }
108
+
109
+  void ChironTFT::PrinterKilled(PGM_P error,PGM_P component)  {
110
+    SendtoTFTLN(AC_msg_kill_lcd);
111
+    #if ACDEBUG(AC_MARLIN)
112
+      SERIAL_ECHOLNPAIR("PrinterKilled()\nerror: ", error , "\ncomponent: ", component);
113
+    #endif
114
+  }
115
+
116
+  void ChironTFT::MediaEvent(media_event_t event)  {
117
+    #if ACDEBUG(AC_MARLIN)
118
+      SERIAL_ECHOLNPAIR("ProcessMediaStatus() ", event);
119
+    #endif
120
+    switch (event) {
121
+      case AC_media_inserted:
122
+        SendtoTFTLN(AC_msg_sd_card_inserted);
123
+      break;
124
+
125
+      case AC_media_removed:
126
+        SendtoTFTLN(AC_msg_sd_card_removed);
127
+      break;
128
+
129
+      case AC_media_error:
130
+        SendtoTFTLN(AC_msg_no_sd_card);
131
+      break;
132
+    }
133
+  }
134
+
135
+  void ChironTFT::TimerEvent(timer_event_t event)  {
136
+    #if ACDEBUG(AC_MARLIN)
137
+      SERIAL_ECHOLNPAIR("TimerEvent() ", event);
138
+      SERIAL_ECHOLNPAIR("Printer State: ", printer_state);
139
+    #endif
140
+
141
+    switch (event) {
142
+      case AC_timer_started: {
143
+        live_Zoffset = 0.0; // reset print offset
144
+        setSoftEndstopState(false);  // disable endstops to print
145
+        printer_state = AC_printer_printing;
146
+        SendtoTFTLN(AC_msg_print_from_sd_card);
147
+      } break;
148
+
149
+      case AC_timer_paused: {
150
+        printer_state = AC_printer_paused;
151
+        pause_state   = AC_paused_idle;
152
+        SendtoTFTLN(AC_msg_paused);
153
+      } break;
154
+
155
+      case AC_timer_stopped: {
156
+        if (printer_state != AC_printer_idle) {
157
+          printer_state = AC_printer_stopping;
158
+          SendtoTFTLN(AC_msg_print_complete);
159
+        }
160
+        setSoftEndstopState(true); // enable endstops
161
+      } break;
162
+    }
163
+  }
164
+
165
+  void ChironTFT::FilamentRunout()  {
166
+    #if ACDEBUG(AC_MARLIN)
167
+      SERIAL_ECHOLNPAIR("FilamentRunout() printer_state ", printer_state);
168
+    #endif
169
+    // 1 Signal filament out
170
+    SendtoTFTLN(isPrintingFromMedia() ? AC_msg_filament_out_alert : AC_msg_filament_out_block);
171
+    //printer_state = AC_printer_filament_out;
172
+    PlayTune(BEEPER_PIN, FilamentOut, 1);
173
+  }
174
+
175
+  void ChironTFT::ConfirmationRequest(const char * const msg)  {
176
+    // M108 continue
177
+    #if ACDEBUG(AC_MARLIN)
178
+      SERIAL_ECHOLNPAIR("ConfirmationRequest() ", msg, " printer_state:", printer_state);
179
+    #endif
180
+    switch (printer_state) {
181
+      case AC_printer_pausing: {
182
+        if ( (strcmp_P(msg, MARLIN_msg_print_paused) == 0 ) || (strcmp_P(msg, MARLIN_msg_nozzle_parked) == 0 ) ) {
183
+          SendtoTFTLN(AC_msg_paused); // enable continue button
184
+          printer_state = AC_printer_paused;
185
+        }
186
+      } break;
187
+
188
+      case AC_printer_resuming_from_power_outage:
189
+      case AC_printer_printing:
190
+      case AC_printer_paused: {
191
+        // Heater timout, send acknowledgement
192
+        if (strcmp_P(msg, MARLIN_msg_heater_timeout) == 0 ) {
193
+          pause_state = AC_paused_heater_timed_out;
194
+          SendtoTFTLN(AC_msg_paused); // enable continue button
195
+          PlayTune(BEEPER_PIN,Heater_Timedout,1);
196
+        }
197
+        // Reheat finished, send acknowledgement
198
+        else if (strcmp_P(msg, MARLIN_msg_reheat_done) == 0 ) {
199
+          pause_state = AC_paused_idle;
200
+          SendtoTFTLN(AC_msg_paused); // enable continue button
201
+        }
202
+        // Filament Purging, send acknowledgement enter run mode
203
+        else if (strcmp_P(msg, MARLIN_msg_filament_purging) == 0 ) {
204
+          pause_state = AC_paused_purging_filament;
205
+          SendtoTFTLN(AC_msg_paused); // enable continue button
206
+        }
207
+      } break;
208
+      default:
209
+      break;
210
+    }
211
+  }
212
+
213
+  void ChironTFT::StatusChange(const char * const msg)  {
214
+    #if ACDEBUG(AC_MARLIN)
215
+      SERIAL_ECHOLNPAIR("StatusChange() ", msg);
216
+      SERIAL_ECHOLNPAIR("printer_state:", printer_state);
217
+    #endif
218
+    bool msg_matched = false;
219
+    // The only way to get printer status is to parse messages
220
+    // Use the state to minimise the work we do here.
221
+    switch (printer_state) {
222
+      case AC_printer_probing: {
223
+        // If probing completes ok save the mesh and park
224
+        if (strcmp_P(msg, MARLIN_msg_ready) == 0 ) {
225
+          injectCommands_P(PSTR("M500\nG27"));
226
+          SendtoTFTLN(AC_msg_probing_complete);
227
+          printer_state = AC_printer_idle;
228
+          msg_matched = true;
229
+        }
230
+        // If probing fails dont save the mesh raise the probe above the bad point
231
+        if (strcmp_P(msg, MARLIN_msg_probing_failed) == 0 ) {
232
+          PlayTune(BEEPER_PIN, BeepBeepBeeep, 1);
233
+          injectCommands_P(PSTR("G1 Z50 F500"));
234
+          SendtoTFTLN(AC_msg_probing_complete);
235
+          printer_state = AC_printer_idle;
236
+          msg_matched = true;
237
+        }
238
+      } break;
239
+
240
+      case AC_printer_printing: {
241
+        if (strcmp_P(msg, MARLIN_msg_reheating) == 0 ) {
242
+          SendtoTFTLN(AC_msg_paused); // enable continue button
243
+          msg_matched = true;
244
+         }
245
+      } break;
246
+
247
+      case AC_printer_pausing: {
248
+        if (strcmp_P(msg, MARLIN_msg_print_paused) == 0 ) {
249
+          SendtoTFTLN(AC_msg_paused);
250
+          printer_state = AC_printer_paused;
251
+          pause_state = AC_paused_idle;
252
+          msg_matched = true;
253
+         }
254
+      } break;
255
+
256
+      case AC_printer_stopping: {
257
+        if (strcmp_P(msg, MARLIN_msg_print_aborted) == 0 ) {
258
+          SendtoTFTLN(AC_msg_stop);
259
+          printer_state = AC_printer_idle;
260
+          msg_matched = true;
261
+        }
262
+      } break;
263
+      default:
264
+      break;
265
+    }
266
+
267
+    // If not matched earlier see if this was a heater message
268
+    if (!msg_matched) {
269
+      if (strcmp_P(msg, MARLIN_msg_extruder_heating) == 0) {
270
+        SendtoTFTLN(AC_msg_nozzle_heating);
271
+        hotend_state = AC_heater_temp_set;
272
+      }
273
+      else if (strcmp_P(msg, MARLIN_msg_bed_heating) == 0) {
274
+        SendtoTFTLN(AC_msg_bed_heating);
275
+        hotbed_state = AC_heater_temp_set;
276
+      }
277
+    }
278
+  }
279
+
280
+  void ChironTFT::PowerLossRecovery()  {
281
+    printer_state = AC_printer_resuming_from_power_outage; // Play tune to notify user we can recover.
282
+    PlayTune(BEEPER_PIN, SOS, 1);
283
+    SERIAL_ECHOLNPGM("Resuming from power outage...");
284
+    SERIAL_ECHOLNPGM("Select SD file then press resume");
285
+  }
286
+
287
+  void ChironTFT::SendtoTFT(PGM_P str) {  // A helper to print PROGMEN string to the panel
288
+    #if ACDEBUG(AC_SOME)
289
+      serialprintPGM(str);
290
+    #endif
291
+    while (const char c = pgm_read_byte(str++)) TFTSer.print(c);
292
+    }
293
+
294
+  void ChironTFT::SendtoTFTLN(PGM_P str = nullptr) {
295
+    if (str != nullptr) {
296
+      #if ACDEBUG(AC_SOME)
297
+        SERIAL_ECHO("> ");
298
+      #endif
299
+      SendtoTFT(str);
300
+      #if ACDEBUG(AC_SOME)
301
+        SERIAL_EOL();
302
+      #endif
303
+   }
304
+   TFTSer.println("");
305
+  }
306
+
307
+  bool ChironTFT::ReadTFTCommand() {
308
+    bool command_ready = false;
309
+    while( (TFTSer.available() > 0) && (command_len < MAX_CMND_LEN) ) {
310
+      panel_command[command_len] = TFTSer.read();
311
+      if(panel_command[command_len] == '\n') {
312
+        command_ready = true;
313
+        break;
314
+      }
315
+      command_len++;
316
+    }
317
+
318
+    if(command_ready) {
319
+      panel_command[command_len] = 0x00;
320
+      #if ACDEBUG(AC_ALL)
321
+        SERIAL_ECHOLNPAIR("< ", panel_command);
322
+      #endif
323
+      #if ACDEBUG(AC_SOME)
324
+        // Ignore status request commands
325
+        uint8_t req = atoi(&panel_command[1]);
326
+        if (req > 7 && req != 20) {
327
+          SERIAL_ECHOLNPAIR("> ", panel_command);
328
+          SERIAL_ECHOLNPAIR("printer_state:", printer_state);
329
+        }
330
+      #endif
331
+    }
332
+    return command_ready;
333
+  }
334
+
335
+  int8_t ChironTFT::Findcmndpos(const char * buff, char q) {
336
+    bool found = false;
337
+    int8_t pos = 0;
338
+    do {
339
+      if (buff[pos] == q) {
340
+        found = true;
341
+        break;
342
+      }
343
+      pos ++;
344
+    } while(pos < MAX_CMND_LEN);
345
+    if (found) return pos;
346
+    return -1;
347
+  }
348
+
349
+  void ChironTFT::CheckHeaters() {
350
+    uint8_t faultDuration = 0; float temp = 0;
351
+
352
+    // if the hotend temp is abnormal, confirm state before signalling panel
353
+    temp = getActualTemp_celsius(E0);
354
+    if ( (temp <= HEATER_0_MINTEMP) || (temp >= HEATER_0_MAXTEMP) ) {
355
+      do {
356
+        faultDuration ++;
357
+        if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) {
358
+          SendtoTFTLN(AC_msg_nozzle_temp_abnormal);
359
+          SERIAL_ECHOLNPAIR("Extruder temp abnormal! : ", temp);
360
+          break;
361
+        }
362
+        delay_ms(500);
363
+        temp = getActualTemp_celsius(E0);
364
+      } while ((temp <= HEATER_0_MINTEMP) || (temp >= HEATER_0_MAXTEMP) );
365
+    }
366
+
367
+    // if the hotbed temp is abnormal, confirm state before signalling panel
368
+    faultDuration = 0;
369
+    temp = getActualTemp_celsius(BED);
370
+    if ( (temp <= BED_MINTEMP) || (temp >= BED_MAXTEMP) ) {
371
+      do {
372
+        faultDuration ++;
373
+        if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) {
374
+          SendtoTFTLN(AC_msg_nozzle_temp_abnormal);
375
+          SERIAL_ECHOLNPAIR_P("Bed temp abnormal! : ", temp);
376
+        break;
377
+        }
378
+        delay_ms(500);
379
+        temp = getActualTemp_celsius(E0);
380
+      } while ((temp <= BED_MINTEMP) || (temp >= BED_MAXTEMP) );
381
+    }
382
+
383
+    // Update panel with hotend heater status
384
+    if (hotend_state != AC_heater_temp_reached) {
385
+      if ( WITHIN( getActualTemp_celsius(E0) - getTargetTemp_celsius(E0), -1, 1 ) ) {
386
+        SendtoTFTLN(AC_msg_nozzle_heating_done);
387
+        hotend_state = AC_heater_temp_reached;
388
+      }
389
+    }
390
+
391
+    // Update panel with bed heater status
392
+    if (hotbed_state != AC_heater_temp_reached) {
393
+      if ( WITHIN( getActualTemp_celsius(BED) - getTargetTemp_celsius(BED), -0.5, 0.5 ) ) {
394
+        SendtoTFTLN(AC_msg_bed_heating_done);
395
+        hotbed_state = AC_heater_temp_reached;
396
+      }
397
+    }
398
+  }
399
+
400
+  void ChironTFT::SendFileList(int8_t startindex) {
401
+    // respond to panel request for 4 files starting at index
402
+    #if ACDEBUG(AC_INFO)
403
+      SERIAL_ECHOLNPAIR("## SendFileList ## ", startindex);
404
+    #endif
405
+    SendtoTFTLN(PSTR("FN "));
406
+    filenavigator.getFiles(startindex);
407
+    SendtoTFTLN(PSTR("END"));
408
+  }
409
+
410
+  void ChironTFT::SelectFile() {
411
+    strncpy(selectedfile,panel_command+4,command_len-4);
412
+    selectedfile[command_len-5] = '\0';
413
+    #if ACDEBUG(AC_FILE)
414
+      SERIAL_ECHOLNPAIR_F(" Selected File: ",selectedfile);
415
+    #endif
416
+    switch (selectedfile[0]) {
417
+      case '/':   // Valid file selected
418
+        SendtoTFTLN(AC_msg_sd_file_open_success);
419
+        break;
420
+
421
+      case '<':   // .. (go up folder level)
422
+        filenavigator.upDIR();
423
+        SendtoTFTLN(AC_msg_sd_file_open_failed);
424
+        SendFileList( 0 );
425
+        break;
426
+      default:   // enter sub folder
427
+        filenavigator.changeDIR(selectedfile);
428
+        SendtoTFTLN(AC_msg_sd_file_open_failed);
429
+        SendFileList( 0 );
430
+        break;
431
+    }
432
+  }
433
+
434
+  void ChironTFT::InjectCommandandWait(PGM_P cmd) {
435
+    //injectCommands_P(cmnd); queue.enqueue_now_P(cmd);
436
+    //SERIAL_ECHOLN(PSTR("Inject>"));
437
+  }
438
+
439
+  void ChironTFT::ProcessPanelRequest() {
440
+    // Break these up into logical blocks // as its easier to navigate than one huge switch case!
441
+    int8_t req = atoi(&panel_command[1]);
442
+
443
+    // Information requests A0 - A8 and A33
444
+    if (req <= 8 || req == 33) PanelInfo(req);
445
+
446
+    // Simple Actions A9 - A28
447
+    else if ( req <= 28) PanelAction(req);
448
+
449
+    // Process Initiation
450
+    else if (req <= 34) PanelProcess(req);
451
+
452
+    else SendtoTFTLN();
453
+  }
454
+
455
+  void ChironTFT::PanelInfo(uint8_t req) {
456
+    // information requests A0-A8 and A33
457
+    switch (req) {
458
+      case 0:   // A0 Get HOTEND Temp
459
+        SendtoTFT(PSTR("A0V "));
460
+        TFTSer.println(getActualTemp_celsius(E0));
461
+        break;
462
+
463
+      case 1:   // A1 Get HOTEND Target Temp
464
+        SendtoTFT(PSTR("A1V "));
465
+        TFTSer.println(getTargetTemp_celsius(E0));
466
+        break;
467
+
468
+      case 2:   // A2 Get BED Temp
469
+        SendtoTFT(PSTR("A2V "));
470
+        TFTSer.println(getActualTemp_celsius(BED));
471
+        break;
472
+
473
+      case 3:   // A3 Get BED Target Temp
474
+        SendtoTFT(PSTR("A3V "));
475
+        TFTSer.println(getTargetTemp_celsius(BED));
476
+        break;
477
+
478
+      case 4:   // A4 Get FAN Speed
479
+        SendtoTFT(PSTR("A4V "));
480
+        TFTSer.println(getActualFan_percent(FAN0));
481
+        break;
482
+
483
+      case 5:   // A5 Get Current Coordinates
484
+        SendtoTFT(PSTR("A5V X: "));
485
+        TFTSer.print(getAxisPosition_mm(X));
486
+        SendtoTFT(PSTR(" Y: "));
487
+        TFTSer.print(getAxisPosition_mm(Y));
488
+        SendtoTFT(PSTR(" Z: "));
489
+        TFTSer.println(getAxisPosition_mm(Z));
490
+        break;
491
+
492
+      case 6:   // A6 Get printing progress
493
+        if (isPrintingFromMedia()) {
494
+          SendtoTFT(PSTR("A6V "));
495
+          TFTSer.println(ui8tostr2(getProgress_percent()));
496
+
497
+        }
498
+        else
499
+          SendtoTFTLN(PSTR("A6V ---"));
500
+        break;
501
+
502
+      case 7: { // A7 Get Printing Time
503
+        uint32_t time = getProgress_seconds_elapsed() / 60;
504
+        SendtoTFT(PSTR("A7V "));
505
+        TFTSer.print(ui8tostr2(time / 60));
506
+        SendtoTFT(PSTR(" H "));
507
+        TFTSer.print(ui8tostr2(time % 60));
508
+        SendtoTFT(PSTR(" M"));
509
+        #if ACDEBUG(AC_ALL)
510
+          SERIAL_ECHOLNPAIR("Print time ", ui8tostr2(time / 60), ":", ui8tostr2(time % 60));
511
+        #endif
512
+      } break;
513
+
514
+      case 8:   // A8 Get SD Card list A8 S0
515
+        if (!isMediaInserted()) safe_delay(500);
516
+        if (!isMediaInserted())   // Make sure the card is removed
517
+          SendtoTFTLN(AC_msg_no_sd_card);
518
+        else if (panel_command[3] == 'S')
519
+          SendFileList( atoi( &panel_command[4] ) );
520
+        break;
521
+
522
+      case 33:   // A33 Get firmware info
523
+        SendtoTFT(PSTR("J33 "));
524
+        SendtoTFTLN(PSTR(SHORT_BUILD_VERSION));
525
+        break;
526
+    }
527
+  }
528
+
529
+  void ChironTFT::PanelAction(uint8_t req) {
530
+    switch (req) {
531
+      case  9:   // A9 Pause SD print
532
+        if (isPrintingFromMedia()) {
533
+          SendtoTFTLN(AC_msg_pause);
534
+          pausePrint();
535
+          printer_state = AC_printer_pausing;
536
+        }
537
+        else
538
+          SendtoTFTLN(AC_msg_stop);
539
+        break;
540
+
541
+      case 10: // A10 Resume SD Print
542
+        if (pause_state == AC_paused_idle || printer_state == AC_printer_resuming_from_power_outage)
543
+          resumePrint();
544
+        else
545
+          setUserConfirmed();
546
+        break;
547
+
548
+      case 11:   // A11 Stop SD print
549
+        if (isPrintingFromMedia()) {
550
+          printer_state = AC_printer_stopping;
551
+          stopPrint();
552
+        }
553
+        else {
554
+          if (printer_state == AC_printer_resuming_from_power_outage)
555
+            injectCommands_P(PSTR("M1000 C\n")); // Cancel recovery
556
+          SendtoTFTLN(AC_msg_stop);
557
+          printer_state = AC_printer_idle;
558
+        }
559
+        break;
560
+
561
+      case 12:   // A12 Kill printer
562
+        kill();  // from marlincore.h
563
+        break;
564
+
565
+      case 13:   // A13 Select file
566
+        SelectFile();
567
+        break;
568
+
569
+      case 14: { // A14 Start Printing
570
+        // Allows printer to restart the job if we dont want to recover
571
+        if (printer_state == AC_printer_resuming_from_power_outage) {
572
+          injectCommands_P(PSTR("M1000 C\n")); // Cancel recovery
573
+          printer_state = AC_printer_idle;
574
+        }
575
+        #if ACDebugLevel >= 1
576
+          SERIAL_ECHOLNPAIR_F("Print: ", selectedfile);
577
+        #endif
578
+        // the card library needs a path starting // but the File api doesn't...
579
+        char file[MAX_PATH_LEN];
580
+        file[0] = '/';
581
+        strcpy(file + 1, selectedfile);
582
+        printFile(file);
583
+        SendtoTFTLN(AC_msg_print_from_sd_card);
584
+      } break;
585
+
586
+      case 15:   // A15 Resuming from outage
587
+        if (printer_state == AC_printer_resuming_from_power_outage)
588
+          // Need to home here to restore the Z position
589
+          injectCommands_P(AC_cmnd_power_loss_recovery);
590
+
591
+          injectCommands_P(PSTR("M1000\n"));  // home and start recovery
592
+        break;
593
+
594
+      case 16: { // A16 Set HotEnd temp  A17 S170
595
+        const float set_Htemp = atof(&panel_command[5]);
596
+        hotend_state = set_Htemp ? AC_heater_temp_set : AC_heater_off;
597
+        switch ((char)panel_command[4]) {
598
+          // Set Temp
599
+          case 'S': case 'C': setTargetTemp_celsius(set_Htemp, E0);
600
+        }
601
+      } break;
602
+
603
+      case 17: { // A17 Set bed temp
604
+        const float set_Btemp = atof(&panel_command[5]);
605
+        hotbed_state = set_Btemp ? AC_heater_temp_set : AC_heater_off;
606
+        if (panel_command[4] == 'S')
607
+          setTargetTemp_celsius(set_Btemp, BED);
608
+      } break;
609
+
610
+      case 18:   // A18 Set Fan Speed
611
+        if (panel_command[4] == 'S')
612
+          setTargetFan_percent(atof(&panel_command[5]), FAN0);
613
+        break;
614
+
615
+      case 19:   // A19 Motors off
616
+        if (!isPrinting()) {
617
+          disable_all_steppers(); // from marlincore.h
618
+          SendtoTFTLN(AC_msg_ready);
619
+        }
620
+        break;
621
+
622
+      case 20:   // A20 Read/write print speed
623
+        if (panel_command[4] == 'S')
624
+          setFeedrate_percent(atoi(&panel_command[5]));
625
+        else {
626
+          SendtoTFT(PSTR("A20V "));
627
+          TFTSer.println(getFeedrate_percent());
628
+        }
629
+        break;
630
+
631
+      case 21:   // A21 Home Axis  A21 X
632
+        if (!isPrinting()) {
633
+          switch ((char)panel_command[4]) {
634
+            case 'X': injectCommands_P(PSTR("G28 X\n")); break;
635
+            case 'Y': injectCommands_P(PSTR("G28 Y\n")); break;
636
+            case 'Z': injectCommands_P(PSTR("G28 Z\n")); break;
637
+            case 'C': injectCommands_P(PSTR("G28\n")); break;
638
+          }
639
+        }
640
+        break;
641
+
642
+      case 22:   // A22 Move Axis  A22 Y +10F3000
643
+        // Ignore request if printing
644
+        if (!isPrinting()) {
645
+          // setAxisPosition_mm() uses pre defined manual feedrates so ignore the feedrate from the panel
646
+          setSoftEndstopState(true);  // enable endstops
647
+          float newposition = atof(&panel_command[6]);
648
+
649
+          #if ACDEBUG(AC_ACTION)
650
+            SERIAL_ECHOLNPAIR("Nudge ", panel_command[4], " axis ", newposition);
651
+          #endif
652
+
653
+          switch (panel_command[4]) {
654
+            case 'X': setAxisPosition_mm(getAxisPosition_mm(X) + newposition, X); break;
655
+            case 'Y': setAxisPosition_mm(getAxisPosition_mm(Y) + newposition, Y); break;
656
+            case 'Z': setAxisPosition_mm(getAxisPosition_mm(Z) + newposition, Z); break;
657
+            case 'E':   // The only time we get this command is from the filament load/unload menu
658
+                        // the standard movement is too slow so we will use the load unlod GCode to speed it up a bit
659
+              if (canMove(E0) && !commandsInQueue())
660
+                injectCommands_P(newposition > 0 ? AC_cmnd_manual_load_filament : AC_cmnd_manual_unload_filament);
661
+              break;
662
+          }
663
+        }
664
+        break;
665
+
666
+      case 23:   // A23 Preheat PLA
667
+        // Ignore request if printing
668
+        if (!isPrinting()) {
669
+          // Temps defined in configuration.h
670
+          setTargetTemp_celsius(PREHEAT_1_TEMP_BED, BED);
671
+          setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, E0);
672
+          SendtoTFTLN();
673
+          hotbed_state = AC_heater_temp_set;
674
+          hotend_state = AC_heater_temp_set;
675
+        }
676
+        break;
677
+
678
+      case 24:   // A24 Preheat ABS
679
+        // Ignore request if printing
680
+        if (!isPrinting()) {
681
+          setTargetTemp_celsius(PREHEAT_2_TEMP_BED, BED);
682
+          setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, E0);
683
+          SendtoTFTLN();
684
+          hotbed_state = AC_heater_temp_set;
685
+          hotend_state = AC_heater_temp_set;
686
+        }
687
+        break;
688
+
689
+      case 25:   // A25 Cool Down
690
+        // Ignore request if printing
691
+        if (!isPrinting()) {
692
+          setTargetTemp_celsius(0, E0);
693
+          setTargetTemp_celsius(0, BED);
694
+          SendtoTFTLN(AC_msg_ready);
695
+          hotbed_state = AC_heater_off;
696
+          hotend_state = AC_heater_off;
697
+        }
698
+        break;
699
+
700
+      case 26:   // A26 Refresh SD
701
+        // M22 M21 maybe needed here to reset sd card
702
+        filenavigator.reset();
703
+        break;
704
+
705
+      case 27:   // A27 Servo Angles adjust
706
+        break;
707
+
708
+      case 28:   // A28 Filament set A28 O/C
709
+        // Ignore request if printing
710
+        if (isPrinting()) break;
711
+        SendtoTFTLN();
712
+        break;
713
+    }
714
+  }
715
+
716
+  void ChironTFT::PanelProcess(uint8_t req) {
717
+    switch (req) {
718
+      case 29: { // A29 Read Mesh Point A29 X1 Y1
719
+        xy_uint8_t pos;
720
+        float pos_z;
721
+        pos.x = atoi(&panel_command[5]);
722
+        pos.y = atoi(&panel_command[8]);
723
+        pos_z = getMeshPoint(pos);
724
+
725
+        SendtoTFT(PSTR("A29V "));
726
+        TFTSer.println(pos_z * 100);
727
+        if (!isPrinting()) {
728
+          setSoftEndstopState(true);  // disable endstops
729
+          // If the same meshpoint is selected twice in a row, move the head to that ready for adjustment
730
+          if ((selectedmeshpoint.x == pos.x) && (selectedmeshpoint.y == pos.y)) {
731
+            if (!isPositionKnown())
732
+              injectCommands_P(PSTR("G28\n")); // home
733
+
734
+            if (isPositionKnown()) {
735
+              #if ACDEBUG(AC_INFO)
736
+                SERIAL_ECHOLNPAIR("Moving to mesh point at x: ", pos.x, " y: ", pos.y, " z: ", pos_z);
737
+              #endif
738
+              // Go up before moving
739
+              setAxisPosition_mm(3.0,Z);
740
+
741
+              setAxisPosition_mm(17 + (93 * pos.x), X);
742
+              setAxisPosition_mm(20 + (93 * pos.y), Y);
743
+              setAxisPosition_mm(0.0, Z);
744
+              #if ACDEBUG(AC_INFO)
745
+                SERIAL_ECHOLNPAIR("Current Z: ", getAxisPosition_mm(Z));
746
+              #endif
747
+            }
748
+          }
749
+          selectedmeshpoint.x = pos.x;
750
+          selectedmeshpoint.y = pos.y;
751
+        }
752
+      } break;
753
+
754
+      case 30: {  // A30 Auto leveling
755
+        if (panel_command[3] == 'S') { // Start probing
756
+          // Ignore request if printing
757
+          if (isPrinting())
758
+            SendtoTFTLN(AC_msg_probing_not_allowed); // forbid auto leveling
759
+          else {
760
+            injectCommands_P(isMachineHomed() ? PSTR("G29") : PSTR("G28\nG29"));
761
+            printer_state = AC_printer_probing;
762
+            SendtoTFTLN(AC_msg_start_probing);
763
+          }
764
+        }
765
+        else SendtoTFTLN(AC_msg_start_probing);
766
+      }  break;
767
+
768
+      case 31: { // A31 Adjust all Probe Points
769
+        switch (panel_command[3]) {
770
+          case 'C':   // Restore and apply original offsets
771
+            if (!isPrinting()) {
772
+              injectCommands_P(PSTR("M501\nM420 S1\n"));
773
+              selectedmeshpoint.x = 99;
774
+              selectedmeshpoint.y = 99;
775
+            }
776
+          break;
777
+          case 'D':   // Save Z Offset tables and restore levelling state
778
+            if (!isPrinting()) {
779
+              setAxisPosition_mm(1.0,Z);
780
+              injectCommands_P(PSTR("M500\n"));
781
+              selectedmeshpoint.x = 99;
782
+              selectedmeshpoint.y = 99;
783
+            }
784
+          break;
785
+          case 'G':   // Get current offset
786
+            SendtoTFT(PSTR("A31V "));
787
+            // When printing use the live z Offset position
788
+            // we will use babystepping to move the print head
789
+            if (isPrinting())
790
+              TFTSer.println(live_Zoffset);
791
+            else {
792
+              TFTSer.println(getZOffset_mm());
793
+              selectedmeshpoint.x = 99;
794
+              selectedmeshpoint.y = 99;
795
+            }
796
+          break;
797
+          case 'S': { // Set offset (adjusts all points by value)
798
+            float Zshift = atof(&panel_command[4]);
799
+            setSoftEndstopState(false);  // disable endstops
800
+            // Allow temporary Z position nudging during print
801
+            // From the levelling panel use the all points UI to adjust the print pos.
802
+            if (isPrinting()) {
803
+              #if ACDEBUG(AC_INFO)
804
+                SERIAL_ECHOLNPAIR("Change Zoffset from:", live_Zoffset, " to ", live_Zoffset + Zshift);
805
+              #endif
806
+              if (isAxisPositionKnown(Z)) {
807
+                #if ACDEBUG(AC_INFO)
808
+                  const float currZpos = getAxisPosition_mm(Z);
809
+                  SERIAL_ECHOLNPAIR("Nudge Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05));
810
+                #endif
811
+                // Use babystepping to adjust the head position
812
+                int16_t steps = mmToWholeSteps(constrain(Zshift,-0.05,0.05), Z);
813
+                #if ACDEBUG(AC_INFO)
814
+                  SERIAL_ECHOLNPAIR("Steps to move Z: ", steps);
815
+                #endif
816
+                babystepAxis_steps(steps, Z);
817
+                live_Zoffset += Zshift;
818
+              }
819
+              SendtoTFT(PSTR("A31V "));
820
+              TFTSer.println(live_Zoffset);
821
+            }
822
+            else {
823
+              GRID_LOOP(x, y) {
824
+                const xy_uint8_t pos { x, y };
825
+                const float currval = getMeshPoint(pos);
826
+                setMeshPoint(pos, constrain(currval + Zshift, AC_LOWEST_MESHPOINT_VAL, 2));
827
+              }
828
+              const float currZOffset = getZOffset_mm();
829
+              #if ACDEBUG(AC_INFO)
830
+                SERIAL_ECHOLNPAIR("Change probe offset from ", currZOffset, " to  ", currZOffset + Zshift);
831
+              #endif
832
+
833
+              setZOffset_mm(currZOffset + Zshift);
834
+              SendtoTFT(PSTR("A31V "));
835
+              TFTSer.println(getZOffset_mm());
836
+
837
+              if (isAxisPositionKnown(Z)) {
838
+                // Move Z axis
839
+                const float currZpos = getAxisPosition_mm(Z);
840
+                #if ACDEBUG(AC_INFO)
841
+                  SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05));
842
+                #endif
843
+                setAxisPosition_mm(currZpos+constrain(Zshift,-0.05,0.05),Z);
844
+              }
845
+            }
846
+          } break;
847
+        } // end switch
848
+      } break;
849
+
850
+      case 32: { // A32 clean leveling beep flag
851
+        // Ignore request if printing
852
+        //if (isPrinting()) break;
853
+        //injectCommands_P(PSTR("M500\nM420 S1\nG1 Z10 F240\nG1 X0 Y0 F6000"));
854
+        //TFTSer.println("");
855
+      } break;
856
+
857
+      // A33 firmware info request seet PanelInfo()
858
+
859
+      case 34: {  // A34 Adjust single mesh point A34 C/S X1 Y1 V123
860
+        if (panel_command[3] == 'C') { // Restore original offsets
861
+          injectCommands_P(PSTR("M501\nM420 S1"));
862
+          selectedmeshpoint.x = 99;
863
+          selectedmeshpoint.y = 99;
864
+          //printer_state = AC_printer_idle;
865
+        }
866
+        else {
867
+          xy_uint8_t pos;
868
+          pos.x = atoi(&panel_command[5]);
869
+          pos.y = atoi(&panel_command[8]);
870
+
871
+          float currmesh = getMeshPoint(pos);
872
+          float newval   = atof(&panel_command[11])/100;
873
+          #if ACDEBUG(AC_INFO)
874
+            SERIAL_ECHOLNPAIR("Change mesh point x:", pos.x, " y:", pos.y);
875
+            SERIAL_ECHOLNPAIR("from ", currmesh, " to ", newval);
876
+          #endif
877
+          // Update Meshpoint
878
+          setMeshPoint(pos,newval);
879
+          if ( (printer_state == AC_printer_idle) || (printer_state == AC_printer_probing) ) {//!isPrinting()) {
880
+            // if we are at the current mesh point indicated on the panel Move Z pos +/- 0.05mm ( The panel changes the mesh value by +/- 0.05mm on each button press)
881
+            if ((selectedmeshpoint.x == pos.x) && (selectedmeshpoint.y == pos.y)) {
882
+              setSoftEndstopState(false);
883
+              float currZpos = getAxisPosition_mm(Z);
884
+              #if ACDEBUG(AC_INFO)
885
+                SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(newval - currmesh, -0.05, 0.05));
886
+              #endif
887
+              setAxisPosition_mm(currZpos + constrain(newval - currmesh, -0.05, 0.05), Z);
888
+            }
889
+          }
890
+        }
891
+      }  break;
892
+    }
893
+  }
894
+} // namespace
895
+
896
+#endif // ANYCUBIC_LCD_CHIRON

+ 77
- 0
Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h View File

@@ -0,0 +1,77 @@
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
+#pragma once
23
+
24
+/**
25
+ * lcd/extui/lib/chiron_tft.h
26
+ *
27
+ * Extensible_UI implementation for Anycubic Chiron
28
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
29
+ *  (not affiliated with Anycubic, Ltd.)
30
+ */
31
+
32
+#include "chiron_tft_defs.h"
33
+#include "../../../../inc/MarlinConfigPre.h"
34
+#include "../../ui_api.h"
35
+namespace Anycubic {
36
+
37
+  class ChironTFT {
38
+    static printer_state_t  printer_state;
39
+    static paused_state_t   pause_state;
40
+    static heater_state_t   hotend_state;
41
+    static heater_state_t   hotbed_state;
42
+    static xy_uint8_t       selectedmeshpoint;
43
+    static char             panel_command[MAX_CMND_LEN];
44
+    static uint8_t          command_len;
45
+    static char             selectedfile[MAX_PATH_LEN];
46
+    static float            live_Zoffset;
47
+    static file_menu_t      file_menu;
48
+    public:
49
+      ChironTFT();
50
+      void Startup();
51
+      void IdleLoop();
52
+      void PrinterKilled(PGM_P,PGM_P);
53
+      void MediaEvent(media_event_t);
54
+      void TimerEvent(timer_event_t);
55
+      void FilamentRunout();
56
+      void ConfirmationRequest(const char * const );
57
+      void StatusChange(const char * const );
58
+      void PowerLossRecovery();
59
+
60
+    private:
61
+      void SendtoTFT(PGM_P);
62
+      void SendtoTFTLN(PGM_P);
63
+      bool ReadTFTCommand();
64
+      int8_t Findcmndpos(const char *, char);
65
+      void CheckHeaters();
66
+      void SendFileList(int8_t);
67
+      void SelectFile();
68
+      void InjectCommandandWait(PGM_P);
69
+      void ProcessPanelRequest();
70
+      void PanelInfo(uint8_t);
71
+      void PanelAction(uint8_t);
72
+      void PanelProcess(uint8_t);
73
+  };
74
+
75
+  extern ChironTFT Chiron;
76
+
77
+}

+ 151
- 0
Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h View File

@@ -0,0 +1,151 @@
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
+
23
+/**
24
+ * lcd/extui/lib/chiron_defs.h
25
+ *
26
+ * Extensible_UI implementation for Anycubic Chiron
27
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
28
+ *  (not affiliated with Anycubic, Ltd.)
29
+ */
30
+
31
+#pragma once
32
+#include "../../../../inc/MarlinConfigPre.h"
33
+//#define ACDEBUGLEVEL 255
34
+
35
+#if ACDEBUGLEVEL
36
+  // Bit-masks for selective debug:
37
+  enum ACDebugMask : uint8_t {
38
+    AC_INFO   =  1,
39
+    AC_ACTION =  2,
40
+    AC_FILE   =  4,
41
+    AC_PANEL  =  8,
42
+    AC_MARLIN = 16,
43
+    AC_SOME   = 32,
44
+    AC_ALL    = 64
45
+  };
46
+  #define ACDEBUG(mask) ( ((mask) & ACDEBUGLEVEL) == mask )  // Debug flag macro
47
+#else
48
+  #define ACDEBUG(mask) false
49
+#endif
50
+
51
+#define TFTSer LCD_SERIAL                    // Serial interface for TFT panel now uses marlinserial
52
+#define MAX_FOLDER_DEPTH                4    // Limit folder depth TFT has a limit for the file path
53
+#define MAX_CMND_LEN                   16 * MAX_FOLDER_DEPTH // Maximum Length for a Panel command
54
+#define MAX_PATH_LEN                   16 * MAX_FOLDER_DEPTH // Maximum number of characters in a SD file path
55
+
56
+#define AC_HEATER_FAULT_VALIDATION_TIME 5    // number of 1/2 second loops before signalling a heater fault
57
+#define AC_LOWEST_MESHPOINT_VAL        -7.00 // The lowest value you can set for a single mesh point offset
58
+
59
+ // TFT panel commands
60
+#define  AC_msg_sd_card_inserted       PSTR("J00")
61
+#define  AC_msg_sd_card_removed        PSTR("J01")
62
+#define  AC_msg_no_sd_card             PSTR("J02")
63
+#define  AC_msg_usb_connected          PSTR("J03")
64
+#define  AC_msg_print_from_sd_card     PSTR("J04")
65
+#define  AC_msg_pause                  PSTR("J05")
66
+#define  AC_msg_nozzle_heating         PSTR("J06")
67
+#define  AC_msg_nozzle_heating_done    PSTR("J07")
68
+#define  AC_msg_bed_heating            PSTR("J08")
69
+#define  AC_msg_bed_heating_done       PSTR("J09")
70
+#define  AC_msg_nozzle_temp_abnormal   PSTR("J10")
71
+#define  AC_msg_kill_lcd               PSTR("J11")
72
+#define  AC_msg_ready                  PSTR("J12")
73
+#define  AC_msg_low_nozzle_temp        PSTR("J13")
74
+#define  AC_msg_print_complete         PSTR("J14")
75
+#define  AC_msg_filament_out_alert     PSTR("J15")
76
+#define  AC_msg_stop                   PSTR("J16")
77
+#define  AC_msg_main_board_has_reset   PSTR("J17")
78
+#define  AC_msg_paused                 PSTR("J18")
79
+#define  AC_msg_j19_unknown            PSTR("J19")
80
+#define  AC_msg_sd_file_open_success   PSTR("J20")
81
+#define  AC_msg_sd_file_open_failed    PSTR("J21")
82
+#define  AC_msg_level_monitor_finished PSTR("J22")
83
+#define  AC_msg_filament_out_block     PSTR("J23")
84
+#define  AC_msg_probing_not_allowed    PSTR("J24")
85
+#define  AC_msg_probing_complete       PSTR("J25")
86
+#define  AC_msg_start_probing          PSTR("J26")
87
+#define  AC_msg_version                PSTR("J27")
88
+
89
+#define MARLIN_msg_start_probing       PSTR("Probing Point 1/25")
90
+#define MARLIN_msg_probing_failed      PSTR("Probing Failed")
91
+#define MARLIN_msg_ready               PSTR("3D Printer Ready.")
92
+#define MARLIN_msg_print_paused        PSTR("Print Paused")
93
+#define MARLIN_msg_print_aborted       PSTR("Print Aborted")
94
+#define MARLIN_msg_extruder_heating    PSTR("E Heating...")
95
+#define MARLIN_msg_bed_heating         PSTR("Bed Heating...")
96
+
97
+#define MARLIN_msg_nozzle_parked       PSTR("Nozzle Parked")
98
+#define MARLIN_msg_heater_timeout      PSTR("Heater Timeout")
99
+#define MARLIN_msg_reheating           PSTR("Reheating...")
100
+#define MARLIN_msg_reheat_done         PSTR("Reheat finished.")
101
+#define MARLIN_msg_filament_purging    PSTR("Filament Purging...")
102
+#define MARLIN_msg_special_pause       PSTR("PB")
103
+#define AC_cmnd_auto_unload_filament   PSTR("M701")                    // Use Marlin unload routine
104
+#define AC_cmnd_auto_load_filament     PSTR("M702 M0 PB")              // Use Marlin load routing then pause for user to clean nozzle
105
+
106
+#define AC_cmnd_manual_load_filament   PSTR("M83\nG1 E50 F700\nM82")   // replace the manual panel commands with something a little faster
107
+#define AC_cmnd_manual_unload_filament PSTR("M83\nG1 E-50 F1200\nM82")
108
+#define AC_cmnd_enable_levelling       PSTR("M420 S1 V1")
109
+#define AC_cmnd_power_loss_recovery    PSTR("G28 X Y R5\nG28 Z")       // Lift, home X and Y then home Z when in 'safe' position
110
+
111
+namespace Anycubic {
112
+  enum heater_state_t : uint8_t {
113
+    AC_heater_off,
114
+    AC_heater_temp_set,
115
+    AC_heater_temp_reached
116
+  };
117
+
118
+  enum paused_state_t : uint8_t {
119
+    AC_paused_heater_timed_out,
120
+    AC_paused_purging_filament,
121
+    AC_paused_idle
122
+  };
123
+
124
+  enum printer_state_t : uint8_t {
125
+    AC_printer_idle,
126
+    AC_printer_probing,
127
+    AC_printer_printing,
128
+    AC_printer_pausing,
129
+    AC_printer_paused,
130
+    AC_printer_stopping,
131
+    AC_printer_resuming_from_power_outage
132
+  };
133
+
134
+  enum timer_event_t : uint8_t {
135
+    AC_timer_started,
136
+    AC_timer_paused,
137
+    AC_timer_stopped
138
+  };
139
+
140
+  enum media_event_t : uint8_t {
141
+    AC_media_inserted,
142
+    AC_media_removed,
143
+    AC_media_error
144
+  };
145
+  enum file_menu_t : uint8_t {
146
+    AC_menu_file,
147
+    AC_menu_command,
148
+    AC_menu_change_to_file,
149
+    AC_menu_change_to_command
150
+  };
151
+}

+ 26
- 84
Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp View File

@@ -24,16 +24,17 @@
24 24
 #if ENABLED(ANYCUBIC_LCD_I3MEGA)
25 25
 
26 26
 #include "anycubic_i3mega_lcd.h"
27
-
28
-#include "../../../../inc/MarlinConfig.h"
29 27
 #include "../../ui_api.h"
30
-#include "../../../../MarlinCore.h"     // for quickstop_stepper and disable_steppers
28
+
29
+#include "../../../../libs/numtostr.h"
31 30
 #include "../../../../module/motion.h"  // for A20 read printing speed feedrate_percentage
31
+#include "../../../../MarlinCore.h"     // for quickstop_stepper and disable_steppers
32
+#include "../../../../inc/MarlinConfig.h"
32 33
 
33 34
 // command sending macro's with debugging capability
34 35
 #define SEND_PGM(x)                                 send_P(PSTR(x))
35 36
 #define SENDLINE_PGM(x)                             sendLine_P(PSTR(x))
36
-#define SEND_PGM_VAL(x,y)                           (send_P(PSTR(x)), sendLine(itostr3(y)))
37
+#define SEND_PGM_VAL(x,y)                           (send_P(PSTR(x)), sendLine(i8tostr3rj(y)))
37 38
 #define SEND(x)                                     send(x)
38 39
 #define SENDLINE(x)                                 sendLine(x)
39 40
 #if ENABLED(ANYCUBIC_LCD_DEBUG)
@@ -44,20 +45,8 @@
44 45
   #define SENDLINE_DBG_PGM_VAL(x,y,z)               sendLine_P(PSTR(x))
45 46
 #endif
46 47
 
47
-
48 48
 AnycubicTFTClass AnycubicTFT;
49 49
 
50
-char _conv[8];
51
-
52
-char *itostr2(const uint8_t &x) {
53
-  // sprintf(conv,"%5.1f",x);
54
-  int xx = x;
55
-  _conv[0] = (xx / 10) % 10 + '0';
56
-  _conv[1] = (xx) % 10 + '0';
57
-  _conv[2] = 0;
58
-  return _conv;
59
-}
60
-
61 50
 static void sendNewLine(void) {
62 51
   LCD_SERIAL.write('\r');
63 52
   LCD_SERIAL.write('\n');
@@ -82,34 +71,6 @@ static void sendLine_P(PGM_P str) {
82 71
   sendNewLine();
83 72
 }
84 73
 
85
-#ifndef ULTRA_LCD
86
-  #define DIGIT(n) ('0' + (n))
87
-  #define DIGIMOD(n, f) DIGIT((n) / (f) % 10)
88
-  #define RJDIGIT(n, f) ((n) >= (f) ? DIGIMOD(n, f) : ' ')
89
-  #define MINUSOR(n, alt) (n >= 0 ? (alt) : (n = -n, '-'))
90
-
91
-  char* itostr3(const int x) {
92
-    int xx = x;
93
-    _conv[4] = MINUSOR(xx, RJDIGIT(xx, 100));
94
-    _conv[5] = RJDIGIT(xx, 10);
95
-    _conv[6] = DIGIMOD(xx, 1);
96
-    return &_conv[4];
97
-  }
98
-
99
-// Convert signed float to fixed-length string with 023.45 / -23.45 format
100
-  char *ftostr32(const float &x) {
101
-    long xx = x * 100;
102
-    _conv[1] = MINUSOR(xx, DIGIMOD(xx, 10000));
103
-    _conv[2] = DIGIMOD(xx, 1000);
104
-    _conv[3] = DIGIMOD(xx, 100);
105
-    _conv[4] = '.';
106
-    _conv[5] = DIGIMOD(xx, 10);
107
-    _conv[6] = DIGIMOD(xx, 1);
108
-    return &_conv[1];
109
-  }
110
-
111
-#endif
112
-
113 74
 AnycubicTFTClass::AnycubicTFTClass() {}
114 75
 
115 76
 void AnycubicTFTClass::OnSetup() {
@@ -181,7 +142,7 @@ void AnycubicTFTClass::OnKillTFT() {
181 142
 void AnycubicTFTClass::OnSDCardStateChange(bool isInserted) {
182 143
   #if ENABLED(ANYCUBIC_LCD_DEBUG)
183 144
     SERIAL_ECHOPGM("TFT Serial Debug: OnSDCardStateChange event triggered...");
184
-    SERIAL_ECHO(itostr2(isInserted));
145
+    SERIAL_ECHO(ui8tostr2(isInserted));
185 146
     SERIAL_EOL();
186 147
   #endif
187 148
   DoSDCardStateCheck();
@@ -622,19 +583,15 @@ void AnycubicTFTClass::GetCommandFromTFT() {
622 583
           case 3: { // A3 GET HOTBED TARGET TEMP
623 584
             float heatedBedTargetTemp = ExtUI::getTargetTemp_celsius((ExtUI::heater_t) ExtUI::BED);
624 585
             SEND_PGM_VAL("A3V ", int(heatedBedTargetTemp + 0.5));
625
-          }
626
-          break;
586
+          } break;
627 587
 
628
-          case 4: // A4 GET FAN SPEED
629
-          {
588
+          case 4: { // A4 GET FAN SPEED
630 589
             float fanPercent = ExtUI::getActualFan_percent(ExtUI::FAN0);
631 590
             fanPercent = constrain(fanPercent, 0, 100);
632 591
             SEND_PGM_VAL("A4V ", int(fanPercent));
633
-          }
634
-          break;
592
+          } break;
635 593
 
636
-          case 5: // A5 GET CURRENT COORDINATE
637
-          {
594
+          case 5: { // A5 GET CURRENT COORDINATE
638 595
             float xPostition = ExtUI::getAxisPosition_mm(ExtUI::X);
639 596
             float yPostition = ExtUI::getAxisPosition_mm(ExtUI::Y);
640 597
             float zPostition = ExtUI::getAxisPosition_mm(ExtUI::Z);
@@ -645,39 +602,34 @@ void AnycubicTFTClass::GetCommandFromTFT() {
645 602
             SEND_PGM(" Z: ");
646 603
             LCD_SERIAL.print(zPostition);
647 604
             SENDLINE_PGM("");
648
-          }
649
-          break;
605
+          } break;
650 606
 
651 607
           case 6: // A6 GET SD CARD PRINTING STATUS
652 608
             #if ENABLED(SDSUPPORT)
653 609
               if (ExtUI::isPrintingFromMedia()) {
654 610
                 SEND_PGM("A6V ");
655
-                if (ExtUI::isMediaInserted()) {
656
-                  SENDLINE(itostr3(int(ExtUI::getProgress_percent())));
657
-                }
658
-                else {
611
+                if (ExtUI::isMediaInserted())
612
+                  SENDLINE(ui8tostr3rj(ExtUI::getProgress_percent()));
613
+                else
659 614
                   SENDLINE_DBG_PGM("J02", "TFT Serial Debug: No SD Card mounted to return printing status... J02");
660
-                }
661 615
               }
662
-              else {
616
+              else
663 617
                 SENDLINE_PGM("A6V ---");
664
-              }
665 618
             #endif
666 619
             break;
667 620
 
668 621
           case 7: { // A7 GET PRINTING TIME
669
-            uint32_t elapsedSeconds = ExtUI::getProgress_seconds_elapsed();
622
+            const uint32_t elapsedSeconds = ExtUI::getProgress_seconds_elapsed();
670 623
             SEND_PGM("A7V ");
671 624
             if (elapsedSeconds != 0) {  // print time
672
-              uint32_t elapsedMinutes = elapsedSeconds / 60;
673
-              SEND(itostr2(elapsedMinutes / 60));
625
+              const uint32_t elapsedMinutes = elapsedSeconds / 60;
626
+              SEND(ui8tostr2(elapsedMinutes / 60));
674 627
               SEND_PGM(" H ");
675
-              SEND(itostr2(elapsedMinutes % 60));
628
+              SEND(ui8tostr2(elapsedMinutes % 60));
676 629
               SENDLINE_PGM(" M");
677 630
             }
678
-            else {
631
+            else
679 632
               SENDLINE_PGM(" 999:999");
680
-            }
681 633
           }
682 634
           break;
683 635
 
@@ -692,7 +644,6 @@ void AnycubicTFTClass::GetCommandFromTFT() {
692 644
             #if ENABLED(SDSUPPORT)
693 645
               if (ExtUI::isPrintingFromMedia())
694 646
                 PausePrint();
695
-
696 647
             #endif
697 648
             break;
698 649
 
@@ -700,14 +651,11 @@ void AnycubicTFTClass::GetCommandFromTFT() {
700 651
             #if ENABLED(SDSUPPORT)
701 652
               if (ExtUI::isPrintingFromMediaPaused())
702 653
                 ResumePrint();
703
-
704 654
             #endif
705 655
             break;
706 656
 
707 657
           case 11: // A11 STOP SD PRINT
708
-            #if ENABLED(SDSUPPORT)
709
-              StopPrint();
710
-            #endif
658
+            TERN_(SDSUPPORT, StopPrint());
711 659
             break;
712 660
 
713 661
           case 12: // A12 kill
@@ -748,7 +696,6 @@ void AnycubicTFTClass::GetCommandFromTFT() {
748 696
             #if ENABLED(SDSUPPORT)
749 697
               if (!ExtUI::isPrinting() && strlen(SelectedFile) > 0)
750 698
                 StartPrint();
751
-
752 699
             #endif
753 700
             break;
754 701
 
@@ -771,8 +718,7 @@ void AnycubicTFTClass::GetCommandFromTFT() {
771 718
           }
772 719
           break;
773 720
 
774
-          case 17:// A17 set heated bed temp
775
-          {
721
+          case 17: { // A17 set heated bed temp
776 722
             unsigned int tempbed;
777 723
             if (CodeSeen('S')) {
778 724
               tempbed = constrain(CodeValue(), 0, 100);
@@ -781,19 +727,17 @@ void AnycubicTFTClass::GetCommandFromTFT() {
781 727
           }
782 728
           break;
783 729
 
784
-          case 18:// A18 set fan speed
785
-          {
730
+          case 18: { // A18 set fan speed
786 731
             float fanPercent;
787 732
             if (CodeSeen('S')) {
788 733
               fanPercent = CodeValue();
789 734
               fanPercent = constrain(fanPercent, 0, 100);
790 735
               ExtUI::setTargetFan_percent(fanPercent, ExtUI::FAN0);
791 736
             }
792
-            else {
737
+            else
793 738
               fanPercent = 100;
794
-            }
795
-            ExtUI::setTargetFan_percent(fanPercent, ExtUI::FAN0);
796 739
 
740
+            ExtUI::setTargetFan_percent(fanPercent, ExtUI::FAN0);
797 741
             SENDLINE_PGM("");
798 742
           }
799 743
           break;
@@ -807,13 +751,11 @@ void AnycubicTFTClass::GetCommandFromTFT() {
807 751
             SENDLINE_PGM("");
808 752
             break;
809 753
 
810
-          case 20: { // A20 read printing speed
811
-
754
+          case 20: // A20 read printing speed
812 755
             if (CodeSeen('S'))
813 756
               feedrate_percentage = constrain(CodeValue(), 40, 999);
814 757
             else
815 758
               SEND_PGM_VAL("A20V ", feedrate_percentage);
816
-          }
817 759
             break;
818 760
 
819 761
           case 21: // A21 all home

+ 0
- 6
Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h View File

@@ -23,12 +23,6 @@
23 23
 #include "../../../../inc/MarlinConfigPre.h"
24 24
 #include "../../../../sd/SdFatConfig.h"   // for the FILENAME_LENGTH macro
25 25
 
26
-char *itostr2(const uint8_t &x);
27
-#ifndef ULTRA_LCD
28
-  char *itostr3(const int);
29
-  char *ftostr32(const float &);
30
-#endif
31
-
32 26
 #define TFTBUFSIZE 4
33 27
 #define TFT_MAX_CMD_SIZE 96
34 28
 

+ 7
- 0
Marlin/src/libs/numtostr.cpp View File

@@ -52,6 +52,13 @@ const char* ui8tostr3rj(const uint8_t i) {
52 52
   return &conv[4];
53 53
 }
54 54
 
55
+// Convert uint8_t to string with 12 format
56
+const char* ui8tostr2(const uint8_t i) {
57
+  conv[5] = DIGIMOD(i, 10);
58
+  conv[6] = DIGIMOD(i, 1);
59
+  return &conv[5];
60
+}
61
+
55 62
 // Convert signed 8bit int to rj string with 123 or -12 format
56 63
 const char* i8tostr3rj(const int8_t x) {
57 64
   int xx = x;

+ 3
- 0
Marlin/src/libs/numtostr.h View File

@@ -26,6 +26,9 @@
26 26
 // Convert a full-range unsigned 8bit int to a percentage
27 27
 const char* ui8tostr4pctrj(const uint8_t i);
28 28
 
29
+// Convert uint8_t to string with 12 format
30
+const char* ui8tostr2(const uint8_t x);
31
+
29 32
 // Convert uint8_t to string with 123 format
30 33
 const char* ui8tostr3rj(const uint8_t i);
31 34
 

Loading…
Cancel
Save