2016-03-25 06:19:46 +00:00
|
|
|
/**
|
2016-03-24 18:01:20 +00:00
|
|
|
* Marlin 3D Printer Firmware
|
2020-02-03 14:00:57 +00:00
|
|
|
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
2016-03-24 18:01:20 +00:00
|
|
|
*
|
|
|
|
* Based on Sprinter and grbl.
|
2019-06-28 04:57:50 +00:00
|
|
|
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
2016-03-24 18:01:20 +00: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 03:20:14 +00:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2016-03-24 18:01:20 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-07-17 02:02:52 +00:00
|
|
|
#include "../inc/MarlinConfig.h"
|
2017-09-06 11:28:32 +00:00
|
|
|
|
2021-03-24 17:21:11 +00:00
|
|
|
#include "../MarlinCore.h" // for printingIsPaused
|
|
|
|
|
2019-06-13 02:59:39 +00:00
|
|
|
#ifdef LED_BACKLIGHT_TIMEOUT
|
|
|
|
#include "../feature/leds/leds.h"
|
|
|
|
#endif
|
|
|
|
|
2019-12-01 23:39:28 +00:00
|
|
|
#if ENABLED(HOST_ACTION_COMMANDS)
|
|
|
|
#include "../feature/host_actions.h"
|
|
|
|
#endif
|
|
|
|
|
2020-11-18 04:30:32 +00:00
|
|
|
#if ENABLED(BROWSE_MEDIA_ON_INSERT, PASSWORD_ON_SD_PRINT_MENU)
|
|
|
|
#include "../feature/password/password.h"
|
|
|
|
#endif
|
|
|
|
|
2020-01-03 01:01:38 +00:00
|
|
|
// All displays share the MarlinUI class
|
2020-10-17 00:36:25 +00:00
|
|
|
#include "marlinui.h"
|
2019-12-01 23:39:28 +00:00
|
|
|
MarlinUI ui;
|
|
|
|
|
2019-05-08 01:32:50 +00:00
|
|
|
#if HAS_DISPLAY
|
2019-10-10 00:44:49 +00:00
|
|
|
#include "../gcode/queue.h"
|
2019-04-26 07:32:01 +00:00
|
|
|
#include "fontutils.h"
|
2018-11-29 01:28:31 +00:00
|
|
|
#include "../sd/cardreader.h"
|
2021-03-24 15:12:57 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ENABLED(DWIN_CREALITY_LCD)
|
|
|
|
#include "dwin/e3v2/dwin.h"
|
|
|
|
#endif
|
|
|
|
|
2021-03-24 17:21:11 +00:00
|
|
|
#if ENABLED(LCD_PROGRESS_BAR) && !IS_TFTGLCD_PANEL
|
|
|
|
#define BASIC_PROGRESS_BAR 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ANY(HAS_DISPLAY, HAS_STATUS_MESSAGE, BASIC_PROGRESS_BAR)
|
|
|
|
#include "../module/printcounter.h"
|
2018-11-13 07:47:45 +00:00
|
|
|
#endif
|
2018-05-15 04:54:50 +00:00
|
|
|
|
2020-01-26 06:02:06 +00:00
|
|
|
#if LCD_HAS_WAIT_FOR_MOVE
|
|
|
|
bool MarlinUI::wait_for_move; // = false
|
|
|
|
#endif
|
|
|
|
|
2020-07-24 02:28:44 +00:00
|
|
|
constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;
|
|
|
|
|
2021-03-24 15:12:57 +00:00
|
|
|
#if HAS_STATUS_MESSAGE
|
|
|
|
#if HAS_WIRED_LCD
|
|
|
|
#if ENABLED(STATUS_MESSAGE_SCROLLING)
|
|
|
|
uint8_t MarlinUI::status_scroll_offset; // = 0
|
|
|
|
constexpr uint8_t MAX_MESSAGE_LENGTH = _MAX(LONG_FILENAME_LENGTH, MAX_LANG_CHARSIZE * 2 * (LCD_WIDTH));
|
|
|
|
#else
|
|
|
|
constexpr uint8_t MAX_MESSAGE_LENGTH = MAX_LANG_CHARSIZE * (LCD_WIDTH);
|
|
|
|
#endif
|
2018-11-20 06:02:13 +00:00
|
|
|
#else
|
2021-03-24 15:12:57 +00:00
|
|
|
constexpr uint8_t MAX_MESSAGE_LENGTH = 63;
|
2018-11-20 06:02:13 +00:00
|
|
|
#endif
|
|
|
|
char MarlinUI::status_message[MAX_MESSAGE_LENGTH + 1];
|
2021-03-24 15:12:57 +00:00
|
|
|
uint8_t MarlinUI::alert_level; // = 0
|
2018-11-20 06:02:13 +00:00
|
|
|
#endif
|
|
|
|
|
2018-12-12 23:21:37 +00:00
|
|
|
#if ENABLED(LCD_SET_PROGRESS_MANUALLY)
|
2019-10-11 02:03:33 +00:00
|
|
|
MarlinUI::progress_t MarlinUI::progress_override; // = 0
|
2021-03-24 15:12:57 +00:00
|
|
|
#if ENABLED(USE_M73_REMAINING_TIME)
|
2019-11-13 01:36:54 +00:00
|
|
|
uint32_t MarlinUI::remaining_time;
|
|
|
|
#endif
|
2018-12-12 23:21:37 +00:00
|
|
|
#endif
|
|
|
|
|
2021-01-21 00:52:06 +00:00
|
|
|
#if HAS_MULTI_LANGUAGE
|
|
|
|
uint8_t MarlinUI::language; // Initialized by settings.load()
|
|
|
|
#endif
|
|
|
|
|
2020-10-28 01:41:12 +00:00
|
|
|
#if ENABLED(SOUND_MENU_ITEM)
|
|
|
|
bool MarlinUI::buzzer_enabled = true;
|
|
|
|
#endif
|
|
|
|
|
2020-08-06 05:49:15 +00:00
|
|
|
#if EITHER(PCA9632_BUZZER, USE_BEEPER)
|
2019-11-06 22:52:28 +00:00
|
|
|
#include "../libs/buzzer.h" // for BUZZ() macro
|
2019-08-24 03:30:11 +00:00
|
|
|
#if ENABLED(PCA9632_BUZZER)
|
|
|
|
#include "../feature/leds/pca9632.h"
|
|
|
|
#endif
|
2019-08-20 07:01:37 +00:00
|
|
|
void MarlinUI::buzz(const long duration, const uint16_t freq) {
|
2020-10-28 01:41:12 +00:00
|
|
|
if (!buzzer_enabled) return;
|
2019-11-06 22:52:28 +00:00
|
|
|
#if ENABLED(PCA9632_BUZZER)
|
2020-08-24 04:57:51 +00:00
|
|
|
PCA9632_buzz(duration, freq);
|
2019-08-20 07:01:37 +00:00
|
|
|
#elif USE_BEEPER
|
|
|
|
buzzer.tone(duration, freq);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-07-17 02:02:52 +00:00
|
|
|
#if PREHEAT_COUNT
|
|
|
|
preheat_t MarlinUI::material_preset[PREHEAT_COUNT]; // Initialized by settings.load()
|
|
|
|
PGM_P MarlinUI::get_preheat_label(const uint8_t m) {
|
|
|
|
#ifdef PREHEAT_1_LABEL
|
|
|
|
static PGMSTR(preheat_0_label, PREHEAT_1_LABEL);
|
|
|
|
#endif
|
|
|
|
#ifdef PREHEAT_2_LABEL
|
|
|
|
static PGMSTR(preheat_1_label, PREHEAT_2_LABEL);
|
|
|
|
#endif
|
|
|
|
#ifdef PREHEAT_3_LABEL
|
|
|
|
static PGMSTR(preheat_2_label, PREHEAT_3_LABEL);
|
|
|
|
#endif
|
|
|
|
#ifdef PREHEAT_4_LABEL
|
|
|
|
static PGMSTR(preheat_3_label, PREHEAT_4_LABEL);
|
|
|
|
#endif
|
|
|
|
#ifdef PREHEAT_5_LABEL
|
|
|
|
static PGMSTR(preheat_4_label, PREHEAT_5_LABEL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define _PLBL(N) preheat_##N##_label,
|
|
|
|
static PGM_P const preheat_labels[PREHEAT_COUNT] PROGMEM = { REPEAT(PREHEAT_COUNT, _PLBL) };
|
|
|
|
|
|
|
|
return (PGM_P)pgm_read_ptr(&preheat_labels[m]);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
#if HAS_WIRED_LCD
|
2018-11-11 18:16:24 +00:00
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
#if HAS_MARLINUI_U8GLIB
|
2020-10-17 00:36:25 +00:00
|
|
|
#include "dogm/marlinui_DOGM.h"
|
2018-11-13 07:47:45 +00:00
|
|
|
#endif
|
2018-11-11 18:16:24 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
#include "lcdprint.h"
|
2017-09-06 11:28:32 +00:00
|
|
|
|
|
|
|
#include "../sd/cardreader.h"
|
2020-10-09 11:25:23 +00:00
|
|
|
|
2017-09-06 11:28:32 +00:00
|
|
|
#include "../module/temperature.h"
|
|
|
|
#include "../module/planner.h"
|
2018-11-13 07:47:45 +00:00
|
|
|
#include "../module/motion.h"
|
2018-09-17 06:06:22 +00:00
|
|
|
|
2020-10-09 11:25:23 +00:00
|
|
|
#if HAS_LCD_MENU
|
|
|
|
#include "../module/settings.h"
|
|
|
|
#endif
|
|
|
|
|
2018-11-13 07:47:45 +00:00
|
|
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
2019-07-01 05:44:39 +00:00
|
|
|
#include "../feature/bedlevel/bedlevel.h"
|
2017-06-12 23:26:49 +00:00
|
|
|
#endif
|
|
|
|
|
2020-03-02 18:03:43 +00:00
|
|
|
#if HAS_TRINAMIC_CONFIG
|
2019-01-17 19:17:16 +00:00
|
|
|
#include "../feature/tmc_util.h"
|
|
|
|
#endif
|
|
|
|
|
2019-11-06 23:49:17 +00:00
|
|
|
#if HAS_ADC_BUTTONS
|
|
|
|
#include "../module/thermistor/thermistors.h"
|
|
|
|
#endif
|
|
|
|
|
2020-06-18 20:23:03 +00:00
|
|
|
#if HAS_POWER_MONITOR
|
|
|
|
#include "../feature/power_monitor.h"
|
|
|
|
#endif
|
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
#if HAS_ENCODER_ACTION
|
|
|
|
volatile uint8_t MarlinUI::buttons;
|
2018-11-21 03:39:30 +00:00
|
|
|
#if HAS_SLOW_BUTTONS
|
2018-11-11 18:16:24 +00:00
|
|
|
volatile uint8_t MarlinUI::slow_buttons;
|
|
|
|
#endif
|
2020-11-15 22:39:58 +00:00
|
|
|
#if HAS_TOUCH_BUTTONS
|
2020-08-21 23:54:21 +00:00
|
|
|
#include "touch/touch_buttons.h"
|
2020-06-12 02:21:18 +00:00
|
|
|
bool MarlinUI::on_edit_screen = false;
|
2019-07-14 23:16:26 +00:00
|
|
|
#endif
|
2018-11-11 18:16:24 +00:00
|
|
|
#endif
|
2018-10-28 07:59:21 +00:00
|
|
|
|
2020-05-06 08:34:05 +00:00
|
|
|
#if HAS_LCD_MENU && LCD_TIMEOUT_TO_STATUS > 0
|
2018-11-11 18:16:24 +00:00
|
|
|
bool MarlinUI::defer_return_to_status;
|
2018-05-01 02:16:31 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
uint8_t MarlinUI::lcd_status_update_delay = 1; // First update one loop delayed
|
|
|
|
|
2019-03-17 04:43:06 +00:00
|
|
|
#if BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT)
|
2018-11-11 18:16:24 +00:00
|
|
|
millis_t MarlinUI::next_filament_display; // = 0
|
2017-10-19 03:15:33 +00:00
|
|
|
#endif
|
2011-12-12 18:34:37 +00:00
|
|
|
|
2019-09-04 18:13:05 +00:00
|
|
|
millis_t MarlinUI::next_button_update_ms; // = 0
|
2018-10-23 21:00:34 +00:00
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
#if HAS_MARLINUI_U8GLIB
|
2018-11-11 18:16:24 +00:00
|
|
|
bool MarlinUI::drawing_screen, MarlinUI::first_page; // = false
|
2013-03-19 19:59:21 +00:00
|
|
|
#endif
|
2011-12-12 18:34:37 +00:00
|
|
|
|
2018-11-09 06:07:16 +00:00
|
|
|
// Encoder Handling
|
|
|
|
#if HAS_ENCODER_ACTION
|
2019-10-21 23:34:29 +00:00
|
|
|
uint32_t MarlinUI::encoderPosition;
|
2018-11-11 18:16:24 +00:00
|
|
|
volatile int8_t encoderDiff; // Updated in update_buttons, added to encoderPosition every LCD update
|
2018-10-23 21:00:34 +00:00
|
|
|
#endif
|
|
|
|
|
2020-06-16 06:45:27 +00:00
|
|
|
#if ENABLED(SDSUPPORT)
|
2018-11-17 03:44:48 +00:00
|
|
|
|
2020-06-16 06:45:27 +00:00
|
|
|
#include "../sd/cardreader.h"
|
2018-11-17 03:44:48 +00:00
|
|
|
|
2020-06-16 06:45:27 +00:00
|
|
|
#if MARLINUI_SCROLL_NAME
|
|
|
|
uint8_t MarlinUI::filename_scroll_pos, MarlinUI::filename_scroll_max;
|
|
|
|
#endif
|
2018-11-17 03:44:48 +00:00
|
|
|
|
2020-06-16 06:45:27 +00:00
|
|
|
const char * MarlinUI::scrolled_filename(CardReader &theCard, const uint8_t maxlen, uint8_t hash, const bool doScroll) {
|
|
|
|
const char *outstr = theCard.longest_filename();
|
|
|
|
if (theCard.longFilename[0]) {
|
|
|
|
#if MARLINUI_SCROLL_NAME
|
|
|
|
if (doScroll) {
|
|
|
|
for (uint8_t l = FILENAME_LENGTH; l--;)
|
|
|
|
hash = ((hash << 1) | (hash >> 7)) ^ theCard.filename[l]; // rotate, xor
|
|
|
|
static uint8_t filename_scroll_hash;
|
|
|
|
if (filename_scroll_hash != hash) { // If the hash changed...
|
|
|
|
filename_scroll_hash = hash; // Save the new hash
|
|
|
|
filename_scroll_max = _MAX(0, utf8_strlen(theCard.longFilename) - maxlen); // Update the scroll limit
|
|
|
|
filename_scroll_pos = 0; // Reset scroll to the start
|
|
|
|
lcd_status_update_delay = 8; // Don't scroll right away
|
2018-11-17 03:44:48 +00:00
|
|
|
}
|
2020-11-13 04:49:19 +00:00
|
|
|
// Advance byte position corresponding to filename_scroll_pos char position
|
|
|
|
outstr += TERN(UTF_FILENAME_SUPPORT, utf8_byte_pos_by_char_num(outstr, filename_scroll_pos), filename_scroll_pos);
|
2020-06-16 06:45:27 +00:00
|
|
|
}
|
|
|
|
#else
|
2020-11-13 04:49:19 +00:00
|
|
|
theCard.longFilename[
|
|
|
|
TERN(UTF_FILENAME_SUPPORT, utf8_byte_pos_by_char_num(theCard.longFilename, maxlen), maxlen)
|
|
|
|
] = '\0'; // cutoff at screen edge
|
2020-06-16 06:45:27 +00:00
|
|
|
#endif
|
2018-11-17 03:44:48 +00:00
|
|
|
}
|
2020-06-16 06:45:27 +00:00
|
|
|
return outstr;
|
|
|
|
}
|
2017-12-30 10:08:26 +00:00
|
|
|
|
2020-06-16 06:45:27 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if HAS_LCD_MENU
|
|
|
|
#include "menu/menu.h"
|
2018-11-11 18:16:24 +00:00
|
|
|
|
|
|
|
screenFunc_t MarlinUI::currentScreen; // Initialized in CTOR
|
2019-11-15 02:30:30 +00:00
|
|
|
bool MarlinUI::screen_changed;
|
2018-05-01 02:16:31 +00:00
|
|
|
|
2018-11-09 06:07:16 +00:00
|
|
|
#if ENABLED(ENCODER_RATE_MULTIPLIER)
|
2018-11-11 18:16:24 +00:00
|
|
|
bool MarlinUI::encoderRateMultiplierEnabled;
|
|
|
|
millis_t MarlinUI::lastEncoderMovementMillis = 0;
|
|
|
|
void MarlinUI::enable_encoder_multiplier(const bool onoff) {
|
|
|
|
encoderRateMultiplierEnabled = onoff;
|
|
|
|
lastEncoderMovementMillis = 0;
|
|
|
|
}
|
2018-11-09 06:07:16 +00:00
|
|
|
#endif
|
|
|
|
|
2019-07-30 22:42:57 +00:00
|
|
|
#if EITHER(REVERSE_MENU_DIRECTION, REVERSE_SELECT_DIRECTION)
|
|
|
|
int8_t MarlinUI::encoderDirection = ENCODERBASE;
|
2018-11-11 18:16:24 +00:00
|
|
|
#endif
|
|
|
|
|
2020-11-15 22:39:58 +00:00
|
|
|
#if HAS_TOUCH_BUTTONS
|
2019-12-06 06:47:50 +00:00
|
|
|
uint8_t MarlinUI::touch_buttons;
|
2019-09-13 03:14:24 +00:00
|
|
|
uint8_t MarlinUI::repeat_delay;
|
|
|
|
#endif
|
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
bool MarlinUI::lcd_clicked;
|
2018-05-01 02:16:31 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
bool MarlinUI::use_click() {
|
2018-10-23 21:00:34 +00:00
|
|
|
const bool click = lcd_clicked;
|
|
|
|
lcd_clicked = false;
|
|
|
|
return click;
|
|
|
|
}
|
2018-11-09 06:07:16 +00:00
|
|
|
|
2019-03-17 04:43:06 +00:00
|
|
|
#if EITHER(AUTO_BED_LEVELING_UBL, G26_MESH_VALIDATION)
|
2018-11-09 06:07:16 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
bool MarlinUI::external_control; // = false
|
|
|
|
|
|
|
|
void MarlinUI::wait_for_release() {
|
|
|
|
while (button_pressed()) safe_delay(50);
|
|
|
|
safe_delay(50);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2018-11-09 06:07:16 +00:00
|
|
|
|
2020-11-11 01:39:34 +00:00
|
|
|
#if !HAS_GRAPHICAL_TFT
|
|
|
|
|
|
|
|
void _wrap_string(uint8_t &col, uint8_t &row, const char * const string, read_byte_cb_t cb_read_byte, bool wordwrap/*=false*/) {
|
|
|
|
SETCURSOR(col, row);
|
|
|
|
if (!string) return;
|
|
|
|
|
|
|
|
auto _newline = [&col, &row]{
|
|
|
|
col = 0; row++; // Move col to string len (plus space)
|
|
|
|
SETCURSOR(0, row); // Simulate carriage return
|
|
|
|
};
|
|
|
|
|
|
|
|
uint8_t *p = (uint8_t*)string;
|
|
|
|
wchar_t ch;
|
|
|
|
if (wordwrap) {
|
|
|
|
uint8_t *wrd = nullptr, c = 0;
|
|
|
|
// find the end of the part
|
|
|
|
for (;;) {
|
|
|
|
if (!wrd) wrd = p; // Get word start /before/ advancing
|
|
|
|
p = get_utf8_value_cb(p, cb_read_byte, &ch);
|
|
|
|
const bool eol = !ch; // zero ends the string
|
|
|
|
// End or a break between phrases?
|
|
|
|
if (eol || ch == ' ' || ch == '-' || ch == '+' || ch == '.') {
|
|
|
|
if (!c && ch == ' ') { if (wrd) wrd++; continue; } // collapse extra spaces
|
|
|
|
// Past the right and the word is not too long?
|
|
|
|
if (col + c > LCD_WIDTH && col >= (LCD_WIDTH) / 4) _newline(); // should it wrap?
|
|
|
|
c += !eol; // +1 so the space will be printed
|
|
|
|
col += c; // advance col to new position
|
|
|
|
while (c) { // character countdown
|
|
|
|
--c; // count down to zero
|
|
|
|
wrd = get_utf8_value_cb(wrd, cb_read_byte, &ch); // get characters again
|
|
|
|
lcd_put_wchar(ch); // character to the LCD
|
|
|
|
}
|
|
|
|
if (eol) break; // all done!
|
|
|
|
wrd = nullptr; // set up for next word
|
2019-06-10 22:46:42 +00:00
|
|
|
}
|
2020-11-11 01:39:34 +00:00
|
|
|
else c++; // count word characters
|
2019-06-10 22:46:42 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-11 01:39:34 +00:00
|
|
|
else {
|
|
|
|
for (;;) {
|
|
|
|
p = get_utf8_value_cb(p, cb_read_byte, &ch);
|
|
|
|
if (!ch) break;
|
|
|
|
lcd_put_wchar(ch);
|
|
|
|
col++;
|
|
|
|
if (col >= LCD_WIDTH) _newline();
|
|
|
|
}
|
2019-04-08 18:44:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 01:39:34 +00:00
|
|
|
void MarlinUI::draw_select_screen_prompt(PGM_P const pref, const char * const string/*=nullptr*/, PGM_P const suff/*=nullptr*/) {
|
|
|
|
const uint8_t plen = utf8_strlen_P(pref), slen = suff ? utf8_strlen_P(suff) : 0;
|
|
|
|
uint8_t col = 0, row = 0;
|
|
|
|
if (!string && plen + slen <= LCD_WIDTH) {
|
|
|
|
col = (LCD_WIDTH - plen - slen) / 2;
|
|
|
|
row = LCD_HEIGHT > 3 ? 1 : 0;
|
|
|
|
}
|
|
|
|
wrap_string_P(col, row, pref, true);
|
|
|
|
if (string) {
|
|
|
|
if (col) { col = 0; row++; } // Move to the start of the next line
|
|
|
|
wrap_string(col, row, string);
|
|
|
|
}
|
|
|
|
if (suff) wrap_string_P(col, row, suff);
|
2019-04-24 15:13:44 +00:00
|
|
|
}
|
2020-11-11 01:39:34 +00:00
|
|
|
|
|
|
|
#endif // !HAS_GRAPHICAL_TFT
|
2019-04-24 15:13:44 +00:00
|
|
|
|
2019-04-08 18:44:35 +00:00
|
|
|
#endif // HAS_LCD_MENU
|
2018-05-01 02:16:31 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
void MarlinUI::init() {
|
|
|
|
|
|
|
|
init_lcd();
|
2017-12-31 05:57:12 +00:00
|
|
|
|
2018-11-18 03:21:30 +00:00
|
|
|
#if HAS_DIGITAL_BUTTONS
|
2018-10-23 21:00:34 +00:00
|
|
|
#if BUTTON_EXISTS(EN1)
|
|
|
|
SET_INPUT_PULLUP(BTN_EN1);
|
2016-06-30 09:24:29 +00:00
|
|
|
#endif
|
2018-10-23 21:00:34 +00:00
|
|
|
#if BUTTON_EXISTS(EN2)
|
|
|
|
SET_INPUT_PULLUP(BTN_EN2);
|
|
|
|
#endif
|
|
|
|
#if BUTTON_EXISTS(ENC)
|
|
|
|
SET_INPUT_PULLUP(BTN_ENC);
|
2018-01-04 11:06:34 +00:00
|
|
|
#endif
|
2020-10-25 00:41:52 +00:00
|
|
|
#if BUTTON_EXISTS(ENC_EN)
|
|
|
|
SET_INPUT_PULLUP(BTN_ENC_EN);
|
|
|
|
#endif
|
2019-10-24 17:04:45 +00:00
|
|
|
#if BUTTON_EXISTS(BACK)
|
|
|
|
SET_INPUT_PULLUP(BTN_BACK);
|
|
|
|
#endif
|
2018-10-23 21:00:34 +00:00
|
|
|
#if BUTTON_EXISTS(UP)
|
|
|
|
SET_INPUT(BTN_UP);
|
|
|
|
#endif
|
|
|
|
#if BUTTON_EXISTS(DWN)
|
|
|
|
SET_INPUT(BTN_DWN);
|
|
|
|
#endif
|
|
|
|
#if BUTTON_EXISTS(LFT)
|
|
|
|
SET_INPUT(BTN_LFT);
|
|
|
|
#endif
|
|
|
|
#if BUTTON_EXISTS(RT)
|
|
|
|
SET_INPUT(BTN_RT);
|
|
|
|
#endif
|
2021-01-13 02:43:52 +00:00
|
|
|
#endif
|
2018-11-19 02:39:49 +00:00
|
|
|
|
|
|
|
#if HAS_SHIFT_ENCODER
|
2017-04-17 02:32:52 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
#if ENABLED(SR_LCD_2W_NL) // Non latching 2 wire shift register
|
2018-11-19 02:39:49 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
SET_OUTPUT(SR_DATA_PIN);
|
|
|
|
SET_OUTPUT(SR_CLK_PIN);
|
2018-11-19 02:39:49 +00:00
|
|
|
|
2021-01-13 02:43:52 +00:00
|
|
|
#elif PIN_EXISTS(SHIFT_CLK)
|
2018-11-19 02:39:49 +00:00
|
|
|
|
2021-01-13 02:43:52 +00:00
|
|
|
SET_OUTPUT(SHIFT_CLK_PIN);
|
|
|
|
OUT_WRITE(SHIFT_LD_PIN, HIGH);
|
|
|
|
#if PIN_EXISTS(SHIFT_EN)
|
|
|
|
OUT_WRITE(SHIFT_EN_PIN, LOW);
|
2018-11-19 02:39:49 +00:00
|
|
|
#endif
|
2021-01-13 02:43:52 +00:00
|
|
|
SET_INPUT_PULLUP(SHIFT_OUT_PIN);
|
2017-04-17 02:32:52 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // HAS_SHIFT_ENCODER
|
2017-04-17 02:32:52 +00:00
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
#if BOTH(HAS_ENCODER_ACTION, HAS_SLOW_BUTTONS)
|
2020-04-01 23:53:58 +00:00
|
|
|
slow_buttons = 0;
|
2017-10-07 23:16:41 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
update_buttons();
|
2016-04-02 23:09:56 +00:00
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_ENCODER_ACTION, encoderDiff = 0);
|
2018-10-23 21:00:34 +00:00
|
|
|
}
|
2012-12-12 10:47:03 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
bool MarlinUI::get_blink() {
|
2018-10-23 21:00:34 +00:00
|
|
|
static uint8_t blink = 0;
|
|
|
|
static millis_t next_blink_ms = 0;
|
|
|
|
millis_t ms = millis();
|
|
|
|
if (ELAPSED(ms, next_blink_ms)) {
|
|
|
|
blink ^= 0xFF;
|
|
|
|
next_blink_ms = ms + 1000 - (LCD_UPDATE_INTERVAL) / 2;
|
2017-12-27 04:12:05 +00:00
|
|
|
}
|
2018-10-23 21:00:34 +00:00
|
|
|
return blink != 0;
|
|
|
|
}
|
2017-12-27 04:12:05 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
////////////////////////////////////////////
|
|
|
|
///////////// Keypad Handling //////////////
|
|
|
|
////////////////////////////////////////////
|
2017-03-03 01:15:21 +00:00
|
|
|
|
2020-10-15 08:00:27 +00:00
|
|
|
#if IS_RRW_KEYPAD && HAS_ENCODER_ACTION
|
2018-10-28 07:59:21 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
volatile uint8_t MarlinUI::keypad_buttons;
|
2017-03-03 01:15:21 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
#if HAS_LCD_MENU && !HAS_ADC_BUTTONS
|
2018-11-09 06:07:16 +00:00
|
|
|
|
|
|
|
void lcd_move_x();
|
|
|
|
void lcd_move_y();
|
|
|
|
void lcd_move_z();
|
|
|
|
|
|
|
|
void _reprapworld_keypad_move(const AxisEnum axis, const int16_t dir) {
|
2020-07-03 14:53:22 +00:00
|
|
|
ui.manual_move.menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
|
2020-03-02 01:54:22 +00:00
|
|
|
ui.encoderPosition = dir;
|
2018-11-09 06:07:16 +00:00
|
|
|
switch (axis) {
|
|
|
|
case X_AXIS: lcd_move_x(); break;
|
|
|
|
case Y_AXIS: lcd_move_y(); break;
|
|
|
|
case Z_AXIS: lcd_move_z();
|
|
|
|
default: break;
|
|
|
|
}
|
2018-10-23 21:00:34 +00:00
|
|
|
}
|
2018-11-09 06:07:16 +00:00
|
|
|
|
|
|
|
#endif
|
2017-05-29 17:19:02 +00:00
|
|
|
|
2018-11-14 12:00:21 +00:00
|
|
|
bool MarlinUI::handle_keypad() {
|
2012-12-12 10:47:03 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
#if HAS_ADC_BUTTONS
|
2016-03-09 11:52:05 +00:00
|
|
|
|
2018-11-14 12:00:21 +00:00
|
|
|
#define ADC_MIN_KEY_DELAY 100
|
2018-11-19 02:39:49 +00:00
|
|
|
if (keypad_buttons) {
|
2018-11-14 12:00:21 +00:00
|
|
|
#if HAS_ENCODER_ACTION
|
|
|
|
refresh(LCDVIEW_REDRAW_NOW);
|
2018-11-22 12:00:00 +00:00
|
|
|
#if HAS_LCD_MENU
|
2020-10-15 08:00:27 +00:00
|
|
|
if (encoderDirection == -(ENCODERBASE)) { // HAS_ADC_BUTTONS forces REVERSE_MENU_DIRECTION, so this indicates menu navigation
|
2018-11-22 12:00:00 +00:00
|
|
|
if (RRK(EN_KEYPAD_UP)) encoderPosition += ENCODER_STEPS_PER_MENU_ITEM;
|
|
|
|
else if (RRK(EN_KEYPAD_DOWN)) encoderPosition -= ENCODER_STEPS_PER_MENU_ITEM;
|
2018-11-21 03:39:30 +00:00
|
|
|
else if (RRK(EN_KEYPAD_LEFT)) { MenuItem_back::action(); quick_feedback(); }
|
|
|
|
else if (RRK(EN_KEYPAD_RIGHT)) { return_to_status(); quick_feedback(); }
|
2018-11-22 12:00:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
#if HAS_LCD_MENU
|
2020-07-24 02:28:44 +00:00
|
|
|
if (RRK(EN_KEYPAD_UP)) encoderPosition -= epps;
|
|
|
|
else if (RRK(EN_KEYPAD_DOWN)) encoderPosition += epps;
|
2018-11-22 12:00:00 +00:00
|
|
|
else if (RRK(EN_KEYPAD_LEFT)) { MenuItem_back::action(); quick_feedback(); }
|
|
|
|
else if (RRK(EN_KEYPAD_RIGHT)) encoderPosition = 0;
|
|
|
|
#else
|
2020-07-24 02:28:44 +00:00
|
|
|
if (RRK(EN_KEYPAD_UP) || RRK(EN_KEYPAD_LEFT)) encoderPosition -= epps;
|
|
|
|
else if (RRK(EN_KEYPAD_DOWN) || RRK(EN_KEYPAD_RIGHT)) encoderPosition += epps;
|
2018-11-14 12:00:21 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
next_button_update_ms = millis() + ADC_MIN_KEY_DELAY;
|
|
|
|
return true;
|
|
|
|
}
|
2016-04-03 04:12:18 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
#else // !HAS_ADC_BUTTONS
|
2017-08-16 07:27:50 +00:00
|
|
|
|
2018-11-14 12:00:21 +00:00
|
|
|
static uint8_t keypad_debounce = 0;
|
2018-10-23 21:00:34 +00:00
|
|
|
|
2018-11-21 03:39:30 +00:00
|
|
|
if (!RRK( EN_KEYPAD_F1 | EN_KEYPAD_F2
|
|
|
|
| EN_KEYPAD_F3 | EN_KEYPAD_DOWN
|
|
|
|
| EN_KEYPAD_RIGHT | EN_KEYPAD_MIDDLE
|
|
|
|
| EN_KEYPAD_UP | EN_KEYPAD_LEFT )
|
2018-11-14 12:00:21 +00:00
|
|
|
) {
|
|
|
|
if (keypad_debounce > 0) keypad_debounce--;
|
|
|
|
}
|
|
|
|
else if (!keypad_debounce) {
|
|
|
|
keypad_debounce = 2;
|
2018-11-09 06:07:16 +00:00
|
|
|
|
2018-11-14 12:00:21 +00:00
|
|
|
const bool homed = all_axes_homed();
|
|
|
|
|
|
|
|
#if HAS_LCD_MENU
|
2018-11-09 06:07:16 +00:00
|
|
|
|
2018-11-21 03:39:30 +00:00
|
|
|
if (RRK(EN_KEYPAD_MIDDLE)) goto_screen(menu_move);
|
2018-11-14 12:00:21 +00:00
|
|
|
|
2019-07-02 14:38:29 +00:00
|
|
|
#if DISABLED(DELTA) && Z_HOME_DIR < 0
|
2018-11-21 03:39:30 +00:00
|
|
|
if (RRK(EN_KEYPAD_F2)) _reprapworld_keypad_move(Z_AXIS, 1);
|
2018-11-09 06:07:16 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-14 12:00:21 +00:00
|
|
|
if (homed) {
|
|
|
|
#if ENABLED(DELTA) || Z_HOME_DIR != -1
|
2018-11-21 03:39:30 +00:00
|
|
|
if (RRK(EN_KEYPAD_F2)) _reprapworld_keypad_move(Z_AXIS, 1);
|
2018-11-14 12:00:21 +00:00
|
|
|
#endif
|
2018-11-21 03:39:30 +00:00
|
|
|
if (RRK(EN_KEYPAD_F3)) _reprapworld_keypad_move(Z_AXIS, -1);
|
|
|
|
if (RRK(EN_KEYPAD_LEFT)) _reprapworld_keypad_move(X_AXIS, -1);
|
|
|
|
if (RRK(EN_KEYPAD_RIGHT)) _reprapworld_keypad_move(X_AXIS, 1);
|
|
|
|
if (RRK(EN_KEYPAD_DOWN)) _reprapworld_keypad_move(Y_AXIS, 1);
|
|
|
|
if (RRK(EN_KEYPAD_UP)) _reprapworld_keypad_move(Y_AXIS, -1);
|
2018-11-14 12:00:21 +00:00
|
|
|
}
|
2018-11-09 06:07:16 +00:00
|
|
|
|
2018-11-14 12:00:21 +00:00
|
|
|
#endif // HAS_LCD_MENU
|
|
|
|
|
2019-11-02 04:51:25 +00:00
|
|
|
if (!homed && RRK(EN_KEYPAD_F1)) queue.inject_P(G28_STR);
|
2018-11-14 12:00:21 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-10-15 08:00:27 +00:00
|
|
|
#endif // !HAS_ADC_BUTTONS
|
2018-11-14 12:00:21 +00:00
|
|
|
|
|
|
|
return false;
|
2018-03-06 05:05:15 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 08:00:27 +00:00
|
|
|
#endif // IS_RRW_KEYPAD && HAS_ENCODER_ACTION
|
2016-03-09 11:52:05 +00:00
|
|
|
|
2015-04-28 02:11:25 +00:00
|
|
|
/**
|
2018-10-23 21:00:34 +00:00
|
|
|
* Status Screen
|
2015-04-28 02:11:25 +00:00
|
|
|
*
|
|
|
|
* This is very display-dependent, so the lcd implementation draws this.
|
|
|
|
*/
|
|
|
|
|
2021-03-24 17:21:11 +00:00
|
|
|
#if BASIC_PROGRESS_BAR
|
2018-11-11 18:16:24 +00:00
|
|
|
millis_t MarlinUI::progress_bar_ms; // = 0
|
2018-10-30 21:34:45 +00:00
|
|
|
#if PROGRESS_MSG_EXPIRE > 0
|
2018-11-11 18:16:24 +00:00
|
|
|
millis_t MarlinUI::expire_status_ms; // = 0
|
2018-10-30 21:34:45 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
void MarlinUI::status_screen() {
|
2016-06-11 21:12:00 +00:00
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_LCD_MENU, ENCODER_RATE_MULTIPLY(false));
|
2015-03-31 01:00:54 +00:00
|
|
|
|
2021-03-24 17:21:11 +00:00
|
|
|
#if BASIC_PROGRESS_BAR
|
2017-10-15 07:15:19 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// HD44780 implements the following message blinking and
|
|
|
|
// message expiration because Status Line and Progress Bar
|
|
|
|
// share the same line on the display.
|
|
|
|
//
|
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
#if DISABLED(PROGRESS_MSG_ONCE) || (PROGRESS_MSG_EXPIRE > 0)
|
2019-01-05 01:30:08 +00:00
|
|
|
#define GOT_MS
|
|
|
|
const millis_t ms = millis();
|
2018-11-19 02:39:49 +00:00
|
|
|
#endif
|
2017-10-15 07:15:19 +00:00
|
|
|
|
|
|
|
// If the message will blink rather than expire...
|
2015-08-03 19:30:37 +00:00
|
|
|
#if DISABLED(PROGRESS_MSG_ONCE)
|
2017-10-15 07:15:19 +00:00
|
|
|
if (ELAPSED(ms, progress_bar_ms + PROGRESS_BAR_MSG_TIME + PROGRESS_BAR_BAR_TIME))
|
2015-04-25 05:16:09 +00:00
|
|
|
progress_bar_ms = ms;
|
2014-12-28 06:26:14 +00:00
|
|
|
#endif
|
2017-10-15 07:15:19 +00:00
|
|
|
|
2014-12-28 06:26:14 +00:00
|
|
|
#if PROGRESS_MSG_EXPIRE > 0
|
2017-10-15 07:15:19 +00:00
|
|
|
|
2015-03-31 01:00:54 +00:00
|
|
|
// Handle message expire
|
2020-03-26 01:47:27 +00:00
|
|
|
if (expire_status_ms) {
|
2017-10-15 07:15:19 +00:00
|
|
|
|
|
|
|
// Expire the message if a job is active and the bar has ticks
|
2019-10-11 02:03:33 +00:00
|
|
|
if (get_progress_percent() > 2 && !print_job_timer.isPaused()) {
|
2017-10-15 07:15:19 +00:00
|
|
|
if (ELAPSED(ms, expire_status_ms)) {
|
2018-11-11 18:16:24 +00:00
|
|
|
status_message[0] = '\0';
|
2015-09-05 00:40:12 +00:00
|
|
|
expire_status_ms = 0;
|
2014-12-28 06:26:14 +00:00
|
|
|
}
|
2017-10-15 07:15:19 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Defer message expiration before bar appears
|
|
|
|
// and during any pause (not just SD)
|
|
|
|
expire_status_ms += LCD_UPDATE_INTERVAL;
|
|
|
|
}
|
2014-12-28 06:26:14 +00:00
|
|
|
}
|
2017-10-15 07:15:19 +00:00
|
|
|
|
|
|
|
#endif // PROGRESS_MSG_EXPIRE
|
|
|
|
|
2021-03-24 17:21:11 +00:00
|
|
|
#endif // BASIC_PROGRESS_BAR
|
2014-12-28 06:26:14 +00:00
|
|
|
|
2018-10-30 21:34:45 +00:00
|
|
|
#if HAS_LCD_MENU
|
2017-12-27 04:12:05 +00:00
|
|
|
if (use_click()) {
|
2019-03-17 04:43:06 +00:00
|
|
|
#if BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT)
|
2018-11-11 18:16:24 +00:00
|
|
|
next_filament_display = millis() + 5000UL; // Show status message for 5s
|
2016-08-06 23:24:26 +00:00
|
|
|
#endif
|
2018-11-11 18:16:24 +00:00
|
|
|
goto_screen(menu_main);
|
2019-06-24 08:42:22 +00:00
|
|
|
#if DISABLED(NO_LCD_REINIT)
|
|
|
|
init_lcd(); // May revive the LCD if static electricity killed it
|
|
|
|
#endif
|
2017-05-30 00:09:38 +00:00
|
|
|
return;
|
2012-12-12 10:47:03 +00:00
|
|
|
}
|
2013-06-06 22:49:25 +00:00
|
|
|
|
2019-07-23 01:08:54 +00:00
|
|
|
#endif
|
2018-11-09 06:07:16 +00:00
|
|
|
|
2019-01-05 01:30:08 +00:00
|
|
|
#if ENABLED(ULTIPANEL_FEEDMULTIPLY)
|
|
|
|
|
|
|
|
const int16_t old_frm = feedrate_percentage;
|
2019-04-09 02:10:41 +00:00
|
|
|
int16_t new_frm = old_frm + int16_t(encoderPosition);
|
2018-11-09 06:07:16 +00:00
|
|
|
|
|
|
|
// Dead zone at 100% feedrate
|
2019-01-05 01:30:08 +00:00
|
|
|
if (old_frm == 100) {
|
2019-04-09 02:10:41 +00:00
|
|
|
if (int16_t(encoderPosition) > ENCODER_FEEDRATE_DEADZONE)
|
2019-01-05 01:30:08 +00:00
|
|
|
new_frm -= ENCODER_FEEDRATE_DEADZONE;
|
2019-04-09 02:10:41 +00:00
|
|
|
else if (int16_t(encoderPosition) < -(ENCODER_FEEDRATE_DEADZONE))
|
2019-01-05 01:30:08 +00:00
|
|
|
new_frm += ENCODER_FEEDRATE_DEADZONE;
|
|
|
|
else
|
|
|
|
new_frm = old_frm;
|
2018-11-09 06:07:16 +00:00
|
|
|
}
|
2019-01-05 01:30:08 +00:00
|
|
|
else if ((old_frm < 100 && new_frm > 100) || (old_frm > 100 && new_frm < 100))
|
|
|
|
new_frm = 100;
|
|
|
|
|
2019-07-10 08:33:28 +00:00
|
|
|
LIMIT(new_frm, 10, 999);
|
2019-01-05 01:30:08 +00:00
|
|
|
|
|
|
|
if (old_frm != new_frm) {
|
2018-11-09 06:07:16 +00:00
|
|
|
feedrate_percentage = new_frm;
|
|
|
|
encoderPosition = 0;
|
2020-04-24 02:42:38 +00:00
|
|
|
#if BOTH(HAS_BUZZER, BEEP_ON_FEEDRATE_CHANGE)
|
2019-01-05 01:30:08 +00:00
|
|
|
static millis_t next_beep;
|
|
|
|
#ifndef GOT_MS
|
|
|
|
const millis_t ms = millis();
|
|
|
|
#endif
|
|
|
|
if (ELAPSED(ms, next_beep)) {
|
2019-08-20 07:01:37 +00:00
|
|
|
buzz(FEEDRATE_CHANGE_BEEP_DURATION, FEEDRATE_CHANGE_BEEP_FREQUENCY);
|
2019-01-05 01:30:08 +00:00
|
|
|
next_beep = ms + 500UL;
|
|
|
|
}
|
|
|
|
#endif
|
2018-11-09 06:07:16 +00:00
|
|
|
}
|
2015-04-11 11:45:04 +00:00
|
|
|
|
2018-11-09 06:07:16 +00:00
|
|
|
#endif // ULTIPANEL_FEEDMULTIPLY
|
2017-05-30 00:09:38 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
draw_status_screen();
|
2011-12-12 18:34:37 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 00:46:10 +00:00
|
|
|
void MarlinUI::kill_screen(PGM_P lcd_error, PGM_P lcd_component) {
|
2018-11-11 18:16:24 +00:00
|
|
|
init();
|
2019-10-10 00:46:10 +00:00
|
|
|
status_printf_P(1, PSTR(S_FMT ": " S_FMT), lcd_error, lcd_component);
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_LCD_MENU, return_to_status());
|
2019-06-13 02:59:39 +00:00
|
|
|
|
|
|
|
// RED ALERT. RED ALERT.
|
|
|
|
#ifdef LED_BACKLIGHT_TIMEOUT
|
|
|
|
leds.set_color(LEDColorRed());
|
|
|
|
#ifdef NEOPIXEL_BKGD_LED_INDEX
|
2019-07-21 04:14:09 +00:00
|
|
|
neo.set_pixel_color(NEOPIXEL_BKGD_LED_INDEX, 255, 0, 0, 0);
|
|
|
|
neo.show();
|
2019-06-13 02:59:39 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
draw_kill_screen();
|
2016-07-10 02:50:45 +00:00
|
|
|
}
|
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) {
|
2018-04-22 00:41:26 +00:00
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_LCD_MENU, refresh());
|
2018-11-11 18:16:24 +00:00
|
|
|
|
|
|
|
#if HAS_ENCODER_ACTION
|
2018-10-23 21:00:34 +00:00
|
|
|
if (clear_buttons) buttons = 0;
|
|
|
|
next_button_update_ms = millis() + 500;
|
|
|
|
#else
|
|
|
|
UNUSED(clear_buttons);
|
|
|
|
#endif
|
2015-06-17 14:31:14 +00:00
|
|
|
|
2020-05-27 18:12:08 +00:00
|
|
|
#if HAS_CHIRP
|
|
|
|
chirp(); // Buzz and wait. Is the delay needed for buttons to settle?
|
|
|
|
#if BOTH(HAS_LCD_MENU, USE_BEEPER)
|
|
|
|
for (int8_t i = 5; i--;) { buzzer.tick(); delay(2); }
|
|
|
|
#elif HAS_LCD_MENU
|
|
|
|
delay(10);
|
2018-10-23 21:00:34 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
2015-09-05 00:40:12 +00:00
|
|
|
|
2018-11-13 07:47:45 +00:00
|
|
|
////////////////////////////////////////////
|
|
|
|
/////////////// Manual Move ////////////////
|
|
|
|
////////////////////////////////////////////
|
|
|
|
|
2018-10-30 21:34:45 +00:00
|
|
|
#if HAS_LCD_MENU
|
2016-06-11 21:12:00 +00:00
|
|
|
|
2020-07-03 14:53:22 +00:00
|
|
|
ManualMove MarlinUI::manual_move{};
|
2016-06-11 21:12:00 +00:00
|
|
|
|
2020-07-03 14:53:22 +00:00
|
|
|
millis_t ManualMove::start_time = 0;
|
|
|
|
float ManualMove::menu_scale = 1;
|
2021-01-03 01:01:09 +00:00
|
|
|
#if IS_KINEMATIC
|
|
|
|
float ManualMove::offset = 0;
|
|
|
|
xyze_pos_t ManualMove::all_axes_destination = { 0 };
|
|
|
|
bool ManualMove::processing = false;
|
|
|
|
#endif
|
2021-03-24 10:40:28 +00:00
|
|
|
#if ENABLED(MULTI_MANUAL)
|
|
|
|
int8_t ManualMove::e_index = 0;
|
|
|
|
#endif
|
2021-01-02 02:08:10 +00:00
|
|
|
AxisEnum ManualMove::axis = NO_AXIS;
|
2011-12-12 18:34:37 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
/**
|
2020-07-03 14:53:22 +00:00
|
|
|
* If a manual move has been posted and its time has arrived, and if the planner
|
|
|
|
* has a space for it, then add a linear move to current_position the planner.
|
|
|
|
*
|
|
|
|
* If any manual move needs to be interrupted, make sure to force a manual move
|
|
|
|
* by setting manual_move.start_time to millis() after updating current_position.
|
|
|
|
*
|
|
|
|
* To post a manual move:
|
|
|
|
* - Update current_position to the new place you want to go.
|
|
|
|
* - Set manual_move.axis to an axis like X_AXIS. Use ALL_AXES for diagonal moves.
|
|
|
|
* - Set manual_move.start_time to a point in the future (in ms) when the move should be done.
|
|
|
|
*
|
|
|
|
* For kinematic machines:
|
|
|
|
* - Set manual_move.offset to modify one axis and post the move.
|
|
|
|
* This is used to achieve more rapid stepping on kinematic machines.
|
|
|
|
*
|
|
|
|
* Currently used by the _lcd_move_xyz function in menu_motion.cpp
|
|
|
|
* and the ubl_map_move_to_xy funtion in menu_ubl.cpp.
|
2018-10-23 21:00:34 +00:00
|
|
|
*/
|
2020-07-03 14:53:22 +00:00
|
|
|
void ManualMove::task() {
|
2015-10-03 06:08:58 +00:00
|
|
|
|
2020-07-03 14:53:22 +00:00
|
|
|
if (processing) return; // Prevent re-entry from idle() calls
|
2015-02-22 01:38:56 +00:00
|
|
|
|
2020-07-03 14:53:22 +00:00
|
|
|
// Add a manual move to the queue?
|
2021-01-02 02:08:10 +00:00
|
|
|
if (axis != NO_AXIS && ELAPSED(millis(), start_time) && !planner.is_full()) {
|
2020-07-03 14:53:22 +00:00
|
|
|
|
2021-01-02 02:08:10 +00:00
|
|
|
const feedRate_t fr_mm_s = (axis <= E_AXIS) ? manual_feedrate_mm_s[axis] : XY_PROBE_FEEDRATE_MM_S;
|
2015-10-03 06:08:58 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
#if IS_KINEMATIC
|
2015-10-03 06:08:58 +00:00
|
|
|
|
2020-09-20 23:29:08 +00:00
|
|
|
#if HAS_MULTI_EXTRUDER
|
2021-01-02 02:08:10 +00:00
|
|
|
REMEMBER(ae, active_extruder);
|
2020-07-03 14:53:22 +00:00
|
|
|
if (axis == E_AXIS) active_extruder = e_index;
|
2018-10-23 21:00:34 +00:00
|
|
|
#endif
|
2015-10-03 06:08:58 +00:00
|
|
|
|
2020-07-03 14:53:22 +00:00
|
|
|
// Apply a linear offset to a single axis
|
2021-01-03 01:01:09 +00:00
|
|
|
if (axis == ALL_AXES)
|
|
|
|
destination = all_axes_destination;
|
|
|
|
else if (axis <= XYZE) {
|
|
|
|
destination = current_position;
|
|
|
|
destination[axis] += offset;
|
|
|
|
}
|
2015-10-03 06:08:58 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
// Reset for the next move
|
2020-07-03 14:53:22 +00:00
|
|
|
offset = 0;
|
2021-01-02 02:08:10 +00:00
|
|
|
axis = NO_AXIS;
|
2013-10-30 10:45:32 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
// DELTA and SCARA machines use segmented moves, which could fill the planner during the call to
|
|
|
|
// move_to_destination. This will cause idle() to be called, which can then call this function while the
|
2020-07-03 14:53:22 +00:00
|
|
|
// previous invocation is being blocked. Modifications to offset shouldn't be made while
|
|
|
|
// processing is true or the planner will get out of sync.
|
|
|
|
processing = true;
|
2019-09-26 06:28:09 +00:00
|
|
|
prepare_internal_move_to_destination(fr_mm_s); // will set current_position from destination
|
2020-07-03 14:53:22 +00:00
|
|
|
processing = false;
|
2015-02-22 01:38:56 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
#else
|
2015-02-22 01:38:56 +00:00
|
|
|
|
2020-07-03 14:53:22 +00:00
|
|
|
// For Cartesian / Core motion simply move to the current_position
|
|
|
|
planner.buffer_line(current_position, fr_mm_s, axis == E_AXIS ? e_index : active_extruder);
|
|
|
|
|
2021-04-07 20:43:07 +00:00
|
|
|
//SERIAL_ECHOLNPAIR("Add planner.move with Axis ", AS_CHAR(axis_codes[axis]), " at FR ", fr_mm_s);
|
2020-07-03 14:53:22 +00:00
|
|
|
|
2021-01-02 02:08:10 +00:00
|
|
|
axis = NO_AXIS;
|
2011-12-12 18:34:37 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
#endif
|
|
|
|
}
|
2016-03-29 02:33:04 +00:00
|
|
|
}
|
2018-10-23 21:00:34 +00:00
|
|
|
|
2020-07-03 14:53:22 +00:00
|
|
|
//
|
|
|
|
// Tell ui.update() to start a move to current_position after a short delay.
|
|
|
|
//
|
|
|
|
void ManualMove::soon(AxisEnum move_axis
|
|
|
|
#if MULTI_MANUAL
|
|
|
|
, const int8_t eindex/*=-1*/
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
#if MULTI_MANUAL
|
|
|
|
if (move_axis == E_AXIS) e_index = eindex >= 0 ? eindex : active_extruder;
|
|
|
|
#endif
|
|
|
|
start_time = millis() + (menu_scale < 0.99f ? 0UL : 250UL); // delay for bigger moves
|
2021-01-02 02:08:10 +00:00
|
|
|
axis = move_axis;
|
2021-04-07 20:43:07 +00:00
|
|
|
//SERIAL_ECHOLNPAIR("Post Move with Axis ", AS_CHAR(axis_codes[axis]), " soon.");
|
2020-07-03 14:53:22 +00:00
|
|
|
}
|
|
|
|
|
2020-07-25 20:57:16 +00:00
|
|
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
2020-07-03 14:53:22 +00:00
|
|
|
|
2020-07-25 20:57:16 +00:00
|
|
|
void MarlinUI::external_encoder() {
|
|
|
|
if (external_control && encoderDiff) {
|
|
|
|
ubl.encoder_diff += encoderDiff; // Encoder for UBL G29 mesh editing
|
|
|
|
encoderDiff = 0; // Hide encoder events from the screen handler
|
|
|
|
refresh(LCDVIEW_REDRAW_NOW); // ...but keep the refresh.
|
|
|
|
}
|
2020-07-03 14:53:22 +00:00
|
|
|
}
|
|
|
|
|
2020-07-25 20:57:16 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // HAS_LCD_MENU
|
2020-07-03 14:53:22 +00:00
|
|
|
|
2015-04-28 02:11:25 +00:00
|
|
|
/**
|
|
|
|
* Update the LCD, read encoder buttons, etc.
|
|
|
|
* - Read button states
|
|
|
|
* - Check the SD Card slot state
|
|
|
|
* - Act on RepRap World keypad input
|
|
|
|
* - Update the encoder position
|
|
|
|
* - Apply acceleration to the encoder position
|
2018-11-11 18:16:24 +00:00
|
|
|
* - Do refresh(LCDVIEW_CALL_REDRAW_NOW) on controller events
|
2015-04-28 02:11:25 +00:00
|
|
|
* - Reset the Info Screen timeout if there's any input
|
|
|
|
* - Update status indicators, if any
|
|
|
|
*
|
2016-04-02 23:09:56 +00:00
|
|
|
* Run the current LCD menu handler callback function:
|
2016-04-09 02:52:40 +00:00
|
|
|
* - Call the handler only if lcdDrawUpdate != LCDVIEW_NONE
|
|
|
|
* - Before calling the handler, LCDVIEW_CALL_NO_REDRAW => LCDVIEW_NONE
|
2016-04-02 23:09:56 +00:00
|
|
|
* - Call the menu handler. Menu handlers should do the following:
|
2016-04-21 02:49:00 +00:00
|
|
|
* - If a value changes, set lcdDrawUpdate to LCDVIEW_REDRAW_NOW and draw the value
|
|
|
|
* (Encoder events automatically set lcdDrawUpdate for you.)
|
2018-11-11 18:16:24 +00:00
|
|
|
* - if (should_draw()) { redraw }
|
2016-04-02 23:09:56 +00:00
|
|
|
* - Before exiting the handler set lcdDrawUpdate to:
|
2016-04-09 02:52:40 +00:00
|
|
|
* - LCDVIEW_CLEAR_CALL_REDRAW to clear screen and set LCDVIEW_CALL_REDRAW_NEXT.
|
2017-05-25 20:13:57 +00:00
|
|
|
* - LCDVIEW_REDRAW_NOW to draw now (including remaining stripes).
|
|
|
|
* - LCDVIEW_CALL_REDRAW_NEXT to draw now and get LCDVIEW_REDRAW_NOW on the next loop.
|
|
|
|
* - LCDVIEW_CALL_NO_REDRAW to draw now and get LCDVIEW_NONE on the next loop.
|
2016-04-21 02:49:00 +00:00
|
|
|
* - NOTE: For graphical displays menu handlers may be called 2 or more times per loop,
|
|
|
|
* so don't change lcdDrawUpdate without considering this.
|
2016-04-02 23:09:56 +00:00
|
|
|
*
|
|
|
|
* After the menu handler callback runs (or not):
|
2016-04-09 02:52:40 +00:00
|
|
|
* - Clear the LCD if lcdDrawUpdate == LCDVIEW_CLEAR_CALL_REDRAW
|
2016-04-21 19:40:22 +00:00
|
|
|
* - Update lcdDrawUpdate for the next loop (i.e., move one state down, usually)
|
2016-04-02 23:09:56 +00:00
|
|
|
*
|
2018-10-23 21:00:34 +00:00
|
|
|
* This function is only called from the main thread.
|
2015-04-28 02:11:25 +00:00
|
|
|
*/
|
2018-10-23 21:00:34 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
LCDViewAction MarlinUI::lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW;
|
2020-04-04 05:08:25 +00:00
|
|
|
millis_t next_lcd_update_ms;
|
2020-07-30 06:43:19 +00:00
|
|
|
#if HAS_LCD_MENU && LCD_TIMEOUT_TO_STATUS
|
|
|
|
millis_t MarlinUI::return_to_status_ms = 0;
|
|
|
|
#endif
|
2018-10-23 21:00:34 +00:00
|
|
|
|
2020-10-25 09:19:51 +00:00
|
|
|
inline bool can_encode() {
|
2021-01-13 02:43:52 +00:00
|
|
|
return !BUTTON_PRESSED(ENC_EN); // Update encoder only when ENC_EN is not LOW (pressed)
|
2020-10-25 09:19:51 +00:00
|
|
|
}
|
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
void MarlinUI::update() {
|
2016-06-11 21:12:00 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
static uint16_t max_display_update_time = 0;
|
2019-04-22 01:48:53 +00:00
|
|
|
millis_t ms = millis();
|
2018-10-23 21:00:34 +00:00
|
|
|
|
2020-05-06 08:34:05 +00:00
|
|
|
#if HAS_LCD_MENU && LCD_TIMEOUT_TO_STATUS > 0
|
2019-09-04 18:13:05 +00:00
|
|
|
#define RESET_STATUS_TIMEOUT() (return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS)
|
|
|
|
#else
|
|
|
|
#define RESET_STATUS_TIMEOUT() NOOP
|
|
|
|
#endif
|
|
|
|
|
2019-06-13 02:59:39 +00:00
|
|
|
#ifdef LED_BACKLIGHT_TIMEOUT
|
|
|
|
leds.update_timeout(powersupply_on);
|
|
|
|
#endif
|
|
|
|
|
2018-10-30 21:34:45 +00:00
|
|
|
#if HAS_LCD_MENU
|
2018-11-05 00:06:00 +00:00
|
|
|
|
2017-11-21 06:18:46 +00:00
|
|
|
// Handle any queued Move Axis motion
|
2020-07-03 14:53:22 +00:00
|
|
|
manual_move.task();
|
2015-02-16 12:53:58 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
// Update button states for button_pressed(), etc.
|
|
|
|
// If the state changes the next update may be delayed 300-500ms.
|
|
|
|
update_buttons();
|
2017-03-18 15:15:54 +00:00
|
|
|
|
2016-10-26 06:42:52 +00:00
|
|
|
// If the action button is pressed...
|
2019-09-04 18:13:05 +00:00
|
|
|
static bool wait_for_unclick; // = false
|
2019-08-31 00:14:43 +00:00
|
|
|
|
2020-03-28 08:18:53 +00:00
|
|
|
auto do_click = [&]{
|
|
|
|
wait_for_unclick = true; // - Set debounce flag to ignore continous clicks
|
2020-04-12 01:36:17 +00:00
|
|
|
lcd_clicked = !wait_for_user; // - Keep the click if not waiting for a user-click
|
2020-03-28 08:18:53 +00:00
|
|
|
wait_for_user = false; // - Any click clears wait for user
|
|
|
|
quick_feedback(); // - Always make a click sound
|
|
|
|
};
|
|
|
|
|
2020-11-15 22:39:58 +00:00
|
|
|
#if HAS_TOUCH_BUTTONS
|
2019-12-06 06:47:50 +00:00
|
|
|
if (touch_buttons) {
|
|
|
|
RESET_STATUS_TIMEOUT();
|
2020-01-30 18:29:30 +00:00
|
|
|
if (touch_buttons & (EN_A | EN_B)) { // Menu arrows, in priority
|
2019-12-06 06:47:50 +00:00
|
|
|
if (ELAPSED(ms, next_button_update_ms)) {
|
2020-07-24 02:28:44 +00:00
|
|
|
encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * epps * encoderDirection;
|
2020-01-30 18:29:30 +00:00
|
|
|
if (touch_buttons & EN_A) encoderDiff *= -1;
|
2020-07-03 14:53:22 +00:00
|
|
|
TERN_(AUTO_BED_LEVELING_UBL, external_encoder());
|
2019-12-06 06:47:50 +00:00
|
|
|
next_button_update_ms = ms + repeat_delay; // Assume the repeat delay
|
|
|
|
if (!wait_for_unclick) {
|
|
|
|
next_button_update_ms += 250; // Longer delay on first press
|
|
|
|
wait_for_unclick = true; // Avoid Back/Select click while repeating
|
2020-06-02 00:42:56 +00:00
|
|
|
chirp();
|
2019-08-10 23:22:11 +00:00
|
|
|
}
|
2019-08-10 06:42:52 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-28 08:18:53 +00:00
|
|
|
else if (!wait_for_unclick && (buttons & EN_C)) // OK button, if not waiting for a debounce release:
|
|
|
|
do_click();
|
2019-08-10 06:42:52 +00:00
|
|
|
}
|
2021-01-13 02:43:52 +00:00
|
|
|
// keep wait_for_unclick value
|
|
|
|
#endif
|
2018-02-27 04:52:57 +00:00
|
|
|
|
2021-01-13 02:43:52 +00:00
|
|
|
if (!touch_buttons) {
|
|
|
|
// Integrated LCD click handling via button_pressed
|
|
|
|
if (!external_control && button_pressed()) {
|
|
|
|
if (!wait_for_unclick) do_click(); // Handle the click
|
2018-02-27 04:52:57 +00:00
|
|
|
}
|
2021-01-13 02:43:52 +00:00
|
|
|
else
|
|
|
|
wait_for_unclick = false;
|
|
|
|
}
|
2019-09-04 18:13:05 +00:00
|
|
|
|
|
|
|
if (LCD_BACK_CLICKED()) {
|
|
|
|
quick_feedback();
|
|
|
|
goto_previous_screen();
|
|
|
|
}
|
2018-02-27 04:52:57 +00:00
|
|
|
|
2018-10-30 21:34:45 +00:00
|
|
|
#endif // HAS_LCD_MENU
|
2013-12-08 20:34:56 +00:00
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
if (ELAPSED(ms, next_lcd_update_ms) || TERN0(HAS_MARLINUI_U8GLIB, drawing_screen)) {
|
2015-02-22 01:38:56 +00:00
|
|
|
|
2016-04-09 02:52:40 +00:00
|
|
|
next_lcd_update_ms = ms + LCD_UPDATE_INTERVAL;
|
|
|
|
|
2020-11-15 22:39:58 +00:00
|
|
|
#if HAS_TOUCH_BUTTONS
|
2019-12-06 06:47:50 +00:00
|
|
|
|
|
|
|
if (on_status_screen()) next_lcd_update_ms += (LCD_UPDATE_INTERVAL) * 2;
|
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_ENCODER_ACTION, touch_buttons = touch.read_buttons());
|
2019-12-06 06:47:50 +00:00
|
|
|
|
2019-07-14 23:16:26 +00:00
|
|
|
#endif
|
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(LCD_HAS_STATUS_INDICATORS, update_indicators());
|
2016-04-09 02:52:40 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
#if HAS_ENCODER_ACTION
|
2015-02-22 01:38:56 +00:00
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_SLOW_BUTTONS, slow_buttons = read_slow_buttons()); // Buttons that take too long to read in interrupt context
|
2016-08-20 23:12:57 +00:00
|
|
|
|
2020-12-17 12:05:25 +00:00
|
|
|
if (TERN0(IS_RRW_KEYPAD, handle_keypad()))
|
2020-04-22 21:35:03 +00:00
|
|
|
RESET_STATUS_TIMEOUT();
|
2015-02-22 01:38:56 +00:00
|
|
|
|
2020-07-19 22:20:35 +00:00
|
|
|
uint8_t abs_diff = ABS(encoderDiff);
|
|
|
|
|
|
|
|
#if ENCODER_PULSES_PER_STEP > 1
|
|
|
|
// When reversing the encoder direction, a movement step can be missed because
|
|
|
|
// encoderDiff has a non-zero residual value, making the controller unresponsive.
|
2020-07-24 02:28:44 +00:00
|
|
|
// The fix clears the residual value when the encoder is idle.
|
2020-07-19 22:20:35 +00:00
|
|
|
// Also check if past half the threshold to compensate for missed single steps.
|
|
|
|
static int8_t lastEncoderDiff;
|
2020-07-24 02:28:44 +00:00
|
|
|
|
|
|
|
// Timeout? No decoder change since last check. 10 or 20 times per second.
|
|
|
|
if (encoderDiff == lastEncoderDiff && abs_diff <= epps / 2) // Same direction & size but not over a half-step?
|
|
|
|
encoderDiff = 0; // Clear residual pulses.
|
|
|
|
else if (WITHIN(abs_diff, epps / 2 + 1, epps - 1)) { // Past half of threshold?
|
|
|
|
abs_diff = epps; // Treat as a full step size
|
|
|
|
encoderDiff = (encoderDiff < 0 ? -1 : 1) * abs_diff; // ...in the spin direction.
|
2020-07-19 22:20:35 +00:00
|
|
|
}
|
2020-07-24 02:28:44 +00:00
|
|
|
lastEncoderDiff = encoderDiff;
|
2020-07-19 22:20:35 +00:00
|
|
|
#endif
|
|
|
|
|
2020-07-24 02:28:44 +00:00
|
|
|
const bool encoderPastThreshold = (abs_diff >= epps);
|
2016-10-26 06:42:52 +00:00
|
|
|
if (encoderPastThreshold || lcd_clicked) {
|
2020-09-28 06:52:38 +00:00
|
|
|
if (encoderPastThreshold && TERN1(IS_TFTGLCD_PANEL, !external_control)) {
|
2015-02-22 04:18:49 +00:00
|
|
|
|
2020-04-24 02:42:38 +00:00
|
|
|
#if BOTH(HAS_LCD_MENU, ENCODER_RATE_MULTIPLIER)
|
2018-11-09 06:07:16 +00:00
|
|
|
|
|
|
|
int32_t encoderMultiplier = 1;
|
2015-02-22 04:18:49 +00:00
|
|
|
|
|
|
|
if (encoderRateMultiplierEnabled) {
|
2020-07-24 02:28:44 +00:00
|
|
|
const float encoderMovementSteps = float(abs_diff) / epps;
|
2015-02-22 04:18:49 +00:00
|
|
|
|
2017-06-10 05:12:18 +00:00
|
|
|
if (lastEncoderMovementMillis) {
|
2017-06-12 23:26:49 +00:00
|
|
|
// Note that the rate is always calculated between two passes through the
|
2015-02-22 04:18:49 +00:00
|
|
|
// loop and that the abs of the encoderDiff value is tracked.
|
2018-11-11 18:16:24 +00:00
|
|
|
const float encoderStepRate = encoderMovementSteps / float(ms - lastEncoderMovementMillis) * 1000;
|
2015-02-22 04:18:49 +00:00
|
|
|
|
|
|
|
if (encoderStepRate >= ENCODER_100X_STEPS_PER_SEC) encoderMultiplier = 100;
|
|
|
|
else if (encoderStepRate >= ENCODER_10X_STEPS_PER_SEC) encoderMultiplier = 10;
|
|
|
|
|
2020-08-21 10:21:34 +00:00
|
|
|
// Enable to output the encoder steps per second value
|
|
|
|
//#define ENCODER_RATE_MULTIPLIER_DEBUG
|
2015-07-31 05:26:53 +00:00
|
|
|
#if ENABLED(ENCODER_RATE_MULTIPLIER_DEBUG)
|
2017-06-09 15:51:23 +00:00
|
|
|
SERIAL_ECHO_START();
|
2016-06-27 23:29:35 +00:00
|
|
|
SERIAL_ECHOPAIR("Enc Step Rate: ", encoderStepRate);
|
|
|
|
SERIAL_ECHOPAIR(" Multiplier: ", encoderMultiplier);
|
|
|
|
SERIAL_ECHOPAIR(" ENCODER_10X_STEPS_PER_SEC: ", ENCODER_10X_STEPS_PER_SEC);
|
|
|
|
SERIAL_ECHOPAIR(" ENCODER_100X_STEPS_PER_SEC: ", ENCODER_100X_STEPS_PER_SEC);
|
2017-06-09 15:51:23 +00:00
|
|
|
SERIAL_EOL();
|
2018-11-05 07:23:23 +00:00
|
|
|
#endif
|
2015-02-22 04:18:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lastEncoderMovementMillis = ms;
|
2015-03-30 23:39:47 +00:00
|
|
|
} // encoderRateMultiplierEnabled
|
2018-11-09 06:07:16 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
constexpr int32_t encoderMultiplier = 1;
|
|
|
|
|
2017-05-09 17:35:43 +00:00
|
|
|
#endif // ENCODER_RATE_MULTIPLIER
|
2015-02-22 04:18:49 +00:00
|
|
|
|
2020-10-25 09:19:51 +00:00
|
|
|
if (can_encode()) encoderPosition += (encoderDiff * encoderMultiplier) / epps;
|
2020-10-25 00:41:52 +00:00
|
|
|
|
2015-02-22 01:38:56 +00:00
|
|
|
encoderDiff = 0;
|
2012-08-21 22:46:10 +00:00
|
|
|
}
|
2019-06-13 02:59:39 +00:00
|
|
|
|
2019-09-04 18:13:05 +00:00
|
|
|
RESET_STATUS_TIMEOUT();
|
2019-06-13 02:59:39 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
refresh(LCDVIEW_REDRAW_NOW);
|
2019-06-13 02:59:39 +00:00
|
|
|
|
|
|
|
#ifdef LED_BACKLIGHT_TIMEOUT
|
2021-02-08 02:36:04 +00:00
|
|
|
if (!powersupply_on) leds.reset_timeout(ms);
|
2019-06-13 02:59:39 +00:00
|
|
|
#endif
|
2015-02-22 01:38:56 +00:00
|
|
|
}
|
2018-10-23 21:00:34 +00:00
|
|
|
|
2018-11-09 06:07:16 +00:00
|
|
|
#endif
|
2015-02-22 01:38:56 +00:00
|
|
|
|
2018-10-23 21:00:34 +00:00
|
|
|
// This runs every ~100ms when idling often enough.
|
|
|
|
// Instead of tracking changes just redraw the Status Screen once per second.
|
2018-11-11 18:16:24 +00:00
|
|
|
if (on_status_screen() && !lcd_status_update_delay--) {
|
2020-09-28 06:13:27 +00:00
|
|
|
lcd_status_update_delay = TERN(HAS_MARLINUI_U8GLIB, 12, 9);
|
2020-05-20 20:28:02 +00:00
|
|
|
if (max_display_update_time) max_display_update_time--; // Be sure never go to a very big number
|
2018-11-11 18:16:24 +00:00
|
|
|
refresh(LCDVIEW_REDRAW_NOW);
|
2016-12-12 13:35:02 +00:00
|
|
|
}
|
2015-04-13 01:07:08 +00:00
|
|
|
|
2020-04-24 02:42:38 +00:00
|
|
|
#if BOTH(HAS_LCD_MENU, SCROLL_LONG_FILENAMES)
|
2017-10-19 03:15:33 +00:00
|
|
|
// If scrolling of long file names is enabled and we are in the sd card menu,
|
|
|
|
// cause a refresh to occur until all the text has scrolled into view.
|
2019-08-14 22:52:14 +00:00
|
|
|
if (currentScreen == menu_media && !lcd_status_update_delay--) {
|
2020-11-13 04:49:19 +00:00
|
|
|
lcd_status_update_delay = ++filename_scroll_pos >= filename_scroll_max ? 12 : 4; // Long delay at end and start
|
|
|
|
if (filename_scroll_pos > filename_scroll_max) filename_scroll_pos = 0;
|
2018-11-11 18:16:24 +00:00
|
|
|
refresh(LCDVIEW_REDRAW_NOW);
|
2019-09-04 18:13:05 +00:00
|
|
|
RESET_STATUS_TIMEOUT();
|
2017-10-19 03:15:33 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-06-25 21:39:22 +00:00
|
|
|
// Then we want to use only 50% of the time
|
|
|
|
const uint16_t bbr2 = planner.block_buffer_runtime() >> 1;
|
2015-02-22 01:38:56 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
if ((should_draw() || drawing_screen) && (!bbr2 || bbr2 > max_display_update_time)) {
|
2017-11-08 04:26:33 +00:00
|
|
|
|
2017-12-27 04:12:05 +00:00
|
|
|
// Change state of drawing flag between screen updates
|
2018-11-11 18:16:24 +00:00
|
|
|
if (!drawing_screen) switch (lcdDrawUpdate) {
|
2017-11-08 04:26:33 +00:00
|
|
|
case LCDVIEW_CALL_NO_REDRAW:
|
2018-11-11 18:16:24 +00:00
|
|
|
refresh(LCDVIEW_NONE);
|
2017-11-08 04:26:33 +00:00
|
|
|
break;
|
2017-12-27 04:12:05 +00:00
|
|
|
case LCDVIEW_CLEAR_CALL_REDRAW:
|
|
|
|
case LCDVIEW_CALL_REDRAW_NEXT:
|
2018-11-11 18:16:24 +00:00
|
|
|
refresh(LCDVIEW_REDRAW_NOW);
|
2017-11-08 04:26:33 +00:00
|
|
|
case LCDVIEW_REDRAW_NOW: // set above, or by a handler through LCDVIEW_CALL_REDRAW_NEXT
|
|
|
|
case LCDVIEW_NONE:
|
|
|
|
break;
|
|
|
|
} // switch
|
2017-06-10 05:12:18 +00:00
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_ADC_BUTTONS, keypad_buttons = 0);
|
2017-06-10 05:12:18 +00:00
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
#if HAS_MARLINUI_U8GLIB
|
2018-11-11 18:16:24 +00:00
|
|
|
|
2018-02-14 21:43:54 +00:00
|
|
|
#if ENABLED(LIGHTWEIGHT_UI)
|
2018-11-11 18:16:24 +00:00
|
|
|
const bool in_status = on_status_screen(),
|
|
|
|
do_u8g_loop = !in_status;
|
2018-02-14 21:43:54 +00:00
|
|
|
lcd_in_status(in_status);
|
2018-11-11 18:16:24 +00:00
|
|
|
if (in_status) status_screen();
|
2018-02-14 21:43:54 +00:00
|
|
|
#else
|
|
|
|
constexpr bool do_u8g_loop = true;
|
|
|
|
#endif
|
2018-11-11 18:16:24 +00:00
|
|
|
|
2018-02-14 21:43:54 +00:00
|
|
|
if (do_u8g_loop) {
|
2018-11-20 13:36:37 +00:00
|
|
|
if (!drawing_screen) { // If not already drawing pages
|
|
|
|
u8g.firstPage(); // Start the first page
|
|
|
|
drawing_screen = first_page = true; // Flag as drawing pages
|
2018-02-14 21:43:54 +00:00
|
|
|
}
|
2018-11-20 13:36:37 +00:00
|
|
|
set_font(FONT_MENU); // Setup font for every page draw
|
|
|
|
u8g.setColorIndex(1); // And reset the color
|
|
|
|
run_current_screen(); // Draw and process the current screen
|
2018-03-06 05:05:15 +00:00
|
|
|
first_page = false;
|
2018-02-14 21:43:54 +00:00
|
|
|
|
|
|
|
// The screen handler can clear drawing_screen for an action that changes the screen.
|
|
|
|
// If still drawing and there's another page, update max-time and return now.
|
|
|
|
// The nextPage will already be set up on the next call.
|
|
|
|
if (drawing_screen && (drawing_screen = u8g.nextPage())) {
|
2019-11-08 01:04:19 +00:00
|
|
|
if (on_status_screen())
|
|
|
|
NOLESS(max_display_update_time, millis() - ms);
|
2018-02-14 21:43:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-12-12 13:35:02 +00:00
|
|
|
}
|
2018-11-11 18:16:24 +00:00
|
|
|
|
2016-12-12 13:35:02 +00:00
|
|
|
#else
|
2018-11-11 18:16:24 +00:00
|
|
|
|
|
|
|
run_current_screen();
|
|
|
|
|
2016-12-12 13:35:02 +00:00
|
|
|
#endif
|
2017-11-08 04:26:33 +00:00
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_LCD_MENU, lcd_clicked = false);
|
2017-12-27 04:12:05 +00:00
|
|
|
|
2017-11-08 04:26:33 +00:00
|
|
|
// Keeping track of the longest time for an individual LCD update.
|
|
|
|
// Used to do screen throttling when the planner starts to fill up.
|
2019-11-08 01:04:19 +00:00
|
|
|
if (on_status_screen())
|
|
|
|
NOLESS(max_display_update_time, millis() - ms);
|
2016-12-12 13:35:02 +00:00
|
|
|
}
|
|
|
|
|
2020-05-06 08:34:05 +00:00
|
|
|
#if HAS_LCD_MENU && LCD_TIMEOUT_TO_STATUS > 0
|
2016-12-12 13:35:02 +00:00
|
|
|
// Return to Status Screen after a timeout
|
2018-11-11 18:16:24 +00:00
|
|
|
if (on_status_screen() || defer_return_to_status)
|
2019-09-04 18:13:05 +00:00
|
|
|
RESET_STATUS_TIMEOUT();
|
2016-12-12 13:35:02 +00:00
|
|
|
else if (ELAPSED(ms, return_to_status_ms))
|
2018-11-11 18:16:24 +00:00
|
|
|
return_to_status();
|
2018-11-05 00:06:00 +00:00
|
|
|
#endif
|
2016-12-12 13:35:02 +00:00
|
|
|
|
2017-12-27 04:12:05 +00:00
|
|
|
// Change state of drawing flag between screen updates
|
2018-11-11 18:16:24 +00:00
|
|
|
if (!drawing_screen) switch (lcdDrawUpdate) {
|
2017-11-08 04:26:33 +00:00
|
|
|
case LCDVIEW_CLEAR_CALL_REDRAW:
|
2018-11-11 18:16:24 +00:00
|
|
|
clear_lcd(); break;
|
2017-11-08 04:26:33 +00:00
|
|
|
case LCDVIEW_REDRAW_NOW:
|
2018-11-11 18:16:24 +00:00
|
|
|
refresh(LCDVIEW_NONE);
|
2017-11-08 04:26:33 +00:00
|
|
|
case LCDVIEW_NONE:
|
2017-12-27 04:12:05 +00:00
|
|
|
case LCDVIEW_CALL_REDRAW_NEXT:
|
|
|
|
case LCDVIEW_CALL_NO_REDRAW:
|
|
|
|
default: break;
|
2017-11-08 04:26:33 +00:00
|
|
|
} // switch
|
|
|
|
|
Distribute GLCD screen updates in time
Currently we draw and send the screens for a graphical LCD all at once.
We draw in two or four parts but draw them directly behind each other.
For the tested status screen this takes 59-62ms in a single block.
During this time nothing else (except the interrupts) can be done.
When printing a sequence of very short moves the buffer drains - sometimes until it's empty.
This PR splits the screen update into parts.
Currently we have 10 time slots. During the first one the complete screen is drawn. (60,0,0,0,0,0,0,0,0,0,0)
Here i introduce pauses for doing other things. (30,30,0,0,0,0,0,0) or (15,15,15,15,0,0,0,0,0,0)
Drawing in consecutive time slots prevents from lagging too much. Even with a 4 stripe display all the drawing is done after 400ms.
Previous experiments with a even better distribution of the time slots like
(30,0,0,0,0,30,0,0,0,0) and (15,0,15,0,15,0,15,0,0,0) did not feel good when using the menu, because of too much lag.
Because of the previous PRs to speed up the display updates and especially reducing the difference between drawing 2 or 4 stripes,
it now makes sense for the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER to go from 2 to 4 stripes. This costs about 1-2ms per complete
screen update, but is payed back by having partial updates lasting only the half time and two additional brakes. Also ~256 byte of
framebuffer are saved in RAM.
13:45:59.213 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59
13:46:00.213 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60
13:46:01.215 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59
13:46:02.215 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59
13:46:03.214 : echo: #:17 >:13 s:30; #:17 >:13 s:30; S#:34 S>:26 S:60
13:46:04.214 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59
13:46:05.212 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60
13:46:06.212 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59
03:30:36.779 : echo: #:8 >:7 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:8 >:7 s:15; S#:34 S>:27 S:61
03:30:37.778 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:9 >:7 s:16; #:8 >:6 s:14; S#:35 S>:26 S:61
03:30:38.778 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:7 s:15; S#:35 S>:26 S:61
03:30:39.777 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:8 >:8 s:16; #:8 >:6 s:14; S#:34 S>:27 S:61
03:30:40.780 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:35 S>:25 S:60
03:30:41.780 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:9 >:6 s:15; S#:36 S>:25 S:61
03:30:42.779 : echo: #:8 >:6 s:14; #:10 >:8 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:34 S>:26 S:60
03:30:43.778 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:7 s:15; #:9 >:6 s:15; S#:36 S>:26 S:62
#: draw a stripe
>: transfer a stripe
s: sum of of draw and transfer for one stripe
S#: sum of draws for a complete screen
S>: sum of transfers for a complete screen
S: time to draw and transfer a complete screen
2016-11-24 20:17:25 +00:00
|
|
|
} // ELAPSED(ms, next_lcd_update_ms)
|
2020-07-30 06:43:19 +00:00
|
|
|
|
|
|
|
TERN_(HAS_GRAPHICAL_TFT, tft_idle());
|
2012-12-12 10:47:03 +00:00
|
|
|
}
|
2012-08-21 22:46:10 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
#if HAS_ADC_BUTTONS
|
2018-10-23 21:00:34 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint16_t ADCKeyValueMin, ADCKeyValueMax;
|
|
|
|
uint8_t ADCKeyNo;
|
|
|
|
} _stADCKeypadTable_;
|
|
|
|
|
2019-01-20 05:43:32 +00:00
|
|
|
#ifndef ADC_BUTTONS_VALUE_SCALE
|
|
|
|
#define ADC_BUTTONS_VALUE_SCALE 1.0 // for the power voltage equal to the reference voltage
|
|
|
|
#endif
|
|
|
|
#ifndef ADC_BUTTONS_R_PULLUP
|
|
|
|
#define ADC_BUTTONS_R_PULLUP 4.7 // common pull-up resistor in the voltage divider
|
|
|
|
#endif
|
|
|
|
#ifndef ADC_BUTTONS_LEFT_R_PULLDOWN
|
|
|
|
#define ADC_BUTTONS_LEFT_R_PULLDOWN 0.47 // pull-down resistor for LEFT button voltage divider
|
|
|
|
#endif
|
|
|
|
#ifndef ADC_BUTTONS_RIGHT_R_PULLDOWN
|
|
|
|
#define ADC_BUTTONS_RIGHT_R_PULLDOWN 4.7 // pull-down resistor for RIGHT button voltage divider
|
|
|
|
#endif
|
|
|
|
#ifndef ADC_BUTTONS_UP_R_PULLDOWN
|
|
|
|
#define ADC_BUTTONS_UP_R_PULLDOWN 1.0 // pull-down resistor for UP button voltage divider
|
|
|
|
#endif
|
|
|
|
#ifndef ADC_BUTTONS_DOWN_R_PULLDOWN
|
|
|
|
#define ADC_BUTTONS_DOWN_R_PULLDOWN 10.0 // pull-down resistor for DOWN button voltage divider
|
|
|
|
#endif
|
|
|
|
#ifndef ADC_BUTTONS_MIDDLE_R_PULLDOWN
|
|
|
|
#define ADC_BUTTONS_MIDDLE_R_PULLDOWN 2.2 // pull-down resistor for MIDDLE button voltage divider
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Calculate the ADC value for the voltage divider with specified pull-down resistor value
|
2019-11-06 23:49:17 +00:00
|
|
|
#define ADC_BUTTON_VALUE(r) int(HAL_ADC_RANGE * (ADC_BUTTONS_VALUE_SCALE) * r / (r + ADC_BUTTONS_R_PULLUP))
|
2019-01-20 05:43:32 +00:00
|
|
|
|
2019-11-06 23:49:17 +00:00
|
|
|
static constexpr uint16_t adc_button_tolerance = HAL_ADC_RANGE * 25 / 1024,
|
|
|
|
adc_other_button = HAL_ADC_RANGE * 1000 / 1024;
|
2018-10-23 21:00:34 +00:00
|
|
|
static const _stADCKeypadTable_ stADCKeyTable[] PROGMEM = {
|
|
|
|
// VALUE_MIN, VALUE_MAX, KEY
|
2019-11-06 23:49:17 +00:00
|
|
|
{ adc_other_button, HAL_ADC_RANGE, 1 + BLEN_KEYPAD_F1 }, // F1
|
|
|
|
{ adc_other_button, HAL_ADC_RANGE, 1 + BLEN_KEYPAD_F2 }, // F2
|
|
|
|
{ adc_other_button, HAL_ADC_RANGE, 1 + BLEN_KEYPAD_F3 }, // F3
|
|
|
|
{ ADC_BUTTON_VALUE(ADC_BUTTONS_LEFT_R_PULLDOWN) - adc_button_tolerance,
|
|
|
|
ADC_BUTTON_VALUE(ADC_BUTTONS_LEFT_R_PULLDOWN) + adc_button_tolerance, 1 + BLEN_KEYPAD_LEFT }, // LEFT ( 272 ... 472)
|
|
|
|
{ ADC_BUTTON_VALUE(ADC_BUTTONS_RIGHT_R_PULLDOWN) - adc_button_tolerance,
|
|
|
|
ADC_BUTTON_VALUE(ADC_BUTTONS_RIGHT_R_PULLDOWN) + adc_button_tolerance, 1 + BLEN_KEYPAD_RIGHT }, // RIGHT (1948 ... 2148)
|
|
|
|
{ ADC_BUTTON_VALUE(ADC_BUTTONS_UP_R_PULLDOWN) - adc_button_tolerance,
|
|
|
|
ADC_BUTTON_VALUE(ADC_BUTTONS_UP_R_PULLDOWN) + adc_button_tolerance, 1 + BLEN_KEYPAD_UP }, // UP ( 618 ... 818)
|
|
|
|
{ ADC_BUTTON_VALUE(ADC_BUTTONS_DOWN_R_PULLDOWN) - adc_button_tolerance,
|
|
|
|
ADC_BUTTON_VALUE(ADC_BUTTONS_DOWN_R_PULLDOWN) + adc_button_tolerance, 1 + BLEN_KEYPAD_DOWN }, // DOWN (2686 ... 2886)
|
|
|
|
{ ADC_BUTTON_VALUE(ADC_BUTTONS_MIDDLE_R_PULLDOWN) - adc_button_tolerance,
|
|
|
|
ADC_BUTTON_VALUE(ADC_BUTTONS_MIDDLE_R_PULLDOWN) + adc_button_tolerance, 1 + BLEN_KEYPAD_MIDDLE }, // ENTER (1205 ... 1405)
|
2018-10-23 21:00:34 +00:00
|
|
|
};
|
|
|
|
|
2019-09-17 01:31:08 +00:00
|
|
|
uint8_t get_ADC_keyValue() {
|
2018-10-23 21:00:34 +00:00
|
|
|
if (thermalManager.ADCKey_count >= 16) {
|
2019-11-06 23:49:17 +00:00
|
|
|
const uint16_t currentkpADCValue = thermalManager.current_ADCKey_raw;
|
|
|
|
thermalManager.current_ADCKey_raw = HAL_ADC_RANGE;
|
2018-10-23 21:00:34 +00:00
|
|
|
thermalManager.ADCKey_count = 0;
|
2019-11-06 23:49:17 +00:00
|
|
|
if (currentkpADCValue < adc_other_button)
|
2020-03-14 04:18:16 +00:00
|
|
|
LOOP_L_N(i, ADC_KEY_NUM) {
|
2018-10-23 21:00:34 +00:00
|
|
|
const uint16_t lo = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMin),
|
|
|
|
hi = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMax);
|
|
|
|
if (WITHIN(currentkpADCValue, lo, hi)) return pgm_read_byte(&stADCKeyTable[i].ADCKeyNo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2019-01-20 05:43:32 +00:00
|
|
|
|
|
|
|
#endif // HAS_ADC_BUTTONS
|
2018-10-23 21:00:34 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
#if HAS_ENCODER_ACTION
|
|
|
|
|
2015-04-28 02:11:25 +00:00
|
|
|
/**
|
|
|
|
* Read encoder buttons from the hardware registers
|
|
|
|
* Warning: This function is called from interrupt context!
|
|
|
|
*/
|
2018-11-11 18:16:24 +00:00
|
|
|
void MarlinUI::update_buttons() {
|
2017-11-21 06:18:46 +00:00
|
|
|
const millis_t now = millis();
|
2016-09-13 21:09:50 +00:00
|
|
|
if (ELAPSED(now, next_button_update_ms)) {
|
|
|
|
|
2018-11-18 03:21:30 +00:00
|
|
|
#if HAS_DIGITAL_BUTTONS
|
2016-09-13 21:09:50 +00:00
|
|
|
|
2019-03-17 04:43:06 +00:00
|
|
|
#if ANY_BUTTON(EN1, EN2, ENC, BACK)
|
2018-11-19 02:39:49 +00:00
|
|
|
|
|
|
|
uint8_t newbutton = 0;
|
2021-01-13 02:43:52 +00:00
|
|
|
if (BUTTON_PRESSED(EN1)) newbutton |= EN_A;
|
|
|
|
if (BUTTON_PRESSED(EN2)) newbutton |= EN_B;
|
|
|
|
if (can_encode() && BUTTON_PRESSED(ENC)) newbutton |= EN_C;
|
|
|
|
if (BUTTON_PRESSED(BACK)) newbutton |= EN_D;
|
2018-11-19 02:39:49 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
constexpr uint8_t newbutton = 0;
|
|
|
|
|
2018-02-27 04:52:57 +00:00
|
|
|
#endif
|
2016-09-13 21:09:50 +00:00
|
|
|
|
2017-11-21 06:18:46 +00:00
|
|
|
//
|
|
|
|
// Directional buttons
|
|
|
|
//
|
2019-03-17 04:43:06 +00:00
|
|
|
#if ANY_BUTTON(UP, DWN, LFT, RT)
|
2016-05-03 19:50:49 +00:00
|
|
|
|
2020-07-24 02:28:44 +00:00
|
|
|
const int8_t pulses = epps * encoderDirection;
|
2016-10-22 12:40:02 +00:00
|
|
|
|
2021-01-13 02:43:52 +00:00
|
|
|
if (BUTTON_PRESSED(UP)) {
|
|
|
|
encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * pulses;
|
|
|
|
next_button_update_ms = now + 300;
|
|
|
|
}
|
|
|
|
else if (BUTTON_PRESSED(DWN)) {
|
|
|
|
encoderDiff = -(ENCODER_STEPS_PER_MENU_ITEM) * pulses;
|
|
|
|
next_button_update_ms = now + 300;
|
|
|
|
}
|
|
|
|
else if (BUTTON_PRESSED(LFT)) {
|
|
|
|
encoderDiff = -pulses;
|
|
|
|
next_button_update_ms = now + 300;
|
|
|
|
}
|
|
|
|
else if (BUTTON_PRESSED(RT)) {
|
|
|
|
encoderDiff = pulses;
|
|
|
|
next_button_update_ms = now + 300;
|
2015-12-13 17:40:48 +00:00
|
|
|
}
|
2016-05-03 19:50:49 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
#endif // UP || DWN || LFT || RT
|
2016-05-03 19:50:49 +00:00
|
|
|
|
2021-01-13 02:43:52 +00:00
|
|
|
buttons = (newbutton | TERN0(HAS_SLOW_BUTTONS, slow_buttons)
|
2020-11-15 22:39:58 +00:00
|
|
|
#if BOTH(HAS_TOUCH_BUTTONS, HAS_ENCODER_ACTION)
|
2020-04-24 03:46:45 +00:00
|
|
|
| (touch_buttons & TERN(HAS_ENCODER_WHEEL, ~(EN_A | EN_B), 0xFF))
|
2019-12-06 06:47:50 +00:00
|
|
|
#endif
|
2019-11-06 22:28:36 +00:00
|
|
|
);
|
2019-09-04 18:13:05 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
#elif HAS_ADC_BUTTONS
|
2019-09-04 18:13:05 +00:00
|
|
|
|
2018-11-19 02:39:49 +00:00
|
|
|
buttons = 0;
|
2019-09-04 18:13:05 +00:00
|
|
|
|
2019-03-11 23:10:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if HAS_ADC_BUTTONS
|
2018-11-19 02:39:49 +00:00
|
|
|
if (keypad_buttons == 0) {
|
|
|
|
const uint8_t b = get_ADC_keyValue();
|
|
|
|
if (WITHIN(b, 1, 8)) keypad_buttons = _BV(b - 1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-03-02 23:43:37 +00:00
|
|
|
#if HAS_SHIFT_ENCODER
|
2020-03-02 01:54:22 +00:00
|
|
|
/**
|
|
|
|
* Set up Rotary Encoder bit values (for two pin encoders to indicate movement).
|
|
|
|
* These values are independent of which pins are used for EN_A / EN_B indications.
|
|
|
|
* The rotary encoder part is also independent of the LCD chipset.
|
|
|
|
*/
|
|
|
|
uint8_t val = 0;
|
2021-01-13 02:43:52 +00:00
|
|
|
WRITE(SHIFT_LD_PIN, LOW);
|
|
|
|
WRITE(SHIFT_LD_PIN, HIGH);
|
2020-03-02 01:54:22 +00:00
|
|
|
LOOP_L_N(i, 8) {
|
|
|
|
val >>= 1;
|
2021-01-13 02:43:52 +00:00
|
|
|
if (READ(SHIFT_OUT_PIN)) SBI(val, 7);
|
|
|
|
WRITE(SHIFT_CLK_PIN, HIGH);
|
|
|
|
WRITE(SHIFT_CLK_PIN, LOW);
|
2020-03-02 01:54:22 +00:00
|
|
|
}
|
2020-05-10 05:12:56 +00:00
|
|
|
TERN(REPRAPWORLD_KEYPAD, keypad_buttons, buttons) = ~val;
|
2017-11-21 06:20:01 +00:00
|
|
|
#endif
|
2016-09-13 21:09:50 +00:00
|
|
|
|
2020-09-28 06:52:38 +00:00
|
|
|
#if IS_TFTGLCD_PANEL
|
|
|
|
next_button_update_ms = now + (LCD_UPDATE_INTERVAL / 2);
|
|
|
|
buttons = slow_buttons;
|
|
|
|
TERN_(AUTO_BED_LEVELING_UBL, external_encoder());
|
|
|
|
#endif
|
|
|
|
|
2016-09-13 21:09:50 +00:00
|
|
|
} // next_button_update_ms
|
2015-04-28 02:11:25 +00:00
|
|
|
|
2020-01-30 18:29:30 +00:00
|
|
|
#if HAS_ENCODER_WHEEL
|
2018-11-19 02:39:49 +00:00
|
|
|
static uint8_t lastEncoderBits;
|
2018-11-18 03:21:30 +00:00
|
|
|
|
|
|
|
// Manage encoder rotation
|
|
|
|
#define ENCODER_SPIN(_E1, _E2) switch (lastEncoderBits) { case _E1: encoderDiff += encoderDirection; break; case _E2: encoderDiff -= encoderDirection; }
|
|
|
|
|
|
|
|
uint8_t enc = 0;
|
|
|
|
if (buttons & EN_A) enc |= B01;
|
|
|
|
if (buttons & EN_B) enc |= B10;
|
|
|
|
if (enc != lastEncoderBits) {
|
|
|
|
switch (enc) {
|
2021-01-13 02:43:52 +00:00
|
|
|
case ENCODER_PHASE_0: ENCODER_SPIN(ENCODER_PHASE_3, ENCODER_PHASE_1); break;
|
|
|
|
case ENCODER_PHASE_1: ENCODER_SPIN(ENCODER_PHASE_0, ENCODER_PHASE_2); break;
|
|
|
|
case ENCODER_PHASE_2: ENCODER_SPIN(ENCODER_PHASE_1, ENCODER_PHASE_3); break;
|
|
|
|
case ENCODER_PHASE_3: ENCODER_SPIN(ENCODER_PHASE_2, ENCODER_PHASE_0); break;
|
2018-11-18 03:21:30 +00:00
|
|
|
}
|
2020-07-25 20:57:16 +00:00
|
|
|
#if BOTH(HAS_LCD_MENU, AUTO_BED_LEVELING_UBL)
|
|
|
|
external_encoder();
|
|
|
|
#endif
|
2018-11-18 03:21:30 +00:00
|
|
|
lastEncoderBits = enc;
|
2018-11-11 18:16:24 +00:00
|
|
|
}
|
2018-11-18 03:21:30 +00:00
|
|
|
|
|
|
|
#endif // HAS_ENCODER_WHEEL
|
2015-02-22 01:38:56 +00:00
|
|
|
}
|
2014-03-03 21:01:27 +00:00
|
|
|
|
2018-11-11 18:16:24 +00:00
|
|
|
#endif // HAS_ENCODER_ACTION
|
2015-06-14 22:12:02 +00:00
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
#endif // HAS_WIRED_LCD
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
#if HAS_STATUS_MESSAGE
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
////////////////////////////////////////////
|
2020-11-23 00:44:17 +00:00
|
|
|
////////////// Status Message //////////////
|
2018-11-18 04:21:44 +00:00
|
|
|
////////////////////////////////////////////
|
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
#if ENABLED(EXTENSIBLE_UI)
|
|
|
|
#include "extui/ui_api.h"
|
2019-03-17 10:32:12 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
bool MarlinUI::has_status() { return (status_message[0] != '\0'); }
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
void MarlinUI::set_status(const char * const message, const bool persist) {
|
2019-07-01 05:44:39 +00:00
|
|
|
if (alert_level) return;
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HOST_PROMPT_SUPPORT, host_action_notify(message));
|
2019-12-01 23:39:28 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
// Here we have a problem. The message is encoded in UTF8, so
|
|
|
|
// arbitrarily cutting it will be a problem. We MUST be sure
|
|
|
|
// that there is no cutting in the middle of a multibyte character!
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
// Get a pointer to the null terminator
|
|
|
|
const char* pend = message + strlen(message);
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
// If length of supplied UTF8 string is greater than
|
|
|
|
// our buffer size, start cutting whole UTF8 chars
|
|
|
|
while ((pend - message) > MAX_MESSAGE_LENGTH) {
|
|
|
|
--pend;
|
|
|
|
while (!START_OF_UTF8_CHAR(*pend)) --pend;
|
|
|
|
};
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
// At this point, we have the proper cut point. Use it
|
|
|
|
uint8_t maxLen = pend - message;
|
|
|
|
strncpy(status_message, message, maxLen);
|
|
|
|
status_message[maxLen] = '\0';
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2019-03-17 10:32:28 +00:00
|
|
|
finish_status(persist);
|
2018-11-18 04:21:44 +00:00
|
|
|
}
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
/**
|
|
|
|
* Reset the status message
|
|
|
|
*/
|
2021-03-24 17:21:11 +00:00
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
void MarlinUI::reset_status(const bool no_welcome) {
|
|
|
|
#if SERVICE_INTERVAL_1 > 0
|
|
|
|
static PGMSTR(service1, "> " SERVICE_NAME_1 "!");
|
|
|
|
#endif
|
|
|
|
#if SERVICE_INTERVAL_2 > 0
|
|
|
|
static PGMSTR(service2, "> " SERVICE_NAME_2 "!");
|
|
|
|
#endif
|
|
|
|
#if SERVICE_INTERVAL_3 > 0
|
|
|
|
static PGMSTR(service3, "> " SERVICE_NAME_3 "!");
|
|
|
|
#endif
|
|
|
|
PGM_P msg;
|
|
|
|
if (printingIsPaused())
|
|
|
|
msg = GET_TEXT(MSG_PRINT_PAUSED);
|
|
|
|
#if ENABLED(SDSUPPORT)
|
|
|
|
else if (IS_SD_PRINTING())
|
|
|
|
return set_status(card.longest_filename(), true);
|
|
|
|
#endif
|
|
|
|
else if (print_job_timer.isRunning())
|
|
|
|
msg = GET_TEXT(MSG_PRINTING);
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
#if SERVICE_INTERVAL_1 > 0
|
|
|
|
else if (print_job_timer.needsService(1)) msg = service1;
|
|
|
|
#endif
|
|
|
|
#if SERVICE_INTERVAL_2 > 0
|
|
|
|
else if (print_job_timer.needsService(2)) msg = service2;
|
|
|
|
#endif
|
|
|
|
#if SERVICE_INTERVAL_3 > 0
|
|
|
|
else if (print_job_timer.needsService(3)) msg = service3;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
else if (!no_welcome)
|
|
|
|
msg = GET_TEXT(WELCOME_MSG);
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
set_status_P(msg, -1);
|
2018-11-18 04:21:44 +00:00
|
|
|
}
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
void MarlinUI::set_status_P(PGM_P const message, int8_t level) {
|
2019-07-01 05:44:39 +00:00
|
|
|
if (level < 0) level = alert_level = 0;
|
|
|
|
if (level < alert_level) return;
|
|
|
|
alert_level = level;
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2020-05-11 02:19:23 +00:00
|
|
|
TERN_(HOST_PROMPT_SUPPORT, host_action_notify_P(message));
|
2019-12-01 23:39:28 +00:00
|
|
|
|
2019-07-01 05:44:39 +00:00
|
|
|
// Since the message is encoded in UTF8 it must
|
|
|
|
// only be cut on a character boundary.
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
// Get a pointer to the null terminator
|
|
|
|
PGM_P pend = message + strlen_P(message);
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2019-07-01 05:44:39 +00:00
|
|
|
// If length of supplied UTF8 string is greater than
|
|
|
|
// the buffer size, start cutting whole UTF8 chars
|
2018-11-18 04:21:44 +00:00
|
|
|
while ((pend - message) > MAX_MESSAGE_LENGTH) {
|
|
|
|
--pend;
|
|
|
|
while (!START_OF_UTF8_CHAR(pgm_read_byte(pend))) --pend;
|
|
|
|
};
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
// At this point, we have the proper cut point. Use it
|
|
|
|
uint8_t maxLen = pend - message;
|
|
|
|
strncpy_P(status_message, message, maxLen);
|
|
|
|
status_message[maxLen] = '\0';
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2019-03-17 10:32:28 +00:00
|
|
|
finish_status(level > 0);
|
2018-11-18 04:21:44 +00:00
|
|
|
}
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2018-11-18 04:21:44 +00:00
|
|
|
void MarlinUI::set_alert_status_P(PGM_P const message) {
|
|
|
|
set_status_P(message, 1);
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_LCD_MENU, return_to_status());
|
2018-11-18 04:21:44 +00:00
|
|
|
}
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
#include <stdarg.h>
|
2019-10-02 23:54:20 +00:00
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
void MarlinUI::status_printf_P(const uint8_t level, PGM_P const fmt, ...) {
|
|
|
|
if (level < alert_level) return;
|
|
|
|
alert_level = level;
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf_P(status_message, MAX_MESSAGE_LENGTH, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
finish_status(level > 0);
|
|
|
|
}
|
2019-02-12 21:58:56 +00:00
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
void MarlinUI::finish_status(const bool persist) {
|
2019-02-12 21:58:56 +00:00
|
|
|
|
2021-03-24 17:21:11 +00:00
|
|
|
#if HAS_WIRED_LCD
|
2018-11-13 07:47:45 +00:00
|
|
|
|
2021-03-24 17:21:11 +00:00
|
|
|
#if !(BASIC_PROGRESS_BAR && (PROGRESS_MSG_EXPIRE) > 0)
|
2020-11-23 00:44:17 +00:00
|
|
|
UNUSED(persist);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ENABLED(LCD_PROGRESS_BAR) || BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT)
|
|
|
|
const millis_t ms = millis();
|
|
|
|
#endif
|
|
|
|
|
2021-03-24 17:21:11 +00:00
|
|
|
#if BASIC_PROGRESS_BAR
|
2020-11-23 00:44:17 +00:00
|
|
|
progress_bar_ms = ms;
|
|
|
|
#if PROGRESS_MSG_EXPIRE > 0
|
|
|
|
expire_status_ms = persist ? 0 : ms + PROGRESS_MSG_EXPIRE;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT)
|
|
|
|
next_filament_display = ms + 5000UL; // Show status message for 5s
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ENABLED(STATUS_MESSAGE_SCROLLING)
|
|
|
|
status_scroll_offset = 0;
|
|
|
|
#endif
|
2021-03-24 17:21:11 +00:00
|
|
|
#else // HAS_WIRED_LCD
|
2021-01-14 15:48:29 +00:00
|
|
|
UNUSED(persist);
|
2020-11-23 00:44:17 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onStatusChanged(status_message));
|
2021-03-24 15:12:57 +00:00
|
|
|
TERN_(DWIN_CREALITY_LCD, DWIN_StatusChanged(status_message));
|
2018-11-13 07:47:45 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
#if ENABLED(STATUS_MESSAGE_SCROLLING)
|
|
|
|
|
|
|
|
void MarlinUI::advance_status_scroll() {
|
|
|
|
// Advance by one UTF8 code-word
|
|
|
|
if (status_scroll_offset < utf8_strlen(status_message))
|
|
|
|
while (!START_OF_UTF8_CHAR(status_message[++status_scroll_offset]));
|
|
|
|
else
|
|
|
|
status_scroll_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* MarlinUI::status_and_len(uint8_t &len) {
|
|
|
|
char *out = status_message + status_scroll_offset;
|
|
|
|
len = utf8_strlen(out);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if HAS_DISPLAY
|
|
|
|
|
|
|
|
#if ENABLED(SDSUPPORT)
|
|
|
|
extern bool wait_for_user, wait_for_heatup;
|
|
|
|
#endif
|
|
|
|
|
2019-05-30 21:24:13 +00:00
|
|
|
void MarlinUI::abort_print() {
|
|
|
|
#if ENABLED(SDSUPPORT)
|
|
|
|
wait_for_heatup = wait_for_user = false;
|
|
|
|
card.flag.abort_sd_printing = true;
|
|
|
|
#endif
|
|
|
|
#ifdef ACTION_ON_CANCEL
|
|
|
|
host_action_cancel();
|
|
|
|
#endif
|
2021-01-26 08:30:31 +00:00
|
|
|
IF_DISABLED(SDSUPPORT, print_job_timer.stop());
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HOST_PROMPT_SUPPORT, host_prompt_open(PROMPT_INFO, PSTR("UI Aborted"), DISMISS_STR));
|
2020-11-23 00:44:17 +00:00
|
|
|
LCD_MESSAGEPGM(MSG_PRINT_ABORTED);
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HAS_LCD_MENU, return_to_status());
|
2019-05-30 21:24:13 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 06:41:56 +00:00
|
|
|
void MarlinUI::flow_fault() {
|
|
|
|
LCD_ALERTMESSAGEPGM(MSG_FLOWMETER_FAULT);
|
|
|
|
TERN_(HAS_BUZZER, buzz(1000, 440));
|
|
|
|
TERN_(HAS_LCD_MENU, return_to_status());
|
|
|
|
}
|
|
|
|
|
2019-06-20 21:37:20 +00:00
|
|
|
#if ANY(PARK_HEAD_ON_PAUSE, SDSUPPORT)
|
|
|
|
#include "../gcode/queue.h"
|
|
|
|
#endif
|
|
|
|
|
2019-05-30 21:24:13 +00:00
|
|
|
void MarlinUI::pause_print() {
|
2019-06-07 12:08:41 +00:00
|
|
|
#if HAS_LCD_MENU
|
2020-04-09 23:09:36 +00:00
|
|
|
synchronize(GET_TEXT(MSG_PAUSING));
|
2020-04-12 01:36:17 +00:00
|
|
|
defer_status_screen();
|
2019-06-07 12:08:41 +00:00
|
|
|
#endif
|
2019-05-30 21:24:13 +00:00
|
|
|
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(HOST_PROMPT_SUPPORT, host_prompt_open(PROMPT_PAUSE_RESUME, PSTR("UI Pause"), PSTR("Resume")));
|
2019-05-30 21:24:13 +00:00
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
LCD_MESSAGEPGM(MSG_PRINT_PAUSED);
|
2019-05-30 21:24:13 +00:00
|
|
|
|
|
|
|
#if ENABLED(PARK_HEAD_ON_PAUSE)
|
2021-01-21 09:40:07 +00:00
|
|
|
pause_show_message(PAUSE_MESSAGE_PARKING, PAUSE_MODE_PAUSE_PRINT); // Show message immediately to let user know about pause in progress
|
2019-06-19 05:00:19 +00:00
|
|
|
queue.inject_P(PSTR("M25 P\nM24"));
|
2019-05-30 21:24:13 +00:00
|
|
|
#elif ENABLED(SDSUPPORT)
|
2019-06-19 05:00:19 +00:00
|
|
|
queue.inject_P(PSTR("M25"));
|
2019-05-30 21:24:13 +00:00
|
|
|
#elif defined(ACTION_ON_PAUSE)
|
|
|
|
host_action_pause();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void MarlinUI::resume_print() {
|
|
|
|
reset_status();
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(PARK_HEAD_ON_PAUSE, wait_for_heatup = wait_for_user = false);
|
2021-01-22 21:01:19 +00:00
|
|
|
TERN_(SDSUPPORT, if (IS_SD_PAUSED()) queue.inject_P(M24_STR));
|
2019-05-30 21:24:13 +00:00
|
|
|
#ifdef ACTION_ON_RESUME
|
|
|
|
host_action_resume();
|
|
|
|
#endif
|
|
|
|
print_job_timer.start(); // Also called by M24
|
|
|
|
}
|
|
|
|
|
2019-03-09 04:13:24 +00:00
|
|
|
#if HAS_PRINT_PROGRESS
|
2019-10-11 02:03:33 +00:00
|
|
|
|
|
|
|
MarlinUI::progress_t MarlinUI::_get_progress() {
|
2020-05-10 05:12:56 +00:00
|
|
|
return (
|
|
|
|
TERN0(LCD_SET_PROGRESS_MANUALLY, (progress_override & PROGRESS_MASK))
|
2019-10-08 20:24:14 +00:00
|
|
|
#if ENABLED(SDSUPPORT)
|
2020-05-10 05:12:56 +00:00
|
|
|
?: TERN(HAS_PRINT_PROGRESS_PERMYRIAD, card.permyriadDone(), card.percentDone())
|
2019-10-08 20:24:14 +00:00
|
|
|
#endif
|
|
|
|
);
|
2019-03-09 04:13:24 +00:00
|
|
|
}
|
2019-10-11 02:03:33 +00:00
|
|
|
|
2019-03-09 04:13:24 +00:00
|
|
|
#endif
|
|
|
|
|
2020-11-15 22:39:58 +00:00
|
|
|
#if HAS_TOUCH_BUTTONS
|
2020-06-11 21:13:52 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Screen Click
|
|
|
|
// - On menu screens move directly to the touched item
|
|
|
|
// - On menu screens, right side (last 3 cols) acts like a scroll - half up => prev page, half down = next page
|
|
|
|
// - On select screens (and others) touch the Right Half for +, Left Half for -
|
2020-06-12 02:21:18 +00:00
|
|
|
// - On edit screens, touch Up Half for -, Bottom Half to +
|
2020-06-11 21:13:52 +00:00
|
|
|
//
|
2020-06-12 02:21:18 +00:00
|
|
|
void MarlinUI::screen_click(const uint8_t row, const uint8_t col, const uint8_t, const uint8_t) {
|
2020-10-12 05:59:30 +00:00
|
|
|
const millis_t now = millis();
|
|
|
|
if (PENDING(now, next_button_update_ms)) return;
|
|
|
|
next_button_update_ms = now + repeat_delay; // Assume the repeat delay
|
2020-06-12 02:21:18 +00:00
|
|
|
const int8_t xdir = col < (LCD_WIDTH ) / 2 ? -1 : 1,
|
|
|
|
ydir = row < (LCD_HEIGHT) / 2 ? -1 : 1;
|
|
|
|
if (on_edit_screen)
|
2020-07-24 02:28:44 +00:00
|
|
|
encoderDiff = epps * ydir;
|
2020-06-12 02:21:18 +00:00
|
|
|
else if (screen_items > 0) {
|
2020-10-12 05:59:30 +00:00
|
|
|
// Last 5 cols act as a scroll :-)
|
2020-06-16 01:51:12 +00:00
|
|
|
if (col > (LCD_WIDTH) - 5)
|
2020-06-12 02:21:18 +00:00
|
|
|
// 2 * LCD_HEIGHT to scroll to bottom of next page. (LCD_HEIGHT would only go 1 item down.)
|
2020-07-24 02:28:44 +00:00
|
|
|
encoderDiff = epps * (encoderLine - encoderTopLine + 2 * (LCD_HEIGHT)) * ydir;
|
2020-06-11 21:13:52 +00:00
|
|
|
else
|
2020-07-24 02:28:44 +00:00
|
|
|
encoderDiff = epps * (row - encoderPosition + encoderTopLine);
|
2020-06-11 21:13:52 +00:00
|
|
|
}
|
|
|
|
else if (!on_status_screen())
|
2020-07-24 02:28:44 +00:00
|
|
|
encoderDiff = epps * xdir;
|
2020-06-11 21:13:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2021-03-24 15:12:57 +00:00
|
|
|
#elif !HAS_STATUS_MESSAGE // && !HAS_DISPLAY
|
2019-12-01 23:39:28 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Send the status line as a host notification
|
|
|
|
//
|
|
|
|
void MarlinUI::set_status(const char * const message, const bool) {
|
2020-05-10 05:12:56 +00:00
|
|
|
TERN(HOST_PROMPT_SUPPORT, host_action_notify(message), UNUSED(message));
|
2019-12-01 23:39:28 +00:00
|
|
|
}
|
|
|
|
void MarlinUI::set_status_P(PGM_P message, const int8_t) {
|
2020-05-11 02:19:23 +00:00
|
|
|
TERN(HOST_PROMPT_SUPPORT, host_action_notify_P(message), UNUSED(message));
|
2019-12-01 23:39:28 +00:00
|
|
|
}
|
|
|
|
void MarlinUI::status_printf_P(const uint8_t, PGM_P const message, ...) {
|
2020-05-11 02:19:23 +00:00
|
|
|
TERN(HOST_PROMPT_SUPPORT, host_action_notify_P(message), UNUSED(message));
|
2019-12-01 23:39:28 +00:00
|
|
|
}
|
|
|
|
|
2021-03-24 15:12:57 +00:00
|
|
|
#endif // !HAS_DISPLAY && !HAS_STATUS_MESSAGE
|
2020-04-04 05:08:25 +00:00
|
|
|
|
|
|
|
#if ENABLED(SDSUPPORT)
|
|
|
|
|
2020-11-23 00:44:17 +00:00
|
|
|
#if ENABLED(EXTENSIBLE_UI)
|
|
|
|
#include "extui/ui_api.h"
|
|
|
|
#endif
|
|
|
|
|
2020-04-04 05:08:25 +00:00
|
|
|
void MarlinUI::media_changed(const uint8_t old_status, const uint8_t status) {
|
|
|
|
if (old_status == status) {
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onMediaError()); // Failed to mount/unmount
|
2020-04-04 05:08:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status) {
|
2020-04-05 04:51:11 +00:00
|
|
|
if (old_status < 2) {
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onMediaInserted()); // ExtUI response
|
2020-11-18 04:30:32 +00:00
|
|
|
#if ENABLED(BROWSE_MEDIA_ON_INSERT)
|
2020-11-22 00:21:43 +00:00
|
|
|
clear_menu_history();
|
2020-11-18 04:30:32 +00:00
|
|
|
quick_feedback();
|
|
|
|
goto_screen(MEDIA_MENU_GATEWAY);
|
|
|
|
#else
|
2020-11-23 00:44:17 +00:00
|
|
|
LCD_MESSAGEPGM(MSG_MEDIA_INSERTED);
|
2020-11-18 04:30:32 +00:00
|
|
|
#endif
|
2020-04-05 04:51:11 +00:00
|
|
|
}
|
2020-04-04 05:08:25 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (old_status < 2) {
|
2020-04-22 21:35:03 +00:00
|
|
|
TERN_(EXTENSIBLE_UI, ExtUI::onMediaRemoved()); // ExtUI response
|
2020-04-04 05:08:25 +00:00
|
|
|
#if PIN_EXISTS(SD_DETECT)
|
2020-11-23 00:44:17 +00:00
|
|
|
LCD_MESSAGEPGM(MSG_MEDIA_REMOVED);
|
2020-05-10 05:12:56 +00:00
|
|
|
#if HAS_LCD_MENU
|
|
|
|
if (!defer_return_to_status) return_to_status();
|
|
|
|
#endif
|
2020-04-04 05:08:25 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if PIN_EXISTS(SD_DETECT) && DISABLED(NO_LCD_REINIT)
|
|
|
|
init_lcd(); // Revive a noisy shared SPI LCD
|
|
|
|
#endif
|
|
|
|
|
|
|
|
refresh();
|
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
#if HAS_WIRED_LCD || defined(LED_BACKLIGHT_TIMEOUT)
|
2020-04-04 05:08:25 +00:00
|
|
|
const millis_t ms = millis();
|
|
|
|
#endif
|
|
|
|
|
2020-09-28 06:13:27 +00:00
|
|
|
TERN_(HAS_WIRED_LCD, next_lcd_update_ms = ms + LCD_UPDATE_INTERVAL); // Delay LCD update for SD activity
|
2020-04-04 05:08:25 +00:00
|
|
|
|
|
|
|
#ifdef LED_BACKLIGHT_TIMEOUT
|
|
|
|
leds.reset_timeout(ms);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // SDSUPPORT
|
2020-05-10 05:12:56 +00:00
|
|
|
|
|
|
|
#if HAS_LCD_MENU
|
2021-02-04 21:31:46 +00:00
|
|
|
void MarlinUI::reset_settings() {
|
|
|
|
settings.reset();
|
|
|
|
completion_feedback();
|
|
|
|
#if ENABLED(TOUCH_SCREEN_CALIBRATION)
|
|
|
|
if (touch_calibration.need_calibration()) ui.goto_screen(touch_screen_calibration);
|
|
|
|
#endif
|
|
|
|
}
|
2020-05-10 05:12:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ENABLED(EEPROM_SETTINGS)
|
|
|
|
|
|
|
|
#if HAS_LCD_MENU
|
|
|
|
void MarlinUI::init_eeprom() {
|
|
|
|
const bool good = settings.init_eeprom();
|
|
|
|
completion_feedback(good);
|
|
|
|
return_to_status();
|
|
|
|
}
|
|
|
|
void MarlinUI::load_settings() {
|
|
|
|
const bool good = settings.load();
|
|
|
|
completion_feedback(good);
|
|
|
|
}
|
|
|
|
void MarlinUI::store_settings() {
|
|
|
|
const bool good = settings.save();
|
|
|
|
completion_feedback(good);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if DISABLED(EEPROM_AUTO_INIT)
|
|
|
|
|
|
|
|
static inline PGM_P eeprom_err(const uint8_t msgid) {
|
|
|
|
switch (msgid) {
|
|
|
|
default:
|
|
|
|
case 0: return GET_TEXT(MSG_ERR_EEPROM_CRC);
|
|
|
|
case 1: return GET_TEXT(MSG_ERR_EEPROM_INDEX);
|
|
|
|
case 2: return GET_TEXT(MSG_ERR_EEPROM_VERSION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MarlinUI::eeprom_alert(const uint8_t msgid) {
|
|
|
|
#if HAS_LCD_MENU
|
|
|
|
editable.uint8 = msgid;
|
|
|
|
goto_screen([]{
|
2020-05-10 05:37:19 +00:00
|
|
|
PGM_P const restore_msg = GET_TEXT(MSG_INIT_EEPROM);
|
2020-05-10 05:12:56 +00:00
|
|
|
char msg[utf8_strlen_P(restore_msg) + 1];
|
|
|
|
strcpy_P(msg, restore_msg);
|
|
|
|
MenuItem_confirm::select_screen(
|
|
|
|
GET_TEXT(MSG_BUTTON_RESET), GET_TEXT(MSG_BUTTON_IGNORE),
|
|
|
|
init_eeprom, return_to_status,
|
|
|
|
eeprom_err(editable.uint8), msg, PSTR("?")
|
|
|
|
);
|
|
|
|
});
|
|
|
|
#else
|
|
|
|
set_status_P(eeprom_err(msgid));
|
|
|
|
#endif
|
|
|
|
}
|
2020-06-16 06:45:27 +00:00
|
|
|
|
|
|
|
#endif // EEPROM_AUTO_INIT
|
|
|
|
|
|
|
|
#endif // EEPROM_SETTINGS
|