#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>         //definiert den Datentyp uint8_t   
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/signal.h>

///////////////////////////////////////////////////////////////
//
// Sonstige Variablen
//

volatile unsigned long zeiteinheit = 0;
volatile unsigned long zeiteinheit2 = 0;
volatile unsigned long adcwert = 0;



volatile unsigned char NrOverflows = 0; // Anzahl der Timer Overflows die während
// der Messung passiert sind
volatile unsigned int StartTime = 0;   // ICR-Wert bei 1.High-Flanke speichern
volatile unsigned int EndTime = 0;     // ICR-Wert bei 2.High-Flanke speichern
volatile unsigned int FallingEdgeTime = 0;
volatile unsigned char messungFertig;   // Job Flag

double Erg = 0.0;


double tragFrequenz = 0.0;
double pwmFrequenz = 0.0;
double DutyCicle = 0.0;


#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif





///////////////////////////////////////////////////////////////
//
// UART Variablen
//

#define F_CPU 16000000UL
#define BAUD 4800UL

///////////////////////////////////////////////////////////////
//
// UART Funktionen
//


void initUART_RxTx(void)
{
  UCSR0A = 0x00;
  UCSR0B |= ( (1 << RXEN0)  | (1 << RXCIE0) | (1 << TXEN0) ); // TX, RX Interrupt einschalten
  UCSR0C |= ( (1 << UCSZ01) | (1 << UCSZ00) ); // 8N1 in Asynchron
  UBRR0H = 0;
  UBRR0L = 207; //Baud 4800 bei 16 Mhz
}


void uartPutC( char c )      //Ausgabe eines einzelnen Zeichens
{
  while ( ! (UCSR0A & ( 1 << UDRIE0) ) );    //Abwarten bis Zeichen geschrieben wurde
  UDR0 = c;
}

void uartPutI(uint16_t integer)    //Ausgabe einer 16 Bit Integerzahl
{
  char putImessage[255];
  uartPutS(itoa(integer, putImessage, 10));
}

void uartPutS( const char* str )     //Ausgabe eines Strings
{
  while ( *str )
  {
    uartPutC( *str );
    str++;
  }
}


///////////////////////////////////////////////////////////////
//
// ADC Funktionen
//

void initADC(void)   //Initialisiere ADC und mache einen Dummy-Ausleser
{
  long int result;

  ADMUX &= ~( (1 << REFS1) | (1 << REFS0) );   //AREF-Pin als Referenz wählen
  ADCSRA |= ( (1 << ADPS1) | (1 << ADPS0) );  //Takt einstellen
  ADCSRA |= (1 << ADEN);
  ADCSRA |= ( (1 << ADSC) | (1 << ADIE) );
  while (ADCSRA & (1 << ADSC) ) {
  }  //Dummy-Ausleser und warten bis ADC fertig ist
  result = ADCW;
}

uint16_t ADC_Read( uint8_t channel )  //Kanalnummer angeben um Kanals auszugeben
{
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);   //Maske für Kanalwahl
  ADCSRA |= (1 << ADSC);
  while (ADCSRA & (1 << ADSC) ) {
  }    //Warten bis ADC fertig ausgelesen hat
  return ADCW;
}




///////////////////////////////////////////////////////////////
//
// Timer Funktionen
//


void initTIMER0_PWM(void)
{
  GTCCR |= ( (1 << TSM) | (1 << PSRASY) );  //Timer stoppen und Prescaler zurücksetzen
  DDRD |= (1<<DDD6);                         // Setup PD6 as output

  TCCR0A |= ( (1<<WGM01) | (1<<WGM00) );
  TCCR0A |= ( (1<<COM0A1) | (1<<WGM00) );
  TCCR0B |= ( (0 << CS02) | (1 << CS01) | (0 << CS00) );
  //TCCR0B |= ( (1 << CS01) );

  OCR0A = 127;                           // Set Dutycycle to 25%
  GTCCR &= ~(1 << TSM);     //Timer wieder starten
}

