#include <EEPROM.h>
#include <IRremote.h>
#include <SPI.h>
#include <Wire.h> 
#include <stdlib.h>
#include <LiquidCrystal_I2C.h>
#include "SPI.h"
#define lenght 16.5

LiquidCrystal_I2C lcd(0x20,2,16);  // Set the LCD I2C address


const int slaveSelectPin = 10;
int RECV_PIN = 5;
IRrecv irrecv(RECV_PIN);
decode_results results;
int rotaryPinA = 3;
int rotaryPinB = 2;
long rotaryCount = 0;
long rotaryCount_balans = 1;
long lastrotaryCount = 1;
const int DataPin = 8;
const int ClkPin = 6;
const int ShiftPin = 7;
const int Shift_enablePin = A0;
int power = 9;

    int inputButton_Pin = 4;             // switch is connected to pin 2
    int monitorButton_Pin = A1;
    int haedphoneSwitch_Pin = A2;
    int val1;                        // variable for reading the pin status
    int val2;                        // variable for reading the delayed status
    int val3;                        // variable for reading the pin status
    int val4;                        // variable for reading the delayed status
    int val5;                        // variable for reading the pin status
    int val6;  
    int address_0 = 0;
    int address_1 = 1;
    int buttonState_input;// variable to hold the button state
    int buttonState_monitor;// variable to hold the button state
    int buttonState_headphone;// variable to hold the button state
    int Mode;
    int monitorSW = 0;
    int headPhoneSW = 0;
    const int PGA_CS_PIN = 10;
    const int PGA_SCLK_PIN = 13;
    const int PGA_SDI_PIN = 11;
    float volume;
    float offset;
    unsigned char b;
    unsigned int peace;
    char myStr1[10] = "    cd";
    char myStr2[10] = "    Aux";
    char myStr3[10] = "   Tuner";
    char myStr4[10] = "   Phono";
    char myStr5[10] = "Hifidelio";
    char myStr6[10] = "  MONITOR";
    
boolean mute = false;

byte p1[8]={B00000,B00000,B00000,B10000,B10000,B10000,B10000,B00000};
byte p2[8]={B00000,B00000,B00000,B11000,B11000,B11000,B11000,B00000};
byte p3[8]={B00000,B00000,B00000,B11100,B11100,B11100,B11100,B00000};
byte p4[8]={B00000,B00000,B00000,B11110,B11110,B11110,B11110,B00000};
byte p5[8]={B00000,B00000,B00000,B11111,B11111,B11111,B11111,B00000};

