2019-06-21 11:47:23 +02:00
|
|
|
/**
|
|
|
|
* Marlin 3D Printer Firmware
|
2020-02-03 08:00:57 -06:00
|
|
|
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
2019-06-21 11:47:23 +02:00
|
|
|
*
|
|
|
|
* Based on Sprinter and grbl.
|
2019-06-27 23:57:50 -05:00
|
|
|
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
2019-06-21 11:47:23 +02:00
|
|
|
*
|
|
|
|
* 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
|
2020-07-23 05:20:14 +02:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2019-06-21 11:47:23 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "../../../../inc/MarlinConfigPre.h"
|
|
|
|
|
2020-01-04 11:00:44 +08:00
|
|
|
#if HAS_DGUS_LCD
|
|
|
|
|
|
|
|
#if HOTENDS > 2
|
2021-02-28 07:35:32 +08:00
|
|
|
#warning "More than 2 hotends not implemented on DGUS Display UI."
|
2020-01-04 11:00:44 +08:00
|
|
|
#endif
|
2019-06-21 11:47:23 +02:00
|
|
|
|
|
|
|
#include "../../ui_api.h"
|
|
|
|
|
2020-01-03 02:01:38 +01:00
|
|
|
#include "../../../../MarlinCore.h"
|
2019-06-21 11:47:23 +02:00
|
|
|
#include "../../../../module/motion.h"
|
|
|
|
#include "../../../../gcode/queue.h"
|
|
|
|
#include "../../../../module/planner.h"
|
|
|
|
#include "../../../../libs/duration_t.h"
|
|
|
|
#include "../../../../module/printcounter.h"
|
2020-01-04 11:00:44 +08:00
|
|
|
#if ENABLED(POWER_LOSS_RECOVERY)
|
2020-03-13 16:29:29 -05:00
|
|
|
#include "../../../../feature/powerloss.h"
|
2020-01-04 11:00:44 +08:00
|
|
|
#endif
|
2019-06-21 11:47:23 +02:00
|
|
|
|
2020-03-24 07:00:22 +08:00
|
|
|
#include "DGUSDisplay.h"
|
|
|
|
#include "DGUSVPVariable.h"
|
|
|
|
#include "DGUSDisplayDef.h"
|
|
|
|
|
2021-02-28 07:35:32 +08:00
|
|
|
DGUSDisplay dgusdisplay;
|
|
|
|
|
2019-06-21 11:47:23 +02:00
|
|
|
// Preamble... 2 Bytes, usually 0x5A 0xA5, but configurable
|
|
|
|
constexpr uint8_t DGUS_HEADER1 = 0x5A;
|
|
|
|
constexpr uint8_t DGUS_HEADER2 = 0xA5;
|
|
|
|
|
|
|
|
constexpr uint8_t DGUS_CMD_WRITEVAR = 0x82;
|
|
|
|
constexpr uint8_t DGUS_CMD_READVAR = 0x83;
|
|
|
|
|
|
|
|
#if ENABLED(DEBUG_DGUSLCD)
|
|
|
|
bool dguslcd_local_debug; // = false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void DGUSDisplay::InitDisplay() {
|
2020-09-24 18:28:48 -07:00
|
|
|
#ifndef LCD_BAUDRATE
|
|
|
|
#define LCD_BAUDRATE 115200
|
|
|
|
#endif
|
|
|
|
LCD_SERIAL.begin(LCD_BAUDRATE);
|
2021-03-31 15:34:17 +08:00
|
|
|
|
|
|
|
if (TERN1(POWER_LOSS_RECOVERY, !recovery.valid())) { // If no Power-Loss Recovery is needed...
|
|
|
|
TERN_(DGUS_LCD_UI_MKS, delay(LOGO_TIME_DELAY)); // Show the logo for a little while
|
|
|
|
}
|
|
|
|
|
2021-02-28 07:35:32 +08:00
|
|
|
RequestScreen(TERN(SHOW_BOOTSCREEN, DGUSLCD_SCREEN_BOOT, DGUSLCD_SCREEN_MAIN));
|
2019-06-21 11:47:23 +02:00
|
|
|
}
|
|
|
|
|
2021-04-04 18:07:16 -05:00
|
|
|
void DGUSDisplay::WriteVariable(uint16_t adr, const void *values, uint8_t valueslen, bool isstr) {
|
2019-06-21 11:47:23 +02:00
|
|
|
const char* myvalues = static_cast<const char*>(values);
|
2020-01-04 11:00:44 +08:00
|
|
|
bool strend = !myvalues;
|
2019-06-21 11:47:23 +02:00
|
|
|
WriteHeader(adr, DGUS_CMD_WRITEVAR, valueslen);
|
|
|
|
while (valueslen--) {
|
|
|
|
char x;
|
|
|
|
if (!strend) x = *myvalues++;
|
|
|
|
if ((isstr && !x) || strend) {
|
|
|
|
strend = true;
|
|
|
|
x = ' ';
|
|
|
|
}
|
2020-09-24 18:28:48 -07:00
|
|
|
LCD_SERIAL.write(x);
|
2019-06-21 11:47:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-18 15:26:00 -07:00
|
|
|
void DGUSDisplay::WriteVariable(uint16_t adr, uint16_t value) {
|
2021-02-28 07:35:32 +08:00
|
|
|
value = (value & 0xFFU) << 8U | (value >> 8U);
|
2020-07-18 15:26:00 -07:00
|
|
|
WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint16_t));
|
|
|
|
}
|
|
|
|
|
2020-07-19 15:34:36 -07:00
|
|
|
void DGUSDisplay::WriteVariable(uint16_t adr, int16_t value) {
|
2021-02-28 07:35:32 +08:00
|
|
|
value = (value & 0xFFU) << 8U | (value >> 8U);
|
2020-07-19 15:34:36 -07:00
|
|
|
WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint16_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
void DGUSDisplay::WriteVariable(uint16_t adr, uint8_t value) {
|
|
|
|
WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint8_t));
|
|
|
|
}
|
|
|
|
|
2020-07-21 01:19:25 -07:00
|
|
|
void DGUSDisplay::WriteVariable(uint16_t adr, int8_t value) {
|
|
|
|
WriteVariable(adr, static_cast<const void*>(&value), sizeof(int8_t));
|
|
|
|
}
|
|
|
|
|
2021-02-28 07:35:32 +08:00
|
|
|
#if ENABLED(DGUS_LCD_UI_MKS)
|
|
|
|
void DGUSDisplay::MKS_WriteVariable(uint16_t adr, uint8_t value) {
|
|
|
|
WriteVariable(adr, static_cast<const void *>(&value), sizeof(uint8_t));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-07-19 15:34:36 -07:00
|
|
|
void DGUSDisplay::WriteVariable(uint16_t adr, long value) {
|
2021-02-28 07:35:32 +08:00
|
|
|
union { long l; char lb[4]; } endian;
|
|
|
|
char tmp[4];
|
|
|
|
endian.l = value;
|
|
|
|
tmp[0] = endian.lb[3];
|
|
|
|
tmp[1] = endian.lb[2];
|
|
|
|
tmp[2] = endian.lb[1];
|
|
|
|
tmp[3] = endian.lb[0];
|
|
|
|
WriteVariable(adr, static_cast<const void*>(&tmp), sizeof(long));
|
2020-07-19 15:34:36 -07:00
|
|
|
}
|
|
|
|
|
2021-04-04 18:07:16 -05:00
|
|
|
void DGUSDisplay::WriteVariablePGM(uint16_t adr, const void *values, uint8_t valueslen, bool isstr) {
|
2019-06-21 11:47:23 +02:00
|
|
|
const char* myvalues = static_cast<const char*>(values);
|
2020-01-04 11:00:44 +08:00
|
|
|
bool strend = !myvalues;
|
2019-06-21 11:47:23 +02:00
|
|
|
WriteHeader(adr, DGUS_CMD_WRITEVAR, valueslen);
|
|
|
|
while (valueslen--) {
|
|
|
|
char x;
|
|
|
|
if (!strend) x = pgm_read_byte(myvalues++);
|
|
|
|
if ((isstr && !x) || strend) {
|
|
|
|
strend = true;
|
|
|
|
x = ' ';
|
|
|
|
}
|
2020-09-24 18:28:48 -07:00
|
|
|
LCD_SERIAL.write(x);
|
2019-06-21 11:47:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DGUSDisplay::ProcessRx() {
|
|
|
|
|
2020-09-24 21:46:13 -05:00
|
|
|
#if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
|
2020-09-24 18:28:48 -07:00
|
|
|
if (!LCD_SERIAL.available() && LCD_SERIAL.buffer_overruns()) {
|
2020-01-04 11:00:44 +08:00
|
|
|
// Overrun, but reset the flag only when the buffer is empty
|
|
|
|
// We want to extract as many as valid datagrams possible...
|
|
|
|
DEBUG_ECHOPGM("OVFL");
|
|
|
|
rx_datagram_state = DGUS_IDLE;
|
2020-09-24 18:28:48 -07:00
|
|
|
//LCD_SERIAL.reset_rx_overun();
|
|
|
|
LCD_SERIAL.flush();
|
2020-01-04 11:00:44 +08:00
|
|
|
}
|
|
|
|
#endif
|
2019-06-21 11:47:23 +02:00
|
|
|
|
|
|
|
uint8_t receivedbyte;
|
2020-09-24 18:28:48 -07:00
|
|
|
while (LCD_SERIAL.available()) {
|
2019-06-21 11:47:23 +02:00
|
|
|
switch (rx_datagram_state) {
|
|
|
|
|
2019-06-26 07:40:29 +02:00
|
|
|
case DGUS_IDLE: // Waiting for the first header byte
|
2020-09-24 18:28:48 -07:00
|
|
|
receivedbyte = LCD_SERIAL.read();
|
2019-06-21 11:47:23 +02:00
|
|
|
//DEBUG_ECHOPAIR("< ",x);
|
|
|
|
if (DGUS_HEADER1 == receivedbyte) rx_datagram_state = DGUS_HEADER1_SEEN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DGUS_HEADER1_SEEN: // Waiting for the second header byte
|
2020-09-24 18:28:48 -07:00
|
|
|
receivedbyte = LCD_SERIAL.read();
|
2019-06-21 11:47:23 +02:00
|
|
|
//DEBUG_ECHOPAIR(" ",x);
|
|
|
|
rx_datagram_state = (DGUS_HEADER2 == receivedbyte) ? DGUS_HEADER2_SEEN : DGUS_IDLE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DGUS_HEADER2_SEEN: // Waiting for the length byte
|
2020-09-24 18:28:48 -07:00
|
|
|
rx_datagram_len = LCD_SERIAL.read();
|
2020-01-04 11:00:44 +08:00
|
|
|
DEBUG_ECHOPAIR(" (", rx_datagram_len, ") ");
|
2019-06-21 11:47:23 +02:00
|
|
|
|
|
|
|
// Telegram min len is 3 (command and one word of payload)
|
|
|
|
rx_datagram_state = WITHIN(rx_datagram_len, 3, DGUS_RX_BUFFER_SIZE) ? DGUS_WAIT_TELEGRAM : DGUS_IDLE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DGUS_WAIT_TELEGRAM: // wait for complete datagram to arrive.
|
2020-09-24 18:28:48 -07:00
|
|
|
if (LCD_SERIAL.available() < rx_datagram_len) return;
|
2019-06-21 11:47:23 +02:00
|
|
|
|
|
|
|
Initialized = true; // We've talked to it, so we defined it as initialized.
|
2020-09-24 18:28:48 -07:00
|
|
|
uint8_t command = LCD_SERIAL.read();
|
2019-06-21 11:47:23 +02:00
|
|
|
|
|
|
|
DEBUG_ECHOPAIR("# ", command);
|
|
|
|
|
|
|
|
uint8_t readlen = rx_datagram_len - 1; // command is part of len.
|
|
|
|
unsigned char tmp[rx_datagram_len - 1];
|
|
|
|
unsigned char *ptmp = tmp;
|
|
|
|
while (readlen--) {
|
2020-09-24 18:28:48 -07:00
|
|
|
receivedbyte = LCD_SERIAL.read();
|
2019-06-21 11:47:23 +02:00
|
|
|
DEBUG_ECHOPAIR(" ", receivedbyte);
|
|
|
|
*ptmp++ = receivedbyte;
|
|
|
|
}
|
|
|
|
DEBUG_ECHOPGM(" # ");
|
|
|
|
// mostly we'll get this: 5A A5 03 82 4F 4B -- ACK on 0x82, so discard it.
|
|
|
|
if (command == DGUS_CMD_WRITEVAR && 'O' == tmp[0] && 'K' == tmp[1]) {
|
|
|
|
DEBUG_ECHOLNPGM(">");
|
|
|
|
rx_datagram_state = DGUS_IDLE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* AutoUpload, (and answer to) Command 0x83 :
|
|
|
|
| tmp[0 1 2 3 4 ... ]
|
|
|
|
| Example 5A A5 06 83 20 01 01 78 01 ……
|
|
|
|
| / / | | \ / | \ \
|
|
|
|
| Header | | | | \_____\_ DATA (Words!)
|
|
|
|
| DatagramLen / VPAdr |
|
|
|
|
| Command DataLen (in Words) */
|
|
|
|
if (command == DGUS_CMD_READVAR) {
|
|
|
|
const uint16_t vp = tmp[0] << 8 | tmp[1];
|
2020-06-24 21:50:57 -05:00
|
|
|
//const uint8_t dlen = tmp[2] << 1; // Convert to Bytes. (Display works with words)
|
2019-06-26 07:40:29 +02:00
|
|
|
//DEBUG_ECHOPAIR(" vp=", vp, " dlen=", dlen);
|
2019-06-21 11:47:23 +02:00
|
|
|
DGUS_VP_Variable ramcopy;
|
|
|
|
if (populate_VPVar(vp, &ramcopy)) {
|
2020-03-11 16:40:30 +08:00
|
|
|
if (ramcopy.set_by_display_handler)
|
2019-06-21 11:47:23 +02:00
|
|
|
ramcopy.set_by_display_handler(ramcopy, &tmp[3]);
|
|
|
|
else
|
|
|
|
DEBUG_ECHOLNPGM(" VPVar found, no handler.");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
DEBUG_ECHOLNPAIR(" VPVar not found:", vp);
|
|
|
|
|
|
|
|
rx_datagram_state = DGUS_IDLE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-01-04 11:00:44 +08:00
|
|
|
// discard anything else
|
2019-06-21 11:47:23 +02:00
|
|
|
rx_datagram_state = DGUS_IDLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-24 18:28:48 -07:00
|
|
|
size_t DGUSDisplay::GetFreeTxBuffer() { return SERIAL_GET_TX_BUFFER_FREE(); }
|
2019-06-21 11:47:23 +02:00
|
|
|
|
|
|
|
void DGUSDisplay::WriteHeader(uint16_t adr, uint8_t cmd, uint8_t payloadlen) {
|
2020-09-24 18:28:48 -07:00
|
|
|
LCD_SERIAL.write(DGUS_HEADER1);
|
|
|
|
LCD_SERIAL.write(DGUS_HEADER2);
|
|
|
|
LCD_SERIAL.write(payloadlen + 3);
|
|
|
|
LCD_SERIAL.write(cmd);
|
|
|
|
LCD_SERIAL.write(adr >> 8);
|
|
|
|
LCD_SERIAL.write(adr & 0xFF);
|
2019-06-21 11:47:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DGUSDisplay::WritePGM(const char str[], uint8_t len) {
|
2020-09-24 18:28:48 -07:00
|
|
|
while (len--) LCD_SERIAL.write(pgm_read_byte(str++));
|
2019-06-21 11:47:23 +02:00
|
|
|
}
|
|
|
|
|
2020-07-19 14:35:15 -07:00
|
|
|
void DGUSDisplay::loop() {
|
|
|
|
// protect against recursion… ProcessRx() may indirectly call idle() when injecting gcode commands.
|
|
|
|
if (!no_reentrance) {
|
|
|
|
no_reentrance = true;
|
|
|
|
ProcessRx();
|
|
|
|
no_reentrance = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rx_datagram_state_t DGUSDisplay::rx_datagram_state = DGUS_IDLE;
|
|
|
|
uint8_t DGUSDisplay::rx_datagram_len = 0;
|
|
|
|
bool DGUSDisplay::Initialized = false;
|
|
|
|
bool DGUSDisplay::no_reentrance = false;
|
|
|
|
|
2019-06-21 11:47:23 +02:00
|
|
|
// A SW memory barrier, to ensure GCC does not overoptimize loops
|
|
|
|
#define sw_barrier() asm volatile("": : :"memory");
|
|
|
|
|
2020-07-19 14:35:15 -07:00
|
|
|
bool populate_VPVar(const uint16_t VP, DGUS_VP_Variable * const ramcopy) {
|
|
|
|
// DEBUG_ECHOPAIR("populate_VPVar ", VP);
|
|
|
|
const DGUS_VP_Variable *pvp = DGUSLCD_FindVPVar(VP);
|
|
|
|
// DEBUG_ECHOLNPAIR(" pvp ", (uint16_t )pvp);
|
|
|
|
if (!pvp) return false;
|
|
|
|
memcpy_P(ramcopy, pvp, sizeof(DGUS_VP_Variable));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-01-04 11:00:44 +08:00
|
|
|
#endif // HAS_DGUS_LCD
|