
#include <rgb_lcd.h>
#include <si5351.h>

char version[] = "v0.1";

const long channel_array[] = 
{
5258500,5260000,5261000,5262000,5263000, 5276000,
5278500,5279000,5287200,5290000,5298000,
5301000,5304000,5317000,5320000,5333000,
5334000,5335000,5354000,5355000,5362000,
5363000,5364700,5366500,5371500,5378000,
5379000,5395000,5398500,5403500,
5345000,5245000,5450000,5505000,5680000,
5195000,5616000,5649000
} ;

const long scan_array[] = 
{
 5260000,5261000,
 5262000,5263000,
 5366500,5354000,
 5355000,
} ;


const int mems = sizeof(channel_array)/sizeof(long);

const int scan_mems = sizeof(scan_array)/sizeof(long);

// the last "no_scan" number channels of
// channel_array are not to be scanned. 
// Put the channels not to be scanned last 
// in the array and update no_scan to reflect. 

const int no_scan = 0; 

const long bandStart = 5000000;    
const long bandEnd = 6000000;
const long txcio = 9001200;
 
const long cwoffset = 600;
const long filteroffset = 500;

volatile int channel = 01;

volatile long freq = channel_array[channel];  //      
volatile long oldfreq = 0;





volatile long currentfreq = 0;
volatile int updatedisplay = 0;

// Rotary encoder pins and other inputs
static const int rotAPin = 2;
static const int rotBPin = 3;
static const int pushSwPin = 4;
static const int mictxrxPin = 5;
static const int txRLA1Pin = 7;
static const int txRLA2Pin = 6;
static const int datatxrxPin = 8;
static const int modRLAPin = 9;
static const int modeSWPin = 11;
static const int scanSWPin = 10;

volatile int scanning = 0;
volatile int old_scanning = 0;

volatile int tx = 0;
volatile int oldtxrx = 0;

volatile int mod = 0;
volatile int oldmod = 0;

volatile int channel_freq = 0; // push-button to toggle tune method
volatile int old_channel_freq = 0;

volatile long scan_freq = scan_array[channel];
volatile long old_scan_freq = 0;

volatile int mode = 1; // 1 = USB/LSB, 0 = CW 
volatile int oldmode = 0;

// Rotary encoder variables, used by interrupt routines
volatile int rotState = 0;
volatile int rotAval = 1;
volatile int rotBval = 1;


int digit1 = 0;
int digit2 = 0;
int digit3 = 0;
int digit4 = 0;   
int digit5 = 0;
int digit6 = 0;
int digit7 = 0;

// Instantiate the Objects
rgb_lcd lcd;
Si5351 si5351;



byte customChar[8] = {
  0b11111,
  0b11011,
  0b11001,
  0b00000,
  0b11001,
  0b11011,
  0b11111,
  0b11111
};



void setup()
{

 
  // Set up frequency and radix switches
  pinMode(rotAPin, INPUT_PULLUP);
  pinMode(rotBPin, INPUT_PULLUP);
  pinMode(pushSwPin, INPUT_PULLUP);
  
  pinMode(mictxrxPin, INPUT_PULLUP);
  pinMode(datatxrxPin, INPUT_PULLUP);
  
  pinMode(modeSWPin, INPUT_PULLUP);
  pinMode(scanSWPin, INPUT_PULLUP);
  pinMode(txRLA1Pin, OUTPUT);
  pinMode(txRLA2Pin, OUTPUT);
  pinMode(modRLAPin, OUTPUT);
 
  digitalWrite(txRLA1Pin, LOW);
  digitalWrite(txRLA2Pin, LOW);
  digitalWrite(modRLAPin, LOW);

  // Set up interrupt pins
  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE);

  // Initialize the display
  lcd.begin(16, 2);

lcd.createChar(0, customChar); // create a new custom character

  lcd.cursor();

  // Initialize the Si5351

  //si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, -31200);         // 
  //si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);   // 2 mA for HB mixers
  //si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);   // 2 mA for HB mixers
  
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(-34976, SI5351_PLL_INPUT_XO);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);

  
  // Update display and send start frequency
  UpdateDisplay();
  SendFrequency();
}


void loop()
{

  CheckScanSwitch();
  
  CheckTXSwitch();
  
  //CheckModSwitch();

  CheckModeSwitch();
  
  // Check to see if the freq has changed
  currentfreq = getfreq();                      // Interrupt safe method to get the current frequency
  
  if (currentfreq != oldfreq)
  {
   
    oldfreq = currentfreq;
     
    UpdateDisplay();
    SendFrequency();

  }

  // Check the rotary encoder (radix) swith
  if (digitalRead(pushSwPin) == LOW)           // Read the rotary encoder switch
  {
    delay(500);
    if (digitalRead(pushSwPin) == LOW)
    {
    
    if (channel_freq == 1)
    {
      channel_freq = 0;
    }
    else if (channel_freq == 0)
    {
      channel_freq = 1;
    }
    //delay(50);
    
    UpdateDisplay();
    
    }
  }
  
} // end of main loop


