// MENU CODE =(20*4 I2C LCD) + (4/4 KEYPAD) + (4N-PUSH BTNS) + (IR REMOTE) + (CLOCK) + (TEMP/HMD) + (VOICE)

#include "CMBMenu.hpp"  // include CMBMenu

#include <Wire.h>  // include I2C MODULE

#include <LiquidCrystal_I2C.h>  // include LCD

#include <IRremote.h>  // include IR

#include <Keypad.h>    // include Keypad

// Set up pins for pushButtons
const char STATUS_LED_RED_OP = 2;
const char STATUS_LED_BLUE_OP = 3;
const char STATUS_LED_GREEN_OP = 4;

// Set up pins for pushButtons
const char Right_Button = 5;
const char Left_Button = 6; 
const char Enter_Button = 7;
const char Exit_Button = 8;

# define PIN_RECEIVER 9

IRrecv receiver(PIN_RECEIVER);

bool pressed = false;

char keypressed; // Character to hold key input

char IRKey; // Character to hold key input
 
// Constants for row and column sizes
const byte ROWS = 4;
const byte COLS = 4;

// Array to represent keys on keypad
char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

// Connections to Arduino
byte rowPins[ROWS] = {A7, A6, A5, A4};
byte colPins[COLS] = {A3, A2, A1, A0};
 
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); // Create keypad object

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

/************************************************************************************************************/
//                                      MENU LAYERS & DISPLAY TEXT
/************************************************************************************************************/

// define text to display
const char g_MenuA_pc[] PROGMEM = {"   1.SOUND SENSOR"}; //1
const char g_MenuA_a1_pc[] PROGMEM = {" 1.1 CURRENT STATUS"}; //1.1
const char g_MenuA_b1_pc[] PROGMEM = {"1.2 PREVIOUS STATUS"}; //1.2
const char g_MenuA_c1_pc[] PROGMEM = {"1.3 CHECK TEMPERTURE"};//1.3
const char g_MenuA_d1_pc[] PROGMEM = {" 1.4 CHECK HUMIDITY"};//1.4


const char g_MenuB_pc[] PROGMEM = {"   2.LIGHT SENSOR"};//2
const char g_MenuB_a1_pc[] PROGMEM = {" 2.1 B_a1"};//2.1
const char g_MenuB_b1_pc[] PROGMEM = {"  2.2 GENERAL MODE"};//2.2
const char g_MenuB_c1_pc[] PROGMEM = {"  DEACTIVATE ADMIN"};//2.3


const char g_MenuC_pc[] PROGMEM = {"  3.REMOTE CONTROL"};//3
const char g_MenuC_a1_pc[] PROGMEM = {"3.1 INTIALIZE PANEL"};//3.1
const char g_MenuC_b1_pc[] PROGMEM = {"3.2 PREVIOUS VALUES"};//3.2

const char g_MenuD_pc[] PROGMEM = {"   4.TIMER SENSOR"};//3

const char g_MenuE_pc[] PROGMEM = {"5.WATER LEVEL SENSOR"};//3


// define function IDs
enum MenuFID {
  MenuDummy,
  MenuA,
  MenuA_a1,
  MenuA_b1,
  MenuA_c1,
  MenuA_d1,
  MenuB,
  MenuB_a1,
  MenuB_b1,
  MenuB_c1,
  MenuC,
  MenuC_a1,
  MenuC_b1,
  MenuD,
  MenuE,
};

// define key types
enum KeyType {
  KeyNone, // no key is pressed
  KeyLeft,
  KeyRight,
  KeyEnter,
  KeyExit
};

// ** menu **
// create global CMBMenu instance
// (here for maximum 100 menu entries)
CMBMenu<100> g_Menu;

/************************************************************************************************************/
//                                   CREATE CUSTOM CHARECTERS FOR MENU
/************************************************************************************************************/

byte customChar1[8] = {
  0b00000,
  0b01000,
  0b01100,
  0b01110,
  0b01111,
  0b01110,
  0b01100,
  0b01000
};

byte customChar2[8] = {
  0b00000,
  0b00010,
  0b00110,
  0b01110,
  0b11110,
  0b01110,
  0b00110,
  0b00010
};

byte customChar3[8] = {
  0b00000,
  0b00100,
  0b01110,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000
};

byte customChar4[8] = {
  0b00111,
  0b00001,
  0b00001,
  0b00101,
  0b01101,
  0b11111,
  0b01100,
  0b00100
};

/************************************************************************************************************/
//                                     CREATE CUSTOM CHARECTERS FOR DS3231
/************************************************************************************************************/
byte customChar5[8] = {
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
  B00100
};  

