
//-----------------------------------------------------------------------------

#include <avr/io.h>
#include <avr/interrupt.h>

#include <inttypes.h>

//-----------------------------------------------------------------------------

#define	LED_SZ	56

#define A1_LO	0x01
#define A1_HI	0x02
#define A2_LO	0x04
#define A2_HI	0x08
#define A3_LO	0x10
#define A3_HI	0x20
#define A4_LO	0x40
#define A4_HI	0x80

#define C5_LO	0x80
#define C5_HI	0x40
#define C6_LO	0x20
#define C6_HI	0x10
#define C7_LO	0x08
#define C7_HI	0x04
#define C8_LO	0x02
#define C8_HI	0x01

//-----------------------------------------------------------------------------

volatile uint8_t	g_led[LED_SZ];

volatile uint32_t	g_timer = 0;

//-----------------------------------------------------------------------------

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  static uint8_t	counter = 0,
									intensity = 0;

  uint8_t					a = 0,
									c = 0;
	
  PORTA = 0;
  PORTC = 0;

	g_timer++;

  switch (counter)
  {
  case 0:
    a = A1_HI;
		if (g_led[0] > intensity)  a |= A2_LO;
		if (g_led[2] > intensity)  a |= A3_LO;
		if (g_led[4] > intensity)  a |= A4_LO;
		if (g_led[6] > intensity)  c |= C5_LO;
		if (g_led[8] > intensity)  c |= C6_LO;
		if (g_led[10] > intensity) c |= C7_LO;
		if (g_led[12] > intensity) c |= C8_LO;
    break;
  case 1:
    a = A1_LO;
		if (g_led[1] > intensity)  a |= A2_HI;
		if (g_led[3] > intensity)  a |= A3_HI;
		if (g_led[5] > intensity)  a |= A4_HI;
		if (g_led[7] > intensity)  c |= C5_HI;
		if (g_led[9] > intensity)  c |= C6_HI;
		if (g_led[11] > intensity) c |= C7_HI;
		if (g_led[13] > intensity) c |= C8_HI;
    break;
  case 2:
    a = A2_HI;
		if (g_led[14] > intensity) a |= A3_LO;
		if (g_led[16] > intensity) a |= A4_LO;
		if (g_led[18] > intensity) c |= C5_LO;
		if (g_led[20] > intensity) c |= C6_LO;
		if (g_led[22] > intensity) c |= C7_LO;
		if (g_led[24] > intensity) c |= C8_LO;
    break;
  case 3:
    a = A2_LO;
		if (g_led[15] > intensity) a |= A3_HI;
		if (g_led[17] > intensity) a |= A4_HI;
		if (g_led[19] > intensity) c |= C5_HI;
		if (g_led[21] > intensity) c |= C6_HI;
		if (g_led[23] > intensity) c |= C7_HI;
		if (g_led[25] > intensity) c |= C8_HI;
    break;
  case 4:
    a = A3_HI;
		if (g_led[26] > intensity) a |= A4_LO;
		if (g_led[28] > intensity) c |= C5_LO;
		if (g_led[30] > intensity) c |= C6_LO;
		if (g_led[32] > intensity) c |= C7_LO;
		if (g_led[34] > intensity) c |= C8_LO;
    break;
  case 5:
    a = A3_LO;
		if (g_led[27] > intensity) a |= A4_HI;
		if (g_led[29] > intensity) c |= C5_HI;
		if (g_led[31] > intensity) c |= C6_HI;
		if (g_led[33] > intensity) c |= C7_HI;
		if (g_led[35] > intensity) c |= C8_HI;
    break;
  case 6:
    a = A4_HI;
		if (g_led[36] > intensity) c |= C5_LO;
		if (g_led[38] > intensity) c |= C6_LO;
		if (g_led[40] > intensity) c |= C7_LO;
		if (g_led[42] > intensity) c |= C8_LO;
    break;
  case 7:
    a = A4_LO;
		if (g_led[37] > intensity) c |= C5_HI;
		if (g_led[39] > intensity) c |= C6_HI;
		if (g_led[41] > intensity) c |= C7_HI;
		if (g_led[43] > intensity) c |= C8_HI;
    break;
  case 8:
    c = C5_HI;
		if (g_led[44] > intensity) c |= C6_LO;
		if (g_led[46] > intensity) c |= C7_LO;
		if (g_led[48] > intensity) c |= C8_LO;
    break;
  case 9:
    c = C5_LO;
		if (g_led[45] > intensity) c |= C6_HI;
		if (g_led[47] > intensity) c |= C7_HI;
		if (g_led[49] > intensity) c |= C8_HI;
    break;
  case 10:
    c = C6_HI;
		if (g_led[50] > intensity) c |= C7_LO;
		if (g_led[52] > intensity) c |= C8_LO;
    break;
  case 11:
    c = C6_LO;
		if (g_led[51] > intensity) c |= C7_HI;
		if (g_led[53] > intensity) c |= C8_HI;
    break;
  case 12:
    c = C7_HI;
		if (g_led[54] > intensity) c |= C8_LO;
    break;
  case 13:
    c = C7_LO;
		if (g_led[55] > intensity) c |= C8_HI;
    break;
  }
  
	intensity++;
	if (intensity == 16)
		intensity = 0;

  counter++;
  if (counter == 13)
    counter = 0;

  PORTA = a;
  PORTC = c;
}

