
#include "Waveforms.h"

uint8_t  wf_wave0     = 0;
uint8_t  wf_pos       = 0;
uint16_t wf_freq      = 0;
uint8_t  wf_dutyCycle = 0;

unsigned long wf_sample_us  = 0;
unsigned long wf_prevMicros = 0;

bool wf_outputEnabled       = true;  // Variable to control waveform output state
bool wf_pwm_needs_disabling = true;

void initWaveformGenerator()
{
  pinMode(PWM_PIN, OUTPUT);
  setWaveform(WAVEFORM_SINUS);
  // Call the function to set default frequency, here you might want to specify a default frequency
  setWaveformFrequency(WAVEFORM_DEFAULT_FREQ_HZ);
  setWaveformDC(0);
  analogWrite(PWM_PIN, 0);
}

void setWaveform(uint8_t waveform0)
{
  if (waveform0 >= 0 and waveform0 < WAVEFORM_MAXWAVEFORM_NUM)
  {
    wf_wave0 = waveform0;
  } else {
    // Set default waveforms
    wf_wave0 = WAVEFORM_SINUS;
  }
}

void setWaveformFrequency(uint16_t frequency)
{
  if (frequency >= 1 and frequency < WF_FREQ_MAX_HZ)
  {
    wf_freq = frequency;
  } else {
    wf_freq = WAVEFORM_DEFAULT_FREQ_HZ;
  }
  wf_sample_us = 1000000UL / ((unsigned long)wf_freq * WAVEFORM_MAX_SAMPLES_NUM);
  
  if (frequency >= 30 && frequency <= 1000000)
  {
    setupPWMFrequency(PWM_PIN, frequency);
  }
}

void setWaveformDC(uint8_t dc)
{
  wf_dutyCycle = dc;
}

void enableWaveformOutput()
{
  wf_outputEnabled = true;
}

void disableWaveformOutput()
{
  wf_outputEnabled = false;
}

bool isWaveformEnabled()
{
  return wf_outputEnabled;
}

void pollWaveformGenerator()
{

  if (wf_outputEnabled)
  {

    if (wf_wave0 != WAVEFORM_DUTYCYCLE)
    {
      /*unsigned long currentMicros = micros();  // Aktuelle Zeit abrufen
      if (currentMicros - wf_prevMicros >= wf_sample_us)
      {
          wf_prevMicros = currentMicros;

          uint16_t sample = map(waveformsTable[wf_wave0][wf_pos], 0, 0xfff, 0, DAC_MAX_VOLTAGE);
          sample = constrain(sample, 0, DAC_MAX_VOLTAGE);*/
          // write the selected waveform on DAC0
          dac_setVoltage(MCP4725_I2C_ADDRESS, wf_pos*10); // do not write to EEPROM, 400000Hz DAC frequency

          //wf_pos++;
          wf_pos += 1;
          if (wf_pos >= WAVEFORM_MAX_SAMPLES_NUM)  // Reset the counter to repeat the wave
              wf_pos = 0;

      //}
    } else {
      // WAVEFORM_DUTYCYCLE
      if (analogRead(PWM_PIN) != wf_dutyCycle)
        analogWrite(PWM_PIN, wf_dutyCycle);
    }

    if (!wf_pwm_needs_disabling)
      wf_pwm_needs_disabling = true;

  } else {
    if (wf_pwm_needs_disabling)
    {
      dac_setVoltage(MCP4725_I2C_ADDRESS, 0);
      analogWrite(PWM_PIN, 0);
      wf_pwm_needs_disabling = false;
    }
  }
}

void setupPWMFrequency(uint8_t pin, unsigned long frequency) {
  byte prescalerbits = 0b001; // Voreinstellung: kein Prescaler (F_CPU)
  unsigned long prescaler_value;
  unsigned long ocr;

  // Berechne den idealen Prescaler für die gewünschte Frequenz
  prescaler_value = F_CPU / frequency;

  // Finde den passenden Prescaler
  if (prescaler_value < 65536UL) {
    prescalerbits = 0b001; // Kein Prescaler (F_CPU)
  }
  else if ((prescaler_value >>= 3) < 65536UL) {
    prescalerbits = 0b010; // Prescaler 8
  }
  else if ((prescaler_value >>= 3) < 65536UL) {
    prescalerbits = 0b011; // Prescaler 64
  }
  else if ((prescaler_value >>= 2) < 65536UL) {
    prescalerbits = 0b100; // Prescaler 256
  }
  else if ((prescaler_value >>= 2) < 65536UL) {
    prescalerbits = 0b101; // Prescaler 1024
  }
  else {
    prescalerbits = 0b101; // Prescaler 1024
    frequency = F_CPU / (prescaler_value = 65535UL);
  }

  // Berechne den Wert für den Output Compare Register (OCR)
  ocr = F_CPU / (prescaler_value * frequency) - 1;

  // Timer konfigurieren
  pinMode(pin, OUTPUT);
  if (pin == 5 || pin == 6) {
    TCCR0B &= ~0b111; // Prescaler löschen
    TCCR0B |= prescalerbits; // Neuen Prescaler setzen
    OCR0A = ocr; // Output Compare Register setzen
    TCCR0A |= (1 << WGM01); // CTC-Modus aktivieren
  }
  else if (pin == 9 || pin == 10) {
    TCCR1B &= ~0b111; // Prescaler löschen
    TCCR1B |= prescalerbits; // Neuen Prescaler setzen
    OCR1A = ocr; // Output Compare Register setzen
    TCCR1A |= (1 << WGM11); // CTC-Modus aktivieren
  }
  else if (pin == 3 || pin == 11) {
    TCCR2B &= ~0b111; // Prescaler löschen
    TCCR2B |= prescalerbits; // Neuen Prescaler setzen
    OCR2A = ocr; // Output Compare Register setzen
    TCCR2A |= (1 << WGM21); // CTC-Modus aktivieren
  }
}

