ultralcd_implementation_hitachi_HD44780.h 29.7 KB
Newer Older
MagoKimbra's avatar
MagoKimbra committed
1 2
#ifndef ULTRALCD_IMPLEMENTATION_HITACHI_HD44780_H
#define ULTRALCD_IMPLEMENTATION_HITACHI_HD44780_H
MagoKimbra's avatar
MagoKimbra committed
3

MagoKimbra's avatar
MagoKimbra committed
4 5 6 7 8
/**
* Implementation of the LCD display routines for a Hitachi HD44780 display. These are common LCD character displays.
* When selecting the Russian language, a slightly different LCD implementation is used to handle UTF8 characters.
**/

Simone Primarosa's avatar
Simone Primarosa committed
9
//#if DISABLED(REPRAPWORLD_KEYPAD)
MagoKimbra's avatar
MagoKimbra committed
10 11 12 13
//  extern volatile uint8_t buttons;  //the last checked buttons in a bit array.
//#else
  extern volatile uint8_t buttons;  //an extended version of the last checked buttons in a bit array.
//#endif
MagoKimbra's avatar
MagoKimbra committed
14 15 16 17

////////////////////////////////////
// Setup button and encode mappings for each panel (into 'buttons' variable
//
MagoKimbra's avatar
MagoKimbra committed
18 19
// This is just to map common functions (across different panels) onto the same
// macro name. The mapping is independent of whether the button is directly connected or
MagoKimbra's avatar
MagoKimbra committed
20 21
// via a shift/i2c register.

MagoKimbra's avatar
MagoKimbra committed
22
#if ENABLED(ULTIPANEL)
MagoKimbra's avatar
MagoKimbra committed
23 24 25
  // All UltiPanels might have an encoder - so this is always be mapped onto first two bits
  #define BLEN_B 1
  #define BLEN_A 0
MagoKimbra's avatar
MagoKimbra committed
26

MagoKimbra's avatar
MagoKimbra committed
27 28
  #define EN_B BIT(BLEN_B) // The two encoder pins are connected through BTN_EN1 and BTN_EN2
  #define EN_A BIT(BLEN_A)
MagoKimbra's avatar
MagoKimbra committed
29

MagoKimbra's avatar
MagoKimbra committed
30
  #if ENABLED(BTN_ENC) && BTN_ENC > 0
MagoKimbra's avatar
MagoKimbra committed
31 32 33
    // encoder click is directly connected
    #define BLEN_C 2
    #define EN_C BIT(BLEN_C)
MagoKimbra's avatar
MagoKimbra committed
34
  #endif
MagoKimbra's avatar
MagoKimbra committed
35

MagoKimbra's avatar
MagoKimbra committed
36
  #if ENABLED(BTN_BACK) && BTN_BACK > 0
MagoKimbra's avatar
MagoKimbra committed
37 38 39 40 41 42 43 44
    #define BLEN_D 3
    #define EN_D BIT(BLEN_D)
  #endif
  
  //
  // Setup other button mappings of each panel
  //
  #if ENABLED(LCD_I2C_VIKI)
MagoKimbra's avatar
MagoKimbra committed
45
    #define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C)
MagoKimbra's avatar
MagoKimbra committed
46

MagoKimbra's avatar
MagoKimbra committed
47 48 49 50 51 52 53 54 55 56
    // button and encoder bit positions within 'buttons'
    #define B_LE (BUTTON_LEFT<<B_I2C_BTN_OFFSET)    // The remaining normalized buttons are all read via I2C
    #define B_UP (BUTTON_UP<<B_I2C_BTN_OFFSET)
    #define B_MI (BUTTON_SELECT<<B_I2C_BTN_OFFSET)
    #define B_DW (BUTTON_DOWN<<B_I2C_BTN_OFFSET)
    #define B_RI (BUTTON_RIGHT<<B_I2C_BTN_OFFSET)

    #if ENABLED(BTN_ENC) && BTN_ENC > -1
      // the pause/stop/restart button is connected to BTN_ENC when used
      #define B_ST (EN_C)                            // Map the pause/stop/resume button into its normalized functional name
MagoKimbra's avatar
MagoKimbra committed
57 58 59 60 61 62

      #if ENABLED(INVERT_CLICK_BUTTON)
        #define LCD_CLICKED !(buttons&(B_MI|B_RI|B_ST)) // pause/stop button also acts as click until we implement proper pause/stop.
      #else
        #define LCD_CLICKED (buttons&(B_MI|B_RI|B_ST)) // pause/stop button also acts as click until we implement proper pause/stop.
      #endif
MagoKimbra's avatar
MagoKimbra committed
63
    #else
MagoKimbra's avatar
MagoKimbra committed
64 65 66 67 68
      #if ENABLED(INVERT_CLICK_BUTTON)
        #define LCD_CLICKED !(buttons&(B_MI|B_RI))
      #else
        #define LCD_CLICKED (buttons&(B_MI|B_RI))
      #endif
MagoKimbra's avatar
MagoKimbra committed
69
    #endif
MagoKimbra's avatar
MagoKimbra committed
70 71 72 73

    // I2C buttons take too long to read inside an interrupt context and so we read them during lcd_update
    #define LCD_HAS_SLOW_BUTTONS

MagoKimbra's avatar
MagoKimbra committed
74 75 76 77 78 79 80
  #elif ENABLED(LCD_I2C_PANELOLU2)
    // encoder click can be read through I2C if not directly connected
    #if BTN_ENC <= 0
      #define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C)

      #define B_MI (PANELOLU2_ENCODER_C<<B_I2C_BTN_OFFSET) // requires LiquidTWI2 library v1.2.3 or later

MagoKimbra's avatar
MagoKimbra committed
81 82 83 84 85
      #if ENABLED(INVERT_CLICK_BUTTON)
        #define LCD_CLICKED !(buttons&B_MI)
      #else
        #define LCD_CLICKED (buttons&B_MI)
      #endif
MagoKimbra's avatar
MagoKimbra committed
86 87 88 89

      // I2C buttons take too long to read inside an interrupt context and so we read them during lcd_update
      #define LCD_HAS_SLOW_BUTTONS
    #else
MagoKimbra's avatar
MagoKimbra committed
90 91 92 93 94
      #if ENABLED(INVERT_CLICK_BUTTON)
        #define LCD_CLICKED !(buttons&EN_C)
      #else
        #define LCD_CLICKED (buttons&EN_C)
      #endif
MagoKimbra's avatar
MagoKimbra committed
95 96 97
    #endif

  #elif ENABLED(REPRAPWORLD_KEYPAD)
MagoKimbra's avatar
MagoKimbra committed
98 99 100 101
    // define register bit values, don't change it
    #define BLEN_REPRAPWORLD_KEYPAD_F3 0
    #define BLEN_REPRAPWORLD_KEYPAD_F2 1
    #define BLEN_REPRAPWORLD_KEYPAD_F1 2
