/*
  Main code by Richard Visokey AD7C - www.ad7c.com
  Small changes by Ivan Sizov and Andrey Politov
*/
#include <rotary.h>
#include <EEPROM.h>
 
#define DDS_SCLK 8
#define DDS_FSYNC 9
#define DDS_SDATA  10
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW);}
#define pulseLow(pin) {digitalWrite(pin, LOW); digitalWrite(pin, HIGH);}
 
Rotary r = Rotary(2, 3);
 
const int LEDS[] = {11, 12, 13};  // Пины светодиодов-индикаторов шага престройки
const int_fast32_t INC_VALUES[] = {1000, 250, 25};  // Возможные значения шага перестройки
const int INC_CNT = 3;  // Число возможных значений
const int_fast32_t DEFAULT_RX = 3600000;  // Частота по умолчанию
 
int_fast32_t increment;
int cur_inc = 0;
int_fast32_t rx;
 
int button_state = 0;
//---------------------------------------------------------------------------------------------------------
void setup() {
  // Инициализируем глобальные переменные
  increment = INC_VALUES[0];
 
  // Работа с EEPROM
  // Число 123 используется как маркер, что в памяти не рандомный бред
  if (EEPROM.read(0) != 123)
  {
    rx = DEFAULT_RX;
    // EEPROM.clear();
    EEPROM.write(0, 123);
    EEPROM.put(1, rx);
  }
  else
    EEPROM.get(1, rx);
 
  for (int i = 0; i < INC_CNT; ++i)
  {
    pinMode(LEDS[i], OUTPUT);
    digitalWrite(LEDS[i], HIGH);
  }
  pinMode(A0, INPUT);
  digitalWrite(A0, HIGH);
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();
  pinMode(DDS_FSYNC, OUTPUT);
  pinMode(DDS_SCLK, OUTPUT);
  pinMode(DDS_SDATA, OUTPUT);
  digitalWrite(DDS_SCLK, HIGH);
  digitalWrite(DDS_FSYNC, HIGH);
  tfr_word(0x2100);
  send_frequency(rx);
  tfr_word(0xC000);
  tfr_word(0x2000);
}
//---------------------------------------------------------------------------------------------------------
void loop()
{
  button_state = digitalRead(A0);
  if (button_state == LOW)
    set_increment();
  delay(30);
}
//---------------------------------------------------------------------------------------------------------
ISR(PCINT2_vect)
{
  unsigned char result = r.process();
 
  if (result) {
    if (result == DIR_CW) {
      if ((rx + increment) < 3800000) {
        rx = rx + increment;
      }
    }
    else {
      if ((rx - increment) > 3500000) {
        rx = rx - increment;
      }
    }
  }
  EEPROM.put(1, rx);
  send_frequency(rx);
}
//---------------------------------------------------------------------------------------------------------
void send_frequency(double frequency)
{
  int32_t freq;
  int16_t MSB;
  int16_t LSB;
  int16_t phase = 0xC000;
  freq = frequency * 268435 / 25000;
 
  MSB = (int)((freq & 0xFFFC000)>>14);
  LSB = (int)(freq & 0x3FFF);
 
  //Установка DB15 и DB14
  LSB |= 0x4000;
  MSB |= 0x4000;
 
  //tfr_word(0x2100);
  tfr_word(LSB);
  tfr_word(MSB);
  tfr_word(phase);
  //tfr_word(0x2000);
}
//---------------------------------------------------------------------------------------------------------
void tfr_word(int16_t data)
{
  digitalWrite(DDS_FSYNC, LOW);
  for (int i = 0; i < 16; i++) {
    digitalWrite(DDS_SDATA, (bool)(data & 0x8000));
    data <<= 1;
    data &= 0xFFFF;
    pulseLow(DDS_SCLK);
  }
  digitalWrite(DDS_FSYNC, HIGH);
}
//---------------------------------------------------------------------------------------------------------
void set_increment()
{
  cur_inc = (cur_inc + 1) % INC_CNT;
  increment = INC_VALUES[cur_inc];
  for (int i = 0; i < cur_inc; ++i)
  digitalWrite(LEDS[i], LOW);
  for (int i = cur_inc; i < INC_CNT; ++i)
  digitalWrite(LEDS[i], HIGH);
  delay(250);
}
//---------------------------------------------------------------------------------------------------------