MarlinUI for Ender 3 v2 DWIN LCD (#22594)

Co-Authored-By: Taylor Talkington <taylor.talkington@gmail.com>
This commit is contained in:
Scott Lahteine 2021-08-22 05:25:07 -05:00 committed by Scott Lahteine
parent d51e70083d
commit 73ef26a106
35 changed files with 56500 additions and 41 deletions

View file

@ -2746,6 +2746,12 @@
//
//#define DWIN_CREALITY_LCD
//
// MarlinUI for Creality's DWIN display (and others)
//
//#define DWIN_MARLINUI_PORTRAIT
//#define DWIN_MARLINUI_LANDSCAPE
//
// Touch Screen Settings
//

View file

@ -1306,7 +1306,7 @@
// LCD Print Progress options
#if EITHER(SDSUPPORT, LCD_SET_PROGRESS_MANUALLY)
#if ANY(HAS_MARLINUI_U8GLIB, EXTENSIBLE_UI, HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL)
#if ANY(HAS_MARLINUI_U8GLIB, EXTENSIBLE_UI, HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL, IS_DWIN_MARLINUI)
//#define SHOW_REMAINING_TIME // Display estimated time to completion
#if ENABLED(SHOW_REMAINING_TIME)
//#define USE_M73_REMAINING_TIME // Use remaining time from M73 command instead of estimation
@ -1579,16 +1579,10 @@
* printing performance versus fast display updates.
*/
#if HAS_MARLINUI_U8GLIB
// Show SD percentage next to the progress bar
//#define SHOW_SD_PERCENT
// Save many cycles by drawing a hollow frame or no frame on the Info Screen
//#define XYZ_NO_FRAME
#define XYZ_HOLLOW_FRAME
// Enable to save many cycles by drawing a hollow frame on Menu Screens
#define MENU_HOLLOW_FRAME
// A bigger font is available for edit items. Costs 3120 bytes of PROGMEM.
// Western only. Not available for Cyrillic, Kana, Turkish, Greek, or Chinese.
//#define USE_BIG_EDIT_FONT
@ -1597,9 +1591,6 @@
// Western only. Not available for Cyrillic, Kana, Turkish, Greek, or Chinese.
//#define USE_SMALL_INFOFONT
// Swap the CW/CCW indicators in the graphics overlay
//#define OVERLAY_GFX_REVERSE
/**
* ST7920-based LCDs can emulate a 16 x 4 character display using
* the ST7920 character-generator for very fast screen updates.
@ -1651,6 +1642,17 @@
#endif // HAS_MARLINUI_U8GLIB
#if HAS_MARLINUI_U8GLIB || IS_DWIN_MARLINUI
// Show SD percentage next to the progress bar
//#define SHOW_SD_PERCENT
// Enable to save many cycles by drawing a hollow frame on Menu Screens
#define MENU_HOLLOW_FRAME
// Swap the CW/CCW indicators in the graphics overlay
//#define OVERLAY_GFX_REVERSE
#endif
//
// Additional options for DGUS / DWIN displays
//
@ -1716,7 +1718,7 @@
//
// Specify additional languages for the UI. Default specified by LCD_LANGUAGE.
//
#if ANY(DOGLCD, TFT_COLOR_UI, TOUCH_UI_FTDI_EVE)
#if ANY(DOGLCD, TFT_COLOR_UI, TOUCH_UI_FTDI_EVE, IS_DWIN_MARLINUI)
//#define LCD_LANGUAGE_2 fr
//#define LCD_LANGUAGE_3 de
//#define LCD_LANGUAGE_4 es

View file

@ -238,8 +238,8 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load
if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE);
TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("Filament Purging...")));
TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Filament Purging..."), CONTINUE_STR));
TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(GET_TEXT(MSG_FILAMENT_CHANGE_PURGE)));
TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, GET_TEXT(MSG_FILAMENT_CHANGE_PURGE), CONTINUE_STR));
wait_for_user = true; // A click or M108 breaks the purge_length loop
for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count)
unscaled_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE);

View file

@ -488,7 +488,10 @@
#define HAS_MARLINUI_U8GLIB 1
#elif IS_TFTGLCD_PANEL
// Neither DOGM nor HD44780. Fully customized interface.
#elif DISABLED(HAS_GRAPHICAL_TFT)
#elif IS_DWIN_MARLINUI
// Since HAS_MARLINUI_U8GLIB refers to U8G displays
// the DWIN display can define its own flags
#elif !HAS_GRAPHICAL_TFT
#define HAS_MARLINUI_HD44780 1
#endif
#endif
@ -1087,7 +1090,7 @@
#define HAS_ETHERNET 1
#endif
#if ENABLED(DWIN_CREALITY_LCD)
#if EITHER(DWIN_CREALITY_LCD, IS_DWIN_MARLINUI)
#define SERIAL_CATCHALL 0
#ifndef LCD_SERIAL_PORT
#if MB(BTT_SKR_MINI_E3_V1_0, BTT_SKR_MINI_E3_V1_2, BTT_SKR_MINI_E3_V2_0, BTT_SKR_E3_TURBO)

View file

@ -461,7 +461,7 @@
#endif
#if ANY(HAS_GRAPHICAL_TFT, LCD_USE_DMA_FSMC, HAS_FSMC_GRAPHICAL_TFT, HAS_SPI_GRAPHICAL_TFT) || !PIN_EXISTS(SD_DETECT)
#if ANY(HAS_GRAPHICAL_TFT, LCD_USE_DMA_FSMC, HAS_FSMC_GRAPHICAL_TFT, HAS_SPI_GRAPHICAL_TFT, IS_DWIN_MARLINUI) || !PIN_EXISTS(SD_DETECT)
#define NO_LCD_REINIT 1 // Suppress LCD re-initialization
#endif
@ -3258,6 +3258,8 @@
#ifndef LCD_WIDTH
#if HAS_MARLINUI_U8GLIB
#define LCD_WIDTH 21
#elif IS_DWIN_MARLINUI
// Defined by header
#else
#define LCD_WIDTH TERN(IS_ULTIPANEL, 20, 16)
#endif
@ -3265,6 +3267,8 @@
#ifndef LCD_HEIGHT
#if HAS_MARLINUI_U8GLIB
#define LCD_HEIGHT 5
#elif IS_DWIN_MARLINUI
// Defined by header
#else
#define LCD_HEIGHT TERN(IS_ULTIPANEL, 4, 2)
#endif

View file

@ -798,8 +798,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
#error "PROGRESS_MSG_EXPIRE must be greater than or equal to 0."
#endif
#elif ENABLED(LCD_SET_PROGRESS_MANUALLY)
#if NONE(HAS_MARLINUI_U8GLIB, HAS_GRAPHICAL_TFT, HAS_MARLINUI_HD44780, EXTENSIBLE_UI)
#error "LCD_SET_PROGRESS_MANUALLY requires LCD_PROGRESS_BAR, Character LCD, Graphical LCD, TFT, or EXTENSIBLE_UI."
#if NONE(HAS_MARLINUI_U8GLIB, HAS_GRAPHICAL_TFT, HAS_MARLINUI_HD44780, EXTENSIBLE_UI, IS_DWIN_MARLINUI)
#error "LCD_SET_PROGRESS_MANUALLY requires LCD_PROGRESS_BAR, Character LCD, Graphical LCD, TFT, EXTENSIBLE_UI, OR DWIN MarlinUI."
#endif
#endif
@ -1721,7 +1721,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
#endif
#endif
#if ENABLED(MESH_EDIT_GFX_OVERLAY) && !BOTH(AUTO_BED_LEVELING_UBL, HAS_MARLINUI_U8GLIB)
#if ENABLED(MESH_EDIT_GFX_OVERLAY) && !(ENABLED(AUTO_BED_LEVELING_UBL) && EITHER(HAS_MARLINUI_U8GLIB, IS_DWIN_MARLINUI))
#error "MESH_EDIT_GFX_OVERLAY requires AUTO_BED_LEVELING_UBL and a Graphical LCD."
#endif
@ -2640,6 +2640,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
+ 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(ENDER2_STOCKDISPLAY, CR10_STOCKDISPLAY, DWIN_CREALITY_LCD) \
+ COUNT_ENABLED(DWIN_MARLINUI_PORTRAIT, DWIN_MARLINUI_LANDSCAPE) \
+ 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) \
+ COUNT_ENABLED(MKS_12864OLED, MKS_12864OLED_SSD1306) \

View file

@ -0,0 +1,470 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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/>.
*
*/
/********************************************************************************
* @file lcd/e3v2/marlinui/dwin_lcd.cpp
* @brief DWIN screen control functions
********************************************************************************/
#include "../../../inc/MarlinConfigPre.h"
#if IS_DWIN_MARLINUI
#include "../../../inc/MarlinConfig.h"
#include "dwin_lcd.h"
#include <string.h> // for memset
//#define DEBUG_OUT 1
#include "../../../core/debug_out.h"
// Make sure DWIN_SendBuf is large enough to hold the largest string plus draw command and tail.
// Assume the narrowest (6 pixel) font and 2-byte gb2312-encoded characters.
uint8_t DWIN_SendBuf[11 + DWIN_WIDTH / 6 * 2] = { 0xAA };
uint8_t DWIN_BufTail[4] = { 0xCC, 0x33, 0xC3, 0x3C };
uint8_t databuf[26] = { 0 };
uint8_t receivedType;
int recnum = 0;
inline void DWIN_Byte(size_t &i, const uint16_t bval) {
DWIN_SendBuf[++i] = bval;
}
inline void DWIN_Word(size_t &i, const uint16_t wval) {
DWIN_SendBuf[++i] = wval >> 8;
DWIN_SendBuf[++i] = wval & 0xFF;
}
inline void DWIN_Long(size_t &i, const uint32_t lval) {
DWIN_SendBuf[++i] = (lval >> 24) & 0xFF;
DWIN_SendBuf[++i] = (lval >> 16) & 0xFF;
DWIN_SendBuf[++i] = (lval >> 8) & 0xFF;
DWIN_SendBuf[++i] = lval & 0xFF;
}
inline void DWIN_String(size_t &i, char * const string) {
const size_t len = _MIN(sizeof(DWIN_SendBuf) - i, strlen(string));
memcpy(&DWIN_SendBuf[i+1], string, len);
i += len;
}
inline void DWIN_String(size_t &i, const __FlashStringHelper * string) {
if (!string) return;
const size_t len = strlen_P((PGM_P)string); // cast it to PGM_P, which is basically const char *, and measure it using the _P version of strlen.
if (len == 0) return;
memcpy(&DWIN_SendBuf[i+1], string, len);
i += len;
}
// Send the data in the buffer and the packet end
inline void DWIN_Send(size_t &i) {
++i;
LOOP_L_N(n, i) { LCD_SERIAL.write(DWIN_SendBuf[n]); delayMicroseconds(1); }
LOOP_L_N(n, 4) { LCD_SERIAL.write(DWIN_BufTail[n]); delayMicroseconds(1); }
}
/*-------------------------------------- System variable function --------------------------------------*/
// Handshake (1: Success, 0: Fail)
bool DWIN_Handshake(void) {
#ifndef LCD_BAUDRATE
#define LCD_BAUDRATE 115200
#endif
LCD_SERIAL.begin(LCD_BAUDRATE);
const millis_t serial_connect_timeout = millis() + 1000UL;
while (!LCD_SERIAL.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
size_t i = 0;
DWIN_Byte(i, 0x00);
DWIN_Send(i);
while (LCD_SERIAL.available() > 0 && recnum < (signed)sizeof(databuf)) {
databuf[recnum] = LCD_SERIAL.read();
// ignore the invalid data
if (databuf[0] != FHONE) { // prevent the program from running.
if (recnum > 0) {
recnum = 0;
ZERO(databuf);
}
continue;
}
delay(10);
recnum++;
}
return ( recnum >= 3
&& databuf[0] == FHONE
&& databuf[1] == '\0'
&& databuf[2] == 'O'
&& databuf[3] == 'K' );
}
void DWIN_Startup(void) {
DEBUG_ECHOPGM("\r\nDWIN handshake ");
delay(750); // Delay here or init later in the boot process
const bool success = DWIN_Handshake();
if (success) DEBUG_ECHOLNPGM("ok."); else DEBUG_ECHOLNPGM("error.");
DWIN_Frame_SetDir(TERN(DWIN_MARLINUI_LANDSCAPE, 0, 1));
DWIN_Frame_Clear(Color_Bg_Black); // MarlinUI handles the bootscreen so just clear here
DWIN_UpdateLCD();
}
// Set the backlight luminance
// luminance: (0x00-0xFF)
void DWIN_Backlight_SetLuminance(const uint8_t luminance) {
size_t i = 0;
DWIN_Byte(i, 0x30);
DWIN_Byte(i, _MAX(luminance, 0x1F));
DWIN_Send(i);
}
// Set screen display direction
// dir: 0=0°, 1=90°, 2=180°, 3=270°
void DWIN_Frame_SetDir(uint8_t dir) {
size_t i = 0;
DWIN_Byte(i, 0x34);
DWIN_Byte(i, 0x5A);
DWIN_Byte(i, 0xA5);
DWIN_Byte(i, dir);
DWIN_Send(i);
}
// Update display
void DWIN_UpdateLCD(void) {
size_t i = 0;
DWIN_Byte(i, 0x3D);
DWIN_Send(i);
}
/*---------------------------------------- Drawing functions ----------------------------------------*/
// Clear screen
// color: Clear screen color
void DWIN_Frame_Clear(const uint16_t color) {
size_t i = 0;
DWIN_Byte(i, 0x01);
DWIN_Word(i, color);
DWIN_Send(i);
}
// Draw a point
// width: point width 0x01-0x0F
// height: point height 0x01-0x0F
// x,y: upper left point
void DWIN_Draw_Point(uint16_t color, uint8_t width, uint8_t height, uint16_t x, uint16_t y) {
size_t i = 0;
DWIN_Byte(i, 0x02);
DWIN_Word(i, color);
DWIN_Byte(i, width);
DWIN_Byte(i, height);
DWIN_Word(i, x);
DWIN_Word(i, y);
DWIN_Send(i);
}
// Draw a line
// color: Line segment color
// xStart/yStart: Start point
// xEnd/yEnd: End point
void DWIN_Draw_Line(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
size_t i = 0;
DWIN_Byte(i, 0x03);
DWIN_Word(i, color);
DWIN_Word(i, xStart);
DWIN_Word(i, yStart);
DWIN_Word(i, xEnd);
DWIN_Word(i, yEnd);
DWIN_Send(i);
}
// Draw a rectangle
// mode: 0=frame, 1=fill, 2=XOR fill
// color: Rectangle color
// xStart/yStart: upper left point
// xEnd/yEnd: lower right point
void DWIN_Draw_Rectangle(uint8_t mode, uint16_t color,
uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
size_t i = 0;
DWIN_Byte(i, 0x05);
DWIN_Byte(i, mode);
DWIN_Word(i, color);
DWIN_Word(i, xStart);
DWIN_Word(i, yStart);
DWIN_Word(i, xEnd);
DWIN_Word(i, yEnd);
DWIN_Send(i);
}
// Move a screen area
// mode: 0, circle shift; 1, translation
// dir: 0=left, 1=right, 2=up, 3=down
// dis: Distance
// color: Fill color
// xStart/yStart: upper left point
// xEnd/yEnd: bottom right point
void DWIN_Frame_AreaMove(uint8_t mode, uint8_t dir, uint16_t dis,
uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
size_t i = 0;
DWIN_Byte(i, 0x09);
DWIN_Byte(i, (mode << 7) | dir);
DWIN_Word(i, dis);
DWIN_Word(i, color);
DWIN_Word(i, xStart);
DWIN_Word(i, yStart);
DWIN_Word(i, xEnd);
DWIN_Word(i, yEnd);
DWIN_Send(i);
}
/*---------------------------------------- Text related functions ----------------------------------------*/
// Draw a string
// bShow: true=display background color; false=don't display background color
// size: Font size
// color: Character color
// bColor: Background color
// x/y: Upper-left coordinate of the string
// *string: The string
void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, char *string) {
uint8_t widthAdjust = 0;
size_t i = 0;
DWIN_Byte(i, 0x11);
// Bit 7: widthAdjust
// Bit 6: bShow
// Bit 5-4: Unused (0)
// Bit 3-0: size
DWIN_Byte(i, (widthAdjust * 0x80) | (bShow * 0x40) | size);
DWIN_Word(i, color);
DWIN_Word(i, bColor);
DWIN_Word(i, x);
DWIN_Word(i, y);
DWIN_String(i, string);
DWIN_Send(i);
}
// Draw a positive integer
// bShow: true=display background color; false=don't display background color
// zeroFill: true=zero fill; false=no zero fill
// zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
// size: Font size
// color: Character color
// bColor: Background color
// iNum: Number of digits
// x/y: Upper-left coordinate
// value: Integer value
void DWIN_Draw_IntValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, uint16_t value) {
size_t i = 0;
DWIN_Byte(i, 0x14);
// Bit 7: bshow
// Bit 6: 1 = signed; 0 = unsigned number;
// Bit 5: zeroFill
// Bit 4: zeroMode
// Bit 3-0: size
DWIN_Byte(i, (bShow * 0x80) | (zeroFill * 0x20) | (zeroMode * 0x10) | size);
DWIN_Word(i, color);
DWIN_Word(i, bColor);
DWIN_Byte(i, iNum);
DWIN_Byte(i, 0); // fNum
DWIN_Word(i, x);
DWIN_Word(i, y);
#if 0
for (char count = 0; count < 8; count++) {
DWIN_Byte(i, value);
value >>= 8;
if (!(value & 0xFF)) break;
}
#else
// Write a big-endian 64 bit integer
const size_t p = i + 1;
for (char count = 8; count--;) { // 7..0
++i;
DWIN_SendBuf[p + count] = value;
value >>= 8;
}
#endif
DWIN_Send(i);
}
// Draw a floating point number
// bShow: true=display background color; false=don't display background color
// zeroFill: true=zero fill; false=no zero fill
// zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
// size: Font size
// color: Character color
// bColor: Background color
// iNum: Number of whole digits
// fNum: Number of decimal digits
// x/y: Upper-left point
// value: Float value
void DWIN_Draw_FloatValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, long value) {
//uint8_t *fvalue = (uint8_t*)&value;
size_t i = 0;
DWIN_Byte(i, 0x14);
DWIN_Byte(i, (bShow * 0x80) | (zeroFill * 0x20) | (zeroMode * 0x10) | size);
DWIN_Word(i, color);
DWIN_Word(i, bColor);
DWIN_Byte(i, iNum);
DWIN_Byte(i, fNum);
DWIN_Word(i, x);
DWIN_Word(i, y);
DWIN_Long(i, value);
/*
DWIN_Byte(i, fvalue[3]);
DWIN_Byte(i, fvalue[2]);
DWIN_Byte(i, fvalue[1]);
DWIN_Byte(i, fvalue[0]);
*/
DWIN_Send(i);
}
/*---------------------------------------- Picture related functions ----------------------------------------*/
// Draw JPG and cached in #0 virtual display area
// id: Picture ID
void DWIN_JPG_ShowAndCache(const uint8_t id) {
size_t i = 0;
DWIN_Word(i, 0x2200);
DWIN_Byte(i, id);
DWIN_Send(i); // AA 23 00 00 00 00 08 00 01 02 03 CC 33 C3 3C
}
// Draw an Icon
// libID: Icon library ID
// picID: Icon ID
// x/y: Upper-left point
void DWIN_ICON_Show(uint8_t libID, uint8_t picID, uint16_t x, uint16_t y) {
NOMORE(x, DWIN_WIDTH - 1);
NOMORE(y, DWIN_HEIGHT - 1); // -- ozy -- srl
size_t i = 0;
DWIN_Byte(i, 0x23);
DWIN_Word(i, x);
DWIN_Word(i, y);
DWIN_Byte(i, 0x80 | libID);
//DWIN_Byte(i, libID);
DWIN_Byte(i, picID);
DWIN_Send(i);
}
// Unzip the JPG picture to a virtual display area
// n: Cache index
// id: Picture ID
void DWIN_JPG_CacheToN(uint8_t n, uint8_t id) {
size_t i = 0;
DWIN_Byte(i, 0x25);
DWIN_Byte(i, n);
DWIN_Byte(i, id);
DWIN_Send(i);
}
// Copy area from virtual display area to current screen
// cacheID: virtual area number
// xStart/yStart: Upper-left of virtual area
// xEnd/yEnd: Lower-right of virtual area
// x/y: Screen paste point
void DWIN_Frame_AreaCopy(uint8_t cacheID, uint16_t xStart, uint16_t yStart,
uint16_t xEnd, uint16_t yEnd, uint16_t x, uint16_t y) {
size_t i = 0;
DWIN_Byte(i, 0x27);
DWIN_Byte(i, 0x80 | cacheID);
DWIN_Word(i, xStart);
DWIN_Word(i, yStart);
DWIN_Word(i, xEnd);
DWIN_Word(i, yEnd);
DWIN_Word(i, x);
DWIN_Word(i, y);
DWIN_Send(i);
}
// Animate a series of icons
// animID: Animation ID; 0x00-0x0F
// animate: true on; false off;
// libID: Icon library ID
// picIDs: Icon starting ID
// picIDe: Icon ending ID
// x/y: Upper-left point
// interval: Display time interval, unit 10mS
void DWIN_ICON_Animation(uint8_t animID, bool animate, uint8_t libID, uint8_t picIDs, uint8_t picIDe, uint16_t x, uint16_t y, uint16_t interval) {
NOMORE(x, DWIN_WIDTH - 1);
NOMORE(y, DWIN_HEIGHT - 1); // -- ozy -- srl
size_t i = 0;
DWIN_Byte(i, 0x28);
DWIN_Word(i, x);
DWIN_Word(i, y);
// Bit 7: animation on or off
// Bit 6: start from begin or end
// Bit 5-4: unused (0)
// Bit 3-0: animID
DWIN_Byte(i, (animate * 0x80) | 0x40 | animID);
DWIN_Byte(i, libID);
DWIN_Byte(i, picIDs);
DWIN_Byte(i, picIDe);
DWIN_Byte(i, interval);
DWIN_Send(i);
}
// Animation Control
// state: 16 bits, each bit is the state of an animation id
void DWIN_ICON_AnimationControl(uint16_t state) {
size_t i = 0;
DWIN_Byte(i, 0x29);
DWIN_Word(i, state);
DWIN_Send(i);
}
/*---------------------------------------- Memory functions ----------------------------------------*/
// The LCD has an additional 32KB SRAM and 16KB Flash
// Data can be written to the sram and save to one of the jpeg page files
// Write Data Memory
// command 0x31
// Type: Write memory selection; 0x5A=SRAM; 0xA5=Flash
// Address: Write data memory address; 0x000-0x7FFF for SRAM; 0x000-0x3FFF for Flash
// Data: data
//
// Flash writing returns 0xA5 0x4F 0x4B
// Read Data Memory
// command 0x32
// Type: Read memory selection; 0x5A=SRAM; 0xA5=Flash
// Address: Read data memory address; 0x000-0x7FFF for SRAM; 0x000-0x3FFF for Flash
// Length: leangth of data to read; 0x01-0xF0
//
// Response:
// Type, Address, Length, Data
// Write Picture Memory
// Write the contents of the 32KB SRAM data memory into the designated image memory space
// Issued: 0x5A, 0xA5, PIC_ID
// Response: 0xA5 0x4F 0x4B
//
// command 0x33
// 0x5A, 0xA5
// PicId: Picture Memory location, 0x00-0x0F
//
// Flash writing returns 0xA5 0x4F 0x4B
#endif // IS_DWIN_MARLINUI

