#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
uint8_t lcd_update = 1,lcd_update2 = 1,p = 0;
String Display = "";
//----------------------------------------------------------------------------------------------
// interrupt variable
volatile uint8_t button1 = 0,button2 = 0;
//------------------------------------------------------------------------------------------
// selecting frequency
uint8_t pointer = 0, number = 0,wave_forme = 0;
uint8_t frequency_p[4] = {0,0,0,0};
long frequency = 0;
uint8_t value2 = 0;
//------------------------------------------------------------------------------
//function

long n = 0,fs = 160000, samples = 0;
uint8_t new_sample = 0;
uint8_t function_points(uint8_t wave_forme,long p,long f,long s);

void setup() {
  // put your setup code here, to run once:
  //Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);  lcd.print("frequency:");
  lcd.setCursor(0,1);  lcd.print("wave:");  
  //DDRD = (1<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
  DDRD |= (1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
  interrupt_config();
  timer1_config();
}

void loop() {
  // put your main code here, to run repeatedly:
  frequency_p[pointer] = number;
  if(frequency_p[0]==10){  frequency_p[1]=0;frequency_p[2]=0;frequency_p[3]=0;  }
  
  if(lcd_update == 1){
    p = pointer;
    //Serial.print("frequency: ");Serial.print(frequency);  Serial.print("  |   pointer: ");Serial.println(pointer);
    lcd.setCursor(11,0);    lcd.print("      ");lcd.setCursor(11,0); 
    lcd.print(frequency_p[0]);lcd.print(frequency_p[1]);lcd.print(frequency_p[2]);lcd.print(frequency_p[3]);
    if(frequency_p[0]==10)p++;
    lcd.setCursor(11,1);  lcd.print("      ");
    lcd.setCursor(11+p,1);  lcd.print("_");
    p = pointer;
    lcd_update = 0;
  }
  if(lcd_update2 == 1){
    lcd_update2 = 0;
    lcd.setCursor(6,1);  lcd.print("      ");lcd.setCursor(6,1); 
    if(wave_forme==0)Display = "sin";
    if(wave_forme==1)Display = "squa";
    if(wave_forme==2)Display = "tri";
    if(wave_forme==3)Display = "pulse";
    if(wave_forme==4)Display = "rampe";
    lcd.print(Display);
    //Serial.print("wave: "); Serial.println(Display);
  }
  switch(button1){
    case 1: frequency = frequency_p[0]*1000 + frequency_p[1]*100 + frequency_p[2]*10 + frequency_p[3];
            samples = fs/frequency; n=0;
            
             //Serial.print("samples: ");  Serial.println(samples);
             
            pointer = 0;
            lcd.setCursor(11,1);  lcd.print("     ");
            button1 = 0;  break;
    case 2: lcd_update = 1; number++; 
            if( number >=10 )number = (pointer == 0)? 10:9;
            if(pointer != 0 && frequency_p[0] == 10 ){number = 0; }
            button1 = 0;  
            break;
    case 4: lcd_update = 1; pointer--; 
            if(pointer == 255)pointer = 0; 
            number = frequency_p[pointer]; 
            button1 = 0;
            break;
    case 8: lcd_update = 1;  number--; 
            if( number ==255 )number = 0; 
            if(pointer != 0 && frequency_p[0]==10){ frequency_p[0]=9;} 
            button1 = 0; 
            break;
    default : button1 = 0; break;
  }
  switch(button2){
    case 1: lcd_update = 1; pointer++; 
            if(pointer == 4)pointer = 3;  
            number = frequency_p[pointer];
            button2 = 0;  
            break;
    case 2: lcd_update2 = 1;wave_forme = 0;  n=0; button2 = 0;  
            break;
    case 4: lcd_update2 = 1;wave_forme = 1; n=0; button2 = 0; 
            break;
    case 8: lcd_update2 = 1;wave_forme = 2; n=0; button2 = 0;  
            break;
    case 16: lcd_update2 = 1;wave_forme = 3; n=0;  button2 = 0;  
             break;
    case 32: lcd_update2 = 1;wave_forme = 4; n=0;  button2 = 0;  
             break;
    default : button2 = 0; break;
  }
  if(new_sample==1){
    new_sample = 0;
    if(frequency != 0){  PORTD =  127*(1+sin(2*PI*n*frequency/fs));  }
    else PORTD = 0;
    n++;
    if(n== samples) n=0;
  }
  
}
void interrupt_config(){
  DDRB &= ~(0b00111111);
  DDRC &= ~(0b00001111);
  PORTB |= 0b00111111;
  PORTC |= 0b00001111;
  PCICR |= (1<<PCIE0)|(1<<PCIE1);
  PCMSK0 |= (1<<PCINT0)|(1<<PCINT1)|(1<<PCINT2)|(1<<PCINT3)|(1<<PCINT4)|(1<<PCINT5);
  PCMSK1 |= (1<<PCINT8)|(1<<PCINT9)|(1<<PCINT10)|(1<<PCINT11);
}
ISR(PCINT1_vect){
  button1 = ~PINC & 0b00001111;
  //Serial.print("button1:  ");Serial.println(button1);
  // up = 2;  down = 8;  left =  4; ok = 1;
}
ISR(PCINT0_vect){
  button2 = ~PINB & 0b00111111;
  //Serial.print("button2:  ");Serial.println(button2);
  // right = 1;  sin =  2 ; triangle = 4;  pulse = 32; rampe = 4 ; square = 16;
}
/*uint8_t function_points(uint8_t wave_forme,long p,long f,long s){
  uint8_t value;
  switch(wave_forme){
    case 0: if(f>0)value =  127*(1+sin(2*PI*f*p/160000)); else value = 0; break;
    case 1: if(f>0)value = (p<s/2)? 255*p*f*2/160000:510 - (510*p*f/160000); else value = 0; break;
    case 2: if(f>0)value = 255*p*f/160000; else value = 0;break;
    case 3: value = (p<s/2)?  255:0; break;
    case 4: value = (p<1)?  255:0;  break;
    default : break;
  }
  return value;
}*/
void timer1_config(void)
{
  TCCR1A = 0; TCCR1B = (1<<WGM12)|(1<<CS10);  TCNT1 = 0;  OCR1A = 99;
  TIMSK1 |= (1<<OCIE1A);
  sei();
}
ISR(TIMER1_COMPA_vect){ 
  //PORTD ^=(1<<PD7);
  new_sample = 1;
}