void setup() {
  Mode = EEPROM.read(address_0);
  rotaryCount = EEPROM.read(address_1);
  lcd.noBacklight();
  pinMode (DataPin, OUTPUT);
  digitalWrite(DataPin,LOW);
  pinMode (ClkPin, OUTPUT);
  digitalWrite(ClkPin, LOW);
  pinMode (ShiftPin, OUTPUT);
  digitalWrite (ShiftPin, LOW);
  pinMode(Shift_enablePin, OUTPUT);
  digitalWrite(Shift_enablePin, HIGH);
 
  volume = rotaryCount;
  Serial.begin(9600);
  lcd.init();
  
  lcd.begin(16, 2);
  lcd.createChar(0, p1);
  lcd.createChar(1, p2);
  lcd.createChar(2, p3);
  lcd.createChar(3, p4);
  lcd.createChar(4, p5);

  pinMode (power,OUTPUT);
  digitalWrite(power,LOW);
  pinMode(PGA_CS_PIN,OUTPUT);
  pinMode(PGA_SCLK_PIN,OUTPUT);
  pinMode(PGA_SDI_PIN,OUTPUT);
  digitalWrite(PGA_CS_PIN,LOW);
  digitalWrite(PGA_SCLK_PIN,LOW);
  digitalWrite(PGA_SDI_PIN,LOW);
  
//Button_sketch
  pinMode(inputButton_Pin, INPUT);    // Set the switch pin as input
  digitalWrite(inputButton_Pin, HIGH);
  buttonState_input = digitalRead(inputButton_Pin);
  pinMode(monitorButton_Pin, INPUT);    // Set the switch pin as input
  digitalWrite(monitorButton_Pin, HIGH);
  buttonState_monitor = digitalRead(monitorButton_Pin);
  pinMode(haedphoneSwitch_Pin, INPUT);
  digitalWrite(haedphoneSwitch_Pin, HIGH);
  buttonState_headphone = digitalRead(haedphoneSwitch_Pin);

updateShiftRegister();
  
  pinMode(rotaryPinA, INPUT);
  pinMode(rotaryPinB, INPUT);
  digitalWrite(rotaryPinA, HIGH);
  digitalWrite(rotaryPinB, HIGH); 

attachInterrupt (1, rotaryTurn, RISING);// interrupt 0 is pin 2, For rotary encoder
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.backlight();
    lcd.print(" Start na ");
    lcd.setCursor(12,1);
    lcd.print("sec");
    lcd.setCursor(2,0);
    lcd.print("HIFI pre-AMP ");
      for(int x=5; x>0; x--){
      lcd.setCursor(10,1);
      lcd.print(x);
      delay(1000);
            
    }
  digitalWrite(Shift_enablePin, LOW);
  irrecv.enableIRIn();
  pinMode(slaveSelectPin, OUTPUT);
  SPI.begin();
  setGain(volume);
  lcd.clear();
  digitalWrite (power, HIGH);
  digitalWrite(PGA_CS_PIN,HIGH);
  digitalWrite(PGA_SCLK_PIN,HIGH);
  digitalWrite(PGA_SDI_PIN,HIGH);
 
  delay(1000);
  PowerOn_ShiftRegister();
  input_state();
}

void decodeIR(int value) {
  switch (value) {

case 0x40a:case 0xc0a:
    mute = !mute;
    lcd.setCursor(0, 0);
    if (mute == true) {
      lcd.print("      Muted        ");
      setGain(1);
    }
    if (mute == false) { 
      lcd.clear();
      input_state(); 
      setGain(volume);
      setVolumeBar(volume);  
    }
    delay(1000);
    break;
 
  case 0x411:case 0xc11:
    if (volume < 255){
      volume = volume + 1;
      setGain(volume);
      setVolumeBar(volume);   
    }
    else {
      lcd.setCursor(0, 0);
      lcd.print("Maximum Bereikt");
      delay(500);
    }  
    break;
  
 
  case 0x410:case 0xc10:
  if (volume > 1){
      volume = volume - 1;
       setGain(volume);
      setVolumeBar(volume);  

    }
    else {
      lcd.setCursor(0,0);
      lcd.print("Minimum Bereikt ");
      delay(500);     
    }
    break;
    
case 0x401:case 0xc01:{
     Mode = 1;
     input_state();
  }
break;
     
case 0x402:case 0xc02:{
     Mode = 2;
     input_state();
   }
break;

case 0x403:case 0xc03:{
     Mode = 3;
     input_state();
  }
break;
 
case 0x404:case 0xc04:{
     Mode = 4;
     input_state();
  }
break;
     
case 0x405:case 0xc05:{
     Mode = 5;
     input_state();
  }
break;
  }
}

void setGain(int volume) {
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(volume - offset);  // right channel
  SPI.transfer(volume + offset);  // left channel
  digitalWrite(slaveSelectPin,HIGH);
}
/*
   //voor waarde in decibel
void setVolumeBar(int volume) {
  //convert gain to a decibel string, and write to the lcd
    iGain = 31.5 - 0.5 * (255 - float(volume));
    gain .toCharArray(icGain, 6);
    dtostrf(iGain, 4, 1, icGain);
    gain = String(icGain);
    //lcd.clear();
    lcd.setCursor(8,0);
    lcd.print(gain);
    lcd.print(" dB");
    //lcd.print(toCharArray(cGain,17));
    lcd.setCursor(0, 0);  //first line
    lcd.print(cGain);
}*/  
   //voor waarde in procenten