MagoKimbra's avatar
MagoKimbra committed
102
    #define BLEN_REPRAPWORLD_KEYPAD_UP 6
MagoKimbra's avatar
MagoKimbra committed
103 104
    #define BLEN_REPRAPWORLD_KEYPAD_RIGHT 4
    #define BLEN_REPRAPWORLD_KEYPAD_MIDDLE 5
MagoKimbra's avatar
MagoKimbra committed
105
    #define BLEN_REPRAPWORLD_KEYPAD_DOWN 3
MagoKimbra's avatar
MagoKimbra committed
106
    #define BLEN_REPRAPWORLD_KEYPAD_LEFT 7
MagoKimbra's avatar
MagoKimbra committed
107

MagoKimbra's avatar
MagoKimbra committed
108
    #define REPRAPWORLD_BTN_OFFSET 0 // bit offset into buttons for shift register values
MagoKimbra's avatar
MagoKimbra committed
109 110 111 112 113 114 115 116 117 118

    #define EN_REPRAPWORLD_KEYPAD_F3 BIT((BLEN_REPRAPWORLD_KEYPAD_F3+REPRAPWORLD_BTN_OFFSET))
    #define EN_REPRAPWORLD_KEYPAD_F2 BIT((BLEN_REPRAPWORLD_KEYPAD_F2+REPRAPWORLD_BTN_OFFSET))
    #define EN_REPRAPWORLD_KEYPAD_F1 BIT((BLEN_REPRAPWORLD_KEYPAD_F1+REPRAPWORLD_BTN_OFFSET))
    #define EN_REPRAPWORLD_KEYPAD_UP BIT((BLEN_REPRAPWORLD_KEYPAD_UP+REPRAPWORLD_BTN_OFFSET))
    #define EN_REPRAPWORLD_KEYPAD_RIGHT BIT((BLEN_REPRAPWORLD_KEYPAD_RIGHT+REPRAPWORLD_BTN_OFFSET))
    #define EN_REPRAPWORLD_KEYPAD_MIDDLE BIT((BLEN_REPRAPWORLD_KEYPAD_MIDDLE+REPRAPWORLD_BTN_OFFSET))
    #define EN_REPRAPWORLD_KEYPAD_DOWN BIT((BLEN_REPRAPWORLD_KEYPAD_DOWN+REPRAPWORLD_BTN_OFFSET))
    #define EN_REPRAPWORLD_KEYPAD_LEFT BIT((BLEN_REPRAPWORLD_KEYPAD_LEFT+REPRAPWORLD_BTN_OFFSET))

MagoKimbra's avatar
MagoKimbra committed
119 120 121 122 123 124 125
    /*
    #if ENABLED(INVERT_CLICK_BUTTON)
      #define LCD_CLICKED !((buttons&EN_C) || (buttons&EN_REPRAPWORLD_KEYPAD_F1))
    #else
      #define LCD_CLICKED ((buttons&EN_C) || (buttons&EN_REPRAPWORLD_KEYPAD_F1))
    #endif
    */
MagoKimbra's avatar
MagoKimbra committed
126 127 128
    //#define REPRAPWORLD_KEYPAD_MOVE_Y_DOWN (buttons&EN_REPRAPWORLD_KEYPAD_DOWN)
    //#define REPRAPWORLD_KEYPAD_MOVE_Y_UP (buttons&EN_REPRAPWORLD_KEYPAD_UP)
    //#define REPRAPWORLD_KEYPAD_MOVE_HOME (buttons&EN_REPRAPWORLD_KEYPAD_MIDDLE)
MagoKimbra's avatar
MagoKimbra committed
129

MagoKimbra's avatar
MagoKimbra committed
130
  #elif ENABLED(NEWPANEL)
MagoKimbra's avatar
MagoKimbra committed
131 132 133 134 135
    #if ENABLED(INVERT_CLICK_BUTTON)
      #define LCD_CLICKED !(buttons&EN_C)
    #else
      #define LCD_CLICKED (buttons&EN_C)
    #endif
MagoKimbra's avatar
MagoKimbra committed
136
    #if HAS(BTN_BACK)
MagoKimbra's avatar
MagoKimbra committed
137 138 139 140 141
      #if ENABLED(INVERT_BACK_BUTTON)
        #define LCD_BACK_CLICKED !(buttons&EN_D)
      #else
        #define LCD_BACK_CLICKED (buttons&EN_D)
      #endif
MagoKimbra's avatar
MagoKimbra committed
142
    #endif
MagoKimbra's avatar
MagoKimbra committed
143

MagoKimbra's avatar
MagoKimbra committed
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
  #else // old style ULTIPANEL
    //bits in the shift register that carry the buttons for:
    // left up center down right red(stop)
    #define BL_LE 7
    #define BL_UP 6
    #define BL_MI 5
    #define BL_DW 4
    #define BL_RI 3
    #define BL_ST 2

    //automatic, do not change
    #define B_LE BIT(BL_LE)
    #define B_UP BIT(BL_UP)
    #define B_MI BIT(BL_MI)
    #define B_DW BIT(BL_DW)
    #define B_RI BIT(BL_RI)
    #define B_ST BIT(BL_ST)

MagoKimbra's avatar
MagoKimbra committed
162 163 164 165 166
    #if ENABLED(INVERT_CLICK_BUTTON)
      #define LCD_CLICKED !(buttons&(B_MI|B_ST))
    #else
      #define LCD_CLICKED (buttons&(B_MI|B_ST))
    #endif
MagoKimbra's avatar
MagoKimbra committed
167
  #endif
MagoKimbra's avatar
MagoKimbra committed
168 169 170 171 172

#endif //ULTIPANEL

////////////////////////////////////
// Create LCD class instance and chipset-specific information
MagoKimbra's avatar
MagoKimbra committed
173
#if ENABLED(LCD_I2C_TYPE_PCF8575)
MagoKimbra's avatar
MagoKimbra committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187
  // note: these are register mapped pins on the PCF8575 controller not Arduino pins
  #define LCD_I2C_PIN_BL  3
  #define LCD_I2C_PIN_EN  2
  #define LCD_I2C_PIN_RW  1
  #define LCD_I2C_PIN_RS  0
  #define LCD_I2C_PIN_D4  4
  #define LCD_I2C_PIN_D5  5
  #define LCD_I2C_PIN_D6  6
  #define LCD_I2C_PIN_D7  7

  #include <Wire.h>
  #include <LCD.h>
  #include <LiquidCrystal_I2C.h>
  #define LCD_CLASS LiquidCrystal_I2C
MagoKimbra's avatar
MagoKimbra committed
188
  LCD_CLASS lcd(LCD_I2C_ADDRESS, LCD_I2C_PIN_EN, LCD_I2C_PIN_RW, LCD_I2C_PIN_RS, LCD_I2C_PIN_D4, LCD_I2C_PIN_D5, LCD_I2C_PIN_D6, LCD_I2C_PIN_D7);
MagoKimbra's avatar
MagoKimbra committed
189