View file

@ -0,0 +1,302 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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
/********************************************************************************
* @file lcd/e3v2/marlinui/dwin_lcd.h
* @brief DWIN screen control functions
********************************************************************************/
#include <stdint.h>
#define RECEIVED_NO_DATA 0x00
#define RECEIVED_SHAKE_HAND_ACK 0x01
#define FHONE 0xAA
#define DWIN_SCROLL_UP 2
#define DWIN_SCROLL_DOWN 3
#if DISABLED(DWIN_MARLINUI_LANDSCAPE)
#define DWIN_WIDTH 272
#define DWIN_HEIGHT 480
#else
#define DWIN_WIDTH 480
#define DWIN_HEIGHT 272
#endif
// Picture ID
#define DWIN_Boot_Horiz 0
#define DWIN_Boot_Vert 1
#define DWIN_MarlinUI_Assets 2
/**
* 3-.0The font size, 0x00-0x09, corresponds to the font size below:
* 0x00=6*12 0x01=8*16 0x02=10*20 0x03=12*24 0x04=14*28
* 0x05=16*32 0x06=20*40 0x07=24*48 0x08=28*56 0x09=32*64
*/
#define font6x12 0x00
#define font8x16 0x01
#define font10x20 0x02
#define font12x24 0x03
#define font14x28 0x04
#define font16x32 0x05
#define font20x40 0x06
#define font24x48 0x07
#define font28x56 0x08
#define font32x64 0x09
#define DWIN_FONT_MENU font10x20
#define DWIN_FONT_STAT font14x28
#define DWIN_FONT_HEAD font10x20
#define DWIN_FONT_ALERT font14x28
// Color
#define Color_White 0xFFFF
#define Color_Yellow 0xFF0F
#define Color_Error_Red 0xB000 // Error!
#define Color_Bg_Red 0xF00F // Red background color
#define Color_Bg_Window 0x31E8 // Popup background color
#define Color_Bg_Heading 0x3344 // Static Heading
#define Color_Bg_Blue 0x1125 // Dark blue background color
#define Color_Bg_Black 0x0841 // Black background color
#define Color_IconBlue 0x45FA // Lighter blue that matches icons/accents
#define Popup_Text_Color 0xD6BA // Popup font background color
#define Line_Color 0x3A6A // Split line color
#define Rectangle_Color 0xEE2F // Blue square cursor color
#define Percent_Color 0xFE29 // Percentage color
#define BarFill_Color 0x10E4 // Fill color of progress bar
#define Select_Color 0x33BB // Selected color
// Character matrix width x height
//#define LCD_WIDTH ((DWIN_WIDTH) / 8)
//#define LCD_HEIGHT ((DWIN_HEIGHT) / 12)
// ICON ID
#define BOOT_ICON 3 // Icon set file 3.ICO
#define ICON 4 // Icon set file 4.ICO
// MarlinUI Boot Icons
#define ICON_MarlinBoot 0
#define ICON_OpenSource 1
#define ICON_GitHubURL 2
#define ICON_MarlinURL 3
#define ICON_Copyright 4
// MarlinUI Icons
#define ICON_LOGO_Marlin 0
#define ICON_HotendOff 1
#define ICON_HotendOn 2
#define ICON_BedOff 3
#define ICON_BedOn 4
#define ICON_Fan0 5
#define ICON_Fan1 6
#define ICON_Fan2 7
#define ICON_Fan3 8
#define ICON_Halted 9
#define ICON_Question 10
#define ICON_Alert 11
#define ICON_RotateCW 12
#define ICON_RotateCCW 13
#define ICON_UpArrow 14
#define ICON_DownArrow 15
#define ICON_BedLine 16
#define ICON_AdvSet ICON_Language
#define ICON_HomeOff ICON_AdvSet
#define ICON_HomeOffX ICON_StepX
#define ICON_HomeOffY ICON_StepY
#define ICON_HomeOffZ ICON_StepZ
#define ICON_ProbeOff ICON_AdvSet
#define ICON_ProbeOffX ICON_StepX
#define ICON_ProbeOffY ICON_StepY
#define ICON_PIDNozzle ICON_SetEndTemp
#define ICON_PIDbed ICON_SetBedTemp
/*-------------------------------------- System variable function --------------------------------------*/
// Handshake (1: Success, 0: Fail)
bool DWIN_Handshake(void);
// Common DWIN startup
void DWIN_Startup(void);
// Set the backlight luminance
// luminance: (0x00-0xFF)
void DWIN_Backlight_SetLuminance(const uint8_t luminance);
// Set screen display direction
// dir: 0=0°, 1=90°, 2=180°, 3=270°
void DWIN_Frame_SetDir(uint8_t dir);
// Update display
void DWIN_UpdateLCD(void);
/*---------------------------------------- Drawing functions ----------------------------------------*/
// Clear screen
// color: Clear screen color
void DWIN_Frame_Clear(const uint16_t color);
// Draw a point
// color: point color
// width: point width 0x01-0x0F
// height: point height 0x01-0x0F
// x,y: upper left point
void DWIN_Draw_Point(uint16_t color, uint8_t width, uint8_t height, uint16_t x, uint16_t y);
// Draw a line
// color: Line segment color
// xStart/yStart: Start point
// xEnd/yEnd: End point
void DWIN_Draw_Line(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd);
// Draw a Horizontal line
// color: Line segment color
// xStart/yStart: Start point
// xLength: Line Length
inline void DWIN_Draw_HLine(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xLength) {
DWIN_Draw_Line(color, xStart, yStart, xStart + xLength - 1, yStart);
}
// Draw a Vertical line
// color: Line segment color
// xStart/yStart: Start point
// yLength: Line Length
inline void DWIN_Draw_VLine(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t yLength) {
DWIN_Draw_Line(color, xStart, yStart, xStart, yStart + yLength - 1);
}
// Draw a rectangle
// mode: 0=frame, 1=fill, 2=XOR fill
// color: Rectangle color
// xStart/yStart: upper left point
// xEnd/yEnd: lower right point
void DWIN_Draw_Rectangle(uint8_t mode, uint16_t color,
uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd);
// Draw a box
// mode: 0=frame, 1=fill, 2=XOR fill
// color: Rectangle color
// xStart/yStart: upper left point
// xSize/ySize: box size
inline void DWIN_Draw_Box(uint8_t mode, uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xSize, uint16_t ySize) {
DWIN_Draw_Rectangle(mode, color, xStart, yStart, xStart + xSize - 1, yStart + ySize - 1);
}
// Move a screen area
// mode: 0, circle shift; 1, translation
// dir: 0=left, 1=right, 2=up, 3=down
// dis: Distance
// color: Fill color
// xStart/yStart: upper left point
// xEnd/yEnd: bottom right point
void DWIN_Frame_AreaMove(uint8_t mode, uint8_t dir, uint16_t dis,
uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd);
/*---------------------------------------- Text related functions ----------------------------------------*/
// Draw a string
// bShow: true=display background color; false=don't display background color
// size: Font size
// color: Character color
// bColor: Background color
// x/y: Upper-left coordinate of the string
// *string: The string
void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, char *string);
class __FlashStringHelper;
inline void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, const __FlashStringHelper *title) {
DWIN_Draw_String(bShow, size, color, bColor, x, y, (char *)title);
}
// Draw a positive integer
// bShow: true=display background color; false=don't display background color
// zeroFill: true=zero fill; false=no zero fill
// zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
// size: Font size
// color: Character color
// bColor: Background color
// iNum: Number of digits
// x/y: Upper-left coordinate
// value: Integer value
void DWIN_Draw_IntValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, uint16_t value);
// Draw a floating point number
// bShow: true=display background color; false=don't display background color
// zeroFill: true=zero fill; false=no zero fill
// zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
// size: Font size
// color: Character color
// bColor: Background color
// iNum: Number of whole digits
// fNum: Number of decimal digits
// x/y: Upper-left point
// value: Float value
void DWIN_Draw_FloatValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, long value);
/*---------------------------------------- Picture related functions ----------------------------------------*/
// Draw JPG and cached in #0 virtual display area
// id: Picture ID
void DWIN_JPG_ShowAndCache(const uint8_t id);
// Draw an Icon
// libID: Icon library ID
// picID: Icon ID
// x/y: Upper-left point
void DWIN_ICON_Show(uint8_t libID, uint8_t picID, uint16_t x, uint16_t y);
// Unzip the JPG picture to a virtual display area
// n: Cache index
// id: Picture ID
void DWIN_JPG_CacheToN(uint8_t n, uint8_t id);
// Unzip the JPG picture to virtual display area #1
// id: Picture ID
inline void DWIN_JPG_CacheTo1(uint8_t id) { DWIN_JPG_CacheToN(1, id); }
// Copy area from virtual display area to current screen
// cacheID: virtual area number
// xStart/yStart: Upper-left of virtual area
// xEnd/yEnd: Lower-right of virtual area
// x/y: Screen paste point
void DWIN_Frame_AreaCopy(uint8_t cacheID, uint16_t xStart, uint16_t yStart,
uint16_t xEnd, uint16_t yEnd, uint16_t x, uint16_t y);
// Animate a series of icons
// animID: Animation ID up to 16
// animate: animation on or off
// libID: Icon library ID
// picIDs: Icon starting ID
// picIDe: Icon ending ID
// x/y: Upper-left point
// interval: Display time interval, unit 10mS
void DWIN_ICON_Animation(uint8_t animID, bool animate, uint8_t libID, uint8_t picIDs,
uint8_t picIDe, uint16_t x, uint16_t y, uint16_t interval);
// Animation Control
// state: 16 bits, each bit is the state of an animation id
void DWIN_ICON_AnimationControl(uint16_t state);

