#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <MD_REncoder.h>
#include <EEPROM.h>
#include <EasyButton.h>

#define ROTARY_PIN1 2
#define ROTARY_PIN2 3
#define PIN_SW 4

#define SCALE_CLEAR0   0
#define SCALE_CLEAR1   1
#define SCALE_CLEAR2   2
#define SCALE_CLEAR3   3
#define SCALE_CLEAR4   4
#define SCALE_CLEAR5   5

LiquidCrystal_I2C lcd(0x27, 20, 4);
MD_REncoder R = MD_REncoder(ROTARY_PIN1, ROTARY_PIN2);
EasyButton button(PIN_SW);

int count;
int countLast;

int numfreq;
int numfreqLast;

int level;
int freq;
float num;

float frequency;

int duration = 2000;

typedef enum {
  TUNE,
  PROGRAM,
  SAVE,
  CLEAR_EEPROM,
} Mode;

Mode mode;

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  pinMode(PIN_SW, INPUT);
  button.begin();
  button.onPressed(onPressed);
  button.onPressedFor(duration, onPressedForDuration);

  R.begin();

  lcd.init();
  lcd.backlight();

  count = 1;
  numfreq = 0;

  mode = PROGRAM;

  displayFrequency();
  setFrequency();

  byte scaleChar0[8] = {
    0b10101,
    0b10101,
    0b10100,
    0b10000,
    0b10000,
    0b10000,
    0b10000,
    0b00000
  };
  lcd.createChar(SCALE_CLEAR0, scaleChar0);

  byte scaleChar1[8] = {
    0b11101,
    0b11101,
    0b01100,
    0b01000,
    0b01000,
    0b01000,
    0b01000,
    0b00000
  };
  lcd.createChar(SCALE_CLEAR1, scaleChar1);

  byte scaleChar2[8] = {
    0b10101,
    0b10101,
    0b00100,
    0b00100,
    0b00100,
    0b00100,
    0b00100,
    0b00000
  };
  lcd.createChar(SCALE_CLEAR2, scaleChar2);

  byte scaleChar3[8] = {
    0b10111,
    0b10111,
    0b00110,
    0b00010,
    0b00010,
    0b00010,
    0b00010,
    0b00000
  };
  lcd.createChar(SCALE_CLEAR3, scaleChar3);

  byte scaleChar4[8] = {
    0b10101,
    0b10101,
    0b00101,
    0b00001,
    0b00001,
    0b00001,
    0b00001,
    0b00000
  };
  lcd.createChar(SCALE_CLEAR4, scaleChar4);

  byte scaleChar5[8] = {
    0b10101,
    0b10101,
    0b00100,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000
  };
  lcd.createChar(SCALE_CLEAR5, scaleChar5);

  displayFrequency();
  displaybackscale();
  displaySCALE();

}

void displaybackscale()
{
  lcd.setCursor(0, 0);
  for (byte i = 0; i < 16; i ++)
  {
    lcd.write(SCALE_CLEAR5);
  }
}

void loop()
{
  button.read();
  uint8_t x = R.read();

  if (x)
  {
    if (x == DIR_CW )
    {
      if (mode == PROGRAM) {
        count += 1;
        if (count > 16)
          count = 16;
      } else if (mode == TUNE) {
        numfreq += 1;
        if (numfreq > 84)
          numfreq = 0;
      } else if (mode == SAVE) {
        count += 1;
        if (count > 16)
          count = 16;
      }
    } else {
      if (mode == PROGRAM) {
        count -= 1;
        if (count < 1)
          count = 1;
      } else if (mode == TUNE) {
        numfreq -= 1;
        if (numfreq < 0)
          numfreq = 84;
      } else if (mode == SAVE) {
        count -= 1;
        if (count < 1)
          count = 1;
      }
    }

    if (mode == PROGRAM)
    {
      displayFrequency();
      setFrequency();
    } else if (mode == TUNE) {

      displayFrequency();
      displayprogram();
      setFrequency();
    } else if (mode == SAVE) {
      displaySave();
    }
  }
}

void displayFrequency()
{
  if (mode == PROGRAM)
  {
    numfreq = EEPROM.read(count);
    frequency = ((numfreq * 25) + 8700) * 0.01;

    lcd.setCursor(0, 1);
    lcd.print("CH");
    if (count < 10)
      lcd.print('0');
    lcd.print(count);
    lcd.print(" ");
    lcd.setCursor(5, 1);
    if (frequency < 100)
    {
      lcd.print(" ");
      lcd.setCursor(6, 1);
    }
    if (frequency == 150.75) {
      lcd.setCursor(5, 1);
      lcd.print("------");
    } else {
      lcd.print(frequency);
    }

    lcd.print(" MHz ");

    freq = frequency * 100;
    num = (((freq - 8750) / 25) * 10) / 5;
    int numlevel = num;
    level = (numlevel % 10) / 2;
    displaybackscale();
    displaySCALE();

  } else if (mode == TUNE) {

    if (frequency == 150.75) {
      numfreq = 0;
    }
 
    frequency = ((numfreq * 25) + 8700) * 0.01;

    lcd.setCursor(0, 1);
    lcd.print("TUNE");
    lcd.setCursor(5, 1);
    if (frequency < 100)
    {
      lcd.print(" ");
      lcd.setCursor(6, 1);
    }
    lcd.print(frequency);
    lcd.print(" MHz ");

    freq = frequency * 100;
    num = (((freq - 8750) / 25) * 10) / 5;
    int numlevel = num;
    level = (numlevel % 10) / 2;
    displaybackscale();
    displaySCALE();
  }
}