MagoKimbra's avatar
MagoKimbra committed
190
#elif ENABLED(LCD_I2C_TYPE_MCP23017)
MagoKimbra's avatar
MagoKimbra committed
191 192 193 194 195 196 197 198 199 200
  //for the LED indicators (which maybe mapped to different things in lcd_implementation_update_indicators())
  #define LED_A 0x04 //100
  #define LED_B 0x02 //010
  #define LED_C 0x01 //001

  #define LCD_HAS_STATUS_INDICATORS

  #include <Wire.h>
  #include <LiquidTWI2.h>
  #define LCD_CLASS LiquidTWI2
MagoKimbra's avatar
MagoKimbra committed
201
  #if ENABLED(DETECT_DEVICE)
MagoKimbra's avatar
MagoKimbra committed
202
    LCD_CLASS lcd(LCD_I2C_ADDRESS, 1);
MagoKimbra's avatar
MagoKimbra committed
203
  #else
MagoKimbra's avatar
MagoKimbra committed
204
    LCD_CLASS lcd(LCD_I2C_ADDRESS);
MagoKimbra's avatar
MagoKimbra committed
205
  #endif
MagoKimbra's avatar
MagoKimbra committed
206

MagoKimbra's avatar
MagoKimbra committed
207
#elif ENABLED(LCD_I2C_TYPE_MCP23008)
MagoKimbra's avatar
MagoKimbra committed
208 209 210
  #include <Wire.h>
  #include <LiquidTWI2.h>
  #define LCD_CLASS LiquidTWI2
MagoKimbra's avatar
MagoKimbra committed
211
  #if ENABLED(DETECT_DEVICE)
MagoKimbra's avatar
MagoKimbra committed
212
    LCD_CLASS lcd(LCD_I2C_ADDRESS, 1);
MagoKimbra's avatar
MagoKimbra committed
213
  #else
MagoKimbra's avatar
MagoKimbra committed
214
    LCD_CLASS lcd(LCD_I2C_ADDRESS);
MagoKimbra's avatar
MagoKimbra committed
215 216
  #endif

MagoKimbra's avatar
MagoKimbra committed
217
#elif ENABLED(LCD_I2C_TYPE_PCA8574)
MagoKimbra's avatar
MagoKimbra committed
218 219 220
  #include <LiquidCrystal_I2C.h>
  #define LCD_CLASS LiquidCrystal_I2C
  LCD_CLASS lcd(LCD_I2C_ADDRESS, LCD_WIDTH, LCD_HEIGHT);
MagoKimbra's avatar
MagoKimbra committed
221

MagoKimbra's avatar
MagoKimbra committed
222
// 2 wire Non-latching LCD SR from:
MagoKimbra's avatar
MagoKimbra committed
223
// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection
MagoKimbra's avatar
MagoKimbra committed
224
#elif ENABLED(SR_LCD_2W_NL)
MagoKimbra's avatar
MagoKimbra committed
225 226 227 228 229 230 231 232 233
  extern "C" void __cxa_pure_virtual() { while (1); }
  #include <LCD.h>
  #include <LiquidCrystal_SR.h>
  #define LCD_CLASS LiquidCrystal_SR
  LCD_CLASS lcd(SR_DATA_PIN, SR_CLK_PIN);
#else
  // Standard directly connected LCD implementations
  #include <LiquidCrystal.h>
  #define LCD_CLASS LiquidCrystal
MagoKimbra's avatar
MagoKimbra committed
234
  LCD_CLASS lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5, LCD_PINS_D6, LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7
MagoKimbra's avatar
MagoKimbra committed
235 236 237 238
#endif

#include "utf_mapper.h"

MagoKimbra's avatar
MagoKimbra committed
239 240 241 242 243
#if ENABLED(SHOW_BOOTSCREEN)
  static void bootscreen();
  static bool show_bootscreen = true;
#endif

MagoKimbra's avatar
MagoKimbra committed
244
#if ENABLED(LCD_PROGRESS_BAR)
MagoKimbra's avatar
MagoKimbra committed
245
  static millis_t progress_bar_ms = 0;
MagoKimbra's avatar
MagoKimbra committed
246
  #if PROGRESS_MSG_EXPIRE > 0
MagoKimbra's avatar
MagoKimbra committed
247
    static millis_t expire_status_ms = 0;
MagoKimbra's avatar
MagoKimbra committed
248 249 250 251 252
  #endif
  #define LCD_STR_PROGRESS  "\x03\x04\x05"
#endif

static void lcd_set_custom_characters(
MagoKimbra's avatar
MagoKimbra committed
253
  #if ENABLED(LCD_PROGRESS_BAR)
MagoKimbra's avatar
MagoKimbra committed
254
    bool progress_bar_set = true
MagoKimbra's avatar
MagoKimbra committed
255 256
  #endif
) {
MagoKimbra's avatar
MagoKimbra committed
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
  byte bedTemp[8] = {
    B00000,
    B11111,
    B10101,
    B10001,
    B10101,
    B11111,
    B00000,
    B00000
  }; //thanks Sonny Mounicou
  byte degree[8] = {
    B01100,
    B10010,
    B10010,
    B01100,
    B00000,
    B00000,
    B00000,
    B00000
  };
  byte thermometer[8] = {
    B00100,
    B01010,
    B01010,
    B01010,
    B01010,
    B11111,
    B11111,
    B01110
  };
  byte uplevel[8] = {
    B00100,
    B01110,
    B11111,
    B00100,
    B11100,
    B00000,
    B00000,
    B00000
  }; //thanks joris
  byte refresh[8] = {
    B00000,
    B00110,
    B11001,
    B11000,
    B00011,
    B10011,
    B01100,
    B00000,
  }; //thanks joris
  byte folder[8] = {
    B00000,
    B11100,
    B11111,
    B10001,
    B10001,
    B11111,
    B00000,
    B00000
  }; //thanks joris
  byte feedrate[8] = {
    B11100,
    B10000,
    B11000,
    B10111,
    B00101,
    B00110,
    B00101,
    B00000
  }; //thanks Sonny Mounicou
  byte clock[8] = {
    B00000,
    B01110,
    B10011,
    B10101,
    B10001,
    B01110,
    B00000,
    B00000
  }; //thanks Sonny Mounicou
MagoKimbra's avatar
MagoKimbra committed
337

MagoKimbra's avatar
MagoKimbra committed
338
  #if ENABLED(LCD_PROGRESS_BAR)
MagoKimbra's avatar
MagoKimbra committed
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    static bool char_mode = false;
    byte progress[3][8] = { {
      B00000,
      B10000,
      B10000,
      B10000,
      B10000,
      B10000,
      B10000,
      B00000
    }, {
      B00000,
      B10100,
      B10100,
      B10100,
      B10100,
      B10100,
      B10100,
      B00000
    }, {
      B00000,
      B10101,
      B10101,
      B10101,
      B10101,
      B10101,
      B10101,
      B00000
    } };
    if (progress_bar_set != char_mode) {
      char_mode = progress_bar_set;
      lcd.createChar(LCD_STR_BEDTEMP[0], bedTemp);
      lcd.createChar(LCD_STR_DEGREE[0], degree);
      lcd.createChar(LCD_STR_THERMOMETER[0], thermometer);
      lcd.createChar(LCD_STR_FEEDRATE[0], feedrate);
      lcd.createChar(LCD_STR_CLOCK[0], clock);
      if (progress_bar_set) {
        // Progress bar characters for info screen
MagoKimbra's avatar
MagoKimbra committed
377
        for (int i = 3; i--;) lcd.createChar(LCD_STR_PROGRESS[i], progress[i]);
MagoKimbra's avatar
MagoKimbra committed
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
      }
      else {
        // Custom characters for submenus
        lcd.createChar(LCD_STR_UPLEVEL[0], uplevel);
        lcd.createChar(LCD_STR_REFRESH[0], refresh);
        lcd.createChar(LCD_STR_FOLDER[0], folder);
      }
    }
  #else
    lcd.createChar(LCD_STR_BEDTEMP[0], bedTemp);
    lcd.createChar(LCD_STR_DEGREE[0], degree);
    lcd.createChar(LCD_STR_THERMOMETER[0], thermometer);
    lcd.createChar(LCD_STR_UPLEVEL[0], uplevel);
    lcd.createChar(LCD_STR_REFRESH[0], refresh);
    lcd.createChar(LCD_STR_FOLDER[0], folder);
    lcd.createChar(LCD_STR_FEEDRATE[0], feedrate);
    lcd.createChar(LCD_STR_CLOCK[0], clock);
  #endif
}