View file

@ -0,0 +1,180 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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/>.
*
*/
#include "../../../inc/MarlinConfig.h"
#if IS_DWIN_MARLINUI
#include "dwin_string.h"
//#include "../../fontutils.h"
uint8_t DWIN_String::data[];
uint16_t DWIN_String::span;
uint8_t DWIN_String::len;
void DWIN_String::set() {
//*data = 0x00;
memset(data, 0x00, sizeof(data));
span = 0;
len = 0;
}
uint8_t read_byte(uint8_t *byte) { return *byte; }
/**
* Add a string, applying substitutions for the following characters:
*
* = displays '0'....'10' for indexes 0 - 10
* ~ displays '1'....'11' for indexes 0 - 10
* * displays 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL)
*/
void DWIN_String::add(uint8_t *string, int8_t index, uint8_t *itemString) {
wchar_t wchar;
while (*string) {
string = get_utf8_value_cb(string, read_byte, &wchar);
if (wchar > 255) wchar |= 0x0080;
uint8_t ch = uint8_t(wchar & 0x00FF);
if (ch == '=' || ch == '~' || ch == '*') {
if (index >= 0) {
int8_t inum = index + ((ch == '=') ? 0 : LCD_FIRST_TOOL);
if (ch == '*') add_character('E');
if (inum >= 10) { add_character('0' + (inum / 10)); inum %= 10; }
add_character('0' + inum);
}
else {
add(index == -2 ? GET_TEXT(MSG_CHAMBER) : GET_TEXT(MSG_BED));
}
continue;
}
else if (ch == '$' && itemString) {
add(itemString);
continue;
}
add_character(ch);
}
eol();
}
void DWIN_String::add(uint8_t *string, uint8_t max_len) {
wchar_t wchar;
while (*string && max_len) {
string = get_utf8_value_cb(string, read_byte, &wchar);
/*
if (wchar > 255) wchar |= 0x0080;
uint8_t ch = uint8_t(wchar & 0x00FF);
add_character(ch);
*/
add(wchar);
max_len--;
}
eol();
}
void DWIN_String::add(wchar_t character) {
int ret;
size_t idx = 0;
dwin_charmap_t pinval;
dwin_charmap_t *copy_address = nullptr;
pinval.uchar = character;
pinval.idx = -1;
// For 8-bit ASCII just print the single character
char str[] = { '?', 0 };
if (character < 255) {
str[0] = (char)character;
}
else {
copy_address = nullptr;
ret = pf_bsearch_r((void *)g_dwin_charmap_device, COUNT(g_dwin_charmap_device), pf_bsearch_cb_comp_dwinmap_pgm, (void *)&pinval, &idx);
if (ret >= 0) {
copy_address = (dwin_charmap_t*)(g_dwin_charmap_device + idx);
}
else {
ret = pf_bsearch_r((void *)g_dwin_charmap_common, COUNT(g_dwin_charmap_common), pf_bsearch_cb_comp_dwinmap_pgm, (void *)&pinval, &idx);
if (ret >= 0)
copy_address = (dwin_charmap_t*)(g_dwin_charmap_common + idx);
}
if (ret >= 0) {
dwin_charmap_t localval;
memcpy_P(&localval, copy_address, sizeof(localval));
str[0] = localval.idx;
str[1] = localval.idx2;
}
}
if (str[0]) add_character(str[0]);
if (str[1]) add_character(str[1]);
}
void DWIN_String::add_character(uint8_t character) {
if (len < MAX_STRING_LENGTH) {
data[len] = character;
len++;
//span += glyph(character)->DWidth;
}
}
void DWIN_String::rtrim(uint8_t character) {
while (len) {
if (data[len - 1] == 0x20 || data[len - 1] == character) {
len--;
//span -= glyph(data[length])->DWidth;
eol();
}
else
break;
}
}
void DWIN_String::ltrim(uint8_t character) {
uint16_t i, j;
for (i = 0; (i < len) && (data[i] == 0x20 || data[i] == character); i++) {
//span -= glyph(data[i])->DWidth;
}
if (i == 0) return;
for (j = 0; i < len; data[j++] = data[i++]);
len = j;
eol();
}
void DWIN_String::trim(uint8_t character) {
rtrim(character);
ltrim(character);
}
/* return v1 - v2 */
int dwin_charmap_compare(dwin_charmap_t *v1, dwin_charmap_t *v2) {
return (v1->uchar < v2->uchar) ? -1 : (v1->uchar > v2->uchar) ? 1 : 0;
}
int pf_bsearch_cb_comp_dwinmap_pgm(void *userdata, size_t idx, void * data_pin) {
dwin_charmap_t localval;
dwin_charmap_t *p_dwin_charmap = (dwin_charmap_t *)userdata;
memcpy_P(&localval, p_dwin_charmap + idx, sizeof(localval));
return dwin_charmap_compare(&localval, (dwin_charmap_t *)data_pin);
}
DWIN_String dwin_string;
#endif // IS_DWIN_MARLINUI

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,193 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* lcd/e3v2/marlinui/lcdprint_dwin.cpp
*
* Due to DWIN hardware limitations simplified characters are used
*/
#include "../../../inc/MarlinConfigPre.h"
#if IS_DWIN_MARLINUI
#include "lcdprint_dwin.h"
#include "dwin_lcd.h"
#include "dwin_string.h"
#include "../../marlinui.h"
#include "../../../MarlinCore.h"
#include <string.h>
cursor_t cursor;
extern dwin_font_t dwin_font;
void lcd_moveto_xy(const lcd_uint_t x, const lcd_uint_t y) { cursor.x = x; cursor.y = y; }
void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) {
cursor.x = col * dwin_font.width;
cursor.y = (row * (dwin_font.height + EXTRA_ROW_HEIGHT)) + (EXTRA_ROW_HEIGHT / 2);
}
inline void lcd_advance_cursor() { cursor.x += dwin_font.width; }
void lcd_put_int(const int i) {
// TODO: Draw an int at the cursor position, advance the cursor
}
int lcd_put_dwin_string() {
DWIN_Draw_String(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, (char*)dwin_string.string());
cursor.x += dwin_string.length() * dwin_font.width;
return dwin_string.length();
}
// return < 0 on error
// return the advanced cols
int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
dwin_string.set();
dwin_string.add(c);
dwin_string.truncate(max_length);
// Draw the char(s) at the cursor and advance the cursor
DWIN_Draw_String(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, (char*)dwin_string.string());
cursor.x += dwin_string.length() * dwin_font.width;
return dwin_string.length();
}
/**
* @brief Draw a UTF-8 string
*
* @param utf8_str : the UTF-8 string
* @param cb_read_byte : the callback function to read one byte from the utf8_str (from RAM or ROM)
* @param max_length : the pixel length of the string allowed (or number of slots in HD44780)
*
* @return the number of pixels advanced
*
* Draw a UTF-8 string
*/
static int lcd_put_u8str_max_cb(const char * utf8_str, uint8_t (*cb_read_byte)(uint8_t * str), pixel_len_t max_length) {
uint8_t *p = (uint8_t *)utf8_str;
dwin_string.set();
while (dwin_string.length() < max_length) {
wchar_t ch = 0;
p = get_utf8_value_cb(p, cb_read_byte, &ch);
if (!ch) break;
dwin_string.add(ch);
}
DWIN_Draw_String(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, (char*)dwin_string.string());
cursor.x += dwin_string.length() * dwin_font.width;
return dwin_string.length();
}
int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
return lcd_put_u8str_max_cb(utf8_str, read_byte_ram, max_length);
}
int lcd_put_u8str_max_P(PGM_P utf8_str_P, pixel_len_t max_length) {
return lcd_put_u8str_max_cb(utf8_str_P, read_byte_rom, max_length);
}
lcd_uint_t lcd_put_u8str_ind_P(PGM_P const pstr, const int8_t ind, PGM_P const inStr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) {
dwin_string.set();
dwin_string.add((uint8_t*)pstr, ind, (uint8_t*)inStr);
dwin_string.truncate(maxlen);
DWIN_Draw_String(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, (char*)dwin_string.string());
cursor.x += dwin_string.length() * dwin_font.width;
return dwin_string.length();
}
#if ENABLED(DEBUG_LCDPRINT)
int test_dwin_charmap(dwin_charmap_t *data, size_t size, char *name, char flg_show_contents) {
int ret;
size_t idx = 0;
dwin_charmap_t preval = { 0, 0, 0 };
dwin_charmap_t pinval = { 0, 0, 0 };
char flg_error = 0;
int i;
TRACE("Test %s\n", name);
for (i = 0; i < size; i ++) {
memcpy_P(&pinval, &(data[i]), sizeof(pinval));
if (flg_show_contents) {
#if 1
TRACE("[% 4d] % 6" PRIu32 "(0x%04" PRIX32 ") --> 0x%02X,0x%02X%s\n", i, pinval.uchar, pinval.uchar, (unsigned int)(pinval.idx), (unsigned int)(pinval.idx2), (preval.uchar < pinval.uchar?"":" <--- ERROR"));
#else
TRACE("[% 4d]", i);
TRACE("% 6" PRIu32 "(0x%04" PRIX32 "),", pinval.uchar, pinval.uchar);
TRACE("0x%02X,", (unsigned int)(pinval.idx));
TRACE("0x%02X,", (unsigned int)(pinval.idx2));
TRACE("%s", (preval.uchar < pinval.uchar?"":" <--- ERROR"));
#endif
}
if (preval.uchar >= pinval.uchar) {
flg_error = 1;
//TRACE("Error: out of order in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
//return -1;
}
memcpy(&preval, &pinval, sizeof(pinval));
ret = pf_bsearch_r((void *)data, size, pf_bsearch_cb_comp_dwinmap_pgm, (void *)&pinval, &idx);
if (ret < 0) {
flg_error = 1;
TRACE("Error: not found item in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
//return -1;
}
if (idx != i) {
flg_error = 1;
TRACE("Error: wrong index found item in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
//return -1;
}
}
if (flg_error) {
TRACE("\nError: in array %s\n\n", name);
return -1;
}
TRACE("\nPASS array %s\n\n", name);
return 0;
}
int test_dwin_charmap_all() {
int flg_error = 0;
if (test_dwin_charmap(g_dwin_charmap_device, COUNT(g_dwin_charmap_device), "g_dwin_charmap_device", 0) < 0) {
flg_error = 1;
test_dwin_charmap(g_dwin_charmap_device, COUNT(g_dwin_charmap_device), "g_dwin_charmap_device", 1);
}
if (test_dwin_charmap(g_dwin_charmap_common, COUNT(g_dwin_charmap_common), "g_dwin_charmap_common", 0) < 0) {
flg_error = 1;
test_dwin_charmap(g_dwin_charmap_common, COUNT(g_dwin_charmap_common), "g_dwin_charmap_common", 1);
}
if (flg_error) {
TRACE("\nFAILED in dwin tests!\n");
return -1;
}
TRACE("\nPASS in dwin tests.\n");
return 0;
}
#endif // DEBUG_LCDPRINT
#endif // IS_DWIN_MARLINUI

View file

@ -0,0 +1,30 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 "../../lcdprint.h"
typedef struct { int16_t x, y; } cursor_t;
extern cursor_t cursor;
int lcd_put_dwin_string();
void lcd_moveto_xy(const lcd_uint_t, const lcd_uint_t);

View file

@ -0,0 +1,146 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* lcd/e3v2/marlinui/lcdprint_dwin.h
*/
#include "../../../inc/MarlinConfigPre.h"
#include "dwin_lcd.h"
typedef uint16_t dwin_coord_t; // Screen can be pretty big
typedef uint16_t lcd_uint_t;
typedef int16_t lcd_int_t;
typedef struct {
uint8_t index, width, height;
uint16_t fg, bg;
bool solid;
} dwin_font_t;
extern dwin_font_t dwin_font;
// Only Western languages support big / small fonts
//#if DISABLED(DISPLAY_CHARSET_ISO10646_1)
// #undef USE_BIG_EDIT_FONT
// #undef USE_SMALL_INFOFONT
//#endif
#if ENABLED(USE_BIG_EDIT_FONT)
#define DWIN_FONT_EDIT font10x20
#else
#define DWIN_FONT_EDIT font8x16
#endif
#define DWIN_FONT_INFO font8x16
#if DWIN_FONT_MENU == font6x12
#define MENU_FONT_WIDTH 6
#define MENU_FONT_ASCENT 10
#define MENU_FONT_DESCENT 2
#elif DWIN_FONT_MENU == font8x16
#define MENU_FONT_WIDTH 8
#define MENU_FONT_ASCENT 13
#define MENU_FONT_DESCENT 3
#elif DWIN_FONT_MENU == font10x20
#define MENU_FONT_WIDTH 10
#define MENU_FONT_ASCENT 16
#define MENU_FONT_DESCENT 4
#endif
#define MENU_FONT_HEIGHT (MENU_FONT_ASCENT + MENU_FONT_DESCENT)
#define EXTRA_ROW_HEIGHT 8
#define MENU_LINE_HEIGHT (MENU_FONT_HEIGHT + EXTRA_ROW_HEIGHT)
#if DWIN_FONT_EDIT == font6x12
#define EDIT_FONT_WIDTH 6
#define EDIT_FONT_ASCENT 10
#define EDIT_FONT_DESCENT 2
#elif DWIN_FONT_EDIT == font8x16
#define EDIT_FONT_WIDTH 8
#define EDIT_FONT_ASCENT 13
#define EDIT_FONT_DESCENT 3
#elif DWIN_FONT_EDIT == font10x20
#define EDIT_FONT_WIDTH 10
#define EDIT_FONT_ASCENT 16
#define EDIT_FONT_DESCENT 4
#endif
#define EDIT_FONT_HEIGHT (EDIT_FONT_ASCENT + EDIT_FONT_DESCENT)
#if DWIN_FONT_INFO == font6x12
#define INFO_FONT_WIDTH 6
#define INFO_FONT_ASCENT 10
#define INFO_FONT_DESCENT 2
#elif DWIN_FONT_INFO == font8x16
#define INFO_FONT_WIDTH 8
#define INFO_FONT_ASCENT 13
#define INFO_FONT_DESCENT 3
#elif DWIN_FONT_INFO == font10x20
#define INFO_FONT_WIDTH 10
#define INFO_FONT_ASCENT 16
#define INFO_FONT_DESCENT 4
#endif
#define INFO_FONT_HEIGHT (INFO_FONT_ASCENT + INFO_FONT_DESCENT)
#if DWIN_FONT_STAT == font6x12
#define STAT_FONT_WIDTH 6
#define STAT_FONT_ASCENT 10
#define STAT_FONT_DESCENT 2
#elif DWIN_FONT_STAT == font8x16
#define STAT_FONT_WIDTH 8
#define STAT_FONT_ASCENT 13
#define STAT_FONT_DESCENT 3
#elif DWIN_FONT_STAT == font10x20
#define STAT_FONT_WIDTH 10
#define STAT_FONT_ASCENT 16
#define STAT_FONT_DESCENT 4
#elif DWIN_FONT_STAT == font12x24
#define STAT_FONT_WIDTH 12
#define STAT_FONT_ASCENT 19
#define STAT_FONT_DESCENT 5
#elif DWIN_FONT_STAT == font14x28
#define STAT_FONT_WIDTH 14
#define STAT_FONT_ASCENT 22
#define STAT_FONT_DESCENT 6
#elif DWIN_FONT_STAT == font16x32
#define STAT_FONT_WIDTH 16
#define STAT_FONT_ASCENT 26
#define STAT_FONT_DESCENT 6
#elif DWIN_FONT_STAT == font20x40
#define STAT_FONT_WIDTH 20
#define STAT_FONT_ASCENT 32
#define STAT_FONT_DESCENT 8
#elif DWIN_FONT_STAT == font24x48
#define STAT_FONT_WIDTH 24
#define STAT_FONT_ASCENT 38
#define STAT_FONT_DESCENT 10
#elif DWIN_FONT_STAT == font28x56
#define STAT_FONT_WIDTH 28
#define STAT_FONT_ASCENT 44
#define STAT_FONT_DESCENT 12
#elif DWIN_FONT_STAT == font32x64
#define STAT_FONT_WIDTH 32
#define STAT_FONT_ASCENT 50
#define STAT_FONT_DESCENT 14
#endif
#define STAT_FONT_HEIGHT (STAT_FONT_ASCENT + STAT_FONT_DESCENT)

View file

@ -0,0 +1,595 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 <http://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfigPre.h"
#if IS_DWIN_MARLINUI
#include "marlinui_dwin.h"
#include "dwin_lcd.h"
#include "dwin_string.h"
//#include "../../lcdprint.h"
#include "lcdprint_dwin.h"
#include "../../fontutils.h"
#include "../../../libs/numtostr.h"
#include "../../marlinui.h"
#include "../../../sd/cardreader.h"
#include "../../../module/motion.h"
#include "../../../module/temperature.h"
#include "../../../module/printcounter.h"
#if ENABLED(SDSUPPORT)
#include "../../../libs/duration_t.h"
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
#include "../../../feature/bedlevel/bedlevel.h"
#endif
// DWIN printing specifies the font on each string operation
// but we'll make the font modal for Marlin
dwin_font_t dwin_font = { font8x16, 8, 16, Color_White, Color_Bg_Black, true };
void MarlinUI::set_font(const uint8_t font_nr) {
if (font_nr != dwin_font.index) {
dwin_font.index = font_nr;
uint8_t w, h;
switch (font_nr) {
default:
case font6x12: w = 6; h = 12; break;
case font8x16: w = 8; h = 16; break;
case font10x20: w = 10; h = 20; break;
case font12x24: w = 12; h = 24; break;
case font14x28: w = 14; h = 28; break;
case font16x32: w = 16; h = 32; break;
case font20x40: w = 20; h = 40; break;
case font24x48: w = 24; h = 48; break;
case font28x56: w = 28; h = 56; break;
case font32x64: w = 32; h = 64; break;
}
dwin_font.width = w;
dwin_font.height = h;
// TODO: Array with dimensions, auto fit menu items,
// update char width / height of the screen based on
// new (fixed-width) font size.
}
}
// This display is always detected
bool MarlinUI::detected() { return true; }
// Initialize or re-initialize the LCD
void MarlinUI::init_lcd() {
DWIN_Startup();
// Load the assets JPG (currently just the status screen 'icon')
DWIN_JPG_CacheToN(1, DWIN_MarlinUI_Assets);
}
// This LCD should clear where it will draw anew
void MarlinUI::clear_lcd() {
DWIN_ICON_AnimationControl(0x0000); // disable all icon animations
DWIN_Frame_Clear(Color_Bg_Black);
DWIN_UpdateLCD();
did_first_redraw = false;
}
#if ENABLED(SHOW_BOOTSCREEN)
void MarlinUI::show_bootscreen() {
clear_lcd();
dwin_string.set(F(SHORT_BUILD_VERSION));
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
#define LOGO_CENTER ((LCD_PIXEL_WIDTH) / 2)
#define INFO_CENTER LOGO_CENTER
#define VERSION_Y 330
DWIN_ICON_Show(BOOT_ICON, ICON_MarlinBoot, LOGO_CENTER - 266 / 2, 15);
DWIN_ICON_Show(BOOT_ICON, ICON_OpenSource, LOGO_CENTER - 174 / 2, 280);
DWIN_ICON_Show(BOOT_ICON, ICON_GitHubURL, LOGO_CENTER - 180 / 2, 420);
DWIN_ICON_Show(BOOT_ICON, ICON_MarlinURL, LOGO_CENTER - 100 / 2, 440);
DWIN_ICON_Show(BOOT_ICON, ICON_Copyright, LOGO_CENTER - 126 / 2, 460);
#else
#define LOGO_CENTER (280 / 2)
#define INFO_CENTER ((LCD_PIXEL_WIDTH) - 200 / 2)
#define VERSION_Y 84
DWIN_ICON_Show(BOOT_ICON, ICON_MarlinBoot, LOGO_CENTER - 266 / 2, 15);
DWIN_ICON_Show(BOOT_ICON, ICON_OpenSource, INFO_CENTER - 174 / 2, 60);
DWIN_ICON_Show(BOOT_ICON, ICON_GitHubURL, INFO_CENTER - 180 / 2, 130);
DWIN_ICON_Show(BOOT_ICON, ICON_MarlinURL, INFO_CENTER - 100 / 2, 152);
DWIN_ICON_Show(BOOT_ICON, ICON_Copyright, INFO_CENTER - 126 / 2, 200);
#endif
DWIN_Draw_String(false, font10x20, Color_Yellow, Color_Bg_Black, INFO_CENTER - (dwin_string.length() * 10) / 2, VERSION_Y, S(dwin_string.string()));
DWIN_UpdateLCD();
}
void MarlinUI::bootscreen_completion(const millis_t sofar) {
if ((BOOTSCREEN_TIMEOUT) > sofar) safe_delay((BOOTSCREEN_TIMEOUT) - sofar);
clear_lcd();
}
#endif
// The kill screen is displayed for unrecoverable conditions
void MarlinUI::draw_kill_screen() {
set_font(DWIN_FONT_ALERT);
DWIN_Frame_Clear(Color_Bg_Black);
dwin_font.fg = Color_Error_Red;
dwin_font.solid = false;
DWIN_Draw_Rectangle(1, Color_Bg_Window, 20, 20, LCD_PIXEL_WIDTH - 20, LCD_PIXEL_HEIGHT - 20);
// make the frame a few pixels thick
DWIN_Draw_Rectangle(0, Color_Yellow, 20, 20, LCD_PIXEL_WIDTH - 20, LCD_PIXEL_HEIGHT - 20);
DWIN_Draw_Rectangle(0, Color_Yellow, 21, 21, LCD_PIXEL_WIDTH - 21, LCD_PIXEL_HEIGHT - 21);
DWIN_Draw_Rectangle(0, Color_Yellow, 22, 22, LCD_PIXEL_WIDTH - 22, LCD_PIXEL_HEIGHT - 22);
uint8_t cx = (LCD_PIXEL_WIDTH / dwin_font.width / 2),
cy = (LCD_PIXEL_HEIGHT / dwin_font.height / 2);
#if ENABLED(DWIN_MARLINUI_LANDSCAPE)
cx += (96 / 2 / dwin_font.width);
DWIN_ICON_Show(ICON, ICON_Halted, 40, (LCD_PIXEL_HEIGHT - 96) / 2);
#else
DWIN_ICON_Show(ICON, ICON_Halted, (LCD_PIXEL_WIDTH - 96) / 2, 40);
#endif
uint8_t slen = utf8_strlen(status_message);
lcd_moveto(cx - (slen / 2), cy - 1);
lcd_put_u8str(status_message);
slen = utf8_strlen(S(GET_TEXT_F(MSG_HALTED)));
lcd_moveto(cx - (slen / 2), cy);
lcd_put_u8str_P((const char*)GET_TEXT_F(MSG_HALTED));
slen = utf8_strlen(S(GET_TEXT_F(MSG_HALTED)));
lcd_moveto(cx - (slen / 2), cy + 1);
lcd_put_u8str_P((const char*)GET_TEXT_F(MSG_HALTED));
}
//
// Status Message
//
void MarlinUI::draw_status_message(const bool blink) {
set_font(DWIN_FONT_STAT);
dwin_font.solid = true;
dwin_font.fg = Color_White;
dwin_font.bg = Color_Bg_Black;
lcd_moveto_xy(0, LCD_PIXEL_HEIGHT - (STAT_FONT_HEIGHT) - 1);
constexpr uint8_t max_status_chars = (LCD_PIXEL_WIDTH) / (STAT_FONT_WIDTH);
auto status_changed = []{
static uint16_t old_hash = 0x0000;
uint16_t hash = 0x0000;
for (uint8_t i = 0; i < MAX_MESSAGE_LENGTH; i++) {
const char c = ui.status_message[i];
if (!c) break;
hash = ((hash << 1) | (hash >> 15)) ^ c;
}
const bool hash_changed = hash != old_hash;
old_hash = hash;
return hash_changed || !ui.did_first_redraw;
};
#if ENABLED(STATUS_MESSAGE_SCROLLING)
static bool last_blink = false;
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(status_message);
// If the string fits into the LCD, just print it and do not scroll it
if (slen <= max_status_chars) {
if (status_changed()) {
// The string isn't scrolling and may not fill the screen
lcd_put_u8str(status_message);
// Fill the rest with spaces
while (slen < max_status_chars) { lcd_put_wchar(' '); ++slen; }
}
}
else {
// String is larger than the available line space
// Get a pointer to the next valid UTF8 character
// and the string remaining length
uint8_t rlen;
const char *stat = status_and_len(rlen);
lcd_put_u8str_max(stat, max_status_chars);
// If the string doesn't completely fill the line...
if (rlen < max_status_chars) {
lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot
uint8_t chars = max_status_chars - rlen; // Amount of space left in characters
if (--chars) { // Draw a second dot if there's space
lcd_put_wchar('.');
if (--chars)
lcd_put_u8str_max(status_message, chars); // Print a second copy of the message
}
}
if (last_blink != blink) {
last_blink = blink;
advance_status_scroll();
}
}
#else
UNUSED(blink);
if (status_changed()) {
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(status_message);
// Just print the string to the LCD
lcd_put_u8str_max(status_message, max_status_chars);
// Fill the rest with spaces if there are missing spaces
while (slen < max_status_chars) { lcd_put_wchar(' '); ++slen; }
}
#endif
}
#if HAS_LCD_MENU
#include "../../menu/menu.h"
#if ENABLED(ADVANCED_PAUSE_FEATURE)
void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) {
dwin_font.solid = false;
dwin_font.fg = Color_White;
dwin_string.set("E");
dwin_string.add('1' + extruder);
dwin_string.add(' ');
dwin_string.add(i16tostr3rj(thermalManager.degHotend(extruder)));
dwin_string.add('/');
if (get_blink() || !thermalManager.heater_idle[thermalManager.idle_index_for_id(extruder)].timed_out)
dwin_string.add(i16tostr3rj(thermalManager.degTargetHotend(extruder)));
else
dwin_string.add(PSTR(" "));
lcd_moveto(LCD_WIDTH - dwin_string.length(), row);
lcd_put_dwin_string();
}
#endif
// Set the colors for a menu item based on whether it is selected
static bool mark_as_selected(const uint8_t row, const bool sel, const bool is_static=false) {
const dwin_coord_t y = row * (MENU_LINE_HEIGHT) + 1;
if (y >= LCD_PIXEL_HEIGHT) return false;
if (is_static && sel)
DWIN_Draw_Box(1, Color_Bg_Heading, 0, y, LCD_PIXEL_WIDTH, MENU_LINE_HEIGHT - 1);
else {
#if ENABLED(MENU_HOLLOW_FRAME)
DWIN_Draw_Box(1, Color_Bg_Black, 0, y, LCD_PIXEL_WIDTH, MENU_LINE_HEIGHT - 1);
if (sel) DWIN_Draw_Box(0, Select_Color, 0, y, LCD_PIXEL_WIDTH, MENU_LINE_HEIGHT - 1);
#else
DWIN_Draw_Box(1, sel ? Select_Color : Color_Bg_Black, 0, y, LCD_PIXEL_WIDTH, MENU_LINE_HEIGHT - 1);
#endif
}
return true;
}
// Draw a static line of text in the same idiom as a menu item
void MenuItem_static::draw(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const vstr/*=nullptr*/) {
// Call mark_as_selected to draw a bigger selection box
// and draw the text without a background
if (mark_as_selected(row, (bool)(style & SS_INVERT), true)) {
ui.set_font(DWIN_FONT_MENU);
dwin_font.solid = false;
dwin_font.fg = Color_White;
dwin_string.set();
const int8_t plen = pstr ? utf8_strlen_P(pstr) : 0,
vlen = vstr ? utf8_strlen(vstr) : 0;
if (style & SS_CENTER) {
int8_t pad = (LCD_WIDTH - 1 - plen - vlen) / 2;
while (--pad) dwin_string.add(' ');
}
if (plen) dwin_string.add((uint8_t*)pstr, itemIndex, (uint8_t*)itemString);
if (vlen) dwin_string.add((uint8_t*)vstr);
if (style & SS_CENTER) {
int8_t pad = (LCD_WIDTH - 1 - plen - vlen) / 2;
while (--pad) dwin_string.add(' ');
}
lcd_moveto(1, row);
lcd_put_dwin_string();
}
}
// Draw a generic menu item
void MenuItemBase::_draw(const bool sel, const uint8_t row, PGM_P const pstr, const char, const char post_char) {
if (mark_as_selected(row, sel)) {
ui.set_font(DWIN_FONT_MENU);
dwin_font.solid = false;
dwin_font.fg = Color_White;
dwin_string.set(pstr, itemIndex, itemString);
pixel_len_t n = LCD_WIDTH - 1 - dwin_string.length();
while (--n > 1) dwin_string.add(' ');
dwin_string.add(post_char);
lcd_moveto(1, row);
lcd_put_dwin_string();
}
}
//
// Draw a menu item with an editable value
//
void MenuEditItemBase::draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
if (mark_as_selected(row, sel)) {
ui.set_font(DWIN_FONT_MENU);
dwin_font.solid = false;
dwin_font.fg = Color_White;
const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen(S(data)));
dwin_string.set(pstr, itemIndex, itemString);
if (vallen) dwin_string.add(':');
lcd_moveto(1, row);
lcd_put_dwin_string();
if (vallen) {
dwin_font.fg = Color_Yellow;
dwin_string.set(data);
lcd_moveto(LCD_WIDTH - vallen - 1, row);
lcd_put_dwin_string();
}
}
}
//
// Draw an edit screen with label and current value
//
void MenuEditItemBase::draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
ui.encoder_direction_normal();
const dwin_coord_t labellen = utf8_strlen_P(pstr), vallen = utf8_strlen(value);
dwin_string.set();
dwin_string.add((uint8_t*)pstr, itemIndex);
if (vallen) dwin_string.add(':'); // If a value is included, add a colon
// Assume the label is alpha-numeric (with a descender)
const uint16_t row = (LCD_HEIGHT / 2) - 1;
dwin_font.fg = Color_White;
dwin_font.solid = true;
lcd_moveto((LCD_WIDTH - labellen + !!vallen) / 2, row);
lcd_put_dwin_string();
// If a value is included, print the value in larger text below the label
if (vallen) {
dwin_string.set();
dwin_string.add(value);
const dwin_coord_t by = (row * MENU_LINE_HEIGHT) + MENU_FONT_HEIGHT + EXTRA_ROW_HEIGHT / 2;
DWIN_Draw_String(true, font16x32, Color_Yellow, Color_Bg_Black, (LCD_PIXEL_WIDTH - vallen * 16) / 2, by, S(dwin_string.string()));
extern screenFunc_t _manual_move_func_ptr;
if (ui.currentScreen != _manual_move_func_ptr && !ui.external_control) {
const dwin_coord_t slider_length = LCD_PIXEL_WIDTH - TERN(DWIN_MARLINUI_LANDSCAPE, 120, 20),
slider_height = 16,
slider_x = (LCD_PIXEL_WIDTH - slider_length) / 2,
slider_y = by + 32 + 4,
amount = ui.encoderPosition * slider_length / maxEditValue;
DWIN_Draw_Rectangle(1, Color_Bg_Window, slider_x - 1, slider_y - 1, slider_x - 1 + slider_length + 2 - 1, slider_y - 1 + slider_height + 2 - 1);
if (amount > 0)
DWIN_Draw_Box(1, BarFill_Color, slider_x, slider_y, amount, slider_height);
if (amount < slider_length)
DWIN_Draw_Box(1, Color_Bg_Black, slider_x + amount, slider_y, slider_length - amount, slider_height);
}
}
}
inline void draw_boxed_string(const bool yesopt, PGM_P const pstr, const bool inv) {
const uint8_t len = utf8_strlen_P(pstr),
mar = TERN(DWIN_MARLINUI_PORTRAIT, 1, 4),
col = yesopt ? LCD_WIDTH - mar - len : mar,
row = (LCD_HEIGHT >= 8 ? LCD_HEIGHT / 2 + 3 : LCD_HEIGHT - 1);
lcd_moveto(col, row);
DWIN_Draw_Box(1, inv ? Select_Color : Color_Bg_Black, cursor.x - dwin_font.width, cursor.y + 1, dwin_font.width * (len + 2), dwin_font.height + 2);
lcd_put_u8str_P(col, row, pstr);
}
void MenuItem_confirm::draw_select_screen(
PGM_P const yes, PGM_P const no, const bool yesno,
PGM_P const pref, const char * const string/*=nullptr*/, PGM_P const suff/*=nullptr*/
) {
ui.set_font(DWIN_FONT_MENU);
dwin_font.solid = false;
dwin_font.fg = Color_White;
ui.draw_select_screen_prompt(pref, string, suff);
draw_boxed_string(false, no, !yesno);
draw_boxed_string(true, yes, yesno);
}
#if ENABLED(SDSUPPORT)
void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
if (mark_as_selected(row, sel)) {
dwin_string.set();
uint8_t maxlen = LCD_WIDTH - 1;
if (isDir) {
dwin_string.add(LCD_STR_FOLDER " ");
maxlen -= 2;
}
dwin_string.add((uint8_t*)ui.scrolled_filename(theCard, maxlen, row, sel), maxlen);
uint8_t n = maxlen - dwin_string.length();
while (n > 0) { dwin_string.add(' '); --n; }
lcd_moveto(1, row);
lcd_put_dwin_string();
}
}
#endif // SDSUPPORT
#if ENABLED(AUTO_BED_LEVELING_UBL)
/**
* UBL LCD "radar" map data
*/
#define MAP_UPPER_LEFT_CORNER_X 5 // These probably should be moved to the .h file But for now,
#define MAP_UPPER_LEFT_CORNER_Y 5 // it is easier to play with things having them here
#define MAP_MAX_PIXELS_X 262 // 272 - 10
#define MAP_MAX_PIXELS_Y 262
void MarlinUI::ubl_plot(const uint8_t x_plot, const uint8_t y_plot) {
// Scale the box pixels appropriately
dwin_coord_t x_map_pixels = ((MAP_MAX_PIXELS_X - 4) / (GRID_MAX_POINTS_X)) * (GRID_MAX_POINTS_X),
y_map_pixels = ((MAP_MAX_PIXELS_Y - 4) / (GRID_MAX_POINTS_Y)) * (GRID_MAX_POINTS_Y),
pixels_per_x_mesh_pnt = x_map_pixels / (GRID_MAX_POINTS_X),
pixels_per_y_mesh_pnt = y_map_pixels / (GRID_MAX_POINTS_Y),
x_offset = MAP_UPPER_LEFT_CORNER_X + 1 + (MAP_MAX_PIXELS_X - x_map_pixels - 2) / 2,
y_offset = MAP_UPPER_LEFT_CORNER_Y + 1 + (MAP_MAX_PIXELS_Y - y_map_pixels - 2) / 2;
// Clear the Mesh Map
// First draw the bigger box in White so we have a border around the mesh map box
DWIN_Draw_Rectangle(1, Color_White, x_offset - 2, y_offset - 2, x_offset + 2 + x_map_pixels, y_offset + 2 + y_map_pixels);
// Now actually clear the mesh map box
DWIN_Draw_Rectangle(1, Color_Bg_Black, x_offset, y_offset, x_offset + x_map_pixels, y_offset + y_map_pixels);
// Fill in the Specified Mesh Point
const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y - 1) - y_plot; // The origin is typically in the lower right corner. We need to
// invert the Y to get it to plot in the right location.
const dwin_coord_t by = y_offset + y_plot_inv * pixels_per_y_mesh_pnt;
DWIN_Draw_Rectangle(1, Select_Color,
x_offset + (x_plot * pixels_per_x_mesh_pnt), by,
x_offset + (x_plot * pixels_per_x_mesh_pnt) + pixels_per_x_mesh_pnt, by + pixels_per_y_mesh_pnt
);
// Display Mesh Point Locations
const dwin_coord_t sx = x_offset + pixels_per_x_mesh_pnt / 2;
dwin_coord_t y = y_offset + pixels_per_y_mesh_pnt / 2;
for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++, y += pixels_per_y_mesh_pnt)
for (uint8_t i = 0, x = sx; i < GRID_MAX_POINTS_X; i++, x += pixels_per_x_mesh_pnt)
DWIN_Draw_Point(Color_White, 1, 1, x, y);
// Put Relevant Text on Display
// Show X and Y positions at top of screen
dwin_font.fg = Color_White;
dwin_font.solid = true;
const xy_pos_t pos = { ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot) },
lpos = pos.asLogical();
lcd_moveto(
TERN(DWIN_MARLINUI_LANDSCAPE, ((x_offset + x_map_pixels) / MENU_FONT_WIDTH) + 2, 1),
TERN(DWIN_MARLINUI_LANDSCAPE, 1, ((y_offset + y_map_pixels) / MENU_LINE_HEIGHT) + 1)
);
lcd_put_u8str_P(X_LBL);
lcd_put_u8str(ftostr52(lpos.x));
lcd_moveto(
TERN(DWIN_MARLINUI_LANDSCAPE, ((x_offset + x_map_pixels) / MENU_FONT_WIDTH) + 2, 1),
TERN(DWIN_MARLINUI_LANDSCAPE, 3, ((y_offset + y_map_pixels) / MENU_LINE_HEIGHT) + 2)
);
lcd_put_u8str_P(Y_LBL);
lcd_put_u8str(ftostr52(lpos.y));
// Print plot position
dwin_string.set("(");
dwin_string.add(i8tostr3rj(x_plot));
dwin_string.add(",");
dwin_string.add(i8tostr3rj(y_plot));
dwin_string.add(")");
lcd_moveto(
TERN(DWIN_MARLINUI_LANDSCAPE, ((x_offset + x_map_pixels) / MENU_FONT_WIDTH) + 2, LCD_WIDTH - dwin_string.length()),
TERN(DWIN_MARLINUI_LANDSCAPE, LCD_HEIGHT - 2, ((y_offset + y_map_pixels) / MENU_LINE_HEIGHT) + 1)
);
lcd_put_dwin_string();
// Show the location value
dwin_string.set(Z_LBL);
if (!isnan(ubl.z_values[x_plot][y_plot]))
dwin_string.add(ftostr43sign(ubl.z_values[x_plot][y_plot]));
else
dwin_string.add(PSTR(" -----"));
lcd_moveto(
TERN(DWIN_MARLINUI_LANDSCAPE, ((x_offset + x_map_pixels) / MENU_FONT_WIDTH) + 2, LCD_WIDTH - dwin_string.length()),
TERN(DWIN_MARLINUI_LANDSCAPE, LCD_HEIGHT - 1, ((y_offset + y_map_pixels) / MENU_LINE_HEIGHT) + 2)
);
lcd_put_dwin_string();
}
#endif // AUTO_BED_LEVELING_UBL
#if ANY(BABYSTEP_ZPROBE_GFX_OVERLAY, MESH_EDIT_GFX_OVERLAY, BABYSTEP_GFX_OVERLAY)
void _lcd_zoffset_overlay_gfx(const float zvalue) {
// Determine whether the user is raising or lowering the nozzle.
static int8_t dir;
static float old_zvalue;
if (zvalue != old_zvalue) {
dir = zvalue ? zvalue < old_zvalue ? -1 : 1 : 0;
old_zvalue = zvalue;
}
const int rot_up = TERN(OVERLAY_GFX_REVERSE, ICON_RotateCCW, ICON_RotateCW),
rot_down = TERN(OVERLAY_GFX_REVERSE, ICON_RotateCW, ICON_RotateCCW);
const int nozzle = (LCD_PIXEL_WIDTH / 2) - 20;
// Draw a representation of the nozzle
DWIN_Draw_Box(1, Color_Bg_Black, nozzle + 3, 8, 48, 52); // 'clear' the area where the nozzle is drawn in case it was moved up/down
DWIN_ICON_Show(ICON, ICON_HotendOff, nozzle + 3, 10 - dir);
DWIN_ICON_Show(ICON, ICON_BedLine, nozzle, 10 + 36);
// Draw cw/ccw indicator and up/down arrows
const int arrow_y = LCD_PIXEL_HEIGHT / 2 - 24;
DWIN_ICON_Show(ICON, ICON_DownArrow, 0, arrow_y - dir);
DWIN_ICON_Show(ICON, rot_down, 48, arrow_y);
DWIN_ICON_Show(ICON, ICON_UpArrow, LCD_PIXEL_WIDTH - 10 - (48*2), arrow_y - dir);
DWIN_ICON_Show(ICON, rot_up, LCD_PIXEL_WIDTH - 10 - 48, arrow_y);
}
#endif // BABYSTEP_ZPROBE_GFX_OVERLAY || MESH_EDIT_GFX_OVERLAY
#endif // HAS_LCD_MENU
#endif // IS_DWIN_MARLINUI

