/*
VERSIONE CON SHIFT DEL BLINKING SUL CURSORE CORRISPONDENTE AL MOVIMENTO ROTARY ENCODER

 semplice banco di prova per SI4012
 collegare 
 SCL ad A5 DI ARDUINO NANO
 SDA ad A4 DI ARDUINO NANO
 
 collegare i due clok del rotary encoder a D2 e D3
 collegare switch rotary encoder a D4
 il comune del rotary encoder a massa (vengono usati pull-up)

 collegare SDA e SCL di SI4012, 
 collegare SDA e SCL del display 

usa display LCD di tipo I2c bus , modello MCCOG21605 D6W - FPTLWI
tale display è compatibile con la libreria ST7032.h usando indirizzo 0x7C
nel disply il reset va al positivo
*/


//usa display i2c MCCOG2605 di midas, quindi libreria ST7032
#include <ST7032.h>  //libreria per ST7032 da mettere nella cartella libraries di arduino
#include "bin.h"     //altra libreria utilizzata per ST7032

ST7032 lcd = ST7032 ( 2, 16, 0x7C );  //indirizzo real del datsheet!! lo scanner arduino fornisce 0x3E
   
   
   
   
   
   
   
    //Gotcha with the address, needed to be shifted one to the left



#include <Wire.h>
#include <SI4012_CW.h>  //tra virgolette, metterlo nella stessa directory
#include "serialmenutils.h"
#include <Encoder.h>

Encoder myEnc(2, 3); //rotary encoder sui pin D2 e D3

char ch;
char prompt[]=">>";
char stamp[]="si4012_rfgenerator_v2_1";
char stamp2[]="_v2_1";

int led = 13;
boolean statuz;
boolean request_restart=false;

byte val = 0;
byte cursor_posx=0; //posizone del cursore per cambio di step
byte freq_cursor_startx=0;


//definizione dei piedini del rotary encoder
 #define pin_enc_up 3
 #define pin_enc_dn 2
 #define pin_enc_push 4



  //VARIABILI GLOBALI
  long oldPosition  = 0;       //POSIZIONI INCREMENTALI DELL'ENCODER
  long newPosition = 0;  
  long rotary_inc = 0; 
 
 boolean rotary_chg = false ;  //Rotary has changed!
 boolean rotary_push =false; //Rotary has been pushed!

//definizione di variabili per SI4012 
  unsigned long current_freq =950000000;    //VALORE DI FREQUENZA  ALLO STATRUP  
  unsigned long freq_step = 1000000; //step con encoder iniziale
  byte current_power=90;       //potenza iniziale di uscita di SI4012  è il PaLevel di SI4012
  
  byte pamaxdrv = 0x01;
  byte cap8 =  0x00 ;
  byte cap7_0= 0x80 ;
  byte falpha= 0x7D; 
  byte fbeta=0x7F;



  
   enum typemenu{setfreqmenu,setpowermenu,setstepmenu};
   typemenu mymenu;
   
   
  



//PRESENTAZIONE FUNZIONI
//funzione di refresh dei valory su display lcd
void displayrefresh(typemenu what_value); 

 void serialrefreshmenu();

  
  
  
  
  
  
//#------------------------------------------------------------------------------------#
// SETUP ONLY
//#------------------------------------------------------------------------------------#
 
  
  
  
void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
  pinMode(led,OUTPUT); //generico led 13 per il controllo del funzionamento
  
  
  
  //inizializzo i weak pull-up dei tre piedini
  pinMode(pin_enc_up,INPUT); digitalWrite(pin_enc_up,HIGH);   //collegare rotary encoder
  pinMode(pin_enc_dn,INPUT); digitalWrite(pin_enc_dn,HIGH);
  pinMode(pin_enc_push,INPUT_PULLUP); //digitalWrite(enc_push,HIGH);  ...modi diversi di fare il pullup
  
  //inizializzo display lcd i2c
    lcd.init();
    lcd.on();
    lcd.clear();    lcd.setCursor(0, 0);    lcd.print(stamp);
    delay(100);
    lcd.setContrast(200);//128=basso contrasto, 255=max
    
  
  
  
  
  //Begin serial comunication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);
  while(!Serial);
  
  Serial.println(stamp);
  Serial.println("...started");
  
  
  
 
  //reset generale di tutti i chip si4012, serve per capire quando si riavvia il software 
  Serial.println(">>doing a general reset, turn off leds");
   lcd.clear();    
   lcd.setCursor(0, 0);    lcd.print(stamp); //riga 0
    lcd.setCursor(1, 0);    lcd.print(stamp2); //riga 1
   delay(1000);
   lcd.clear();    lcd.setCursor(0, 0);    lcd.print(">>reset,off leds");
                
        SI4012_ledcontrol(0x01,false);
        SI4012_CMDtxstop(_IDLE,_PERIODICTUNING);
               
   
   
   delay(500);
   
   
   freq_step = 1000000; //step con encoder
   cursor_posx=2;
   
   
   
  serialrefreshmenu();
   
   Serial.print(prompt); Serial.println("press i for Info");

  
}






