Prusa-Firmware/Firmware/lcd.cpp
Yuri D'Elia b710ca0e58 Improve warning behavior during thermal anomaly
The current code forces any warning to return the user to the status
screen in order to show the message.

Thermal anomaly warnings can repeat at very short intervals, making menu
navigation (to pause/tune the print) impossible.

We now check if the message to be displayed is the same and only force a
kickback for new messages.

This partially reverts https://github.com/prusa3d/Prusa-Firmware/pull/3600
since we need the string to be null terminated for ease of comparison.

We pad the status line at display time instead using the new
lcd_print_pad() function which achieves the same effect.
2022-09-23 14:55:03 +02:00

965 lines
21 KiB
C++

//menu.cpp
#include "lcd.h"
#include <stdio.h>
#include <stdarg.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "Timer.h"
#include "Configuration.h"
#include "pins.h"
#include <binary.h>
#include <Arduino.h>
#include "Marlin.h"
#include "fastio.h"
//-//
#include "sound.h"
#define LCD_DEFAULT_DELAY 100
#if (defined(LCD_PINS_D0) && defined(LCD_PINS_D1) && defined(LCD_PINS_D2) && defined(LCD_PINS_D3))
#define LCD_8BIT
#endif
// #define VT100
// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// bitmasks for flag argument settings
#define LCD_RS_FLAG 0x01
#define LCD_HALF_FLAG 0x02
FILE _lcdout; // = {0}; Global variable is always zero initialized, no need to explicitly state that.
uint8_t lcd_displayfunction = 0;
uint8_t lcd_displaycontrol = 0;
uint8_t lcd_displaymode = 0;
uint8_t lcd_currline;
#ifdef VT100
uint8_t lcd_escape[8];
#endif
static void lcd_display(void);
#if 0
static void lcd_no_display(void);
static void lcd_no_cursor(void);
static void lcd_cursor(void);
static void lcd_no_blink(void);
static void lcd_blink(void);
static void lcd_scrollDisplayLeft(void);
static void lcd_scrollDisplayRight(void);
static void lcd_leftToRight(void);
static void lcd_rightToLeft(void);
static void lcd_autoscroll(void);
static void lcd_no_autoscroll(void);
#endif
#ifdef VT100
void lcd_escape_write(uint8_t chr);
#endif
static void lcd_pulseEnable(void)
{
WRITE(LCD_PINS_ENABLE,HIGH);
_delay_us(1); // enable pulse must be >450ns
WRITE(LCD_PINS_ENABLE,LOW);
}
static void lcd_writebits(uint8_t value)
{
#ifdef LCD_8BIT
WRITE(LCD_PINS_D0, value & 0x01);
WRITE(LCD_PINS_D1, value & 0x02);
WRITE(LCD_PINS_D2, value & 0x04);
WRITE(LCD_PINS_D3, value & 0x08);
#endif
WRITE(LCD_PINS_D4, value & 0x10);
WRITE(LCD_PINS_D5, value & 0x20);
WRITE(LCD_PINS_D6, value & 0x40);
WRITE(LCD_PINS_D7, value & 0x80);
lcd_pulseEnable();
}
static void lcd_send(uint8_t data, uint8_t flags, uint16_t duration = LCD_DEFAULT_DELAY)
{
WRITE(LCD_PINS_RS,flags&LCD_RS_FLAG);
_delay_us(5);
lcd_writebits(data);
#ifndef LCD_8BIT
if (!(flags & LCD_HALF_FLAG))
{
_delay_us(LCD_DEFAULT_DELAY);
lcd_writebits(data<<4);
}
#endif
delayMicroseconds(duration);
}
static void lcd_command(uint8_t value, uint16_t delayExtra = 0)
{
lcd_send(value, LOW, LCD_DEFAULT_DELAY + delayExtra);
}
static void lcd_write(uint8_t value)
{
if (value == '\n')
{
if (lcd_currline > 3) lcd_currline = -1;
lcd_set_cursor(0, lcd_currline + 1); // LF
return;
}
#ifdef VT100
if (lcd_escape[0] || (value == 0x1b)){
lcd_escape_write(value);
return;
}
#endif
lcd_send(value, HIGH);
}
static void lcd_begin(uint8_t clear)
{
lcd_currline = 0;
lcd_send(LCD_FUNCTIONSET | LCD_8BITMODE, LOW | LCD_HALF_FLAG, 4500); // wait min 4.1ms
// second try
lcd_send(LCD_FUNCTIONSET | LCD_8BITMODE, LOW | LCD_HALF_FLAG, 150);
// third go!
lcd_send(LCD_FUNCTIONSET | LCD_8BITMODE, LOW | LCD_HALF_FLAG, 150);
#ifndef LCD_8BIT
// set to 4-bit interface
lcd_send(LCD_FUNCTIONSET | LCD_4BITMODE, LOW | LCD_HALF_FLAG, 150);
#endif
// finally, set # lines, font size, etc.0
lcd_command(LCD_FUNCTIONSET | lcd_displayfunction);
// turn the display on with no cursor or blinking default
lcd_displaycontrol = LCD_CURSOROFF | LCD_BLINKOFF;
lcd_display();
// clear it off
if (clear) lcd_clear();
// Initialize to default text direction (for romance languages)
lcd_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// set the entry mode
lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
#ifdef VT100
lcd_escape[0] = 0;
#endif
}
static int lcd_putchar(char c, FILE *)
{
lcd_write(c);
return 0;
}
void lcd_init(void)
{
WRITE(LCD_PINS_ENABLE,LOW);
SET_OUTPUT(LCD_PINS_RS);
SET_OUTPUT(LCD_PINS_ENABLE);
#ifdef LCD_8BIT
SET_OUTPUT(LCD_PINS_D0);
SET_OUTPUT(LCD_PINS_D1);
SET_OUTPUT(LCD_PINS_D2);
SET_OUTPUT(LCD_PINS_D3);
#endif
SET_OUTPUT(LCD_PINS_D4);
SET_OUTPUT(LCD_PINS_D5);
SET_OUTPUT(LCD_PINS_D6);
SET_OUTPUT(LCD_PINS_D7);
#ifdef LCD_8BIT
lcd_displayfunction |= LCD_8BITMODE;
#endif
lcd_displayfunction |= LCD_2LINE;
_delay_us(50000);
lcd_begin(1); //first time init
fdev_setup_stream(lcdout, lcd_putchar, NULL, _FDEV_SETUP_WRITE); //setup lcdout stream
}
void lcd_refresh(void)
{
lcd_begin(1);
lcd_set_custom_characters();
}
void lcd_refresh_noclear(void)
{
lcd_begin(0);
lcd_set_custom_characters();
}
void lcd_clear(void)
{
lcd_command(LCD_CLEARDISPLAY, 1600); // clear display, set cursor position to zero
lcd_currline = 0;
}
void lcd_home(void)
{
lcd_command(LCD_RETURNHOME, 1600); // set cursor position to zero
lcd_currline = 0;
}
// Turn the display on/off (quickly)
void lcd_display(void)
{
lcd_displaycontrol |= LCD_DISPLAYON;
lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
}
#if 0
void lcd_no_display(void)
{
lcd_displaycontrol &= ~LCD_DISPLAYON;
lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
}
#endif
#ifdef VT100 //required functions for VT100
// Turns the underline cursor on/off
void lcd_no_cursor(void)
{
lcd_displaycontrol &= ~LCD_CURSORON;
lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
}
void lcd_cursor(void)
{
lcd_displaycontrol |= LCD_CURSORON;
lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
}
#endif
#if 0
// Turn on and off the blinking cursor
void lcd_no_blink(void)
{
lcd_displaycontrol &= ~LCD_BLINKON;
lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
}
void lcd_blink(void)
{
lcd_displaycontrol |= LCD_BLINKON;
lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol);
}
// These commands scroll the display without changing the RAM
void lcd_scrollDisplayLeft(void)
{
lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void lcd_scrollDisplayRight(void)
{
lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
// This is for text that flows Left to Right
void lcd_leftToRight(void)
{
lcd_displaymode |= LCD_ENTRYLEFT;
lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
}
// This is for text that flows Right to Left
void lcd_rightToLeft(void)
{
lcd_displaymode &= ~LCD_ENTRYLEFT;
lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
}
// This will 'right justify' text from the cursor
void lcd_autoscroll(void)
{
lcd_displaymode |= LCD_ENTRYSHIFTINCREMENT;
lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
}
// This will 'left justify' text from the cursor
void lcd_no_autoscroll(void)
{
lcd_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
lcd_command(LCD_ENTRYMODESET | lcd_displaymode);
}
#endif
void lcd_set_cursor(uint8_t col, uint8_t row)
{
uint8_t row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
if (row >= LCD_HEIGHT)
row = LCD_HEIGHT - 1; // we count rows starting w/0
lcd_currline = row;
lcd_command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void lcd_createChar_P(uint8_t location, const uint8_t* charmap)
{
location &= 0x7; // we only have 8 locations 0-7
lcd_command(LCD_SETCGRAMADDR | (location << 3));
for (uint8_t i = 0; i < 8; i++)
lcd_send(pgm_read_byte(&charmap[i]), HIGH);
}
#ifdef VT100
//Supported VT100 escape codes:
//EraseScreen "\x1b[2J"
//CursorHome "\x1b[%d;%dH"
//CursorShow "\x1b[?25h"
//CursorHide "\x1b[?25l"
void lcd_escape_write(uint8_t chr)
{
#define escape_cnt (lcd_escape[0]) //escape character counter
#define is_num_msk (lcd_escape[1]) //numeric character bit mask
#define chr_is_num (is_num_msk & 0x01) //current character is numeric
#define e_2_is_num (is_num_msk & 0x04) //escape char 2 is numeric
#define e_3_is_num (is_num_msk & 0x08) //...
#define e_4_is_num (is_num_msk & 0x10)
#define e_5_is_num (is_num_msk & 0x20)
#define e_6_is_num (is_num_msk & 0x40)
#define e_7_is_num (is_num_msk & 0x80)
#define e2_num (lcd_escape[2] - '0') //number from character 2
#define e3_num (lcd_escape[3] - '0') //number from character 3
#define e23_num (10*e2_num+e3_num) //number from characters 2 and 3
#define e4_num (lcd_escape[4] - '0') //number from character 4
#define e5_num (lcd_escape[5] - '0') //number from character 5
#define e45_num (10*e4_num+e5_num) //number from characters 4 and 5
#define e6_num (lcd_escape[6] - '0') //number from character 6
#define e56_num (10*e5_num+e6_num) //number from characters 5 and 6
if (escape_cnt > 1) // escape length > 1 = "\x1b["
{
lcd_escape[escape_cnt] = chr; // store current char
if ((chr >= '0') && (chr <= '9')) // char is numeric
is_num_msk |= (1 | (1 << escape_cnt)); //set mask
else
is_num_msk &= ~1; //clear mask
}
switch (escape_cnt++)
{
case 0:
if (chr == 0x1b) return; // escape = "\x1b"
break;
case 1:
is_num_msk = 0x00; // reset 'is number' bit mask
if (chr == '[') return; // escape = "\x1b["
break;
case 2:
switch (chr)
{
case '2': return; // escape = "\x1b[2"
case '?': return; // escape = "\x1b[?"
default:
if (chr_is_num) return; // escape = "\x1b[%1d"
}
break;
case 3:
switch (lcd_escape[2])
{
case '?': // escape = "\x1b[?"
if (chr == '2') return; // escape = "\x1b[?2"
break;
case '2':
if (chr == 'J') // escape = "\x1b[2J"
{ lcd_clear(); lcd_currline = 0; break; } // EraseScreen
default:
if (e_2_is_num && // escape = "\x1b[%1d"
((chr == ';') || // escape = "\x1b[%1d;"
chr_is_num)) // escape = "\x1b[%2d"
return;
}
break;
case 4:
switch (lcd_escape[2])
{
case '?': // "\x1b[?"
if ((lcd_escape[3] == '2') && (chr == '5')) return; // escape = "\x1b[?25"
break;
default:
if (e_2_is_num) // escape = "\x1b[%1d"
{
if ((lcd_escape[3] == ';') && chr_is_num) return; // escape = "\x1b[%1d;%1d"
else if (e_3_is_num && (chr == ';')) return; // escape = "\x1b[%2d;"
}
}
break;
case 5:
switch (lcd_escape[2])
{
case '?':
if ((lcd_escape[3] == '2') && (lcd_escape[4] == '5')) // escape = "\x1b[?25"
switch (chr)
{
case 'h': // escape = "\x1b[?25h"
lcd_cursor(); // CursorShow
break;
case 'l': // escape = "\x1b[?25l"
lcd_no_cursor(); // CursorHide
break;
}
break;
default:
if (e_2_is_num) // escape = "\x1b[%1d"
{
if ((lcd_escape[3] == ';') && e_4_is_num) // escape = "\x1b%1d;%1dH"
{
if (chr == 'H') // escape = "\x1b%1d;%1dH"
lcd_set_cursor(e4_num, e2_num); // CursorHome
else if (chr_is_num)
return; // escape = "\x1b%1d;%2d"
}
else if (e_3_is_num && (lcd_escape[4] == ';') && chr_is_num)
return; // escape = "\x1b%2d;%1d"
}
}
break;
case 6:
if (e_2_is_num) // escape = "\x1b[%1d"
{
if ((lcd_escape[3] == ';') && e_4_is_num && e_5_is_num && (chr == 'H')) // escape = "\x1b%1d;%2dH"
lcd_set_cursor(e45_num, e2_num); // CursorHome
else if (e_3_is_num && (lcd_escape[4] == ';') && e_5_is_num) // escape = "\x1b%2d;%1d"
{
if (chr == 'H') // escape = "\x1b%2d;%1dH"
lcd_set_cursor(e5_num, e23_num); // CursorHome
else if (chr_is_num) // "\x1b%2d;%2d"
return;
}
}
break;
case 7:
if (e_2_is_num && e_3_is_num && (lcd_escape[4] == ';')) // "\x1b[%2d;"
if (e_5_is_num && e_6_is_num && (chr == 'H')) // "\x1b[%2d;%2dH"
lcd_set_cursor(e56_num, e23_num); // CursorHome
break;
}
escape_cnt = 0; // reset escape
}
#endif //VT100
int lcd_putc(char c)
{
return fputc(c, lcdout);
}
int lcd_putc_at(uint8_t c, uint8_t r, char ch)
{
lcd_set_cursor(c, r);
return fputc(ch, lcdout);
}
int lcd_puts_P(const char* str)
{
return fputs_P(str, lcdout);
}
int lcd_puts_at_P(uint8_t c, uint8_t r, const char* str)
{
lcd_set_cursor(c, r);
return fputs_P(str, lcdout);
}
int lcd_printf_P(const char* format, ...)
{
va_list args;
va_start(args, format);
int ret = vfprintf_P(lcdout, format, args);
va_end(args);
return ret;
}
void lcd_space(uint8_t n)
{
while (n--) lcd_putc(' ');
}
void lcd_print(const char* s)
{
while (*s) lcd_write(*(s++));
}
void lcd_print_pad(const char* s, uint8_t len)
{
while (len-- && *s) lcd_write(*(s++));
lcd_space(len);
}
void lcd_print(char c, int base)
{
lcd_print((long) c, base);
}
void lcd_print(unsigned char b, int base)
{
lcd_print((unsigned long) b, base);
}
void lcd_print(int n, int base)
{
lcd_print((long) n, base);
}
void lcd_print(unsigned int n, int base)
{
lcd_print((unsigned long) n, base);
}
void lcd_print(long n, int base)
{
if (base == 0)
lcd_write(n);
else if (base == 10)
{
if (n < 0)
{
lcd_print('-');
n = -n;
}
lcd_printNumber(n, 10);
}
else
lcd_printNumber(n, base);
}
void lcd_print(unsigned long n, int base)
{
if (base == 0)
lcd_write(n);
else
lcd_printNumber(n, base);
}
void lcd_print(double n, int digits)
{
lcd_printFloat(n, digits);
}
void lcd_printNumber(unsigned long n, uint8_t base)
{
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
unsigned long i = 0;
if (n == 0)
{
lcd_print('0');
return;
}
while (n > 0)
{
buf[i++] = n % base;
n /= base;
}
for (; i > 0; i--)
lcd_print((char) (buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10));
}
void lcd_printFloat(double number, uint8_t digits)
{
// Handle negative numbers
if (number < 0.0)
{
lcd_print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
lcd_print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0)
lcd_print('.');
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
lcd_print(toPrint);
remainder -= toPrint;
}
}
uint8_t lcd_draw_update = 2;
int32_t lcd_encoder = 0;
uint8_t lcd_encoder_bits = 0;
int8_t lcd_encoder_diff = 0;
uint8_t lcd_buttons = 0;
uint8_t lcd_button_pressed = 0;
uint8_t lcd_update_enabled = 1;
uint32_t lcd_next_update_millis = 0;
lcd_longpress_func_t lcd_longpress_func = 0;
lcd_lcdupdate_func_t lcd_lcdupdate_func = 0;
static ShortTimer buttonBlanking;
ShortTimer longPressTimer;
LongTimer lcd_timeoutToStatus;
//! @brief Was button clicked?
//!
//! Consume click event, following call would return 0.
//! See #LCD_CLICKED macro for version not consuming the event.
//!
//! Generally is used in modal dialogs.
//!
//! @retval 0 not clicked
//! @retval nonzero clicked
uint8_t lcd_clicked(void)
{
bool clicked = LCD_CLICKED;
if(clicked)
{
lcd_consume_click();
}
return clicked;
}
void lcd_beeper_quick_feedback(void)
{
//-//
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
/*
for(int8_t i = 0; i < 10; i++)
{
Sound_MakeCustom(100,0,false);
_delay_us(100);
}
*/
}
void lcd_quick_feedback(void)
{
lcd_draw_update = 2;
lcd_button_pressed = false;
lcd_beeper_quick_feedback();
}
void lcd_update(uint8_t lcdDrawUpdateOverride)
{
if (lcd_draw_update < lcdDrawUpdateOverride)
lcd_draw_update = lcdDrawUpdateOverride;
if (!lcd_update_enabled)
return;
if (lcd_lcdupdate_func)
lcd_lcdupdate_func();
}
void lcd_update_enable(uint8_t enabled)
{
// printf_P(PSTR("lcd_update_enable(%u -> %u)\n"), lcd_update_enabled, enabled);
if (lcd_update_enabled != enabled)
{
lcd_update_enabled = enabled;
if (enabled)
{ // Reset encoder position. This is equivalent to re-entering a menu.
lcd_encoder = 0;
lcd_encoder_diff = 0;
// Enabling the normal LCD update procedure.
// Reset the timeout interval.
lcd_timeoutToStatus.start();
// Force the keypad update now.
lcd_next_update_millis = _millis() - 1;
// Full update.
lcd_clear();
lcd_update(2);
} else
{
// Clear the LCD always, or let it to the caller?
}
}
}
bool lcd_longpress_trigger = 0;
// WARNING: this function is called from the temperature ISR.
// Only update flags, but do not perform any menu/lcd operation!
void lcd_buttons_update(void)
{
static uint8_t lcd_long_press_active = 0;
uint8_t newbutton = 0;
if (READ(BTN_EN1) == 0) newbutton |= EN_A;
if (READ(BTN_EN2) == 0) newbutton |= EN_B;
if (READ(BTN_ENC) == 0)
{ //button is pressed
if (!buttonBlanking.running() || buttonBlanking.expired(BUTTON_BLANKING_TIME)) {
buttonBlanking.start();
safetyTimer.start();
if ((lcd_button_pressed == 0) && (lcd_long_press_active == 0))
{
longPressTimer.start();
lcd_button_pressed = 1;
}
else if (longPressTimer.expired(LONG_PRESS_TIME))
{
lcd_long_press_active = 1;
lcd_longpress_trigger = 1;
}
}
}
else
{ //button not pressed
if (lcd_button_pressed)
{ //button was released
buttonBlanking.start();
if (lcd_long_press_active == 0)
{ //button released before long press gets activated
newbutton |= EN_C;
}
//else if (menu_menu == lcd_move_z) lcd_quick_feedback();
//lcd_button_pressed is set back to false via lcd_quick_feedback function
}
lcd_long_press_active = 0;
}
lcd_buttons = newbutton;
//manage encoder rotation
uint8_t enc = 0;
if (lcd_buttons & EN_A) enc |= B01;
if (lcd_buttons & EN_B) enc |= B10;
if (enc != lcd_encoder_bits)
{
switch (enc)
{
case encrot0:
if (lcd_encoder_bits == encrot3)
lcd_encoder_diff++;
else if (lcd_encoder_bits == encrot1)
lcd_encoder_diff--;
break;
case encrot1:
if (lcd_encoder_bits == encrot0)
lcd_encoder_diff++;
else if (lcd_encoder_bits == encrot2)
lcd_encoder_diff--;
break;
case encrot2:
if (lcd_encoder_bits == encrot1)
lcd_encoder_diff++;
else if (lcd_encoder_bits == encrot3)
lcd_encoder_diff--;
break;
case encrot3:
if (lcd_encoder_bits == encrot2)
lcd_encoder_diff++;
else if (lcd_encoder_bits == encrot0)
lcd_encoder_diff--;
break;
}
}
lcd_encoder_bits = enc;
}
////////////////////////////////////////////////////////////////////////////////
// Custom character data
const uint8_t lcd_chardata_bedTemp[8] PROGMEM = {
B00000,
B11111,
B10101,
B10001,
B10101,
B11111,
B00000,
B00000}; //thanks Sonny Mounicou
const uint8_t lcd_chardata_degree[8] PROGMEM = {
B01100,
B10010,
B10010,
B01100,
B00000,
B00000,
B00000,
B00000};
const uint8_t lcd_chardata_thermometer[8] PROGMEM = {
B00100,
B01010,
B01010,
B01010,
B01010,
B10001,
B10001,
B01110};
const uint8_t lcd_chardata_uplevel[8] PROGMEM = {
B00100,
B01110,
B11111,
B00100,
B11100,
B00000,
B00000,
B00000}; //thanks joris
const uint8_t lcd_chardata_refresh[8] PROGMEM = {
B00000,
B00110,
B11001,
B11000,
B00011,
B10011,
B01100,
B00000}; //thanks joris
const uint8_t lcd_chardata_folder[8] PROGMEM = {
B00000,
B11100,
B11111,
B10001,
B10001,
B11111,
B00000,
B00000}; //thanks joris
/*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
B11100,
B10000,
B11000,
B10111,
B00101,
B00110,
B00101,
B00000};*/ //thanks Sonny Mounicou
/*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
B11100,
B10100,
B11000,
B10100,
B00000,
B00111,
B00010,
B00010};*/
/*const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
B01100,
B10011,
B00000,
B01100,
B10011,
B00000,
B01100,
B10011};*/
const uint8_t lcd_chardata_feedrate[8] PROGMEM = {
B00000,
B00100,
B10010,
B01001,
B10010,
B00100,
B00000,
B00000};
const uint8_t lcd_chardata_clock[8] PROGMEM = {
B00000,
B01110,
B10011,
B10101,
B10001,
B01110,
B00000,
B00000}; //thanks Sonny Mounicou
void lcd_set_custom_characters(void)
{
lcd_createChar_P(LCD_STR_BEDTEMP[0], lcd_chardata_bedTemp);
lcd_createChar_P(LCD_STR_DEGREE[0], lcd_chardata_degree);
lcd_createChar_P(LCD_STR_THERMOMETER[0], lcd_chardata_thermometer);
lcd_createChar_P(LCD_STR_UPLEVEL[0], lcd_chardata_uplevel);
lcd_createChar_P(LCD_STR_REFRESH[0], lcd_chardata_refresh);
lcd_createChar_P(LCD_STR_FOLDER[0], lcd_chardata_folder);
lcd_createChar_P(LCD_STR_FEEDRATE[0], lcd_chardata_feedrate);
lcd_createChar_P(LCD_STR_CLOCK[0], lcd_chardata_clock);
}
const uint8_t lcd_chardata_arr2down[8] PROGMEM = {
B00000,
B00000,
B10001,
B01010,
B00100,
B10001,
B01010,
B00100};
const uint8_t lcd_chardata_confirm[8] PROGMEM = {
B00000,
B00001,
B00011,
B10110,
B11100,
B01000,
B00000};
void lcd_set_custom_characters_nextpage(void)
{
lcd_createChar_P(LCD_STR_ARROW_2_DOWN[0], lcd_chardata_arr2down);
lcd_createChar_P(LCD_STR_CONFIRM[0], lcd_chardata_confirm);
}