Browse Source

LVGL UI G-code console (#20755)

vanilla_fb_2.0.x
X-Ryl669 3 years ago
committed by GitHub
parent
commit
c74f972627
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      Marlin/src/HAL/AVR/HAL.h
  2. 2
      Marlin/src/HAL/AVR/MarlinSerial.cpp
  3. 8
      Marlin/src/HAL/AVR/MarlinSerial.h
  4. 2
      Marlin/src/HAL/STM32/HAL.h
  5. 1
      Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp
  6. 26
      Marlin/src/HAL/STM32F1/MarlinSerial.h
  7. 4
      Marlin/src/core/macros.h
  8. 7
      Marlin/src/core/serial_hook.h
  9. 109
      Marlin/src/lcd/extui/lib/mks_ui/draw_gcode.cpp
  10. 33
      Marlin/src/lcd/extui/lib/mks_ui/draw_gcode.h
  11. 24
      Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp
  12. 2
      Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp
  13. 34
      Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp
  14. 3
      Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp
  15. 1
      Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
  16. 9
      Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h
  17. 2
      Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h
  18. 50
      Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h
  19. 2
      Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h
  20. 2
      Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h
  21. 2
      Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h
  22. 2
      Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h
  23. 2
      Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h
  24. 16
      Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp
  25. 2
      Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h
  26. 8
      Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h
  27. 5
      buildroot/tests/mega2560-tests
  28. 16
      docs/Serial.md

4
Marlin/src/HAL/AVR/HAL.h

@ -82,14 +82,14 @@ typedef int8_t pin_t;
// Serial ports
#ifdef USBCON
#include "../../core/serial_hook.h"
#include "../../core/serial_hook.h"
typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
extern DefaultSerial MSerial;
#ifdef BLUETOOTH
typedef ForwardSerial0Type< decltype(bluetoothSerial) > BTSerial;
extern BTSerial btSerial;
#endif
#define MYSERIAL0 TERN(BLUETOOTH, btSerial, MSerial)
#else
#if !WITHIN(SERIAL_PORT, -1, 3)

2
Marlin/src/HAL/AVR/MarlinSerial.cpp

@ -611,7 +611,7 @@ MSerialT customizedSerial1(MSerialT::HasEmergencyParser);
template class MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> >;
MSerialT4 lcdSerial(MSerialT4::HasEmergencyParser);
#if HAS_DGUS_LCD
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::get_tx_buffer_free() {

8
Marlin/src/HAL/AVR/MarlinSerial.h

@ -238,11 +238,11 @@
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
};
typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT;
typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT;
extern MSerialT customizedSerial1;
#ifdef SERIAL_PORT_2
typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
@ -262,7 +262,7 @@
static constexpr bool RX_OVERRUNS = false;
};
typedef Serial0Type< MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> > > MSerialT3;
typedef Serial0Type< MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> > > MSerialT3;
extern MSerial3 mmuSerial;
#endif
@ -292,7 +292,7 @@
};
typedef Serial0Type< MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> > > MSerialT4;
typedef Serial0Type< MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> > > MSerialT4;
extern MSerialT4 lcdSerial;
#endif

2
Marlin/src/HAL/STM32/HAL.h

@ -39,7 +39,7 @@
#ifdef USBCON
#include <USBSerial.h>
#include "../../core/serial_hook.h"
#include "../../core/serial_hook.h"
typedef ForwardSerial0Type< decltype(SerialUSB) > DefaultSerial;
extern DefaultSerial MSerial;
#endif

1
Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp

@ -163,7 +163,6 @@
GPIO_InitStruct.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
#if DISABLED(STM32F1xx)
// TODO: use __HAL_RCC_SDIO_RELEASE_RESET() and __HAL_RCC_SDIO_CLK_ENABLE();
RCC->APB2RSTR &= ~RCC_APB2RSTR_SDIORST_Msk; // take SDIO out of reset

26
Marlin/src/HAL/STM32F1/MarlinSerial.h

@ -28,6 +28,10 @@
#include "../../inc/MarlinConfigPre.h"
#include "../../core/serial_hook.h"
#if HAS_TFT_LVGL_UI
extern "C" { extern char public_buf_m[100]; }
#endif
// Increase priority of serial interrupts, to reduce overflow errors
#define UART_IRQ_PRIO 1
@ -45,6 +49,28 @@ struct MarlinSerial : public HardwareSerial {
nvic_irq_set_priority(c_dev()->irq_num, UART_IRQ_PRIO);
}
#endif
#if HAS_TFT_LVGL_UI
// Hook the serial write method to capture the output of GCode command sent via LCD
uint32_t current_wpos;
void (*line_callback)(void *, const char * msg);
void *user_pointer;
void set_hook(void (*hook)(void *, const char *), void * that) { line_callback = hook; user_pointer = that; current_wpos = 0; }
size_t write(uint8_t c) {
if (line_callback) {
if (c == '\n' || current_wpos == sizeof(public_buf_m) - 1) { // End of line, probably end of command anyway
public_buf_m[current_wpos] = 0;
line_callback(user_pointer, public_buf_m);
current_wpos = 0;
}
else
public_buf_m[current_wpos++] = c;
}
return HardwareSerial::write(c);
}
#endif
};
typedef Serial0Type<MarlinSerial> MSerialT;

4
Marlin/src/core/macros.h