View file

@ -0,0 +1,391 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 <http://www.gnu.org/licenses/>.
*
*/
#include "../../../inc/MarlinConfigPre.h"
#if IS_DWIN_MARLINUI
#include "marlinui_dwin.h"
#include "dwin_lcd.h"
#include "dwin_string.h"
#include "lcdprint_dwin.h"
#include "../../fontutils.h"
#include "../../../libs/numtostr.h"
#include "../../marlinui.h"
#include "../../../sd/cardreader.h"
#include "../../../module/motion.h"
#include "../../../module/temperature.h"
#include "../../../module/printcounter.h"
#if ENABLED(SDSUPPORT)
#include "../../../libs/duration_t.h"
#endif
#if ENABLED(LCD_SHOW_E_TOTAL)
#include "../../../MarlinCore.h" // for printingIsActive
#endif
#define STATUS_HEATERS_X 15
#define STATUS_HEATERS_Y 56
#define STATUS_HEATERS_XSPACE 64
#define STATUS_FAN_WIDTH 48
#define STATUS_FAN_HEIGHT 48
#define STATUS_FAN_Y STATUS_HEATERS_Y + 22
#define STATUS_CHR_WIDTH 14
#define STATUS_CHR_HEIGHT 28
//
// Before homing, blink '123' <-> '???'.
// Homed but unknown... '123' <-> ' '.
// Homed and known, display constantly.
//
FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const bool blink, const uint16_t x, const uint16_t y) {
uint8_t vallen = utf8_strlen(value);
if (!ui.did_first_redraw) {
dwin_string.set();
dwin_string.add('X' + axis);
DWIN_Draw_String(true, font16x32, Color_IconBlue, Color_Bg_Black, x + (vallen * 14 - 14) / 2, y + 2, S(dwin_string.string()));
}
dwin_string.set();
if (blink)
dwin_string.add(value);
else {
if (!TEST(axis_homed, axis))
while (const char c = *value++) dwin_string.add(c <= '.' ? c : '?');
else {
#if NONE(HOME_AFTER_DEACTIVATE, DISABLE_REDUCED_ACCURACY_WARNING)
if (!TEST(axis_trusted, axis))
dwin_string.add(TERN1(DWIN_MARLINUI_PORTRAIT, axis == Z_AXIS) ? PSTR(" ") : PSTR(" "));
else
#endif
dwin_string.add(value);
}
}
// For E_TOTAL there may be some characters to cover up
if (BOTH(DWIN_MARLINUI_PORTRAIT, LCD_SHOW_E_TOTAL) && axis == X_AXIS)
dwin_string.add(" ");
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + 32, S(dwin_string.string()));
}
#if ENABLED(LCD_SHOW_E_TOTAL)
FORCE_INLINE void _draw_e_value(const_float_t value, const uint16_t x, const uint16_t y) {
const uint8_t scale = value >= 100000.0f ? 10 : 1; // show cm after 99,999mm
if (!ui.did_first_redraw) {
// Extra spaces so we don't have to clear the 'Y' label separately
dwin_string.set("E ");
DWIN_Draw_String(true, font16x32, Color_IconBlue, Color_Bg_Black, x + (4 * 14 / 2) - 7, y + 2, S(dwin_string.string()));
}
dwin_string.set(ui16tostr5rj(value / scale));
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + 32, S(dwin_string.string()));
// Extra spaces so we don't have to clear out the Y value separately
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, x + (5 * 14), y + 32, S(scale == 1 ? "mm " : "cm "));
}
#endif
//
// Fan Icon and Percentage
//
FORCE_INLINE void _draw_fan_status(const uint16_t x, const uint16_t y) {
const uint16_t fanx = (4 * STATUS_CHR_WIDTH - STATUS_FAN_WIDTH) / 2;
const uint8_t fan_pct = thermalManager.scaledFanSpeedPercent(0);
const bool fan_on = !!fan_pct;
if (fan_on) {
DWIN_ICON_Animation(0, fan_on, ICON, ICON_Fan0, ICON_Fan3, x + fanx, y, 25);
dwin_string.set(i8tostr3rj(fan_pct));
dwin_string.add('%');
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + STATUS_FAN_HEIGHT, S(dwin_string.string()));
}
else {
DWIN_ICON_Show(ICON, ICON_Fan0, x + fanx, y);
dwin_string.set(PSTR(" "));
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + STATUS_FAN_HEIGHT, S(dwin_string.string()));
}
}
#if HOTENDS > 2
#define HOTEND_STATS 3
#elif HOTENDS > 1
#define HOTEND_STATS 2
#elif HAS_HOTEND
#define HOTEND_STATS 1
#endif
/**
* Draw a single heater icon with current and target temperature, at the given XY
*/
FORCE_INLINE void _draw_heater_status(const heater_id_t heater, const uint16_t x, const uint16_t y) {
#if HAS_HOTEND
static celsius_t old_temp[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, 500),
old_target[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, 500);
static bool old_on[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, false);
#endif
#if HAS_HEATED_BED
static celsius_t old_bed_temp = 500, old_bed_target = 500;
static bool old_bed_on = false;
#endif
#if HAS_HOTEND && HAS_HEATED_BED
const bool isBed = heater < 0;
const float tc = (isBed ? thermalManager.degBed() : thermalManager.degHotend(heater)),
tt = (isBed ? thermalManager.degTargetBed() : thermalManager.degTargetHotend(heater));
const uint8_t ta = isBed ? thermalManager.isHeatingBed() : thermalManager.isHeatingHotend(heater);
const bool c_draw = tc != (isBed ? old_bed_temp : old_temp[heater]),
t_draw = tt != (isBed ? old_bed_target : old_target[heater]),
i_draw = ta != (isBed ? old_bed_on : old_on[heater]);
if (isBed) { old_bed_temp = tc; old_bed_target = tt; old_bed_on = ta; }
else { old_temp[heater] = tc; old_target[heater] = tt; old_on[heater] = ta; }
#elif HAS_HOTEND
constexpr bool isBed = false;
const float tc = thermalManager.degHotend(heater), tt = thermalManager.degTargetHotend(heater);
const uint8_t ta = thermalManager.isHeatingHotend(heater);
const bool c_draw = tc != old_bed_temp, t_draw = tt != old_bed_target, i_draw = ta != old_bed_on;
old_temp[heater] = tc; old_target[heater] = tt; old_on[heater] = ta;
#elif HAS_HEATED_BED
constexpr bool isBed = true;
const float tc = thermalManager.degBed(), tt = thermalManager.degTargetBed();
const uint8_t ta = thermalManager.isHeatingBed();
const bool c_draw = tc != old_temp[heater], t_draw = tt != old_target[heater], i_draw = ta != old_on[heater];
old_bed_temp = tc; old_bed_target = tt; old_bed_on = ta;
#endif
if (!ui.did_first_redraw || t_draw) {
dwin_string.set(i16tostr3rj(tt + 0.5));
dwin_string.add(LCD_STR_DEGREE);
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y, S(dwin_string.string()));
}
if (!ui.did_first_redraw || i_draw)
DWIN_ICON_Show(ICON, (isBed ? ICON_BedOff : ICON_HotendOff) + ta, x, y + STATUS_CHR_HEIGHT + 2);
if (!ui.did_first_redraw || c_draw) {
dwin_string.set(i16tostr3rj(tc + 0.5));
dwin_string.add(LCD_STR_DEGREE);
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + 70, S(dwin_string.string()));
}
}
/**
* Draw the current "feed rate" percentage preceded by the >> character
*/
FORCE_INLINE void _draw_feedrate_status(const char *value, uint16_t x, uint16_t y) {
if (!ui.did_first_redraw) {
dwin_string.set(LCD_STR_FEEDRATE);
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, x, y, S(dwin_string.string()));
}
dwin_string.set(value);
dwin_string.add(PSTR("%"));
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x + 14, y, S(dwin_string.string()));
}
/**
* Draw the MarlinUI Status Screen for Ender 3 V2
*/
void MarlinUI::draw_status_screen() {
const bool blink = get_blink();
// Draw elements that never change
if (!ui.did_first_redraw) {
// Logo/Status Icon
#define STATUS_LOGO_WIDTH 128
#define STATUS_LOGO_HEIGHT 40
DWIN_ICON_Show(ICON, ICON_LOGO_Marlin, (LCD_PIXEL_WIDTH - (STATUS_LOGO_WIDTH)) / 2, ((STATUS_HEATERS_Y - 4) - (STATUS_LOGO_HEIGHT)) / 2);
// Draw a frame around the x/y/z values
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
DWIN_Draw_Rectangle(0, Select_Color, 0, 193, LCD_PIXEL_WIDTH, 260);
#else
//DWIN_Draw_Rectangle(0, Select_Color, LCD_PIXEL_WIDTH - 106, 50, LCD_PIXEL_WIDTH - 1, 230);
#endif
}
uint16_t hx = STATUS_HEATERS_X;
#if HAS_HOTEND
_draw_heater_status(H_E0, hx, STATUS_HEATERS_Y);
hx += STATUS_HEATERS_XSPACE;
#endif
#if HAS_MULTI_HOTEND
_draw_heater_status(H_E1, hx, STATUS_HEATERS_Y);
hx += STATUS_HEATERS_XSPACE;
#endif
#if HAS_HEATED_BED
_draw_heater_status(H_BED, hx, STATUS_HEATERS_Y);
#endif
#if HAS_FAN
// Fan display, pinned to the right side
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
_draw_fan_status(LCD_PIXEL_WIDTH - STATUS_CHR_WIDTH * 4, STATUS_FAN_Y);
#else
_draw_fan_status(212, STATUS_FAN_Y);
#endif
#endif
// Axis values
const xyz_pos_t lpos = current_position.asLogical();
const bool show_e_total = TERN0(LCD_SHOW_E_TOTAL, printingIsActive()); UNUSED(show_e_total);
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
constexpr int16_t cpy = 195;
if (show_e_total) {
TERN_(LCD_SHOW_E_TOTAL, _draw_e_value(e_move_accumulator, 6, cpy));
}
else {
_draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink, 6, cpy);
TERN_(HAS_Y_AXIS, _draw_axis_value(Y_AXIS, ftostr4sign(lpos.y), blink, 95, cpy));
}
TERN_(HAS_Z_AXIS, _draw_axis_value(Z_AXIS, ftostr52sp(lpos.z), blink, 165, cpy));
#else
constexpr int16_t cpx = LCD_PIXEL_WIDTH - 104;
_draw_axis_value(X_AXIS, ftostr52sp(lpos.x), blink, cpx, STATUS_HEATERS_Y);
TERN_(HAS_Y_AXIS, _draw_axis_value(Y_AXIS, ftostr52sp(lpos.y), blink, cpx, STATUS_HEATERS_Y + 59));
TERN_(HAS_Z_AXIS, _draw_axis_value(Z_AXIS, ftostr52sp(lpos.z), blink, cpx, STATUS_HEATERS_Y + 118));
#endif
// Feedrate
static uint16_t old_fp = 0;
if (!ui.did_first_redraw || old_fp != feedrate_percentage) {
old_fp = feedrate_percentage;
_draw_feedrate_status(i16tostr3rj(feedrate_percentage),
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
5, 290
#else
294, STATUS_HEATERS_Y
#endif
);
}
//
// Elapsed time
//
char buffer[14];
duration_t time;
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
// Portrait mode only shows one value at a time, and will rotate if ROTATE_PROGRESS_DISPLAY
dwin_string.set();
char prefix = ' ';
#if ENABLED(SHOW_REMAINING_TIME)
if (TERN1(ROTATE_PROGRESS_DISPLAY, blink) && print_job_timer.isRunning()) {
time = get_remaining_time();
prefix = 'R';
}
else
#endif
time = print_job_timer.duration();
time.toDigital(buffer);
dwin_string.add(prefix);
dwin_string.add(buffer);
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, (LCD_PIXEL_WIDTH - ((dwin_string.length() + 1) * 14)), 290, S(dwin_string.string()));
#else
// landscape mode shows both elapsed and remaining (if SHOW_REMAINING_TIME)
time = print_job_timer.duration();
time.toDigital(buffer);
dwin_string.set(" ");
dwin_string.add(buffer);
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, 280, 100, S(dwin_string.string()));
#if ENABLED(LCD_SHOW_E_TOTAL)
if (show_e_total && TERN1(SHOW_REMAINING_TIME, !blink)) { // if SHOW_REMAINING_TIME is also
const uint8_t escale = e_move_accumulator >= 100000.0f ? 10 : 1; // show cm after 99,000mm
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, 249, 135, S("E"));
dwin_string.set(ui16tostr5rj(e_move_accumulator * escale));
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, 263, 135, S(dwin_string.string()));
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, 333, 135, S(escale==1 ? "mm" : "cm"));
}
#endif
#if ENABLED(SHOW_REMAINING_TIME)
if (!show_e_total || blink) {
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, 249, 135, S(" R "));
time = get_remaining_time();
time.toDigital(buffer);
dwin_string.set(buffer);
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, 291, 135, S(dwin_string.string()));
}
#endif
#endif
//
// Progress Bar
//
constexpr int16_t pb_margin = 5, pb_left = pb_margin, pb_height = 60,
pb_right = LCD_PIXEL_WIDTH - TERN(DWIN_MARLINUI_PORTRAIT, 0, 107) - pb_margin,
pb_bottom = TERN(DWIN_MARLINUI_PORTRAIT, 410, 230),
pb_top = pb_bottom - pb_height,
pb_width = pb_right - pb_left;
const progress_t progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)();
if (!ui.did_first_redraw)
DWIN_Draw_Rectangle(0, Select_Color, pb_left, pb_top, pb_right, pb_bottom); // Outline
static uint16_t old_solid = 50;
const uint16_t pb_solid = (pb_width - 2) * (progress / (PROGRESS_SCALE)) * 0.01f;
const bool p_draw = !ui.did_first_redraw || old_solid != pb_solid;
if (p_draw) {
//if (pb_solid)
DWIN_Draw_Rectangle(1, Select_Color, pb_left + 1, pb_top + 1, pb_left + pb_solid, pb_bottom - 1); // Fill the solid part
//if (pb_solid < old_solid)
DWIN_Draw_Rectangle(1, Color_Bg_Black, pb_left + 1 + pb_solid, pb_top + 1, pb_right - 1, pb_bottom - 1); // Erase the rest
#if ENABLED(SHOW_SD_PERCENT)
dwin_string.set(TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(progress), ui8tostr3rj(progress / (PROGRESS_SCALE))));
dwin_string.add(PSTR("%"));
DWIN_Draw_String(
false, font16x32, Percent_Color, Color_Bg_Black,
pb_left + (pb_width - dwin_string.length() * 16) / 2,
pb_top + (pb_height - 32) / 2,
S(dwin_string.string())
);
#endif
old_solid = pb_solid;
}
//
// Status Message
//
draw_status_message(blink);
ui.did_first_redraw = true;
}
#endif // IS_DWIN_MARLINUI

