#include <SPI.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// 1602 LCD konfiguráció (0x27 vagy 0x3F szokott lenni az I2C cím, 16 oszlop, 2 sor)
LiquidCrystal_I2C lcd(0x27, 16, 2);

// AD9833 Chip Select (FSYNC) pinek
const int FSYNC_A = 10;
const int FSYNC_B = 9;
const int FSYNC_C = 8;

// Potméter lába
const int POT_PIN = A0;

// Frekvencia változók
unsigned long lastFrequency = 9999; // Alapból eltérő érték a kényszerített első kiíráshoz
const int tolerance = 2;            // Küszöbérték a potméter zajának kiszűrésére (Hz)

// AD9833 parancsok
const uint16_t AD9833_B28    = 0x2000;
const uint16_t AD9833_SINE   = 0x2000;
const uint16_t AD9833_RESET  = 0x0100;
const uint16_t AD9833_PHASE0 = 0xC000;
const uint16_t AD9833_FREQ0  = 0x4000;

void writeToAD9833(int pin, uint16_t data) {
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE2));
  digitalWrite(pin, LOW);
  SPI.transfer16(data);
  digitalWrite(pin, HIGH);
  SPI.endTransaction();
}

void updateAllFrequencies(unsigned long freq) {
  if (freq == 0) freq = 1; 

  unsigned long freqWord = (freq * 268435456ULL) / 25000000ULL;
  uint16_t lower14 = (freqWord & 0x3FFF) | AD9833_FREQ0;
  uint16_t upper14 = ((freqWord >> 14) & 0x3FFF) | AD9833_FREQ0;
  
  int pins[] = {FSYNC_A, FSYNC_B, FSYNC_C};
  for (int i = 0; i < 3; i++) {
    writeToAD9833(pins[i], AD9833_B28); 
    writeToAD9833(pins[i], lower14);
    writeToAD9833(pins[i], upper14);
  }
}

void setPhase(int pin, uint16_t phaseValue) {
  uint16_t phaseWord = (phaseValue & 0x0FFF) | AD9833_PHASE0;
  writeToAD9833(pin, phaseWord);
}

// 1602 LCD frissítése
void updateDisplay(unsigned long freq) {
  // Első sor frissítése csak szükség esetén (fix szöveg)
  lcd.setCursor(0, 0);
  lcd.print("3-Phase Gen.    "); // 16 karakteres kitöltés
  
  // Második sor: frekvencia kiírása
  lcd.setCursor(0, 1);
  lcd.print("Freq: ");
  lcd.print(freq);
  lcd.print(" Hz   "); // A végén lévő szóközök letörlik a régi hosszabb számjegyeket (pl. 1000 -> 999 esetén)
}

void setup() {
  pinMode(FSYNC_A, OUTPUT);
  pinMode(FSYNC_B, OUTPUT);
  pinMode(FSYNC_C, OUTPUT);
  
  digitalWrite(FSYNC_A, HIGH);
  digitalWrite(FSYNC_B, HIGH);
  digitalWrite(FSYNC_C, HIGH);

  SPI.begin();

  // LCD kijelző elindítása és háttérvilágítás bekapcsolása
  lcd.init();
  lcd.backlight();
  lcd.clear();

  // AD9833 Inicializálás
  writeToAD9833(FSYNC_A, AD9833_B28 | AD9833_RESET);
  writeToAD9833(FSYNC_B, AD9833_B28 | AD9833_RESET);
  writeToAD9833(FSYNC_C, AD9833_B28 | AD9833_RESET);

  setPhase(FSYNC_A, 0);    
  setPhase(FSYNC_B, 1365); // 120°
  setPhase(FSYNC_C, 2730); // 240° 

  // Kezdőértékek beállítása
  int potVal = analogRead(POT_PIN);
  lastFrequency = map(potVal, 0, 1023, 0, 1000);
  updateAllFrequencies(lastFrequency);
  updateDisplay(lastFrequency);

  // Egyszerre indítás
  noInterrupts();
  writeToAD9833(FSYNC_A, AD9833_SINE);
  writeToAD9833(FSYNC_B, AD9833_SINE);
  writeToAD9833(FSYNC_C, AD9833_SINE);
  interrupts();
}

void loop() {
  int potValue = analogRead(POT_PIN);
  unsigned long targetFrequency = map(potValue, 0, 1023, 0, 1000);

  // Frissítés ha elmozdult a potméter a tűréshatáron túl
  if (abs((long)targetFrequency - (long)lastFrequency) > tolerance) {
    lastFrequency = targetFrequency;
    updateAllFrequencies(targetFrequency);
    updateDisplay(targetFrequency); 
  }

  delay(50); 
}