//  tataylino.com
//  control for tda7419 digital tone control ic

#include <LiquidCrystal.h>
#include <Wire.h>
#include <EEPROM.h>
#include "TDA7419.h" 
TDA7419 tda;

// Settings
#define VOL_MAX       100
#define VOL_MIN       0
#define TIMEOUT       500       //counter - not mS
#define SW_DEBOUNCE   50
#define MENU_MAX      4
#define EQ_MIN        -15
#define EQ_MAX        15
int spectrum_read = A0;      // pin for reading spectrum
int spectrum_trigger = 11;   // pin for spectrum trigger
int mute_pin = 8;
byte eeprom;
//int vol = 50;

String modes[] = {"Bluetooth       ", "TV             ", "DVD        ", "Aux           "};
String menu_names[] = {"  Volume  ",  "Input select", " Bass level ", "  Mid level  ", "Treble level "};
int paramval[] = {50,0,0,0,0};
int parammin[] = {0,0,-15,-15,-15};
int parammax[] = {64,3,15,15,15};
String param_unit[] = {"dB", " ", "dB","dB","dB"};
int tempvar;

// VARS
int timeout_ctr = 0;
int debouncer = 0;
int spectrum[] = {6,6,5,4,3,2,1};
int spectrum_ctr = 0;
int spectrum_seq = 0;
int spectrum_reset_cnt = 10;
int spectrum_clk_cnt = 2;
int spec_gain = 11;
int spec_refresh_ctr = 0;
int input = 1;
int menu = 0;
bool up = false;
bool down = false;
bool selected = false;
const int tda749_addr = 0x44;
int i, i2, vol = 50 , set , treb, mid, bass, in , gain , gain1, gain2, gain3, lf, lt, rf, rt, sab, att_loun, s_loun, treb_c, middle_c, bass_c, sub_f, middle_q , bass_q;
int   pluse, minus, mute = 0 ;


byte level1[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111 };
byte level2[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111 };
byte level3[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111 };
byte level4[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111 };
byte level5[8] = {
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111 };
 byte level6[8] = {
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111 };
byte level7[8] = {
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111 };
byte adj[8] = {
  B00100,
  B01110,
  B11111,
  B00100,
  B00100,
  B11111,
  B01110,
  B00100 };

int x = 0;
bool display_update = true;

int backled = 9;
int button = 13;
int val = 0;
int aState;
int aLastState; 
int a0_raw;
int a1_raw; 

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

void TDA7419_init(){
  // initialize
  tda.setAtt_loudness(0,0,0,0);//loud_att, center_f, h_boost, loud_step
  tda.setSoft(1,1,0,0,0);//( s_mute, pin, s_m_time, s_time, clock)
  tda.setAtt_LF(80,0); //(int left_f, int soft1)
  tda.setAtt_RF(80,0); //
  tda.setAtt_LT(80,0); //
  tda.setAtt_RT(80,0); //
    
  tda.setAtt_SUB(0,0);//(int subwoofer, int soft5)
  tda.setAtt_Mix(0,0);//(int mixing, int soft6)
  tda.setFilter_Treble(paramval[4],0,0);//( treble_g, treble_c, treble_ref)
  tda.setFilter_Middle(paramval[3],1,0);//( middle_g, middle_q, middle_s)
  tda.setFilter_Bass(paramval[2],0,0);//( bass_g, bass_q, bass_s)
  // set 2nd source main
  tda.setInput2(0,0,1);//( input2, gain2, auto_z2)
  // set 160hz sub,1khz mid,80hz bass,
  tda.setSub_M_B(3,1,1,0,0);//( sub,  mid,  bas,  bas_d,  s_filter
  tda.setMix_Gain_Eff(0,0,0,0,0);//( mix_l, mix_r, mix_en, sub_en, gain_eff)
  tda.setSpektor(1,1,1,0,0,0,0);
  //( spek_q, spek_res, spek_an_s, spek_an_r, spek_reset, spek_cl, spek_mode)

  tda.setVolume(80-paramval[0],1);
  tda.setInput(1,0,1);//int input, int gain, int auto_z
}

void setup() {
  pinMode(button, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);
  pinMode(mute_pin,OUTPUT);
//  pinMode(13, OUTPUT);
  pinMode(spectrum_trigger, OUTPUT);
  pinMode(backled, OUTPUT);
  analogWrite(backled, 50);
  digitalWrite(mute_pin, LOW);

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.createChar(0, level1);
  lcd.createChar(1, level2);
  lcd.createChar(2, level3);
  lcd.createChar(3, level4);
  lcd.createChar(4, level5);
  lcd.createChar(5, level6);
  lcd.createChar(6, level7);
  lcd.createChar(7, adj);
  lcd.setCursor(0, 0);
  lcd.print("tataylino.com");
  delay(1000);
  vol = EEPROM.read(0);
  paramval[2] = EEPROM.read(2)-15; // bass
  paramval[3] = EEPROM.read(3)-15; // mid
  paramval[4] = EEPROM.read(4)-15; // tre
  paramval[0] = EEPROM.read(0)-80; // Vol
  paramval[1] = EEPROM.read(1); // Input
  
  //Wire.setClock(10000);
  TDA7419_init();
}

