
/* MalZeit 07/2014 */

#include <dmx_steuerung.h>

#include <util/atomic.h>

#include "logarithmierer.h"
#include "dmx_uart.h"

#define DMX_PUFFER_GROESSE (5*48)

struct DmxPuffer {
  uint8_t Daten[DMX_PUFFER_GROESSE];
  uint8_t Zaehler;
};

#define STUFEN_ZAHL 16
#define BEREICH_DB -24

static uint16_t gStufen[STUFEN_ZAHL] = {0};

#define FEIN_STUFEN_ZAHL 64
#define BEREICH_DB -24

static uint16_t gFeinStufen[FEIN_STUFEN_ZAHL] = {0};

volatile struct DmxPuffer gDmxPuffer = {{0}, 0};

void DmxSteuerungInit(void);
void DmxSteuerungStart(void);

void DmxSteuerungCallback(void);

void DmxSteuerungSetzeWert(uint16_t wert, enum Betriebsarten betriebsart);

void DmxSteuerungPegelReversHell(volatile struct DmxPuffer *pDmxPuffer);

/**
 * 
 * 
 * 
 */
void DmxSteuerungInit(void)
{
  DmxUartInit();
  DmxUartRegistriereCb(&DmxSteuerungCallback);
  LogarithmiererErzeugeSkala(gStufen, STUFEN_ZAHL, BEREICH_DB);
  LogarithmiererErzeugeSkala(gFeinStufen, FEIN_STUFEN_ZAHL, BEREICH_DB);


}

/**
 * 
 * 
 * 
 */
void DmxSteuerungStart(void)
{
  DmxUartStart();
}


/**
 * 
 * 
 * 
 */
void DmxSteuerungCallback(void)
{  
  uint8_t zaehler = gDmxPuffer.Zaehler; // volatile puffern
  gDmxPuffer.Zaehler += 1;
  // 3x mit Geloescht
  // 1x mit Gesetzt
  if(zaehler < 1) {
    DmxUartTxBreak();
  } else if(zaehler < 2) {
    DmxUartTxData(0); // Null übertragen
  } else if(zaehler < (DMX_PUFFER_GROESSE+2)){
    DmxUartTxData(gDmxPuffer.Daten[zaehler-2]);
  } else {
    // Interrupt löscht sich selbst.
  }
}

/**
 * 
 *
 * 
 */
void DmxSteuerungSetzeWert(uint16_t wert, enum Betriebsarten betriebsart)
{
static  uint16_t vorWert = 0; // Vorangeganger Wert
  uint8_t anzeige;
  uint8_t i = 0;
  // uint8_t offset = 0;
  // stoppe DRE-Interruptkette
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)  {
    gDmxPuffer.Zaehler = -1;
  }
  DmxUartWarteAufTxc();

  uint16_t temp = wert;
  wert = (vorWert/2) + (wert/2);
  vorWert = temp;

  anzeige = LogarithmiererBildeWert(wert, gStufen, STUFEN_ZAHL);

  // DMX PixelTube ansteuern
  
  while(i < 3*STUFEN_ZAHL) {
    uint8_t rot = 0, gruen = 0, blau = 0;
    if(i < 9*3) { // Grüner Bereich 1..10
      if(i < 3*anzeige) {
        gruen = 0xff; // grün
      } else {
        gruen = 0x05; // grün
      }
    } else if ( i < 3*13)  { // Gelber Bereich 11..13
      if(i < 3*anzeige) {
        rot = 0xff; // = 0xff / sqrt(2)
        gruen = 0x7f;
      } else {
        rot = 0x05; // = 0xff / sqrt(2)
        gruen = 0x04;
      }
    } else {
      if(i < 3*anzeige) {
        rot = 0xff;
      } else {
        rot = 0x05;
      }
    } 
    gDmxPuffer.Daten[i] = rot; // rot
    i += 1;
    gDmxPuffer.Daten[i] = gruen; // grün
    i += 1;
    gDmxPuffer.Daten[i] = blau; // blau
    i += 1;    
  }  

  // DMX Dekoleuchte ansteuern in verschiedenen Farben
  // weiß, rot, grün, blau, orange, lila = 6*8 = 48
  
  // Eurolite PixelTube
  
  // Starville LED Par Spot
  // CH1 = R, CH2 = G, CH3 = B, CH4 = Macro, CH5 = Strobe, CH6 = Modus, CH7 = Dimmer
  
  // Eurolite Par 64
  // CH1 = R, CH2 = G, CH3 = B, CH4 = Dimmer, CH5 = Strobe
  
  // Farbverlauf grün nach rot
  
  for(; i < DMX_PUFFER_GROESSE; i++) {
    gDmxPuffer.Daten[i] = 0;
  }

  switch (betriebsart) {
    case AUS:
      for(i = 0 ; i < DMX_PUFFER_GROESSE ; i++) {
        gDmxPuffer.Daten[i] = 0;
	
      }
      break;
    case PEGEL_HELL:
      break;
    case PEGEL_NORMAL:
      for(i = 0 ; i < DMX_PUFFER_GROESSE ; i++) {
        gDmxPuffer.Daten[i] >>= 1;
      }
      break;
    case PEGEL_SCHWACH:
      for(i = 0 ; i < DMX_PUFFER_GROESSE ; i++) {
        gDmxPuffer.Daten[i] >>= 2;
      }
      break;
    case PEGEL_REVERS_HELL:
      DmxSteuerungPegelReversHell(&gDmxPuffer);
      break;
    case PEGEL_REVERS_NORMAL:
      DmxSteuerungPegelReversHell(&gDmxPuffer);
      for(i = 0 ; i < DMX_PUFFER_GROESSE ; i++) {
        gDmxPuffer.Daten[i] >>= 1;
      }
      break;
    case PEGEL_REVERS_SCHWACH:
      DmxSteuerungPegelReversHell(&gDmxPuffer);
      for(i = 0 ; i < DMX_PUFFER_GROESSE ; i++) {
        gDmxPuffer.Daten[i] >>= 2;
      }
      break;
      
    default:
      for(i = 0 ; i < DMX_PUFFER_GROESSE ; i++) {
        gDmxPuffer.Daten[i] = 0;
	
      }
      break;
  }
  
  // starte DRE-Interruptkette
  gDmxPuffer.Zaehler = 0;
  DmxSteuerungCallback();
}

/**
 * 
 * 
 * 
 */

void DmxSteuerungPegelReversHell(volatile struct DmxPuffer *pDmxPuffer)
{
  uint8_t i = 0;
  while (i < 3*(STUFEN_ZAHL/2)) {
    uint8_t temp;
    temp = pDmxPuffer->Daten[i+0];
    pDmxPuffer->Daten[i+0] = pDmxPuffer->Daten[(STUFEN_ZAHL*3)-i+0-3]; // rot
    pDmxPuffer->Daten[(STUFEN_ZAHL*3)-i+0-3] = temp;
    temp = pDmxPuffer->Daten[i+1];
    pDmxPuffer->Daten[i+1] = pDmxPuffer->Daten[(STUFEN_ZAHL*3)-i+1-3]; // grün
    pDmxPuffer->Daten[(STUFEN_ZAHL*3)-i+1-3] = temp;
    temp = pDmxPuffer->Daten[i+2];
    pDmxPuffer->Daten[i+2] = pDmxPuffer->Daten[(STUFEN_ZAHL*3)-i+2-3]; // blau
    pDmxPuffer->Daten[(STUFEN_ZAHL*3)-i+2-3] = temp;
    i+=3;
  } 
}

// EOF
