/* ZylonMatrixBalken (c) Oliver Mezger 27.6.2017  */

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned char vram[] = {0,0}; // Videospeicher
unsigned char balken[2][8]={{0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80},
                            {0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff}};

#define KEYREADER ~PIND & 0b01110000 // Einlesen, invertieren, maskieren zurecht schieben

unsigned char keyOld = 0;       // alter Tasten-Zustand 
unsigned char keyEnter,keyExit; // gedrueckte und losgelassene Tasten 
void keyCheck(){                // Tastaturabfrage mit Flankendedektion  
  unsigned char keyTest,tmp; 
  keyEnter = 0, keyExit = 0; 
  keyTest = KEYREADER;          // Einlesen
  if (keyOld != keyTest){       // hat sich was getan 
    _delay_ms(10);              // Prellen abwarten 
    tmp = KEYREADER;            // noch mal Einlesen
    if (tmp == keyTest){        // ist es stabil? 
      keyEnter = (~keyOld) & keyTest; // steigende Flanke !alt und neu 
      keyExit = keyOld & (~keyTest);  // fallende Flanke alt und !neu 
      keyOld = keyTest; 
    } 
  } 
} 

void ausgebeBalken(unsigned char n){
  vram[1]= vram[0]=0;
  vram[0]=0;
  if (n<=7){
    vram[0]=balken[0][n];
  }
  else {
    vram[0] = 0x80;
    n-=8;
    vram[1]=balken[1][n];
  }
}

int main(){
  DDRB=0xff;
  PORTD=0b01110000;   // PullUps an
  TCCR0A |= 1<<WGM01; // Timer im CTC-Mode
  TCCR0B |= 3;        // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
  TIMSK |= 1<<OCIE0A; // Timer/Counter0 Output Compare Match A Interrupt Enable
  OCR0A = 50;         // Wert bei dem der Timer wieder auf 0 gesetzt wird
  sei();              // globale Interruptfreigabe
  unsigned char z=7;
  ausgebeBalken(z);
  while(1){
    keyCheck();
    switch (keyEnter){
      case 1<<PD6: // Taste S2
        if (z<15) z++;
        ausgebeBalken(z);
        break;
      case 1<<PD5: // Taste S1
        z=7;
        ausgebeBalken(z);
        break;
      case 1<<PD4: // Taste S0
        if(z>0) z--;
        ausgebeBalken(z);
        break;
    }
  }
}

ISR(TIMER0_COMPA_vect){ // Interrupt Service Routine
  static unsigned char zyklus=0;
  switch (zyklus){
    case 0:
      PORTB=0xe0 | (vram[0] & 0x0f);
      zyklus++;
      break;
    case 1:
      PORTB=0xd0 | (vram[0]>>4);
      zyklus++;
      break;
    case 2:
      PORTB=0xb0 | (vram[1] & 0x0f);
      zyklus++;
      break;
    case 3:
      PORTB=0x70 | (vram[1]>>4);
      zyklus =0;
      break;
  }
}