void setVolumeBar(int volume) {
   volume = volume / 1.27;
   volume = 0.5 + volume * 5;
   lcd.setCursor(11,0);
   lcd.print(volume / 10);
   lcd.print(".");
   lcd.print(volume % 10);
   lcd.setCursor(15,0);
   lcd.print("%");
   
   float a=lenght / 100 * volume / 10;
   lcd.setCursor(0, 1);  //first line
 //write the volume bar
   if (a>=1){
   for (int i=1;i<a;i++){
     lcd.write(4);
     b=i;
    }
    a=a-b;
 }
  peace=a*5;
  
  switch (peace) {
    case 0:
break;

  case 1:
    lcd.write(0);
break;

  case 2:
    lcd.write(1);
break;

  case 3:
    lcd.write(2);
break;

  case 4:
    lcd.write(3);
break;

  }

//clearing line
  for (int i =0;i<(lenght-b);i++) {
  lcd.print(" ");
  }
  
}

void loop(){
    //receive an IR signal
    //digitalWrite (ShiftPin,LOW);
      if (irrecv.decode(&results)) {
      decodeIR(results.value);
      //Serial.println(results.value, HEX);
      irrecv.resume();
      rotaryCount = (volume);    
      }
      volumeControl();
      inputChoice_button();
      Headphone_Switch();
      Monitor_button();
}

void inputChoice_button(){
 val1 = digitalRead(inputButton_Pin);      // read input value and store it in val
      delay(10);                         // 10 milliseconds is a good amount of time
      val2 = digitalRead(inputButton_Pin);     // read the input again to check for bounces
      if (val1 == val2) {                 // make sure we got 2 consistant readings!
        if (val1 != buttonState_input) {          // the button state has changed!
          if (val1 == LOW){                // check if the button is pressed        
              if (Mode == 5){
                Mode = 1;

            }else{
            
              Mode++;
            } 
             input_state();
          }
        }
      }
  }
                
void Monitor_button(){
 val3 = digitalRead(monitorButton_Pin);                      // read input value and store it in val
      delay(10);                                             // 10 milliseconds is a good amount of time
      val4 = digitalRead(monitorButton_Pin);                 // read the input again to check for bounces
      if (val3 == val4) {                                    // make sure we got 2 consistant readings!
        if (val3 != buttonState_monitor && val3 == LOW) {          // the button state has changed! check if the button is pressed         
          if(monitorSW == 0){
             monitorSW = 1;
               input_state_monitor();

  }else{
          
         if(val3 != buttonState_monitor && val3 == LOW){
           if(monitorSW == 1){
              monitorSW = 0;  
              input_state();
          }
        }
     }
   }
 }
}

void Headphone_Switch(){     
val5 = digitalRead(haedphoneSwitch_Pin);                    // read input value and store it in val
     delay(10);                                            // 10 milliseconds is a good amount of time
       val5 = digitalRead(haedphoneSwitch_Pin);             // read the input again to check for bounces
        if (val5 == val6) {                                // make sure we got 2 consistant readings!
          if (val5 != buttonState_headphone && val5 == LOW){      
            if (headPhoneSW == 0){
                headPhoneSW = 1;
                input_state_headPhone();
             }
           }
         
}else{
        
      if (val5 == buttonState_headphone){
        if (val5 == HIGH){
          if (headPhoneSW == 1){
              headPhoneSW = 0;  
              input_state();
           }
        }
     }
  } 
}

void volumeControl(){    
      if (lastrotaryCount != (rotaryCount)){
      volume = (rotaryCount);
      rotaryTurn;
      setVolumeBar(volume);
      setGain(rotaryCount);
      lastrotaryCount = (rotaryCount);
        EEPROM.update(address_1,rotaryCount);
    
    if (rotaryCount < 2){
      setGain(1);
      rotaryCount = 2;
     }
    if (rotaryCount > 254){
      setGain(255);
      rotaryCount = 255;
    }
  }
}  



