Nick
4 years ago
committed by
Scott Lahteine
16 changed files with 1735 additions and 573 deletions
@ -0,0 +1,162 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
|
|||
/**
|
|||
* lcd/extui/lib/FileNavigator.cpp |
|||
* |
|||
* Extensible_UI implementation for Anycubic Chiron |
|||
* Written By Nick Wells, 2020 [https://github.com/SwiftNick]
|
|||
* (not affiliated with Anycubic, Ltd.) |
|||
*/ |
|||
|
|||
/***************************************************************************
|
|||
* The AC panel wants files in block of 4 and can only display a flat list * |
|||
* This library allows full folder traversal. * |
|||
***************************************************************************/ |
|||
|
|||
#include "../../../../inc/MarlinConfigPre.h" |
|||
|
|||
#if ENABLED(ANYCUBIC_LCD_CHIRON) |
|||
|
|||
#include "FileNavigator.h" |
|||
#include "chiron_tft.h" |
|||
|
|||
using namespace ExtUI; |
|||
|
|||
namespace Anycubic { |
|||
|
|||
FileList FileNavigator::filelist; // Instance of the Marlin file API
|
|||
char FileNavigator::currentfoldername[MAX_PATH_LEN]; // Current folder path
|
|||
uint16_t FileNavigator::lastindex; |
|||
uint8_t FileNavigator::folderdepth; |
|||
uint16_t FileNavigator::currentindex; // override the panel request
|
|||
|
|||
FileNavigator::FileNavigator() { reset(); } |
|||
|
|||
void FileNavigator::reset() { |
|||
currentfoldername[0] = '\0'; |
|||
folderdepth = 0; |
|||
currentindex = 0; |
|||
lastindex = 0; |
|||
// Start at root folder
|
|||
while (!filelist.isAtRootDir()) filelist.upDir(); |
|||
refresh(); |
|||
} |
|||
|
|||
void FileNavigator::refresh() { filelist.refresh(); } |
|||
|
|||
void FileNavigator::getFiles(uint16_t index) { |
|||
uint8_t files = 4; |
|||
if (index == 0) currentindex = 0; |
|||
|
|||
// Each time we change folder we reset the file index to 0 and keep track
|
|||
// of the current position as the TFT panel isnt aware of folders trees.
|
|||
if (index > 0) { |
|||
--currentindex; // go back a file to take account off the .. we added to the root.
|
|||
if (index > lastindex) |
|||
currentindex += files; |
|||
else |
|||
currentindex = currentindex < 4 ? 0 : currentindex - files; |
|||
} |
|||
lastindex = index; |
|||
|
|||
#if ACDEBUG(AC_FILE) |
|||
SERIAL_ECHOLNPAIR("index=", index, " currentindex=", currentindex); |
|||
#endif |
|||
|
|||
if (currentindex == 0 && folderdepth > 0) { // Add a link to go up a folder
|
|||
TFTSer.println("<<"); |
|||
TFTSer.println(".."); |
|||
files--; |
|||
} |
|||
|
|||
for (uint16_t seek = currentindex; seek < currentindex + files; seek++) { |
|||
if (filelist.seek(seek)) { |
|||
sendFile(); |
|||
#if ACDEBUG(AC_FILE) |
|||
SERIAL_ECHOLNPAIR("-", seek, " '", filelist.longFilename(), "' '", currentfoldername, "", filelist.shortFilename(), "'\n"); |
|||
#endif |
|||
} |
|||
} |
|||
} |
|||
|
|||
void FileNavigator::sendFile() { |
|||
// send the file and folder info to the panel
|
|||
// this info will be returned when the file is selected
|
|||
// Permitted special characters in file name -_*#~
|
|||
// Panel can display 22 characters per line
|
|||
if (filelist.isDir()) { |
|||
//TFTSer.print(currentfoldername);
|
|||
TFTSer.println(filelist.shortFilename()); |
|||
TFTSer.print(filelist.shortFilename()); |
|||
TFTSer.println("/"); |
|||
} |
|||
else { |
|||
// Logical Name
|
|||
TFTSer.print("/"); |
|||
if (folderdepth > 0) TFTSer.print(currentfoldername); |
|||
|
|||
TFTSer.println(filelist.shortFilename()); |
|||
|
|||
// Display Name
|
|||
TFTSer.println(filelist.longFilename()); |
|||
} |
|||
} |
|||
void FileNavigator::changeDIR(char *folder) { |
|||
#if ACDEBUG(AC_FILE) |
|||
SERIAL_ECHOLNPAIR("currentfolder: ", currentfoldername, " New: ", folder); |
|||
#endif |
|||
if (folderdepth >= MAX_FOLDER_DEPTH) return; // limit the folder depth
|
|||
strcat(currentfoldername, folder); |
|||
strcat(currentfoldername, "/"); |
|||
filelist.changeDir(folder); |
|||
refresh(); |
|||
folderdepth++; |
|||
currentindex = 0; |
|||
} |
|||
|
|||
void FileNavigator::upDIR() { |
|||
filelist.upDir(); |
|||
refresh(); |
|||
folderdepth--; |
|||
currentindex = 0; |
|||
// Remove the last child folder from the stored path
|
|||
if (folderdepth == 0) { |
|||
currentfoldername[0] = '\0'; |
|||
reset(); |
|||
} |
|||
else { |
|||
char *pos = nullptr; |
|||
for (uint8_t f = 0; f < folderdepth; f++) |
|||
pos = strchr(currentfoldername, '/'); |
|||
|
|||
*(pos + 1) = '\0'; |
|||
} |
|||
#if ACDEBUG(AC_FILE) |
|||
SERIAL_ECHOLNPAIR("depth: ", folderdepth, " currentfoldername: ", currentfoldername); |
|||
#endif |
|||
} |
|||
|
|||
char* FileNavigator::getCurrentFolderName() { return currentfoldername; } |
|||
} |
|||
|
|||
#endif // ANYCUBIC_LCD_CHIRON
|
@ -0,0 +1,56 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
#pragma once |
|||
|
|||
/**
|
|||
* lcd/extui/lib/FileNavigator.h |
|||
* |
|||
* Extensible_UI implementation for Anycubic Chiron |
|||
* Written By Nick Wells, 2020 [https://github.com/SwiftNick]
|
|||
* (not affiliated with Anycubic, Ltd.) |
|||
*/ |
|||
|
|||
#include "chiron_tft_defs.h" |
|||
#include "../../ui_api.h" |
|||
|
|||
using namespace ExtUI; |
|||
|
|||
namespace Anycubic { |
|||
class FileNavigator { |
|||
public: |
|||
FileNavigator(); |
|||
void reset(); |
|||
void getFiles(uint16_t); |
|||
void upDIR(); |
|||
void changeDIR(char *); |
|||
void sendFile(); |
|||
void refresh(); |
|||
char * getCurrentFolderName(); |
|||
private: |
|||
static FileList filelist; |
|||
static char currentfoldername[MAX_PATH_LEN]; |
|||
static uint16_t lastindex; |
|||
static uint8_t folderdepth; |
|||
static uint16_t currentindex; |
|||
}; |
|||
extern FileNavigator filenavigator; |
|||
} |
@ -0,0 +1,62 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
|
|||
/**
|
|||
* lcd/extui/lib/Tunes.cpp |
|||
* |
|||
* Extensible_UI implementation for Anycubic Chiron |
|||
* Written By Nick Wells, 2020 [https://github.com/SwiftNick]
|
|||
* (not affiliated with Anycubic, Ltd.) |
|||
*/ |
|||
|
|||
/***********************************************************************
|
|||
* A Utility to play tunes using the buzzer in the printer controller. * |
|||
* See Tunes.h for note and tune definitions. * |
|||
***********************************************************************/ |
|||
|
|||
#include "../../../../inc/MarlinConfigPre.h" |
|||
|
|||
#if ENABLED(ANYCUBIC_LCD_CHIRON) |
|||
|
|||
#include "Tunes.h" |
|||
#include "../../ui_api.h" |
|||
|
|||
namespace Anycubic { |
|||
|
|||
void PlayTune(uint8_t beeperPin, const uint16_t *tune, uint8_t speed=1) { |
|||
uint8_t pos = 1; |
|||
uint16_t wholenotelen = tune[0] / speed; |
|||
do { |
|||
uint16_t freq = tune[pos]; |
|||
uint16_t notelen = wholenotelen / tune[pos + 1]; |
|||
|
|||
::tone(beeperPin, freq, notelen); |
|||
ExtUI::delay_ms(notelen); |
|||
pos += 2; |
|||
|
|||
if (pos >= MAX_TUNE_LENGTH) break; |
|||
} while (tune[pos] != n_END); |
|||
} |
|||
|
|||
} |
|||
|
|||
#endif // ANYCUBIC_LCD_CHIRON
|
@ -0,0 +1,224 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
#pragma once |
|||
|
|||
/**
|
|||
* lcd/extui/lib/Tunes.h |
|||
* |
|||
* Extensible_UI implementation for Anycubic Chiron |
|||
* Written By Nick Wells, 2020 [https://github.com/SwiftNick]
|
|||
* (not affiliated with Anycubic, Ltd.) |
|||
*/ |
|||
|
|||
/**************************************************************************
|
|||
* Notes definition from https://pages.mtu.edu/~suits/NoteFreqCalcs.html *
|
|||
* * |
|||
* The format of a tune is: * |
|||
* {<whole note time>,<note1>,<length1>, <note2>,<length2>, ... <END>} * |
|||
* * |
|||
* 1) The first value is the length of a whole note in milliseconds * |
|||
* 2) Then a sequence of pitch and duration pairs * |
|||
* 3) Finally the END marker so your tunes can be any length up to * |
|||
* MAX_TUNE_LEN * |
|||
*************************************************************************/ |
|||
|
|||
#include <stdint.h> |
|||
|
|||
#define MAX_TUNE_LENGTH 128 |
|||
|
|||
// Special notes!
|
|||
#define n_P 0 // silence or pause
|
|||
#define n_END 10000 // end of tune marker
|
|||
|
|||
// Note duration divisors
|
|||
#define l_T1 1 |
|||
#define l_T2 2 |
|||
#define l_T3 3 |
|||
#define l_T4 4 |
|||
#define l_T8 8 |
|||
#define l_T16 16 |
|||
|
|||
// Note Frequency
|
|||
#define n_C0 16 |
|||
#define n_CS0 17 |
|||
#define n_D0 18 |
|||
#define n_DS0 19 |
|||
#define n_E0 21 |
|||
#define n_F0 22 |
|||
#define n_FS0 23 |
|||
#define n_G0 25 |
|||
#define n_GS0 26 |
|||
#define n_A0 28 |
|||
#define n_AS0 29 |
|||
#define n_B0 31 |
|||
#define n_C1 33 |
|||
#define n_CS1 35 |
|||
#define n_D1 37 |
|||
#define n_DS1 39 |
|||
#define n_E1 41 |
|||
#define n_F1 44 |
|||
#define n_FS1 46 |
|||
#define n_G1 49 |
|||
#define n_GS1 52 |
|||
#define n_A1 55 |
|||
#define n_AS1 58 |
|||
#define n_B1 62 |
|||
#define n_C2 65 |
|||
#define n_CS2 69 |
|||
#define n_D2 73 |
|||
#define n_DS2 78 |
|||
#define n_E2 82 |
|||
#define n_F2 87 |
|||
#define n_FS2 93 |
|||
#define n_G2 98 |
|||
#define n_GS2 104 |
|||
#define n_A2 110 |
|||
#define n_AS2 117 |
|||
#define n_B2 123 |
|||
#define n_C3 131 |
|||
#define n_CS3 139 |
|||
#define n_D3 147 |
|||
#define n_DS3 156 |
|||
#define n_E3 165 |
|||
#define n_F3 175 |
|||
#define n_FS3 185 |
|||
#define n_G3 196 |
|||
#define n_GS3 208 |
|||
#define n_A3 220 |
|||
#define n_AS3 233 |
|||
#define n_B3 247 |
|||
#define n_C4 262 |
|||
#define n_CS4 277 |
|||
#define n_D4 294 |
|||
#define n_DS4 311 |
|||
#define n_E4 330 |
|||
#define n_F4 349 |
|||
#define n_FS4 370 |
|||
#define n_G4 392 |
|||
#define n_GS4 415 |
|||
#define n_A4 440 |
|||
#define n_AS4 466 |
|||
#define n_B4 494 |
|||
#define n_C5 523 |
|||
#define n_CS5 554 |
|||
#define n_D5 587 |
|||
#define n_DS5 622 |
|||
#define n_E5 659 |
|||
#define n_F5 698 |
|||
#define n_FS5 740 |
|||
#define n_G5 784 |
|||
#define n_GS5 831 |
|||
#define n_A5 880 |
|||
#define n_AS5 932 |
|||
#define n_B5 988 |
|||
#define n_C6 1047 |
|||
#define n_CS6 1109 |
|||
#define n_D6 1175 |
|||
#define n_DS6 1245 |
|||
#define n_E6 1319 |
|||
#define n_F6 1397 |
|||
#define n_FS6 1480 |
|||
#define n_G6 1568 |
|||
#define n_GS6 1661 |
|||
#define n_A6 1760 |
|||
#define n_AS6 1865 |
|||
#define n_B6 1976 |
|||
#define n_C7 2093 |
|||
#define n_CS7 2217 |
|||
#define n_D7 2349 |
|||
#define n_DS7 2489 |
|||
#define n_E7 2637 |
|||
#define n_F7 2794 |
|||
#define n_FS7 2960 |
|||
#define n_G7 3136 |
|||
#define n_GS7 3322 |
|||
#define n_A7 3520 |
|||
#define n_AS7 3729 |
|||
#define n_B7 3951 |
|||
#define n_C8 4186 |
|||
#define n_CS8 4435 |
|||
#define n_D8 4699 |
|||
#define n_DS8 4978 |
|||
#define n_E8 5274 |
|||
#define n_F8 5587 |
|||
#define n_FS8 5920 |
|||
#define n_G8 6272 |
|||
#define n_GS8 6645 |
|||
#define n_A8 7040 |
|||
#define n_AS8 7459 |
|||
#define n_B8 7902 |
|||
|
|||
namespace Anycubic { |
|||
|
|||
void PlayTune(uint8_t beeperPin, const uint16_t *tune, uint8_t speed); |
|||
|
|||
// Only uncomment the tunes you are using to save memory
|
|||
// This will help you write tunes!
|
|||
// https://www.apronus.com/music/flashpiano.htm
|
|||
|
|||
const uint16_t SOS[] = { |
|||
250, |
|||
n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T1, |
|||
n_G6,l_T1, n_P,l_T3, n_G6,l_T1, n_P,l_T3, n_G6,l_T1, n_P,l_T1, |
|||
n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T1, |
|||
n_END |
|||
}; |
|||
|
|||
const uint16_t BeepBeep[] = { |
|||
500, |
|||
n_C7,l_T8, n_P,l_T16, n_C7,l_T8, n_P,l_T8, |
|||
n_END |
|||
}; |
|||
|
|||
const uint16_t BeepBeepBeeep[] = { |
|||
1000, |
|||
n_G7,l_T4, n_P,l_T16, n_G7,l_T4, n_P,l_T8, n_G7,l_T2, |
|||
n_END |
|||
}; |
|||
|
|||
const uint16_t Anycubic_PowerOn[] = { |
|||
1000, |
|||
n_F7,l_T8, n_P,l_T8, n_C7,l_T8, n_P,l_T8, n_D7,l_T8, n_P,l_T8, |
|||
n_E7,l_T8, n_P,l_T8, n_D7,l_T4, n_P,l_T4, n_G7,l_T4, n_P,l_T4, |
|||
n_A7,l_T2, n_P,l_T1, |
|||
n_END |
|||
}; |
|||
|
|||
const uint16_t GB_PowerOn[] = { |
|||
500, |
|||
n_C6,l_T4, n_P,l_T16, n_C7,l_T2, n_P,l_T8, |
|||
n_END |
|||
}; |
|||
|
|||
const uint16_t Heater_Timedout[] = { |
|||
1000, |
|||
n_C6,l_T1, |
|||
n_END |
|||
}; |
|||
|
|||
const uint16_t FilamentOut[] = { |
|||
1000, |
|||
n_AS7,l_T4, n_P,l_T16, n_FS7,l_T2, |
|||
n_END |
|||
}; |
|||
|
|||
} |
@ -0,0 +1,896 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
|
|||
/**
|
|||
* lcd/extui/lib/chiron_tft.cpp |
|||
* |
|||
* Extensible_UI implementation for Anycubic Chiron |
|||
* Written By Nick Wells, 2020 [https://github.com/SwiftNick]
|
|||
* (not affiliated with Anycubic, Ltd.) |
|||
*/ |
|||
|
|||
#include "../../../../inc/MarlinConfigPre.h" |
|||
|
|||
#if ENABLED(ANYCUBIC_LCD_CHIRON) |
|||
|
|||
#include "chiron_tft.h" |
|||
#include "Tunes.h" |
|||
#include "FileNavigator.h" |
|||
|
|||
#include "../../../../gcode/queue.h" |
|||
#include "../../../../sd/cardreader.h" |
|||
#include "../../../../libs/numtostr.h" |
|||
#include "../../../../MarlinCore.h" |
|||
namespace Anycubic { |
|||
|
|||
printer_state_t ChironTFT::printer_state; |
|||
paused_state_t ChironTFT::pause_state; |
|||
heater_state_t ChironTFT::hotend_state; |
|||
heater_state_t ChironTFT::hotbed_state; |
|||
xy_uint8_t ChironTFT::selectedmeshpoint; |
|||
char ChironTFT::selectedfile[MAX_PATH_LEN]; |
|||
char ChironTFT::panel_command[MAX_CMND_LEN]; |
|||
uint8_t ChironTFT::command_len; |
|||
float ChironTFT::live_Zoffset; |
|||
file_menu_t ChironTFT::file_menu; |
|||
|
|||
ChironTFT::ChironTFT(){} |
|||
|
|||
void ChironTFT::Startup() { |
|||
selectedfile[0] = '\0'; |
|||
panel_command[0] = '\0'; |
|||
command_len = 0; |
|||
printer_state = AC_printer_idle; |
|||
pause_state = AC_paused_idle; |
|||
hotend_state = AC_heater_off; |
|||
hotbed_state = AC_heater_off; |
|||
live_Zoffset = 0.0; |
|||
file_menu = AC_menu_file; |
|||
|
|||
// Setup pins for powerloss detection
|
|||
// Two IO pins are connected on the Trigorilla Board
|
|||
// On a power interruption the OUTAGECON_PIN goes low.
|
|||
|
|||
#if ENABLED(POWER_LOSS_RECOVERY) |
|||
OUT_WRITE(OUTAGECON_PIN, HIGH); |
|||
#endif |
|||
|
|||
// Filament runout is handled by Marlin settings in Configuration.h
|
|||
// set FIL_RUNOUT_STATE HIGH // Pin state indicating that filament is NOT present.
|
|||
// enable FIL_RUNOUT_PULLUP
|
|||
|
|||
TFTSer.begin(115200); |
|||
|
|||
// Signal Board has reset
|
|||
SendtoTFTLN(AC_msg_main_board_has_reset); |
|||
|
|||
safe_delay(200); |
|||
|
|||
// Enable levelling and Disable end stops during print
|
|||
// as Z home places nozzle above the bed so we need to allow it past the end stops
|
|||
injectCommands_P(AC_cmnd_enable_levelling); //M211 S0\n"));
|
|||
|
|||
// Startup tunes are defined in Tunes.h
|
|||
//PlayTune(BEEPER_PIN, Anycubic_PowerOn, 1);
|
|||
PlayTune(BEEPER_PIN, GB_PowerOn, 1); |
|||
#if ACDEBUGLEVEL |
|||
SERIAL_ECHOLNPAIR("AC Debug Level ", ACDEBUGLEVEL); |
|||
#endif |
|||
SendtoTFTLN(AC_msg_ready); |
|||
} |
|||
|
|||
void ChironTFT::IdleLoop() { |
|||
if (ReadTFTCommand()) { |
|||
ProcessPanelRequest(); |
|||
command_len = 0; |
|||
} |
|||
CheckHeaters(); |
|||
} |
|||
|
|||
void ChironTFT::PrinterKilled(PGM_P error,PGM_P component) { |
|||
SendtoTFTLN(AC_msg_kill_lcd); |
|||
#if ACDEBUG(AC_MARLIN) |
|||
SERIAL_ECHOLNPAIR("PrinterKilled()\nerror: ", error , "\ncomponent: ", component); |
|||
#endif |
|||
} |
|||
|
|||
void ChironTFT::MediaEvent(media_event_t event) { |
|||
#if ACDEBUG(AC_MARLIN) |
|||
SERIAL_ECHOLNPAIR("ProcessMediaStatus() ", event); |
|||
#endif |
|||
switch (event) { |
|||
case AC_media_inserted: |
|||
SendtoTFTLN(AC_msg_sd_card_inserted); |
|||
break; |
|||
|
|||
case AC_media_removed: |
|||
SendtoTFTLN(AC_msg_sd_card_removed); |
|||
break; |
|||
|
|||
case AC_media_error: |
|||
SendtoTFTLN(AC_msg_no_sd_card); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void ChironTFT::TimerEvent(timer_event_t event) { |
|||
#if ACDEBUG(AC_MARLIN) |
|||
SERIAL_ECHOLNPAIR("TimerEvent() ", event); |
|||
SERIAL_ECHOLNPAIR("Printer State: ", printer_state); |
|||
#endif |
|||
|
|||
switch (event) { |
|||
case AC_timer_started: { |
|||
live_Zoffset = 0.0; // reset print offset
|
|||
setSoftEndstopState(false); // disable endstops to print
|
|||
printer_state = AC_printer_printing; |
|||
SendtoTFTLN(AC_msg_print_from_sd_card); |
|||
} break; |
|||
|
|||
case AC_timer_paused: { |
|||
printer_state = AC_printer_paused; |
|||
pause_state = AC_paused_idle; |
|||
SendtoTFTLN(AC_msg_paused); |
|||
} break; |
|||
|
|||
case AC_timer_stopped: { |
|||
if (printer_state != AC_printer_idle) { |
|||
printer_state = AC_printer_stopping; |
|||
SendtoTFTLN(AC_msg_print_complete); |
|||
} |
|||
setSoftEndstopState(true); // enable endstops
|
|||
} break; |
|||
} |
|||
} |
|||
|
|||
void ChironTFT::FilamentRunout() { |
|||
#if ACDEBUG(AC_MARLIN) |
|||
SERIAL_ECHOLNPAIR("FilamentRunout() printer_state ", printer_state); |
|||
#endif |
|||
// 1 Signal filament out
|
|||
SendtoTFTLN(isPrintingFromMedia() ? AC_msg_filament_out_alert : AC_msg_filament_out_block); |
|||
//printer_state = AC_printer_filament_out;
|
|||
PlayTune(BEEPER_PIN, FilamentOut, 1); |
|||
} |
|||
|
|||
void ChironTFT::ConfirmationRequest(const char * const msg) { |
|||
// M108 continue
|
|||
#if ACDEBUG(AC_MARLIN) |
|||
SERIAL_ECHOLNPAIR("ConfirmationRequest() ", msg, " printer_state:", printer_state); |
|||
#endif |
|||
switch (printer_state) { |
|||
case AC_printer_pausing: { |
|||
if ( (strcmp_P(msg, MARLIN_msg_print_paused) == 0 ) || (strcmp_P(msg, MARLIN_msg_nozzle_parked) == 0 ) ) { |
|||
SendtoTFTLN(AC_msg_paused); // enable continue button
|
|||
printer_state = AC_printer_paused; |
|||
} |
|||
} break; |
|||
|
|||
case AC_printer_resuming_from_power_outage: |
|||
case AC_printer_printing: |
|||
case AC_printer_paused: { |
|||
// Heater timout, send acknowledgement
|
|||
if (strcmp_P(msg, MARLIN_msg_heater_timeout) == 0 ) { |
|||
pause_state = AC_paused_heater_timed_out; |
|||
SendtoTFTLN(AC_msg_paused); // enable continue button
|
|||
PlayTune(BEEPER_PIN,Heater_Timedout,1); |
|||
} |
|||
// Reheat finished, send acknowledgement
|
|||
else if (strcmp_P(msg, MARLIN_msg_reheat_done) == 0 ) { |
|||
pause_state = AC_paused_idle; |
|||
SendtoTFTLN(AC_msg_paused); // enable continue button
|
|||
} |
|||
// Filament Purging, send acknowledgement enter run mode
|
|||
else if (strcmp_P(msg, MARLIN_msg_filament_purging) == 0 ) { |
|||
pause_state = AC_paused_purging_filament; |
|||
SendtoTFTLN(AC_msg_paused); // enable continue button
|
|||
} |
|||
} break; |
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void ChironTFT::StatusChange(const char * const msg) { |
|||
#if ACDEBUG(AC_MARLIN) |
|||
SERIAL_ECHOLNPAIR("StatusChange() ", msg); |
|||
SERIAL_ECHOLNPAIR("printer_state:", printer_state); |
|||
#endif |
|||
bool msg_matched = false; |
|||
// The only way to get printer status is to parse messages
|
|||
// Use the state to minimise the work we do here.
|
|||
switch (printer_state) { |
|||
case AC_printer_probing: { |
|||
// If probing completes ok save the mesh and park
|
|||
if (strcmp_P(msg, MARLIN_msg_ready) == 0 ) { |
|||
injectCommands_P(PSTR("M500\nG27")); |
|||
SendtoTFTLN(AC_msg_probing_complete); |
|||
printer_state = AC_printer_idle; |
|||
msg_matched = true; |
|||
} |
|||
// If probing fails dont save the mesh raise the probe above the bad point
|
|||
if (strcmp_P(msg, MARLIN_msg_probing_failed) == 0 ) { |
|||
PlayTune(BEEPER_PIN, BeepBeepBeeep, 1); |
|||
injectCommands_P(PSTR("G1 Z50 F500")); |
|||
SendtoTFTLN(AC_msg_probing_complete); |
|||
printer_state = AC_printer_idle; |
|||
msg_matched = true; |
|||
} |
|||
} break; |
|||
|
|||
case AC_printer_printing: { |
|||
if (strcmp_P(msg, MARLIN_msg_reheating) == 0 ) { |
|||
SendtoTFTLN(AC_msg_paused); // enable continue button
|
|||
msg_matched = true; |
|||
} |
|||
} break; |
|||
|
|||
case AC_printer_pausing: { |
|||
if (strcmp_P(msg, MARLIN_msg_print_paused) == 0 ) { |
|||
SendtoTFTLN(AC_msg_paused); |
|||
printer_state = AC_printer_paused; |
|||
pause_state = AC_paused_idle; |
|||
msg_matched = true; |
|||
} |
|||
} break; |
|||
|
|||
case AC_printer_stopping: { |
|||
if (strcmp_P(msg, MARLIN_msg_print_aborted) == 0 ) { |
|||
SendtoTFTLN(AC_msg_stop); |
|||
printer_state = AC_printer_idle; |
|||
msg_matched = true; |
|||
} |
|||
} break; |
|||
default: |
|||
break; |
|||
} |
|||
|
|||
// If not matched earlier see if this was a heater message
|
|||
if (!msg_matched) { |
|||
if (strcmp_P(msg, MARLIN_msg_extruder_heating) == 0) { |
|||
SendtoTFTLN(AC_msg_nozzle_heating); |
|||
hotend_state = AC_heater_temp_set; |
|||
} |
|||
else if (strcmp_P(msg, MARLIN_msg_bed_heating) == 0) { |
|||
SendtoTFTLN(AC_msg_bed_heating); |
|||
hotbed_state = AC_heater_temp_set; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void ChironTFT::PowerLossRecovery() { |
|||
printer_state = AC_printer_resuming_from_power_outage; // Play tune to notify user we can recover.
|
|||
PlayTune(BEEPER_PIN, SOS, 1); |
|||
SERIAL_ECHOLNPGM("Resuming from power outage..."); |
|||
SERIAL_ECHOLNPGM("Select SD file then press resume"); |
|||
} |
|||
|
|||
void ChironTFT::SendtoTFT(PGM_P str) { // A helper to print PROGMEN string to the panel
|
|||
#if ACDEBUG(AC_SOME) |
|||
serialprintPGM(str); |
|||
#endif |
|||
while (const char c = pgm_read_byte(str++)) TFTSer.print(c); |
|||
} |
|||
|
|||
void ChironTFT::SendtoTFTLN(PGM_P str = nullptr) { |
|||
if (str != nullptr) { |
|||
#if ACDEBUG(AC_SOME) |
|||
SERIAL_ECHO("> "); |
|||
#endif |
|||
SendtoTFT(str); |
|||
#if ACDEBUG(AC_SOME) |
|||
SERIAL_EOL(); |
|||
#endif |
|||
} |
|||
TFTSer.println(""); |
|||
} |
|||
|
|||
bool ChironTFT::ReadTFTCommand() { |
|||
bool command_ready = false; |
|||
while( (TFTSer.available() > 0) && (command_len < MAX_CMND_LEN) ) { |
|||
panel_command[command_len] = TFTSer.read(); |
|||
if(panel_command[command_len] == '\n') { |
|||
command_ready = true; |
|||
break; |
|||
} |
|||
command_len++; |
|||
} |
|||
|
|||
if(command_ready) { |
|||
panel_command[command_len] = 0x00; |
|||
#if ACDEBUG(AC_ALL) |
|||
SERIAL_ECHOLNPAIR("< ", panel_command); |
|||
#endif |
|||
#if ACDEBUG(AC_SOME) |
|||
// Ignore status request commands
|
|||
uint8_t req = atoi(&panel_command[1]); |
|||
if (req > 7 && req != 20) { |
|||
SERIAL_ECHOLNPAIR("> ", panel_command); |
|||
SERIAL_ECHOLNPAIR("printer_state:", printer_state); |
|||
} |
|||
#endif |
|||
} |
|||
return command_ready; |
|||
} |
|||
|
|||
int8_t ChironTFT::Findcmndpos(const char * buff, char q) { |
|||
bool found = false; |
|||
int8_t pos = 0; |
|||
do { |
|||
if (buff[pos] == q) { |
|||
found = true; |
|||
break; |
|||
} |
|||
pos ++; |
|||
} while(pos < MAX_CMND_LEN); |
|||
if (found) return pos; |
|||
return -1; |
|||
} |
|||
|
|||
void ChironTFT::CheckHeaters() { |
|||
uint8_t faultDuration = 0; float temp = 0; |
|||
|
|||
// if the hotend temp is abnormal, confirm state before signalling panel
|
|||
temp = getActualTemp_celsius(E0); |
|||
if ( (temp <= HEATER_0_MINTEMP) || (temp >= HEATER_0_MAXTEMP) ) { |
|||
do { |
|||
faultDuration ++; |
|||
if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) { |
|||
SendtoTFTLN(AC_msg_nozzle_temp_abnormal); |
|||
SERIAL_ECHOLNPAIR("Extruder temp abnormal! : ", temp); |
|||
break; |
|||
} |
|||
delay_ms(500); |
|||
temp = getActualTemp_celsius(E0); |
|||
} while ((temp <= HEATER_0_MINTEMP) || (temp >= HEATER_0_MAXTEMP) ); |
|||
} |
|||
|
|||
// if the hotbed temp is abnormal, confirm state before signalling panel
|
|||
faultDuration = 0; |
|||
temp = getActualTemp_celsius(BED); |
|||
if ( (temp <= BED_MINTEMP) || (temp >= BED_MAXTEMP) ) { |
|||
do { |
|||
faultDuration ++; |
|||
if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) { |
|||
SendtoTFTLN(AC_msg_nozzle_temp_abnormal); |
|||
SERIAL_ECHOLNPAIR_P("Bed temp abnormal! : ", temp); |
|||
break; |
|||
} |
|||
delay_ms(500); |
|||
temp = getActualTemp_celsius(E0); |
|||
} while ((temp <= BED_MINTEMP) || (temp >= BED_MAXTEMP) ); |
|||
} |
|||
|
|||
// Update panel with hotend heater status
|
|||
if (hotend_state != AC_heater_temp_reached) { |
|||
if ( WITHIN( getActualTemp_celsius(E0) - getTargetTemp_celsius(E0), -1, 1 ) ) { |
|||
SendtoTFTLN(AC_msg_nozzle_heating_done); |
|||
hotend_state = AC_heater_temp_reached; |
|||
} |
|||
} |
|||
|
|||
// Update panel with bed heater status
|
|||
if (hotbed_state != AC_heater_temp_reached) { |
|||
if ( WITHIN( getActualTemp_celsius(BED) - getTargetTemp_celsius(BED), -0.5, 0.5 ) ) { |
|||
SendtoTFTLN(AC_msg_bed_heating_done); |
|||
hotbed_state = AC_heater_temp_reached; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void ChironTFT::SendFileList(int8_t startindex) { |
|||
// respond to panel request for 4 files starting at index
|
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("## SendFileList ## ", startindex); |
|||
#endif |
|||
SendtoTFTLN(PSTR("FN ")); |
|||
filenavigator.getFiles(startindex); |
|||
SendtoTFTLN(PSTR("END")); |
|||
} |
|||
|
|||
void ChironTFT::SelectFile() { |
|||
strncpy(selectedfile,panel_command+4,command_len-4); |
|||
selectedfile[command_len-5] = '\0'; |
|||
#if ACDEBUG(AC_FILE) |
|||
SERIAL_ECHOLNPAIR_F(" Selected File: ",selectedfile); |
|||
#endif |
|||
switch (selectedfile[0]) { |
|||
case '/': // Valid file selected
|
|||
SendtoTFTLN(AC_msg_sd_file_open_success); |
|||
break; |
|||
|
|||
case '<': // .. (go up folder level)
|
|||
filenavigator.upDIR(); |
|||
SendtoTFTLN(AC_msg_sd_file_open_failed); |
|||
SendFileList( 0 ); |
|||
break; |
|||
default: // enter sub folder
|
|||
filenavigator.changeDIR(selectedfile); |
|||
SendtoTFTLN(AC_msg_sd_file_open_failed); |
|||
SendFileList( 0 ); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void ChironTFT::InjectCommandandWait(PGM_P cmd) { |
|||
//injectCommands_P(cmnd); queue.enqueue_now_P(cmd);
|
|||
//SERIAL_ECHOLN(PSTR("Inject>"));
|
|||
} |
|||
|
|||
void ChironTFT::ProcessPanelRequest() { |
|||
// Break these up into logical blocks // as its easier to navigate than one huge switch case!
|
|||
int8_t req = atoi(&panel_command[1]); |
|||
|
|||
// Information requests A0 - A8 and A33
|
|||
if (req <= 8 || req == 33) PanelInfo(req); |
|||
|
|||
// Simple Actions A9 - A28
|
|||
else if ( req <= 28) PanelAction(req); |
|||
|
|||
// Process Initiation
|
|||
else if (req <= 34) PanelProcess(req); |
|||
|
|||
else SendtoTFTLN(); |
|||
} |
|||
|
|||
void ChironTFT::PanelInfo(uint8_t req) { |
|||
// information requests A0-A8 and A33
|
|||
switch (req) { |
|||
case 0: // A0 Get HOTEND Temp
|
|||
SendtoTFT(PSTR("A0V ")); |
|||
TFTSer.println(getActualTemp_celsius(E0)); |
|||
break; |
|||
|
|||
case 1: // A1 Get HOTEND Target Temp
|
|||
SendtoTFT(PSTR("A1V ")); |
|||
TFTSer.println(getTargetTemp_celsius(E0)); |
|||
break; |
|||
|
|||
case 2: // A2 Get BED Temp
|
|||
SendtoTFT(PSTR("A2V ")); |
|||
TFTSer.println(getActualTemp_celsius(BED)); |
|||
break; |
|||
|
|||
case 3: // A3 Get BED Target Temp
|
|||
SendtoTFT(PSTR("A3V ")); |
|||
TFTSer.println(getTargetTemp_celsius(BED)); |
|||
break; |
|||
|
|||
case 4: // A4 Get FAN Speed
|
|||
SendtoTFT(PSTR("A4V ")); |
|||
TFTSer.println(getActualFan_percent(FAN0)); |
|||
break; |
|||
|
|||
case 5: // A5 Get Current Coordinates
|
|||
SendtoTFT(PSTR("A5V X: ")); |
|||
TFTSer.print(getAxisPosition_mm(X)); |
|||
SendtoTFT(PSTR(" Y: ")); |
|||
TFTSer.print(getAxisPosition_mm(Y)); |
|||
SendtoTFT(PSTR(" Z: ")); |
|||
TFTSer.println(getAxisPosition_mm(Z)); |
|||
break; |
|||
|
|||
case 6: // A6 Get printing progress
|
|||
if (isPrintingFromMedia()) { |
|||
SendtoTFT(PSTR("A6V ")); |
|||
TFTSer.println(ui8tostr2(getProgress_percent())); |
|||
|
|||
} |
|||
else |
|||
SendtoTFTLN(PSTR("A6V ---")); |
|||
break; |
|||
|
|||
case 7: { // A7 Get Printing Time
|
|||
uint32_t time = getProgress_seconds_elapsed() / 60; |
|||
SendtoTFT(PSTR("A7V ")); |
|||
TFTSer.print(ui8tostr2(time / 60)); |
|||
SendtoTFT(PSTR(" H ")); |
|||
TFTSer.print(ui8tostr2(time % 60)); |
|||
SendtoTFT(PSTR(" M")); |
|||
#if ACDEBUG(AC_ALL) |
|||
SERIAL_ECHOLNPAIR("Print time ", ui8tostr2(time / 60), ":", ui8tostr2(time % 60)); |
|||
#endif |
|||
} break; |
|||
|
|||
case 8: // A8 Get SD Card list A8 S0
|
|||
if (!isMediaInserted()) safe_delay(500); |
|||
if (!isMediaInserted()) // Make sure the card is removed
|
|||
SendtoTFTLN(AC_msg_no_sd_card); |
|||
else if (panel_command[3] == 'S') |
|||
SendFileList( atoi( &panel_command[4] ) ); |
|||
break; |
|||
|
|||
case 33: // A33 Get firmware info
|
|||
SendtoTFT(PSTR("J33 ")); |
|||
SendtoTFTLN(PSTR(SHORT_BUILD_VERSION)); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void ChironTFT::PanelAction(uint8_t req) { |
|||
switch (req) { |
|||
case 9: // A9 Pause SD print
|
|||
if (isPrintingFromMedia()) { |
|||
SendtoTFTLN(AC_msg_pause); |
|||
pausePrint(); |
|||
printer_state = AC_printer_pausing; |
|||
} |
|||
else |
|||
SendtoTFTLN(AC_msg_stop); |
|||
break; |
|||
|
|||
case 10: // A10 Resume SD Print
|
|||
if (pause_state == AC_paused_idle || printer_state == AC_printer_resuming_from_power_outage) |
|||
resumePrint(); |
|||
else |
|||
setUserConfirmed(); |
|||
break; |
|||
|
|||
case 11: // A11 Stop SD print
|
|||
if (isPrintingFromMedia()) { |
|||
printer_state = AC_printer_stopping; |
|||
stopPrint(); |
|||
} |
|||
else { |
|||
if (printer_state == AC_printer_resuming_from_power_outage) |
|||
injectCommands_P(PSTR("M1000 C\n")); // Cancel recovery
|
|||
SendtoTFTLN(AC_msg_stop); |
|||
printer_state = AC_printer_idle; |
|||
} |
|||
break; |
|||
|
|||
case 12: // A12 Kill printer
|
|||
kill(); // from marlincore.h
|
|||
break; |
|||
|
|||
case 13: // A13 Select file
|
|||
SelectFile(); |
|||
break; |
|||
|
|||
case 14: { // A14 Start Printing
|
|||
// Allows printer to restart the job if we dont want to recover
|
|||
if (printer_state == AC_printer_resuming_from_power_outage) { |
|||
injectCommands_P(PSTR("M1000 C\n")); // Cancel recovery
|
|||
printer_state = AC_printer_idle; |
|||
} |
|||
#if ACDebugLevel >= 1 |
|||
SERIAL_ECHOLNPAIR_F("Print: ", selectedfile); |
|||
#endif |
|||
// the card library needs a path starting // but the File api doesn't...
|
|||
char file[MAX_PATH_LEN]; |
|||
file[0] = '/'; |
|||
strcpy(file + 1, selectedfile); |
|||
printFile(file); |
|||
SendtoTFTLN(AC_msg_print_from_sd_card); |
|||
} break; |
|||
|
|||
case 15: // A15 Resuming from outage
|
|||
if (printer_state == AC_printer_resuming_from_power_outage) |
|||
// Need to home here to restore the Z position
|
|||
injectCommands_P(AC_cmnd_power_loss_recovery); |
|||
|
|||
injectCommands_P(PSTR("M1000\n")); // home and start recovery
|
|||
break; |
|||
|
|||
case 16: { // A16 Set HotEnd temp A17 S170
|
|||
const float set_Htemp = atof(&panel_command[5]); |
|||
hotend_state = set_Htemp ? AC_heater_temp_set : AC_heater_off; |
|||
switch ((char)panel_command[4]) { |
|||
// Set Temp
|
|||
case 'S': case 'C': setTargetTemp_celsius(set_Htemp, E0); |
|||
} |
|||
} break; |
|||
|
|||
case 17: { // A17 Set bed temp
|
|||
const float set_Btemp = atof(&panel_command[5]); |
|||
hotbed_state = set_Btemp ? AC_heater_temp_set : AC_heater_off; |
|||
if (panel_command[4] == 'S') |
|||
setTargetTemp_celsius(set_Btemp, BED); |
|||
} break; |
|||
|
|||
case 18: // A18 Set Fan Speed
|
|||
if (panel_command[4] == 'S') |
|||
setTargetFan_percent(atof(&panel_command[5]), FAN0); |
|||
break; |
|||
|
|||
case 19: // A19 Motors off
|
|||
if (!isPrinting()) { |
|||
disable_all_steppers(); // from marlincore.h
|
|||
SendtoTFTLN(AC_msg_ready); |
|||
} |
|||
break; |
|||
|
|||
case 20: // A20 Read/write print speed
|
|||
if (panel_command[4] == 'S') |
|||
setFeedrate_percent(atoi(&panel_command[5])); |
|||
else { |
|||
SendtoTFT(PSTR("A20V ")); |
|||
TFTSer.println(getFeedrate_percent()); |
|||
} |
|||
break; |
|||
|
|||
case 21: // A21 Home Axis A21 X
|
|||
if (!isPrinting()) { |
|||
switch ((char)panel_command[4]) { |
|||
case 'X': injectCommands_P(PSTR("G28 X\n")); break; |
|||
case 'Y': injectCommands_P(PSTR("G28 Y\n")); break; |
|||
case 'Z': injectCommands_P(PSTR("G28 Z\n")); break; |
|||
case 'C': injectCommands_P(PSTR("G28\n")); break; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case 22: // A22 Move Axis A22 Y +10F3000
|
|||
// Ignore request if printing
|
|||
if (!isPrinting()) { |
|||
// setAxisPosition_mm() uses pre defined manual feedrates so ignore the feedrate from the panel
|
|||
setSoftEndstopState(true); // enable endstops
|
|||
float newposition = atof(&panel_command[6]); |
|||
|
|||
#if ACDEBUG(AC_ACTION) |
|||
SERIAL_ECHOLNPAIR("Nudge ", panel_command[4], " axis ", newposition); |
|||
#endif |
|||
|
|||
switch (panel_command[4]) { |
|||
case 'X': setAxisPosition_mm(getAxisPosition_mm(X) + newposition, X); break; |
|||
case 'Y': setAxisPosition_mm(getAxisPosition_mm(Y) + newposition, Y); break; |
|||
case 'Z': setAxisPosition_mm(getAxisPosition_mm(Z) + newposition, Z); break; |
|||
case 'E': // The only time we get this command is from the filament load/unload menu
|
|||
// the standard movement is too slow so we will use the load unlod GCode to speed it up a bit
|
|||
if (canMove(E0) && !commandsInQueue()) |
|||
injectCommands_P(newposition > 0 ? AC_cmnd_manual_load_filament : AC_cmnd_manual_unload_filament); |
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case 23: // A23 Preheat PLA
|
|||
// Ignore request if printing
|
|||
if (!isPrinting()) { |
|||
// Temps defined in configuration.h
|
|||
setTargetTemp_celsius(PREHEAT_1_TEMP_BED, BED); |
|||
setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, E0); |
|||
SendtoTFTLN(); |
|||
hotbed_state = AC_heater_temp_set; |
|||
hotend_state = AC_heater_temp_set; |
|||
} |
|||
break; |
|||
|
|||
case 24: // A24 Preheat ABS
|
|||
// Ignore request if printing
|
|||
if (!isPrinting()) { |
|||
setTargetTemp_celsius(PREHEAT_2_TEMP_BED, BED); |
|||
setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, E0); |
|||
SendtoTFTLN(); |
|||
hotbed_state = AC_heater_temp_set; |
|||
hotend_state = AC_heater_temp_set; |
|||
} |
|||
break; |
|||
|
|||
case 25: // A25 Cool Down
|
|||
// Ignore request if printing
|
|||
if (!isPrinting()) { |
|||
setTargetTemp_celsius(0, E0); |
|||
setTargetTemp_celsius(0, BED); |
|||
SendtoTFTLN(AC_msg_ready); |
|||
hotbed_state = AC_heater_off; |
|||
hotend_state = AC_heater_off; |
|||
} |
|||
break; |
|||
|
|||
case 26: // A26 Refresh SD
|
|||
// M22 M21 maybe needed here to reset sd card
|
|||
filenavigator.reset(); |
|||
break; |
|||
|
|||
case 27: // A27 Servo Angles adjust
|
|||
break; |
|||
|
|||
case 28: // A28 Filament set A28 O/C
|
|||
// Ignore request if printing
|
|||
if (isPrinting()) break; |
|||
SendtoTFTLN(); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void ChironTFT::PanelProcess(uint8_t req) { |
|||
switch (req) { |
|||
case 29: { // A29 Read Mesh Point A29 X1 Y1
|
|||
xy_uint8_t pos; |
|||
float pos_z; |
|||
pos.x = atoi(&panel_command[5]); |
|||
pos.y = atoi(&panel_command[8]); |
|||
pos_z = getMeshPoint(pos); |
|||
|
|||
SendtoTFT(PSTR("A29V ")); |
|||
TFTSer.println(pos_z * 100); |
|||
if (!isPrinting()) { |
|||
setSoftEndstopState(true); // disable endstops
|
|||
// If the same meshpoint is selected twice in a row, move the head to that ready for adjustment
|
|||
if ((selectedmeshpoint.x == pos.x) && (selectedmeshpoint.y == pos.y)) { |
|||
if (!isPositionKnown()) |
|||
injectCommands_P(PSTR("G28\n")); // home
|
|||
|
|||
if (isPositionKnown()) { |
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("Moving to mesh point at x: ", pos.x, " y: ", pos.y, " z: ", pos_z); |
|||
#endif |
|||
// Go up before moving
|
|||
setAxisPosition_mm(3.0,Z); |
|||
|
|||
setAxisPosition_mm(17 + (93 * pos.x), X); |
|||
setAxisPosition_mm(20 + (93 * pos.y), Y); |
|||
setAxisPosition_mm(0.0, Z); |
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("Current Z: ", getAxisPosition_mm(Z)); |
|||
#endif |
|||
} |
|||
} |
|||
selectedmeshpoint.x = pos.x; |
|||
selectedmeshpoint.y = pos.y; |
|||
} |
|||
} break; |
|||
|
|||
case 30: { // A30 Auto leveling
|
|||
if (panel_command[3] == 'S') { // Start probing
|
|||
// Ignore request if printing
|
|||
if (isPrinting()) |
|||
SendtoTFTLN(AC_msg_probing_not_allowed); // forbid auto leveling
|
|||
else { |
|||
injectCommands_P(isMachineHomed() ? PSTR("G29") : PSTR("G28\nG29")); |
|||
printer_state = AC_printer_probing; |
|||
SendtoTFTLN(AC_msg_start_probing); |
|||
} |
|||
} |
|||
else SendtoTFTLN(AC_msg_start_probing); |
|||
} break; |
|||
|
|||
case 31: { // A31 Adjust all Probe Points
|
|||
switch (panel_command[3]) { |
|||
case 'C': // Restore and apply original offsets
|
|||
if (!isPrinting()) { |
|||
injectCommands_P(PSTR("M501\nM420 S1\n")); |
|||
selectedmeshpoint.x = 99; |
|||
selectedmeshpoint.y = 99; |
|||
} |
|||
break; |
|||
case 'D': // Save Z Offset tables and restore levelling state
|
|||
if (!isPrinting()) { |
|||
setAxisPosition_mm(1.0,Z); |
|||
injectCommands_P(PSTR("M500\n")); |
|||
selectedmeshpoint.x = 99; |
|||
selectedmeshpoint.y = 99; |
|||
} |
|||
break; |
|||
case 'G': // Get current offset
|
|||
SendtoTFT(PSTR("A31V ")); |
|||
// When printing use the live z Offset position
|
|||
// we will use babystepping to move the print head
|
|||
if (isPrinting()) |
|||
TFTSer.println(live_Zoffset); |
|||
else { |
|||
TFTSer.println(getZOffset_mm()); |
|||
selectedmeshpoint.x = 99; |
|||
selectedmeshpoint.y = 99; |
|||
} |
|||
break; |
|||
case 'S': { // Set offset (adjusts all points by value)
|
|||
float Zshift = atof(&panel_command[4]); |
|||
setSoftEndstopState(false); // disable endstops
|
|||
// Allow temporary Z position nudging during print
|
|||
// From the levelling panel use the all points UI to adjust the print pos.
|
|||
if (isPrinting()) { |
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("Change Zoffset from:", live_Zoffset, " to ", live_Zoffset + Zshift); |
|||
#endif |
|||
if (isAxisPositionKnown(Z)) { |
|||
#if ACDEBUG(AC_INFO) |
|||
const float currZpos = getAxisPosition_mm(Z); |
|||
SERIAL_ECHOLNPAIR("Nudge Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05)); |
|||
#endif |
|||
// Use babystepping to adjust the head position
|
|||
int16_t steps = mmToWholeSteps(constrain(Zshift,-0.05,0.05), Z); |
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("Steps to move Z: ", steps); |
|||
#endif |
|||
babystepAxis_steps(steps, Z); |
|||
live_Zoffset += Zshift; |
|||
} |
|||
SendtoTFT(PSTR("A31V ")); |
|||
TFTSer.println(live_Zoffset); |
|||
} |
|||
else { |
|||
GRID_LOOP(x, y) { |
|||
const xy_uint8_t pos { x, y }; |
|||
const float currval = getMeshPoint(pos); |
|||
setMeshPoint(pos, constrain(currval + Zshift, AC_LOWEST_MESHPOINT_VAL, 2)); |
|||
} |
|||
const float currZOffset = getZOffset_mm(); |
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("Change probe offset from ", currZOffset, " to ", currZOffset + Zshift); |
|||
#endif |
|||
|
|||
setZOffset_mm(currZOffset + Zshift); |
|||
SendtoTFT(PSTR("A31V ")); |
|||
TFTSer.println(getZOffset_mm()); |
|||
|
|||
if (isAxisPositionKnown(Z)) { |
|||
// Move Z axis
|
|||
const float currZpos = getAxisPosition_mm(Z); |
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05)); |
|||
#endif |
|||
setAxisPosition_mm(currZpos+constrain(Zshift,-0.05,0.05),Z); |
|||
} |
|||
} |
|||
} break; |
|||
} // end switch
|
|||
} break; |
|||
|
|||
case 32: { // A32 clean leveling beep flag
|
|||
// Ignore request if printing
|
|||
//if (isPrinting()) break;
|
|||
//injectCommands_P(PSTR("M500\nM420 S1\nG1 Z10 F240\nG1 X0 Y0 F6000"));
|
|||
//TFTSer.println("");
|
|||
} break; |
|||
|
|||
// A33 firmware info request seet PanelInfo()
|
|||
|
|||
case 34: { // A34 Adjust single mesh point A34 C/S X1 Y1 V123
|
|||
if (panel_command[3] == 'C') { // Restore original offsets
|
|||
injectCommands_P(PSTR("M501\nM420 S1")); |
|||
selectedmeshpoint.x = 99; |
|||
selectedmeshpoint.y = 99; |
|||
//printer_state = AC_printer_idle;
|
|||
} |
|||
else { |
|||
xy_uint8_t pos; |
|||
pos.x = atoi(&panel_command[5]); |
|||
pos.y = atoi(&panel_command[8]); |
|||
|
|||
float currmesh = getMeshPoint(pos); |
|||
float newval = atof(&panel_command[11])/100; |
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("Change mesh point x:", pos.x, " y:", pos.y); |
|||
SERIAL_ECHOLNPAIR("from ", currmesh, " to ", newval); |
|||
#endif |
|||
// Update Meshpoint
|
|||
setMeshPoint(pos,newval); |
|||
if ( (printer_state == AC_printer_idle) || (printer_state == AC_printer_probing) ) {//!isPrinting()) {
|
|||
// 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)
|
|||
if ((selectedmeshpoint.x == pos.x) && (selectedmeshpoint.y == pos.y)) { |
|||
setSoftEndstopState(false); |
|||
float currZpos = getAxisPosition_mm(Z); |
|||
#if ACDEBUG(AC_INFO) |
|||
SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(newval - currmesh, -0.05, 0.05)); |
|||
#endif |
|||
setAxisPosition_mm(currZpos + constrain(newval - currmesh, -0.05, 0.05), Z); |
|||
} |
|||
} |
|||
} |
|||
} break; |
|||
} |
|||
} |
|||
} // namespace
|
|||
|
|||
#endif // ANYCUBIC_LCD_CHIRON
|
@ -0,0 +1,77 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
#pragma once |
|||
|
|||
/**
|
|||
* lcd/extui/lib/chiron_tft.h |
|||
* |
|||
* Extensible_UI implementation for Anycubic Chiron |
|||
* Written By Nick Wells, 2020 [https://github.com/SwiftNick]
|
|||
* (not affiliated with Anycubic, Ltd.) |
|||
*/ |
|||
|
|||
#include "chiron_tft_defs.h" |
|||
#include "../../../../inc/MarlinConfigPre.h" |
|||
#include "../../ui_api.h" |
|||
namespace Anycubic { |
|||
|
|||
class ChironTFT { |
|||
static printer_state_t printer_state; |
|||
static paused_state_t pause_state; |
|||
static heater_state_t hotend_state; |
|||
static heater_state_t hotbed_state; |
|||
static xy_uint8_t selectedmeshpoint; |
|||
static char panel_command[MAX_CMND_LEN]; |
|||
static uint8_t command_len; |
|||
static char selectedfile[MAX_PATH_LEN]; |
|||
static float live_Zoffset; |
|||
static file_menu_t file_menu; |
|||
public: |
|||
ChironTFT(); |
|||
void Startup(); |
|||
void IdleLoop(); |
|||
void PrinterKilled(PGM_P,PGM_P); |
|||
void MediaEvent(media_event_t); |
|||
void TimerEvent(timer_event_t); |
|||
void FilamentRunout(); |
|||
void ConfirmationRequest(const char * const ); |
|||
void StatusChange(const char * const ); |
|||
void PowerLossRecovery(); |
|||
|
|||
private: |
|||
void SendtoTFT(PGM_P); |
|||
void SendtoTFTLN(PGM_P); |
|||
bool ReadTFTCommand(); |
|||
int8_t Findcmndpos(const char *, char); |
|||
void CheckHeaters(); |
|||
void SendFileList(int8_t); |
|||
void SelectFile(); |
|||
void InjectCommandandWait(PGM_P); |
|||
void ProcessPanelRequest(); |
|||
void PanelInfo(uint8_t); |
|||
void PanelAction(uint8_t); |
|||
void PanelProcess(uint8_t); |
|||
}; |
|||
|
|||
extern ChironTFT Chiron; |
|||
|
|||
} |
@ -0,0 +1,151 @@ |
|||
/**
|
|||
* Marlin 3D Printer Firmware |
|||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|||
* |
|||
* Based on Sprinter and grbl. |
|||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
|
|||
/**
|
|||
* lcd/extui/lib/chiron_defs.h |
|||
* |
|||
* Extensible_UI implementation for Anycubic Chiron |
|||
* Written By Nick Wells, 2020 [https://github.com/SwiftNick]
|
|||
* (not affiliated with Anycubic, Ltd.) |
|||
*/ |
|||
|
|||
#pragma once |
|||
#include "../../../../inc/MarlinConfigPre.h" |
|||
//#define ACDEBUGLEVEL 255
|
|||
|
|||
#if ACDEBUGLEVEL |
|||
// Bit-masks for selective debug:
|
|||
enum ACDebugMask : uint8_t { |
|||
AC_INFO = 1, |
|||
AC_ACTION = 2, |
|||
AC_FILE = 4, |
|||
AC_PANEL = 8, |
|||
AC_MARLIN = 16, |
|||
AC_SOME = 32, |
|||
AC_ALL = 64 |
|||
}; |
|||
#define ACDEBUG(mask) ( ((mask) & ACDEBUGLEVEL) == mask ) // Debug flag macro
|
|||
#else |
|||
#define ACDEBUG(mask) false |
|||
#endif |
|||
|
|||
#define TFTSer LCD_SERIAL // Serial interface for TFT panel now uses marlinserial
|
|||
#define MAX_FOLDER_DEPTH 4 // Limit folder depth TFT has a limit for the file path
|
|||
#define MAX_CMND_LEN 16 * MAX_FOLDER_DEPTH // Maximum Length for a Panel command
|
|||
#define MAX_PATH_LEN 16 * MAX_FOLDER_DEPTH // Maximum number of characters in a SD file path
|
|||
|
|||
#define AC_HEATER_FAULT_VALIDATION_TIME 5 // number of 1/2 second loops before signalling a heater fault
|
|||
#define AC_LOWEST_MESHPOINT_VAL -7.00 // The lowest value you can set for a single mesh point offset
|
|||
|
|||
// TFT panel commands
|
|||
#define AC_msg_sd_card_inserted PSTR("J00") |
|||
#define AC_msg_sd_card_removed PSTR("J01") |
|||
#define AC_msg_no_sd_card PSTR("J02") |
|||
#define AC_msg_usb_connected PSTR("J03") |
|||
#define AC_msg_print_from_sd_card PSTR("J04") |
|||
#define AC_msg_pause PSTR("J05") |
|||
#define AC_msg_nozzle_heating PSTR("J06") |
|||
#define AC_msg_nozzle_heating_done PSTR("J07") |
|||
#define AC_msg_bed_heating PSTR("J08") |
|||
#define AC_msg_bed_heating_done PSTR("J09") |
|||
#define AC_msg_nozzle_temp_abnormal PSTR("J10") |
|||
#define AC_msg_kill_lcd PSTR("J11") |
|||
#define AC_msg_ready PSTR("J12") |
|||
#define AC_msg_low_nozzle_temp PSTR("J13") |
|||
#define AC_msg_print_complete PSTR("J14") |
|||
#define AC_msg_filament_out_alert PSTR("J15") |
|||
#define AC_msg_stop PSTR("J16") |
|||
#define AC_msg_main_board_has_reset PSTR("J17") |
|||
#define AC_msg_paused PSTR("J18") |
|||
#define AC_msg_j19_unknown PSTR("J19") |
|||
#define AC_msg_sd_file_open_success PSTR("J20") |
|||
#define AC_msg_sd_file_open_failed PSTR("J21") |
|||
#define AC_msg_level_monitor_finished PSTR("J22") |
|||
#define AC_msg_filament_out_block PSTR("J23") |
|||
#define AC_msg_probing_not_allowed PSTR("J24") |
|||
#define AC_msg_probing_complete PSTR("J25") |
|||
#define AC_msg_start_probing PSTR("J26") |
|||
#define AC_msg_version PSTR("J27") |
|||
|
|||
#define MARLIN_msg_start_probing PSTR("Probing Point 1/25") |
|||
#define MARLIN_msg_probing_failed PSTR("Probing Failed") |
|||
#define MARLIN_msg_ready PSTR("3D Printer Ready.") |
|||
#define MARLIN_msg_print_paused PSTR("Print Paused") |
|||
#define MARLIN_msg_print_aborted PSTR("Print Aborted") |
|||
#define MARLIN_msg_extruder_heating PSTR("E Heating...") |
|||
#define MARLIN_msg_bed_heating PSTR("Bed Heating...") |
|||
|
|||
#define MARLIN_msg_nozzle_parked PSTR("Nozzle Parked") |
|||
#define MARLIN_msg_heater_timeout PSTR("Heater Timeout") |
|||
#define MARLIN_msg_reheating PSTR("Reheating...") |
|||
#define MARLIN_msg_reheat_done PSTR("Reheat finished.") |
|||
#define MARLIN_msg_filament_purging PSTR("Filament Purging...") |
|||
#define MARLIN_msg_special_pause PSTR("PB") |
|||
#define AC_cmnd_auto_unload_filament PSTR("M701") // Use Marlin unload routine
|
|||
#define AC_cmnd_auto_load_filament PSTR("M702 M0 PB") // Use Marlin load routing then pause for user to clean nozzle
|
|||
|
|||
#define AC_cmnd_manual_load_filament PSTR("M83\nG1 E50 F700\nM82") // replace the manual panel commands with something a little faster
|
|||
#define AC_cmnd_manual_unload_filament PSTR("M83\nG1 E-50 F1200\nM82") |
|||
#define AC_cmnd_enable_levelling PSTR("M420 S1 V1") |
|||
#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
|
|||
|
|||
namespace Anycubic { |
|||
enum heater_state_t : uint8_t { |
|||
AC_heater_off, |
|||
AC_heater_temp_set, |
|||
AC_heater_temp_reached |
|||
}; |
|||
|
|||
enum paused_state_t : uint8_t { |
|||
AC_paused_heater_timed_out, |
|||
AC_paused_purging_filament, |
|||
AC_paused_idle |
|||
}; |
|||
|
|||
enum printer_state_t : uint8_t { |
|||
AC_printer_idle, |
|||
AC_printer_probing, |
|||
AC_printer_printing, |
|||
AC_printer_pausing, |
|||
AC_printer_paused, |
|||
AC_printer_stopping, |
|||
AC_printer_resuming_from_power_outage |
|||
}; |
|||
|
|||
enum timer_event_t : uint8_t { |
|||
AC_timer_started, |
|||
AC_timer_paused, |
|||
AC_timer_stopped |
|||
}; |
|||
|
|||
enum media_event_t : uint8_t { |
|||
AC_media_inserted, |
|||
AC_media_removed, |
|||
AC_media_error |
|||
}; |
|||
enum file_menu_t : uint8_t { |
|||
AC_menu_file, |
|||
AC_menu_command, |
|||
AC_menu_change_to_file, |
|||
AC_menu_change_to_command |
|||
}; |
|||
} |
Loading…
Reference in new issue