// *** LED Helligkeitssteuerung mit PWM 2.0 (c) Oliver Mezger 29.6.2014

#include <avr/io.h>        // Definitionen laden
#include <avr/interrupt.h> // Interrupts laden
#include <util/delay.h>    // Delay-Bibliothek laden
#include <avr/pgmspace.h>  // Flashzugriffe laden

// **  mit STK 200 (LED neg. Logik) und ATtiny2313 @ 4MHz

/* 6 LEDs sollen in ihrer Helligkeit gesteuert werden
   Helligkeit soll Werte von 0 bis 255 annehmen
   Wiederholung 100 mal pro Sekunde: ISR muss 25500 * pro Sekunde aufgerufen werden
   Soll-Zeit: 4000000us/25500 = 39,2us
   Vorteiler 4*39,2/256 = 0,6 gewaehlt: 1
   TOP-Wert des Timers 4*39,2 = 156,8 gewaehlt 156
   Tatsaechliche Zeit zwischen ISR-Aufruf: 0,25us*156= 39us
*/
unsigned char helligkeit[]={127,255,254,0,1,2,3}; // Helligkeitswerte der LED

ISR(TIMER0_COMPA_vect){ // bei 4MHZ Aufruf alle 39us Dauer 24,2us
  static unsigned char level = 0; // zaehlt die Helligkeitslevel
  asm volatile ("sbi 0x16,7"); // sbi PINB,7 zum Messen der ISR Dauer
  unsigned char i,ausgabe=0;
  unsigned char k=1;
  for (i=0;i<7;i++){
    if(level>=helligkeit[i]) ausgabe |= k; // LED aus
    k=k<<1;
  }
  level++;
  PORTB = (PORTB & 0b10000000) | ausgabe;
  asm volatile ("sbi 0x16,7"); // sbi PINB,7
}

#define KEYREADER ~PIND & 0b00111111 // Einlesen, invertieren, maskieren zurecht schieben  
#include "keycheck.inc"        // http://mezdata.de/avr/083_c-entprellen/keycheck.inc 

int auswerteTaste(){ // ermittelt die niedrigste Taste
  unsigned char i;
  for (i=0;i<6;i++){
    if(keyEnter&(1<<i)) break;
  }
  return i;
}
// Helligkeitswerte dem Empfinden anpassen
const unsigned char PROGMEM anpassung[]={0,1,2,3,4,5,7,8,10,12,14,16,20,23,28,33,39,46,55,65,77,91,108,128,151,179,212,255};

void pulsierendWeis(){
  static unsigned char up=1,move=0;
  if(up){
    move++;
    if (move>=sizeof(anpassung)-1) up=0;
  }
  else{
    move--;
    if (move<=0) up=1;  
  }
  helligkeit[0]=helligkeit[1]=helligkeit[2]=pgm_read_byte(&anpassung[move]);
}

typedef enum {Rup,Rdown,Gup,Gdown,Bup,Bdown}fadeRichtung;
const fadeRichtung fadeIt[]={Rup,Gup,Rdown,Bup,Gdown,Rup,Gup,Rdown,Gdown,Bdown};
void rgbFade(){  // Code ist fehlerhaft!
  static unsigned char fade=0;
  static unsigned char moveR=0,moveG=0,moveB=0;
  switch (fadeIt[fade]){
    case Rup:
      moveR++;
      if (moveR>=sizeof(anpassung)-1) fade++;
      helligkeit[0]=pgm_read_byte(&anpassung[moveR]);
      break;
    case Rdown:
      moveR--;
      if (moveR<=0) fade++;
      helligkeit[0]=pgm_read_byte(&anpassung[moveR]);
      break;
    case Gup:
      moveG++;
      if (moveG>=sizeof(anpassung)-1) fade++;
      helligkeit[1]=pgm_read_byte(&anpassung[moveG]);
      break;
    case Gdown:
      moveG--;
      if (moveG<=0) fade++;
      helligkeit[1]=pgm_read_byte(&anpassung[moveG]);
      break;
    case Bup:
      moveB++;
      if (moveB>=sizeof(anpassung)-1) fade++;
      helligkeit[2]=pgm_read_byte(&anpassung[moveB]);
      break;
    case Bdown:
      moveB--;
      if (moveB<=0) fade++;
      helligkeit[2]=pgm_read_byte(&anpassung[moveB]);
      break;
  }
  if (fade>=sizeof(fadeIt)) fade=0;
}
int main(){         // Hauptprogramm
  unsigned char i;
  PORTB=0xff;       // alle LED aus
  DDRB=0xff;        // PB als Ausgang
  TCCR0B = 1;       // Phi
  TCCR0A= 1<<WGM01; // CTC Mode mit OCR0A als TOP
  TIMSK = 1<<OCIE0A;// Interrupt frei geben
  OCR0A=156;         // bei 82 Interrupt ausloesen
  sei();            // globale Interruptfreigabe
  while(1){         // Endlosschleife
    keyCheck();
    if (keyEnter){
      i = auswerteTaste();
      if (helligkeit[i]>=255) helligkeit[i]=0;
      else helligkeit[i]++;
    }
    else{
      rgbFade();
      //pulsierendWeis();
      _delay_ms(5);
    }
  }
  return 0;
}