static void lcd_implementation_init(
MagoKimbra's avatar
MagoKimbra committed
399
  #if ENABLED(LCD_PROGRESS_BAR)
MagoKimbra's avatar
MagoKimbra committed
400
    bool progress_bar_set = true
MagoKimbra's avatar
MagoKimbra committed
401 402 403
  #endif
) {

MagoKimbra's avatar
MagoKimbra committed
404
  #if ENABLED(LCD_I2C_TYPE_PCF8575)
MagoKimbra's avatar
MagoKimbra committed
405
    lcd.begin(LCD_WIDTH, LCD_HEIGHT);
Simone Primarosa's avatar
Simone Primarosa committed
406
    #if ENABLED(LCD_I2C_PIN_BL)
MagoKimbra's avatar
MagoKimbra committed
407 408 409 410
      lcd.setBacklightPin(LCD_I2C_PIN_BL, POSITIVE);
      lcd.setBacklight(HIGH);
    #endif

MagoKimbra's avatar
MagoKimbra committed
411
  #elif ENABLED(LCD_I2C_TYPE_MCP23017)
MagoKimbra's avatar
MagoKimbra committed
412 413 414
    lcd.setMCPType(LTI_TYPE_MCP23017);
    lcd.begin(LCD_WIDTH, LCD_HEIGHT);
    lcd.setBacklight(0); //set all the LEDs off to begin with
MagoKimbra's avatar
MagoKimbra committed
415

MagoKimbra's avatar
MagoKimbra committed
416
  #elif ENABLED(LCD_I2C_TYPE_MCP23008)
MagoKimbra's avatar
MagoKimbra committed
417 418
    lcd.setMCPType(LTI_TYPE_MCP23008);
    lcd.begin(LCD_WIDTH, LCD_HEIGHT);
MagoKimbra's avatar
MagoKimbra committed
419

MagoKimbra's avatar
MagoKimbra committed
420
  #elif ENABLED(LCD_I2C_TYPE_PCA8574)
MagoKimbra's avatar
MagoKimbra committed
421 422 423 424 425
    lcd.init();
    lcd.backlight();

  #else
    #if (LCD_PINS_RS != -1) && (LCD_PINS_ENABLE != -1)
MagoKimbra's avatar
MagoKimbra committed
426 427 428
      // required for RAMPS-FD, but does no harm for other targets
      SET_OUTPUT(LCD_PINS_RS);
      SET_OUTPUT(LCD_PINS_ENABLE);
Simone Primarosa's avatar
Simone Primarosa committed
429
    #endif
MagoKimbra's avatar
MagoKimbra committed
430
    lcd.begin(LCD_WIDTH, LCD_HEIGHT);
MagoKimbra's avatar
MagoKimbra committed
431
  #endif
MagoKimbra's avatar
MagoKimbra committed
432

MagoKimbra's avatar
MagoKimbra committed
433 434 435 436
  #if ENABLED(SHOW_BOOTSCREEN)
    if (show_bootscreen) bootscreen();
  #endif

MagoKimbra's avatar
MagoKimbra committed
437
  lcd_set_custom_characters(
MagoKimbra's avatar
MagoKimbra committed
438
    #if ENABLED(LCD_PROGRESS_BAR)
MagoKimbra's avatar
MagoKimbra committed
439 440 441
      progress_bar_set
    #endif
  );
MagoKimbra's avatar
MagoKimbra committed
442 443 444 445

  lcd.clear();
}

MagoKimbra's avatar
MagoKimbra committed
446 447
static void lcd_implementation_clear() { lcd.clear(); }

MagoKimbra's avatar
MagoKimbra committed
448 449
/* Arduino < 1.0.0 is missing a function to print PROGMEM strings, so we need to implement our own */
char lcd_printPGM(const char* str) {
MagoKimbra's avatar
MagoKimbra committed
450 451
  char c, n = 0;
  while ((c = pgm_read_byte(str++))) n += charset_mapper(c);
MagoKimbra's avatar
MagoKimbra committed
452 453 454 455
  return n;
}

char lcd_print(char* str) {
MagoKimbra's avatar
MagoKimbra committed
456
  char c, n = 0;
MagoKimbra's avatar
MagoKimbra committed
457
  unsigned char i = 0;
MagoKimbra's avatar
MagoKimbra committed
458
  while ((c = str[i++])) n += charset_mapper(c);
MagoKimbra's avatar
MagoKimbra committed
459 460 461
  return n;
}

MagoKimbra's avatar
MagoKimbra committed
462
unsigned lcd_print(char c) { return charset_mapper(c); }
MagoKimbra's avatar
MagoKimbra committed
463