//-----------------------------------------------------------------------------

void switch_leds_off()
{
  uint8_t i;

  for (i = 0; i < LED_SZ; i++)
		g_led[i] = 0;
}

//-----------------------------------------------------------------------------

void pattern1()
{
  uint8_t   i, j, k;
  
  for (k = 0; k < 10; k++)
  {
    for (j = 0; j < LED_SZ; j++)
    {

      for (i = 0; i < LED_SZ; i++)
        g_led[i] = 0;

      g_led[j] = 0xFF;
      g_led[LED_SZ - 1 - j] = 0xFF;

      while (g_timer < 2500) { asm volatile ("nop"); }
      g_timer = 0;
    }
  }
}

//-----------------------------------------------------------------------------

void pattern2()
{
  uint8_t   i = 0;
  uint16_t  cnt = 0;

  while (cnt < LED_SZ * 10)
  {
		if (g_timer > 2000)
		{
      cnt++;
		  g_timer = 0;
			
			g_led[i] = ~g_led[i];

			i++;
			if (i == LED_SZ)
				i = 0;
		}
  }
}

//-----------------------------------------------------------------------------

void pattern3(uint8_t step)
{
  uint8_t   i, j, k;
  
  for (k = 0; k < 40; k++)
  {
    for (j = 0; j < step; j++)
    {

      for (i = 0; i < LED_SZ; i++)
        g_led[i] = 0;

      for (i = j; i < LED_SZ; i += step)
        g_led[i] = 0xFF;

      while (g_timer < 10000) { asm volatile ("nop"); }
      g_timer = 0;
    }
  }
}

//-----------------------------------------------------------------------------

void pattern4()
{
  uint8_t   i, j;
  
  for (j = LED_SZ; j > 0; j--)
  {

    for (i = 0; i != j; i++)
    {
      if (i != 0)
        g_led[i - 1] = 0;

      g_led[i] = 0xFF;

      while (g_timer < 1000) { asm volatile ("nop"); }
      g_timer = 0;
    }
  }

  for (i = 0; i < LED_SZ; i++)
  {
    g_led[i] = 0;

    while (g_timer < 1000) { asm volatile ("nop"); }
    g_timer = 0;
  }
}

//-----------------------------------------------------------------------------

void pattern5(uint8_t step)
{
  uint8_t   i, j, k;
  
  for (k = 0; k < 50; k++)
  {
    for (j = 0; j < step; j++)
    {

      for (i = 0; i < LED_SZ; i++)
        g_led[i] = 0;

      for (i = LED_SZ / 2 + j; i < LED_SZ; i += step)
        g_led[i] = 0xFF;

      for (i = LED_SZ / 2 - j; (i >= 0) && (i < LED_SZ); i -= step)
        g_led[i] = 0xFF;

      while (g_timer < 5000) { asm volatile ("nop"); }
      g_timer = 0;
    }
  }
}

//-----------------------------------------------------------------------------

void pattern6()
{
  uint8_t   i, j, k;
  
  j = 0;
  for (k = 0; k < 20; k++)
  {

    for (; j < LED_SZ - 5; j++)
    {
      for (i = 0; i < LED_SZ; i++)
        g_led[i] = 0;
      
      for (i = 0; i < 5; i++)
        g_led[j + i] = 0xFF;

      while (g_timer < 1500) { asm volatile ("nop"); }
      g_timer = 0;
    }

    for (; j > 0; j--)
    {
      for (i = 0; i < LED_SZ; i++)
        g_led[i] = 0;
      
      for (i = 0; i < 5; i++)
        g_led[j + i] = 0xFF;

      while (g_timer < 1500) { asm volatile ("nop"); }
      g_timer = 0;
    }

  }
}

//-----------------------------------------------------------------------------

int main(int argc, char **argv)
{
  DDRA = 0xFF;
  PORTA = 0x00;

  DDRB = 0x00;
  PORTB = 0xFF;

  DDRC = 0xFF;
  PORTC = 0x00;
  
  DDRD = 0x00;
  PORTD = 0xFE;
  DDRD = 0x01;
  PORTD = 0x00; // 0x01;

  // Timer interrupt
  TCNT1 = 0;              // clear counter
  //OCR1A = 160;            // timer 1 compare value 10us
  OCR1A = 320;            // timer 1 compare value 20us
  TCCR1A = 0;             // no PWM, no pin action
  TCCR1B = (1 << WGM12) | (1 << CS10); // no prescalar, reset-counter on output compare match
  TIMSK = 1 << OCIE1A;    // enable compare match interrupt
  
	switch_leds_off();

  // Interrupts erlauben
  sei();
	
  while (1)
  {
    pattern6();
    switch_leds_off();

    pattern3(4);
    switch_leds_off();

    pattern1();
    switch_leds_off();

    pattern5(7);
    switch_leds_off();

    pattern3(7);
    switch_leds_off();

    pattern2();
    switch_leds_off();

    pattern3(4);
    switch_leds_off();

    pattern4();
    switch_leds_off();

    pattern3(5);
    switch_leds_off();
  }

  return 0;
}

//-----------------------------------------------------------------------------
