/*
 * Interfacing a RGB LED Matrix
 * Uses double-buffering for smoother fading
 * 
 * Author: Tobias Floery
 * Email: tobias.floery@cable.vol.at
 * Homepage: http://tobiscorner.floery.net
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#include <avr/io.h>
#include <avr/interrupt.h>

/*
 	Signals at PORTD
*/

#define SH_RED 0
#define SH_GREEN 1
#define SH_BLUE 2
#define SH_ROW 3

/*
	Signals at PORTB
*/
#define SH_SCL 0
#define SH_RCK 1

volatile unsigned char row=0;
volatile unsigned char buffer=0, nextBuffer=1;
volatile unsigned char step=0;
volatile unsigned char update=0;


volatile unsigned char 	red[2][8][8],
						green[2][8][8],
						blue[2][8][8];

volatile unsigned char char_T[8][8] = {
		{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
		{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
		{0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00},
		{0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00},
		{0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00},
		{0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00},
		{0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00},
		{0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00}};

volatile unsigned int TIM0_cnt = 0;
volatile unsigned int TIM1_cnt = 0;
volatile unsigned int TIM2_cnt = 0;

unsigned char sinTable[]={4,4,5,5,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,6,6,6,5,5,4,4,4,3,3,2,2,2,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,3,3,4};

ISR(TIMER0_COMPA_vect) {
	unsigned char i;
	
	for (i=0; i<8; i++) {
		PORTD=0x00;
		
		PORTD = (((red[buffer][row][i]>step?0:1)<<SH_RED)&0x01)
				+ (((green[buffer][row][i]>step?0:1)<<SH_GREEN)&0x02)
				+ (((blue[buffer][row][i]>step?0:1)<<SH_BLUE)&0x04);

		if (i==row)
			PORTD |= (1<<SH_ROW);
		else
			PORTD &= ~(1<<SH_ROW);
			
		PORTB |= (1<<SH_SCL);
		PORTB &= ~(1<<SH_SCL);
	}
	PORTB |= (1<<SH_RCK);
	PORTB &= ~(1<<SH_RCK);
	
	row++;
	if (row == 8) {
		row=0;
		step++;
		if (step == 7) {
			step=0;
			if (update == 1) {
				update = 0;
				buffer = (buffer+1)%2;
				nextBuffer = (buffer+1)%2;
			}
		}
	}
	if (TIM0_cnt) TIM0_cnt--;
	if (TIM1_cnt) TIM1_cnt--;
	if (TIM2_cnt) TIM2_cnt--;
}


int main(void) {
	unsigned int i,j, k=0;

	DDRD = 0x0F;
	PORTD = 0x00;
	DDRB = 0x03;
	PORTB = 0x00;

	row=0;

	TCCR0A = 0x02;  // CTC Mode
	OCR0A = 0x7D/4; // time adjusted for better viewing
	TCCR0B = 0x03;  // prescaler = 8

	TIMSK0 = 0x02;
	buffer = 0;

	sei();
	
	TIM0_cnt = 20;

	while (1) {

		/* create some patterns */

		if (TIM0_cnt == 0) {			
			for (i=0; i<8; i++) {				
				for (j=0; j<8; j++) {
					red[nextBuffer][i][j]=blue[nextBuffer][i][j]=green[nextBuffer][i][j]=0;
				
					if (k>256)
						red[nextBuffer][i][j]=sinTable[((i+j+k+256)/24+44)%64];
					
					if (k>128)
						green[nextBuffer][i][j]=sinTable[((i+j-k+128)/8+44)%64];
					
					blue[nextBuffer][i][j]=sinTable[((i+(8-j)-k)/2+44)%64];

					/*
					red[nextBuffer][i][j]&=char_T[i][j];
					green[nextBuffer][i][j]&=char_T[i][j];
					blue[nextBuffer][i][j]&=char_T[i][j];
					*/
				}

				
			}
			
			k++;
			
			/* tell ISR to switch buffers */
			update=1;
			
			/* pattern update rate */
			TIM0_cnt = 100;
		}		
	}


}