View file

@ -26,7 +26,7 @@
#include "../inc/MarlinConfigPre.h"
#if HAS_WIRED_LCD && !HAS_GRAPHICAL_TFT
#if HAS_WIRED_LCD && !HAS_GRAPHICAL_TFT && !IS_DWIN_MARLINUI
#include "marlinui.h"
#include "lcdprint.h"

View file

@ -34,7 +34,21 @@
#include "../inc/MarlinConfig.h"
#if HAS_MARLINUI_U8GLIB
#if IS_DWIN_MARLINUI
#include "e3v2/marlinui/marlinui_dwin.h"
#define LCD_PIXEL_WIDTH DWIN_WIDTH
#define LCD_PIXEL_HEIGHT DWIN_HEIGHT
#define LCD_WIDTH ((LCD_PIXEL_WIDTH) / (MENU_FONT_WIDTH))
#define LCD_HEIGHT ((LCD_PIXEL_HEIGHT) / (MENU_LINE_HEIGHT))
// The DWIN lcd_moveto function uses row / column, not pixels
#define LCD_COL_X(col) (col)
#define LCD_ROW_Y(row) (row)
#define LCD_COL_X_RJ(len) (LCD_WIDTH - LCD_COL_X(len))
#elif HAS_MARLINUI_U8GLIB
#include "dogm/u8g_fontutf8.h"
typedef u8g_uint_t lcd_uint_t;
@ -105,7 +119,10 @@
#define MENU_LINE_HEIGHT MENU_FONT_HEIGHT
#endif
#define LCD_COL_X_RJ(len) (LCD_PIXEL_WIDTH - LCD_COL_X(len))
#ifndef LCD_COL_X_RJ
#define LCD_COL_X_RJ(len) (LCD_PIXEL_WIDTH - LCD_COL_X(len))
#endif
#define SETCURSOR(col, row) lcd_moveto(LCD_COL_X(col), LCD_ROW_Y(row))
#define SETCURSOR_RJ(len, row) lcd_moveto(LCD_COL_X_RJ(len), LCD_ROW_Y(row))
#define SETCURSOR_X(col) SETCURSOR(col, _lcdLineNr)

