#include <stdint.h>
#include <stddef.h>
#include <avr/io.h>
#define F_CPU 20000000UL
#include <util/delay.h>
#include <stdbool.h>
#define BAUD 9600
#include <util/setbaud.h>

#include "colors.notc"

/*
  255   0   0
  255 255   0
    0   0 255
 */ 

/*
// f=20MHz -> T=0,05 µs
uint8_t T0H = 6;  // == 0.3  µs ~ 0.4 µs (+- 150ns) == [0.25, 0.55] µs
uint8_t T1H = 14; // == 0.7  µs ~ 0.8 µs (+- 150ns) == [0.65, 0.95] µs
uint8_t T0L = 15; // == 0.75 µs ~ 0.85µs (+- 150ns) == [0.70, 1.00] µs
uint8_t T1L = 8;  // == 0.35 µs ~ 0.45µs (+- 150ns) == [0.30, 0.60] µs
uint8_t RES = 51; //  > 50   µs
*/

// #define VAR1

#ifdef VAR1
	#define nop __asm__  ("nop")
	
	#define wait6 __asm__  ("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop")
	#define wait8 __asm__  ("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop")
	#define wait14 __asm__  ("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop")
	#define wait15 __asm__  ("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop")
#else
	// https://github.com/cpldcpu/light_ws2812/blob/master/light_ws2812_AVR/Light_WS2812/light_ws2812.c
	#define w_nop1  __asm__("nop      \n\t")
	#define w_nop2  __asm__("rjmp .+0 \n\t")
	#define w_nop4  w_nop2; w_nop2
	#define w_nop8  w_nop4; w_nop4
	#define w_nop16 w_nop8; w_nop8

	#define wait6 w_nop2; w_nop4
	#define wait8 w_nop4; w_nop4
	#define wait14 wait8; wait6
	#define wait15 wait14; w_nop1
#endif

#define HUE_DEGREE 120
#define HUE_MAX 610
#define HUE_MIN 350
#define LEDS 30
#define DELAYS 536

void uart_init();
void writeZero();
void writeOne();
void writeRGB(uint8_t red, uint8_t green, uint8_t blue);
void writeNothing(uint8_t c);
void mydelay(uint16_t ms);

int mainParty()
{
	DDRC = 1;
	uint8_t d = 14;
	
	while(1)
	{
		for(int i = 0; i < LEDS; i += 1)
			writeRGB(85,0,0);

		mydelay(DELAYS);

		for(int i = 0; i < LEDS; i += 1)
			writeRGB(0,0,85);
			
		mydelay(DELAYS);
		
		//~ for(int i = 0; i < LEDS; i += 1)
			//~ writeRGB(0,128,0);
			
		//~ mydelay(DELAYS);
	}
	
	return 0;	
}

int main(){
	DDRC = 1; // PORT C0 output
	// uart_init();
	
	uint16_t min = HUE_MIN, max = HUE_MAX;
	uint8_t val = 20, sat = 100;
	uint8_t vl = 40;
	uint16_t  steps = 8;
	bool falling = true;
	hsv_t colorsHSV[LEDS];
	rgb_t colorsRGB[LEDS];
	
	do{	
		//~ if(left == 360){
			//~ left = 180;
			//~ right = 360;
		//~ }else{
			//~ left = 360;
			//~ right = 180;
		//~ }
		
		interpolateLinearly(makeHSV(min, sat, val), makeHSV(max, sat, val), LEDS, colorsHSV);

		hsv2rgbList(colorsHSV, colorsRGB, LEDS);
		
		for( int i = 0; i < LEDS; i++){
				writeRGB( colorsRGB[i].r, colorsRGB[i].g, colorsRGB[i].b);
		}
		
		// switch
		if(falling){
			min = min + steps;
			max = max - steps;
		} else {
			min = min - steps;
			max = max + steps;
		}
		
		if(falling && (min >= HUE_MAX || max <= HUE_MIN)) {
			falling = false;
		} else if(!falling && (min <= HUE_MIN || max >= HUE_MAX)){
			falling = true;
		}
		_delay_ms(2100/(520/steps));
		
		// pulse
		//~ if(falling){
			//~ vl -= steps;
			//~ // right = right - steps;
		//~ } else {
			//~ vl += steps;
			//~ right = right + steps;
		//~ }
		
		//~ if(vl == 5 || vl == 40){
			//~ falling = !falling;
		//~ }
		
		//_delay_us(100);
	}while(true);
}

inline void writeZero() {
	PORTC = 1;
	wait6;
	PORTC = 0;
	wait15;
}

inline void writeOne() {
	PORTC = 1;
	wait14;
	PORTC = 0;
	wait8;
}

void writeRGB(uint8_t red, uint8_t green, uint8_t blue) {
	int i;
	
	for( i = 128; i > 0; i >>= 1 ) {
		if( green & i ){
			writeOne();			
		} else {
			writeZero();
		}
	}
	
	for( i = 128; i > 0; i >>= 1 ) {
		if( red & i ){
			writeOne();			
		} else {
			writeZero();
		}
	}
	
	for( i = 128; i > 0; i >>= 1 ) {
		if( blue & i ){
			writeOne();			
		} else {
			writeZero();
		}
	}
}

void uart_init(void) {
    #define BAUDRATE ((F_CPU)/(BAUD*8UL)-1) // set baud rate value for UBRR
    UBRR0H = (BAUDRATE>>8);  // shift the register right by 8 bits to get the upper 8 bits
    UBRR0L = BAUDRATE & 0xff;       // set baud rate
	
	// UCSR0A |= (1 << U2X0);   // double transmission speed
	// UCSR0B = (1 << TXEN0) | (1 << RXEN0);
    // UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
    
	// UBRR0H = UBRRH_VALUE;
    // UBRR0L = UBRRL_VALUE;
    

	UCSR0A |= _BV(U2X0);
	// UCSR0A &= ~(_BV(U2X0));


    // UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0C = 0x06; /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0);   /* Enable RX and TX */    
}


void writeNothing(uint8_t c){
	for(uint8_t i = 0; i < c; i++){
		writeRGB(0,0,0);
	}
	_delay_ms(500);
}

void mydelay(uint16_t ms) {
	while(ms--) {
		_delay_loop_2(5000); // 1ms
	}
}
