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

const long bandStart = 18068000;    // 
const long bandEnd = 18168000;      // 


volatile long freq = 18109000;         // this is a variable (changes) - set it to the beginning of the band
volatile long radix = 1000;           // how much to change the frequency by, clicking the rotary encoder will change this.
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;


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




// Instantiate the Objects
rgb_lcd lcd;
Si5351 si5351;

void setup()
{
  // Set up frequency and radix switches
  pinMode(rotAPin, INPUT_PULLUP);
  pinMode(rotBPin, INPUT_PULLUP);
  pinMode(pushSwPin, INPUT_PULLUP);
  

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

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

  lcd.cursor();

  // Initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(-30756, 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()
{
  // Check to see if the freq has changed
  currentfreq = getfreq();                    // Interrupt safe method to get the current frequency

  if (currentfreq != oldfreq)
  {
    UpdateDisplay();
    SendFrequency();
    oldfreq = currentfreq;
  }

  // Check the rotary encoder (radix) swith
  if (digitalRead(pushSwPin) == LOW)           // Read the rotary encoder switch
  {
    delay(10);
    while (digitalRead(pushSwPin) == LOW)
    {
      if (updatedisplay == 1)
      {
        UpdateDisplay();
        updatedisplay = 0;
      }
    }
    delay(50);
  }

  
}


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


// 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 (digitalRead(pushSwPin) == LOW)
          {
            updatedisplay = 1;
            if (radix == 10000000)
              radix = 1000000;
            else if (radix == 1000000)
              radix = 100000;
            else if (radix == 100000)
              radix = 10000;
            else if (radix == 10000)
              radix = 1000;
            else if (radix == 1000)
              radix = 100;
            else if (radix == 100)
              radix = 10;
            else if (radix == 10)
              radix = 1;
            else
              radix = 10000000;
          }
          else
          {
            freq = (freq + radix);
            
            if (freq > bandEnd)
              freq = bandStart;
          }
          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)
        {
          // either decrement the radix or freq
          if (digitalRead(pushSwPin) == LOW)
          {
            updatedisplay = 1;
            if (radix == 1)
              radix = 10;
            else if (radix == 10)
              radix = 100;
            else if (radix == 100)
              radix = 1000;
            else if (radix == 1000)
              radix = 10000;
            else if (radix == 10000)
              radix = 100000;
            else if (radix == 100000)
              radix = 1000000;
            else if (radix == 1000000)
              radix = 10000000;
            else
              radix = 1;
          }
          else
          {
            freq = (freq - radix);
            
            if (freq < bandStart)
              freq = bandEnd;
          }
          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()
{
  lcd.setCursor(0, 0);
  lcd.print("        ");
  if (freq < 10000000)
    {
    lcd.setCursor(1, 0);
    lcd.print(freq);
    }
  else
    {
    lcd.setCursor(0,0);
    lcd.print(freq);
    }

lcd.setCursor(0,1);
lcd.print("17m DSB RX");

lcd.setCursor(10,0);
lcd.print("GM4SLV");

 if (radix == 1)
    lcd.setCursor(7, 0);
  if (radix == 10)
    lcd.setCursor(6, 0);
  if (radix == 100)
    lcd.setCursor(5, 0);
  if (radix == 1000)
    lcd.setCursor(4, 0);
  if (radix == 10000)
    lcd.setCursor(3, 0);
  if (radix == 100000)
    lcd.setCursor(2, 0);
  if (radix == 1000000)
    lcd.setCursor(1, 0);
  if (radix == 10000000)
    lcd.setCursor(0, 0);


  
}






void SendFrequency()
{
  si5351.set_freq((freq * 100ULL), SI5351_CLK0);
  //si5351.set_freq((freq * 100ULL), SI5351_CLK2);
}