byte customChar6[8] = {
  0b00100,
  0b00100,
  0b00100,
  0b11111,
  0b00100,
  0b00100,
  0b00100,
  0b00100
};

const unsigned long eventInterval = 2000;

unsigned long previousTime = 0;

/************************************************************************************************************/
//                                           MAIN setup & PINMODES
/************************************************************************************************************/
void setup()
{   
  // Set up pinmode
  pinMode(Left_Button, INPUT_PULLUP);
  pinMode(Right_Button, INPUT_PULLUP);
  pinMode(Enter_Button, INPUT_PULLUP);
  pinMode(Exit_Button, INPUT_PULLUP);

  pinMode(STATUS_LED_RED_OP, OUTPUT);
  pinMode(STATUS_LED_GREEN_OP, OUTPUT);
  pinMode(STATUS_LED_BLUE_OP, OUTPUT);



  receiver.enableIRIn(); // Start the receiver

  Serial.begin(9600);
  lcd.begin(20,4);
      
      lcd.clear();     
      lcd.setCursor(6,0);
      lcd.print("WELCOME");
      lcd.setCursor(3,2);
      lcd.print("INSPIRE INDIA");
      lcd.setCursor(5,3);
      lcd.print("INSTITUTE");
      delay(1500);
      lcd.clear();
      lcd.setCursor(2,1);
      lcd.print("INDUSTRIAL PSLC");
      lcd.setCursor(1,2);
      lcd.print("ECG - PSR KV 910R");
      delay(2500);
      lcd.clear();
      lcd.setCursor(6,0);
      lcd.print("WELCOME");
      lcd.setCursor(4,2);
      lcd.print("SYSTEM READY");
      delay(1000);
  
  lcd.createChar(1, customChar1); 
  lcd.createChar(2, customChar2); 
  lcd.createChar(3, customChar3); 
  lcd.createChar(4, customChar4); 

  lcd.createChar(5, customChar5);
  lcd.createChar(6, customChar6);

  Serial.println("===========================");    
  Serial.println("INDUSTRIAL PSLC - PSR KV910 R");
  Serial.println("===========================");
  Serial.println("PSLC-AUTH SEGMENT CODE");
  Serial.println("===========================");
  Serial.println("Programmer: TEEGLA NARENDRA");
  Serial.println("===========================");
  Serial.println("Cheif PROGRAMMER @ INSPRE INDIA INSTITUTE");
  Serial.println("===========================");
  Serial.println("function Designer: TEEGALA YASHODA");
  Serial.println("===========================");
  Serial.println("CORRESPONDENT @ INSPRE INDIA INSTITUTE");
  Serial.println("===========================");


  // ** MENU LAYERS**
  // add nodes to menu (layer, string, function ID)
  g_Menu.addNode(0, g_MenuA_pc , MenuA);
  g_Menu.addNode(1, g_MenuA_a1_pc , MenuA_a1);
  g_Menu.addNode(1, g_MenuA_b1_pc , MenuA_b1);
  g_Menu.addNode(1, g_MenuA_c1_pc, MenuA_c1);
  g_Menu.addNode(1, g_MenuA_d1_pc, MenuA_d1);

  
  g_Menu.addNode(0, g_MenuB_pc , MenuB);
  g_Menu.addNode(1, g_MenuB_a1_pc, MenuB_a1);
  g_Menu.addNode(1, g_MenuB_b1_pc, MenuB_b1);
  g_Menu.addNode(1, g_MenuB_c1_pc, MenuB_c1);

  g_Menu.addNode(0, g_MenuC_pc, MenuC);
  g_Menu.addNode(1, g_MenuC_a1_pc, MenuC_a1);
  g_Menu.addNode(1, g_MenuC_b1_pc, MenuC_b1);

  g_Menu.addNode(0, g_MenuD_pc, MenuD);

  g_Menu.addNode(0, g_MenuE_pc, MenuE);


  // *****MENU*****
  // build menu and print menu
  // (see terminal for output)
  const char* info;
  g_Menu.buildMenu(info);
  g_Menu.printMenu();

  // ** menu **
  // print current menu entry
    printMenuEntry(info);

   blinkLedY();
   delay(100); 
   blinkLedY(); 

}