MagoKimbra's avatar
MagoKimbra committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
#if ENABLED(SHOW_BOOTSCREEN)
  void lcd_erase_line(int line) {
    lcd.setCursor(0, 3);
    for (int i = 0; i < LCD_WIDTH; i++)
      lcd_print(' ');
  }

  // Scroll the PSTR 'text' in a 'len' wide field for 'time' milliseconds at position col,line
  void lcd_scroll(int col, int line, const char* text, int len, int time) {
    char tmp[LCD_WIDTH + 1] = {0};
    int n = max(lcd_strlen_P(text) - len, 0);
    for (int i = 0; i <= n; i++) {
      strncpy_P(tmp, text + i, min(len, LCD_WIDTH));
      lcd.setCursor(col, line);
      lcd_print(tmp);
      delay(time / max(n, 1));
    }
  }

  static void bootscreen() {
    show_bootscreen = false;
    byte top_left[8] = {
      B00000,
      B00000,
      B00000,
      B00000,
      B00001,
      B00010,
      B00100,
      B00100
    };
    byte top_right[8] = {
      B00000,
      B00000,
      B00000,
      B11100,
      B11100,
      B01100,
      B00100,
      B00100
    };
    byte botom_left[8] = {
      B00100,
      B00010,
      B00001,
      B00000,
      B00000,
      B00000,
      B00000,
      B00000
    };
    byte botom_right[8] = {
      B00100,
      B01000,
      B10000,
      B00000,
      B00000,
      B00000,
      B00000,
      B00000
    };
    lcd.createChar(0, top_left);
    lcd.createChar(1, top_right);
    lcd.createChar(2, botom_left);
    lcd.createChar(3, botom_right);

    lcd.clear();

    #define TEXT_SCREEN_LOGO_SHIFT ((LCD_WIDTH/2) - 7)
    lcd.setCursor(TEXT_SCREEN_LOGO_SHIFT, 0); lcd.print('\x00'); lcd_printPGM(PSTR( "------------" ));  lcd.print('\x01');
    lcd.setCursor(TEXT_SCREEN_LOGO_SHIFT, 1);                    lcd_printPGM(PSTR("|MarlinKimbra|"));
    lcd.setCursor(TEXT_SCREEN_LOGO_SHIFT, 2); lcd.print('\x02'); lcd_printPGM(PSTR( "------------" ));  lcd.print('\x03');

    delay(1000);

    #ifdef STRING_SPLASH_LINE1
      lcd_erase_line(3);
      lcd_scroll(0, 3, PSTR(STRING_SPLASH_LINE1), LCD_WIDTH, 3000);
    #endif

    #ifdef STRING_SPLASH_LINE2
      lcd_erase_line(3);
      lcd_scroll(0, 3, PSTR(STRING_SPLASH_LINE2), LCD_WIDTH, 3000);
    #endif

    #ifdef FIRMWARE_URL
      lcd_erase_line(3);
      lcd_scroll(0, 3, PSTR(FIRMWARE_URL), LCD_WIDTH, 5000);
    #endif
  }
#endif // SHOW_BOOTSCREEN