//#######################################################################################
// MAIN PROGRMAM
//######################################################################################


void loop()
{
  
  digitalWrite(led,statuz);
  delay(100);

  Serial.println(prompt); 
  Serial.print("current frequency=");Serial.println(current_freq);
  lcd.clear();    lcd.setCursor(0, 0);    lcd.print("freq=");
                  lcd.setCursor(1, 0);    lcd.print(current_freq);

_setvfoandstart:

//fase di inizializzazione di SI4012 inizializzazione default
      SI4012_ledcontrol(0x01,true);
      SI4012_chipconfig(_NotUseXo);
      SI4012_settuneinterval(0x0000);
      SI4012_settxfreq(current_freq);
      SI4012_setpaconfig(0x01,current_power,0x00,0x80,0x7D,0x7F); //il byte da impostare è quello corrispondente a current_power
      SI4012_CMDtxstartCW();
delay(100);    


  
_setRestart:

if (request_restart){  //elabora una richiesta di riconfugurazione, ad esempio da seriale
      Serial.println(">>doing a stop after serial reconfig");
      SI4012_CMDtxstop(_IDLE,_PERIODICTUNING);
      SI4012_setpaconfig(pamaxdrv,current_power,cap8,cap7_0,falpha,fbeta);
      SI4012_settxfreq(current_freq);
      SI4012_CMDtxstartCW();
      Serial.println(">>restarted CW");
      request_restart=false;
}


                 
//aggiustamento frequenza se rotazione encoder
 if (rotary_chg & (mymenu==setfreqmenu)) {
            SI4012_CMDtxstop(_IDLE,_PERIODICTUNING);
            long old_freq=current_freq;
            current_freq += rotary_inc*freq_step;
            
            if ((current_freq > 1000000000) || (current_freq < 27000000)){
                   //our of range, ristabilisce vecchio range
                   current_freq=old_freq;
                   Serial.println("...out of range! restoring limit for  frequency");
                  }
            
            if (current_freq >= 100000000){ freq_cursor_startx=0;}
                 else    { freq_cursor_startx=1;} 
                  
            SI4012_settxfreq(current_freq);
            SI4012_CMDtxstartCW();
            
            Serial.print("current frequency=");Serial.println(current_freq);
            
            
            /*
            lcd.clear();    lcd.setCursor(0, 0);    lcd.print("freq=");
                  lcd.setCursor(1, freq_cursor_startx);    lcd.print(current_freq);
                  lcd.setCursor(1, cursor_posx);
            */
            displayrefresh(setfreqmenu);
            rotary_chg=false;//annullo il flag 
            }
 
 
 
 
 
           
            
            
 //aggiustamento potenza se rotazione encoder           
   if (rotary_chg & (mymenu==setpowermenu)) {
            SI4012_CMDtxstop(_IDLE,_PERIODICTUNING);
            current_power += (byte)rotary_inc;
            
            
            //SI4012_setpaconfig(0x01,current_power,0x00,0x80,0x7D,0x7F);
            SI4012_setpaconfig(pamaxdrv,current_power,cap8,cap7_0,falpha,fbeta);
            SI4012_settxfreq(current_freq);
            SI4012_CMDtxstartCW();
            
            Serial.print("current power=");Serial.println(current_power);
            displayrefresh(setpowermenu);
            rotary_chg=false;  //annullo il flag 
            }
  
  
  //aggiustamento step  se rotazione encoder           
   if (rotary_chg & (mymenu==setstepmenu)) {
            
            
            while(rotary_inc >0){rotary_inc--; freq_step=freq_step/10; cursor_posx++ ;}//nota che se incremento encoder devo spostare cursore
            while(rotary_inc <0){rotary_inc++; freq_step=freq_step*10; cursor_posx-- ;}// a destra! per un fatto ergonomico
            
            if(freq_step >100000000){freq_step=1;cursor_posx=8 ;}
            if(freq_step <1){freq_step=100000000;cursor_posx=0;}
            
            
            Serial.print("current step=");Serial.println(freq_step);
            displayrefresh(setstepmenu);
            rotary_chg=false;  //annullo il flag 
            }
  
  
  
  
  
  
  
  statuz= !statuz;

  
    // SI4012_CMDtxstop(_IDLE,_PERIODICTUNING);
  delay(100);
 
 
 
  
  
_menu:
 
 
 //gestione lettura di eventuali rotazioni (sono su interrupt)
  newPosition = myEnc.read();
  if (newPosition != oldPosition) {   //se c'è stata una qualche rotazione la leggo e scrivo l'incremento nella variabile globale
     rotary_chg =true;
     rotary_inc =(newPosition-oldPosition)/2;
     oldPosition =rotary_inc  +oldPosition;
   
     //Serial.println(oldPosition);
     myEnc.write(oldPosition); 
     delay(50);
     }
 
 //lettura per polling della pressione dell'encoder
 rotary_push=!digitalRead(pin_enc_push); //livello invertito in quanto pulsante verso massa
 while(!digitalRead(pin_enc_push)){}  //attesa uscita pressione  pulsante
 
 
 //gestione di una eventuale pressione del rotary encoder
  if (rotary_push){  //switccho su altra voce di menù
  
              if (mymenu==setfreqmenu){mymenu = setpowermenu; Serial.println("switch to power adj...");
                                       lcd.clear();    lcd.setCursor(0, 0);    lcd.print("set pow adj.."); 
                                       delay(400);
                                       displayrefresh(setpowermenu); } 
              else      
         
              if (mymenu == setpowermenu){mymenu = setstepmenu ; Serial.println("switch to step adj...");
                                       lcd.clear();    lcd.setCursor(0, 0);    lcd.print("set step adj..");
                                       delay(400);
                                       displayrefresh(setstepmenu); } 
              else                         
              if (mymenu == setstepmenu){mymenu = setfreqmenu ; Serial.println("switch to freq adj...");
                                       lcd.clear();    lcd.setCursor(0, 0);    lcd.print("set freq adj..");
                                        delay(400);
                                       displayrefresh(setfreqmenu);}                       
                                      
                  rotary_push =false;
             } 

             
//gestione chiamate dalla seriale             
  if(Serial.available()){
      char  keyboard= serial_askfor_singlechar(">> entering config... PRESS m=set MHz, k= set Khz, a=pamaxdr, p=PAlevel, c=cap8, d=cap7_0, f=falpha, b=fbeta, i=INFO ?");
      float newfreq;
      if (keyboard=='a'){  pamaxdrv=(byte)serial_askfor_int(">>enter pAmaxdriv 0/1 ?");}
      if (keyboard=='p'){  current_power=(byte)serial_askfor_int(">>enter PAlevel (current_power) 0...255 ?");}
      if (keyboard=='c'){  cap8=(byte)serial_askfor_int(">>enter cap8  [0/1] ?");}
      if (keyboard=='d'){  cap7_0=(byte)serial_askfor_int(">>enter cap7_0 [0...255] ?");}
      if (keyboard=='f'){  falpha=(byte)serial_askfor_int(">>enter falpha [0...255] ?");}
      if (keyboard=='b'){  fbeta=(byte)serial_askfor_int(">>enter fbeta [0...255] ?");}
      if (keyboard=='m'){  newfreq=serial_askfor_float(">>enter freq MHz (float)[27 upto 960 mhz] ?");
                           
                          if ((newfreq < 27)||(newfreq > 960)){Serial.println(" error! out of range, 27< fmhz <960");}
                           else { newfreq=newfreq*1000000; current_freq=(long)newfreq;}
                         }
                         
      if (keyboard=='k'){  newfreq=serial_askfor_float(">>enter freq KHz (float) ?");
                           Serial.println(newfreq);
                          if ((newfreq < 27000)||(newfreq > 960000)){Serial.println(" error! out of range, 27000< fKhz <960000");}
                           else { newfreq=newfreq*1000; current_freq=(long)newfreq;}
      /*
      if (keyboard=='i'){   Serial.print("current_freq=");Serial.println(current_freq);   
                             Serial.print("freq_step=");Serial.println(freq_step); 
                             Serial.print("pamaxdrv=");Serial.println(pamaxdrv);
                           Serial.print("current_power=");Serial.println(current_power);}
      */           
                        }                  
                        
                         
                         
                         
                         
      serialrefreshmenu();

     displayrefresh(mymenu);
     request_restart=true;

}



goto   _setRestart;
}
//-----------------------------------------------------------END OF MAIN LOOP---------------------------------------------