void initTIMER1_CaptureTime(void)
{
  TCCR1B = (1<<ICES1) | (1<<CS10) | (1<<ICNC1); // Input Capture Edge, kein PreScale
  TIMSK1 = (1<<ICIE1) | (1<<TOIE1); // Interrupts akivieren, Capture + Overflow
}

void initTIMER2_Counter0_001S(void)
{
  GTCCR |= (1 << TSM) | (1 << PSRASY);  //Timer anhalten, Prescaler Reset
  //ASSR |= (1 << AS2);                   //Asynchron Mode einschalten
  TCCR2A = (1 << WGM21);                //CTC Modus
  TCCR2B |= (1 << CS22) | (1 << CS20);  //Prescaler 256
  // 32768 / 256 / 1 = 128                Intervall = 1s
  OCR2A = 156 - 1;
  TIMSK2 |= (1<<OCIE2A);                //Enable Compare Interrupt
  GTCCR &= ~(1 << TSM);                 //Timer starten
}

int main()
{
  
  sei();
  
  initUART_RxTx();
  initTIMER0_PWM();
  initTIMER1_CaptureTime();
  initTIMER2_Counter0_001S();
  initADC();
  
  while(1)
  {
    if(zeiteinheit == 29)
    {
      ADC_Read(0);
    }
    else if(zeiteinheit == 49)
    {
      OCR0A = adcwert / 4;

    }
    else if(zeiteinheit > 99)
    {
      zeiteinheit = 0; 
    }

    if(zeiteinheit2 == 800)
    {
      char s[8]; 
      uartPutS("Frequenzmessung: ");
      uartPutS( dtostrf( Erg, 7, 3, s ) );
      uartPutS(" Hz\n");
      uartPutS("DutyCycle: ");
      uartPutS( dtostrf( DutyCicle * 100, 7, 3, s ) );
      uartPutS(" %\n");  
    }

    if(zeiteinheit2 > 999)
    {
      zeiteinheit2 = 0; 
    }

    if( messungFertig == TRUE )
    {
      tragFrequenz = (NrOverflows * 65536) + EndTime - StartTime;

      pwmFrequenz = (NrOverflows * 65536) + FallingEdgeTime - StartTime;

      DutyCicle = pwmFrequenz / tragFrequenz;
      Erg = F_CPU / tragFrequenz;       // f = 1 / t

      messungFertig = FALSE;
    }

  }
}

ISR (TIMER2_COMPA_vect)
{
  zeiteinheit++;      //begrenzt Auswertung des ADC
  zeiteinheit2++;     //begrenzt Bildschirm Inhalt
}

ISR( TIMER1_CAPT_vect )
{
  static unsigned char ErsteFlanke = TRUE;
  static unsigned char MittelFlanke = FALSE;

  if( ErsteFlanke )
  {
    NrOverflows = 0;
    FallingEdgeTime = 0;
    EndTime = 0;

    StartTime = ICR1;
    ErsteFlanke = FALSE;       // Die naechste Flanke ist das Ende der Messung
    TCCR1B &= ~(1<<ICES1);    // Jetzt auf fallende Flanke triggern
    MittelFlanke = TRUE;      // Jetzt soll fallende Flanke gemessen werden
  }

  else if( MittelFlanke )
  {
    FallingEdgeTime = ICR1;  //Zeit der fallenden Flanke
    TCCR1B |= (1<<ICES1);    //Ab jetzt soll wieder steigende Flanke genommen werden
    MittelFlanke = FALSE;    //Flanke gekommen, jetzt nächste steigende
  }
  else
  {
    EndTime = ICR1;            // Endwert der Messung
    messungFertig = TRUE;      // Eine vollständige Messung. Sie kann ausgewertet werden

    ErsteFlanke = TRUE;        // Bei der naechsten Flanke beginnt der naechste Messzyklus
  }
}


ISR( TIMER1_OVF_vect )
{
  NrOverflows++;
}


ISR (ADC_vect)
{
  adcwert = ADCW - 1;
  if(adcwert < 0)
  {
    adcwert = 0;    
  }
}