void display_volume() { // volume
    lcd.setCursor(0, 0);
    lcd.print("Volume level:    ");
    lcd.setCursor(0, 1);
    if (up) {
      paramval[menu]++;
      up = false;
    }
    if(down) {
      paramval[menu]--;
      down = false;
    }
    paramval[menu] = constrain(paramval[menu],parammin[menu],parammax[menu]); //limit vol
    lcd.print(paramval[menu]);
    tda.setVolume(80-paramval[menu],1);
}

void display_bars(){
  lcd.setCursor(0, 1);
  lcd.write(byte(spectrum[0]));
  lcd.write(byte(spectrum[1]));
  lcd.write(byte(spectrum[2]));
  lcd.write(byte(spectrum[3]));
  lcd.write(byte(spectrum[4]));
  lcd.write(byte(spectrum[5]));
  lcd.write(byte(spectrum[6]));
}

void display_home() {
  spec_refresh_ctr++;
  if(spec_refresh_ctr >30){
    spec_refresh_ctr = 0;
    read_spectrum();
    lcd.setCursor(0, 0);
    lcd.print(modes[input]);
    display_bars();
  }
  
  delay(1);
}

void read_spectrum() {
  int max_read;
  max_read = 0;
  digitalWrite(spectrum_trigger, HIGH); // reset high (Trepeat)
  delay(50);
  digitalWrite(spectrum_trigger, LOW); //Low
  delay(2);
  
  for(int i = 0; i < 7;i++){
    digitalWrite(spectrum_trigger, HIGH); //Low
    delay(1);
    tempvar = analogRead(spectrum_read); // read spectrum output
    a0_raw = tempvar*spec_gain;
    if(a0_raw>1023){
      a0_raw=1023;
      spec_gain--;
      }
      if (a0_raw>max_read){
        max_read = a0_raw;
      }
    spectrum[i] = map(a0_raw,0, 1023, 0, 6);
    digitalWrite(spectrum_trigger, LOW); //Low
    
    if(max_read<128){
      spec_gain++;
      if(spec_gain>60){spec_gain=60;}
    }
  }
  
}

void loop() {
  if(debouncer <= 0){
    val = digitalRead(button);  // read button
    if (val == LOW) {
      //button_click = true;
      lcd.clear();
      debouncer = SW_DEBOUNCE;
      timeout_ctr = TIMEOUT;
       if(menu == 0) {
        menu++;
      } else {
        if(selected){
          selected = false;
        }else{
          selected = true;
        }
      }
    }
  }

  aState = digitalRead(A3);
  if ((aState== LOW) && (aLastState == HIGH)){  // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
     if (digitalRead(A2) == LOW) { 
       down = true;
       debouncer = SW_DEBOUNCE;
       timeout_ctr = TIMEOUT;
       lcd.clear();
      } else {
       up = true;
       debouncer = SW_DEBOUNCE;
       timeout_ctr = TIMEOUT;
       lcd.clear();
     }
   } 
   aLastState = aState; //

  if(menu == 0){ // home
      if(timeout_ctr > 0){
        display_volume(); 
      } else {
        display_home();
      }
  } else {
    if(selected){
      lcd.setCursor(0, 0);
      lcd.print(menu_names[menu]);
      lcd.setCursor(15, 0);
      lcd.write(byte(7));
      lcd.setCursor(0, 1);
      if(menu == 1){
        lcd.print(modes[input]);
        if(up){ input++; }
        if(down) {input--;}
        input = constrain(paramval[menu], parammin[menu],parammax[menu]);
        tda.setInput(input,0,1);//( input, gain, auto_z)
      } else {
        lcd.print(paramval[menu]);
        if(paramval[menu]<10 && paramval[menu]>=0){
            lcd.setCursor(1, 1);
            lcd.print(" ");
          }
        lcd.setCursor(3, 1);
        lcd.print(param_unit[menu]);
        
      }
      if(up){ paramval[menu]++; }
      if(down) {paramval[menu]--;}
      paramval[menu] = constrain(paramval[menu], parammin[menu],parammax[menu]);
      if(menu==4){
          tda.setFilter_Treble(paramval[menu],0,0);
        }
      if(menu==3){
          tda.setFilter_Middle(paramval[menu],1,0); // q = 0.75
        }
      if(menu==2){
          tda.setFilter_Bass(paramval[menu],0,0);
        }
      up = false;
      down = false;
    }else {
        lcd.setCursor(0, 0);
        lcd.print("<-");
        lcd.setCursor(2, 0);
        lcd.print(menu_names[menu]);
        lcd.setCursor(14, 0);
        lcd.print("->");
        if(up){ menu++; }
        if(down) {menu--;}
        menu = constrain(menu, 1, MENU_MAX);
        up = false;
        down = false;
    }
  }

  if(timeout_ctr > 0){ // counter to automatically back to home display
    timeout_ctr--;
    if(timeout_ctr==0){
      menu = 0;
      //update eeprom values here
      EEPROM.write(2, paramval[2]+15); //bass
      EEPROM.write(3, paramval[3]+15); //mid
      EEPROM.write(4, paramval[4]+15); //tre
      EEPROM.write(0, paramval[0]+80); //vol
      EEPROM.write(1, paramval[1]); //input
      
      
      lcd.clear();
    }
  }
  
  if( debouncer > 0){
    debouncer--;
  }
  delay(1); // loop delay
}