void displayrefresh(typemenu what_value)
{
   if (what_value==setfreqmenu){lcd.clear();    lcd.setCursor(0, 0);    lcd.print("freq=");
                  lcd.setCursor(1, freq_cursor_startx);    lcd.print(current_freq);
                  lcd.setCursor(1, cursor_posx);}
                  
   if (what_value==setpowermenu){lcd.clear();    lcd.setCursor(0, 0);    lcd.print("pow=");
                  lcd.setCursor(1, 0);    lcd.print(current_power);}
                  
                  
   if (what_value==setstepmenu){lcd.clear();    lcd.setCursor(0, 0);    lcd.print("step=");
                  lcd.setCursor(1, freq_cursor_startx);    lcd.print(current_freq);
                  lcd.setCursor(1, cursor_posx);}

  }
  
  
  
  
  
  
  
 void serialrefreshmenu() {
      Serial.println(">>now set to:");
      Serial.print("current_freq=");Serial.println(current_freq);    
      Serial.print("pamaxdrv=");Serial.println(pamaxdrv);
      Serial.print("current_power=");Serial.println(current_power);
      Serial.print("cap8=");Serial.println(cap8);
      Serial.print("cap7_0=");Serial.println(cap7_0);
      Serial.print("falpha=");Serial.println(falpha);
      Serial.print("fbeta=");Serial.println(fbeta);
 }
  
  
  
  
  






