/**************************************************************************




  https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts
  FreeMono12pt7b.h		  FreeSansBoldOblique12pt7b.h FreeMono18pt7b.h		        FreeSansBoldOblique18pt7b.h
  FreeMono24pt7b.h		  FreeSansBoldOblique24pt7b.h FreeMono9pt7b.h			        FreeSansBoldOblique9pt7b.h
  FreeMonoBold12pt7b.h		  FreeSansOblique12pt7b.h FreeMonoBold18pt7b.h		    FreeSansOblique18pt7b.h
  FreeMonoBold24pt7b.h		  FreeSansOblique24pt7b.h FreeMonoBold9pt7b.h		      FreeSansOblique9pt7b.h
  FreeMonoBoldOblique12pt7b.h	  FreeSerif12pt7b.h   FreeMonoBoldOblique18pt7b.h	FreeSerif18pt7b.h
  FreeMonoBoldOblique24pt7b.h	   FreeSerif24pt7b.h  FreeMonoBoldOblique9pt7b.h	FreeSerif9pt7b.h
  FreeMonoOblique12pt7b.h		  FreeSerifBold12pt7b.h FreeMonoOblique18pt7b.h		  FreeSerifBold18pt7b.h
  FreeMonoOblique24pt7b.h		  FreeSerifBold24pt7b.h FreeMonoOblique9pt7b.h		  FreeSerifBold9pt7b.h
  FreeSans12pt7b.h		  FreeSerifBoldItalic12pt7b.h FreeSans18pt7b.h		        FreeSerifBoldItalic18pt7b.h
  FreeSans24pt7b.h		  FreeSerifBoldItalic24pt7b.h FreeSans9pt7b.h			        FreeSerifBoldItalic9pt7b.h
  FreeSansBold12pt7b.h		  FreeSerifItalic12pt7b.h FreeSansBold18pt7b.h		    FreeSerifItalic18pt7b.h
  FreeSansBold24pt7b.h		  FreeSerifItalic24pt7b.h FreeSansBold9pt7b.h		      FreeSerifItalic9pt7b.h
  
 **************************************************************************/

//#include <SPI.h> // protocollo SPI alternativo al i2c
#include <Wire.h> // protocollo i2c per settare ad esempio la velocità
#include <Adafruit_GFX.h> // font
#include <Adafruit_SSD1306.h>
#include <stdio.h>


#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int  start_h=15, start_m=04, clk=53;
char outstr[30];

  #define led1 	11 // led 1 sulla porta 13
  #define led2 	 8 // led 2 sulla porta 4
  #define led3   4
  #define button 3 // pulsante sulla porta 3
  
  volatile bool buttonState;
  volatile bool state=false;
  volatile long counter=0L,start=0L,stop=0L;

  
  void rising_count() {
    // interrupt
    stop=millis();   
    attachInterrupt(digitalPinToInterrupt(button),count,FALLING);   
  }
  
  void count() {
    // interrupt
    start=millis();   
    attachInterrupt(digitalPinToInterrupt(button),rising_count,RISING);
    counter++;
   
  }
  

void setup() {
  Serial.begin(9600);
  //Wire.begin();
  //Wire.setClock(400000L); // velocità dell' i2c

  // Display setup
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();              // cancella il logo iniziale di Adafruit
  

  pinMode(led1,OUTPUT);
  pinMode(led2,OUTPUT);
  pinMode(led3,OUTPUT);
  

  pinMode(button,INPUT_PULLUP);
  
  cli(); // Nointerrupt
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1B |= (1 << CS12)|(1 << CS10); //(1 << CS11)|(1 << CS10);
  TCCR1B |= (1 << WGM10); 
  //TCCR1B |= (1 << WGM12); //CTC con CTC non si accende il led1 
  OCR1A = 37000;
  OCR1B = 26000; 
  TIMSK1 |= (1 << OCIE1B);
  TIMSK1 |= (1 << OCIE1A);
  //TCNT1=0; 
  TIMSK1 |= (1 << TOIE1);
  
 
  
  sei(); // ok interrupt
  attachInterrupt(digitalPinToInterrupt(button),count,FALLING); 

  

  // START
  digitalWrite(led1, HIGH);
  digitalWrite(led2, HIGH);
  digitalWrite(led3, HIGH);
  delay(300);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);
  display.setTextSize(2);              // 2:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(36, 22);           // top-left corner
  display.cp437(true);                 // Use full 256 char 'Code Page 437' font
  display.write("START");
  display.display();
  delay(300);
  display.clearDisplay();

  


  // READY
  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setCursor(6,0);
  display.print("COUNTER");
  display.setCursor(80, 24);
  display.setTextColor(SSD1306_WHITE);
  display.print("00000");
  reset_watch();      
  digitalWrite(led1,HIGH);     
}

ISR(TIMER1_COMPB_vect) {
    state =2;
    digitalWrite(led1,HIGH); 
    digitalWrite(led2,HIGH); 
    digitalWrite(led3,LOW); 
}

ISR(TIMER1_COMPA_vect) {
    state =3;
    digitalWrite(led1,LOW); 
    digitalWrite(led2,LOW);
    digitalWrite(led3,HIGH);   
}

ISR(TIMER1_OVF_vect) {
    state =1;
    digitalWrite(led1,HIGH); 
    digitalWrite(led2,LOW);
    digitalWrite(led3,LOW);
    /* assegnando a TCNT1 un valore maggiore di zero
       DOPO IL RESET di overflow NON RIPARTE DA ZERO
       ma dal valore assegnato a TCNT1 */

    //TCNT1=15000; 
  }


void reset_watch (void){
  // simula inizializzazione del RTC
  start_h=17;
  start_m=59;
  clk=53;
}

void clock(void)
{ 
  
  // cancella vecchio orario
  display.setCursor(80, 0);
  display.setTextColor(SSD1306_BLACK);
  sprintf(outstr,"%02d:%02d:%02d",start_h,start_m,clk);
  display.print(outstr);
  
  // simula RTC
  if(clk==59) {
    
    if(start_m==59){
      if(start_h==23) start_h=0;
      else start_h++;
      start_m=-1;
    }
    start_m++;
    clk=-1;  
  }
  
  clk++;
    
  // stampa orario aggiornato
  display.setCursor(80, 0);
  display.setTextColor(SSD1306_WHITE);
  sprintf(outstr,"%02d:%02d:%02d",start_h,start_m,clk);
  display.print(outstr);

  display.display();

}

void loop() {
  static long now,last,old_counter=0;
  static int k=0;
  
  if((stop-start)>1200)
  { stop=0L;
    start=0L;
    counter=0L;
  }
  if(counter!=old_counter)
  {  
    display.setCursor(80, 24);
    display.setTextColor(SSD1306_BLACK);
    sprintf(outstr,"%05d",old_counter);
    display.print(outstr);

    display.setCursor(80, 24);
    display.setTextColor(SSD1306_WHITE);
    sprintf(outstr,"%05d",counter);
    display.print(outstr);

    old_counter=counter;
     
    display.display();
  }
  // aggiorna orario sul display ogni 1000ms
  // meglio farlo con un timer
  now=millis(); 
  if( (now-last) > 1000L) 
  { clock(); 
    last=now; 
    k++;
    
    // funzione di debug
    if(k==900)
    { // ogni 15 minuti resetta l'orologio
      k=0;
      reset_watch();
  } }

  

}