void setFrequency()
{
  unsigned int frequencyB = 4 * (frequency * 1000000 + 225000) / 32768;
  byte frequencyH = frequencyB >> 8;
  byte frequencyL = frequencyB & 0XFF;
  Wire.beginTransmission(0x60);
  Wire.write(frequencyH);
  Wire.write(frequencyL);
  Wire.write(0xB0);
  Wire.write(0x10);
  Wire.write(0x00);
  Wire.endTransmission();
}

void nextMode()
{
  switch (mode) {
    case PROGRAM:
      mode = TUNE;
      displayFrequency();
      break;
    case TUNE:
      mode = SAVE;
      displaySave();
      break;
    case SAVE:
      mode = CLEAR_EEPROM;
      displayCLEAR_EEPROM();
      break;
    case CLEAR_EEPROM:
      mode = PROGRAM;
      displayFrequency();
      break;
  }
}

void onPressed()
{
  nextMode();
}

void onPressedForDuration()
{
  if (mode == SAVE)
  {
    numfreq = ((frequency * 100) - 8700) / 25;
    EEPROM.write(count, numfreq);

    lcd.setCursor(0, 1);
    lcd.print("   SAVE CH");
    if (count < 10)
      lcd.print('0');
    lcd.print(count);
    lcd.print("    ");
    delay(2000);
    lcd.setCursor(0, 1);
    lcd.print("              ");

    mode = PROGRAM;
    displayFrequency();
  }

  if (mode == CLEAR_EEPROM)
  {
    for (int i = 0 ; i < 17 ; i++) {
      EEPROM.write(i, 255);
    }

    lcd.setCursor(0, 0);
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.print("  !! Finish !!  ");
    delay(2000);
    lcd.setCursor(0, 1);
    lcd.print("              ");

    mode = PROGRAM;
    numfreq = 0;
    frequency = ((numfreq * 25) + 8700) * 0.01;
    displayFrequency();

  }
}

void displaySCALE()
{
  byte y = num * 0.1;
  if (freq < 8750)
  {
    y = 0;
    level = 0;
    lcd.setCursor(y, 0);
    lcd.write(level);
  }
  else if (freq > 10725)
  {
    y = 15;
    level = 4;
    lcd.setCursor(y, 0);
    lcd.write(level);
  }
  else
  {
    lcd.setCursor(y, 0);
    lcd.write(level);
  }
}

void displaySave()
{
  lcd.setCursor(0, 0);
  lcd.print(" PRESS 3 SEC TO ");
  lcd.setCursor(0, 1);
  //lcd.print(">> SAVE CH");

  if (frequency < 100)
  {
    lcd.print(" ");
    lcd.setCursor(1, 1);
  }
  lcd.print(frequency);
  lcd.print("-->>CH");

  if (count < 10)
    lcd.print('0');
  lcd.print(count);
  lcd.print("<<");
}

void displayCLEAR_EEPROM()
{
  lcd.setCursor(0, 0);
  lcd.print(" PRESS 3 SEC TO ");
  lcd.setCursor(0, 1);
  lcd.print(" !CLEAR MEMORY! ");
}

  void displayprogram() {

  int CH01 = EEPROM.read(1);
  int CH02 = EEPROM.read(2);
  int CH03 = EEPROM.read(3);
  int CH04 = EEPROM.read(4);
  int CH05 = EEPROM.read(5);
  int CH06 = EEPROM.read(6);
  int CH07 = EEPROM.read(7);
  int CH08 = EEPROM.read(8);
  int CH09 = EEPROM.read(9);
  int CH10 = EEPROM.read(10);
  int CH11 = EEPROM.read(11);
  int CH12 = EEPROM.read(12);
  int CH13 = EEPROM.read(13);
  int CH14 = EEPROM.read(14);
  int CH15 = EEPROM.read(15);
  int CH16 = EEPROM.read(16);

  lcd.setCursor(0, 1);
  if (CH01 == numfreq) {
    lcd.print("TU01");
  }
  else if (CH02 == numfreq) {
    lcd.print("TU02");
  }
  else if (CH03 == numfreq) {
    lcd.print("TU03");
  }
  else if (CH04 == numfreq) {
    lcd.print("TU04");
  }
  else if (CH05 == numfreq) {
    lcd.print("TU05");
  }
  else if (CH06 == numfreq) {
    lcd.print("TU06");
  }
  else if (CH07 == numfreq) {
    lcd.print("TU07");
  }
  else if (CH08 == numfreq) {
    lcd.print("TU08");
  }
  else if (CH09 == numfreq) {
    lcd.print("TU09");
  }
  else if (CH10 == numfreq) {
    lcd.print("TU10");
  }
  else if (CH11 == numfreq) {
    lcd.print("TU11");
  }
  else if (CH12 == numfreq) {
    lcd.print("TU12");
  }
  else if (CH13 == numfreq) {
    lcd.print("TU13");
  }
  else if (CH14 == numfreq) {
    lcd.print("TU14");
  }
  else if (CH15 == numfreq) {
    lcd.print("TU15");
  }
  else if (CH16 == numfreq) {
    lcd.print("TU16");
  }
  else {
    lcd.print("TUNE");
  }
  }