/**************************************************************************
  LogicHINO
**************************************************************************/
#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     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
volatile Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 6 pulsanti sulla porta B
#define UP 13
#define LF 12
#define RG 11
#define DW 10
#define MS  9
#define HO  8
// parola di stato dei 6 LSB bit della porta B
volatile byte portB_state=B00000000;
volatile byte portB_flag=false;
volatile byte least_one=false;
volatile byte portB_oldstate=B00000000;
//long start_mm, dtime;
int start_h=17, start_m=59, clk=53;
char *outstr;
char ch,outstr1[30];
void setup() {
  outstr=&(outstr1[0]); // esercizio sui puntatori
  PCICR = B00000000;    // No Change pin interrupt
  Serial.begin(9600);
  //Wire.begin();
  //Wire.setClock(400000L); // velocità dell' i2c
  // 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.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font
  
  // Clear the buffer
  display.clearDisplay();
 pinMode(UP, INPUT_PULLUP);
 pinMode(LF, INPUT_PULLUP);
 pinMode(RG, INPUT_PULLUP);
 pinMode(DW, INPUT_PULLUP);
 pinMode(MS, INPUT_PULLUP);
 pinMode(HO, INPUT_PULLUP);
 pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(6, OUTPUT);
 pinMode(7, OUTPUT);
 display.write("START");
 display.display();
 delay(300);
 display.clearDisplay();
 display.setCursor(6,0);
 PORTD = B11111100;
 delay(300);
 PORTD &= B10000100;
 delay(300);
 PORTD &= B00000000;
 
start_h=17;
start_m=59;
clk=53;
 write_list();
 display.setTextSize(1); 
 portB_state=B00000000;
 PCICR |= B00000001;			//Bit0 = 1 -> "PCIE0" enabeled (PCINT8 to PCINT13)
 PCMSK0 |= B00111111;	
}
void write_list (void) 
{ /* questa funzione scrive le "8" righe che terminano con OUTmode */
  display.setTextColor(SSD1306_WHITE);
  for (int i=0;i<6;i++)
  { display.setCursor(0,(i+1)*8);
    sprintf(outstr,"%2d ",i+1);
    display.print(outstr);
  }
  
  for (int i=0;i<68;i+=6)
  { display.setCursor(i+36,48);
  sprintf(outstr,"%1d",(i/6)%10);
  display.print(outstr);
  }
  sprintf(outstr,"chanel");
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(48,40);
  display.print(outstr);    
  sprintf(outstr,"%c",219);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(36,56);
  display.print(outstr);
  display.display();
}
void clock(void)
{ /* questa funzione simula la stampa dell'orario corrente nella prima riga */
    // cancella orario precedete
    display.setCursor(76, 0);
    display.setTextColor(SSD1306_BLACK);
    sprintf(outstr,"%02d:%02d:%02d",start_h,start_m,clk);
    display.print(outstr);
    // cambio del minuto
    if(clk==59) {
      // cambio dell'ora
      if(start_m==59){
        if(start_h==23) start_h=0;
        else start_h++;
        start_m=-1;
      }
      start_m++;
      clk=-1;  
    }
    // incremento dei secondi
    clk++;
    
    // stampa nuovo orario
    display.setCursor(76, 0);
    display.setTextColor(SSD1306_WHITE);
    sprintf(outstr,"%02d:%02d:%02d",start_h,start_m,clk);
    display.print(outstr);
    display.display();
    
}
ISR (PCINT0_vect) 
//PCIFR = B00000001;  non serve
{ /* N = valore dec dei 6 LSB della porta B
     li shifto di 2 bit a sinistra (moltiplico Nx4)
     calcolo PORTD=252-Nx4
     in modo tale che se pin13(12,11,10,9,8) è messo a massa
     allora il led pin7(6,5,4,3,2,1) si accenda
  
  Se PORTD !=0 ho premuto uno dei 6 tasti
  si è acceso il relativo led e 
  memorizzo il valore dec nella parola di stato: 
  portB_state
  *********************************************************/
  PORTD = 252 - ( (PINB & B00111111) << 2);
  /* PINB è normalmente alto e si attiva quando uno dei suoi pin 
     viene messo a massa
     PORTB invece funziona in logica negata e quindi occorre fare 
     il complemento ad 1 dei 6 MSB
  */
  portB_state=PORTD;
  if (PORTD!=portB_oldstate)  
  { /* la porta B ha cambiato stato
       //portando almeno un bit ad 1
    */
    portB_flag=true;
    least_one=true;
  }
  else 
  { /* la porta B ha cambiato stato
       portando tutti i suoi bit a zero
    */
    portB_flag=false; 
  }
} 
int chanel_flag=1;
void loop() 
{
  static long now,last;
  static int k=3;
  int i,num;
  byte tmpbyte=B10000000;
  char tmpch[2]={219,0};
  static int chanel=0, old_chanel;
  // K va inizializzato con l'unità in secondi dello start
  //PORTD |=0b00111111;
  
  //se è cambiata la parola di stato;
  if(portB_flag || least_one)
  { // num=6-int(log10(portB_state>>2)/log10(2)+0.01);
    least_one=false;
    
    // stampa il codice numerico della parola di stato
    display.setTextColor(SSD1306_BLACK);
    display.setCursor(104,10);
    sprintf(outstr,"%c%c%c",219,219,219);
    display.print(outstr);
        
    display.setCursor(74,20);
    sprintf(outstr,"%c%c%c%c%c%c%c%c",219,219,219,219,219,219,219,219);
    display.print(outstr);
    
    for(i=0;i<8;i++,outstr++)
    { 
      if(portB_state&tmpbyte) 
      { *outstr=49;
        display.setTextColor(SSD1306_WHITE);
      }
      else 
      { *outstr=48;
        display.setTextColor(SSD1306_BLACK);
      }
      display.setCursor(20,(i+1)*8);
      display.print(tmpch);
      tmpbyte=tmpbyte>>1;
    }
    
    display.setTextColor(SSD1306_WHITE);
    outstr=&(outstr1[0]);
    display.setCursor(74,20);
    display.print(outstr);  
    display.setCursor(104,10);
    sprintf(outstr,"%3d",portB_state);
    display.print(outstr); 
        
    /*
    // stampa un quadratino sull'ultima colonna
    // per memorizzare l'ultimo tasto premuto
    // +0.01 serve a compensare un errore di log10()
      sprintf(outstr,"%c",219);
      
      display.setTextColor(SSD1306_BLACK);
      display.setCursor(20,(6-int(log10(portB_oldstate>>2)/log10(2)+0.01))*8);
      display.print(outstr);
      display.setTextColor(SSD1306_WHITE);
      display.setCursor(20,num*8);
      display.print(outstr);
      portB_oldstate=portB_state; 
    if(chanel_flag)
    {
      switch(num)
      {
      case 5: 
        chanel_flag=0;
        sprintf(outstr,"%c",219);
        display.setTextColor(SSD1306_BLACK);
        display.setCursor(chanel*6+36,56);
        display.print(outstr);
        chanel--;
        if(chanel<0)chanel=0;
        display.setTextColor(SSD1306_WHITE);
        display.setCursor(chanel*6+36,56);
        display.print(outstr);
        
        
      break;
      
      case 6:
        chanel_flag=0;
        sprintf(outstr,"%c",219);
        display.setTextColor(SSD1306_BLACK);
        display.setCursor(chanel*6+36,56);
        display.print(outstr);
        chanel++;
        if(chanel>11)chanel=11;
        display.setTextColor(SSD1306_WHITE);
        display.setCursor(chanel*6+36,56);
        display.print(outstr);
        
      break;
      
      default:
      break;
      } 
      
    } 
    */
  } 
  else
  { chanel_flag=1;
    /*
    // stampa il codice numerico della parola di stato
    display.setTextColor(SSD1306_BLACK);
    display.setCursor(104,0);
    sprintf(outstr,"%3d",num);
    display.print(outstr);
    */
    
    // stampa un quadratino sull'ultima colonna
    // per memorizzare l'ultimo tasto premuto
    // +0.01 serve a compensare un errore di log10()
      sprintf(outstr,"%c",219);
      display.setTextColor(SSD1306_BLACK);
      display.setCursor(20,num*8);
      display.print(outstr);    
       
  } 
  display.display();
  portB_oldstate=portB_state;
  
  
    
  // simulatore RTC
  now=millis(); // sostituire con timer di 1 sec
    if( (now-last) > 500L) { 
    clock(); 
    //chanel_flag=1; // timer ogni 333ms 
    last=now; 
    k++;
  }  
  
}