MagoKimbra's avatar
MagoKimbra committed
556 557
/*
Possible status screens:
MagoKimbra's avatar
MagoKimbra committed
558 559
16x2   |000/000 B000/000|
       |0123456789012345|
MagoKimbra's avatar
MagoKimbra committed
560

MagoKimbra's avatar
MagoKimbra committed
561
16x4   |000/000 B000/000|
MagoKimbra's avatar
MagoKimbra committed
562
       |SD100%  Z 000.00|
MagoKimbra's avatar
MagoKimbra committed
563
       |F100%     T--:--|
MagoKimbra's avatar
MagoKimbra committed
564
       |0123456789012345|
MagoKimbra's avatar
MagoKimbra committed
565

MagoKimbra's avatar
MagoKimbra committed
566 567
20x2   |T000/000D B000/000D |
       |01234567890123456789|
MagoKimbra's avatar
MagoKimbra committed
568

MagoKimbra's avatar
MagoKimbra committed
569
20x4   |T000/000D B000/000D |
MagoKimbra's avatar
MagoKimbra committed
570
       |X 000 Y 000 Z 000.00|
MagoKimbra's avatar
MagoKimbra committed
571
       |F100%  SD100% T--:--|
MagoKimbra's avatar
MagoKimbra committed
572
       |01234567890123456789|
MagoKimbra's avatar
MagoKimbra committed
573

MagoKimbra's avatar
MagoKimbra committed
574
20x4   |T000/000D B000/000D |
MagoKimbra's avatar
MagoKimbra committed
575
       |T000/000D   Z 000.00|
MagoKimbra's avatar
MagoKimbra committed
576
       |F100%  SD100% T--:--|
MagoKimbra's avatar
MagoKimbra committed
577
       |01234567890123456789|
MagoKimbra's avatar
MagoKimbra committed
578
*/
MagoKimbra's avatar
MagoKimbra committed
579
static void lcd_implementation_status_screen() {
MagoKimbra's avatar
MagoKimbra committed
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596

  #define LCD_TEMP_ONLY(T1,T2) \
    lcd.print(itostr3(T1 + 0.5)); \
    lcd.print('/'); \
    lcd.print(itostr3left(T2 + 0.5))

  #define LCD_TEMP(T1,T2,PREFIX) \
    lcd.print(PREFIX); \
    LCD_TEMP_ONLY(T1,T2); \
    lcd_printPGM(PSTR(LCD_STR_DEGREE " ")); \
    if (T2 < 10) lcd.print(' ')

  //
  // Line 1
  //

  lcd.setCursor(0, 0);
MagoKimbra's avatar
MagoKimbra committed
597 598

  #if LCD_WIDTH < 20
MagoKimbra's avatar
MagoKimbra committed
599

MagoKimbra's avatar
MagoKimbra committed
600 601 602 603
    //
    // Hotend 0 Temperature
    //
    LCD_TEMP_ONLY(degHotend(0), degTargetHotend(0));
MagoKimbra's avatar
MagoKimbra committed
604

MagoKimbra's avatar
MagoKimbra committed
605 606 607
    //
    // Hotend 1 or Bed Temperature
    //
MagoKimbra's avatar
MagoKimbra committed
608
    #if HOTENDS > 1 || TEMP_SENSOR_BED != 0
MagoKimbra's avatar
MagoKimbra committed
609

MagoKimbra's avatar
MagoKimbra committed
610 611 612
      lcd.setCursor(8, 0);
      #if HOTENDS > 1
        lcd.print(LCD_STR_THERMOMETER[0]);
MagoKimbra's avatar
MagoKimbra committed
613
        LCD_TEMP_ONLY(degHotend(1), degTargetHotend(1));
MagoKimbra's avatar
MagoKimbra committed
614
      #else
MagoKimbra's avatar
MagoKimbra committed
615
        lcd.print(LCD_STR_BEDTEMP[0]);
MagoKimbra's avatar
MagoKimbra committed
616
        LCD_TEMP_ONLY(degBed(), degTargetBed());
MagoKimbra's avatar
MagoKimbra committed
617 618
      #endif

MagoKimbra's avatar
MagoKimbra committed
619 620
    #endif // HOTENDS > 1 || TEMP_SENSOR_BED != 0

MagoKimbra's avatar
MagoKimbra committed
621
  #else // LCD_WIDTH >= 20
MagoKimbra's avatar
MagoKimbra committed
622

MagoKimbra's avatar
MagoKimbra committed
623 624 625 626
    //
    // Hotend 0 Temperature
    //
    LCD_TEMP(degHotend(0), degTargetHotend(0), LCD_STR_THERMOMETER[0]);
MagoKimbra's avatar
MagoKimbra committed
627

MagoKimbra's avatar
MagoKimbra committed
628 629 630
    //
    // Hotend 1 or Bed Temperature
    //
MagoKimbra's avatar
MagoKimbra committed
631 632 633
    #if HOTENDS > 1 || TEMP_SENSOR_BED != 0
      lcd.setCursor(10, 0);
      #if HOTENDS > 1
MagoKimbra's avatar
MagoKimbra committed
634 635 636
        LCD_TEMP(degHotend(1), degTargetHotend(1), LCD_STR_THERMOMETER[0]);
      #else
        LCD_TEMP(degBed(), degTargetBed(), LCD_STR_BEDTEMP[0]);
MagoKimbra's avatar
MagoKimbra committed
637
      #endif
MagoKimbra's avatar
MagoKimbra committed
638 639 640

    #endif // HOTENDS > 1 || TEMP_SENSOR_BED != 0

MagoKimbra's avatar
MagoKimbra committed
641 642 643 644 645
  #endif // LCD_WIDTH >= 20

  //
  // Line 2
  //
MagoKimbra's avatar
MagoKimbra committed
646 647

  #if LCD_HEIGHT > 2
MagoKimbra's avatar
MagoKimbra committed
648

MagoKimbra's avatar
MagoKimbra committed
649
    #if LCD_WIDTH < 20
MagoKimbra's avatar
MagoKimbra committed
650

MagoKimbra's avatar
MagoKimbra committed
651
      #if ENABLED(SDSUPPORT)
MagoKimbra's avatar
MagoKimbra committed
652 653 654 655 656 657 658
        lcd.setCursor(0, 2);
        lcd_printPGM(PSTR("SD"));
        if (IS_SD_PRINTING)
          lcd.print(itostr3(card.percentDone()));
        else
          lcd_printPGM(PSTR("---"));
        lcd.print('%');
MagoKimbra's avatar
MagoKimbra committed
659 660
      #endif // SDSUPPORT

MagoKimbra's avatar
MagoKimbra committed
661 662 663
    #else // LCD_WIDTH >= 20

      lcd.setCursor(0, 1);
MagoKimbra's avatar
MagoKimbra committed
664

MagoKimbra's avatar
MagoKimbra committed
665 666 667 668 669 670
      //
      // Print XYZ Coordinates
      // If the axis was not homed, show "---"
      // If the position is untrusted, show "?"
      //

MagoKimbra's avatar
MagoKimbra committed
671 672
      #if HOTENDS > 1 && TEMP_SENSOR_BED != 0

MagoKimbra's avatar
MagoKimbra committed
673
        // If we both have a 2nd hotend and a heated bed,
MagoKimbra's avatar
MagoKimbra committed
674
        // show the heated bed temp on the left,
MagoKimbra's avatar
MagoKimbra committed
675
        // since the first line is filled with hotend temps
MagoKimbra's avatar
MagoKimbra committed
676 677
        LCD_TEMP(degBed(), degTargetBed(), LCD_STR_BEDTEMP[0]);

MagoKimbra's avatar
MagoKimbra committed
678
      #else
MagoKimbra's avatar
MagoKimbra committed
679

MagoKimbra's avatar
MagoKimbra committed
680 681
        lcd.print(TEST(axis_known_position, X_AXIS) || !TEST(axis_was_homed, X_AXIS) ? 'X' : '?');
        if (TEST(axis_was_homed, X_AXIS))
MagoKimbra's avatar
MagoKimbra committed
682
          lcd.print(ftostr4sign(current_position[X_AXIS]));
MagoKimbra's avatar
MagoKimbra committed
683
        else
MagoKimbra's avatar
MagoKimbra committed
684
          lcd_printPGM(PSTR(" ---"));
MagoKimbra's avatar
MagoKimbra committed
685

MagoKimbra's avatar
MagoKimbra committed
686 687
        lcd_printPGM(TEST(axis_known_position, Y_AXIS) || !TEST(axis_was_homed, Y_AXIS) ? PSTR(" Y") : PSTR(" ?"));
        if (TEST(axis_was_homed, Y_AXIS))
MagoKimbra's avatar
MagoKimbra committed
688 689 690
          lcd.print(ftostr4sign(current_position[Y_AXIS]));
        else
          lcd_printPGM(PSTR(" ---"));
MagoKimbra's avatar
MagoKimbra committed
691

MagoKimbra's avatar
MagoKimbra committed
692 693
      #endif // HOTENDS > 1 || TEMP_SENSOR_BED != 0

MagoKimbra's avatar
MagoKimbra committed
694
    #endif // LCD_WIDTH >= 20
MagoKimbra's avatar
MagoKimbra committed
695 696

    lcd.setCursor(LCD_WIDTH - 8, 1);
MagoKimbra's avatar
MagoKimbra committed
697 698
    lcd_printPGM(TEST(axis_known_position, Z_AXIS) || !TEST(axis_was_homed, Z_AXIS) ? PSTR("Z ") : PSTR("? "));
    if (TEST(axis_was_homed, Z_AXIS))
MagoKimbra's avatar
MagoKimbra committed
699 700 701
      lcd.print(ftostr32sp(current_position[Z_AXIS] + 0.00001));
    else
      lcd_printPGM(PSTR("---.--"));
MagoKimbra's avatar
MagoKimbra committed
702 703

  #endif // LCD_HEIGHT > 2
MagoKimbra's avatar
MagoKimbra committed
704

MagoKimbra's avatar
MagoKimbra committed
705 706 707 708
  //
  // Line 3
  //

MagoKimbra's avatar
MagoKimbra committed
709
  #if LCD_HEIGHT > 3
MagoKimbra's avatar
MagoKimbra committed
710

MagoKimbra's avatar
MagoKimbra committed
711 712
    lcd.setCursor(0, 2);
    lcd.print(LCD_STR_FEEDRATE[0]);
MagoKimbra's avatar
MagoKimbra committed
713
    lcd.print(itostr3(feedrate_multiplier));
MagoKimbra's avatar
MagoKimbra committed
714
    lcd.print('%');
MagoKimbra's avatar
MagoKimbra committed
715

MagoKimbra's avatar
MagoKimbra committed
716
    #if LCD_WIDTH > 19 && ENABLED(SDSUPPORT)
MagoKimbra's avatar
MagoKimbra committed
717 718 719 720 721 722 723 724 725 726 727

      lcd.setCursor(7, 2);
      lcd_printPGM(PSTR("SD"));
      if (IS_SD_PRINTING)
        lcd.print(itostr3(card.percentDone()));
      else
        lcd_printPGM(PSTR("---"));
      lcd.print('%');

    #endif // LCD_WIDTH > 19 && SDSUPPORT

MagoKimbra's avatar
MagoKimbra committed
728
    lcd.setCursor(LCD_WIDTH - 6, 2);
MagoKimbra's avatar
MagoKimbra committed
729
    if(print_job_start_ms != 0) {
Simone Primarosa's avatar
Simone Primarosa committed
730
      #if HAS(LCD_POWER_SENSOR)
MagoKimbra's avatar
MagoKimbra committed
731 732
        if (millis() < print_millis + 1000) {
          lcd.print(LCD_STR_CLOCK[0]);
MagoKimbra's avatar
MagoKimbra committed
733
          uint16_t time = millis()/60000 - print_job_start_ms/60000;
MagoKimbra's avatar
MagoKimbra committed
734 735 736 737 738 739 740 741 742 743
          lcd.print(itostr2(time/60));
          lcd.print(':');
          lcd.print(itostr2(time%60));
        }
        else {
          lcd.print(itostr4(power_consumption_hour-startpower));
          lcd.print('Wh');
        }
      #else
        lcd.print(LCD_STR_CLOCK[0]);
MagoKimbra's avatar
MagoKimbra committed
744
        uint16_t time = millis()/60000 - print_job_start_ms/60000;
MagoKimbra's avatar
MagoKimbra committed
745 746 747 748 749 750 751 752 753
        lcd.print(itostr2(time/60));
        lcd.print(':');
        lcd.print(itostr2(time%60));
      #endif
    }
    else {
      lcd_printPGM(PSTR("--:--"));
    }

MagoKimbra's avatar
MagoKimbra committed
754 755
  #endif // LCD_HEIGHT > 3

MagoKimbra's avatar
MagoKimbra committed
756 757 758 759
  //
  // Last Line
  // Status Message (which may be a Progress Bar or Filament display)
  //
MagoKimbra's avatar
MagoKimbra committed
760

MagoKimbra's avatar
MagoKimbra committed
761 762
  lcd.setCursor(0, LCD_HEIGHT - 1);

MagoKimbra's avatar
MagoKimbra committed
763
  #if ENABLED(LCD_PROGRESS_BAR)
MagoKimbra's avatar
MagoKimbra committed
764 765

    if (card.isFileOpen()) {
MagoKimbra's avatar
MagoKimbra committed
766 767 768
      // Draw the progress bar if the message has shown long enough
      // or if there is no message set.
      if (millis() >= progress_bar_ms + PROGRESS_BAR_MSG_TIME || !lcd_status_message[0]) {
MagoKimbra's avatar
MagoKimbra committed
769 770
        int tix = (int)(card.percentDone() * LCD_WIDTH * 3) / 100,
          cel = tix / 3, rem = tix % 3, i = LCD_WIDTH;
MagoKimbra's avatar
MagoKimbra committed
771
        char msg[LCD_WIDTH + 1], b = ' ';
MagoKimbra's avatar
MagoKimbra committed
772 773 774 775 776
        msg[i] = '\0';
        while (i--) {
          if (i == cel - 1)
            b = LCD_STR_PROGRESS[2];
          else if (i == cel && rem != 0)
MagoKimbra's avatar
MagoKimbra committed
777
            b = LCD_STR_PROGRESS[rem - 1];
MagoKimbra's avatar
MagoKimbra committed
778 779 780 781 782 783 784
          msg[i] = b;
        }
        lcd.print(msg);
        return;
      }
    } //card.isFileOpen

MagoKimbra's avatar
MagoKimbra committed
785
  #endif // ENABLED(LCD_PROGRESS_BAR)
MagoKimbra's avatar
MagoKimbra committed
786 787

  //Display both Status message line and Filament display on the last line
Simone Primarosa's avatar
Simone Primarosa committed
788
  #if HAS(LCD_FILAMENT_SENSOR) || HAS(LCD_POWER_SENSOR)
MagoKimbra's avatar
MagoKimbra committed
789
    if (millis() >= previous_lcd_status_ms + 5000) {
MagoKimbra's avatar
MagoKimbra committed
790 791
      lcd_print(lcd_status_message);
    }
Simone Primarosa's avatar
Simone Primarosa committed
792 793
    #if HAS(LCD_POWER_SENSOR)
      #if HAS(LCD_FILAMENT_SENSOR)
MagoKimbra's avatar
MagoKimbra committed
794
        else if (millis() < message_millis + 10000)
MagoKimbra's avatar
MagoKimbra committed
795 796 797 798 799 800 801 802 803 804 805
      #else
        else
      #endif
      {
        lcd_printPGM(PSTR("P:"));
        lcd.print(ftostr31(power_consumption_meas));
        lcd_printPGM(PSTR("W C:"));
        lcd.print(ltostr7(power_consumption_hour));
        lcd_printPGM(PSTR("Wh"));
      }
    #endif
Simone Primarosa's avatar
Simone Primarosa committed
806
    #if HAS(LCD_FILAMENT_SENSOR)
MagoKimbra's avatar
MagoKimbra committed
807
      else {
MagoKimbra's avatar
MagoKimbra committed
808
        lcd_printPGM(PSTR("Dia "));
MagoKimbra's avatar
MagoKimbra committed
809
        lcd.print(ftostr12ns(filament_width_meas));
MagoKimbra's avatar
MagoKimbra committed
810 811
        lcd_printPGM(PSTR(" V"));
        lcd.print(itostr3(100.0*volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]));
MagoKimbra's avatar
MagoKimbra committed
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
        lcd.print('%');
        return;
      }
    #endif
  #else
    lcd_print(lcd_status_message);
  #endif
}