void rotaryTurn(){
  // Interrupt Service Routine for a change to Rotary Encoder pin B
    
     if (digitalRead (rotaryPinB)){
     rotaryCount--;   // Turn it Down!
      if (rotaryCount < 1){
        setGain(0);
        rotaryCount = 0;
     }
     }else{
     rotaryCount++;   // Turn it Up!
      if (rotaryCount > 254){
      setGain(255);
      rotaryCount = 255;
    }
  }  
}   

void rotaryTurn_balans(){
  // Interrupt Service Routine for a change to Rotary Encoder pin B
     if (digitalRead (rotaryPinB))
     rotaryCount_balans--;   // Turn it Down!
     else
     if (digitalRead (rotaryPinA))
     rotaryCount_balans++;  // Turn it Up!   
}

void updateShiftRegister(){
        digitalWrite(ShiftPin, LOW);
        shiftOut(DataPin, ClkPin, MSBFIRST, B00000000);
        digitalWrite(ShiftPin, HIGH);
}

void PowerOn_ShiftRegister(){
        digitalWrite(ShiftPin, LOW);
        shiftOut(DataPin, ClkPin, LSBFIRST, B00100000);
        digitalWrite(ShiftPin, HIGH);
}

void volumeUp_Fader(){
  delay(100);
    for(int a = 1;a < volume; a++){
      val1 = digitalRead(inputButton_Pin);      // read input value and store it in val
      delay(10);                            // 10 milliseconds is a good amount of time
      val2 = digitalRead(inputButton_Pin);     // read the input again to check for bounces
      if (val1 == val2) {                 // make sure we got 2 consistant readings!
        if (val1 != buttonState_input) {// the button state has changed!
          if (val1 == LOW) {              // check if the button is pressed 
            break;
          }
        }
      setGain(a); 
    delay(10);
      }
    }
}
void input_state(){       
     if (Mode == 1) { 
      setGain(0);
        delay(100);
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00100001);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr1);
        volumeUp_Fader();
     }
     if (Mode == 2) { 
      setGain(0);
        delay(100);
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00100010);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr2);
        volumeUp_Fader();
     }
      if (Mode == 3) {
        setGain(0);
        delay(100);
        digitalWrite (ShiftPin,LOW); 
        shiftOut (DataPin,ClkPin,LSBFIRST,B00100100);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr3); 
        volumeUp_Fader();   
      }  
      if (Mode == 4)  {
        setGain(0);
        delay(100);
        digitalWrite (ShiftPin,LOW); 
        shiftOut (DataPin,ClkPin,LSBFIRST,B00101000);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr4);
        volumeUp_Fader();      
      }            
      if (Mode == 5)  { 
        setGain(0);
        delay(100);
        digitalWrite (ShiftPin,LOW);  
        shiftOut (DataPin,ClkPin,LSBFIRST,B00110000);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr5);
        volumeUp_Fader();
      }
        EEPROM.update(address_0,Mode);
}

void input_state_headPhone(){ 
     if (Mode == 1) { 
             
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00000001);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr1);
     }
     if (Mode == 2) { 
           
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00000010);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr2);
     }
      if (Mode == 3) {
         
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00000100);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr3);   
      }  
      if (Mode == 4)  {
          
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00001000);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr4);      
      }            
      if (Mode == 5)  { 
           
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00010000);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr5);
      }
        EEPROM.update(address_0,Mode); 
}

void input_state_monitor(){       
     if (Mode == 1) { 
     
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00110001);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr6);
     }
     if (Mode == 2) { 
       
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00110010);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr6);
     }
     if (Mode == 3) {
        
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00110100);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr6);  
      }  
      if (Mode == 4)  {
        
        digitalWrite (ShiftPin,LOW);
        shiftOut (DataPin,ClkPin,LSBFIRST,B00111000);
        digitalWrite (ShiftPin,HIGH);
        digitalWrite (ShiftPin,LOW);
        lcd.setCursor(0,0);
        lcd.print("          ");
        lcd.setCursor(0,0);
        lcd.print(myStr6);      
      }
       delay(500);
}

