/* bulb - BlinkenArea ultimate logo board
   Copyright (C) 2015 Martin Müllenhaupt <mm+bulb@netlair.de>
   Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html
*/

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

#define F_CPU 8000000UL // 8 MHz
#include <util/delay.h>
#include <stdlib.h>

#define ROW_COUNT 6
#define COLUMN_COUNT 7
#define MAX_ROW_TIME 16

struct Frame
{
  uint8_t data[3][COLUMN_COUNT];
  uint8_t time;
};

#include "animations/testbild.c"

uint8_t currentFrame = 0;

ISR(TIMER1_COMPA_vect)
{
  static uint8_t row = 0;
  static uint8_t timeRow = 0;
  static uint16_t timeFrame = 0;

  ++timeRow;
  if (timeRow >= MAX_ROW_TIME)
  {
    row = (row + 1) % ROW_COUNT;
    PORTB = 0;
    PORTD = ~(1 << row);
    timeRow = 0;

    /* upon complete draw cycle increase frame time */
    if (row == 0)
    {
      ++timeFrame;
      if (timeFrame >= pgm_read_byte(&(animation[currentFrame].time))*4)
      {
        currentFrame = (currentFrame + 1) % ANIMATION_SIZE;
        timeFrame = 0;
      }
    }
  }

  uint8_t row_data = 0;
  for(uint8_t column = 0; column < COLUMN_COUNT; ++column)
  {
    uint8_t pixelTime = pgm_read_byte(&(animation[currentFrame].data[row/2][column]));
    if (row % 2)
    {
      pixelTime &= 0x0F;
    }
    else
    {
      pixelTime = pixelTime >> 4;
    }
    if (pixelTime > timeRow)
    {
      row_data |= (1 << column);
    }
  }
  PORTB = row_data;
}

int main(void)
{
    // PA[01] to output, low
    PORTA = 0;
    DDRA = 0x03;

    // PB[0-6] to output, low - PB7 to input, pull-up enabled
    DDRB = 0x7F;
    PORTB = 0x80;

    // PD[0-5] to output, high - PD6 to input, pull-up enabled
    DDRD = 0x3F;
    PORTD = 0x7F;

    // set clock to 8 MHz
    CLKPR = (1<<CLKPCE);
    CLKPR = 0;

    TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

    TIMSK |= (1 << OCIE1A); // Enable CTC interrupt

    sei(); //  Enable global interrupts

    OCR1A   = 4; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64

    TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64

    for(;;)
    {
    }
}