static void lcd_implementation_drawmenu_generic(bool sel, uint8_t row, const char* pstr, char pre_char, char post_char) {
  char c;
  uint8_t n = LCD_WIDTH - 2;
  lcd.setCursor(0, row);
  lcd.print(sel ? pre_char : ' ');
  while ((c = pgm_read_byte(pstr)) && n > 0) {
    n -= lcd_print(c);
    pstr++;
  }
MagoKimbra's avatar
MagoKimbra committed
830
  while (n--) lcd.print(' ');
MagoKimbra's avatar
MagoKimbra committed
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
  lcd.print(post_char);
}

static void lcd_implementation_drawmenu_setting_edit_generic(bool sel, uint8_t row, const char* pstr, char pre_char, char* data) {
  char c;
  uint8_t n = LCD_WIDTH - 2 - lcd_strlen(data);
  lcd.setCursor(0, row);
  lcd.print(sel ? pre_char : ' ');
  while ((c = pgm_read_byte(pstr)) && n > 0) {
    n -= lcd_print(c);
    pstr++;
  }
  lcd.print(':');
  while (n--) lcd.print(' ');
  lcd_print(data);
}
static void lcd_implementation_drawmenu_setting_edit_generic_P(bool sel, uint8_t row, const char* pstr, char pre_char, const char* data) {
  char c;
  uint8_t n = LCD_WIDTH - 2 - lcd_strlen_P(data);
  lcd.setCursor(0, row);
  lcd.print(sel ? pre_char : ' ');
  while ((c = pgm_read_byte(pstr)) && n > 0) {
    n -= lcd_print(c);
    pstr++;
  }
  lcd.print(':');
  while (n--) lcd.print(' ');
  lcd_printPGM(data);
}