View file

@ -202,6 +202,10 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;
bool MarlinUI::drawing_screen, MarlinUI::first_page; // = false
#endif
#if IS_DWIN_MARLINUI
bool MarlinUI::did_first_redraw;
#endif
// Encoder Handling
#if HAS_ENCODER_ACTION
uint32_t MarlinUI::encoderPosition;
@ -335,6 +339,7 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;
col = (LCD_WIDTH - plen - slen) / 2;
row = LCD_HEIGHT > 3 ? 1 : 0;
}
if (LCD_HEIGHT >= 8) row = LCD_HEIGHT / 2 - 2;
wrap_string_P(col, row, pref, true);
if (string) {
if (col) { col = 0; row++; } // Move to the start of the next line
@ -1073,6 +1078,9 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;
run_current_screen();
// Apply all DWIN drawing after processing
TERN_(IS_DWIN_MARLINUI, DWIN_UpdateLCD());
#endif
TERN_(HAS_LCD_MENU, lcd_clicked = false);

View file

@ -387,14 +387,16 @@ public:
#endif
#if HAS_MARLINUI_U8GLIB
static void set_font(const MarlinFont font_nr);
#elif IS_DWIN_MARLINUI
static void set_font(const uint8_t font_nr);
#endif
#else
#if HAS_MARLINUI_HD44780
static void set_custom_characters(const HD44780CharSet screen_charset=CHARSET_INFO);
#endif
#if ENABLED(LCD_PROGRESS_BAR)
#if ENABLED(LCD_PROGRESS_BAR) && !HAS_MARLINUI_U8GLIB
static millis_t progress_bar_ms; // Start time for the current progress bar cycle
static void draw_progress_bar(const uint8_t percent);
#if PROGRESS_MSG_EXPIRE > 0
@ -403,8 +405,6 @@ public:
#endif
#endif
#endif
static uint8_t lcd_status_update_delay;
#if HAS_LCD_CONTRAST
@ -447,6 +447,10 @@ public:
static constexpr bool drawing_screen = false, first_page = true;
#endif
#if IS_DWIN_MARLINUI
static bool did_first_redraw;
#endif
static bool get_blink();
static void kill_screen(PGM_P const lcd_error, PGM_P const lcd_component);
static void draw_kill_screen();

View file

@ -179,6 +179,8 @@ bool printer_busy() {
void MarlinUI::goto_screen(screenFunc_t screen, const uint16_t encoder/*=0*/, const uint8_t top/*=0*/, const uint8_t items/*=0*/) {
if (currentScreen != screen) {
TERN_(IS_DWIN_MARLINUI, did_first_redraw = false);
TERN_(HAS_TOUCH_BUTTONS, repeat_delay = BUTTON_DELAY_MENU);
TERN_(LCD_SET_PROGRESS_MANUALLY, progress_reset());

View file

@ -39,7 +39,7 @@ typedef void (*selectFunc_t)();
#define SS_INVERT 0x02
#define SS_DEFAULT SS_CENTER
#if HAS_MARLINUI_U8GLIB && EITHER(BABYSTEP_ZPROBE_GFX_OVERLAY, MESH_EDIT_GFX_OVERLAY)
#if EITHER(HAS_MARLINUI_U8GLIB, IS_DWIN_MARLINUI) && EITHER(BABYSTEP_ZPROBE_GFX_OVERLAY, MESH_EDIT_GFX_OVERLAY)
void _lcd_zoffset_overlay_gfx(const_float_t zvalue);
#endif

View file

@ -184,7 +184,7 @@
#define BTN_EN1 PB10
#define BTN_EN2 PA6
#elif ENABLED(DWIN_CREALITY_LCD)
#elif EITHER(DWIN_CREALITY_LCD, IS_DWIN_MARLINUI)
// RET6 DWIN ENCODER LCD
#define BTN_ENC PB14
@ -194,7 +194,7 @@
//#define LCD_LED_PIN PB2
#ifndef BEEPER_PIN
#define BEEPER_PIN PB13
#undef SPEAKER
//#undef SPEAKER
#endif
#elif ENABLED(DWIN_VET6_CREALITY_LCD)

View file

@ -0,0 +1,64 @@
# Generate a 'HZK' font file for the T5UIC1 DWIN LCD
# from multiple bdf font files.
# Note: the 16x16 glyphs are not produced
# Author: Taylor Talkington
# License: GPL
import bdflib.reader
import math
def glyph_bits(size_x, size_y, font, glyph_ord):
asc = font[b'FONT_ASCENT']
desc = font[b'FONT_DESCENT']
bits = [0 for y in range(size_y)]
glyph_bytes = math.ceil(size_x / 8)
try:
glyph = font[glyph_ord]
for y, row in enumerate(glyph.data):
v = row
rpad = size_x - glyph.bbW
if rpad < 0: rpad = 0
if glyph.bbW > size_x: v = v >> (glyph.bbW - size_x) # some glyphs are actually too wide to fit!
v = v << (glyph_bytes * 8) - size_x + rpad
v = v >> glyph.bbX
bits[y + desc + glyph.bbY] |= v
except KeyError:
pass
bits.reverse()
return bits
def marlin_font_hzk():
fonts = [
[6,12,'marlin-6x12-3.bdf'],
[8,16,'marlin-8x16.bdf'],
[10,20,'marlin-10x20.bdf'],
[12,24,'marlin-12x24.bdf'],
[14,28,'marlin-14x28.bdf'],
[16,32,'marlin-16x32.bdf'],
[20,40,'marlin-20x40.bdf'],
[24,48,'marlin-24x48.bdf'],
[28,56,'marlin-28x56.bdf'],
[32,64,'marlin-32x64.bdf']
]
with open('marlin_fixed.hzk','wb') as output:
for f in fonts:
with open(f[2], 'rb') as file:
print(f'{f[0]}x{f[1]}')
font = bdflib.reader.read_bdf(file)
for glyph in range(128):
bits = glyph_bits(f[0], f[1], font, glyph)
glyph_bytes = math.ceil(f[0]/8)
for b in bits:
try:
z = b.to_bytes(glyph_bytes, 'big')
output.write(z)
except OverflowError:
print('Overflow')
print(f'{glyph}')
print(font[glyph])
for b in bits: print(f'{b:0{f[0]}b}')
return

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -13,11 +13,9 @@ use_example_configs "Creality/Ender-3 V2/CrealityUI"
opt_enable MARLIN_DEV_MODE BUFFER_MONITORING
exec_test $1 $2 "Ender 3 v2 with CrealityUI" "$3"
use_example_configs "Creality/Ender-3 V2/CrealityUI"
opt_disable CLASSIC_JERK
use_example_configs "Creality/Ender-3 V2/MarlinUI"
opt_add SDCARD_EEPROM_EMULATION
opt_set TEMP_SENSOR_BED 0
exec_test $1 $2 "Ender 3 v2, SD EEPROM, no CLASSIC_JERK, no Bed" "$3"
exec_test $1 $2 "Ender 3 v2 with MarlinUI" "$3"
restore_configs
opt_set MOTHERBOARD BOARD_CREALITY_V452 SERIAL_PORT 1

View file

@ -45,6 +45,7 @@ I2C_EEPROM = src_filter=+<src/HAL/shared/eeprom_if_i
SOFT_I2C_EEPROM = SlowSoftI2CMaster, SlowSoftWire=https://github.com/felias-fogg/SlowSoftWire/archive/master.zip
SPI_EEPROM = src_filter=+<src/HAL/shared/eeprom_if_spi.cpp>
DWIN_CREALITY_LCD = src_filter=+<src/lcd/e3v2/creality>
DWIN_MARLINUI_.+ = src_filter=+<src/lcd/e3v2/marlinui>
HAS_GRAPHICAL_TFT = src_filter=+<src/lcd/tft>
IS_TFTGLCD_PANEL = src_filter=+<src/lcd/TFTGLCD>
HAS_TOUCH_BUTTONS = src_filter=+<src/lcd/touch/touch_buttons.cpp>

View file

@ -48,7 +48,8 @@ extra_scripts =
post:buildroot/share/PlatformIO/scripts/common-dependencies-post.py
lib_deps =
default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
-<src/lcd/HD44780> -<src/lcd/TFTGLCD> -<src/lcd/e3v2/creality> -<src/lcd/dogm> -<src/lcd/tft> -<src/lcd/tft_io>
-<src/lcd/HD44780> -<src/lcd/TFTGLCD> -<src/lcd/dogm> -<src/lcd/tft> -<src/lcd/tft_io>
-<src/lcd/e3v2/creality> -<src/lcd/e3v2/marlinui>
-<src/HAL/STM32/tft> -<src/HAL/STM32F1/tft>
-<src/lcd/menu>
-<src/lcd/menu/game/game.cpp> -<src/lcd/menu/game/brickout.cpp> -<src/lcd/menu/game/invaders.cpp>