/************************************************************************************************************/
//                                             MAIN LOOP
/************************************************************************************************************/
void loop()
{ 
/************************************************************************************************************/
//                                    CURRENTSTATE - BOOL DECLARATION
/************************************************************************************************************/
     
     

/*************************************************************************************************************/
//                                   MENU CASE'S & NAVIGATION KEY        
/************************************************************************************************************/ 

  // function ID
  int fid = 0;

  // info text from menu
  const char* info;

  // go to deeper or upper layer?
  bool layerChanged=false;

  // determine pressed key
  KeyType key = getKey();

  // ** menu **
  // call menu methods regarding pressed key
  switch(key) {
    case KeyExit:     
      g_Menu.exit();
      break;
    case KeyEnter:
      g_Menu.enter(layerChanged);
      break;
    case KeyRight:
      g_Menu.right();
      break;
    case KeyLeft:
      g_Menu.left();
      break;
    default:
      break;
  }

  // ** menu **
  // pint/update menu when key was pressed
  // and get current function ID "fid"
  if (KeyNone != key) {
    fid = g_Menu.getInfo(info);
    printMenuEntry(info);
  }

  // ** menu **
  // do action regarding function ID "fid"
  if ((0 != fid) && (KeyEnter == key) && (!layerChanged)) {
    switch (fid) {
      case MenuA_a1:
        A_a1();
        break;
      case MenuA_b1:
        A_b1();
        break;
      case MenuA_c1:
        A_c1();
        break;
      case MenuA_d1:
        A_d1();
        break;
      case MenuB_a1:
        B_a1();
        break;
      case MenuB_b1:
        B_b1();
        break; 
      case MenuB_c1:
        B_c1();
        break;
      case MenuC_a1:
        C_a1();
        break;
        case MenuC_b1:
        C_b1();
        break;  
      default:
        break;
   }
  }
}
/*************************************************************************************************************/
//                                            LOOP ENDS 
/*************************************************************************************************************/

/*************************************************************************************************************/
//                                    STATUS LED BLINK FUNCTION
/*************************************************************************************************************/

void blinkLedIR(){
  
               digitalWrite(STATUS_LED_GREEN_OP, HIGH);
               digitalWrite(STATUS_LED_BLUE_OP, HIGH);
               delay(100);
               digitalWrite(STATUS_LED_GREEN_OP, LOW);
               digitalWrite(STATUS_LED_BLUE_OP, LOW);
 }  

 void blinkLedKey(){
  
               digitalWrite(STATUS_LED_GREEN_OP, HIGH);
               digitalWrite(STATUS_LED_RED_OP, HIGH);
               delay(100);
               digitalWrite(STATUS_LED_GREEN_OP, LOW);
               digitalWrite(STATUS_LED_RED_OP, LOW);
 }               
/*************************************************************************************************************/
//                                    STATUS LED Y-BLINK FUNCTION
/*************************************************************************************************************/

void blinkLedY(){
  
               digitalWrite(STATUS_LED_GREEN_OP, HIGH);
               digitalWrite(STATUS_LED_RED_OP, HIGH);
               delay(100);
               digitalWrite(STATUS_LED_GREEN_OP, LOW);
               digitalWrite(STATUS_LED_RED_OP, LOW);
               delay(100);
               digitalWrite(STATUS_LED_GREEN_OP, HIGH);
               digitalWrite(STATUS_LED_RED_OP, HIGH);
               delay(100);
               digitalWrite(STATUS_LED_GREEN_OP, LOW);
               digitalWrite(STATUS_LED_RED_OP, LOW);
 }   
/*************************************************************************************************************/
//                                    STATUS LED G-BLINK FUNCTION
/*************************************************************************************************************/

void blinkLedG(){
  
               digitalWrite(STATUS_LED_GREEN_OP, HIGH);
               delay(100);
               digitalWrite(STATUS_LED_GREEN_OP, LOW);
               delay(100);
               digitalWrite(STATUS_LED_GREEN_OP, HIGH);
               delay(100);
               digitalWrite(STATUS_LED_GREEN_OP, LOW);
 }  
/*************************************************************************************************************/
//                                    STATUS LED R-BLINK FUNCTION
/*************************************************************************************************************/

void blinkLedR(){
  
               digitalWrite(STATUS_LED_RED_OP, HIGH);
               delay(100);
               digitalWrite(STATUS_LED_RED_OP, LOW);
               delay(100);
               digitalWrite(STATUS_LED_RED_OP, HIGH);
               delay(100);
               digitalWrite(STATUS_LED_RED_OP, LOW);
 }  
 
/*************************************************************************************************************/
//                                        MENU PRINT & LCD MAIN PRINT
/*************************************************************************************************************/

