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

#define sbi(var, mask) ((var) |= (uint8_t)(1 << mask))
#define cbi(var, mask) ((var) &= (uint8_t)~(1 << mask))

#define CLK 0
#define CLR 3
#define LATCH 2
#define DATA 1
#define EN 4


volatile uint16_t count;
volatile uint8_t temp;
volatile uint8_t spiTemp;
volatile uint16_t temp16;
volatile uint8_t countb;
volatile uint16_t line;
volatile uint8_t row;
volatile uint8_t frameBufferindx;

volatile uint8_t i;
volatile uint8_t t;
volatile uint8_t indx;


volatile uint8_t image[] = { 1, 2, 3, 2, 0, 0, 0, 3,
0, 1, 0, 0, 0, 0, 3, 0,
0, 0, 1, 0, 0, 3, 0, 0,
0, 0, 0, 1, 3, 0, 0, 0,

0, 0, 0, 3, 1, 0, 0, 0,
0, 0, 3, 0, 0, 1, 0, 0,
0, 3, 0, 0, 0, 0, 1, 0,
3, 0, 0, 0, 0, 0, 0, 1,
};


volatile uint8_t rowMap[] = { 7, 6, 5, 4, 0, 1, 2, 3 };

void delay_ms(uint16_t x); // general purpose delay

void ioinit (void); // initializes IO

// this is the function that shifts 16 bits out to the 74hc595 shift registers
// it is inlined to speed things up
void inline shiftLine(uint16_t line, uint8_t rowNum);

// Refresh screen
SIGNAL (SIG_OVERFLOW2)
{
for (row = 0; row < 8; row++){
line = 0;
for (i = 0; i < 8; i++){

switch (image[i + (8 * row)]){
case 1: line |= (0x0001 << i); break;
case 2: line |= (0x0100 << i); break;
case 3: line |= (0x0101 << i); break;
}
}
shiftLine(line, row);
}
}

int main (void)
{
uint8_t count=0;

ioinit ();

TCNT2 = 0; // frame timer
TCCR2B = 0x04;

TIMSK2 = (1<<TOIE2); // interrupt enable timer0 and 2

cbi(PORTC, CLR);
delay_ms(1);
sbi(PORTC, CLR);
cbi(PORTC, EN);

row = 0;
PORTD = 0;

for (i = 0; i < 64; i++)
image[i] = 2;

sei();

for (;;){ //LED_off;
indx += count;
count++ ;
indx %= 64;
image[indx] += 1;
image[indx] %= 4; // do some interesting pattern
delay_ms(200); // not really 50 ms becuase of the interrupt
}

return (0);
}

void ioinit (void) /* Note [5] */
{
DDRD = 0xFF; // atmega8 LEDs
PORTD = 0x01;
DDRC = 0x1F;
sbi(PORTC, CLK);
sbi(PORTC, CLR);
sbi(PORTC, DATA);
sbi(PORTC, LATCH);
sbi(PORTC, EN);
}

void inline shiftLine(uint16_t line, uint8_t rowNum){
uint8_t i;
cbi(PORTC, LATCH);
for(i = 0; i < 16; i++){

cbi(PORTC, CLK);
if (line & (1 << i))
sbi(PORTC, DATA);
else
cbi(PORTC, DATA);

sbi(PORTC, CLK);
}
sbi(PORTC, EN);
sbi(PORTC, LATCH);
PORTD = (1 << rowMap[rowNum]);
cbi(PORTC, EN);
}

//General short delays
void delay_ms(uint16_t x)
{
uint8_t y, z;
for ( ; x > 0 ; x--){
for ( y = 0 ; y < 4 ; y++){
for ( z = 0 ; z < 40 ; z++){
asm volatile ("nop");
}
}
}
}