#define lcd_implementation_drawmenu_setting_edit_int3(sel, row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', itostr3(*(data)))
#define lcd_implementation_drawmenu_setting_edit_float3(sel, row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr3(*(data)))
#define lcd_implementation_drawmenu_setting_edit_float32(sel, row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr32(*(data)))
#define lcd_implementation_drawmenu_setting_edit_float43(sel, row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr43(*(data)))
#define lcd_implementation_drawmenu_setting_edit_float5(sel, row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_float52(sel, row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr52(*(data)))
#define lcd_implementation_drawmenu_setting_edit_float51(sel, row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr51(*(data)))
#define lcd_implementation_drawmenu_setting_edit_long5(sel, row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_bool(sel, row, pstr, pstr2, data) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))

//Add version for callback functions
#define lcd_implementation_drawmenu_setting_edit_callback_int3(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', itostr3(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float3(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr3(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float32(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr32(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float43(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr43(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float5(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float52(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr52(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float51(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr51(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_long5(sel, row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_bool(sel, row, pstr, pstr2, data, callback) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))

void lcd_implementation_drawedit(const char* pstr, char* value) {
  lcd.setCursor(1, 1);
  lcd_printPGM(pstr);
  lcd.print(':');
  lcd.setCursor(LCD_WIDTH - lcd_strlen(value), 1);
  lcd_print(value);
}

MagoKimbra's avatar
MagoKimbra committed
890 891
#if ENABLED(SDSUPPORT)

MagoKimbra's avatar
MagoKimbra committed
892
  static void lcd_implementation_drawmenu_sd(bool sel, uint8_t row, const char* pstr, const char* longFilename, uint8_t concat, char post_char) {
MagoKimbra's avatar
MagoKimbra committed
893 894 895 896
    char c;
    uint8_t n = LCD_WIDTH - concat;
    lcd.setCursor(0, row);
    lcd.print(sel ? '>' : ' ');
MagoKimbra's avatar
MagoKimbra committed
897
    while ((c = *longFilename) && n > 0) {
MagoKimbra's avatar
MagoKimbra committed
898
      n -= lcd_print(c);
MagoKimbra's avatar
MagoKimbra committed
899
      longFilename++;
MagoKimbra's avatar
MagoKimbra committed
900 901 902
    }
    while (n--) lcd.print(' ');
    lcd.print(post_char);
MagoKimbra's avatar
MagoKimbra committed
903
  }
MagoKimbra's avatar
MagoKimbra committed
904

MagoKimbra's avatar
MagoKimbra committed
905 906
  static void lcd_implementation_drawmenu_sdfile(bool sel, uint8_t row, const char* pstr, const char* longFilename) {
    lcd_implementation_drawmenu_sd(sel, row, pstr, longFilename, 2, ' ');
MagoKimbra's avatar
MagoKimbra committed
907 908
  }

MagoKimbra's avatar
MagoKimbra committed
909 910
  static void lcd_implementation_drawmenu_sddirectory(bool sel, uint8_t row, const char* pstr, const char* longFilename) {
    lcd_implementation_drawmenu_sd(sel, row, pstr, longFilename, 2, LCD_STR_FOLDER[0]);
MagoKimbra's avatar
MagoKimbra committed
911
  }
MagoKimbra's avatar
MagoKimbra committed
912

MagoKimbra's avatar
MagoKimbra committed
913
#endif // SDSUPPORT
MagoKimbra's avatar
MagoKimbra committed
914 915 916 917 918 919

#define lcd_implementation_drawmenu_back(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0])
#define lcd_implementation_drawmenu_submenu(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0])
#define lcd_implementation_drawmenu_gcode(sel, row, pstr, gcode) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ')
#define lcd_implementation_drawmenu_function(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ')

MagoKimbra's avatar
MagoKimbra committed
920
#if ENABLED(LCD_HAS_STATUS_INDICATORS)
MagoKimbra's avatar
MagoKimbra committed
921 922

  static void lcd_implementation_update_indicators() {
MagoKimbra's avatar
MagoKimbra committed
923
    #if ENABLED(LCD_I2C_PANELOLU2) || ENABLED(LCD_I2C_VIKI)
MagoKimbra's avatar
MagoKimbra committed
924
      // Set the LEDS - referred to as backlights by the LiquidTWI2 library
MagoKimbra's avatar
MagoKimbra committed
925 926 927 928 929 930 931 932 933 934 935 936
      static uint8_t ledsprev = 0;
      uint8_t leds = 0;
      if (target_temperature_bed > 0) leds |= LED_A;
      if (target_temperature[0] > 0) leds |= LED_B;
      if (fanSpeed) leds |= LED_C;
      #if HOTENDS > 1
        if (target_temperature[1] > 0) leds |= LED_C;
      #endif
      if (leds != ledsprev) {
        lcd.setBacklight(leds);
        ledsprev = leds;
      }
MagoKimbra's avatar
MagoKimbra committed
937
    #endif
MagoKimbra's avatar
MagoKimbra committed
938 939 940
  }

#endif // LCD_HAS_STATUS_INDICATORS
MagoKimbra's avatar
MagoKimbra committed
941

MagoKimbra's avatar
MagoKimbra committed
942
#if ENABLED(LCD_HAS_SLOW_BUTTONS)
MagoKimbra's avatar
MagoKimbra committed
943 944 945 946

  extern millis_t next_button_update_ms;

  static uint8_t lcd_implementation_read_slow_buttons() {
MagoKimbra's avatar
MagoKimbra committed
947
    #if ENABLED(LCD_I2C_TYPE_MCP23017)
MagoKimbra's avatar
MagoKimbra committed
948 949 950
      uint8_t slow_buttons;
      // Reading these buttons this is likely to be too slow to call inside interrupt context
      // so they are called during normal lcd_update
MagoKimbra's avatar
MagoKimbra committed
951
      slow_buttons = lcd.readButtons() << B_I2C_BTN_OFFSET;
MagoKimbra's avatar
MagoKimbra committed
952
      #if ENABLED(LCD_I2C_VIKI)
MagoKimbra's avatar
MagoKimbra committed
953 954
        if ((slow_buttons & (B_MI | B_RI)) && millis() < next_button_update_ms) // LCD clicked
          slow_buttons &= ~(B_MI | B_RI); // Disable LCD clicked buttons if screen is updated
MagoKimbra's avatar
MagoKimbra committed
955 956
      #endif
      return slow_buttons;
MagoKimbra's avatar
MagoKimbra committed
957
    #endif
MagoKimbra's avatar
MagoKimbra committed
958 959 960
  }

#endif // LCD_HAS_SLOW_BUTTONS
MagoKimbra's avatar
MagoKimbra committed
961

MagoKimbra's avatar
MagoKimbra committed
962
#endif // ULTRALCD_IMPLEMENTATION_HITACHI_HD44780_H