
/**
 * 
 * Mit dem Systemtimer ein Flag mit einer Rate von 20Hz setzt, das die Auswertung des RMS-Wertes anstößt.
 * Bei jeder Auswertung auch den Adressencoder auslesen.
 * 
 * 
 */


// Standard libraries
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>


// Own libraries
#include "betriebsarten.h"
#include "dmx_steuerung.h"
#include "kodierer_ports.h"
#include "led_balken.h"
#include "rms_bildner.h"
#include "systemzeitgeber.h"

#include "debug.h"
#define TRUE 1
#define FALSE 0

#ifndef DDR_OFFSET
  #define DDR_OFFSET(X) (*(&X-1))
#endif
#ifndef PIN_OFFSET
  #define PIN_OFFSET(X) (*(&X-2))
#endif


/**
 * 
 * Module die den Systemzeitgeber benötigen:
 * * Main
 * * Taster
 * 
 */



// Globale Variablen
volatile uint8_t gAuswertungRMS = FALSE;

void AuswertungTimerCb(void);
enum Betriebsarten Betriebsarten(uint8_t kodierer);
uint8_t holegAuswertungRMS(void);
void  DeadIoInit(void);
void GehSchlafen(void);

int main(void) {
  // Init
  SystemzeitgeberInit();
  RmsBildnerInit();
  LedBalkenInit();
  DmxSteuerungInit();
  KodiererPortsInit();
  
  SystemzeitgeberRegistriereCb(AuswertungTimerCb, 25);
  DeadIoInit();
  
  LedBalkenSetzeWert(0xffff);
  _delay_ms(500);
  
  // Start
  sei();
  SystemzeitgeberStart();
  RmsBildnerStart();
  DmxSteuerungStart();
  LedBalkenSetzeWert(0);

  
  while(1) {
    uint8_t auswerten = FALSE;
    uint16_t rms = 0;
    uint8_t kodierer = 0;
    enum Betriebsarten betriebsart = AUS;
   
// Schlafe im Idle-Mode    
    GehSchlafen();
    
    
    SYSTEMZEITGEBER_ATOMIC_START;
    auswerten = holegAuswertungRMS();
    SYSTEMZEITGEBER_ATOMIC_ENDE;
    if(auswerten != FALSE) {
      TOGGLE_TP1;
      // RMS behandeln
      rms = RmsBilden();
      
      kodierer = KodiererPortsLesen();
      betriebsart = Betriebsarten(kodierer);
      
      LedBalkenSetzeWert(rms);
      DmxSteuerungSetzeWert(rms, betriebsart);
      TOGGLE_TP1;
    }
    
    
    
  }
  
  
}

/**
 * 
 * 
 * 
 */


void DeadIoInit(void)
{
  // TODO ISP
  // Ausgang
  DDR_OFFSET(PORTC) |= _BV(PC4); 
  DDR_OFFSET(PORTD) |= _BV(PD0); 
  DDR_OFFSET(PORTB) |= _BV(PB2); 

  // Aus
  PORTC &= ~_BV(PC4); 
  PORTD &= ~_BV(PD0); 
  PORTB &= ~_BV(PB2); 

  
}

/**
 * 
 * 
 * 
 * 
 */

void GehSchlafen()
{
  sleep_enable();
  set_sleep_mode(SLEEP_MODE_IDLE); // Wacht vom system_timer
  sleep_mode();
  sleep_disable();
}

/**
 * 
 * Setze Werte vom Kodierer in Betriebsart um.
 * 
 */

enum Betriebsarten Betriebsarten(uint8_t kodierer)
{
  enum Betriebsarten ret = AUS;
  switch(kodierer) {
    case 0: ret = AUS; break;
    case 0x1: ret = PEGEL_HELL; break;
    case 0x2: ret = PEGEL_NORMAL; break;
    case 0x3: ret = PEGEL_SCHWACH; break;
    case 0x4: ret = PEGEL_REVERS_HELL; break;
    case 0x5: ret = PEGEL_REVERS_NORMAL; break;
    case 0x6: ret = PEGEL_REVERS_SCHWACH; break;
    default: ret = AUS; break;
  }
  return ret;
}

/**
 * 
 * ATOMIC
 *
 * Abgesetzter Zugriff auf globale Variable als Optimierungszaun bei atomaren Operationen
 * 
 */ 

uint8_t holegAuswertungRMS(void)
{
  uint8_t ret = gAuswertungRMS;
  gAuswertungRMS = FALSE;
  return ret;
}

/**
 * 
 * 
 * 
 */

void AuswertungTimerCb(void)
{
      TOGGLE_TP2;
  gAuswertungRMS = TRUE;
      TOGGLE_TP2;
}