//for LCD
#define RS 12
#define EN 11
#define D4 10
#define D5 9
#define D6 8
#define D7 7

//for NEC decoding
volatile char text[5];
volatile boolean nec_ok = 0;
volatile byte i, nec_state = 0, command, inv_command , address ;
volatile unsigned long nec_code; //32bit 


// ============= External interrupt ===========
void detectInterrupt(int mode) {

  EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
  EIMSK |= (1 << INT0);

}

void endInterrupt() {

  EIMSK &= ~(1 << INT0);
}
// ==============================================



// ============== LCD function ==============
void pulseEnable() {
  digitalWrite(EN, HIGH);
  delayMicroseconds(1);
  digitalWrite(EN, LOW);
  delayMicroseconds(50);
}

void sendCommand(byte cmd) {
  digitalWrite(RS, LOW);
  digitalWrite(D4, (cmd >> 4) & 1);
  digitalWrite(D5, (cmd >> 5) & 1);
  digitalWrite(D6, (cmd >> 6) & 1);
  digitalWrite(D7, (cmd >> 7) & 1);
  pulseEnable();

  digitalWrite(D4, cmd & 1);
  digitalWrite(D5, (cmd >> 1) & 1);
  digitalWrite(D6, (cmd >> 2) & 1);
  digitalWrite(D7, (cmd >> 3) & 1);
  pulseEnable();
}

void sendData(byte data) {
  digitalWrite(RS, HIGH);
  digitalWrite(D4, (data >> 4) & 1);
  digitalWrite(D5, (data >> 5) & 1);
  digitalWrite(D6, (data >> 6) & 1);
  digitalWrite(D7, (data >> 7) & 1);
  pulseEnable();

  digitalWrite(D4, data & 1);
  digitalWrite(D5, (data >> 1) & 1);
  digitalWrite(D6, (data >> 2) & 1);
  digitalWrite(D7, (data >> 3) & 1);
  pulseEnable();
}

void printText(const char* text, int row, int col) {
  int position = col + (row == 1 ? 0x40 : 0x00);
  sendCommand(0x80 | position); // Set DDRAM address
  for (int i = 0; text[i] != '\0'; ++i) {
    sendData(text[i]);
  }
}

void commandConvert(int command){
  switch(command){
    case 80:
      Serial.println(command);
      printText("Input",1, 9);
      return;
    case 208:
      Serial.println(command);
      printText("Power ",1, 9);
      return;
    case 48:
      Serial.println(command);
      printText("Menu ",1, 9);
      return;
    case 112:
      Serial.println(command);
      printText("ESC  ",1, 9);
      return;
    case 180:
      Serial.println(command);
      printText("KST- ",1, 9);
      return;
    case 84: 
      Serial.println(command);
      printText("KST+ ",1, 9);
      return;
    case 52: 
      Serial.println(command);
      printText("VOL+ ",1, 9);
      return;
    case 244: 
      Serial.println(command);
      printText("VOL- ",1, 9);
      return;
    case 212: 
      Serial.println(command);
      printText("ZOOM+",1, 9);
      return;
    case 116: 
      Serial.println(command);
      printText("ZOOM-",1, 9);
      return;
  }
  return;
}
// ===============================================

void setup() {
  Serial.begin(9600);
  pinMode(RS, OUTPUT);
  pinMode(EN, OUTPUT);
  pinMode(D4, OUTPUT);
  pinMode(D5, OUTPUT);
  pinMode(D6, OUTPUT);
  pinMode(D7, OUTPUT);

  sendCommand(0x33);
  sendCommand(0x32);
  sendCommand(0x28);
  sendCommand(0x0C);
  sendCommand(0x06);
  sendCommand(0x01);
  delay(500);
  printText("Group 2 ",0, 0);
  printText("Hello Mr Hung",1,0);

  // Timer1 config
  TCCR1A = 0;
  TCCR1B = 0;                 // Disable Timer1 module
  TCNT1 = 0;                  // Set Timer1 preload value to 0 
  TIMSK1 = 1;                 // Enable Timer1 overflow interrupt
  
  detectInterrupt(CHANGE); 

}

void remote_read() {
  unsigned int timer_value;
  if(nec_state != 0){
    timer_value = TCNT1;                         // Store Timer1 value
    TCNT1 = 0;                                   // Reset Timer1
  }

  switch(nec_state){
   case 0 :                                      // Start receiving IR (9ms pulse)
    TCNT1  = 0;                                  // Reset Timer1
    TCCR1B = 2;                                  // set prescaler, start measure time 
    nec_state = 1;                               // end of 9ms pulse (start 4.5ms space)
    i = 0;
    return;

   case 1 :                                      // End of 9ms pulse
    if((timer_value > 19000) || (timer_value < 17000)){         // Invalid interval
      nec_state = 0;                             // Reset decoding process
      TCCR1B = 0;                                // Disable Timer1 module
    }
    else
      nec_state = 2;                             // end of 4.5ms space (start of 562µs pulse)
    return;

   case 2 :                                      // End of 4.5ms space
    if((timer_value > 10000) || (timer_value < 8000)){
      nec_state = 0;                             
      TCCR1B = 0;                                
    }
    else
      nec_state = 3;                             // Next state: end of 562µs pulse (start of 562µs or 1687µs space)
    return;

   case 3 :                                      // End of 562µs pulse
    if((timer_value > 1400) || (timer_value < 800)){           
      TCCR1B = 0;                                
      nec_state = 0;                             
    }
    else
      nec_state = 4;                             // Next state: end of 562µs or 1687µs space
    return;

   case 4 :                                      // End of 562µs or 1687µs space
    if((timer_value > 3600) || (timer_value < 800)){           
      TCCR1B = 0;                                
      nec_state = 0;                             
      return;
    }

    // if received a bit successfully 
    if( timer_value > 2000)                      // long space
      nec_code |= (1UL << (31 - i));                
    else                                         // short space
      nec_code &= ~(1UL << (31 - i));
     
    i++;

    if(i > 31){                                  // If all bits are received
      nec_ok = 1;                                
      endInterrupt();                            // Disable external interrupt (INT0)
      return;
    }

    nec_state = 3;                               // Next state -> start of 562µs or 1687µs space
  }
}

ISR(TIMER1_OVF_vect) {                           
  nec_state = 0;                                 // Reset decoding process
  TCCR1B = 0;                                    // Disable Timer1 module
}

ISR(INT0_vect) { 
  remote_read(); 
}


void loop() {
  if(nec_ok){                                   // mcu receives NEC message successfully
    nec_ok = 0;                                  // Reset decoding process
    nec_state = 0;
    TCCR1B = 0;                                  // Disable Timer1 
    address = nec_code >> 24;
    command = nec_code >> 8;
    inv_command = nec_code;

    printText("Address:",0,0);
    printText("Command:",1,0);

    sprintf(text, "%02X", address);
    printText("0x",0,9);
    printText(text,0,11);   

    sprintf(text, "%02X", command);
    Serial.println(command);
    commandConvert(command);
    
    detectInterrupt(CHANGE); 
  }
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
lcd:VSS
lcd:VDD
lcd:V0
lcd:RS
lcd:RW
lcd:E
lcd:D0
lcd:D1
lcd:D2
lcd:D3
lcd:D4
lcd:D5
lcd:D6
lcd:D7
lcd:A
lcd:K
r1:1
r1:2
ir1:GND
ir1:VCC
ir1:DAT