void printMenuEntry(const char* f_Info)
{
  String info_s;
  MBHelper::stringFromPgm(f_Info, info_s);

  // when using LCD: add/replace here code to
  // display info on LCD
  Serial.flush();
  Serial.println("----------------");
  Serial.println(info_s);
  Serial.println("----------------");

  // print on LCD
  
  lcd.clear();
  lcd.setCursor(6,0);
  lcd.print("WELCOME");
  lcd.setCursor(0,2);
  lcd.print(info_s);
  lcd.setCursor(9,3);
  lcd.write((byte)2);  // print the custom char at (3, 3)
  lcd.setCursor(12,3);
  lcd.write((byte)1);  // print the custom char at (8, 3)
  lcd.setCursor(15,3);
  lcd.write((byte)3);  // print the custom char at (13, 3)
  lcd.setCursor(18,3);
  lcd.write((byte)4);  // print the custom char at (18, 3)
  
  // you can print here additional infos into second line of LCD
  // g_Lcd.setCursor(0, 1);
  // g_Lcd.print("my text");
}


/*************************************************************************************************************/
//                                   MENU NAVIGATION KEY & IR NAVIGATION
/*************************************************************************************************************/
KeyType getKey()
{
  KeyType key = KeyNone;

  // here for demonstration: get "pressed" key from terminal
  // replace code when using push buttons 11D9609F
     bool Left_currentState = digitalRead(Left_Button);
     bool Right_currentState = digitalRead(Right_Button);
     bool Enter_currentState = digitalRead(Enter_Button);
     bool Exit_currentState = digitalRead(Exit_Button);
  
   
  if (receiver.decode()) {
          int res = receiver.decodedIRData.command; //IR value to res
   switch (res) {
            case 168:
               key = KeyEnter;
               blinkLedIR();
               Serial.println("OK");
              break;
            case 224:
               key = KeyLeft; // left
               blinkLedIR();
               Serial.println("LEFT");
              break;
            case 144:
               key = KeyRight; // Right
               blinkLedIR();
               Serial.println("RIGHT");
              break;
            case 0x11D9708F:
               key = KeyLeft; // left
               blinkLedIR();
               Serial.println("UP");
              break;
            case 0x11D950AF:
               key = KeyRight; // Right
               blinkLedIR();
               Serial.println("DOWN");
              break;  
            case 	194:
               key = KeyExit;
               blinkLedIR();
               Serial.println("Exit");
              break;
            default: 
              break;
          }
   
         receiver.resume();  // Receive the next value
      }
      
     if(Left_currentState == pressed){
  
      key = KeyLeft; // left
      blinkLedIR();
      Serial.println("<left>");
      delay(100);
      while(digitalRead(Left_Button) == pressed){  
      } 
     } 
    
     else if(Right_currentState == pressed){
  
      key = KeyRight; // Right
      blinkLedIR();
      Serial.println("<Right>");
      delay(100);
      while(digitalRead(Right_Button) == pressed){
      } 
     } 

     else if(Enter_currentState == pressed){
  
      key = KeyEnter;
      blinkLedIR();
      Serial.println("<Enter>");
      delay(100);
      while(digitalRead(Enter_Button) == pressed){
      } 
     } 

     else if(Exit_currentState == pressed){
  
      key = KeyExit;
      blinkLedIR();
      Serial.println("<Exit>");
      delay(100);
      while(digitalRead(Exit_Button) == pressed){
      } 
    } 
 return key;
}


/*************************************************************************************************************/
//                                   1.1 PANEL CURRENT STATUS FUNCTION
/*************************************************************************************************************/
void A_a1()
{
      
  
}
/*************************************************************************************************************/
//                                   1.2 PANEL PREVIOUS STATUS FUNCTION
/*************************************************************************************************************/
void A_b1()
{
     
      
}

/*************************************************************************************************************/
//                                      1.3 CHECK TEMPERTURE function
/*************************************************************************************************************/
void A_c1()
{
  
}

/*************************************************************************************************************/
//                                      1.4 CHECK HUMIDITY function
/*************************************************************************************************************/
void A_d1()
{
  
}

/*************************************************************************************************************/
//                                      2.1 B_a1 FUNCTION
/*************************************************************************************************************/
void B_a1()
{

     
}

/*************************************************************************************************************/
//                                     2.2 GENERAL MODE function
/*************************************************************************************************************/
void B_b1()
{

  
}

/*************************************************************************************************************/
//                                    2.3 DEACTIVATE ADMIN FUNCTION
/*************************************************************************************************************/
void B_c1()
{
 

}
/*************************************************************************************************************/
//                                    3.1 INTIALIZE PANEL FUNCTION
/*************************************************************************************************************/
void C_a1()
{
     

}

/*************************************************************************************************************/
//                                  3.2 LOAD PREVIOUS VALUES FUNCTION
/*************************************************************************************************************/
void C_b1()
{
      


}


// ========================================================================
// naming convention
// prefix:
//   g  : global variayle
//   f  : function/method variayle
//   m  : private member of class
//      : without prefix: public member of class
//
//
// ========================================================================