long getfreq()
{
  long temp_freq;
  cli();
  temp_freq = freq;
  sei();
  return temp_freq;
}

void CheckScanSwitch()
{
 if (digitalRead(scanSWPin) == 0)

    {
    
      scanning  = 1;
      scan_freq = 0;
      channel = channel + 1;

      if (channel > scan_mems - (no_scan + 1))
            {
              channel = 0;
            }
            
      freq = scan_array[channel];
      
      UpdateDisplay();
      SendFrequency();
      delay(500);
    }
    else
    {
     
      
      if (scanning != old_scanning)
      {
        scanning = 0;
        UpdateDisplay();
      }
      old_scanning = scanning;
    }

}

//void CheckModSwitch()
//{
//  if (digitalRead(modSWPin) == 0)
//      mod = 0;                             // 0 = Phone
//  else if (digitalRead(modSWPin) == 1)
//      mod = 1;                                 // 1=Data
    
    
//  if (mod != oldmod)
//  {
//    if ( mod == 0)
//      {
//        digitalWrite(modRLAPin,LOW);
//      }
//    else
//      {
//        digitalWrite(modRLAPin,HIGH);
//      } 
//    UpdateDisplay();
//    SendFrequency();
//    oldmod = mod;
//  }
//}


void CheckModeSwitch()
{
  if (digitalRead(modeSWPin) == 0)
      mode = 0;                             // 0 = CW
  else if (digitalRead(modeSWPin) == 1)
      mode = 1;                                 // 1=SSB
    
    
  if (mode != oldmode)
  {
    if ( mode == 0)
      {
        
      }
    else
      {
       
      } 
    UpdateDisplay();
    SendFrequency();
    oldmode = mode;
  }
}



void CheckTXSwitch()
{
  if (scanning == 0)
  {
  if (digitalRead(mictxrxPin) == 0)

  {
    tx = 1;                             // 1=TX
    mod = 0;
    
   }  else if (digitalRead(datatxrxPin) == 0)

  {  tx = 1;
     mod = 1;
     
  }  else if (digitalRead(mictxrxPin) == 1)
    
  {  tx = 0;                                 // 0=Phone
    
  } else if (digitalRead(datatxrxPin) == 1)

 {   tx = 0;
    
 }
   
  if (tx != oldtxrx)
  {
    if ( tx == 1)
      {
        if ( mod == 0 )
        {
          digitalWrite(modRLAPin,LOW);
        }
        else if ( mod == 1 )
        {
          digitalWrite(modRLAPin,HIGH);
        }
        digitalWrite(txRLA1Pin,HIGH);
        digitalWrite(txRLA2Pin,HIGH);
      }
    else
      {
        digitalWrite(txRLA1Pin,LOW);
        digitalWrite(txRLA2Pin,LOW);   
      }
    UpdateDisplay();
    SendFrequency();
    oldtxrx = tx;
  }
}
}

// Interrupt routines
void ISRrotAChange()
{
  if (digitalRead(rotAPin))
  {
    rotAval = 1;
    UpdateRot();
  }
  else
  {
    rotAval = 0;
    UpdateRot();
  }
}


void ISRrotBChange()
{
  if (digitalRead(rotBPin))
  {
    rotBval = 1;
    UpdateRot();
  }
  else
  {
    rotBval = 0;
    UpdateRot();
  }
}


// Determine which way the rotary encoder is rotating and action as required
void UpdateRot()
{
  switch (rotState)
  {
    case 0:                                         // Idle state, look for direction
      if (!rotBval)
        rotState = 1;                               // CW 1
      if (!rotAval)
        rotState = 11;                              // CCW 1
      break;

    case 1:                                         // CW, wait for A low while B is low
      if (!rotBval)
      {
        if (!rotAval)
        {
          // either increment the radix or freq
          if (channel_freq == 1)
          {
            updatedisplay = 1;
            if (mode == 1)
            {
            freq = freq + 500;
            }
            else
            {
              freq = freq + 100;
            }
            if (freq > bandEnd)
            {
              freq = bandEnd;
            }
           
          }
          else
          {
            channel = channel + 1;
            
            if (channel > mems -1)
            {
              channel = 0;
            }
            freq = channel_array[channel]; 
          }
          rotState = 2;                             // CW 2
        }
      }
      else if (rotAval)
        rotState = 0;                               // It was just a glitch on B, go back to start
      break;

    case 2:                                         // CW, wait for B high
      if (rotBval)
        rotState = 3;                               // CW 3
      break;

    case 3:                                         // CW, wait for A high
      if (rotAval)
        rotState = 0;                               // back to idle (detent) state
      break;

    case 11:                                        // CCW, wait for B low while A is low
      if (!rotAval)
      {
        if (!rotBval)
        {
          if ( channel_freq == 1 )
          {
            updatedisplay = 1;

            if (mode == 1)
            {
            freq = freq - 500;
            }
            else
            {
              freq = freq - 100;
            }
            
            if (freq < bandStart)
            {
              freq = bandStart;
            }
          }
          else
          {
            channel = channel - 1;
            
            if (channel < 0)
             {
              channel = mems - 1;
             }
            freq = channel_array[channel];
           
          }
          rotState = 12;                            // CCW 2
        }
      }
      else if (rotBval)
        rotState = 0;                               // It was just a glitch on A, go back to start
      break;

    case 12:                                        // CCW, wait for A high
      if (rotAval)
        rotState = 13;                              // CCW 3
      break;

    case 13:                                        // CCW, wait for B high
      if (rotBval)
        rotState = 0;                               // back to idle (detent) state
      break;
  }
}


