Add cr6 screen files

This commit is contained in:
InsanityAutomation
2021-06-12 08:54:23 -04:00
parent eca2080a3f
commit 37d5f55396
32 changed files with 5776 additions and 10 deletions
+1 -1
View File
@@ -124,7 +124,7 @@ typedef int8_t pin_t;
#error "LCD_SERIAL_PORT must be from 0 to 3, or -1 for USB Serial."
#endif
#define LCD_SERIAL lcdSerial
#if HAS_DGUS_LCD
#if HAS_DGUS_LCD || ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.get_tx_buffer_free()
#endif
#endif
+1 -1
View File
@@ -629,7 +629,7 @@ MSerialT1 customizedSerial1(MSerialT1::HasEmergencyParser);
template class MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> >;
MSerialLCD lcdSerial(MSerialLCD::HasEmergencyParser);
#if HAS_DGUS_LCD
#if HAS_DGUS_LCD || ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::get_tx_buffer_free() {
const ring_buffer_pos_t t = tx_buffer.tail, // next byte to send.
+1 -1
View File
@@ -212,7 +212,7 @@
static ring_buffer_pos_t available();
static void write(const uint8_t c);
static void flushTX();
#if HAS_DGUS_LCD
#if HAS_DGUS_LCD || ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
static ring_buffer_pos_t get_tx_buffer_free();
#endif
+1 -1
View File
@@ -96,7 +96,7 @@
#else
#error "LCD_SERIAL_PORT must be from 1 to 6. You can also use -1 if the board supports Native USB."
#endif
#if HAS_DGUS_LCD
#if HAS_DGUS_LCD || ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite()
#endif
#endif
+1 -1
View File
@@ -129,7 +129,7 @@
#define LCD_SERIAL MSERIAL(1) // dummy port
static_assert(false, "LCD_SERIAL_PORT must be from 1 to " STRINGIFY(NUM_UARTS) ". You can also use -1 if the board supports Native USB.")
#endif
#if HAS_DGUS_LCD
#if HAS_DGUS_LCD || ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite()
#endif
#endif
+6
View File
@@ -82,6 +82,12 @@
#endif
#endif
#if ENABLED(PROBING_HEATERS_OFF)
#include "../../../module/temperature.h"
#include "../../../module/printcounter.h"
#endif
#define G29_RETURN(b) return TERN_(G29_RETRY_AND_RECOVER, b)
// For manual probing values persist over multiple G29
+1 -1
View File
@@ -464,7 +464,7 @@
#endif
// Extensible UI serial touch screens. (See src/lcd/extui)
#if ANY(HAS_DGUS_LCD, MALYAN_LCD, TOUCH_UI_FTDI_EVE, ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON, NEXTION_TFT)
#if ANY(HAS_DGUS_LCD, MALYAN_LCD, TOUCH_UI_FTDI_EVE, ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON, NEXTION_TFT, DGUS_LCD_UI_CREALITY_TOUCH)
#define IS_EXTUI 1
#define EXTENSIBLE_UI
#endif
+1 -1
View File
@@ -2830,7 +2830,7 @@
#define HAS_TEMPERATURE 1
#endif
#if HAS_TEMPERATURE && EITHER(HAS_LCD_MENU, DWIN_CREALITY_LCD)
#if HAS_TEMPERATURE && ANY(HAS_LCD_MENU, DWIN_CREALITY_LCD, DGUS_LCD_UI_CREALITY_TOUCH)
#ifdef PREHEAT_6_LABEL
#define PREHEAT_COUNT 6
#elif defined(PREHEAT_5_LABEL)
+1 -1
View File
@@ -2438,7 +2438,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
+ (DISABLED(IS_LEGACY_TFT) && ENABLED(TFT_GENERIC)) \
+ (ENABLED(IS_LEGACY_TFT) && COUNT_ENABLED(TFT_320x240, TFT_320x240_SPI, TFT_480x320, TFT_480x320_SPI)) \
+ COUNT_ENABLED(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON, ANYCUBIC_TFT35) \
+ COUNT_ENABLED(DGUS_LCD_UI_ORIGIN, DGUS_LCD_UI_FYSETC, DGUS_LCD_UI_HIPRECY, DGUS_LCD_UI_MKS) \
+ COUNT_ENABLED(DGUS_LCD_UI_ORIGIN, DGUS_LCD_UI_FYSETC, DGUS_LCD_UI_HIPRECY, DGUS_LCD_UI_MKS, DGUS_LCD_UI_CREALITY_TOUCH) \
+ COUNT_ENABLED(ENDER2_STOCKDISPLAY, CR10_STOCKDISPLAY, DWIN_CREALITY_LCD) \
+ COUNT_ENABLED(FYSETC_MINI_12864_X_X, FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0, FYSETC_MINI_12864_2_1, FYSETC_GENERIC_12864_1_1) \
+ COUNT_ENABLED(LCD_SAINSMART_I2C_1602, LCD_SAINSMART_I2C_2004) \
@@ -0,0 +1,352 @@
/**
* 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/>.
*
*/
/* DGUS implementation written by coldtobi in 2019 for Marlin */
#include "../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#if HOTENDS > 2
#error "More than 2 hotends not implemented on the Display UI design."
#endif
#include "../ui_api.h"
#include "../../../MarlinCore.h"
#include "../../../module/temperature.h"
#include "../../../module/motion.h"
#include "../../../gcode/queue.h"
#include "../../../module/planner.h"
#include "../../../sd/cardreader.h"
#include "../../../libs/duration_t.h"
#include "../../../module/printcounter.h"
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../../../feature/powerloss.h"
#endif
#include "DGUSDisplay.h"
#include "DGUSVPVariable.h"
#include "DGUSDisplayDef.h"
// Preamble... 2 Bytes, usually 0x5A 0xA5, but configurable
constexpr uint8_t DGUS_HEADER1 = 0x5A;
constexpr uint8_t DGUS_HEADER2 = 0xA5;
constexpr uint8_t DGUS_CMD_WRITEVAR = 0x82;
constexpr uint8_t DGUS_CMD_READVAR = 0x83;
#if ENABLED(DEBUG_DGUSLCD)
bool dguslcd_local_debug; // = false;
#endif
#define dgusserial LCD_SERIAL
void DGUSDisplay::InitDisplay() {
dgusserial.begin(LCD_BAUDRATE);
/*delay(500); // Attempt to fix possible handshake error
ResetDisplay(); // Reset for firmware update
delay(500); // Attempt to fix possible handshake error
*/
if (true
#if ENABLED(POWER_LOSS_RECOVERY)
&& !recovery.valid()
#endif
)
RequestScreen(
#if ENABLED(SHOW_BOOTSCREEN)
DGUSLCD_SCREEN_BOOT
#else
DGUSLCD_SCREEN_MAIN
#endif
);
}
void DGUSDisplay::ResetDisplay() {
SERIAL_ECHOLN("ResetDisplay");
const unsigned char resetCommand[] = { 0x55, 0xAA, 0x5A, 0xA5 };
WriteVariable(0x04, resetCommand, sizeof(resetCommand));
}
void DGUSDisplay::ReadVariable(uint16_t adr) {
WriteHeader(adr, DGUS_CMD_READVAR, sizeof(uint8_t));
// Specify to read one byte
dgusserial.write(static_cast<uint8_t>(1));
}
void DGUSDisplay::WriteVariable(uint16_t adr, const void* values, uint8_t valueslen, bool isstr, char fillChar) {
const char* myvalues = static_cast<const char*>(values);
bool strend = !myvalues;
WriteHeader(adr, DGUS_CMD_WRITEVAR, valueslen);
while (valueslen--) {
char x;
if (!strend) x = *myvalues++;
if ((isstr && !x) || strend) {
strend = true;
x = fillChar;
}
dgusserial.write(x);
}
}
void DGUSDisplay::WriteVariable(uint16_t adr, uint16_t value) {
value = (value & 0xffU) << 8U | (value >> 8U);
WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint16_t));
}
void DGUSDisplay::WriteVariable(uint16_t adr, int16_t value) {
union { int16_t l; char lb[2]; } endian;
char tmp[2];
endian.l = value;
tmp[0] = endian.lb[1];
tmp[1] = endian.lb[0];
WriteVariable(adr, static_cast<const void*>(&tmp), sizeof(int16_t));
}
void DGUSDisplay::WriteVariable(uint16_t adr, uint8_t value) {
WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint8_t));
}
void DGUSDisplay::WriteVariable(uint16_t adr, int8_t value) {
WriteVariable(adr, static_cast<const void*>(&value), sizeof(int8_t));
}
void DGUSDisplay::WriteVariable(uint16_t adr, long value) {
union { long l; char lb[4]; } endian;
char tmp[4];
endian.l = value;
tmp[0] = endian.lb[3];
tmp[1] = endian.lb[2];
tmp[2] = endian.lb[1];
tmp[3] = endian.lb[0];
WriteVariable(adr, static_cast<const void*>(&tmp), sizeof(long));
}
void DGUSDisplay::WriteVariable(uint16_t adr, float value) {
static_assert(sizeof(float) == 4);
union { float l; char lb[4]; } endian;
char tmp[4];
endian.l = value;
tmp[0] = endian.lb[3];
tmp[1] = endian.lb[2];
tmp[2] = endian.lb[1];
tmp[3] = endian.lb[0];
WriteVariable(adr, static_cast<const void*>(&tmp), sizeof(float));
}
void DGUSDisplay::WriteVariablePGM(uint16_t adr, const void* values, uint8_t valueslen, bool isstr, char fillChar) {
const char* myvalues = static_cast<const char*>(values);
bool strend = !myvalues;
WriteHeader(adr, DGUS_CMD_WRITEVAR, valueslen);
while (valueslen--) {
char x;
if (!strend) x = pgm_read_byte(myvalues++);
if ((isstr && !x) || strend) {
strend = true;
x = fillChar;
}
dgusserial.write(x);
}
}
void DGUSDisplay::SetVariableDisplayColor(uint16_t sp, uint16_t color) {
WriteVariable(sp + 0x03, color);
}
void DGUSDisplay::ProcessRx() {
#if ENABLED(DGUS_SERIAL_STATS_RX_BUFFER_OVERRUNS)
if (!dgusserial.available() && dgusserial.buffer_overruns()) {
// Overrun, but reset the flag only when the buffer is empty
// We want to extract as many as valid datagrams possible...
DEBUG_ECHOPGM("OVFL");
rx_datagram_state = DGUS_IDLE;
//dgusserial.reset_rx_overun();
dgusserial.flush();
}
#endif
uint8_t receivedbyte;
while (dgusserial.available()) {
switch (rx_datagram_state) {
case DGUS_IDLE: // Waiting for the first header byte
receivedbyte = dgusserial.read();
//DEBUGLCDCOMM_ECHOPAIR("< ",receivedbyte);
if (DGUS_HEADER1 == receivedbyte) rx_datagram_state = DGUS_HEADER1_SEEN;
break;
case DGUS_HEADER1_SEEN: // Waiting for the second header byte
receivedbyte = dgusserial.read();
//DEBUGLCDCOMM_ECHOPAIR(" ", receivedbyte);
rx_datagram_state = (DGUS_HEADER2 == receivedbyte) ? DGUS_HEADER2_SEEN : DGUS_IDLE;
break;
case DGUS_HEADER2_SEEN: // Waiting for the length byte
rx_datagram_len = dgusserial.read();
//DEBUGLCDCOMM_ECHOPAIR(" (", rx_datagram_len, ") ");
// Telegram min len is 3 (command and one word of payload)
rx_datagram_state = WITHIN(rx_datagram_len, 3, DGUS_RX_BUFFER_SIZE) ? DGUS_WAIT_TELEGRAM : DGUS_IDLE;
break;
case DGUS_WAIT_TELEGRAM: // wait for complete datagram to arrive.
if (dgusserial.available() < rx_datagram_len) return;
Initialized = true; // We've talked to it, so we defined it as initialized.
uint8_t command = dgusserial.read();
// DEBUGLCDCOMM_ECHOPAIR("# ", command);
uint8_t readlen = rx_datagram_len - 1; // command is part of len.
unsigned char tmp[rx_datagram_len - 1];
unsigned char *ptmp = tmp;
while (readlen--) {
receivedbyte = dgusserial.read();
//DEBUGLCDCOMM_ECHOPAIR(" ", receivedbyte);
*ptmp++ = receivedbyte;
}
//DEBUGLCDCOMM_ECHOPGM(" # ");
// mostly we'll get this: 5A A5 03 82 4F 4B -- ACK on 0x82, so discard it.
if (command == DGUS_CMD_WRITEVAR && 'O' == tmp[0] && 'K' == tmp[1]) {
//DEBUG_ECHOLNPGM(">");
rx_datagram_state = DGUS_IDLE;
break;
}
/* AutoUpload, (and answer to) Command 0x83 :
| tmp[0 1 2 3 4 ... ]
| Example 5A A5 06 83 20 01 01 78 01 ……
| / / | | \ / | \ \
| Header | | | | \_____\_ DATA (Words!)
| DatagramLen / VPAdr |
| Command DataLen (in Words) */
if (command == DGUS_CMD_READVAR) {
const uint16_t vp = tmp[0] << 8 | tmp[1];
//const uint8_t dlen = tmp[2] << 1; // Convert to Bytes. (Display works with words)
//DEBUG_ECHOPAIR(" vp=", vp, " dlen=", dlen);
DGUS_VP_Variable ramcopy;
DEBUG_ECHOLNPAIR("VP received: ", vp , " - val ", tmp[3]);
if (populate_VPVar(vp, &ramcopy)) {
if (ramcopy.set_by_display_handler)
ramcopy.set_by_display_handler(ramcopy, &tmp[3]);
else
DEBUG_ECHOLNPGM(" VPVar found, no handler.");
}
else
DEBUG_ECHOLNPAIR(" VPVar not found:", vp);
rx_datagram_state = DGUS_IDLE;
break;
}
// discard anything else
rx_datagram_state = DGUS_IDLE;
}
}
}
size_t DGUSDisplay::GetFreeTxBuffer() { return SERIAL_GET_TX_BUFFER_FREE(); }
void DGUSDisplay::WriteHeader(uint16_t adr, uint8_t cmd, uint8_t payloadlen) {
dgusserial.write(DGUS_HEADER1);
dgusserial.write(DGUS_HEADER2);
dgusserial.write(payloadlen + 3);
dgusserial.write(cmd);
dgusserial.write(adr >> 8);
dgusserial.write(adr & 0xFF);
}
void DGUSDisplay::WritePGM(const char str[], uint8_t len) {
while (len--) dgusserial.write(pgm_read_byte(str++));
}
void DGUSDisplay::loop() {
// protect against recursion… ProcessRx() may indirectly call idle() when injecting gcode commands.
if (!no_reentrance) {
no_reentrance = true;
ProcessRx();
no_reentrance = false;
}
}
void DGUSDisplay::RequestScreen(DGUSLCD_Screens screen) {
displayRequest = screen;
DEBUG_ECHOLNPAIR("GotoScreen ", screen);
const unsigned char gotoscreen[] = { 0x5A, 0x01, (unsigned char) (screen >> 8U), (unsigned char) (screen & 0xFFU) };
WriteVariable(0x84, gotoscreen, sizeof(gotoscreen));
}
void DGUSDisplay::SetTouchScreenConfiguration(bool enable_standby, bool enable_sound, uint8_t standby_brightness, uint8_t brightness, uint16_t standbyTimeSeconds) {
// Main configuration (System_Config)
unsigned char cfg_bits = 0x0;
cfg_bits |= 1UL << 5; // 5: load 22 touch file
cfg_bits |= 1UL << 4; // 4: auto-upload should always be enabled
if (enable_sound) cfg_bits |= 1UL << 3; // 3: audio
if (enable_standby) cfg_bits |= 1UL << 2; // 2: backlight on standby
cfg_bits |= 1UL << 1; // 1 & 0: 270 degrees orientation of display
cfg_bits |= 1UL << 0;
DEBUG_ECHOLNPAIR("Update touch screen config - standby ", enable_standby);
DEBUG_ECHOLNPAIR("Update touch screen config - sound ", enable_sound);
const unsigned char config_set[] = { 0x5A, 0x00, (unsigned char) (cfg_bits >> 8U), (unsigned char) (cfg_bits & 0xFFU) };
WriteVariable(0x80 /*System_Config*/, config_set, sizeof(config_set));
// Standby brightness (LED_Config)
uint16_t dwinStandbyTimeSeconds = 100 * standbyTimeSeconds; /* milliseconds, but divided by 10 (not 5 like the docs say) */
const unsigned char brightness_set[] = {
brightness /*% active*/,
standby_brightness /*% standby*/,
static_cast<uint8_t>(dwinStandbyTimeSeconds >> 8),
static_cast<uint8_t>(dwinStandbyTimeSeconds)
};
WriteVariable(0x82 /*LED_Config*/, brightness_set, sizeof(brightness_set));
}
rx_datagram_state_t DGUSDisplay::rx_datagram_state = DGUS_IDLE;
uint8_t DGUSDisplay::rx_datagram_len = 0;
bool DGUSDisplay::Initialized = false;
bool DGUSDisplay::no_reentrance = false;
DGUSLCD_Screens DGUSDisplay::displayRequest = DGUSLCD_SCREEN_BOOT;
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() asm volatile("": : :"memory");
bool populate_VPVar(const uint16_t VP, DGUS_VP_Variable * const ramcopy) {
//DEBUG_ECHOLNPAIR("populate_VPVar ", VP);
const DGUS_VP_Variable *pvp = DGUSLCD_FindVPVar(VP);
// DEBUG_ECHOLNPAIR(" pvp ", (uint16_t )pvp);
if (!pvp) return false;
memcpy_P(ramcopy, pvp, sizeof(DGUS_VP_Variable));
return true;
}
#endif // HAS_DGUS_LCD
@@ -0,0 +1,136 @@
/**
* 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
//#define DEBUG_DGUSLCD
//#define DEBUG_DGUSLCD_OUTGOING_COMM
/* Creality DGUS implementation written by Sebastiaan Dammann in 2020 for Marlin */
#include "../../../inc/MarlinConfigPre.h"
#include "../../../MarlinCore.h"
#if HAS_BED_PROBE
#include "../../../module/probe.h"
#endif
#include "DGUSVPVariable.h"
enum DGUSLCD_Screens : uint8_t;
#ifndef DEBUG_OUT
#define DEBUG_OUT ENABLED(DEBUG_DGUSLCD)
#endif
#include "../../../core/debug_out.h"
typedef enum : uint8_t {
DGUS_IDLE, //< waiting for DGUS_HEADER1.
DGUS_HEADER1_SEEN, //< DGUS_HEADER1 received
DGUS_HEADER2_SEEN, //< DGUS_HEADER2 received
DGUS_WAIT_TELEGRAM, //< LEN received, Waiting for to receive all bytes.
} rx_datagram_state_t;
typedef void (*UPDATE_CURRENT_SCREEN_CALLBACK)(DGUSLCD_Screens screen);
// Low-Level access to the display.
class DGUSDisplay {
public:
DGUSDisplay() = default;
static void InitDisplay();
static void ResetDisplay();
// Variable access.
static void WriteVariable(uint16_t adr, const void* values, uint8_t valueslen, bool isstr=false, char fillChar = ' ');
static void WriteVariablePGM(uint16_t adr, const void* values, uint8_t valueslen, bool isstr=false, char fillChar = ' ');
static void WriteVariable(uint16_t adr, int16_t value);
static void WriteVariable(uint16_t adr, uint16_t value);
static void WriteVariable(uint16_t adr, uint8_t value);
static void WriteVariable(uint16_t adr, int8_t value);
static void WriteVariable(uint16_t adr, long value);
static void WriteVariable(uint16_t adr, float value);
static void SetVariableDisplayColor(uint16_t sp, uint16_t color);
static void ReadVariable(uint16_t adr);
// Utility functions for bridging ui_api and dgus
template<typename T, float(*Getter)(const T), T selector, typename WireType=uint16_t>
static void SetVariable(DGUS_VP_Variable &var) {
WriteVariable(var.VP, (WireType)Getter(selector));
}
template<typename T, void(*Setter)(const float V, const T), T selector>
static void GetVariable(DGUS_VP_Variable &var, void *val_ptr) {
uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
Setter(newvalue, selector);
}
// Force display into another screen.
// (And trigger update of containing VPs)
// (to implement a pop up message, which may not be nested)
static void RequestScreen(DGUSLCD_Screens screen);
static void SetTouchScreenConfiguration(bool enable_standby, bool enable_sound, uint8_t standby_brightness, uint8_t active_brightness, uint16_t standbyTimeSeconds);
// Periodic tasks, eg. Rx-Queue handling.
static void loop();
public:
// Helper for users of this class to estimate if an interaction would be blocking.
static size_t GetFreeTxBuffer();
// Checks two things: Can we confirm the presence of the display and has we initiliazed it.
// (both boils down that the display answered to our chatting)
static inline bool isInitialized() { return Initialized; }
private:
static void WriteHeader(uint16_t adr, uint8_t cmd, uint8_t payloadlen);
static void WritePGM(const char str[], uint8_t len);
static void ProcessRx();
static inline uint16_t swap16(const uint16_t value) { return (value & 0xffU) << 8U | (value >> 8U); }
static rx_datagram_state_t rx_datagram_state;
static uint8_t rx_datagram_len;
static bool Initialized, no_reentrance;
static DGUSLCD_Screens displayRequest;
};
#define GET_VARIABLE(f, t, V...) (&DGUSDisplay::GetVariable<decltype(t), f, t, ##V>)
#define SET_VARIABLE(f, t, V...) (&DGUSDisplay::SetVariable<decltype(t), f, t, ##V>)
extern DGUSDisplay dgusdisplay;
// compile-time x^y
template<typename T>
constexpr T cpow(const T x, const int y) { return y == 0 ? 1.0 : x * cpow(x, y - 1); }
/// Find the flash address of a DGUS_VP_Variable for the VP.
const DGUS_VP_Variable* DGUSLCD_FindVPVar(const uint16_t vp);
/// Helper to populate a DGUS_VP_Variable for a given VP. Return false if not found.
bool populate_VPVar(const uint16_t VP, DGUS_VP_Variable * const ramcopy);
@@ -0,0 +1,53 @@
/**
* 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
/* DGUS implementation written by Sebastiaan Dammann in 2020 for Marlin */
#include "DGUSVPVariable.h"
#include <stdint.h>
// This file defines the interaction between Marlin and the display firmware.
// information on which screen which VP is displayed
// As this is a sparse table, two arrays are needed:
// one to list the VPs of one screen and one to map screens to the lists.
// (Strictly this would not be necessary, but allows to only send data the display needs and reducing load on Marlin)
struct VPMapping {
const uint8_t screen;
const uint16_t *VPList; // The list is null-terminated.
};
extern const struct VPMapping VPMap[];
// List of VPs handled by Marlin / The Display.
extern const struct DGUS_VP_Variable ListOfVP[];
#define DWIN_DEFAULT_FILLER_CHAR ' '
#define DWIN_SCROLLER_FILLER_CHAR 0x0
#include "../../../inc/MarlinConfig.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "creality_touch/DGUSDisplayDef.h"
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,458 @@
/**
* 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
#include "DGUSDisplay.h"
#include "DGUSVPVariable.h"
#include "../../../inc/MarlinConfig.h"
#if HAS_COLOR_LEDS
#include "../../../feature/leds/leds.h"
#if ENABLED(PRINTER_EVENT_LEDS)
#define HAS_COLOR_LEDS_PREFERENCES 1
#endif
#endif
enum DGUSLCD_Screens : uint8_t;
struct creality_dwin_settings_t {
size_t settings_size;
uint8_t settings_version;
bool led_state;
bool display_standby;
bool display_sound;
int16_t standby_screen_brightness;
int16_t screen_brightness;
int16_t standby_time_seconds;
#if HAS_COLOR_LEDS_PREFERENCES
LEDColor LastLEDColor;
#endif
};
class DGUSScreenHandler {
public:
DGUSScreenHandler() = default;
static bool loop();
static void Init();
static void DefaultSettings();
static void LoadSettings(const char* buff);
static void StoreSettings(char* buff);
static void SetTouchScreenConfiguration();
static void KillScreenCalled();
static void OnPowerlossResume();
static void RequestSaveSettings();
/// Send all 4 strings that are displayed on the infoscreen, confirmation screen and kill screen
/// The bools specifing whether the strings are in RAM or FLASH.
static void sendinfoscreen(const char* line1, const char* line2, const char* line3, const char* line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash);
static void HandleUserConfirmationPopUp(uint16_t ConfirmVP, const char* line1, const char* line2, const char* line3, const char* line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash);
static void HandleDevelopmentTestButton(DGUS_VP_Variable &var, void *val_ptr);
/// "M117" Message -- msg is a RAM ptr.
static void setstatusmessage(const char* msg);
/// The same for messages from Flash
static void setstatusmessagePGM(PGM_P const msg);
// Callback for VP "Display wants to change screen on idle printer"
static void ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr);
// Callback for VP "Screen has been changed"
static void ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr);
// Callback for VP "All Heaters Off"
static void HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr);
// Hook for "Change this temperature"
static void HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr);
static void HandleFanSpeedChanged(DGUS_VP_Variable &var, void *val_ptr);
// Hook for "Change Flowrate"
static void HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr);
// Hook for manual extrude.
static void HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr);
// Hook for motor lock and unlook
static void HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr);
#if ENABLED(POWER_LOSS_RECOVERY)
static void TogglePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr);
// Hook for power loss recovery.
static void HandlePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr);
#endif
// Version sanity check
static void HandleScreenVersion(DGUS_VP_Variable &var, void *val_ptr);
// Hook for settings
static void HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr);
static void HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr);
static void HandleFadeHeight(DGUS_VP_Variable &var, void *val_ptr);
// Hook for move to position
static void HandlePositionChange(DGUS_VP_Variable &var, void *val_ptr);
static void HandleToggleTouchScreenMute(DGUS_VP_Variable &var, void *val_ptr);
static void HandleToggleTouchScreenStandbySetting(DGUS_VP_Variable &var, void *val_ptr);
static void HandleTouchScreenBrightnessSetting(DGUS_VP_Variable &var, void *val_ptr);
static void HandleTouchScreenStandbyBrightnessSetting(DGUS_VP_Variable &var, void *val_ptr);
static void HandleTouchScreenStandbyTimeSetting(DGUS_VP_Variable &var, void *val_ptr);
#if HAS_PROBE_SETTINGS
static void HandleToggleProbeHeaters(DGUS_VP_Variable &var, void *val_ptr);
static void HandleToggleProbeTemperatureStabilization(DGUS_VP_Variable &var, void *val_ptr);
static void HandleToggleProbePreheatTemp(DGUS_VP_Variable &var, void *val_ptr);
#endif
#if HAS_PID_HEATING
// Hook for "Change this temperature PID para"
static void HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr);
// Hook for PID autotune
static void HandlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr);
#endif
#if HAS_BED_PROBE
// Hook for "Change probe offset z"
static void HandleZoffsetChange(DGUS_VP_Variable &var, void *val_ptr);
static void OnMeshLevelingStart();
static void OnMeshLevelingUpdate(const int8_t x, const int8_t y, const float z);
static void InitMeshValues();
static void ResetMeshValues();
static void UpdateMeshValue(const int8_t x, const int8_t y, const float z);
static void HandleMeshPoint(DGUS_VP_Variable &var, void *val_ptr);
#endif
// LED
#if HAS_COLOR_LEDS
static void HandleLED(DGUS_VP_Variable &var, void *val_ptr);
static void SendLEDToDisplay(DGUS_VP_Variable &var);
#endif
// Hook for live z adjust action
static void HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr);
// Hook for heater control
static void HandleHeaterControl(DGUS_VP_Variable &var, void *val_ptr);
#if ENABLED(DGUS_PREHEAT_UI)
// Hook for preheat
static void HandlePreheat(DGUS_VP_Variable &var, void *val_ptr);
#endif
#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
// Hook for filament load and unload filament option
static void HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr);
// Hook for filament load and unload
static void HandleFilamentLoadUnload(DGUS_VP_Variable &var);
#endif
#if ENABLED(SDSUPPORT)
// Callback for VP "Display wants to change screen when there is a SD card"
static void ScreenChangeHookIfSD(DGUS_VP_Variable &var, void *val_ptr);
/// Scroll buttons on the file listing screen.
static void DGUSLCD_SD_ScrollFilelist(DGUS_VP_Variable &var, void *val_ptr);
/// File touched.
static void DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr);
/// start print after confirmation received.
static void DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr);
/// Send a single filename to the display.
static void DGUSLCD_SD_SendFilename(DGUS_VP_Variable &var);
/// Marlin informed us that a new SD has been inserted.
static void SDCardInserted();
/// Marlin informed us that the SD Card has been removed().
static void SDCardRemoved();
/// Marlin informed us about a bad SD Card.
static void SDCardError();
static void SetPrintingFromHost();
#endif
static void HandleLEDToggle();
static void HandleFanToggle();
static void FilamentRunout();
static void OnFactoryReset();
#if HAS_BUZZER || ENABLED(SPEAKER)
static void Buzzer(const uint16_t frequency, const uint16_t duration);
#endif
static void OnHomingStart();
static void OnHomingComplete();
static void OnPrintFinished();
// OK Button the Confirm screen.
static void ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr);
// Update data after went to new screen (by display or by GotoScreen)
// remember: store the last-displayed screen, so it can get returned to.
// (e.g for pop up messages)
static void UpdateNewScreen(DGUSLCD_Screens newscreen, bool save_current_screen=true);
// Recall the remembered screen.
static void PopToOldScreen();
static void OnBackButton(DGUS_VP_Variable &var, void *val_ptr);
// Make the display show the screen and update all VPs in it.
static void GotoScreen(DGUSLCD_Screens screen, bool save_current_screen = true);
static void UpdateScreenVPData();
// Helpers to convert and transfer data to the display.
static void DGUSLCD_SendWordValueToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendStringToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendScrollingStringToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendStringToDisplayPGM(DGUS_VP_Variable &var);
static void DGUSLCD_SendScrollingStringToDisplayPGM(DGUS_VP_Variable &var);
static void DGUSLCD_SendTemperaturePID(DGUS_VP_Variable &var);
static void DGUSLCD_SendPercentageToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendPrintProgressToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendPrintTimeWithRemainingToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendPrintTimeRemainingToDisplay(DGUS_VP_Variable &var);
#if ENABLED(PRINTCOUNTER)
static void DGUSLCD_SendPrintAccTimeToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendPrintsTotalToDisplay(DGUS_VP_Variable &var);
#endif
#if HAS_FAN
static void DGUSLCD_SendFanStatusToDisplay(DGUS_VP_Variable &var);
static void DGUSLCD_SendFanSpeedToDisplay(DGUS_VP_Variable &var);
#endif
static void DGUSLCD_SendHeaterStatusToDisplay(DGUS_VP_Variable &var);
#if ENABLED(DGUS_UI_WAITING)
static void DGUSLCD_SendWaitingStatusToDisplay(DGUS_VP_Variable &var);
#endif
static void DGUSLCD_SendAboutFirmwareWebsite(DGUS_VP_Variable &var);
static void DGUSLCD_SendAboutFirmwareVersion(DGUS_VP_Variable &var);
static void DGUSLCD_SendAboutPrintSize(DGUS_VP_Variable &var);
/// Send a value from 0..100 to a variable with a range from 0..255
static void DGUSLCD_PercentageToUint8(DGUS_VP_Variable &var, void *val_ptr);
template<typename T>
static void DGUSLCD_SetValueDirectly(DGUS_VP_Variable &var, void *val_ptr) {
if (!var.memadr) return;
union { unsigned char tmp[sizeof(T)]; T t; } x;
unsigned char *ptr = (unsigned char*)val_ptr;
LOOP_L_N(i, sizeof(T)) x.tmp[i] = ptr[sizeof(T) - i - 1];
*(T*)var.memadr = x.t;
}
template<DGUSLCD_Screens TPage>
static void DGUSLCD_NavigateToPage(DGUS_VP_Variable &var, void *val_ptr) {
GotoScreen(TPage);
}
template<DGUSLCD_Screens TPage, typename Handler>
static void DGUSLCD_NavigateToPage(DGUS_VP_Variable &var, void *val_ptr) {
GotoScreen(TPage);
Handler::Init();
}
/// Send a float value to the display.
/// Display will get a 4-byte integer scaled to the number of digits:
/// Tell the display the number of digits and it cheats by displaying a dot between...
template<unsigned int decimals>
static void DGUSLCD_SendFloatAsLongValueToDisplay(DGUS_VP_Variable &var) {
if (var.memadr) {
double d = static_cast<double>(*(float *)var.memadr);
d *= cpow(10, decimals);
// Round - truncated values look like skipped numbers
static_assert(sizeof(long) == 4, "Assuming long is 4 bytes");
long roundedValue = static_cast<long>(round(d));
dgusdisplay.WriteVariable(var.VP, roundedValue);
}
}
// Receive a float from the display - Display will send a 2-byte integer scaled to the number of digits
template<unsigned int decimals>
static void DGUSLCD_SetFloatAsIntFromDisplay(DGUS_VP_Variable &var, void *val_ptr) {
if (var.memadr) {
uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
float value = static_cast<float>(static_cast<double>(value_raw) /cpow(10, decimals));
*(float *)var.memadr = value;
}
}
// Receive a float from the display - Display will send a 4-byte integer scaled to the number of digits
template<unsigned int decimals>
static void DGUSLCD_SetFloatAsLongFromDisplay(DGUS_VP_Variable &var, void *val_ptr) {
if (var.memadr) {
uint32_t value_raw = uInt32Value(*(uint32_t*)val_ptr);
float value = static_cast<float>(static_cast<double>(value_raw) /cpow(10, decimals));
*(float *)var.memadr = value;
}
}
static void DGUSLCD_SendULongToDisplay(DGUS_VP_Variable &var) {
if (var.memadr) {
// Round - truncated values look like skipped numbers
long roundedValue = *(uint32_t *) var.memadr;
dgusdisplay.WriteVariable(var.VP, roundedValue);
}
}
static void DGUSLCD_ReceiveULongFromDisplay(DGUS_VP_Variable &var, void* val_ptr) {
if (var.memadr) {
// Round - truncated values look like skipped numbers
uint32_t incomingValue = *(uint32_t *) val_ptr;
*(uint32_t*)var.memadr = uInt32Value(incomingValue);
}
}
// Toggle a boolean at the specified memory address
static void DGUSLCD_ToggleBoolean(DGUS_VP_Variable &var, void *val_ptr) {
if (var.memadr) {
SERIAL_ECHOLNPAIR("Toggle boolean - ", var.VP);
bool* val = (bool *)var.memadr;
*val = !*val;
}
}
// Send an icon to the display, depending on whether it is true or false
template<unsigned int value_if_true, unsigned int value_if_false>
static void DGUSLCD_SendIconValue(DGUS_VP_Variable &var) {
if (var.memadr) {
bool value = *(bool *)var.memadr;
uint16_t valueToSend = value ? value_if_true : value_if_false;
dgusdisplay.WriteVariable(var.VP, valueToSend);
}
}
/// Send a float value to the display.
/// Display will get a 2-byte integer scaled to the number of digits:
/// Tell the display the number of digits and it cheats by displaying a dot between...
template<unsigned int decimals>
static void DGUSLCD_SendFloatAsIntValueToDisplay(DGUS_VP_Variable &var) {
if (var.memadr) {
double d = static_cast<double>(*(float *)var.memadr);
d *= cpow(10, decimals);
// Round - truncated values look like skipped numbers
int16_t roundedValue = static_cast<int16_t>(round(d));
dgusdisplay.WriteVariable(var.VP, roundedValue);
}
}
template<AxisEnum Axis>
static void SendAxisTrustValue(DGUS_VP_Variable &var) {
bool trust = axis_is_trusted(Axis);
uint16_t color = trust ? 0xFFFF /*White*/ : 0XF800 /*Red*/;
dgusdisplay.SetVariableDisplayColor(var.VP, color);
}
/// Force an update of all VP on the current screen.
static inline void ForceCompleteUpdate() { update_ptr = 0; ScreenComplete = false; }
/// Has all VPs sent to the screen
static inline bool IsScreenComplete() { return ScreenComplete; }
static inline DGUSLCD_Screens getCurrentScreen() { return current_screen; }
static bool HandlePendingUserConfirmation();
static void SetSynchronousOperationStart();
static void SetSynchronousOperationFinish();
static bool HasCurrentSynchronousOperation() { return HasSynchronousOperation; }
static void SendBusyState(DGUS_VP_Variable &var);
static void SetViewMeshLevelState();
static bool fwretract_available;
private:
static void HandleScreenVersionMismatchLEDFlash();
static DGUSLCD_Screens current_screen; ///< currently on screen
static constexpr uint8_t NUM_PAST_SCREENS = 4;
static DGUSLCD_Screens past_screens[NUM_PAST_SCREENS]; ///< LIFO with past screens for the "back" button.
static uint8_t update_ptr; ///< Last sent entry in the VPList for the actual screen.
static uint16_t skipVP; ///< When updating the screen data, skip this one, because the user is interacting with it.
static bool ScreenComplete; ///< All VPs sent to screen?
static uint16_t ConfirmVP; ///< context for confirm screen (VP that will be emulated-sent on "OK").
static uint8_t MeshLevelIndex;
static uint8_t MeshLevelIconIndex;
static bool SaveSettingsRequested;
static bool HasScreenVersionMismatch;
static bool HasSynchronousOperation;
#if ENABLED(SDSUPPORT)
static int16_t top_file; ///< file on top of file chooser
static int16_t file_to_print; ///< touched file to be confirmed
#endif
private:
FORCE_INLINE static DGUSLCD_Screens GetPreviousScreen() {
return past_screens[0];
}
public: // Needed for VP auto-upload
static bool HasRGBSettings;
static creality_dwin_settings_t Settings;
};
extern DGUSScreenHandler ScreenHandler;
struct DGUSSynchronousOperation {
private:
bool is_running;
public:
DGUSSynchronousOperation() : is_running(false) {}
// Don't allow this to be created on the stack
void* operator new (std::size_t size) = delete;
void start() {
is_running = true;
ScreenHandler.SetSynchronousOperationStart();
}
void done() {
is_running = false;
ScreenHandler.SetSynchronousOperationFinish();
}
~DGUSSynchronousOperation() {
if (is_running) {
ScreenHandler.SetSynchronousOperationFinish();
}
}
};
@@ -0,0 +1,67 @@
/**
* 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
#include <stdint.h>
/**
* DGUSVPVariable.h
*
* Created on: Feb 9, 2019
* Author: tobi
*/
struct DGUS_VP_Variable {
uint16_t VP;
void* memadr; // If nullptr, the value cannot be uploaded to the display.
uint8_t size;
// Callback that will be called if the display modified the value.
// nullptr makes it readonly for the display.
void (*set_by_display_handler)(DGUS_VP_Variable &var, void *val_ptr);
void (*send_to_display_handler)(DGUS_VP_Variable &var);
template<typename T>
DGUS_VP_Variable& operator =(T &o) {
*(T*)memadr = o; // warning this is not typesafe.
// TODO: Call out the display or mark as dirty for the next update.
return *this;
}
};
// endianness swap
FORCE_INLINE uint16_t swap16(const uint16_t value) { return (value & 0xffU) << 8U | (value >> 8U); }
FORCE_INLINE int16_t swap16(const int16_t value) {
union { int16_t l; char lb[2]; } endian;
endian.l = value;
char tmp = endian.lb[1];
endian.lb[1] = endian.lb[0];
endian.lb[0] = tmp;
return endian.l;
}
FORCE_INLINE uint32_t uInt32Value(const uint32_t value) { return ((value>>24)&0xff) | ((value<<8)&0xff0000) | ((value>>8)&0xff00) | ((value<<24)&0xff000000); }
FORCE_INLINE uint16_t uInt16Value(void *val_ptr) { return swap16(*static_cast<uint16_t*>(val_ptr)); }
@@ -0,0 +1,230 @@
#include "../../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "../DGUSDisplayDef.h"
#include "../DGUSDisplay.h"
#include "../DGUSScreenHandler.h"
#include "EstepsHandler.h"
#include "AxisSettingsHandler.h"
#include "../../ui_api.h"
#include "../../../marlinui.h"
#include "../../../../module/temperature.h"
#include "../../../../module/settings.h"
#include "../../../../module/planner.h"
#include "../../../../gcode/gcode.h"
#if HAS_TRINAMIC_CONFIG
#include "../../../../feature/tmc_util.h"
#include "../../../../module/stepper/indirection.h"
#endif
AxisEnum AxisSettingsHandler::current_axis;
uint16_t AxisSettingsHandler::axis_settings_title_icon = ICON_AXIS_SETTINGS_TITLE_X;
float AxisSettingsHandler::axis_steps_mm;
uint16_t AxisSettingsHandler::max_acceleration_mm_per_s2;
float AxisSettingsHandler::jerk;
feedRate_t AxisSettingsHandler::max_feedrate;
#if HAS_TRINAMIC_CONFIG
bool AxisSettingsHandler::has_tmc_settings = true;
#else
bool AxisSettingsHandler::has_tmc_settings = false;
#endif
uint16_t AxisSettingsHandler::tmc_current;
bool AxisSettingsHandler::stealthchop;
uint32_t AxisSettingsHandler::hybrid_threshold;
void AxisSettingsHandler::HandleNavigation(DGUS_VP_Variable &var, void *val_ptr) {
switch (uInt16Value(val_ptr)) {
case AXIS_SETTINGS_NAV_BUTTON_VAL_X:
current_axis = X_AXIS;
axis_settings_title_icon = ICON_AXIS_SETTINGS_TITLE_X;
break;
case AXIS_SETTINGS_NAV_BUTTON_VAL_Y:
current_axis = Y_AXIS;
axis_settings_title_icon = ICON_AXIS_SETTINGS_TITLE_Y;
break;
case AXIS_SETTINGS_NAV_BUTTON_VAL_Z:
current_axis = Z_AXIS;
axis_settings_title_icon = ICON_AXIS_SETTINGS_TITLE_Z;
break;
case AXIS_SETTINGS_NAV_BUTTON_VAL_E:
current_axis = E_AXIS;
axis_settings_title_icon = ICON_AXIS_SETTINGS_TITLE_E;
break;
}
// Load settings for axis
axis_steps_mm = planner.settings.axis_steps_per_mm[current_axis];
max_acceleration_mm_per_s2 = static_cast<uint16_t>(planner.settings.max_acceleration_mm_per_s2[current_axis]);
IF_ENABLED(CLASSIC_JERK, jerk = planner.max_jerk[current_axis]);
max_feedrate = planner.settings.max_feedrate_mm_s[current_axis];
#if HAS_TRINAMIC_CONFIG
switch (current_axis){
#if AXIS_IS_TMC(X)
case X_AXIS:
tmc_current = stepperX.getMilliamps();
#if AXIS_HAS_STEALTHCHOP(X)
stealthchop = stepperX.get_stored_stealthChop();
#if ENABLED(HYBRID_THRESHOLD)
hybrid_threshold = static_cast<uint32_t>(stepperX.get_pwm_thrs());
#endif
#endif
break;
#endif
#if AXIS_IS_TMC(Y)
case Y_AXIS:
tmc_current = stepperY.getMilliamps();
#if AXIS_HAS_STEALTHCHOP(Y)
stealthchop = stepperY.get_stored_stealthChop();
#if ENABLED(HYBRID_THRESHOLD)
hybrid_threshold = static_cast<uint32_t>(stepperY.get_pwm_thrs());
#endif
#endif
break;
#endif
#if AXIS_IS_TMC(Z)
case Z_AXIS:
tmc_current = stepperZ.getMilliamps();
#if AXIS_HAS_STEALTHCHOP(Z)
stealthchop = stepperZ.get_stored_stealthChop();
#if ENABLED(HYBRID_THRESHOLD)
hybrid_threshold = static_cast<uint32_t>(stepperZ.get_pwm_thrs());
#endif
#endif
break;
#endif
#if AXIS_IS_TMC(E0)
case E_AXIS:
tmc_current = stepperE0.getMilliamps();
#if AXIS_HAS_STEALTHCHOP(E0)
stealthchop = stepperE0.get_stored_stealthChop();
#if ENABLED(HYBRID_THRESHOLD)
hybrid_threshold = static_cast<uint32_t>(stepperE0.get_pwm_thrs());
#endif
#endif
break;
#endif
default:
// Too bad
break;
}
#endif
// Nav
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_AXIS_SETTINGS_AXIS);
}
void AxisSettingsHandler::HandleBackNavigation(DGUS_VP_Variable &var, void *val_ptr) {
// Save settings for axis
planner.settings.axis_steps_per_mm[current_axis] = axis_steps_mm;
planner.settings.max_acceleration_mm_per_s2[current_axis] = max_acceleration_mm_per_s2;
IF_ENABLED(CLASSIC_JERK, planner.max_jerk[current_axis] = jerk);
planner.settings.max_feedrate_mm_s[current_axis] = max_feedrate;
// If we're handling the E-axis, the back button might end on that screen. Show that we didn't forget the settings.
if (current_axis == E_AXIS) {
EstepsHandler::set_esteps = axis_steps_mm;
EstepsHandler::calculated_esteps = axis_steps_mm;
}
#if HAS_TRINAMIC_CONFIG
switch (current_axis){
#if AXIS_IS_TMC(X)
case X_AXIS:
stepperX.rms_current(tmc_current);
#if AXIS_HAS_STEALTHCHOP(X)
stepperX.set_stealthChop(stealthchop);
#if ENABLED(HYBRID_THRESHOLD)
stepperX.set_pwm_thrs(hybrid_threshold);
#endif
#endif
break;
#endif
#if AXIS_IS_TMC(Y)
case Y_AXIS:
stepperY.rms_current(tmc_current);
#if AXIS_HAS_STEALTHCHOP(Y)
stepperY.set_stealthChop(stealthchop);
#if ENABLED(HYBRID_THRESHOLD)
stepperY.set_pwm_thrs(hybrid_threshold);
#endif
#endif
break;
#endif
#if AXIS_IS_TMC(Z)
case Z_AXIS:
stepperZ.rms_current(tmc_current);
#if AXIS_HAS_STEALTHCHOP(Z)
stepperZ.set_stealthChop(stealthchop);
#if ENABLED(HYBRID_THRESHOLD)
stepperZ.set_pwm_thrs(hybrid_threshold);
#endif
#endif
break;
#endif
#if AXIS_IS_TMC(E0)
case E_AXIS:
stepperE0.rms_current(tmc_current);
#if AXIS_HAS_STEALTHCHOP(E0)
stepperE0.set_stealthChop(stealthchop);
#if ENABLED(HYBRID_THRESHOLD)
stepperE0.set_pwm_thrs(hybrid_threshold);
#endif
#endif
break;
#endif
default:
// Too bad
break;
}
#endif
// Save and pop
ScreenHandler.PopToOldScreen();
settings.save();
}
void AxisSettingsHandler::HandleTMCNavigation(DGUS_VP_Variable &var, void *val_ptr) {
#if HAS_TRINAMIC_CONFIG
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_AXIS_SETTINGS_TMC);
#endif
}
#endif
@@ -0,0 +1,26 @@
#include <cstdint>
class AxisSettingsHandler {
private:
static AxisEnum current_axis;
public:
static uint16_t axis_settings_title_icon;
static float axis_steps_mm;
static uint16_t max_acceleration_mm_per_s2;
static float jerk;
static feedRate_t max_feedrate;
static bool has_tmc_settings;
static uint16_t tmc_current;
static bool stealthchop;
static uint32_t hybrid_threshold;
public:
static void HandleNavigation(DGUS_VP_Variable &var, void *val_ptr);
static void HandleBackNavigation(DGUS_VP_Variable &var, void *val_ptr);
static void HandleTMCNavigation(DGUS_VP_Variable &var, void *val_ptr);
};
@@ -0,0 +1,782 @@
/**
* 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/>.
*
*/
/* DGUS implementation written by Sebastiaan Dammann in 2020 for Marlin */
#include "../../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "../DGUSDisplayDef.h"
#include "../DGUSDisplay.h"
#include "../DGUSScreenHandler.h"
#include "AxisSettingsHandler.h"
#include "EstepsHandler.h"
#include "FilamentLoadUnloadHandler.h"
#include "PIDHandler.h"
#include "MeshValidationHandler.h"
#include "../../../../module/temperature.h"
#include "../../../../module/motion.h"
#include "../../../../module/planner.h"
#include "../../../../feature/caselight.h"
#if ENABLED(FWRETRACT)
#include "../../../../feature/fwretract.h"
#endif
#if HAS_COLOR_LEDS
#include "../../../../feature/leds/leds.h"
#endif
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../../../../feature/powerloss.h"
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#include "../../../../feature/runout.h"
#endif
#include "../../ui_api.h"
#include "../../../marlinui.h"
#include "PageHandlers.h"
#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
uint16_t distanceToMove = 10;
#endif
using namespace ExtUI;
const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION;
// ----- Common var lists
#if HOTENDS >= 1
#define VPList_HeatHotend VP_T_E0_Is, VP_T_E0_Set,
#else
#define VPList_HeatHotend
#endif
#if HAS_HEATED_BED
#define VPList_HeatBed VP_T_Bed_Is, VP_T_Bed_Set,
#else
#define VPList_HeatBed
#endif
#define VPList_Common VP_BACK_BUTTON_STATE
#define VPList_CommonWithStatus VPList_HeatHotend VPList_HeatBed VP_Z_OFFSET, VP_Feedrate_Percentage, VP_BACK_BUTTON_STATE
#define VPList_CommonWithHeatOnly VPList_HeatHotend VPList_HeatBed VP_BACK_BUTTON_STATE
// ----- Which variables to auto-update on which screens
const uint16_t VPList_None[] PROGMEM = {
VPList_Common,
0x0000
};
const uint16_t VPList_DialogStop[] PROGMEM = {
VPList_Common,
0x0000
};
const uint16_t VPList_Main[] PROGMEM = {
VPList_CommonWithStatus,
0x0000
};
const uint16_t VPList_SDFileList[] PROGMEM = {
VPList_CommonWithStatus,
VP_SD_FileName0,
VP_SD_FileName1,
VP_SD_FileName2,
VP_SD_FileName3,
VP_SD_FileName4,
VP_SD_FileName5,
0x0000
};
const uint16_t VPList_Control[] PROGMEM = {
VPList_CommonWithStatus,
VP_LED_TOGGLE,
VP_MUTE_ICON,
0x0000
};
const uint16_t VPList_Feed[] PROGMEM = {
VPList_CommonWithStatus,
VP_FILCHANGE_NOZZLE_TEMP,
VP_FILCHANGE_LENGTH,
0x0000
};
const uint16_t VPList_Temp[] PROGMEM = {
VPList_CommonWithStatus,
VP_FAN_TOGGLE,
0x0000
};
const uint16_t VPList_PreheatPLASettings[] PROGMEM = {
VPList_CommonWithStatus,
VP_PREHEAT_PLA_HOTEND_TEMP,
VP_PREHEAT_PLA_BED_TEMP,
0x0000
};
const uint16_t VPList_PreheatABSSettings[] PROGMEM = {
VPList_CommonWithStatus,
VP_PREHEAT_ABS_HOTEND_TEMP,
VP_PREHEAT_ABS_BED_TEMP,
0x0000
};
const uint16_t VPList_PrintPausingError[] PROGMEM = {
VPList_CommonWithStatus,
VP_X_POSITION,
VP_Y_POSITION,
VP_Z_POSITION_PRECISION,
VP_Z_OFFSET,
VP_Fan0_Percentage,
VP_Feedrate_Percentage,
VP_PrintProgress_Percentage,
VP_PrintTimeProgressBar,
VP_PrintTime,
VP_PrintTimeWithRemainingVisible,
VP_PrintTimeRemaining,
VP_LINEAR_ADVANCE_FACTOR,
0x0000
};
const uint16_t VPList_PrintScreen[] PROGMEM = {
VPList_CommonWithStatus,
VP_X_POSITION, VP_Y_POSITION, VP_Z_POSITION, VP_Z_POSITION_PRECISION,
SP_X_POSITION, SP_Y_POSITION, SP_Z_POSITION,
VP_Flowrate_E0,
VP_Fan0_Percentage,
VP_PrintProgress_Percentage,
VP_PrintTimeProgressBar,
VP_PrintTime,
VP_PrintTimeWithRemainingVisible,
VP_PrintTimeRemaining,
VP_LINEAR_ADVANCE_FACTOR,
VP_FWRETRACT_INDICATOR_ICON,
0x0000
};
const uint16_t VPList_Leveling[] PROGMEM = {
VPList_CommonWithStatus,
VP_MESH_LEVEL_TEMP,
0x0000
};
const uint16_t VPList_ZOffsetLevel[] PROGMEM = {
VPList_CommonWithStatus,
0x0000
};
const uint16_t VPList_TuneScreen[] PROGMEM = {
VPList_CommonWithStatus,
VP_PrintTime,
VP_Flowrate_E0,
VP_LED_TOGGLE,
VP_FAN_TOGGLE,
VP_Fan0_Percentage,
0x0000
};
const uint16_t VPList_TuneExtraScreen[] PROGMEM = {
VPList_CommonWithStatus,
VP_LINEAR_ADVANCE_FACTOR,
VP_RGB_NAV_BUTTON_ICON,
0x0000
};
const uint16_t VPList_Prepare[] PROGMEM = {
VPList_CommonWithStatus,
VP_PrintTime,
0x0000
};
const uint16_t VPList_Info[] PROGMEM = {
VPList_CommonWithStatus,
VP_PrintTime,
VP_PRINTER_BEDSIZE,
VP_MARLIN_WEBSITE,
VP_MARLIN_VERSION,
0x0000
};
const uint16_t VPList_EstepsCalibration[] PROGMEM = {
VPList_CommonWithHeatOnly,
VP_ESTEPS_CURRENT,
VP_ESTEPS_CALIBRATION_TEMP,
VP_ESTEPS_CALIBRATION_LENGTH,
VP_ESTEPS_CALIBRATION_LEFTOVER_LENGTH,
VP_ESTEPS_CALIBRATION_MARK_LENGTH,
VP_ESTEPS_CALCULATED_ESTEPS,
0x0000
};
const uint16_t VPList_PidTune[] PROGMEM = {
VPList_CommonWithHeatOnly,
VP_PIDTUNE_TARGET_TEMP,
VP_PIDTUNE_FAN_TOGGLE_ICON,
VP_PIDTUNE_CYCLES,
0x0000
};
const uint16_t VPList_FWRetractTune[] PROGMEM = {
VPList_CommonWithStatus,
VP_FWRETRACT_RETRACT_LENGTH,
VP_FWRETRACT_RETRACT_FEEDRATE,
VP_FWRETRACT_RETRACT_ZHOP,
VP_FWRETRACT_RESTART_LENGTH,
VP_FWRETRACT_RESTART_FEEDRATE,
VP_FWRETRACT_TOGGLE_BUTTON_ICON,
0x0000
};
const uint16_t VPList_LevelingSettings[] PROGMEM = {
VPList_CommonWithStatus,
VP_TOGGLE_PROBING_HEATERS_OFF_ONOFF_ICON,
VP_TOGGLE_PROBE_PREHEAT_HOTEND_TEMP,
VP_TOGGLE_PROBE_PREHEAT_BED_TEMP,
VP_TOGGLE_POST_PROBING_TEMPERATURE_STABILIZATION_ICON,
VP_LEVELING_FADE_HEIGHT,
0x0000
};
const uint16_t VPList_AxisSettingsNav[] PROGMEM = {
VPList_CommonWithStatus,
0x0000
};
const uint16_t VPList_AxisSettingsAxis[] PROGMEM = {
VPList_CommonWithHeatOnly,
VP_AXIS_SETTINGS_TITLE_ICON,
VP_AXIS_SETTINGS_AXIS_STEPSMM,
VP_AXIS_SETTINGS_AXIS_MAX_ACCEL,
VP_AXIS_SETTINGS_AXIS_JERK,
VP_AXIS_SETTINGS_AXIS_FEEDRATE,
VP_AXIS_TMC_NAV_ICON,
0x0000
};
const uint16_t VPList_AxisSettingsTMC[] PROGMEM = {
VPList_CommonWithHeatOnly,
VP_AXIS_SETTINGS_AXIS_TMCCURRENT,
VP_AXIS_SETTINGS_AXIS_TMCSTEALTHCHOP_ICON,
VP_AXIS_SETTINGS_AXIS_TMCHYBRIDTHRESHOLD,
0x0000
};
const uint16_t VPList_AdvMovementSettings[] PROGMEM = {
VPList_CommonWithHeatOnly,
VP_MOV_MINIMUM_SEGMENT_TIME,
VP_MOV_MINIMUM_FEEDRATE,
VP_MOV_NORMAL_ACCELERATION,
VP_MOV_RETRACT_ACCELERATION,
VP_MOV_MINIMUM_TRAVEL_FEEDRATE,
VP_MOV_MINIMUM_TRAVEL_ACCELERATION,
0x0000
};
const uint16_t VPList_MiscSettings[] PROGMEM = {
VPList_CommonWithHeatOnly,
VP_FILAMENTRUNOUT_SENSOR_TOGGLE_ICON,
VP_PLR_TOGGLE_ICON,
VP_STANDBY_BACKLIGHT_ICON,
VP_SCREEN_BACKLIGHT_STANDBY,
VP_SCREEN_BACKLIGHT,
VP_SCREEN_STANDBY_TIME,
VP_RGB_NAV_BUTTON_ICON,
0x0000
};
const uint16_t VPList_MeshValidation[] PROGMEM = {
VPList_CommonWithHeatOnly,
VP_MESHPATTERN_NOZZLE_TEMP,
VP_MESHPATTERN_BED_TEMP,
VP_MESHPATTERN_BUTTON_ICON,
0x0000
};
const uint16_t VPList_Calibrate[] PROGMEM = {
VPList_CommonWithStatus,
0x0000
};
const uint16_t VPList_RGB[] PROGMEM = {
VPList_CommonWithHeatOnly,
VP_RGB_CONTROL_R,
VP_RGB_CONTROL_G,
VP_RGB_CONTROL_B,
VP_RGB_CONTROL_W,
VP_RGB_CONTROL_I,
0x0000
};
// -- Mapping from screen to variable list
const struct VPMapping VPMap[] PROGMEM = {
{ DGUSLCD_SCREEN_BOOT, VPList_None },
{ DGUSLCD_SCREEN_MAIN, VPList_Main },
{ DGUSLCD_SCREEN_SDFILELIST, VPList_SDFileList },
{ DGUSLCD_SCREEN_FILAMENTRUNOUT1, VPList_PrintPausingError },
{ DGUSLCD_SCREEN_FILAMENTRUNOUT2, VPList_PrintPausingError },
{ DGUSLCD_SCREEN_PRINT_FINISH, VPList_PrintScreen },
{ DGUSLCD_SCREEN_PRINT_RUNNING, VPList_PrintScreen },
{ DGUSLCD_SCREEN_PRINT_PAUSED, VPList_PrintScreen },
{ DGUSLCD_SCREEN_TUNING, VPList_TuneScreen },
{ DGUSLCD_SCREEN_TUNING_EXTRA, VPList_TuneExtraScreen },
{ DGUSLCD_SCREEN_PREPARE, VPList_Prepare },
{ DGUSLCD_SCREEN_INFO, VPList_Info },
{ DGUSLCD_SCREEN_MOVE1MM, VPList_PrintScreen },
{ DGUSLCD_SCREEN_MOVE10MM, VPList_PrintScreen },
{ DGUSLCD_SCREEN_MOVE01MM, VPList_PrintScreen },
{ DGUSLCD_SCREEN_FEED, VPList_Feed },
{ DGUSLCD_SCREEN_SETUP, VPList_Control },
{ DGUSLCD_SCREEN_TEMP, VPList_Temp },
{ DGUSLCD_SCREEN_TEMP_PLA, VPList_PreheatPLASettings },
{ DGUSLCD_SCREEN_TEMP_ABS, VPList_PreheatABSSettings },
{ DGUSLCD_SCREEN_INFO, VPList_PrintScreen },
{ DGUSLCD_SCREEN_ZOFFSET_LEVEL, VPList_ZOffsetLevel },
{ DGUSLCD_SCREEN_LEVELING, VPList_Leveling },
{ DGUSLCD_SCREEN_POWER_LOSS, VPList_None },
{ DGUSLCD_SCREEN_THERMAL_RUNAWAY, VPList_None },
{ DGUSLCD_SCREEN_HEATING_FAILED, VPList_None },
{ DGUSLCD_SCREEN_THERMISTOR_ERROR, VPList_None },
{ DGUSLCD_SCREEN_AUTOHOME, VPList_PrintScreen },
{ DGUSLCD_SCREEN_DIALOG_PAUSE, VPList_None },
{ DGUSLCD_SCREEN_DIALOG_STOP, VPList_DialogStop },
{ DGUSLCD_SCREEN_CONFIRM, VPList_None },
{ DGUSLCD_SCREEN_POPUP, VPList_None },
{ DGUSLCD_SCREEN_ESTEPS_CALIBRATION, VPList_EstepsCalibration },
{ DGUSLCD_SCREEN_PIDTUNE_CALIBRATION, VPList_PidTune },
{ DGUSLCD_SCREEN_TUNEFWRETRACT, VPList_FWRetractTune },
{ DGUSLCD_SCREEN_ESTEPS_CALIBRATION_RESULTS, VPList_EstepsCalibration },
{ DGUSLCD_SCREEN_LEVELING_SETTINGS, VPList_LevelingSettings },
{ DGUSLCD_SCREEN_AXIS_SETTINGS_NAV, VPList_AxisSettingsNav },
{ DGUSLCD_SCREEN_AXIS_SETTINGS_AXIS , VPList_AxisSettingsAxis },
{ DGUSLCD_SCREEN_AXIS_SETTINGS_TMC, VPList_AxisSettingsTMC },
{ DGUSLCD_SCREEN_ADV_MOV_SETTINGS, VPList_AdvMovementSettings },
{ DGUSLCD_SCREEN_MISC_SETTINGS, VPList_MiscSettings },
{ DGUSLCD_SCREEN_MESH_VALIDATION, VPList_MeshValidation },
{ DGUSLCD_SCREEN_CALIBRATE, VPList_Calibrate },
{ DGUSLCD_SCREEN_RGB, VPList_RGB},
{ 0 , nullptr } // List is terminated with an nullptr as table entry.
};
// Helper to define a DGUS_VP_Variable for common use cases.
#define VPHELPER(VPADR, VPADRVAR, RXFPTR, TXFPTR ) { .VP=VPADR, .memadr=VPADRVAR, .size=sizeof(VPADRVAR), \
.set_by_display_handler = RXFPTR, .send_to_display_handler = TXFPTR }
// Helper to define a DGUS_VP_Variable when the sizeo of the var cannot be determined automaticalyl (eg. a string)
#define VPHELPER_STR(VPADR, VPADRVAR, STRLEN, RXFPTR, TXFPTR ) { .VP=VPADR, .memadr=VPADRVAR, .size=STRLEN, \
.set_by_display_handler = RXFPTR, .send_to_display_handler = TXFPTR }
const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
// Back button state
VPHELPER(VP_BACK_BUTTON_STATE, nullptr, nullptr, ScreenHandler.SendBusyState),
// Screen version
VPHELPER(VP_UI_VERSION_MAJOR, nullptr, ScreenHandler.HandleScreenVersion, nullptr),
#if HOTENDS >= 1
VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], ScreenHandler.HandleFlowRateChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
#endif
#if HAS_HEATED_BED
VPHELPER(VP_T_Bed_Is, &thermalManager.temp_bed.celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
VPHELPER(VP_T_Bed_Set, &thermalManager.temp_bed.target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
#endif
VPHELPER(VP_MESH_LEVEL_TEMP, &thermalManager.temp_hotend[0].target, nullptr, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
// Feedrate
VPHELPER(VP_Feedrate_Percentage, &feedrate_percentage, ScreenHandler.DGUSLCD_SetValueDirectly<int16_t>, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_PrintProgress_Percentage, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay),
VPHELPER(VP_PrintTimeProgressBar, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay),
// Calibration
// ... e-steps
VPHELPER(VP_ESTEPS_CURRENT, &EstepsHandler::set_esteps, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_ESTEPS_CALIBRATION_TEMP, &EstepsHandler::calibration_temperature, ScreenHandler.DGUSLCD_SetValueDirectly<uint16_t>, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_ESTEPS_CALIBRATION_LENGTH, &EstepsHandler::filament_to_extrude, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_ESTEPS_CALIBRATION_MARK_LENGTH, &EstepsHandler::mark_filament_mm, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_ESTEPS_CALIBRATION_LEFTOVER_LENGTH, &EstepsHandler::remaining_filament, EstepsHandler::HandleRemainingFilament, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_ESTEPS_CALCULATED_ESTEPS, &EstepsHandler::calculated_esteps, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_ESTEPS_CALIBRATESTART_BUTTON, nullptr, EstepsHandler::HandleStartButton, nullptr),
VPHELPER(VP_ESTEPS_APPLY_BUTTON, nullptr, EstepsHandler::HandleApplyButton, nullptr),
VPHELPER(VP_ESTEPS_BACK_BUTTON, nullptr, EstepsHandler::HandleBackButton, nullptr),
VPHELPER(VP_ESTEP_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_ESTEPS_CALIBRATION, EstepsHandler>), nullptr),
// ... PID
VPHELPER(VP_PIDTUNE_TARGET_TEMP, &PIDHandler::calibration_temperature, ScreenHandler.DGUSLCD_SetValueDirectly<uint16_t>, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_PIDTUNE_CYCLES, &PIDHandler::cycles, ScreenHandler.DGUSLCD_SetValueDirectly<uint16_t>, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_PIDTUNE_FAN_TOGGLE, &PIDHandler::fan_on, ScreenHandler.DGUSLCD_ToggleBoolean, nullptr),
VPHELPER(VP_PIDTUNE_FAN_TOGGLE_ICON, &PIDHandler::fan_on, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_TOGGLE_ON, ICON_TOGGLE_OFF>)),
VPHELPER(VP_PIDTUNE_START_BUTTON, nullptr, PIDHandler::HandleStartButton, nullptr),
VPHELPER(VP_PIDTUNE_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_PIDTUNE_CALIBRATION, PIDHandler>), nullptr),
VPHELPER(VP_GENERIC_BACK_BUTTON, nullptr, ScreenHandler.OnBackButton, nullptr),
// ... Mesh validation
VPHELPER(VP_MESHPATTERN_NOZZLE_TEMP, &MeshValidationHandler::nozzle_temperature, MeshValidationHandler::HandleTemperature, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_MESHPATTERN_BED_TEMP, &MeshValidationHandler::bed_temperature, MeshValidationHandler::HandleTemperature, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_MESHPATTERN_BUTTON_ICON, &MeshValidationHandler::is_running, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<MESHPATTERN_BUTTON_CANCEL, MESHPATTERN_BUTTON_START>)),
VPHELPER(VP_MESHPATTERN_START_BUTTON, nullptr, MeshValidationHandler::HandleStartOrCancelButton, nullptr),
VPHELPER(VP_MESHPATTERN_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_MESH_VALIDATION, MeshValidationHandler>), nullptr),
// Axis settings
VPHELPER(VP_AXIS_SETTINGS_NAV_BUTTON, nullptr, AxisSettingsHandler::HandleNavigation, nullptr),
VPHELPER(VP_AXIS_SETTINGS_TITLE_ICON, &AxisSettingsHandler::axis_settings_title_icon, nullptr, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_AXIS_SETTINGS_AXIS_STEPSMM, &AxisSettingsHandler::axis_steps_mm, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_AXIS_SETTINGS_AXIS_MAX_ACCEL, &AxisSettingsHandler::max_acceleration_mm_per_s2, ScreenHandler.DGUSLCD_SetValueDirectly<uint16_t>, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_AXIS_SETTINGS_AXIS_JERK, &AxisSettingsHandler::jerk, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_AXIS_SETTINGS_AXIS_FEEDRATE, &AxisSettingsHandler::max_feedrate, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_AXIS_SETTINGS_AXIS_TMCCURRENT, &AxisSettingsHandler::tmc_current, ScreenHandler.DGUSLCD_SetValueDirectly<uint16_t>, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_AXIS_SETTINGS_AXIS_TMCSTEALTHCHOP_BUTTON, &AxisSettingsHandler::stealthchop, ScreenHandler.DGUSLCD_ToggleBoolean, nullptr),
VPHELPER(VP_AXIS_SETTINGS_AXIS_TMCSTEALTHCHOP_ICON, &AxisSettingsHandler::stealthchop, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_TOGGLE_ON, ICON_TOGGLE_OFF>)),
VPHELPER(VP_AXIS_SETTINGS_AXIS_TMCHYBRIDTHRESHOLD, &AxisSettingsHandler::hybrid_threshold, ScreenHandler.DGUSLCD_ReceiveULongFromDisplay, ScreenHandler.DGUSLCD_SendULongToDisplay),
VPHELPER(VP_AXIS_TMC_NAV_ICON, &AxisSettingsHandler::has_tmc_settings, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<AXIS_TMC_NAV_ICON_SHOWING, AXIS_TMC_NAV_ICON_HIDING>)),
VPHELPER(VP_AXIS_SETTINGS_NAV_BACKBUTTON, nullptr, AxisSettingsHandler::HandleBackNavigation, nullptr),
VPHELPER(VP_AXIS_TUNING_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_AXIS_SETTINGS_NAV>), nullptr),
VPHELPER(VP_AXIS_TMC_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_AXIS_SETTINGS_TMC>), nullptr),
// Advanced movement settings
VPHELPER(VP_MOV_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_ADV_MOV_SETTINGS>), nullptr),
VPHELPER(VP_MOV_MINIMUM_SEGMENT_TIME, &planner.settings.min_segment_time_us, ScreenHandler.DGUSLCD_SetValueDirectly<uint16_t>, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_MOV_MINIMUM_FEEDRATE, &planner.settings.min_feedrate_mm_s, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_MOV_NORMAL_ACCELERATION, &planner.settings.acceleration, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_MOV_RETRACT_ACCELERATION, &planner.settings.retract_acceleration, ScreenHandler.DGUSLCD_SetFloatAsLongFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<1>),
VPHELPER(VP_MOV_MINIMUM_TRAVEL_FEEDRATE, &planner.settings.min_travel_feedrate_mm_s, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_MOV_MINIMUM_TRAVEL_ACCELERATION, &planner.settings.travel_acceleration, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
// Misc settings
VPHELPER(VP_MISCSETTINGS_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_MISC_SETTINGS>), nullptr),
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
VPHELPER(VP_FILAMENTRUNOUT_SENSOR_TOGGLE_BUTTON, &runout.enabled, ScreenHandler.DGUSLCD_ToggleBoolean, nullptr),
VPHELPER(VP_FILAMENTRUNOUT_SENSOR_TOGGLE_ICON, &runout.enabled, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_TOGGLE_ON, ICON_TOGGLE_OFF>)),
#endif
#if ENABLED(POWER_LOSS_RECOVERY)
VPHELPER(VP_PLR_TOGGLE_BUTTON, nullptr, ScreenHandler.TogglePowerLossRecovery, nullptr),
VPHELPER(VP_PLR_TOGGLE_ICON, &PrintJobRecovery::enabled, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_TOGGLE_ON, ICON_TOGGLE_OFF>)),
#endif
// Preheat settings
#ifdef PREHEAT_1_LABEL
VPHELPER(VP_PREHEAT_PLA_HOTEND_TEMP, &ui.material_preset[0].hotend_temp, ScreenHandler.DGUSLCD_SetValueDirectly<int16_t>, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_PREHEAT_PLA_BED_TEMP, &ui.material_preset[0].bed_temp, ScreenHandler.DGUSLCD_SetValueDirectly<int16_t>, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
#endif
#ifdef PREHEAT_2_LABEL
VPHELPER(VP_PREHEAT_ABS_HOTEND_TEMP, &ui.material_preset[1].hotend_temp, ScreenHandler.DGUSLCD_SetValueDirectly<int16_t>, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_PREHEAT_ABS_BED_TEMP, &ui.material_preset[1].bed_temp, ScreenHandler.DGUSLCD_SetValueDirectly<int16_t>, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
#endif
// About info
VPHELPER_STR(VP_MARLIN_WEBSITE, nullptr, VP_MARLIN_WEBSITE_LEN, nullptr, ScreenHandler.DGUSLCD_SendAboutFirmwareWebsite),
VPHELPER_STR(VP_MARLIN_VERSION, nullptr, VP_MARLIN_VERSION_LEN, nullptr, ScreenHandler.DGUSLCD_SendAboutFirmwareVersion),
VPHELPER_STR(VP_PRINTER_BEDSIZE, nullptr, VP_PRINTER_BEDSIZE_LEN, nullptr, ScreenHandler.DGUSLCD_SendAboutPrintSize),
// Position Data
VPHELPER(VP_X_POSITION, &current_position.x, ScreenHandler.HandlePositionChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_Y_POSITION, &current_position.y, ScreenHandler.HandlePositionChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_Z_POSITION, &current_position.z, ScreenHandler.HandlePositionChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_Z_POSITION_PRECISION, &current_position.z, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
VPHELPER(SP_X_POSITION, nullptr, nullptr, ScreenHandler.SendAxisTrustValue<X_AXIS>),
VPHELPER(SP_Y_POSITION, nullptr, nullptr, ScreenHandler.SendAxisTrustValue<Y_AXIS>),
VPHELPER(SP_Z_POSITION, nullptr, nullptr, ScreenHandler.SendAxisTrustValue<Z_AXIS>),
VPHELPER(VP_Z_OFFSET, &probe.offset.z, ScreenHandler.HandleZoffsetChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
VPHELPER(VP_FAN_TOGGLE, &thermalManager.fan_speed[0], nullptr, ScreenHandler.DGUSLCD_SendFanStatusToDisplay),
VPHELPER(VP_Fan0_Percentage, &thermalManager.fan_speed[0], ScreenHandler.HandleFanSpeedChanged, ScreenHandler.DGUSLCD_SendFanSpeedToDisplay),
#if ENABLED(POWER_LOSS_RECOVERY)
VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, &ScreenHandler.HandlePowerLossRecovery, nullptr),
#endif
VPHELPER_STR(VP_PrintTime, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeToDisplay),
VPHELPER_STR(VP_PrintTimeWithRemainingVisible, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeWithRemainingToDisplay),
VPHELPER_STR(VP_PrintTimeRemaining, nullptr, VP_PrintTimeRemaining_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeRemainingToDisplay),
VPHELPER(VP_SCREENCHANGE, nullptr, ScreenHandler.ScreenChangeHook, nullptr),
VPHELPER(VP_CONFIRMED, nullptr, ScreenHandler.ScreenConfirmedOK, nullptr),
#if HAS_PROBE_SETTINGS
VPHELPER(VP_TOGGLE_PROBING_HEATERS_OFF_ONOFF_BUTTON, nullptr, ScreenHandler.HandleToggleProbeHeaters, nullptr),
VPHELPER(VP_TOGGLE_PROBING_HEATERS_OFF_ONOFF_ICON, &probe.settings.turn_heaters_off, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_ACCURACY_TOGGLE_ON, ICON_ACCURACY_TOGGLE_OFF>)),
VPHELPER(VP_TOGGLE_POST_PROBING_TEMPERATURE_STABILIZATION_BUTTON, nullptr, ScreenHandler.HandleToggleProbeTemperatureStabilization, nullptr),
VPHELPER(VP_TOGGLE_POST_PROBING_TEMPERATURE_STABILIZATION_ICON, &probe.settings.stabilize_temperatures_after_probing, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_POST_PROBE_TEMP_STABILIZATION_TOGGLE_ON, ICON_POST_PROBE_TEMP_STABILIZATION_TOGGLE_OFF>)),
VPHELPER(VP_TOGGLE_PROBE_PREHEAT_HOTEND_TEMP, &probe.settings.preheat_hotend_temp, ScreenHandler.HandleToggleProbePreheatTemp, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_TOGGLE_PROBE_PREHEAT_BED_TEMP, &probe.settings.preheat_bed_temp, ScreenHandler.HandleToggleProbePreheatTemp, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
#endif
VPHELPER(VP_LEVELING_FADE_HEIGHT, &planner.z_fade_height, ScreenHandler.HandleFadeHeight, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_LEVELING_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_ZOFFSET_LEVEL>), nullptr),
VPHELPER(VP_LEVELING_EDIT_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_LEVELING>), nullptr),
VPHELPER(VP_TOGGLE_PROBE_SETTINGS_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_LEVELING_SETTINGS>), nullptr),
// Creality has the same button ID mapped all over the place, so let the generic handler figure it out
VPHELPER(VP_BUTTON_MAINENTERKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_ADJUSTENTERKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_PREPAREENTERKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_RESUMEPRINTKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_SELECTFILEKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_STARTPRINTKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_STOPPRINTKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_PAUSEPRINTKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_COOLDOWN, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_TEMPCONTROL, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_BEDLEVELKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_HEATLOADSTARTKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
VPHELPER(VP_BUTTON_MOVEKEY, nullptr, DGUSCrealityDisplay_HandleReturnKeyEvent, nullptr),
// File listing
VPHELPER(VP_SD_ScrollEvent, nullptr, ScreenHandler.DGUSLCD_SD_ScrollFilelist, nullptr),
VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.DGUSLCD_SD_FileSelected, nullptr),
VPHELPER(VP_SD_FileSelectConfirm, nullptr, ScreenHandler.DGUSLCD_SD_StartPrint, nullptr),
VPHELPER_STR(VP_SD_FileName0, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
VPHELPER_STR(VP_SD_FileName1, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
VPHELPER_STR(VP_SD_FileName2, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
VPHELPER_STR(VP_SD_FileName3, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
VPHELPER_STR(VP_SD_FileName4, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
VPHELPER_STR(VP_SD_FileName5, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
// Firmware retract
VPHELPER(VP_FWRETRACT_NAV_BUTTON, nullptr, ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_TUNEFWRETRACT>, nullptr),
VPHELPER(VP_FWRETRACT_RETRACT_LENGTH, &fwretract.settings.retract_length, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_FWRETRACT_RETRACT_FEEDRATE, &fwretract.settings.retract_feedrate_mm_s, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_FWRETRACT_RETRACT_ZHOP, &fwretract.settings.retract_zraise, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_FWRETRACT_RESTART_LENGTH, &fwretract.settings.retract_recover_extra, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_FWRETRACT_RESTART_FEEDRATE, &fwretract.settings.retract_recover_feedrate_mm_s, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_FWRETRACT_INDICATOR_ICON, &fwretract.autoretract_enabled, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_FWRETRACT_AUTO_ENGAGED, ICON_FWRETRACT_AUTO_DISENGAGED>)),
VPHELPER(VP_FWRETRACT_TOGGLE_BUTTON_ICON, &fwretract.autoretract_enabled, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_FWRETRACT_AUTO_TOGGLE_ON, ICON_FWRETRACT_AUTO_TOGGLE_OFF>)),
VPHELPER(VP_FWRETRACT_TOGGLE_BUTTON, &fwretract.autoretract_enabled, ScreenHandler.DGUSLCD_ToggleBoolean, nullptr),
// Other tuning
#if ENABLED(LIN_ADVANCE)
VPHELPER(VP_LINEAR_ADVANCE_FACTOR, &planner.extruder_advance_K[0], ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<2>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
#endif
VPHELPER(VP_OTHER_TUNE_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_TUNING_EXTRA>), nullptr),
// Additional buttons
VPHELPER(VP_MUTE_TOGGLE, nullptr, ScreenHandler.HandleToggleTouchScreenMute, nullptr),
VPHELPER(VP_STANDBY_BACKLIGHT_TOGGLE, nullptr, ScreenHandler.HandleToggleTouchScreenStandbySetting, nullptr),
// Additional settings
VPHELPER(VP_SCREEN_BACKLIGHT_STANDBY, &ScreenHandler.Settings.standby_screen_brightness, ScreenHandler.HandleTouchScreenStandbyBrightnessSetting, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_SCREEN_BACKLIGHT, &ScreenHandler.Settings.screen_brightness, ScreenHandler.HandleTouchScreenBrightnessSetting, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_SCREEN_STANDBY_TIME, &ScreenHandler.Settings.standby_time_seconds, ScreenHandler.HandleTouchScreenStandbyTimeSetting, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
// RGB
VPHELPER(VP_RGB_NAV_BUTTON_ICON, &ScreenHandler.HasRGBSettings, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_RGB_SETTINGS_AVAILABLE, ICON_RGB_SETTINGS_UNAVAILABLE>)),
#if HAS_COLOR_LEDS
VPHELPER(VP_RGB_NAV_BUTTON, nullptr, ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_RGB>, nullptr),
VPHELPER(VP_RGB_CONTROL_R, &leds.color.r, ScreenHandler.HandleLED, ScreenHandler.SendLEDToDisplay),
VPHELPER(VP_RGB_CONTROL_G, &leds.color.g, ScreenHandler.HandleLED, ScreenHandler.SendLEDToDisplay),
VPHELPER(VP_RGB_CONTROL_B, &leds.color.b, ScreenHandler.HandleLED, ScreenHandler.SendLEDToDisplay),
#if EITHER(RGBW_LED, NEOPIXEL_LED)
VPHELPER(VP_RGB_CONTROL_W, &leds.color.w, ScreenHandler.HandleLED, ScreenHandler.SendLEDToDisplay),
#if ENABLED(NEOPIXEL_LED)
VPHELPER(VP_RGB_CONTROL_I, &leds.color.i, ScreenHandler.HandleLED, ScreenHandler.SendLEDToDisplay),
#endif
#endif
#endif
// Filament load/unload
VPHELPER(VP_FILCHANGE_NAV_BUTTON, nullptr, (ScreenHandler.DGUSLCD_NavigateToPage<DGUSLCD_SCREEN_FEED, FilamentLoadUnloadHandler>), nullptr),
VPHELPER(VP_FILCHANGE_LENGTH, &FilamentLoadUnloadHandler::length, ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
VPHELPER(VP_FILCHANGE_NOZZLE_TEMP, &FilamentLoadUnloadHandler::nozzle_temperature, FilamentLoadUnloadHandler::HandleTemperature, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_FILCHANGE_ACTION_BUTTON, nullptr, FilamentLoadUnloadHandler::HandleLoadUnloadButton, nullptr),
// Icons
VPHELPER(VP_LED_TOGGLE, &caselight.on, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_LED_TOGGLE_ON, ICON_LED_TOGGLE_OFF>)),
VPHELPER(VP_STANDBY_BACKLIGHT_ICON, &ScreenHandler.Settings.display_standby, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_TOGGLE_ON, ICON_TOGGLE_OFF>)),
VPHELPER(VP_MUTE_ICON, &ScreenHandler.Settings.display_sound, nullptr, (ScreenHandler.DGUSLCD_SendIconValue<ICON_SOUND_TOGGLE_ON, ICON_SOUND_TOGGLE_OFF>)),
// Development test button
VPHELPER(VP_DEVELOPMENT_HELPER_BUTTON, nullptr, ScreenHandler.HandleDevelopmentTestButton, nullptr),
// Mesh override input
#if MESH_INPUT_SUPPORTED_SIZE == GRID_MAX_POINTS
//#define _VPHELPER_GP(N) VPHELPER((VP_MESH_INPUT_X0_Y0 + ( ##N## * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
//REPEAT(MESH_INPUT_SUPPORTED_SIZE, _VPHELPER_GP)
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 0 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 1 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 2 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 3 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 4 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 5 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 6 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 7 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 8 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 9 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 10 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 11 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 12 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 13 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 14 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
VPHELPER((VP_MESH_INPUT_X0_Y0 + ( 15 * MESH_INPUT_DATA_SIZE)), nullptr, ScreenHandler.HandleMeshPoint, nullptr),
#endif
// M117 LCD String (We don't need the string in memory but "just" push it to the display on demand, hence the nullptr
{ .VP = VP_M117, .memadr = nullptr, .size = VP_M117_LEN, .set_by_display_handler = nullptr, .send_to_display_handler =&ScreenHandler.DGUSLCD_SendStringToDisplay },
{ .VP = VP_M117_STATIC, .memadr = nullptr, .size = VP_M117_STATIC_LEN, .set_by_display_handler = nullptr, .send_to_display_handler =&ScreenHandler.DGUSLCD_SendStringToDisplay },
// Messages for the User, shared by the popup and the kill screen. They cant be autouploaded as we do not buffer content.
{ .VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
{ .VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
{ .VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
//{ .VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
VPHELPER(0, 0, 0, 0) // must be last entry.
};
#endif // DGUS_LCD_UI_ORIGIN
@@ -0,0 +1,562 @@
/**
* 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
enum DGUSLCD_Screens : uint8_t {
DGUSLCD_SCREEN_BOOT = 0,
DGUSLCD_SCREEN_MAIN = 28,
DGUSLCD_SCREEN_CONFIRM = 66,
DGUSLCD_SCREEN_SDPRINTMANIPULATION = 37 ,
DGUSLCD_SCREEN_SDPRINTTUNE = 41,
DGUSLCD_SCREEN_SDFILELIST = 67,
DGUSLCD_SCREEN_FILAMENTRUNOUT1 = 34, // DWINTouchPage::ERR_FILAMENTRUNOUT_HOTEND_COLD
DGUSLCD_SCREEN_FILAMENTRUNOUT2 = 35, // DWINTouchPage::ERR_FILAMENTRUNOUT_FILAMENT_LOADED
DGUSLCD_SCREEN_PRINT_FINISH = 36, // DWINTouchPage::PRINT_FINISHED
DGUSLCD_SCREEN_PRINT_RUNNING = 37, // DWINTouchPage::PRINT_PROGRESS_RUNNING
DGUSLCD_SCREEN_PRINT_PAUSED = 39, // DWINTouchPage::PRINT_PROGRESS_PAUSED
DGUSLCD_SCREEN_DIALOG_PAUSE = 38, // DWINTouchPage::DIALOG_PAUSE_PRINTING
DGUSLCD_SCREEN_DIALOG_STOP = 40, // DWINTouchPage::DIALOG_STOP_PRINTING
DGUSLCD_SCREEN_TUNING = 41, // DWINTouchPage::MENU_TUNING
DGUSLCD_SCREEN_TUNING_EXTRA = 79, // (this is a new page)
DGUSLCD_SCREEN_PREPARE = 42, // DWINTouchPage::MENU_PREPARE
DGUSLCD_SCREEN_MOVE10MM = 43, // DWINTouchPage::MOVE_1MM
DGUSLCD_SCREEN_MOVE1MM = 44, // DWINTouchPage::MOVE_10MM
DGUSLCD_SCREEN_MOVE01MM = 45, // DWINTouchPage::MOVE_01MM
DGUSLCD_SCREEN_FEED = 46, // DWINTouchPage::FEED
DGUSLCD_SCREEN_SETUP = 47, // DWINTouchPage::MENU_CONTROL
DGUSLCD_SCREEN_TEMP = 48, // DWINTouchPage::MENU_TEMP
DGUSLCD_SCREEN_TEMP_PLA = 49, // DWINTouchPage::MENU_PLA_TEMP
DGUSLCD_SCREEN_TEMP_ABS = 50, // DWINTouchPage::MENU_ABS_TEMP
DGUSLCD_SCREEN_INFO = 51, // DWINTouchPage::MENU_ABOUT
DGUSLCD_SCREEN_ZOFFSET_LEVEL = 52, // DWINTouchPage::MENU_ZOFFSET_LEVELING
DGUSLCD_SCREEN_LEVELING = 53, // DWINTouchPage::LEVELING
DGUSLCD_SCREEN_POWER_LOSS = 54, // DWINTouchPage::DIALOG_POWER_FAILURE
DGUSLCD_SCREEN_THERMAL_RUNAWAY = 57, // DWINTouchPage::ERR_THERMAL_RUNAWAY
DGUSLCD_SCREEN_HEATING_FAILED = 58, // DWINTouchPage::ERR_HEATING_FAILED
DGUSLCD_SCREEN_THERMISTOR_ERROR = 59, // DWINTouchPage::ERR_THERMISTOR
DGUSLCD_SCREEN_AUTOHOME = 61, // DWINTouchPage::AUTOHOME_IN_PROGRESS
DGUSLCD_SCREEN_POPUP = 63, // NEW - does not exist in original display
DGUSLCD_SCREEN_KILL = 64, // NEW - does not exist in original display
DGUSLCD_SCREEN_PIDTUNE_CALIBRATION = 68,
DGUSLCD_SCREEN_ESTEPS_CALIBRATION = 69,
DGUSLCD_SCREEN_TUNEFWRETRACT = 70,
DGUSLCD_SCREEN_ESTEPS_CALIBRATION_RESULTS = 71,
DGUSLCD_SCREEN_LEVELING_SETTINGS = 72,
DGUSLCD_SCREEN_AXIS_SETTINGS_NAV = 73,
DGUSLCD_SCREEN_AXIS_SETTINGS_AXIS = 74,
DGUSLCD_SCREEN_AXIS_SETTINGS_TMC = 75,
DGUSLCD_SCREEN_ADV_MOV_SETTINGS = 76,
DGUSLCD_SCREEN_MISC_SETTINGS = 77,
DGUSLCD_SCREEN_MESH_VALIDATION = 78,
DGUSLCD_SCREEN_CALIBRATE = 80,
DGUSLCD_SCREEN_RGB = 81
};
// Version checks
constexpr uint16_t VP_UI_VERSION_MAJOR = 0xFFFA;
constexpr uint16_t EXPECTED_UI_VERSION_MAJOR = 61;
constexpr uint16_t VERSION_MISMATCH_BUZZ_AMOUNT = 5;
constexpr uint16_t VERSION_MISMATCH_LED_FLASH_DELAY = 1000;
#define VP_STARTPROGRESSBAR 0x1000
// // Storage space for the Killscreen messages. Reused for the popup.
constexpr uint16_t VP_MSGSTR1 = 0x2010;
constexpr uint8_t VP_MSGSTR1_LEN = 0x20; // might be more place for it...
constexpr uint16_t VP_MSGSTR2 = 0x2030;
constexpr uint8_t VP_MSGSTR2_LEN = 0x40;
constexpr uint16_t VP_MSGSTR3 = 0x2070;
constexpr uint8_t VP_MSGSTR3_LEN = 0x40;
constexpr uint16_t VP_MSGSTR4 = 0x2080;
constexpr uint8_t VP_MSGSTR4_LEN = 0x20;
// // Screenchange request for screens that only make sense when printer is idle.
// // e.g movement is only allowed if printer is not printing.
// // Marlin must confirm by setting the screen manually.
// constexpr uint16_t VP_SCREENCHANGE_ASK = 0x2000;
constexpr uint16_t VP_SCREENCHANGE = 0x219f; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte.
// constexpr uint16_t VP_TEMP_ALL_OFF = 0x2002; // Turn all heaters off. Value arbitrary ;)=
// constexpr uint16_t VP_SCREENCHANGE_WHENSD = 0x2003; // "Print" Button touched -- go only there if there is an SD Card.
constexpr uint16_t VP_CONFIRMED = 0x219E; // OK on confirm screen.
// // Buttons on the SD-Card File listing.
// constexpr uint16_t VP_SD_ScrollEvent = 0x2020; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
// constexpr uint16_t VP_SD_FileSelected = 0x2022; // Number of file field selected.
constexpr uint16_t VP_SD_FileSelectConfirm = 0x2024; // (This is a virtual VP and emulated by the Confirm Screen when a file has been confirmed)
// constexpr uint16_t VP_SD_ResumePauseAbort = 0x2026; // Resume(Data=0), Pause(Data=1), Abort(Data=2) SD Card prints
constexpr uint16_t VP_SD_AbortPrintConfirmed = 0x2028; // Abort print confirmation (virtual, will be injected by the confirm dialog)
// constexpr uint16_t VP_SD_Print_Setting = 0x2040;
// constexpr uint16_t VP_SD_Print_LiveAdjustZ = 0x2050; // Data: 0 down, 1 up
// // Controls for movement (we can't use the incremental / decremental feature of the display at this feature works only with 16 bit values
// // (which would limit us to 655.35mm, which is likely not a problem for common setups, but i don't want to rule out hangprinters support)
// // A word about the coding: The VP will be per axis and the return code will be an signed 16 bit value in 0.01 mm resolution, telling us
// // the relative travel amount t he user wants to do. So eg. if the display sends us VP=2100 with value 100, the user wants us to move X by +1 mm.
constexpr uint16_t VP_MOVE_X = 0x2100;
constexpr uint16_t VP_MOVE_Y = 0x2102;
constexpr uint16_t VP_MOVE_Z = 0x2104;
constexpr uint16_t VP_MOVE_E0 = 0x2110;
// constexpr uint16_t VP_MOVE_E1 = 0x2112;
// //constexpr uint16_t VP_MOVE_E2 = 0x2114;
// //constexpr uint16_t VP_MOVE_E3 = 0x2116;
// //constexpr uint16_t VP_MOVE_E4 = 0x2118;
// //constexpr uint16_t VP_MOVE_E5 = 0x211A;
constexpr uint16_t VP_HOME_ALL = 0x2120;
// constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130;
// // Power loss recovery
// constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180;
// // Fan Control Buttons , switch between "off" and "on"
// constexpr uint16_t VP_FAN0_CONTROL = 0x2200;
// constexpr uint16_t VP_FAN1_CONTROL = 0x2202;
// //constexpr uint16_t VP_FAN2_CONTROL = 0x2204;
// //constexpr uint16_t VP_FAN3_CONTROL = 0x2206;
// // Heater Control Buttons , triged between "cool down" and "heat PLA" state
constexpr uint16_t VP_E0_CONTROL = 0x2210;
// constexpr uint16_t VP_E1_CONTROL = 0x2212;
// //constexpr uint16_t VP_E2_CONTROL = 0x2214;
// //constexpr uint16_t VP_E3_CONTROL = 0x2216;
// //constexpr uint16_t VP_E4_CONTROL = 0x2218;
// //constexpr uint16_t VP_E5_CONTROL = 0x221A;
constexpr uint16_t VP_BED_CONTROL = 0x221C;
// // Preheat
// constexpr uint16_t VP_E0_BED_PREHEAT = 0x2220;
// constexpr uint16_t VP_E1_BED_CONTROL = 0x2222;
// //constexpr uint16_t VP_E2_BED_CONTROL = 0x2224;
// //constexpr uint16_t VP_E3_BED_CONTROL = 0x2226;
// //constexpr uint16_t VP_E4_BED_CONTROL = 0x2228;
// //constexpr uint16_t VP_E5_BED_CONTROL = 0x222A;
// // Filament load and unload
// constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300;
// constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2302;
// // Settings store , reset
// constexpr uint16_t VP_SETTINGS = 0x2400;
// // PID autotune
constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x2410;
// //constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x2412;
// //constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x2414;
// //constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x2416;
// //constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x2418;
// //constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x241A;
constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x2420;
// // Firmware version on the boot screen.
constexpr uint16_t VP_PRINTER_BEDSIZE = 0x1074;
constexpr uint16_t VP_PRINTER_BEDSIZE_LEN = 12;
constexpr uint16_t VP_MARLIN_VERSION = 0x2222;
constexpr uint8_t VP_MARLIN_VERSION_LEN = 32;
constexpr uint16_t VP_MARLIN_WEBSITE = 0x2242;
constexpr uint8_t VP_MARLIN_WEBSITE_LEN = 32;
constexpr uint16_t VP_STANDBY_BACKLIGHT_ICON = 0x2280;
constexpr uint16_t VP_STANDBY_BACKLIGHT_TOGGLE = 0x2282;
constexpr uint16_t VP_MUTE_ICON = 0x2284;
constexpr uint16_t VP_MUTE_TOGGLE = 0x2286;
constexpr uint16_t VP_SCREEN_BACKLIGHT_STANDBY = 0x228D;
constexpr uint16_t VP_SCREEN_BACKLIGHT = 0x2384;
constexpr uint16_t VP_SCREEN_STANDBY_TIME = 0x2386;
// Material preheat settings
constexpr uint16_t VP_PREHEAT_PLA_HOTEND_TEMP = 0x1102;
constexpr uint16_t VP_PREHEAT_PLA_BED_TEMP = 0x1104;
constexpr uint16_t VP_PREHEAT_ABS_HOTEND_TEMP = 0x1108;
constexpr uint16_t VP_PREHEAT_ABS_BED_TEMP = 0x110a;
// Place for status messages.
// ... We have memory space for scrolling messages
constexpr uint16_t VP_M117 = 0x3000 + (3 * 1); // Text Variable Pointer. First three VP must be reserved [a VP is two bytes red.]. Text is saved after the 3rd VP and ended with 0x00 or 0x0F.
constexpr uint8_t VP_M117_LEN = 100;
// ... And memory space for static (short) messages. Note this VPAddr is also the VP of the 5 beta and alpha 4 touch screens.
constexpr uint8_t M117_STATIC_DISPLAY_LEN = 28; // Fits "TFT flashed incorrectly v0" exactly
constexpr uint16_t VP_M117_STATIC = 0x21B3;
constexpr uint8_t VP_M117_STATIC_LEN = 70;
// // Temperatures.
constexpr uint16_t VP_T_E0_Is = 0x1036; // 4 Byte Integer - HEAD_CURRENT_TEMP_VP
constexpr uint16_t VP_T_E0_Set = 0x1034; // 2 Byte Integer - HEAD_SET_TEMP_VP
constexpr uint16_t VP_T_Bed_Is = 0x103c; // 4 Byte Integer - BED_SET_TEMP_VP
constexpr uint16_t VP_T_Bed_Set = 0x103A; // 2 Byte Integer - BED_CURRENT_TEMP_VP
constexpr uint16_t VP_Flowrate_E0 = 0x228A; // 2 Byte Integer
constexpr uint16_t VP_Fan0_Percentage = 0x228F; // 2 Byte Integer (0..100)
constexpr uint16_t VP_Feedrate_Percentage = 0x1006; // 2 Byte Integer (0..100) - PRINT_SPEED_RATE_VP
constexpr uint16_t VP_PrintProgress_Percentage = 0x1016; // 2 Byte Integer (0..100)
constexpr uint16_t VP_PrintTimeProgressBar = 0x100E;
constexpr uint16_t VP_PrintTime = 0x21a0;
constexpr uint16_t VP_PrintTimeWithRemainingVisible = 0x2335;
constexpr uint16_t VP_PrintTime_LEN = 19;
constexpr uint16_t VP_PrintTimeRemaining = 0x231f;
constexpr uint16_t VP_PrintTimeRemaining_LEN = 21;
constexpr uint16_t VP_HideRemainingTime_Ico = 0x2380;
constexpr uint16_t ICON_REMAINING_VISIBLE = 26;
constexpr uint16_t ICON_REMAINING_HIDDEN = 27;
constexpr uint16_t VP_Z_OFFSET = 0x1026;
// // SDCard File Listing
constexpr uint16_t VP_SD_ScrollEvent = 0x20D4; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
constexpr uint16_t VP_SD_FileSelected = 0x2200; // Number of file field selected.
constexpr uint16_t VP_SD_FileName_LEN = 21; // LEN is shared for all entries.
constexpr uint16_t VP_SD_FileName_CNT = 5; // LEN is shared for all entries.
constexpr uint16_t DGUS_SD_FILESPERSCREEN = VP_SD_FileName_CNT; // FIXME move that info to the display and read it from there.
constexpr uint16_t VP_SD_FileName0 = 0x20D5;
constexpr uint16_t VP_SD_FileName1 = VP_SD_FileName0 + VP_SD_FileName_LEN;
constexpr uint16_t VP_SD_FileName2 = VP_SD_FileName1 + VP_SD_FileName_LEN;
constexpr uint16_t VP_SD_FileName3 = VP_SD_FileName2 + VP_SD_FileName_LEN;
constexpr uint16_t VP_SD_FileName4 = VP_SD_FileName3 + VP_SD_FileName_LEN;
constexpr uint16_t VP_SD_FileName5 = VP_SD_FileName4 + VP_SD_FileName_LEN;
constexpr uint16_t VP_SD_Print_ProbeOffsetZ = 0x32A0; //
constexpr uint16_t VP_SD_Print_Filename = 0x2000; //
constexpr uint16_t VP_ICON_OVERLAY_CLEAR = 10;
constexpr uint16_t VP_ICON_OVERLAY_SELECTED = 6;
// // Step per mm
constexpr uint16_t VP_X_STEP_PER_MM = 0x3600;
constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604;
constexpr uint16_t VP_Z_STEP_PER_MM = 0x3608;
constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610;
// // PIDs
constexpr uint16_t VP_E0_PID_P = 0x3700;
constexpr uint16_t VP_E0_PID_I = 0x3702;
constexpr uint16_t VP_E0_PID_D = 0x3704;
constexpr uint16_t VP_BED_PID_P = 0x3710;
constexpr uint16_t VP_BED_PID_I = 0x3712;
constexpr uint16_t VP_BED_PID_D = 0x3714;
// Power loss recovery
constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x105F;
// Buttons defined by Creality - Don't worry if you're confused by the naming, so am I
constexpr uint16_t VP_BUTTON_MAINENTERKEY = 0x1002;
constexpr uint16_t VP_BUTTON_ADJUSTENTERKEY = 0x1004;
constexpr uint16_t VP_BUTTON_PAUSEPRINTKEY = 0x100A;
constexpr uint16_t VP_BUTTON_TEMPCONTROL = 0x1030;
constexpr uint16_t VP_BUTTON_COOLDOWN = 0x1032;
constexpr uint16_t VP_BUTTON_PREPAREENTERKEY = 0x103E;
constexpr uint16_t VP_BUTTON_SELECTFILEKEY = 0x20D3;
constexpr uint16_t VP_BUTTON_STARTPRINTKEY = 0x20D2;
constexpr uint16_t VP_BUTTON_STOPPRINTKEY = 0x1008;
constexpr uint16_t VP_BUTTON_RESUMEPRINTKEY = 0x100C;
constexpr uint16_t VP_BUTTON_BEDLEVELKEY = 0x1044;
constexpr uint16_t VP_BUTTON_HEATLOADSTARTKEY = 0x1056;
// Additional stuff defined by Creality
constexpr uint16_t VP_FAN_TOGGLE = 0x101E;
constexpr uint16_t VP_LED_TOGGLE = 0x101F;
// Axis settings
constexpr uint16_t VP_AXIS_SETTINGS_NAV_BUTTON = 0x22D9;
constexpr uint16_t AXIS_SETTINGS_NAV_BUTTON_VAL_X = 1;
constexpr uint16_t AXIS_SETTINGS_NAV_BUTTON_VAL_Y = 2;
constexpr uint16_t AXIS_SETTINGS_NAV_BUTTON_VAL_Z = 3;
constexpr uint16_t AXIS_SETTINGS_NAV_BUTTON_VAL_E = 4;
constexpr uint16_t VP_AXIS_SETTINGS_TITLE_ICON = 0x22DB;
constexpr uint16_t ICON_AXIS_SETTINGS_TITLE_X = 20;
constexpr uint16_t ICON_AXIS_SETTINGS_TITLE_Y = 21;
constexpr uint16_t ICON_AXIS_SETTINGS_TITLE_Z = 22;
constexpr uint16_t ICON_AXIS_SETTINGS_TITLE_E = 23;
constexpr uint16_t VP_AXIS_SETTINGS_NAV_BACKBUTTON = 0x22DD;
constexpr uint16_t VP_AXIS_SETTINGS_AXIS_STEPSMM = 0x22DF; // 2-byte
constexpr uint16_t VP_AXIS_SETTINGS_AXIS_MAX_ACCEL = 0x22E1; // 4-byte (!)
constexpr uint16_t VP_AXIS_SETTINGS_AXIS_JERK = 0x22E5; // 2-byte
constexpr uint16_t VP_AXIS_SETTINGS_AXIS_FEEDRATE = 0x22E7; // 2-byte
constexpr uint16_t VP_AXIS_SETTINGS_AXIS_TMCCURRENT = 0x22E9; // 2-byte
constexpr uint16_t VP_AXIS_SETTINGS_AXIS_TMCSTEALTHCHOP_BUTTON = 0x22EB; // 2-byte
constexpr uint16_t VP_AXIS_SETTINGS_AXIS_TMCSTEALTHCHOP_ICON = 0x22ED; // 2-byte
constexpr uint16_t VP_AXIS_SETTINGS_AXIS_TMCHYBRIDTHRESHOLD = 0x22EF; // 4-byte (!)
constexpr uint16_t VP_AXIS_TUNING_NAV_BUTTON = 0x22F5;
constexpr uint16_t VP_AXIS_TMC_NAV_BUTTON = 0x22F7;
constexpr uint16_t VP_AXIS_TMC_NAV_ICON = 0x22F3; // 2-byte
constexpr uint16_t AXIS_TMC_NAV_ICON_SHOWING = 10;
constexpr uint16_t AXIS_TMC_NAV_ICON_HIDING = 11;
// ... Advanced movement settings
constexpr uint16_t VP_MOV_NAV_BUTTON = 0x2305;
constexpr uint16_t VP_MOV_MINIMUM_SEGMENT_TIME = 0x22F9; // uint 2-byte
constexpr uint16_t VP_MOV_MINIMUM_FEEDRATE = 0x22FB; // float 2-byte
constexpr uint16_t VP_MOV_NORMAL_ACCELERATION = 0x22FD; // float 2-byte
constexpr uint16_t VP_MOV_MINIMUM_TRAVEL_FEEDRATE = 0x2301; // float 2-byte
constexpr uint16_t VP_MOV_MINIMUM_TRAVEL_ACCELERATION = 0x2303; // float 2-byte
constexpr uint16_t VP_MOV_RETRACT_ACCELERATION = 0x2307; // float 4-byte
// Misc settings
constexpr uint16_t VP_MISCSETTINGS_NAV_BUTTON = 0x2311;
constexpr uint16_t VP_FILAMENTRUNOUT_SENSOR_TOGGLE_BUTTON = 0x2309;
constexpr uint16_t VP_FILAMENTRUNOUT_SENSOR_TOGGLE_ICON = 0x230b;
constexpr uint16_t VP_PLR_TOGGLE_BUTTON = 0x230d;
constexpr uint16_t VP_PLR_TOGGLE_ICON = 0x230F;
// Mesh leveling
constexpr uint16_t VP_LEVELING_NAV_BUTTON = 0x238a;
constexpr uint16_t VP_LEVELING_EDIT_NAV_BUTTON = 0x23A8;
constexpr uint16_t VP_MESH_SCREEN_MESSAGE_ICON = 0x22cb;
constexpr uint16_t MESH_SCREEN_MESSAGE_ICON_LEVELING = 5;
constexpr uint16_t MESH_SCREEN_MESSAGE_ICON_VIEWING = 6;
constexpr uint16_t VP_MESH_LEVEL_TEMP = 0x108A;
constexpr uint16_t VP_MESH_LEVEL_STATUS = 0x108D;
constexpr uint8_t DGUS_GRID_VISUALIZATION_START_ID = GRID_MAX_POINTS > (4*4) ? 30 : 1;
static_assert(
(GRID_MAX_POINTS == 16 && DGUS_GRID_VISUALIZATION_START_ID == 1)|| // CR-6 SE
(GRID_MAX_POINTS == 49 && DGUS_GRID_VISUALIZATION_START_ID == 30) || // CR-6 MAX
(GRID_MAX_POINTS != 16 && GRID_MAX_POINTS != 49), // Custom Leveling
"Incorrect offset selected for leveling config"
);
static_assert(GRID_MAX_POINTS_X == GRID_MAX_POINTS_Y, "Assuming bed leveling points is square");
constexpr uint16_t VP_MESH_LEVEL_X0_Y0 = 0x1350;
constexpr uint16_t SP_MESH_LEVEL_X0_Y0 = 0x5000;
constexpr uint16_t MESH_LEVEL_EDGE_MAX_POINTS = 4;
constexpr uint16_t MESH_LEVEL_VP_SIZE = 0x4; // 4-byte native float
constexpr uint16_t MESH_LEVEL_SP_SIZE = 0x10; // 0x10 distance
constexpr uint16_t MESH_LEVEL_VP_EDGE_SIZE = MESH_LEVEL_VP_SIZE * MESH_LEVEL_EDGE_MAX_POINTS;
constexpr uint16_t MESH_LEVEL_SP_EDGE_SIZE = MESH_LEVEL_SP_SIZE * MESH_LEVEL_EDGE_MAX_POINTS;
constexpr uint16_t MESH_LEVEL_MAX_POINTS = MESH_LEVEL_EDGE_MAX_POINTS * MESH_LEVEL_EDGE_MAX_POINTS;
// Mesh inputs
constexpr uint16_t VP_MESH_INPUT_X0_Y0 = 0x2360;
#define MESH_INPUT_SUPPORTED_X_SIZE 4
#define MESH_INPUT_SUPPORTED_Y_SIZE 4
#define MESH_INPUT_SUPPORTED_SIZE 16
#define MESH_INPUT_DATA_SIZE 2 // 2 byte integer
// Color table: https://stackoverflow.com/q/13720937/646215
// Color picker: https://ee-programming-notepad.blogspot.com/2016/10/16-bit-color-generator-picker.html
// Colors below were picked on bed leveling visualizer defaults
constexpr uint16_t MESH_COLOR_BELOW_ZERO = 0x899B; // Blue
constexpr uint16_t MESH_COLOR_NEAR_ZERO = 0x1C80; // Green
constexpr uint16_t MESH_COLOR_ABOVE_ZERO = 0xB800; // Purple
constexpr uint16_t MESH_COLOR_NOT_MEASURED = 0xFFFF; // White (becomes invisible on white background)
constexpr float MESH_NEAR_ZERO = 0.020;
constexpr float MESH_UNSET_EPSILON = 0.001;
// Mesh validation pattern
constexpr uint16_t VP_MESHPATTERN_NOZZLE_TEMP = 0x2313;
constexpr uint16_t VP_MESHPATTERN_BED_TEMP = 0x2315;
constexpr uint16_t VP_MESHPATTERN_START_BUTTON = 0x2317;
constexpr uint16_t VP_MESHPATTERN_BUTTON_ICON = 0x2319;
constexpr uint16_t VP_MESHPATTERN_NAV_BUTTON = 0x231B;
constexpr uint16_t MESHPATTERN_BUTTON_START = 24; // This icon does not exist, and will therefore not show
constexpr uint16_t MESHPATTERN_BUTTON_CANCEL = 25;
// Movement screen
constexpr uint16_t VP_X_POSITION = 0x1048;
constexpr uint16_t SP_X_POSITION = 0x4000;
constexpr uint16_t VP_Y_POSITION = 0x104A;
constexpr uint16_t SP_Y_POSITION = 0x4030;
constexpr uint16_t VP_Z_POSITION = 0x104C;
constexpr uint16_t VP_Z_POSITION_PRECISION = 0x108F;
constexpr uint16_t SP_Z_POSITION = 0x4060;
constexpr uint16_t VP_BUTTON_MOVEKEY = 0x1046;
// Buttons
constexpr uint16_t VP_ESTEP_NAV_BUTTON = 0x2291;
constexpr uint16_t VP_PIDTUNE_NAV_BUTTON = 0x2293;
constexpr uint16_t VP_GENERIC_BACK_BUTTON = 0x2295; // Generic button for popping back to the old display
constexpr uint16_t GENERIC_BACK_BUTTON_NEED_SAVE = 0x1;
// PID tuning
constexpr uint16_t VP_PIDTUNE_TARGET_TEMP = 0x2297;
constexpr uint16_t VP_PIDTUNE_CYCLES = 0x2299;
constexpr uint16_t VP_PIDTUNE_FAN_TOGGLE = 0x238C;
constexpr uint16_t VP_PIDTUNE_FAN_TOGGLE_ICON = 0x238E;
constexpr uint16_t VP_PIDTUNE_START_BUTTON = 0x229B;
// FWRetract
constexpr uint16_t VP_FWRETRACT_NAV_BUTTON = 0x22AD;
constexpr uint16_t VP_FWRETRACT_RETRACT_LENGTH = 0x22B1;
constexpr uint16_t VP_FWRETRACT_RETRACT_FEEDRATE = 0x22B3;
constexpr uint16_t VP_FWRETRACT_RETRACT_ZHOP = 0x22B5;
constexpr uint16_t VP_FWRETRACT_RESTART_LENGTH = 0x22B7;
constexpr uint16_t VP_FWRETRACT_RESTART_FEEDRATE = 0x22B9;
constexpr uint16_t VP_FWRETRACT_TOGGLE_BUTTON = 0x22BB;
constexpr uint16_t VP_FWRETRACT_TOGGLE_BUTTON_ICON = 0x22BD;
constexpr uint16_t VP_FWRETRACT_INDICATOR_ICON = 0x22BF;
// Other tuning
constexpr uint16_t VP_LINEAR_ADVANCE_FACTOR = 0x22AF;
constexpr uint16_t VP_OTHER_TUNE_NAV_BUTTON = 0x2382;
// Leveling settings
constexpr uint16_t VP_TOGGLE_PROBING_HEATERS_OFF_ONOFF_BUTTON = 0x22C1;
constexpr uint16_t VP_TOGGLE_PROBING_HEATERS_OFF_ONOFF_ICON = 0x22C3;
constexpr uint16_t VP_TOGGLE_PROBE_PREHEAT_HOTEND_TEMP = 0x22C5;
constexpr uint16_t VP_TOGGLE_PROBE_PREHEAT_BED_TEMP = 0x22C7;
constexpr uint16_t VP_TOGGLE_PROBE_SETTINGS_NAV_BUTTON = 0x22C9;
constexpr uint16_t VP_TOGGLE_POST_PROBING_TEMPERATURE_STABILIZATION_ICON = 0x22CD;
constexpr uint16_t VP_TOGGLE_POST_PROBING_TEMPERATURE_STABILIZATION_BUTTON = 0x22CF;
constexpr uint16_t VP_LEVELING_FADE_HEIGHT = 0x231D;
// E-steps calibration
constexpr uint16_t VP_ESTEPS_CURRENT = 0x229d;
constexpr uint16_t VP_ESTEPS_CALIBRATION_TEMP = 0x229f;
constexpr uint16_t VP_ESTEPS_CALIBRATION_LENGTH = 0x22a1;
constexpr uint16_t VP_ESTEPS_CALIBRATION_MARK_LENGTH = 0x22ab;
constexpr uint16_t VP_ESTEPS_CALIBRATION_LEFTOVER_LENGTH = 0x22a3;
constexpr uint16_t VP_ESTEPS_CALCULATED_ESTEPS = 0x22a5;
constexpr uint16_t VP_ESTEPS_CALIBRATESTART_BUTTON = 0x22a7;
constexpr uint16_t VP_ESTEPS_APPLY_BUTTON = 0x22a9;
constexpr uint16_t VP_ESTEPS_BACK_BUTTON = 0x22D7;
// RGB
constexpr uint16_t VP_RGB_NAV_BUTTON = 0x2390;
constexpr uint16_t VP_RGB_CONTROL_R = 0x2392;
constexpr uint16_t VP_RGB_CONTROL_G = 0x2394;
constexpr uint16_t VP_RGB_CONTROL_B = 0x2396;
constexpr uint16_t VP_RGB_CONTROL_W = 0x2398;
constexpr uint16_t VP_RGB_CONTROL_I = 0x239A; // brightness
constexpr uint16_t VP_RGB_NAV_BUTTON_ICON = 0x239E;
constexpr uint16_t ICON_RGB_SETTINGS_AVAILABLE = 28;
constexpr uint16_t ICON_RGB_SETTINGS_UNAVAILABLE = 29;
// Filament load/unload
constexpr uint16_t VP_FILCHANGE_NAV_BUTTON = 0x23a6;
constexpr uint16_t VP_FILCHANGE_NOZZLE_TEMP = 0x23a0;
constexpr uint16_t VP_FILCHANGE_LENGTH = 0x23a2;
constexpr uint16_t VP_FILCHANGE_ACTION_BUTTON = 0x23a4;
constexpr uint16_t FILCHANGE_ACTION_UNLOAD_BUTTON = 1;
constexpr uint16_t FILCHANGE_ACTION_LOAD_BUTTON = 2;
// Icons
constexpr uint16_t ICON_TOGGLE_ON = 1;
constexpr uint16_t ICON_TOGGLE_OFF = 2;
constexpr uint16_t ICON_BACK_BUTTON_ENABLED = 7;
constexpr uint16_t ICON_BACK_BUTTON_DISABLED = 8;
constexpr uint16_t ICON_THROBBER_ANIM_OFF = 0;
constexpr uint16_t ICON_THROBBER_ANIM_ON = 1;
// Allow to visually disable/enable the back button
constexpr uint16_t VP_BACK_BUTTON_STATE = 0x22D1;
// Throbber animation
constexpr uint16_t VP_BUSY_ANIM_STATE = 0x22D3;
// Toggles
constexpr uint16_t ICON_FAN_TOGGLE_ON = 1;
constexpr uint16_t ICON_FAN_TOGGLE_OFF = 2;
constexpr uint16_t ICON_LED_TOGGLE_ON = 3;
constexpr uint16_t ICON_LED_TOGGLE_OFF = 4;
constexpr uint16_t ICON_SOUND_TOGGLE_ON = 5;
constexpr uint16_t ICON_SOUND_TOGGLE_OFF = 6;
constexpr uint16_t ICON_FWRETRACT_AUTO_TOGGLE_ON = 9;
constexpr uint16_t ICON_FWRETRACT_AUTO_TOGGLE_OFF = 10;
constexpr uint16_t ICON_ACCURACY_TOGGLE_ON = 11;
constexpr uint16_t ICON_ACCURACY_TOGGLE_OFF = 12;
constexpr uint16_t ICON_POST_PROBE_TEMP_STABILIZATION_TOGGLE_ON = 13;
constexpr uint16_t ICON_POST_PROBE_TEMP_STABILIZATION_TOGGLE_OFF = 14;
constexpr uint16_t ICON_FWRETRACT_AUTO_DISENGAGED = 4; // This icon deliberately does not exist
constexpr uint16_t ICON_FWRETRACT_AUTO_ENGAGED = 3;
// Development helper
constexpr uint16_t VP_DEVELOPMENT_HELPER_BUTTON = 0x22D5;
constexpr uint16_t VP_DEVELOPMENT_HELPER_BUTTON_ACTION_FIRMWARE_UPDATE = 2;
constexpr uint16_t VP_DEVELOPMENT_HELPER_BUTTON_ACTION_TO_MAIN_MENU = 4;
constexpr uint16_t VP_DEVELOPMENT_HELPER_BUTTON_ACTION_RESET_DISPLAY = 8;
@@ -0,0 +1,188 @@
#include "../../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "../DGUSDisplayDef.h"
#include "../DGUSDisplay.h"
#include "../DGUSScreenHandler.h"
#include "EstepsHandler.h"
#include "../../ui_api.h"
#include "../../../marlinui.h"
#include "../../../../module/temperature.h"
#include "../../../../module/settings.h"
#include "../../../../module/planner.h"
#include "../../../../gcode/gcode.h"
// Storage init
float EstepsHandler::set_esteps = 0;
float EstepsHandler::calculated_esteps = 0;
float EstepsHandler::remaining_filament = 0;
float EstepsHandler::mark_filament_mm = 0;
float EstepsHandler::filament_to_extrude = 0;
celsius_t EstepsHandler::calibration_temperature = 0;
void EstepsHandler::Init() {
// Use steps
set_esteps = ExtUI::getAxisSteps_per_mm(ExtUI::E0);
calculated_esteps = 0;
// Reset
filament_to_extrude = 100;
mark_filament_mm = 120;
remaining_filament = 0;
// Use configured PLA temps + 10 degrees
calibration_temperature = ui.material_preset[0].hotend_temp + 10;
// Welcome message
SetStatusMessage(PSTR("Ready"));
}
void EstepsHandler::HandleStartButton(DGUS_VP_Variable &var, void *val_ptr) {
//static_assert(ADVANCED_PAUSE_PURGE_LENGTH == 0, "Assuming PURGE_LENGTH is 0 so we can use M701");
// Validate
if (calibration_temperature < EXTRUDE_MINTEMP) {
SetStatusMessage(PSTR("Invalid temperature set"));
return;
}
if (filament_to_extrude < 10) {
SetStatusMessage(PSTR("Invalid extrusion length set"));
return;
}
if (mark_filament_mm < filament_to_extrude) {
SetStatusMessage(PSTR("Invalid mark length set"));
return;
}
// Synchronous operation - disable back button
DGUSSynchronousOperation syncOperation;
syncOperation.start();
// Prepare
bool zAxisWasRelative = GcodeSuite::axis_is_relative(Z_AXIS);
bool eAxisWasRelative = GcodeSuite::axis_is_relative(E_AXIS);
#if ENABLED(LIN_ADVANCE)
float kFactor = planner.extruder_advance_K[0];
#endif
GcodeSuite::set_e_relative();
GcodeSuite::set_relative_mode(true);
#if ENABLED(LIN_ADVANCE)
planner.extruder_advance_K[0] = 0;
#endif
ExtUI::injectCommands_P("G0 Z5 F150");
queue.advance();
// Heat up if necessary
if (abs(ExtUI::getActualTemp_celsius(ExtUI::E0) - calibration_temperature) > 2) {
thermalManager.setTargetHotend(calibration_temperature, ExtUI::H0);
SetStatusMessage(PSTR("Heating up..."));
thermalManager.wait_for_hotend(ExtUI::H0, false);
}
planner.synchronize();
// Set-up command
SetStatusMessage(PSTR("Extruding..."));
char cmd[64];
sprintf_P(cmd, PSTR("G1 E%f F50"), filament_to_extrude);
ExtUI::injectCommands(cmd);
queue.advance();
planner.synchronize();
// Restore position
ExtUI::injectCommands_P("G0 Z-5 F150");
queue.advance();
planner.synchronize();
// Restore defaults
if (!zAxisWasRelative) GcodeSuite::set_relative_mode(false);
if (!eAxisWasRelative) GcodeSuite::set_e_absolute();
#if ENABLED(LIN_ADVANCE)
planner.extruder_advance_K[0] = kFactor;
#endif
// Done
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_ESTEPS_CALIBRATION_RESULTS, false);
ScreenHandler.Buzzer(0, 250);
syncOperation.done();
SetStatusMessage(PSTR("Measure remaining filament"));
}
void EstepsHandler::HandleApplyButton(DGUS_VP_Variable &var, void *val_ptr) {
if (abs(calculated_esteps) < 1) {
// User intented to set e-steps directly
ExtUI::setAxisSteps_per_mm(set_esteps, ExtUI::E0);
} else {
ExtUI::setAxisSteps_per_mm(calculated_esteps, ExtUI::E0);
}
SaveSettingsAndReturn(true);
}
void EstepsHandler::HandleBackButton(DGUS_VP_Variable &var, void *val_ptr) {
// User intented to set e-steps directly
ExtUI::setAxisSteps_per_mm(set_esteps, ExtUI::E0);
SaveSettingsAndReturn(false);
}
void EstepsHandler::SaveSettingsAndReturn(bool fullConfirm) {
// Save & reset
settings.save();
if (fullConfirm) ScreenHandler.Buzzer(0, 250);
ScreenHandler.PopToOldScreen();
if (fullConfirm) ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN, false);
SetStatusMessage(PSTR("New e-steps value saved"));
}
void EstepsHandler::HandleRemainingFilament(DGUS_VP_Variable &var, void *val_ptr) {
ScreenHandler.DGUSLCD_SetFloatAsIntFromDisplay<1>(var, val_ptr);
// Calculate
constexpr float precision = 0.01;
float actualExtrusion = mark_filament_mm - remaining_filament;
if (actualExtrusion < (-precision)) {
SetStatusMessage(PSTR("Mark filament further"));
return;
}
if (actualExtrusion < precision) {
SetStatusMessage(PSTR("E-steps are correct"));
calculated_esteps = set_esteps;
return;
}
float current_steps = ExtUI::getAxisSteps_per_mm(ExtUI::E0);
SERIAL_ECHOLNPAIR("Current steps: ", current_steps);
SERIAL_ECHOLNPAIR("Actual extrusion: ", actualExtrusion);
float new_steps = (current_steps * filament_to_extrude) / actualExtrusion;
SERIAL_ECHOLNPAIR("New steps: ", new_steps);
calculated_esteps = new_steps;
// Status update
SetStatusMessage(PSTR("Calculated new e-steps"));
}
void EstepsHandler::SetStatusMessage(PGM_P statusMessage) {
ScreenHandler.setstatusmessagePGM(statusMessage);
}
#endif
@@ -0,0 +1,29 @@
#pragma once
#include <cstdint>
class EstepsHandler {
public:
static void Init();
static void HandleStartButton(DGUS_VP_Variable &var, void *val_ptr);
static void HandleApplyButton(DGUS_VP_Variable &var, void *val_ptr);
static void HandleBackButton(DGUS_VP_Variable &var, void *val_ptr);
static void HandleRemainingFilament(DGUS_VP_Variable &var, void *val_ptr);
public:
static float set_esteps;
static float calculated_esteps;
static float mark_filament_mm;
static float remaining_filament;
static float filament_to_extrude;
static celsius_t calibration_temperature;
private:
static void SaveSettingsAndReturn(bool fullConfirm);
static void SetStatusMessage(PGM_P statusMessage);
};
@@ -0,0 +1,106 @@
#include "../../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "../DGUSDisplayDef.h"
#include "../DGUSDisplay.h"
#include "../DGUSScreenHandler.h"
#include "FilamentLoadUnloadHandler.h"
#include "../../ui_api.h"
#include "../../../marlinui.h"
#include "../../../../module/temperature.h"
#include "../../../../module/settings.h"
#include "../../../../module/planner.h"
#include "../../../../gcode/gcode.h"
celsius_t FilamentLoadUnloadHandler::nozzle_temperature = 0;
float FilamentLoadUnloadHandler::length = 0;
void FilamentLoadUnloadHandler::Init() {
nozzle_temperature = ui.material_preset[0].hotend_temp;
length = 150;
if (ExtUI::isPrinting()) {
nozzle_temperature = ExtUI::getTargetTemp_celsius(ExtUI::extruder_t::E0);
}
}
void FilamentLoadUnloadHandler::HandleTemperature(DGUS_VP_Variable &var, void *val_ptr) {
ScreenHandler.DGUSLCD_SetValueDirectly<uint16_t>(var, val_ptr);
ValidateTemperatures();
}
void FilamentLoadUnloadHandler::HandleLoadUnloadButton(DGUS_VP_Variable &var, void *val_ptr) {
// Common for load/unload -> determine minimum temperature
if (length < 0.1) {
SetStatusMessage("Invalid feed length");
return;
}
if (ExtUI::isPrinting() && !ExtUI::isPrintingPaused()) {
SetStatusMessage(PSTR("Please pause print first"));
return;
}
DGUSSynchronousOperation syncOperation;
uint16_t button_value = uInt16Value(val_ptr);
switch (button_value) {
case FILCHANGE_ACTION_LOAD_BUTTON:
syncOperation.start();
ChangeFilamentWithTemperature(PSTR("M701 L%f P0"));
syncOperation.done();
break;
case FILCHANGE_ACTION_UNLOAD_BUTTON:
syncOperation.start();
ChangeFilamentWithTemperature(PSTR("M702 U%f"));
syncOperation.done();
break;
}
}
void FilamentLoadUnloadHandler::ValidateTemperatures() {
LIMIT(nozzle_temperature, EXTRUDE_MINTEMP, HEATER_0_MAXTEMP - HOTEND_OVERSHOOT);
}
void FilamentLoadUnloadHandler::ChangeFilamentWithTemperature(PGM_P command) {
// Heat if necessary
if (ExtUI::getActualTemp_celsius(ExtUI::E0) < nozzle_temperature && abs(ExtUI::getActualTemp_celsius(ExtUI::E0) - nozzle_temperature) > THERMAL_PROTECTION_HYSTERESIS) {
SetStatusMessage(PSTR("Heating up..."));
uint16_t target_celsius = nozzle_temperature;
NOMORE(target_celsius, thermalManager.hotend_max_target(0));
thermalManager.setTargetHotend(target_celsius, ExtUI::H0);
thermalManager.wait_for_hotend(ExtUI::H0, false);
}
// Inject load filament command
SetStatusMessage(PSTR("Filament load/unload..."));
char cmd[64];
sprintf_P(cmd, command, length);
// Handle commands
SERIAL_ECHOPAIR("Injecting command: ", cmd);
GcodeSuite::process_subcommands_now(cmd);
SERIAL_ECHOPGM_P("- done");
if (ScreenHandler.Settings.display_sound) ScreenHandler.Buzzer(500, 100);
SetStatusMessage(PSTR("Filament load/unload complete"));
}
void FilamentLoadUnloadHandler::SetStatusMessage(PGM_P statusMessage) {
ScreenHandler.setstatusmessagePGM(statusMessage);
}
#endif
@@ -0,0 +1,22 @@
#pragma once
#include <cstdint>
class FilamentLoadUnloadHandler {
public:
static void Init();
static void HandleTemperature(DGUS_VP_Variable &var, void *val_ptr);
static void HandleLoadUnloadButton(DGUS_VP_Variable &var, void *val_ptr);
public:
static celsius_t nozzle_temperature;
static float length;
private:
static void ValidateTemperatures();
static void ChangeFilamentWithTemperature(PGM_P command);
static void SetStatusMessage(PGM_P statusMessage);
};
@@ -0,0 +1,150 @@
#include "../../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "../DGUSDisplayDef.h"
#include "../DGUSDisplay.h"
#include "../DGUSScreenHandler.h"
#include "MeshValidationHandler.h"
#include "../../ui_api.h"
#include "../../../marlinui.h"
#include "../../../../module/temperature.h"
#include "../../../../module/settings.h"
#include "../../../../module/planner.h"
#include "../../../../gcode/gcode.h"
celsius_t MeshValidationHandler::nozzle_temperature;
celsius_t MeshValidationHandler::bed_temperature;
bool MeshValidationHandler::is_running;
bool MeshValidationHandler::started_from_screen;
bool MeshValidationHandler::is_cancelling;
feedRate_t MeshValidationHandler::prev_feedrate;
void MeshValidationHandler::Init() {
// Set to PLA pre-heat temps by default
nozzle_temperature = ui.material_preset[0].hotend_temp;
bed_temperature = ui.material_preset[0].bed_temp;
ValidateTemperatures();
}
void MeshValidationHandler::HandleTemperature(DGUS_VP_Variable &var, void *val_ptr) {
ScreenHandler.DGUSLCD_SetValueDirectly<uint16_t>(var, val_ptr);
ValidateTemperatures();
}
void MeshValidationHandler::HandleStartOrCancelButton(DGUS_VP_Variable &var, void *val_ptr) {
if (!is_running) {
Start();
} else {
Cancel();
}
}
void MeshValidationHandler::Start() {
if (is_running) return;
// Validate
if (!ExtUI::getMeshValid()) {
SetStatusMessage("Please level bed first");
return;
}
// Block
ScreenHandler.SetSynchronousOperationStart();
is_running = true;
started_from_screen = true;
// Home if necessary - do this synchronously
if (!all_axes_trusted()) {
queue.inject_P("G28 U0");
queue.advance();
}
// Home X and Y so we droop at the side of the bed.
// G26 with temperature and set for full bed, full pattern, retract 4mm, prime 5mm
char gcodeBuffer[128] = {0};
sprintf_P(gcodeBuffer, PSTR("G90\nG0 X0\nG26 B%d H%d R Q4 P2 X0 Y0"), bed_temperature, nozzle_temperature);
queue.inject(gcodeBuffer);
queue.advance();
// Set feedrate
prev_feedrate = ExtUI::getFeedrate_mm_s();
ExtUI::setFeedrate_mm_s(MESH_VALIDATION_PATTERN_FEEDRATE);
SetStatusMessage("Starting...");
}
void MeshValidationHandler::Cancel() {
if (is_cancelling) return;
is_cancelling = true;
ExtUI::ui_setUICancelOperation(true);
SetStatusMessage("Cancelling...");
}
void MeshValidationHandler::OnMeshValidationStart() {
// Note: can also be called when manually invoking G26
if (ScreenHandler.getCurrentScreen() != DGUSLCD_SCREEN_MESH_VALIDATION) {
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MESH_VALIDATION);
}
// Set state
ScreenHandler.SetSynchronousOperationStart();
is_running = true;
}
void MeshValidationHandler::OnMeshValidationFinish() {
// If invoked externally, pop back
if (!started_from_screen) {
ScreenHandler.PopToOldScreen();
}
if (started_from_screen) {
ExtUI::setFeedrate_mm_s(prev_feedrate);
char gcodeBuffer[128] = {0};
if (!is_cancelling) {
// Present
// - Set absolute mode
// - Present bed, high Z
// - Disable stepper
strcpy_P(gcodeBuffer, PSTR("M84"));
SetStatusMessage("Mesh validation pattern printed");
} else {
// Park and disable steppers
strcpy_P(gcodeBuffer, PSTR("G0 X5 F2000\nG27\nM84"));
SetStatusMessage("Canceled mesh validation pattern");
}
// Enqueue
gcode.process_subcommands_now(gcodeBuffer);
}
// Reset state
is_running = false;
started_from_screen = false;
is_cancelling = false;
ScreenHandler.SetSynchronousOperationFinish();
ExtUI::ui_setUICancelOperation(false);
}
void MeshValidationHandler::ValidateTemperatures() {
LIMIT(nozzle_temperature, EXTRUDE_MINTEMP, HEATER_0_MAXTEMP - HOTEND_OVERSHOOT);
LIMIT(bed_temperature, 40 /*Hardcoded minimum for G26, apparently*/, BED_MAXTEMP - BED_OVERSHOOT);
}
void MeshValidationHandler::SetStatusMessage(PGM_P statusMessage) {
ScreenHandler.setstatusmessagePGM(statusMessage);
}
#endif
@@ -0,0 +1,32 @@
#include <cstdint>
class MeshValidationHandler {
public:
static void Init();
static void HandleTemperature(DGUS_VP_Variable &var, void *val_ptr);
static void HandleStartOrCancelButton(DGUS_VP_Variable &var, void *val_ptr);
static void OnMeshValidationStart();
static void OnMeshValidationFinish();
public:
static celsius_t nozzle_temperature;
static celsius_t bed_temperature;
static feedRate_t prev_feedrate;
static bool is_cancelling;
static bool is_running;
static bool started_from_screen;
private:
static void Start();
static void Cancel();
static void ValidateTemperatures();
static void SetStatusMessage(PGM_P statusMessage);
};
constexpr feedRate_t MESH_VALIDATION_PATTERN_FEEDRATE = G26_XY_FEEDRATE;
@@ -0,0 +1,91 @@
#include "../../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "../DGUSDisplayDef.h"
#include "../DGUSDisplay.h"
#include "../DGUSScreenHandler.h"
#include "PIDHandler.h"
#include "../../ui_api.h"
#include "../../../marlinui.h"
#include "../../../../module/temperature.h"
#include "../../../../module/settings.h"
#include "../../../../module/planner.h"
#include "../../../../gcode/gcode.h"
// Storage init
uint16_t PIDHandler::cycles = 0;
celsius_t PIDHandler::calibration_temperature = 0;
bool PIDHandler::fan_on = false;
PGM_P PIDHandler::result_message = nullptr;
void PIDHandler::Init() {
// Reset
cycles = 3;
fan_on = ExtUI::getTargetFan_percent(ExtUI::fan_t::FAN0) > 10;
// Use configured PLA temps + 10 degrees
calibration_temperature = ui.material_preset[0].hotend_temp + 15;
// Welcome message
SetStatusMessage(PSTR("Ready"));
}
void PIDHandler::HandleStartButton(DGUS_VP_Variable &var, void *val_ptr) {
//static_assert(ADVANCED_PAUSE_PURGE_LENGTH == 0, "Assuming PURGE_LENGTH is 0 so we can use M701");
// Validate
if (calibration_temperature < EXTRUDE_MINTEMP) {
SetStatusMessage(PSTR("Invalid temperature set"));
return;
}
if (calibration_temperature > HEATER_0_MAXTEMP) {
SetStatusMessage(PSTR("Invalid temperature set"));
return;
}
if (cycles < 1) {
SetStatusMessage(PSTR("Invalid number of cycles"));
return;
}
// Synchronous operation - disable back button
DGUSSynchronousOperation syncOperation;
syncOperation.start();
// Fan
const auto prev_fan_percentage = ExtUI::getActualFan_percent(ExtUI::fan_t::FAN0);
const uint8_t fan_speed = fan_on ? 255 : 0;
// Set-up command
SetStatusMessage(PSTR("PID tuning. Please wait..."));
char cmd[64]; // Add a G4 to allow the fan speed to take effect
sprintf_P(cmd, PSTR("M106 S%d\nG4 S2\nM303 S%d C%d U1"), fan_speed, calibration_temperature, cycles);
SERIAL_ECHOLNPAIR("Executing: ", cmd);
ExtUI::injectCommands(cmd);
while (queue.has_commands_queued()) queue.advance();
// Done
ExtUI::setTargetFan_percent(prev_fan_percentage, ExtUI::fan_t::FAN0);
ScreenHandler.Buzzer(0, 250);
settings.save();
syncOperation.done();
SetStatusMessage(result_message);
}
void PIDHandler::SetStatusMessage(PGM_P statusMessage) {
ScreenHandler.setstatusmessagePGM(statusMessage);
}
#endif
@@ -0,0 +1,21 @@
#pragma once
#include <cstdint>
class PIDHandler {
public:
static void Init();
static void HandleStartButton(DGUS_VP_Variable &var, void *val_ptr);
public:
static uint16_t cycles;
static celsius_t calibration_temperature;
static bool fan_on;
static PGM_P result_message;
private:
static void SetStatusMessage(PGM_P statusMessage);
};
@@ -0,0 +1,443 @@
#include "../../../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "../DGUSDisplayDef.h"
#include "../DGUSDisplay.h"
#include "../DGUSScreenHandler.h"
#include "../../../../module/temperature.h"
#include "../../../../module/motion.h"
#include "../../../../module/planner.h"
#include "../../../../feature/pause.h"
#include "../../../../gcode/gcode.h"
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#include "../../../../feature/runout.h"
#endif
#include "../../../../module/settings.h"
#include "../../ui_api.h"
#include "../../../marlinui.h"
#include "PageHandlers.h"
// Definitions of page handlers
void MainMenuHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_MAINENTERKEY:
switch (buttonValue) {
case 1:
// Try to mount an unmounted card (BTT SKR board has especially some trouble sometimes)
card.mount();
ScreenHandler.SDCardInserted();
break;
case 2:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PREPARE);
break;
case 3:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_SETUP);
break;
case 4:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_CALIBRATE);
break;
}
break;
}
}
void SetupMenuHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_PREPAREENTERKEY:
switch(buttonValue) {
case 5: // About
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_INFO);
break;
case 7: // Reset to factory settings
settings.reset();
settings.save();
ExtUI::injectCommands_P(PSTR("M300"));
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN, false);
ScreenHandler.setstatusmessagePGM(PSTR("Restored default settings. Please turn your printer off and then on to complete the reset"));
break;
}
break;
case VP_BUTTON_TEMPCONTROL:
if (buttonValue == 2) ScreenHandler.GotoScreen(DGUSLCD_SCREEN_TEMP);
break;
case VP_BUTTON_ADJUSTENTERKEY:
ScreenHandler.HandleLEDToggle();
break;
}
}
void LevelingModeHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_BEDLEVELKEY:
switch (buttonValue) {
case 1:
queue.enqueue_one_P("G28 U0");
queue.enqueue_one_P("G0 Z0");
break;
case 2:
// Increase Z-offset
ExtUI::smartAdjustAxis_steps(ExtUI::mmToWholeSteps(0.01, ExtUI::axis_t::Z), ExtUI::axis_t::Z, true);;
ScreenHandler.ForceCompleteUpdate();
ScreenHandler.RequestSaveSettings();
break;
case 3:
// Decrease Z-offset
ExtUI::smartAdjustAxis_steps(ExtUI::mmToWholeSteps(-0.01, ExtUI::axis_t::Z), ExtUI::axis_t::Z, true);;
ScreenHandler.ForceCompleteUpdate();
ScreenHandler.RequestSaveSettings();
break;
}
break;
case VP_BUTTON_PREPAREENTERKEY:
if (buttonValue == 9) {
#if DISABLED(HOTEND_IDLE_TIMEOUT)
thermalManager.disable_all_heaters();
#endif
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN, false);
}
if (buttonValue == 1) {
// TODO: set state for "view leveling mesh"
ScreenHandler.SetViewMeshLevelState();
ScreenHandler.InitMeshValues();
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_LEVELING);
}
break;
case VP_BUTTON_MAINENTERKEY:
// Go to leveling screen
ExtUI::injectCommands_P("G28 U0\nG29 U0");
ScreenHandler.ResetMeshValues();
dgusdisplay.WriteVariable(VP_MESH_SCREEN_MESSAGE_ICON, static_cast<uint16_t>(MESH_SCREEN_MESSAGE_ICON_LEVELING));
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_LEVELING);
break;
}
}
void LevelingHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_BEDLEVELKEY:
const bool busy = TERN0(HOST_KEEPALIVE_FEATURE, ((ExtUI::getMachineState() == GcodeSuite::MarlinBusyState::IN_PROCESS) || (ExtUI::getMachineState() == GcodeSuite::MarlinBusyState::IN_HANDLER)));
if (!busy) {
ScreenHandler.PopToOldScreen();
} else {
ScreenHandler.setstatusmessagePGM("Wait for leveling completion...");
}
break;
}
}
void TempMenuHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_ADJUSTENTERKEY:
switch (buttonValue) {
case 3:
ScreenHandler.HandleFanToggle();
break;
}
break;
case VP_BUTTON_TEMPCONTROL:
switch (buttonValue){
case 3:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_TEMP_PLA);
break;
case 4:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_TEMP_ABS);
break;
}
break;
}
}
void PrepareMenuHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_PREPAREENTERKEY:
switch (buttonValue){
case 3:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MOVE10MM);
break;
case 6:
// Disable steppers
ScreenHandler.HandleMotorLockUnlock(var, &buttonValue);
break;
}
break;
case VP_BUTTON_HEATLOADSTARTKEY:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_FEED);
break;
case VP_BUTTON_COOLDOWN:
ScreenHandler.HandleAllHeatersOff(var, &buttonValue);
break;
case VP_BUTTON_TEMPCONTROL:
switch (buttonValue) {
case 5:
thermalManager.setTargetHotend(ui.material_preset[0].hotend_temp, 0);
thermalManager.setTargetBed(ui.material_preset[0].bed_temp);
break;
case 6:
thermalManager.setTargetHotend(ui.material_preset[1].hotend_temp, 0);
thermalManager.setTargetBed(ui.material_preset[1].bed_temp);
break;
}
break;
}
ScreenHandler.ForceCompleteUpdate();
}
void TuneMenuHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_ADJUSTENTERKEY:
switch (buttonValue) {
case 2:
ScreenHandler.GotoScreen(ExtUI::isPrintingPaused() ? DGUSLCD_SCREEN_PRINT_PAUSED : DGUSLCD_SCREEN_PRINT_RUNNING, false);
break;
case 3:
ScreenHandler.HandleFanToggle();
break;
case 4:
ScreenHandler.HandleLEDToggle();
break;
}
}
}
void PrintRunningMenuHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_ADJUSTENTERKEY:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_TUNING);
break;
case VP_BUTTON_PAUSEPRINTKEY:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_DIALOG_PAUSE);
break;
case VP_BUTTON_STOPPRINTKEY:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_DIALOG_STOP);
break;
}
}
void PrintPausedMenuHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP) {
case VP_BUTTON_RESUMEPRINTKEY:
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
runout.reset();
#endif
if (!ScreenHandler.HandlePendingUserConfirmation()) {
ExtUI::resumePrint();
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PRINT_RUNNING);
}
break;
case VP_BUTTON_ADJUSTENTERKEY:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_TUNING);
break;
case VP_BUTTON_STOPPRINTKEY:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_DIALOG_STOP);
break;
}
}
void PrintPauseDialogHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP){
case VP_BUTTON_PAUSEPRINTKEY:
switch (buttonValue) {
case 2:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PRINT_RUNNING);
ScreenHandler.setstatusmessagePGM(PSTR("Pausing print - please wait..."));
ExtUI::pausePrint();
break;
case 3:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PRINT_RUNNING);
break;
}
break;
}
}
void PrintFinishMenuHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP){
case VP_BUTTON_MAINENTERKEY:
switch (buttonValue) {
case 5:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN);
break;
}
break;
}
}
void FilamentRunoutHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP){
case VP_BUTTON_RESUMEPRINTKEY:
ExtUI::resumePrint();
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PRINT_RUNNING);
break;
case VP_BUTTON_STOPPRINTKEY:
ExtUI::stopPrint();
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN);
break;
}
}
void StopConfirmScreenHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP){
case VP_BUTTON_STOPPRINTKEY:
switch (buttonValue) {
case 2:
ExtUI::stopPrint();
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN);
break;
case 3:
ScreenHandler.GotoScreen(ExtUI::isPrintingPaused() ? DGUSLCD_SCREEN_PRINT_PAUSED : DGUSLCD_SCREEN_PRINT_RUNNING);
break;
}
break;
}
}
void PreheatSettingsScreenHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
switch (var.VP){
case VP_BUTTON_PREPAREENTERKEY:
// Save button, save settings and go back
ScreenHandler.RequestSaveSettings();
ScreenHandler.PopToOldScreen();
break;
case VP_BUTTON_COOLDOWN: // You can't make this up
// Back button, discard settings
settings.load();
ScreenHandler.PopToOldScreen();
break;
}
}
void MoveHandler(DGUS_VP_Variable &var, unsigned short buttonValue) {
if (var.VP == VP_BUTTON_MOVEKEY) {
switch (buttonValue) {
case 1:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MOVE10MM, false);
break;
case 2:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MOVE1MM, false);
break;
case 3:
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MOVE01MM, false);
break;
case 4:
// Temporary copy probe settings so we home without preheating, then restore setings afterward
//This machine should never home Z cold...
//auto prev_probe_settings = probe.settings;
//probe.settings.preheat_bed_temp = 0;
//probe.settings.preheat_hotend_temp = 0;
//probe.settings.stabilize_temperatures_after_probing = false;
ExtUI::injectCommands_P("G28");
while (queue.has_commands_queued()) queue.advance();
// ... Restore settings
//probe.settings = prev_probe_settings;
break;
}
}
}
// Register the page handlers
#define PAGE_HANDLER(SCRID, HDLRPTR) { .ScreenID=SCRID, .Handler=HDLRPTR },
const struct PageHandler PageHandlers[] PROGMEM = {
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_MAIN, MainMenuHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_SETUP, SetupMenuHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_ZOFFSET_LEVEL, LevelingModeHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_LEVELING, LevelingHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_TEMP, TempMenuHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_TEMP_PLA, PreheatSettingsScreenHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_TEMP_ABS, PreheatSettingsScreenHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_TUNING, TuneMenuHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_MOVE01MM, MoveHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_MOVE1MM, MoveHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_MOVE10MM, MoveHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_FILAMENTRUNOUT1, FilamentRunoutHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_FILAMENTRUNOUT2, FilamentRunoutHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_DIALOG_STOP, StopConfirmScreenHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_PRINT_RUNNING, PrintRunningMenuHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_PRINT_PAUSED, PrintPausedMenuHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_PRINT_FINISH, PrintFinishMenuHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_DIALOG_PAUSE, PrintPauseDialogHandler)
PAGE_HANDLER(DGUSLCD_Screens::DGUSLCD_SCREEN_PREPARE, PrepareMenuHandler)
// Terminating
PAGE_HANDLER(static_cast<DGUSLCD_Screens>(0) ,0)
};
void DGUSCrealityDisplay_HandleReturnKeyEvent(DGUS_VP_Variable &var, void *val_ptr) {
const struct PageHandler *map = PageHandlers;
const uint16_t *ret;
const DGUSLCD_Screens current_screen = DGUSScreenHandler::getCurrentScreen();
while ((ret = (uint16_t*) pgm_read_ptr(&(map->Handler)))) {
if ((map->ScreenID) == current_screen) {
uint16_t button_value = uInt16Value(val_ptr);
SERIAL_ECHOPAIR("Invoking handler for screen ", current_screen);
SERIAL_ECHOLNPAIR("with VP=", var.VP, " value=", button_value);
map->Handler(var, button_value);
return;
}
map++;
}
}
#endif
@@ -0,0 +1,11 @@
#pragma once
// Mapping of handlers per page. This construction is necessary because the CR-6 touch screen re-uses the same button IDs all over the place.
typedef void (*DGUS_CREALITY_SCREEN_BUTTON_HANDLER)(DGUS_VP_Variable &var, unsigned short buttonValue);
struct PageHandler {
DGUSLCD_Screens ScreenID;
DGUS_CREALITY_SCREEN_BUTTON_HANDLER Handler;
};
void DGUSCrealityDisplay_HandleReturnKeyEvent(DGUS_VP_Variable &var, void *val_ptr);
+255
View File
@@ -0,0 +1,255 @@
/**
* 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/>.
*
*/
/**
* dgus_creality_lcd.cpp
*
* DGUS implementation written by coldtobi in 2019 for Marlin
*/
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
#include "ui_api.h"
#include "../marlinui.h"
#include "./dgus_creality/DGUSDisplay.h"
#include "./dgus_creality/DGUSDisplayDef.h"
#include "./dgus_creality/DGUSScreenHandler.h"
#include "./dgus_creality/creality_touch/PIDHandler.h"
#include "./dgus_creality/creality_touch/MeshValidationHandler.h"
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../../feature/powerloss.h"
#endif
extern const char NUL_STR[];
namespace ExtUI {
void onStartup() {
ScreenHandler.Init();
ScreenHandler.UpdateScreenVPData();
}
void onIdle() { ScreenHandler.loop(); }
void onPrinterKilled(PGM_P const error, PGM_P const component) {
ScreenHandler.sendinfoscreen(GET_TEXT(MSG_HALTED), error, GET_TEXT(MSG_PLEASE_RESET), GET_TEXT(MSG_PLEASE_RESET), true, true, true, true);
if (strcmp_P(error, GET_TEXT(MSG_ERR_MAXTEMP)) == 0 || strcmp_P(error, GET_TEXT(MSG_THERMAL_RUNAWAY)) == 0) {
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_THERMAL_RUNAWAY);
} else if (strcmp_P(error, GET_TEXT(MSG_HEATING_FAILED_LCD)) == 0) {
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_HEATING_FAILED);
}else if (strcmp_P(error, GET_TEXT(MSG_ERR_MINTEMP)) == 0) {
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_THERMISTOR_ERROR);
} else {
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_KILL);
}
ScreenHandler.KillScreenCalled();
while (!ScreenHandler.loop()); // Wait while anything is left to be sent
}
void onMediaInserted() { TERN_(SDSUPPORT, ScreenHandler.SDCardInserted()); }
void onMediaError() { TERN_(SDSUPPORT, ScreenHandler.SDCardError()); }
void onMediaRemoved() { TERN_(SDSUPPORT, ScreenHandler.SDCardRemoved()); }
void onPlayTone(const uint16_t frequency, const uint16_t duration) {
if (ScreenHandler.getCurrentScreen() == DGUSLCD_SCREEN_FEED) {
// We're in the feed (load filament) workflow - no beep - there is no confirmation
return;
}
ScreenHandler.Buzzer(frequency, duration);
}
bool hasPrintTimer = false;
void onPrintTimerStarted() {
hasPrintTimer = true;
if (!IS_SD_FILE_OPEN() && !(PrintJobRecovery::valid() && PrintJobRecovery::exists())) {
ScreenHandler.SetPrintingFromHost();
}
#if ENABLED(LCD_SET_PROGRESS_MANUALLY)
ui.progress_reset();
#endif
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PRINT_RUNNING);
}
void onPrintTimerPaused() {
// Handle M28 Pause SD print - But only if we're not waiting on a user
if (ExtUI::isPrintingFromMediaPaused() && ScreenHandler.getCurrentScreen() == DGUSLCD_SCREEN_PRINT_RUNNING && !ExtUI::isWaitingOnUser()) {
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PRINT_PAUSED);
}
}
void onPrintTimerStopped() {
hasPrintTimer = false;
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PRINT_FINISH);
}
void onFilamentRunout(const extruder_t extruder) {
// Only navigate to filament runout screen when we don't use M600 for changing the filament - otherwise it gets confusing for the user
if (strcmp_P(FILAMENT_RUNOUT_SCRIPT, PSTR("M600")) != 0) {
ScreenHandler.FilamentRunout();
}
}
void onUserConfirmed() {
DEBUG_ECHOLN("User confirmation invoked");
ExtUI::setUserConfirmed();
}
void onUserConfirmRequired(const char * const msg) {
if (msg) {
DEBUG_ECHOLNPAIR("User confirmation requested: ", msg);
if (ScreenHandler.getCurrentScreen() == DGUSLCD_SCREEN_FEED) {
// We're in the feed (load filament) workflow - immediately assume confirmed
onUserConfirmed();
return;
}
ScreenHandler.setstatusmessagePGM(msg);
ScreenHandler.sendinfoscreen(PSTR("Confirmation required"), msg, NUL_STR, PSTR("Ok"), true, true, false, true);
if (ExtUI::isPrinting()) {
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_PRINT_PAUSED);
} else {
ScreenHandler.GotoScreen(DGUSLCD_SCREEN_POPUP);
}
}
else if (ScreenHandler.getCurrentScreen() == DGUSLCD_SCREEN_POPUP) {
DEBUG_ECHOLNPAIR("User confirmation canceled");
ScreenHandler.setstatusmessagePGM(nullptr);
ScreenHandler.PopToOldScreen();
}
}
void onStatusChanged(const char * const msg) { ScreenHandler.setstatusmessage(msg); }
void onFactoryReset() {
ScreenHandler.OnFactoryReset();
}
void onHomingStart() {
ScreenHandler.OnHomingStart();
}
void onHomingComplete() {
ScreenHandler.OnHomingComplete();
}
void onPrintFinished() {
ScreenHandler.OnPrintFinished();
}
void onStoreSettings(char *buff) {
ScreenHandler.StoreSettings(buff);
}
void onLoadSettings(const char *buff) {
ScreenHandler.LoadSettings(buff);
}
void onPostprocessSettings() {
// Called after loading or resetting stored settings
}
void onConfigurationStoreWritten(bool success) {
// Called after the entire EEPROM has been written,
// whether successful or not.
}
void onConfigurationStoreRead(bool success) {
// Called after the entire EEPROM has been read,
// whether successful or not.
}
#if HAS_MESH
void onMeshLevelingStart() {
ScreenHandler.OnMeshLevelingStart();
}
void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {
ScreenHandler.OnMeshLevelingUpdate(xpos, ypos, zval);
}
void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) {
ScreenHandler.OnMeshLevelingUpdate(xpos, ypos, 0);
}
#endif
#if ENABLED(POWER_LOSS_RECOVERY)
void onPowerLossResume() {
// Called on resume from power-loss
ScreenHandler.OnPowerlossResume();
}
#endif
#if HAS_PID_HEATING
void onPidTuning(const result_t rst) {
// Called for temperature PID tuning result
switch (rst) {
case PID_BAD_EXTRUDER_NUM:
PIDHandler::result_message = GET_TEXT(MSG_PID_BAD_EXTRUDER_NUM);
ScreenHandler.setstatusmessagePGM(PIDHandler::result_message);
break;
case PID_TEMP_TOO_HIGH:
PIDHandler::result_message = GET_TEXT(MSG_PID_TEMP_TOO_HIGH);
ScreenHandler.setstatusmessagePGM(PIDHandler::result_message);
break;
case PID_TUNING_TIMEOUT:
PIDHandler::result_message = GET_TEXT(MSG_PID_TIMEOUT);
ScreenHandler.setstatusmessagePGM(PIDHandler::result_message);
break;
case PID_DONE:
PIDHandler::result_message = GET_TEXT(MSG_PID_AUTOTUNE_DONE);
ScreenHandler.setstatusmessagePGM(PIDHandler::result_message);
break;
}
}
#endif
void onSteppersDisabled() {
}
void onSteppersEnabled() {
}
void onMeshValidationStarting() {
MeshValidationHandler::OnMeshValidationStart();
}
void onMeshValidationFinished() {
MeshValidationHandler::OnMeshValidationFinish();
}
}
#endif // HAS_DGUS_LCD
+1 -1
View File
@@ -44,7 +44,7 @@
#endif
#ifndef PS_ON_PIN
#define PS_ON_PIN 40 // Used by CR2020 Industrial series
#define PS_ON_PIN 40 // Used by CR2020 Industrial series
#endif
#if ENABLED(CASE_LIGHT_ENABLE) && !defined(CASE_LIGHT_PIN)
+9 -1
View File
@@ -177,5 +177,13 @@
#define LED_CONTROL_PIN PA13
#ifndef NEOPIXEL_PIN
#define NEOPIXEL_PIN PA8
#define NEOPIXEL_PIN PA8
#endif
#define CASE_LIGHT_PIN LED_CONTROL_PIN
#define SUICIDE_PIN PC13
#ifndef SUICIDE_PIN_INVERTING
#define SUICIDE_PIN_INVERTING false
#endif