#include "LCD.h"

#ifdef ENABLE_LCD

  char now_status[16];
  char now_logo;
  bool now_save=false;

  #define _LCDML_DISP_cfg_button_press_time          200    // button press time in ms
  
  #define _LCDML_u8g_lcd_w       128            // lcd width
  #define _LCDML_u8g_lcd_h       64             // lcd height
  #define _LCDML_u8g_font        u8g_font_6x13  // u8glib font (more fonts under u8g.h line 1520 ...)
  #define _LCDML_u8g_font_w      6              // u8glib font width
  #define _LCDML_u8g_font_h      13             // u8glib font heigt
  
  #define _LCDML_u8g_cols_max    (_LCDML_u8g_lcd_w/_LCDML_u8g_font_w)
  #define _LCDML_u8g_rows_max    (_LCDML_u8g_lcd_h/_LCDML_u8g_font_h)
  
  #define _LCDML_u8g_rows        _LCDML_u8g_rows_max  // max rows 
  #define _LCDML_u8g_cols        20                   // max cols
  
  // scrollbar width
  #define _LCDML_u8g_scrollbar_w 6  // scrollbar width  
  
  // old defines with new content
  #define _LCDML_DISP_cols      _LCDML_u8g_cols
  #define _LCDML_DISP_rows      _LCDML_u8g_rows
  
  U8GLIB_ST7920_128X64_1X u8g(A4, 6, 8, U8G_PIN_NONE);
  
  #define _LCDML_DISP_cnt    20
  LCDML_DISP_initParam(_LCDML_DISP_cnt);
  LCDML_DISP_add      (0  , _LCDML_G1  , LCDML_root        , 1  , "Back"               , LCDML_FUNC_panel);
  LCDML_DISP_add      (1  , _LCDML_G1  , LCDML_root        , 2  , "Cool down"          , LCDML_FUNC_cooldown);
  LCDML_DISP_add      (2  , _LCDML_G1  , LCDML_root        , 3  , "Heat Profile"       , LCDML_FUNC);
  LCDML_DISP_add      (3  , _LCDML_G1  , LCDML_root        , 4  , "Manual Heat"        , LCDML_FUNC);
  LCDML_DISP_add      (4  , _LCDML_G1  , LCDML_root        , 5  , "Setting"            , LCDML_FUNC);
  LCDML_DISP_add      (5  , _LCDML_G1  , LCDML_root_3      , 2  , "Back"               , LCDML_FUNC_back_profile);
  LCDML_DISP_addParam (6  , _LCDML_G1  , LCDML_root_3      , 3  , "PET"                , LCDML_FUNC_profile,  PLASTIC_ID_PET);
  LCDML_DISP_addParam (7  , _LCDML_G1  , LCDML_root_3      , 4  , "HDPE"               , LCDML_FUNC_profile,  PLASTIC_ID_HDPE);
  LCDML_DISP_addParam (8  , _LCDML_G1  , LCDML_root_3      , 5  , "LDPE"               , LCDML_FUNC_profile,  PLASTIC_ID_LDPE);
  LCDML_DISP_addParam (9  , _LCDML_G1  , LCDML_root_3      , 6  , "PP"                 , LCDML_FUNC_profile,  PLASTIC_ID_PP);
  LCDML_DISP_addParam (10 , _LCDML_G1  , LCDML_root_3      , 7  , "PLA"                , LCDML_FUNC_profile,  PLASTIC_ID_PLA);
  LCDML_DISP_add      (11 , _LCDML_G1  , LCDML_root_4      , 1  , "Back"               , LCDML_FUNC_back);
  LCDML_DISP_addParam (12 , _LCDML_G1  , LCDML_root_4      , 2  , "Heater 0 Temp"      , LCDML_FUNC_temp, 0);
  LCDML_DISP_addParam (13 , _LCDML_G1  , LCDML_root_4      , 3  , "Heater 1 Temp"      , LCDML_FUNC_temp, 1);
  LCDML_DISP_add      (14 , _LCDML_G1  , LCDML_root_4      , 4  , "Save to Profile"    , LCDML_FUNC_save_profile);
  LCDML_DISP_add      (15  , _LCDML_G1  , LCDML_root_5     , 1  , "Back"               , LCDML_FUNC_back);
  LCDML_DISP_addParam (16  , _LCDML_G1  , LCDML_root_5     , 2  , "Heater 0 PID"       , LCDML_FUNC_PID_setting, 0);
  LCDML_DISP_addParam (17  , _LCDML_G1  , LCDML_root_5     , 3  , "Heater 1 PID"       , LCDML_FUNC_PID_setting, 1);
  LCDML_DISP_addParam (18  , _LCDML_G1  , LCDML_root_5     , 4  , "Save Settings"      , LCDML_FUNC_manage_setting,0);
  LCDML_DISP_addParam (19  , _LCDML_G1  , LCDML_root_5     , 5  , "Load Settings"      , LCDML_FUNC_manage_setting,1);
  LCDML_DISP_addParam (20  , _LCDML_G1  , LCDML_root_5     , 6  , "Factory Reset"      , LCDML_FUNC_manage_setting,2);
  
  LCDML_DISP_createMenu(_LCDML_DISP_cnt);
  
  // *********************************************************************
  // LCDML BACKEND (core of the menu, do not change here anything yet)
  // *********************************************************************
  // define backend function
  #define _LCDML_BACK_cnt    1  // last backend function id
  
  LCDML_BACK_init(_LCDML_BACK_cnt);
  LCDML_BACK_new_timebased_dynamic (0  , ( 20UL )         , _LCDML_start  , LCDML_BACKEND_control);
  LCDML_BACK_new_timebased_dynamic (1  , ( 10000000UL )   , _LCDML_stop   , LCDML_BACKEND_menu);
  LCDML_BACK_create();
  
  extern void initLCD() {
    statusLCD(F(STATUS_READY));
    logoLCD(-1);
    
    LCDML_DISP_groupEnable (_LCDML_G1);
    LCDML_setup(_LCDML_BACK_cnt);
    LCDML_DISP_jumpToFunc(LCDML_FUNC_panel);
    
    updateLCD(); //immediately updateLCD()
  }
  
  extern void updateLCD() {
    LCDML_run(_LCDML_priority);
  }
  
  
  
  
  
  
  // =====================================================================
  //
  // CONTROL
  //
  // =====================================================================
  // *********************************************************************
  // *********************************************************************
  // content:
  // (0) Control over serial interface
  // (1) Control over one analog input
  // (2) Control over 4 - 6 digital input pins (internal pullups enabled)
  // (3) Control over encoder (internal pullups enabled)
  // (4) Control with Keypad
  // *********************************************************************
  
  //#define _LCDML_CONTROL_cfg      0  // serial
  
  //#define _LCDML_CONTROL_cfg    1  // analog
  //#define _LCDML_CONTROL_cfg    2  // digital
  #define _LCDML_CONTROL_cfg    3  // encoder
  //#define _LCDML_CONTROL_cfg    4  // keypad
  
  // therory:
  // "#if" is a preprocessor directive and no error, look here:
  // (english) https://en.wikipedia.org/wiki/C_preprocessor
  // (german)  https://de.wikipedia.org/wiki/C-Pr%C3%A4prozessor
  
  
  // *********************************************************************
  // CONTROL TASK, DO NOT CHANGE
  // *********************************************************************
  void LCDML_BACK_setup(LCDML_BACKEND_control)
  // *********************************************************************
  {
    // call setup
    LCDML_CONTROL_setup();
  }
  // backend loop
  boolean LCDML_BACK_loop(LCDML_BACKEND_control)
  {
    // call loop
    LCDML_CONTROL_loop();
  
    // go to next backend function and do not block it
    return true;
  }
  // backend stop stable
  void LCDML_BACK_stable(LCDML_BACKEND_control)
  {
  }
  
  // *********************************************************************
  // *************** (3) CONTROL WITH ENCODER ****************************
  // *********************************************************************
  #if(_LCDML_CONTROL_cfg == 3)
  // settings
  #define _LCDML_CONTROL_encoder_pin_a           4 // pin encoder b
  #define _LCDML_CONTROL_encoder_pin_b           5 // pin encoder a
  #define _LCDML_CONTROL_encoder_pin_button      3 // pin taster
  #define _LCDML_CONTROL_encoder_high_active     0  // (0 = low active (pullup), 1 = high active (pulldown)) button
  // // http://playground.arduino.cc/CommonTopics/PullUpDownResistor
  // global defines
  uint8_t  g_LCDML_CONTROL_encoder_t_prev = 0;
  uint8_t  g_LCDML_CONTROL_encoder_a_prev = 0;
  
  // *********************************************************************
  // setup
  void LCDML_CONTROL_setup()
  {
    // set encoder update intervall time
    LCDML_BACK_dynamic_setLoopTime(LCDML_BACKEND_control, 5UL);  // 5ms
  
    // init pins
    pinMode(_LCDML_CONTROL_encoder_pin_a      , INPUT_PULLUP);
    pinMode(_LCDML_CONTROL_encoder_pin_b      , INPUT_PULLUP);
    pinMode(_LCDML_CONTROL_encoder_pin_button , INPUT_PULLUP);
  }
  // *********************************************************************
  // loop
  void LCDML_CONTROL_loop()
  {
    // read encoder status
    unsigned char a = digitalRead(_LCDML_CONTROL_encoder_pin_a);
    unsigned char b = digitalRead(_LCDML_CONTROL_encoder_pin_b);
    unsigned char t = digitalRead(_LCDML_CONTROL_encoder_pin_button);
  
    // change button status if high and low active are switched
    if (_LCDML_CONTROL_encoder_high_active == 1) {
      t != t;
    }
  
    // check encoder status and set control menu
    if (!a && g_LCDML_CONTROL_encoder_a_prev) {
      g_LCDML_CONTROL_encoder_t_prev = 1;
  
      if (!b) {
        LCDML_BUTTON_up();
      }
      else    {
        LCDML_BUTTON_down();
      }
    }
    else {
      // check button press time for enter
      if ((millis() - g_LCDML_DISP_press_time) >= _LCDML_DISP_cfg_button_press_time) {
        g_LCDML_DISP_press_time = millis(); // reset button press time
  
        // press button once
        if (!t && g_LCDML_CONTROL_encoder_t_prev == 0) {
          LCDML_BUTTON_enter();
        }
        else {
          g_LCDML_CONTROL_encoder_t_prev = 0;
        }
      }
    }
    g_LCDML_CONTROL_encoder_a_prev = a;  // set new encoder status
  
  }
  // *********************************************************************
  // ******************************* END *********************************
  // *********************************************************************
  
  
  #else
  #error _LCDML_CONTROL_cfg is not defined or not in range
  #endif
  
  // =====================================================================
  //
  // Output function
  //
  // =====================================================================
  
  /* ******************************************************************** */
  void LCDML_lcd_menu_display()
  /* ******************************************************************** */
  {
    // for first test set font here
    u8g.setFont(_LCDML_u8g_font);
    u8g.setColorIndex(1); // Instructs the display to draw with a pixel on.
  
    if (LCDML_DISP_update()) {
  
      // init vars
      uint8_t n_max = (LCDML.getChilds() >= _LCDML_u8g_rows) ? ((_LCDML_u8g_rows > _LCDML_u8g_rows_max) ? _LCDML_u8g_rows : _LCDML_u8g_rows_max) : (LCDML.getChilds());
  
      // set page
      u8g.firstPage();
  
      // generate content
      do {
  
        // display rows and cursor
        for (uint8_t n = 0; n < n_max; n++)
        {
          // set cursor
          if (n == LCDML.getCursorPos()) {
            u8g.drawStr( 0, _LCDML_u8g_font_h * (n + 1),  ">");
          }
  
          // set content
          // with content id you can add special content to your static menu or replace the content
          // the content_id contains the id wich is set on main tab for a menuitem
          switch (LCDML.content_id[n])
          {
            //case 0:
            //  u8g.drawStr( 10, _LCDML_u8g_font_h * (n + 1), "var_datetime"); // or datetime or other things
            //  break;
  
            default: // static content
              u8g.drawStr( 10, _LCDML_u8g_font_h * (n + 1), LCDML.content[n]);
              break;
          }
        }
  
        // display scrollbar when more content as rows available
        if (LCDML.getChilds() > n_max) {
  
          // set frame for scrollbar
          u8g.drawFrame(_LCDML_u8g_lcd_w - _LCDML_u8g_scrollbar_w, 0, _LCDML_u8g_scrollbar_w, _LCDML_u8g_lcd_h);
  
          // calculate scrollbar length
          uint8_t scrollbar_block_length = LCDML.getChilds() - n_max;
          scrollbar_block_length = _LCDML_u8g_lcd_h / (scrollbar_block_length + _LCDML_DISP_rows);
  
          //set scrollbar
          if (LCDML.getCursorPosAbs() == 0) {                                   // top position     (min)
            u8g.drawBox(_LCDML_u8g_lcd_w - (_LCDML_u8g_scrollbar_w - 1), 1                                                    , (_LCDML_u8g_scrollbar_w - 2)  , scrollbar_block_length);
          }
          else if (LCDML.getCursorPosAbs() == (LCDML.getChilds())) {            // bottom position  (max)
            u8g.drawBox(_LCDML_u8g_lcd_w - (_LCDML_u8g_scrollbar_w - 1), _LCDML_u8g_lcd_h - scrollbar_block_length            , (_LCDML_u8g_scrollbar_w - 2)  , scrollbar_block_length);
          }
          else {                                                                // between top and bottom
            u8g.drawBox(_LCDML_u8g_lcd_w - (_LCDML_u8g_scrollbar_w - 1), (scrollbar_block_length * LCDML.getCursorPosAbs() + 1), (_LCDML_u8g_scrollbar_w - 2)  , scrollbar_block_length);
          }
        }
      } while ( u8g.nextPage() );
    }
  
    // reinit some vars
    LCDML_DISP_update_end();
  }
  
  // lcd clear
  void LCDML_lcd_menu_clear()
  {
  }
  
  /* ===================================================================== *
   *                                                                       *
     DISPLAY SYSTEM
   *                                                                       *
     =====================================================================
     every "disp menu function" needs three functions
     - void LCDML_DISP_setup(func_name)
     - void LCDML_DISP_loop(func_name)
     - void LCDML_DISP_loop_end(func_name)
  
     EXAMPLE CODE:
      void LCDML_DISP_setup(..menu_func_name..)
      {
        // setup
        // is called only if it is started
  
        // starts a trigger event for the loop function every 100 millisecounds
        LCDML_DISP_triggerMenu(100);
      }
  
      void LCDML_DISP_loop(..menu_func_name..)
      {
        // loop
        // is called when it is triggert
        // - with LCDML_DISP_triggerMenu( millisecounds )
        // - with every button status change
  
        // check if any button is presed (enter, up, down, left, right)
        if(LCDML_BUTTON_checkAny()) {
          LCDML_DISP_funcend();
        }
      }
  
      void LCDML_DISP_loop_end(..menu_func_name..)
      {
        // loop end
        // this functions is ever called when a DISP function is quit
        // you can here reset some global vars or do nothing
      }
     =====================================================================
  */
  #define DOG_CHAR_WIDTH         6
  #define DOG_CHAR_HEIGHT        12
  //const unsigned char logo_l[512] PROGMEM = {0x0, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xf8, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x70, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x1, 0xc0, 0x0, 0x0, 0x1, 0xc0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x87, 0x80, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3, 0xf, 0xc0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x2, 0xf, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x6, 0xf, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x20, 0xc, 0x7, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x8, 0x3, 0xc0, 0x0, 0xf0, 0x0, 0x0, 0x10, 0x18, 0x1, 0xc0, 0xf, 0xfe, 0x0, 0x0, 0x18, 0x10, 0x1, 0xff, 0xfc, 0x7, 0x0, 0x0, 0x8, 0x30, 0x3, 0xc1, 0xc0, 0x1, 0xc0, 0x0, 0xc, 0x30, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x80, 0xc, 0x20, 0x1, 0xff, 0xc0, 0x0, 0x1f, 0xfe, 0x4, 0x60, 0x0, 0xe3, 0xfc, 0x0, 0xc, 0x27, 0x6, 0x40, 0x0, 0xe0, 0x3f, 0x80, 0x2, 0x3, 0x6, 0x40, 0x0, 0xf0, 0x1f, 0x0, 0x0, 0x1, 0x2, 0xc0, 0x0, 0xf0, 0x1f, 0x18, 0x0, 0x1, 0x3, 0xc0, 0x0, 0xf0, 0x1f, 0x21, 0x8, 0x21, 0x83, 0xc0, 0x0, 0xf0, 0x1f, 0x21, 0x49, 0x28, 0x83, 0x80, 0x0, 0x78, 0x3f, 0x21, 0x49, 0x38, 0xc1, 0x80, 0x0, 0x78, 0x3f, 0x21, 0x4f, 0x30, 0x41, 0x80, 0x0, 0x78, 0x3f, 0x21, 0x49, 0x30, 0x61, 0x80, 0x0, 0x78, 0x1f, 0x29, 0x4a, 0x68, 0x21, 0x80, 0x0, 0x78, 0x1f, 0x39, 0xca, 0x6c, 0x21, 0x80, 0x0, 0x38, 0x1f, 0x10, 0x8a, 0x44, 0x21, 0x80, 0x0, 0x3c, 0x1f, 0x0, 0x0, 0x0, 0x21, 0x80, 0x0, 0x3c, 0x1f, 0x0, 0x0, 0x0, 0x21, 0x80, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x21, 0xc0, 0x0, 0x33, 0xff, 0xfe, 0x0, 0x0, 0x21, 0xc0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x0, 0x23, 0x40, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x63, 0x40, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x60, 0x0, 0x1e, 0x7f, 0xff, 0xff, 0xff, 0xc2, 0x20, 0x0, 0xe, 0x1f, 0xff, 0xff, 0xff, 0x86, 0x20, 0x0, 0xf, 0x7, 0xff, 0xff, 0xfc, 0x4, 0x30, 0x0, 0xf, 0x0, 0xff, 0xff, 0xf0, 0xc, 0x10, 0x0, 0xf, 0x0, 0x0, 0x0, 0x0, 0x8, 0x18, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x18, 0x8, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x10, 0xc, 0x0, 0x7, 0x80, 0x0, 0x0, 0x0, 0x30, 0x6, 0x0, 0x7, 0x80, 0x0, 0x0, 0x0, 0x20, 0x2, 0x0, 0x7, 0x80, 0x0, 0x0, 0x0, 0x60, 0x3, 0x0, 0x3, 0x80, 0x0, 0x0, 0x0, 0xc0, 0x1, 0x80, 0x3, 0xc0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x80, 0x3, 0xc0, 0x0, 0x0, 0x3, 0x0, 0x0, 0xc0, 0x3, 0xc0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x60, 0x3, 0xc0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x38, 0x3, 0xc0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0xc, 0x1, 0xc0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x7, 0x1, 0xc0, 0x0, 0x0, 0xe0, 0x0, 0x0, 0x1, 0xc1, 0xe0, 0x0, 0x3, 0x80, 0x0, 0x0, 0x0, 0x71, 0xe0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x3c, 0xe0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x7, 0xe0, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0};
  const unsigned char logo_s[128] PROGMEM = {0x0, 0x1f, 0xf0, 0x0, 0x0, 0xf0, 0x1c, 0x0, 0x3, 0x80, 0x3, 0x0, 0x6, 0x0, 0x1, 0x80, 0x8, 0x0, 0x0, 0xc0, 0x13, 0x80, 0x0, 0x20, 0x37, 0x80, 0x0, 0x30, 0x23, 0x83, 0xc0, 0x10, 0x63, 0xfe, 0x60, 0x18, 0x43, 0x0, 0x1f, 0x88, 0xc1, 0xfc, 0xd, 0xc8, 0x81, 0xce, 0x0, 0x2c, 0x81, 0xce, 0x0, 0x24, 0x81, 0xce, 0x0, 0x34, 0x80, 0xce, 0x0, 0x14, 0x80, 0xce, 0x0, 0x14, 0x80, 0xfe, 0x0, 0x14, 0x80, 0xff, 0xe0, 0x14, 0x80, 0x7f, 0xff, 0x34, 0xc0, 0x7f, 0xff, 0xfc, 0x40, 0x67, 0xff, 0xc8, 0x60, 0x70, 0x0, 0x18, 0x20, 0x70, 0x0, 0x10, 0x30, 0x30, 0x0, 0x30, 0x18, 0x30, 0x0, 0x60, 0x8, 0x38, 0x0, 0x40, 0x6, 0x38, 0x1, 0x80, 0x3, 0xb8, 0x7, 0x0, 0x0, 0xf8, 0x1c, 0x0, 0x0, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
  const unsigned char logo_r[128] PROGMEM = {0x0, 0x3, 0x0, 0x0, 0x0, 0xf, 0xc0, 0x0, 0x0, 0x1f, 0xe0, 0x0, 0x0, 0x3c, 0xf0, 0x0, 0x0, 0x38, 0x70, 0x0, 0x0, 0x78, 0x38, 0x0, 0x0, 0xf0, 0x38, 0x0, 0x0, 0xe0, 0x1d, 0x0, 0x1, 0xe0, 0x1f, 0x0, 0x1, 0xc0, 0x1e, 0x0, 0x3, 0xc0, 0x3e, 0x0, 0x3, 0x80, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1e, 0x0, 0x3, 0xc0, 0x3e, 0x0, 0x1, 0xc0, 0x1e, 0x0, 0x1, 0xe0, 0x1f, 0x0, 0x0, 0xe0, 0x3c, 0x0, 0x0, 0xf0, 0x38, 0x0, 0x0, 0x70, 0x70, 0x0, 0x0, 0x38, 0xf0, 0x0, 0x0, 0x3c, 0xe0, 0x0, 0x0, 0x1c, 0xe0, 0x0, 0x0, 0x1c, 0xe0, 0x0, 0x20, 0x1c, 0xf0, 0x0, 0x60, 0x3c, 0x7f, 0xfe, 0xff, 0xf8, 0x3f, 0xfe, 0xff, 0xf0, 0xf, 0xfe, 0x7f, 0xc0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_back)
  // *********************************************************************
  {}
  
  void LCDML_DISP_loop(LCDML_FUNC_back)
  {
    LCDML.goBack();
    LCDML_DISP_funcend();
  }
  
  void LCDML_DISP_loop_end(LCDML_FUNC_back)
  {}
  
  
  
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_panel)
  // *********************************************************************
  {
    panelLCD();
    LCDML_DISP_triggerMenu(500);
  }
  
  void LCDML_DISP_loop(LCDML_FUNC_panel)
  {
    panelLCD();
    if (LCDML_BUTTON_checkEnter()) {
      LCDML.goRoot();
      LCDML_DISP_funcend(); 
    }
  }
  
  void LCDML_DISP_loop_end(LCDML_FUNC_panel)
  {}
  
  
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_profile)
  // *********************************************************************
  {}
  
  void LCDML_DISP_loop(LCDML_FUNC_profile)
  {
    int plastic_id = LCDML_DISP_getParameter();
    for (int i = 0; i < 2; i++) {
      if (now_save) {
        targetTempHeater[plastic_id][i] = PIDSetpoint[i];
      } else {
        setFan(LOW);
        PIDSetpoint[i] = targetTempHeater[plastic_id][i];
        if (PIDSetpoint[i] > 0)
          PIDHeater[i].SetMode(AUTOMATIC);
        else
          PIDHeater[i].SetMode(MANUAL);
      }
    }
  
    now_save = false;  
    logoLCD(plastic_id);
    LCDML_DISP_jumpToFunc(LCDML_FUNC_panel);
    LCDML_DISP_funcend();
  }
  
  void LCDML_DISP_loop_end(LCDML_FUNC_profile)
  {}
  
  
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_back_profile)
  // *********************************************************************
  {
    if (now_save) {
      LCDML.jumpByElement(14);
    } else {
      LCDML.goBack();
    }
    now_save = false;
    LCDML_DISP_funcend();
  }
  
  void LCDML_DISP_loop(LCDML_FUNC_back_profile)
  {}
  
  void LCDML_DISP_loop_end(LCDML_FUNC_back_profile)
  {}
  
  
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_save_profile)
  // *********************************************************************
  {
    now_save = true;
    LCDML.jumpToElement(5);
    LCDML_DISP_funcend();
  }
  
  void LCDML_DISP_loop(LCDML_FUNC_save_profile)
  {}
  
  void LCDML_DISP_loop_end(LCDML_FUNC_save_profile)
  {}
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_cooldown)
  // *********************************************************************
  {}
  
  void LCDML_DISP_loop(LCDML_FUNC_cooldown)
  {
    // loop
    // is called when it is triggert
    offHeater();
    setFan(HIGH);
    statusLCD(F(STATUS_READY));
    logoLCD(-1);
    LCDML_DISP_jumpToFunc(LCDML_FUNC_panel); //panel
    LCDML_DISP_funcend();      // LCDML_DISP_funcend calls the loop_end function
  }
  
  void LCDML_DISP_loop_end(LCDML_FUNC_cooldown)
  {}
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_back_panel)
  // *********************************************************************
  {}
  
  void LCDML_DISP_loop(LCDML_FUNC_back_panel)
  {
    // loop
    // is called when it is triggert
    LCDML_DISP_resetIsTimer(); // reset the initscreen timer
    LCDML_DISP_jumpToFunc(LCDML_FUNC_panel); //panel
    LCDML_DISP_funcend();      // LCDML_DISP_funcend calls the loop_end function
  }
  
  void LCDML_DISP_loop_end(LCDML_FUNC_back_panel)
  {}
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_program_change)
  // *********************************************************************
  {
    uint8_t param = LCDML_DISP_getParameter();
    switch (param)
    {
      case 0:   // enable program
        LCDML_DISP_groupDisable(_LCDML_G3); // disable group 3
        LCDML_DISP_groupEnable(_LCDML_G4); // enable group 4
        break;
  
      case 1:
        LCDML_DISP_groupEnable(_LCDML_G3); // enable group 3
        LCDML_DISP_groupDisable(_LCDML_G4); // disable group 4
        break;
  
      default:
        //get parameter errors
        break;
    }
    LCDML.goRoot(); // go to root element (first element of this menu with id=0)
  }
  
  void LCDML_DISP_loop(LCDML_FUNC_program_change)
  {}
  
  void LCDML_DISP_loop_end(LCDML_FUNC_program_change)
  {}
  
  /*
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_information)
  // *********************************************************************
  {
    u8g.setFont(u8g_font_6x13);
    u8g.firstPage();
    do {
      u8g.drawBitmapP(0, 0, 64 / 8, 64, logo_l);
      u8g.setFont(u8g_font_helvR08);
      u8g.setFontPosTop();
      u8g.drawStr(68, 10, F("PreciousPID"));
      u8g.drawStr(103, 20, F("V1.0"));
      u8g.drawStr(88, 50, F("by Shek"));
    } while ( u8g.nextPage() );
  }
  
  void LCDML_DISP_loop(LCDML_FUNC_information)
  {
    if (LCDML_BUTTON_checkEnter())
      LCDML_DISP_funcend();
  }
  
  void LCDML_DISP_loop_end(LCDML_FUNC_information)
  {}
  */
  
  int currTemp;
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_temp)
  // *******************************************************************
  {
    int idxHeater = LCDML_DISP_getParameter();
    currTemp = (int) PIDSetpoint[idxHeater];
    tempLCD(idxHeater,currTemp);
  }
  
  void LCDML_DISP_loop(LCDML_FUNC_temp)
  {
    int idxHeater = LCDML_DISP_getParameter();
    
    if (LCDML_BUTTON_checkAny()) // check if any button is pressed (enter, up, down, left, right)
    {
      if (LCDML_BUTTON_checkDown() || LCDML_BUTTON_checkUp())
      {
        if (LCDML_BUTTON_checkDown() && currTemp < HEATER_MAX_TEMP) {
          currTemp++;
          LCDML_BUTTON_resetDown();
        } else if (LCDML_BUTTON_checkUp() && currTemp > 0) {
          currTemp--;
          LCDML_BUTTON_resetUp();
        }
        tempLCD(idxHeater,currTemp);
      } else if (LCDML_BUTTON_checkEnter()) {
          LCDML_DISP_funcend();
      }
    }
  
    if (LCDML_BUTTON_checkEnter()) {
      LCDML_DISP_funcend();
    }
  }
  
  void LCDML_DISP_loop_end(LCDML_FUNC_temp)
  {
    int idxHeater = LCDML_DISP_getParameter();
    if (currTemp>=0 && currTemp<=HEATER_MAX_TEMP) 
      setHeaterTemp(idxHeater,currTemp);
  }
  
  // PIDKp, PIDKi, PIDKd are decoupled from the object PIDHeater. No need to create dummy var as in currTemp for Manual Heating
  // currPos for location of cursor
  unsigned char currPos;
  unsigned char selPos;
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_PID_setting)
  // *******************************************************************
  {
    int idxHeater = LCDML_DISP_getParameter();
    currPos=1; // 1 as in FONT_HEIGHT*1
    selPos=0;
    PIDLCD(idxHeater,currPos,selPos);
  }
  
  void LCDML_DISP_loop(LCDML_FUNC_PID_setting)
  {
    int idxHeater = LCDML_DISP_getParameter();
  
    if (selPos==0) {
      if (LCDML_BUTTON_checkDown() && currPos < 5) {
        currPos++;
        LCDML_BUTTON_resetDown();
      } else if (LCDML_BUTTON_checkUp() && currPos > 1) {
        currPos--;
        LCDML_BUTTON_resetUp();
      } else if (LCDML_BUTTON_checkEnter()) {
        LCDML_BUTTON_resetEnter();
        if (currPos == 1) {
            LCDML_DISP_funcend();
        } else if (currPos == 5){
            selPos=0;
            LCDML_DISP_jumpToFunc(LCDML_FUNC_panel); //panel
            AT(250, idxHeater, 3, true);
            LCDML_DISP_funcend();
        } else {
            selPos=currPos;
        }
      }
    } else {
      char increment=0;
      if (LCDML_BUTTON_checkDown()) {
        increment = +1;
        LCDML_BUTTON_resetDown();
      } else if (LCDML_BUTTON_checkUp()) {
        increment = -1;
        LCDML_BUTTON_resetUp();
      }
      switch (selPos) {
        case 2: PIDKp[idxHeater]+=0.5*increment; break;
        case 3: PIDKi[idxHeater]+=0.5*increment; break;
        case 4: PIDKd[idxHeater]+=0.5*increment; break;
      }
      if (LCDML_BUTTON_checkEnter()) {
        LCDML_BUTTON_resetEnter();
        selPos=0;
      }
    }
    
    PIDLCD(idxHeater,currPos,selPos);
  }
  
  void LCDML_DISP_loop_end(LCDML_FUNC_PID_setting)
  {
    int idxHeater = LCDML_DISP_getParameter();
    PIDHeater[idxHeater].SetTunings(PIDKp[idxHeater],PIDKi[idxHeater],PIDKd[idxHeater]);
    printPIDSetting(idxHeater);
  }
  
  // *********************************************************************
  void LCDML_DISP_setup(LCDML_FUNC_manage_setting)
  // *******************************************************************
  {
    int func = LCDML_DISP_getParameter();
    switch (func) {
      case 0:
        writeEEPROMSetting();
        break;
      case 1:
        readEEPROMSetting(false);
        break;
      case 2:
        getDefaultSetting();
        break;
    }
    for (int i=0;i<2;i++)
      printPIDSetting(i);
    LCDML_DISP_jumpToFunc(LCDML_FUNC_panel);
    LCDML_DISP_funcend();
  }
  
  void LCDML_DISP_loop(LCDML_FUNC_manage_setting)
  {}
  
  void LCDML_DISP_loop_end(LCDML_FUNC_manage_setting)
  {}
  
  void panelLCD() {
    #define FONT_WIDTH  6
    #define FONT_HEIGHT 13
    u8g.firstPage();
    do {
      u8g.setFont(u8g_font_6x13);
      if (now_logo < 0) {
        u8g.drawBitmapP(0, 0, 32 / 8, 32, logo_s);
      } else {
        u8g.drawBitmapP(0, 0, 32 / 8, 32, logo_r);
        char *logo_no;
        itoa((int)now_logo+1,logo_no,10);
        u8g.drawStr   (   (32 - FONT_WIDTH - 2) / 2, 32/2 + 3, logo_no);
        switch (now_logo) {
          case PLASTIC_ID_PET:
            statusLCD(F("PET"));
            break;
          case PLASTIC_ID_HDPE:
            statusLCD(F("HDPE"));
            break;
          case PLASTIC_ID_V:
            statusLCD(F("V"));
            break;
          case PLASTIC_ID_LDPE:
            statusLCD(F("LDPE"));
            break;
          case PLASTIC_ID_PP:
            statusLCD(F("PP"));
            break;
          case PLASTIC_ID_PS:
            statusLCD(F("PS"));
            break;
          default:
            statusLCD(F("PLA"));
            break;
        }
      }
      u8g.drawStr   (   32, FONT_HEIGHT * 1, F(STATUS_TITLE));
      u8g.drawStr   (   32, FONT_HEIGHT * 2, now_status);
      
      char buf[20];
      for (int i = 0; i < 2; i++) {
        sprintf (buf, "T%d %3d/%d", i, (int) PIDInput[i], (int) PIDSetpoint[i]); //T:123/456 (total 9 char)
        u8g.drawStr   (    0, FONT_HEIGHT * (i + 1) - 4 + 32 + 4, buf);
        u8g.drawStr   ( 11 * 6, FONT_HEIGHT * (i + 1) - 4 + 32 + 4, F("P"));
        u8g.drawFrame ( FONT_WIDTH * 13 + 2, FONT_HEIGHT * i + 32 + 4,  128 - FONT_WIDTH * 13 - 2,                                          FONT_HEIGHT - 4);
        u8g.drawBox   ( FONT_WIDTH * 13 + 2, FONT_HEIGHT * i + 32 + 4,  ((128 - FONT_WIDTH * 13 - 2)*PIDOutput[i]) / SOFT_PWM_WINDOW_SIZE,  FONT_HEIGHT - 4);
      }
    } while ( u8g.nextPage() );
  }
  
  void tempLCD(int idxHeater, int currTemp) {
    char buf[17];
    sprintf_P(buf, PSTR(MENU_SET_TEMP) , idxHeater, currTemp);
  
    u8g.setFont(u8g_font_6x13);
    u8g.firstPage();
    do {
      u8g.drawStr( 0, 32 + (_LCDML_u8g_font_h >> 2), buf);
    } while ( u8g.nextPage() );
  }
  
  void PIDvalLCD(double val, char line, const __FlashStringHelper * pidchar) {
    char valbuf[6], len;
    ftoa(valbuf,val,2);
    u8g.drawStr( 34+_LCDML_u8g_font_w*(6-strlen(valbuf)), _LCDML_u8g_font_h*line-2, valbuf);
    u8g.drawStr( 10, _LCDML_u8g_font_h*line-2, F("K :"));
    u8g.drawStr( 16, _LCDML_u8g_font_h*line-2, pidchar);
  }
  
  void PIDLCD(int idxHeater, unsigned char pos, unsigned char sel) {  
    u8g.setFont(u8g_font_6x13);
    u8g.firstPage();
    do {
      u8g.drawStr( 10, _LCDML_u8g_font_h-2, F("Back"));
  
      PIDvalLCD(PIDKp[idxHeater],2,F("p"));
      PIDvalLCD(PIDKi[idxHeater],3,F("i"));
      PIDvalLCD(PIDKd[idxHeater],4,F("d"));
      
      u8g.drawStr( 10, _LCDML_u8g_font_h*5-2, F("Auto Tune"));
      u8g.drawStr( 0, _LCDML_u8g_font_h*pos-2, F(">"));
    } while ( u8g.nextPage() );
  }
  
  extern void logoLCD(char setlogo) {
    now_logo = setlogo;
  }
  
  extern void statusLCD(char *statusLCD) {
    strcpy(now_status, statusLCD);
  }
  
  extern void statusLCD(const __FlashStringHelper *statusLCD) {
    strcpy_P(now_status, reinterpret_cast<PGM_P>(statusLCD) );
  }

#endif