void UpdateDisplay()
{


    digit1 = (freq%10);
    digit2 = ((freq/10)%10);
    digit3 = ((freq/100)%10);
    digit4 = ((freq/1000)%10);   
    digit5 = ((freq/10000)%10);
    digit6 = ((freq/100000)%10);
    digit7 = ((freq/1000000)%10);
   
    
  lcd.setCursor(0,0);
  lcd.print(digit7);
  lcd.setCursor(1,0);
  lcd.print(",");
  lcd.setCursor(2,0);
  lcd.print(digit6);
  lcd.setCursor(3,0);
  lcd.print(digit5);
  lcd.setCursor(4,0);
  lcd.print(digit4);
  lcd.setCursor(5,0);
  lcd.print(".");
  lcd.setCursor(6,0);
  lcd.print(digit3);
  lcd.setCursor(7,0);
  lcd.print(digit2);
  
  lcd.setCursor(8,0);
  lcd.print("kHz");
 

 

  lcd.setCursor(0,1);
  lcd.print("        ");
  
  
  
  lcd.setCursor(channel,1); 
  

if (scanning == 1)
{
   // lcd.print("|");

  lcd.write((byte)0);  // print the custom char at (2, 0)
}
  
 /*
  //if (channel < 10)
  //{
  //lcd.print("0");
  //}
  //lcd.print(channel);

 lcd.setCursor(0,1);
 if (freq == 5287200 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("WSPR1");
 }

 if (freq == 5290000 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("ORK");
 }

 if (freq == 5364700 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("WSPR2");
 }

 if (freq == 5450000 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("RAF");
 }

 if (freq == 5505000 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("EIP");
 }

if (freq == 5317000 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("VMARS");
 }

if (freq == 5366500 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("FK");
 }

if (freq == 5258500 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("FA");
 }

if (freq == 5278500 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("FB");
 }

if (freq == 5288500 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("FC");
 }

if (freq == 5371500 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("FL");
 }
 
if (freq == 5398500 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("FE");
 }

 if (freq == 5403500 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("FM");
 }

if (freq == 5195000 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("DRA5");
 }

if (freq == 5262000 )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("QRP CW");
 }
  

if ((freq >= 5259000) && (freq < 5262000) )
 {
  //lcd.setCursor(3,1);
  //lcd.print("    ");
  //lcd.setCursor(3,1);
  lcd.print("CW");
 }


  
*/


 
 
 lcd.setCursor(14,0);

if (tx == 0)
   { lcd.print("RX");
  
   } else if (tx == 1)
   {
    lcd.print("TX");
  }
  
  lcd.setCursor(8,1);
  if (mode == 1)
  {
    lcd.print("SSB");
  }
  if (mode == 0)
  {
    lcd.print(" CW");
  }
    
  lcd.setCursor(12,1);
  if ( mode == 0 )
  {
    lcd.print(" Key");
    //lcd.print(version);
  }
  else
  
  {
    if (mod == 0)
  {
    lcd.print(" Mic");
    //lcd.print(version);
  }
  else
  {
   lcd.print("Data");
   //lcd.print(version);
  }
}
if (channel_freq == 1)
{
  if (mode == 1)
  {
    lcd.setCursor(6,0);
  }
  else if ( mode == 0 )
  {
    lcd.setCursor(7,0);
  }
  lcd.blink();
}
else
{
  lcd.noBlink();
}
} // end of updatedisplay()


void SendFrequency()


 
 
{

if (mode == 1 ) // SSB

  {
    si5351.set_freq(((txcio + freq) * 100ULL), SI5351_CLK0);     // VFO
    si5351.set_freq((txcio * 100ULL), SI5351_CLK2);              // BFO

  }

else if (mode == 0) // CW

  if ( tx == 0 )

  {

    si5351.set_freq(((txcio + freq - cwoffset - filteroffset) * 100ULL), SI5351_CLK0);    // VFO
    si5351.set_freq(((txcio  - filteroffset) * 100ULL), SI5351_CLK2);                     // BFO
  
  }

  else if (tx == 1 )
 
  {
 
    si5351.set_freq(((txcio + freq - cwoffset - filteroffset) * 100ULL), SI5351_CLK0);    // VFO
    si5351.set_freq(((txcio - cwoffset - filteroffset) * 100ULL), SI5351_CLK2);           // BFO
 
  }

} // end of sendfrequency()
