//ICC-AVR application builder : 2011-01-29 오전 11:28:32
// Target : M128
// Crystal: 16.000Mhz

// Protocol define
//
// L0,1,022 : 1번 칩, R LED, 밝기 22 설정
// 			  L0은 밝기 조절 기능으로 칩은 0~2까지 가능하며, 0:R, 1:G, 2:B 을 의미  
// L1,1,000 : 1번 칩의 RGB OFF
// 			  L1은 밝기 조절 기능으로 칩은 0~2 까지 가능하며 1은 ON, 0은 OFF
// L2,1,001 : 1번 칩의 PWM Phase set을 4-step shift로 한다.
// 			  L2은 밝기 조절 기능으로 칩은 0~2 까지 가능하며,
//			  0 : same phase, 1 : 4-step phase, 2 : 8-step phase, 3 : 16-step phase
//
// Protocol은 항상 8bit를 유지해야 하며 사용하지 않는 bit는 0으로 해줘야 한다.

#include <iom128v.h>
#include <macros.h>
#include <stdio.h>

#define LEDPORT	   PORTB
#define RST(m)	   m? (LEDPORT|=0x80):(LEDPORT&=0x7F)
#define CS0(m)	   m? (LEDPORT|=0x10):(LEDPORT&=0xEF)
#define CS1(m)	   m? (LEDPORT|=0x20):(LEDPORT&=0xDF)
#define CS2(m)	   m? (LEDPORT|=0x40):(LEDPORT&=0xBF)

#define ON		   1
#define OFF		   0

volatile unsigned char R_level[32], G_level[32], B_level[32], buf[8], Start;
volatile unsigned i=0;

void uart0_init(void)
{
 UCSR0B = 0x00; //disable while setting baud rate
 UCSR0A = 0x00;
 UCSR0C = 0x06;
 UBRR0L = 0x67; //set baud rate lo
 UBRR0H = 0x00; //set baud rate hi
 UCSR0B = 0x98;
}

void color_protocol(void)
{
 send(buf[3]-'0',32*(buf[5]-'0')|(buf[6]-'0')*10|buf[7]-'0');
}

void PWM_set(void)
{
 send((buf[3]-'0'),(0x60|0x08|((buf[5]-'0')<<2)|((buf[6]-'0')<<1)|(buf[7]-'0')));				 
}

void LED_set(void)
{
 send((buf[3]-'0'),(0x80|(32*(buf[3]-'0'))|(buf[7]-'0')));
}

#pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC
void uart0_rx_isr(void)
{
 char c;
 while(!((UCSR0A&0x80)==0x80));
 c=UDR0;
 if(c == 'L') Start=ON;
 if(Start){
    buf[i]=c;
	i++;
 }
 if(i==8){
    i=0;
	Start=OFF;
	printf("%s\r\n", buf);
	//printf("%c", buf[1]);
	if (buf[1] == '0') color_protocol();
	if (buf[1] == '1') PWM_set(); 
	if (buf[1] == '2') LED_set();
	//send(buf[1]-'0',32*(buf[3]-'0')|(buf[6]-'0')*10|buf[7]-'0');
	//get_rx(buf);
 }
}

int putchar(char c)
{
	while (((UCSR0A>>UDRE0)&0x01) == 0) ;  // UDRE, data register empty
    UDR0 = c;
    return c;
}

int getchar(void)
{
    while ((UCSR0A & 0x80) == 0);
    return UDR0;
}

void delay_LED(void)
{
    int i;	
	for( i=0 ; i<100 ; i++ );
}

void delay_SPI(void)
{
    int i;	
	for( i=0 ; i<100 ; i++ );
}

void delay(unsigned int time)
{
    int i;
	for(i=0;i<time;i++);
}

void level_init(void)
{
 	int i;
	for(i=0;i<32;i++){
	   R_level[i]=i;
	   G_level[i]=i;
	   B_level[i]=i;
	}
}

void port_init(void)
{
 PORTA = 0x00;
 DDRA  = 0x00;
 PORTB = 0x01;
 DDRB  = 0x36;
 PORTC = 0x00; //m103 output only
 DDRC  = 0x00;
 PORTD = 0x00;
 DDRD  = 0x00;
 PORTE = 0x00;
 DDRE  = 0x00;
 PORTF = 0x00;
 DDRF  = 0x00;
 PORTG = 0x00;
 DDRG  = 0x00;
}

//SPI initialize
// clock rate: 4000000hz
void spi_init(void)
{
 SPCR = 0x5C; //setup SPI
 SPSR = 0x00; //setup SPI
 DDRB=0xff;
 PORTB=0xff;
}

//call this routine to initialize all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 XDIV  = 0x00; //xtal divider
 XMCRA = 0x00; //external memory
 port_init();
 spi_init();
 uart0_init();

 MCUCR = 0x00;
 EICRA = 0x00; //extended ext ints
 EICRB = 0x00; //extended ext ints
 EIMSK = 0x00;
 TIMSK = 0x00; //timer interrupt sources
 ETIMSK = 0x00; //extended timer interrupt sources
 SEI(); //re-enable interrupts
 //all peripherals are now initialized
}

unsigned char SPI_Tx(unsigned char instruction)
{
 SPDR = instruction;
 while( !(SPSR&0x80) );
 return SPDR;
}

void send(unsigned char CS, unsigned char instruction){
	 switch(CS){
	 	case 0 : CS0(0); delay_SPI();
	 	  	   	 SPI_Tx(instruction);
	 			 CS0(1); delay_SPI();
				 break;
				 
		case 1 : CS1(0); delay_SPI();
	 	  	   	 SPI_Tx(instruction);
	 			 CS1(1); delay_SPI();
				 break;
				 
		case 2 : CS2(0); delay_SPI();
	 	  	   	 SPI_Tx(instruction);
	 			 CS2(1); delay_SPI();
				 break;
				 
		default : break;
	}		
}

void color(unsigned char chip, unsigned char R, unsigned char G, unsigned char B)
{
 switch(chip){
    case 0 : send(0,0x00|R);
	  	   	 send(0,0x20|G);
			 send(0,0x40|B);
			 break;
			 
	case 1 : send(1,0x00|R);
	  	   	 send(1,0x20|G);
			 send(1,0x40|B);
			 break;
			 
	case 2 : send(2,0x00|R);
	  	   	 send(2,0x20|G);
			 send(2,0x40|B);
			 break;
			 
    default : break;
 }
}

void LEDdriver_init(void)
{
 RST(0);
 delay_LED();
 RST(1);
 
 send(0,0x6f);
 send(0,0x81);
 send(0,0xa2);
 send(0,0xc3);
 
 send(1,0x6f);
 send(1,0x81);
 send(1,0xa1);
 send(1,0xc1);
 
 send(2,0x6f);
 send(2,0x81);
 send(2,0xa1);
 send(2,0xc1);
}

void main(void)
{
 init_devices();
 LEDdriver_init();
 level_init();
 color(0,0,0,0);
 color(1,0,0,0);
 color(2,0,0,0);
 while(1)
 { }
}