@ -320,8 +320,8 @@
template<bool, typename _Tp = void> struct enable_if { };
template<typename _Tp> struct enable_if<true, _Tp> { typedef _Tp type; };
}
// C++11 solution using SFINAE to detect the existance of a member in a class at compile time.
// It creates a HasMember<Type> structure containing 'value' set to true if the member exists
// C++11 solution using SFINAE to detect the existance of a member in a class at compile time.
// It creates a HasMember<Type> structure containing 'value' set to true if the member exists
#define HAS_MEMBER_IMPL(Member) \
namespace Private { \
template <typename Type, typename Yes=char, typename No=long> struct HasMember_ ## Member { \

7
Marlin/src/core/serial_hook.h

@ -131,10 +131,11 @@ struct RuntimeSerial : public SerialBase< RuntimeSerial<SerialT> >, public Seria
using BaseClassT::print;
using BaseClassT::println;
// Underlying implementation might use Arduino's bool operator
bool connected() {
return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected) : static_cast<SerialT*>(this)->operator bool();
}
bool connected() {
return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected) : static_cast<SerialT*>(this)->operator bool();
}
void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) {
// Order is important here as serial code can be called inside interrupts

109
Marlin/src/lcd/extui/lib/mks_ui/draw_gcode.cpp

@ -0,0 +1,109 @@
/**
* 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/>.
*
*/
#include "../../../../inc/MarlinConfigPre.h"
#if HAS_TFT_LVGL_UI
#include "draw_ui.h"
#include <lv_conf.h>
#include "../../../../inc/MarlinConfig.h"
extern lv_group_t *g;
static lv_obj_t *scr,*outL,*outV = 0;
static int currentWritePos = 0;
extern uint8_t public_buf[513];
extern "C" { extern char public_buf_m[100]; }
enum {
ID_GCODE_RETURN = 1,
ID_GCODE_COMMAND,
};
static void event_handler(lv_obj_t *obj, lv_event_t event) {
if (event != LV_EVENT_RELEASED) return;
lv_clear_gcode();
switch (obj->mks_obj_id) {
case ID_GCODE_RETURN:
lv_draw_more();
return;
case ID_GCODE_COMMAND:
keyboard_value = GCodeCommand;
lv_draw_keyboard();
break;
}
}
void lv_show_gcode_output(void * that, const char * txt) {
// Ignore echo of command
if (!memcmp(txt, "echo:", 5)) {
public_buf[0] = 0; // Clear output buffer
return;
}
// Avoid overflow if the answer is too large
size_t len = strlen((const char*)public_buf), tlen = strlen(txt);
if (len + tlen + 1 < sizeof(public_buf)) {
memcpy(public_buf + len, txt, tlen);
public_buf[len + tlen] = '\n';
}
}
void lv_serial_capt_hook(void * userPointer, uint8_t c)
{
if (c == '\n' || currentWritePos == sizeof(public_buf_m) - 1) { // End of line, probably end of command anyway
public_buf_m[currentWritePos] = 0;
lv_show_gcode_output(userPointer, public_buf_m);
currentWritePos = 0;
}
else public_buf_m[currentWritePos++] = c;
}
void lv_eom_hook(void *)
{
// Message is done, let's remove the hook now
MYSERIAL0.setHook();
// We are back from the keyboard, so let's redraw ourselves
draw_return_ui();
}
void lv_draw_gcode(bool clear) {
if (clear) {
currentWritePos = 0;
public_buf[0] = 0;
}
scr = lv_screen_create(GCODE_UI, more_menu.gcode);
lv_screen_menu_item(scr, more_menu.entergcode, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_GCODE_COMMAND, 1);
outL = lv_label_create(scr, PARA_UI_POS_X, PARA_UI_POS_Y * 2, "Result:");
outV = lv_label_create(scr, PARA_UI_POS_X, PARA_UI_POS_Y * 3, (const char*)public_buf);
lv_big_button_create(scr, "F:/bmp_back70x40.bin", common_menu.text_back, PARA_UI_BACL_POS_X + 10, PARA_UI_BACL_POS_Y, event_handler, ID_GCODE_RETURN, true);
}
void lv_clear_gcode() {
#if HAS_ROTARY_ENCODER
if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
#endif
lv_obj_del(scr);
outV = 0;
}
#endif // HAS_TFT_LVGL_UI

33
Marlin/src/lcd/extui/lib/mks_ui/draw_gcode.h

@ -0,0 +1,33 @@
/**
* 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
#ifdef __cplusplus
extern "C" { /* C-declarations for C++ */
#endif
extern void lv_draw_gcode(bool clear = false);
extern void lv_clear_gcode();
#ifdef __cplusplus
} /* C-declarations for C++ */
#endif

24
Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp

@ -27,6 +27,7 @@
#include <lv_conf.h>
#include "../../../../inc/MarlinConfig.h"
#include "../../../../gcode/queue.h"
extern lv_group_t *g;
static lv_obj_t *scr;
@ -153,13 +154,22 @@ static void lv_kb_event_cb(lv_obj_t *kb, lv_event_t event) {
lv_draw_wifi_tips();
break;
#endif // MKS_WIFI_MODULE
case gcodeCommand:
case autoLevelGcodeCommand:
uint8_t buf[100];
strncpy((char *)buf,ret_ta_txt,sizeof(buf));
update_gcode_command(AUTO_LEVELING_COMMAND_ADDR,buf);
lv_clear_keyboard();
draw_return_ui();
break;
case GCodeCommand:
if (queue.length <= (BUFSIZE - 3)) {
// Hook anything that goes to the serial port
MYSERIAL0.setHook(lv_serial_capt_hook, lv_eom_hook, 0);
queue.enqueue_one_now(ret_ta_txt);
}
lv_clear_keyboard();
// draw_return_ui is called in the end of message hook
break;
default: break;
}
}
@ -238,12 +248,18 @@ void lv_draw_keyboard() {
// Create a text area. The keyboard will write here
lv_obj_t *ta = lv_ta_create(scr, nullptr);
lv_obj_align(ta, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10);
if (keyboard_value == gcodeCommand) {
switch (keyboard_value) {
case autoLevelGcodeCommand:
get_gcode_command(AUTO_LEVELING_COMMAND_ADDR,(uint8_t *)public_buf_m);
public_buf_m[sizeof(public_buf_m)-1] = 0;
lv_ta_set_text(ta, public_buf_m);
}
else {
break;
case GCodeCommand:
// Start with uppercase by default
lv_btnm_set_map(kb, kb_map_uc);
lv_btnm_set_ctrl_map(kb, kb_ctrl_uc_map);
// Fallthrough
default:
lv_ta_set_text(ta, "");
}

2
Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp

@ -49,7 +49,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
lv_draw_manual_level_pos_settings();
break;
case ID_LEVEL_COMMAND:
keyboard_value = gcodeCommand;
keyboard_value = autoLevelGcodeCommand;
lv_draw_keyboard();
break;
#if HAS_BED_PROBE

34
Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp

@ -41,20 +41,19 @@ enum {
ID_CUSTOM_4,
ID_CUSTOM_5,
ID_CUSTOM_6,
ID_CUSTOM_7,
ID_M_RETURN,
};
static void event_handler(lv_obj_t * obj, lv_event_t event) {
if (event != LV_EVENT_RELEASED) return;
switch (obj->mks_obj_id) {
case ID_GCODE: lv_clear_more(); lv_draw_gcode(true); break;
case ID_CUSTOM_1: TERN_(USER_CMD_1_ENABLE, queue.inject_P(PSTR(USER_GCODE_1))); break;
case ID_CUSTOM_2: TERN_(USER_CMD_2_ENABLE, queue.inject_P(PSTR(USER_GCODE_2))); break;
case ID_CUSTOM_3: TERN_(USER_CMD_3_ENABLE, queue.inject_P(PSTR(USER_GCODE_3))); break;
case ID_CUSTOM_4: TERN_(USER_CMD_4_ENABLE, queue.inject_P(PSTR(USER_GCODE_4))); break;
case ID_CUSTOM_5: TERN_(USER_CMD_5_ENABLE, queue.inject_P(PSTR(USER_GCODE_5))); break;
case ID_CUSTOM_6: TERN_(USER_CMD_6_ENABLE, queue.inject_P(PSTR(USER_GCODE_6))); break;
case ID_CUSTOM_7: TERN_(USER_CMD_7_ENABLE, queue.inject_P(PSTR(USER_GCODE_7))); break;
case ID_M_RETURN:
lv_clear_more();
lv_draw_tool();
@ -67,53 +66,54 @@ void lv_draw_more() {
const bool enc_ena = TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable);
lv_obj_t *buttonGCode = lv_imgbtn_create(scr, "F:/bmp_machine_para.bin", INTERVAL_V, titleHeight, event_handler, ID_GCODE);
if (enc_ena) lv_group_add_obj(g, buttonGCode);
lv_obj_t *labelGCode = lv_label_create_empty(buttonGCode);
#if ENABLED(USER_CMD_1_ENABLE)
lv_obj_t *buttonCustom1 = lv_imgbtn_create(scr, "F:/bmp_custom1.bin", INTERVAL_V, titleHeight, event_handler, ID_CUSTOM_1);
lv_obj_t *buttonCustom1 = lv_imgbtn_create(scr, "F:/bmp_custom1.bin", BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_CUSTOM_1);
if (enc_ena) lv_group_add_obj(g, buttonCustom1);
lv_obj_t *labelCustom1 = lv_label_create_empty(buttonCustom1);
#endif
#if ENABLED(USER_CMD_2_ENABLE)
lv_obj_t *buttonCustom2 = lv_imgbtn_create(scr, "F:/bmp_custom2.bin", BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_CUSTOM_2);
lv_obj_t *buttonCustom2 = lv_imgbtn_create(scr, "F:/bmp_custom2.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_CUSTOM_2);
if (enc_ena) lv_group_add_obj(g, buttonCustom2);
lv_obj_t *labelCustom2 = lv_label_create_empty(buttonCustom2);
#endif
#if ENABLED(USER_CMD_3_ENABLE)
lv_obj_t *buttonCustom3 = lv_imgbtn_create(scr, "F:/bmp_custom3.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_CUSTOM_3);
lv_obj_t *buttonCustom3 = lv_imgbtn_create(scr, "F:/bmp_custom3.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_CUSTOM_3);
if (enc_ena) lv_group_add_obj(g, buttonCustom3);
lv_obj_t *labelCustom3 = lv_label_create_empty(buttonCustom3);
#endif
#if ENABLED(USER_CMD_4_ENABLE)
lv_obj_t *buttonCustom4 = lv_imgbtn_create(scr, "F:/bmp_custom4.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_CUSTOM_4);
lv_obj_t *buttonCustom4 = lv_imgbtn_create(scr, "F:/bmp_custom4.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_4);
if (enc_ena) lv_group_add_obj(g, buttonCustom4);
lv_obj_t *labelCustom4 = lv_label_create_empty(buttonCustom4);
#endif
#if ENABLED(USER_CMD_5_ENABLE)
lv_obj_t *buttonCustom5 = lv_imgbtn_create(scr, "F:/bmp_custom5.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_5);
lv_obj_t *buttonCustom5 = lv_imgbtn_create(scr, "F:/bmp_custom5.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_5);
if (enc_ena) lv_group_add_obj(g, buttonCustom5);
lv_obj_t *labelCustom5 = lv_label_create_empty(buttonCustom5);
#endif
#if ENABLED(USER_CMD_6_ENABLE)
lv_obj_t *buttonCustom6 = lv_imgbtn_create(scr, "F:/bmp_custom6.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_6);
lv_obj_t *buttonCustom6 = lv_imgbtn_create(scr, "F:/bmp_custom6.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_6);
if (enc_ena) lv_group_add_obj(g, buttonCustom6);
lv_obj_t *labelCustom6 = lv_label_create_empty(buttonCustom6);
#endif
#if ENABLED(USER_CMD_7_ENABLE)
blv_obj_t *uttonCustom7 = lv_imgbtn_create(scr, "F:/bmp_custom7.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_7);
if (enc_ena) lv_group_add_obj(g, buttonCustom7);
lv_obj_t *labelCustom7 = lv_label_create_empty(buttonCustom7);
#endif
lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN);
if (enc_ena) lv_group_add_obj(g, buttonBack);
lv_obj_t *label_Back = lv_label_create_empty(buttonBack);
if (gCfgItems.multiple_language != 0) {
lv_label_set_text(labelGCode, more_menu.gcode);
lv_obj_align(labelGCode, buttonGCode, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
#if ENABLED(USER_CMD_1_ENABLE)
lv_label_set_text(labelCustom1, more_menu.custom1);
lv_obj_align(labelCustom1, buttonCustom1, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
@ -138,23 +138,19 @@ void lv_draw_more() {
lv_label_set_text(labelCustom6, more_menu.custom6);
lv_obj_align(labelCustom6, buttonCustom6, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
#endif
#if ENABLED(USER_CMD_7_ENABLE)
lv_label_set_text(labelCustom7, more_menu.custom7);
lv_obj_align(labelCustom7, buttonCustom7, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
#endif
lv_label_set_text(label_Back, common_menu.text_back);
lv_obj_align(label_Back, buttonBack, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
}
#if BUTTONS_EXIST(EN1, EN2, ENC)
if (enc_ena) {
lv_group_add_obj(g, buttonGCode);
TERN_(USER_CMD_1_ENABLE, lv_group_add_obj(g, buttonCustom1));
TERN_(USER_CMD_2_ENABLE, lv_group_add_obj(g, buttonCustom2));
TERN_(USER_CMD_3_ENABLE, lv_group_add_obj(g, buttonCustom3));
TERN_(USER_CMD_4_ENABLE, lv_group_add_obj(g, buttonCustom4));
TERN_(USER_CMD_5_ENABLE, lv_group_add_obj(g, buttonCustom5));
TERN_(USER_CMD_6_ENABLE, lv_group_add_obj(g, buttonCustom6));
TERN_(USER_CMD_7_ENABLE, lv_group_add_obj(g, buttonCustom7));
lv_group_add_obj(g, buttonBack);
}
#endif

3
Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp

@ -71,7 +71,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
uiCfg.desireSprayerTempBak = thermalManager.temp_hotend[uiCfg.curSprayerChoose].target;
lv_draw_filament_change();
break;
case ID_T_MORE: break;
case ID_T_MORE: lv_draw_more(); break;
case ID_T_RETURN:
TERN_(MKS_TEST, curent_disp_ui = 1);
lv_draw_ready_print();
@ -87,6 +87,7 @@ void lv_draw_tool() {
lv_big_button_create(scr, "F:/bmp_zero.bin", tool_menu.home, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_T_HOME);
lv_big_button_create(scr, "F:/bmp_leveling.bin", tool_menu.TERN(AUTO_BED_LEVELING_BILINEAR, autoleveling, leveling), INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_LEVELING);
lv_big_button_create(scr, "F:/bmp_filamentchange.bin", tool_menu.filament, BTN_X_PIXEL+INTERVAL_V*2,BTN_Y_PIXEL+INTERVAL_H+titleHeight, event_handler,ID_T_FILAMENT);
lv_big_button_create(scr, "F:/bmp_more.bin", tool_menu.more, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_MORE);
lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_RETURN);
}

1
Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp

@ -1077,6 +1077,7 @@ void draw_return_ui() {
case NOZZLE_PROBE_OFFSET_UI: lv_draw_auto_level_offset_settings(); break;
#endif
case TOOL_UI: lv_draw_tool(); break;
case GCODE_UI: lv_draw_gcode(); break;
case MESHLEVELING_UI: break;
case HARDWARE_TEST_UI: break;
#if ENABLED(MKS_WIFI_MODULE)

9
Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h

@ -46,6 +46,7 @@
#include "draw_preHeat.h"
#include "draw_extrusion.h"
#include "draw_home.h"
#include "draw_gcode.h"
#include "draw_more.h"
#include "draw_move_motor.h"
#include "draw_fan.h"
@ -326,7 +327,8 @@ typedef enum {
WIFI_SETTINGS_UI,
HOMING_SENSITIVITY_UI,
ENCODER_SETTINGS_UI,
TOUCH_CALIBRATION_UI
TOUCH_CALIBRATION_UI,
GCODE_UI,
} DISP_STATE;
typedef struct {
@ -413,7 +415,8 @@ typedef enum {
wifiName,
wifiPassWord,
wifiConfig,
gcodeCommand
autoLevelGcodeCommand,
GCodeCommand,
} keyboard_value_state;
extern keyboard_value_state keyboard_value;
@ -449,6 +452,8 @@ extern void preview_gcode_prehandle(char *path);
extern void update_spi_flash();
extern void update_gcode_command(int addr,uint8_t *s);
extern void get_gcode_command(int addr,uint8_t *d);
extern void lv_serial_capt_hook(void *, uint8_t);
extern void lv_eom_hook(void *);
#if HAS_GCODE_PREVIEW
extern void disp_pre_gcode(int xpos_pixel, int ypos_pixel);
#endif

2
Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h

@ -279,6 +279,8 @@
#define AUTO_LEVELING_TEXT_EN "AutoLevel"
#define SET_TEXT_EN "Settings"
#define MORE_TEXT_EN "More"
#define MORE_GCODE_EN "G-Code"
#define MORE_ENTER_GCODE_EN "Enter G-Code"
#define ADD_TEXT_EN "Add"
#define DEC_TEXT_EN "Dec"

50
Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h

@ -22,7 +22,7 @@
#pragma once
//*************法文****************************//
#define TOOL_TEXT_FR "prêt"
#define TOOL_TEXT_FR "Prêt"
#define PREHEAT_TEXT_FR "Préchauffe"
#define MOVE_TEXT_FR "Déplace"
#define HOME_TEXT_FR "Acceuil"
@ -32,6 +32,8 @@
#define AUTO_LEVELING_TEXT_FR "AutoLevel"
#define SET_TEXT_FR "Config"
#define MORE_TEXT_FR "Plus"
#define MORE_GCODE_FR "G-Code"
#define MORE_ENTER_GCODE_FR "Saisir G-Code"
#define ADD_TEXT_FR "Ajouter"
#define DEC_TEXT_FR "Réduire"
@ -74,7 +76,7 @@
#define PAGE_DOWN_TEXT_FR "En bas"
#define EXTRUDER_IN_TEXT_FR "Insérer"
#define EXTRUDER_OUT_TEXT_FR "éjecter"
#define EXTRUDER_OUT_TEXT_FR "Éjecter"
#define EXTRUDE_1MM_TEXT_FR "1mm"
#define EXTRUDE_5MM_TEXT_FR "5mm"
#define EXTRUDE_10MM_TEXT_FR "10mm"
@ -91,13 +93,13 @@
#define FILESYS_TEXT_FR "Fichier"
#define WIFI_TEXT_FR "WiFi"
#define FAN_TEXT_FR "Fan"
#define ABOUT_TEXT_FR "A propos"
#define ABOUT_TEXT_FR "À propos"
#define BREAK_POINT_TEXT_FR "Continuer"
#define FILAMENT_TEXT_FR "Remplacer"
#define LANGUAGE_TEXT_FR "Langue"
#define MOTOR_OFF_TEXT_FR "M-hors"
#define MOTOR_OFF_XY_TEXT_FR "M-hors-XY"
#define SHUTDOWN_TEXT_FR "Eteindre"
#define SHUTDOWN_TEXT_FR "Éteindre"
#define MACHINE_PARA_FR "Config"
#define EEPROM_SETTINGS_FR "Eeprom Set"
@ -130,27 +132,27 @@
#define FAN_TIPS2_TEXT_FR "ventilateur\n0"
#define FILAMENT_IN_TEXT_FR "Insérer"
#define FILAMENT_OUT_TEXT_FR "éjecter"
#define FILAMENT_OUT_TEXT_FR "Éjecter"
#define FILAMENT_EXT0_TEXT_FR "Extr1"
#define FILAMENT_EXT1_TEXT_FR "Extr2"
#define FILAMENT_HEAT_TEXT_FR "Preheat"
#define FILAMENT_STOP_TEXT_FR "Arrêter"
#define FILAMENT_TIPS2_TEXT_FR "T:"
#define FILAMENT_TIPS3_TEXT_FR "Insérer le filament..."
#define FILAMENT_TIPS4_TEXT_FR "éjecter le filament..."
#define FILAMENT_TIPS4_TEXT_FR "Éjecter le filament..."
#define FILAMENT_TIPS5_TEXT_FR "Température trop basse pour démarrer, chauffez svp"
#define FILAMENT_TIPS6_TEXT_FR "Terminé"
#define FILAMENT_CHANGE_TEXT_FR "Please click <Load> \nor <unload>,After \npinter pause."
#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_FR "Heating up the nozzle,\nplease wait..."
#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_FR "Heating up the nozzle,\nplease wait..."
#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_FR "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading."
#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_FR "Please load filament to extruder,\nand click <confirm> for start loading."
#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_FR "Heat completed,please \nclick <confirm> for start unloading.!"
#define FILAMENT_DIALOG_LOADING_TIPS_FR "Is loading ,please wait!"
#define FILAMENT_DIALOG_UNLOADING_TIPS_FR "Is unloading,please wait!"
#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_FR "Load filament completed,\nclick <confirm> for return!"
#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_FR "Unload filament completed,\nclick <confirm> for return!"
#define FILAMENT_CHANGE_TEXT_FR "Veuillez presser <Load> \nou <unload>, après \nla pause."
#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_FR "Chauffe de la tête\nPatientez SVP..."
#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_FR "Chauffe de la tête\nPatientez SVP..."
#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_FR "Tête chaude, veuillez charger le\nfilament dans l'extruder & <confirmer>\nle chargement."
#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_FR "Veuillez charger le filament dans\nl'extruder & <confirmer> le chargement."
#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_FR "Tête chaude, <confirmez>\npour le déchargement."
#define FILAMENT_DIALOG_LOADING_TIPS_FR "Chargement, patientez SVP."
#define FILAMENT_DIALOG_UNLOADING_TIPS_FR "Déchargement, patientez SVP."
#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_FR "Chargement terminé,\n<confirmez> pour revenir!"
#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_FR "Déchargement terminé,\n<confirmez> pour revenir!"
#define PRE_HEAT_EXT_TEXT_FR "E"
@ -205,12 +207,12 @@
#define TITLE_FAN_FR "Ventilateur"
#define TITLE_LANGUAGE_FR "Langue"
#define TITLE_PAUSE_FR "Pause"
#define TITLE_CHANGESPEED_FR "Speed"
#define TITLE_CHANGESPEED_FR "Vitesse"
#define TITLE_CLOUD_TEXT_FR "Cloud"
#define TITLE_DIALOG_CONFIRM_FR "Confirm"
#define TITLE_DIALOG_CONFIRM_FR "Confirmer"
#define TITLE_FILESYS_FR "FileSys"
#define DIALOG_CLOSE_MACHINE_FR "Closing machine......"
#define DIALOG_CLOSE_MACHINE_FR "Extinction..."
#define AUTO_SHUTDOWN_FR "Auto"
#define MANUAL_SHUTDOWN_FR "Manuel"
@ -220,7 +222,7 @@
#define DIALOG_OK_FR "OK"
#define DIALOG_RESET_FR "Réinitialiser"
#define DIALOG_RETRY_FR "Recommencez"
#define DIALOG_DISABLE_FR "Disable"
#define DIALOG_DISABLE_FR "Désactiver"
#define DIALOG_PRINT_MODEL_FR "Imprimer le fichier?"
#define DIALOG_CANCEL_PRINT_FR "Arrêter?"
@ -229,12 +231,12 @@
#define DIALOG_ERROR_TIPS1_FR "Erreur:error:Aucun fichier, \nvérifiez à nouveau."
#define DIALOG_ERROR_TIPS2_FR "Erreur:La opération a échoué. \nVerifiez que le baudrate de l'écran et de \nla carte mère soient identique!"
#define DIALOG_ERROR_TIPS3_FR "Erreur: le nom du fichier ou le \nchemin d'accès est trop long."
#define DIALOG_UNBIND_PRINTER_FR "Unbind the printer?"
#define DIALOG_FILAMENT_NO_PRESS_FR "Filament detection switch is not pressed"
#define DIALOG_UNBIND_PRINTER_FR "Déconnecter l'imprimante?"
#define DIALOG_FILAMENT_NO_PRESS_FR "Détecteur de filament non pressé"
#define DIALOG_PRINT_FINISH_FR "L'impression est terminée!"
#define DIALOG_PRINT_TIME_FR "Temps d'impression: "
#define DIALOG_REPRINT_FR "Print again"
#define DIALOG_WIFI_ENABLE_TIPS_FR "The wifi module is being configured,\nplease wait a moment....."
#define DIALOG_REPRINT_FR "Réimprimer"
#define DIALOG_WIFI_ENABLE_TIPS_FR "Le module WIFI se charge\nAttendez SVP..."
#define MESSAGE_PAUSING_FR "Parking..."
#define MESSAGE_CHANGING_FR "Attente filament pour démarrer"

2
Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h

@ -32,6 +32,8 @@
#define AUTO_LEVELING_TEXT_IT "AutoLevel"
#define SET_TEXT_IT "Imposta"
#define MORE_TEXT_IT "Di più"
#define MORE_GCODE_IT "G-Code"
#define MORE_ENTER_GCODE_IT "Inserisci il G-Code"
#define ADD_TEXT_IT "Aumentare"
#define DEC_TEXT_IT "Ridurre"

2
Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h

@ -32,6 +32,8 @@
#define AUTO_LEVELING_TEXT_RU "aвтоуровень"
#define SET_TEXT_RU "настройки"
#define MORE_TEXT_RU "больше"
#define MORE_GCODE_RU "G-код"
#define MORE_ENTER_GCODE_RU "Введите G-код"
#define ADD_TEXT_RU "добавить"
#define DEC_TEXT_RU "уменьшить"

2
Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h

@ -263,6 +263,8 @@
#define AUTO_LEVELING_TEXT_CN "自动调平"
#define SET_TEXT_CN "设置"
#define MORE_TEXT_CN "更多"
#define MORE_GCODE_CN "G-Code"
#define MORE_ENTER_GCODE_CN "Enter G-Code"
#define ADD_TEXT_CN "增加"
#define DEC_TEXT_CN "减少"

2
Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h

@ -33,6 +33,8 @@
#define AUTO_LEVELING_TEXT_SP "Autolevel"
#define SET_TEXT_SP "Config"
#define MORE_TEXT_SP "Más"
#define MORE_GCODE_SP "G-Code"
#define MORE_ENTER_GCODE_SP "Introduzca el G-Code"
#define ADD_TEXT_SP "Más"
#define DEC_TEXT_SP "Menos"

2
Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h

@ -263,6 +263,8 @@
#define AUTO_LEVELING_TEXT_T_CN "自動調平"
#define SET_TEXT_T_CN "設置"
#define MORE_TEXT_T_CN "更多"
#define MORE_GCODE_T_CN "G-Code"
#define MORE_ENTER_GCODE_T_CN "Enter G-Code"
#define ADD_TEXT_T_CN "增加"
#define DEC_TEXT_T_CN "減少"

16
Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp

@ -943,6 +943,8 @@ void disp_language_init() {
filesys_menu.usb_sys = U_DISK_TEXT_CN;
//
more_menu.title = TITLE_MORE_CN;
more_menu.gcode = MORE_GCODE_CN;
more_menu.entergcode = MORE_ENTER_GCODE_CN;
TERN_(USER_CMD_1_ENABLE, more_menu.custom1 = MORE_CUSTOM1_TEXT_CN);
TERN_(USER_CMD_2_ENABLE, more_menu.custom2 = MORE_CUSTOM2_TEXT_CN);
TERN_(USER_CMD_3_ENABLE, more_menu.custom3 = MORE_CUSTOM3_TEXT_CN);
@ -1175,6 +1177,8 @@ void disp_language_init() {
filesys_menu.usb_sys = U_DISK_TEXT_T_CN;
//
more_menu.title = TITLE_MORE_T_CN;
more_menu.gcode = MORE_GCODE_T_CN;
more_menu.entergcode = MORE_ENTER_GCODE_T_CN;
TERN_(USER_CMD_1_ENABLE, more_menu.custom1 = MORE_CUSTOM1_TEXT_T_CN);
TERN_(USER_CMD_2_ENABLE, more_menu.custom2 = MORE_CUSTOM2_TEXT_T_CN);
TERN_(USER_CMD_3_ENABLE, more_menu.custom3 = MORE_CUSTOM3_TEXT_T_CN);
@ -1394,6 +1398,8 @@ void disp_language_init() {
set_menu.eepromSet = EEPROM_SETTINGS_EN;
//
more_menu.title = TITLE_MORE_EN;
more_menu.gcode = MORE_GCODE_EN;
more_menu.entergcode = MORE_ENTER_GCODE_EN;
TERN_(USER_CMD_1_ENABLE, more_menu.custom1 = MORE_CUSTOM1_TEXT_EN);
TERN_(USER_CMD_2_ENABLE, more_menu.custom2 = MORE_CUSTOM2_TEXT_EN);
TERN_(USER_CMD_3_ENABLE, more_menu.custom3 = MORE_CUSTOM3_TEXT_EN);
@ -1614,6 +1620,8 @@ void disp_language_init() {
set_menu.machine_para = MACHINE_PARA_RU;
set_menu.eepromSet = EEPROM_SETTINGS_RU;
more_menu.title = TITLE_MORE_RU;
more_menu.gcode = MORE_GCODE_RU;
more_menu.entergcode = MORE_ENTER_GCODE_RU;
#if ENABLED(USER_CMD_1_ENABLE)
more_menu.custom1 = MORE_CUSTOM1_TEXT_RU;
#endif
@ -1944,6 +1952,8 @@ void disp_language_init() {
set_menu.machine_para = MACHINE_PARA_SP;
set_menu.eepromSet = EEPROM_SETTINGS_SP;
more_menu.title = TITLE_MORE_SP;
more_menu.gcode = MORE_GCODE_SP;
more_menu.entergcode = MORE_ENTER_GCODE_SP;
#if ENABLED(USER_CMD_1_ENABLE)
more_menu.custom1 = MORE_CUSTOM1_TEXT_SP;
#endif
@ -2179,6 +2189,8 @@ void disp_language_init() {
set_menu.machine_para = MACHINE_PARA_FR;
set_menu.eepromSet = EEPROM_SETTINGS_FR;
more_menu.title = TITLE_MORE_FR;
more_menu.gcode = MORE_GCODE_FR;
more_menu.entergcode = MORE_ENTER_GCODE_FR;
#if ENABLED(USER_CMD_1_ENABLE)
more_menu.custom1 = MORE_CUSTOM1_TEXT_FR;
#endif
@ -2415,6 +2427,8 @@ void disp_language_init() {
set_menu.machine_para = MACHINE_PARA_IT;
set_menu.eepromSet = EEPROM_SETTINGS_IT;
more_menu.title = TITLE_MORE_IT;
more_menu.gcode = MORE_GCODE_IT;
more_menu.entergcode = MORE_ENTER_GCODE_IT;
#if ENABLED(USER_CMD_1_ENABLE)
more_menu.custom1 = MORE_CUSTOM1_TEXT_IT;
#endif
@ -2651,6 +2665,8 @@ void disp_language_init() {
set_menu.eepromSet = EEPROM_SETTINGS_EN;
//
more_menu.title = TITLE_MORE_EN;
more_menu.gcode = MORE_GCODE_EN;
more_menu.entergcode = MORE_ENTER_GCODE_EN;
TERN_(USER_CMD_1_ENABLE, more_menu.custom1 = MORE_CUSTOM1_TEXT_EN);
TERN_(USER_CMD_2_ENABLE, more_menu.custom2 = MORE_CUSTOM2_TEXT_EN);
TERN_(USER_CMD_3_ENABLE, more_menu.custom3 = MORE_CUSTOM3_TEXT_EN);

2
Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h

@ -464,6 +464,8 @@ typedef struct more_menu_disp {
const char *custom5;
const char *custom6;
const char *custom7;
const char *gcode;
const char *entergcode;
const char *back;
} more_menu_def;

8
Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h

@ -80,10 +80,10 @@ class WifiSerial {
}
/* TXE signifies readiness to send a byte to DR. */
if ((regs->CR1 & USART_CR1_TXEIE) && (regs->SR & USART_SR_TXE)) {
if (!rb_is_empty(this->usart_device->wb))
regs->DR=rb_remove(this->usart_device->wb);
else
regs->CR1 &= ~((uint32)USART_CR1_TXEIE); // disable TXEIE
if (!rb_is_empty(this->usart_device->wb))
regs->DR=rb_remove(this->usart_device->wb);
else
regs->CR1 &= ~((uint32)USART_CR1_TXEIE); // disable TXEIE
}
}

5
buildroot/tests/mega2560-tests

@ -72,8 +72,9 @@ opt_set TEMP_SENSOR_1 1
opt_set TEMP_SENSOR_2 1
opt_set TEMP_SENSOR_3 1
opt_set TEMP_SENSOR_4 1
opt_enable VIKI2 Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE BOOT_MARLIN_LOGO_ANIMATED \
AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL \
opt_enable VIKI2 BOOT_MARLIN_LOGO_ANIMATED SDSUPPORT AUTO_REPORT_SD_STATUS \
Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE \
EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL \
NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \
DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \
FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING FIL_RUNOUT3_PULLUP

16
docs/Serial.md

@ -10,13 +10,13 @@ Starting with version `2.0.9`, Marlin provides a common interface for its serial
## Common interface
This interface is declared in `Marlin/src/core/serial_base.h`
This interface is declared in `Marlin/src/core/serial_base.h`
Any implementation will need to follow this interface for being used transparently in Marlin's codebase.
The implementation was written to prioritize performance over abstraction, so the base interface is not using virtual inheritance to avoid the cost of virtual dispatching while calling methods.
Instead, the Curiously Recurring Template Pattern (**CRTP**) is used so that, upon compilation, the interface abstraction does not incur a performance cost.
Because some platform do not follow the same interface, the missing method in the actual low-level implementation are detected via SFINAE and a wrapper is generated when such method are missing. See `CALL_IF_EXISTS` macro in `Marlin/src/core/macros.h` for the documentation of this technic.
Because some platform do not follow the same interface, the missing method in the actual low-level implementation are detected via SFINAE and a wrapper is generated when such method are missing. See `CALL_IF_EXISTS` macro in `Marlin/src/core/macros.h` for the documentation of this technic.
## Composing the desired feature
The different specificities for each architecture are provided by composing the serial type based on desired functionality.
@ -25,11 +25,11 @@ In the `Marlin/src/core/serial_hook.h` file, the different serial feature are de
2. `ForwardSerial` is a composing wrapper. It references an actual Arduino compatible `Serial` instance. You'll use this if the instance is declared in the platform's framework and is being referred directly in the framework. This is not as efficient as the `BaseSerial` implementation since static dereferencing is done for each method call (it'll still be faster than virtual dispatching)
3. `ConditionalSerial` is working a bit like the `ForwardSerial` interface, but it checks a boolean condition before calling the referenced instance. You'll use it when the serial output can be switch off at runtime, for example in a *telnet* like serial output that should not emit any packet if no client is connected.
4. `RuntimeSerial` is providing a runtime-modifiable hooking method for its `write` and `msgDone` method. You'll use it if you need to capture the serial output of Marlin, for example to display the G-Code parser's output on a GUI interface. The hooking interface is setup via the `setHook` method.
5. `MultiSerial` is a runtime modifiable serial output multiplexer. It can output (*respectively input*) to 2 different interface based on a port *mask*. You'll use this if you need to output the same serial stream to multiple port. You can plug a `MultiSerial` to itself to duplicate to more than 2 ports.
5. `MultiSerial` is a runtime modifiable serial output multiplexer. It can output (*respectively input*) to 2 different interface based on a port *mask*. You'll use this if you need to output the same serial stream to multiple port. You can plug a `MultiSerial` to itself to duplicate to more than 2 ports.
## Plumbing
Since all the types above are using CRTP, it's possible to combine them to get the appropriate functionality.
This is easily done via type definition of the feature.
Since all the types above are using CRTP, it's possible to combine them to get the appropriate functionality.
This is easily done via type definition of the feature.
For example, to present a serial interface that's outputting to 2 serial port, the first one being hooked at runtime and the second one connected to a runtime switchable telnet client, you'll declare the type to use as:
```
@ -37,8 +37,8 @@ typedef MultiSerial< RuntimeSerial<Serial>, ConditionalSerial<TelnetClient> > Se
```
## Emergency parser
By default, the serial base interface provide an emergency parser that's only enable for serial classes that support it.
Because of this condition, all underlying type takes a first `bool emergencyParserEnabled` argument to their constructor. You must take into account this parameter when defining the actual type used.
By default, the serial base interface provide an emergency parser that's only enable for serial classes that support it.
Because of this condition, all underlying type takes a first `bool emergencyParserEnabled` argument to their constructor. You must take into account this parameter when defining the actual type used.
*This document was written by [X-Ryl669](https://blog.cyril.by) and is under [CC-SA license](https://creativecommons.org/licenses/by-sa)*
*This document was written by [X-Ryl669](https://blog.cyril.by) and is under [CC-SA license](https://creativecommons.org/licenses/by-sa)*

Loading…
Cancel
Save