/*
 * MoonLamp.c
 *
 * Created: 29.04.2012 16:12:53
 *  Author: Trol
 */ 

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

uint8_t currentColor[3];
uint8_t startColor[3];
uint8_t nextColor[3];

#define currentR currentColor[0]
#define currentG currentColor[1]
#define currentB currentColor[2]
#define startR startColor[0]
#define startG startColor[1]
#define startB startColor[2]
#define nextR nextColor[0]
#define nextG nextColor[1]
#define nextB nextColor[2]


uint16_t tickBeforeChange;

#define TIMER_FREQUENCY	9600000
#define TIMER_OVERFLOW_FREQUENCY	(TIMER_FREQUENCY/0xff)


static uint8_t calculateColor(uint8_t from, uint8_t to, uint16_t tm);
static void calcNextPoint();


/** 
 * Timer overflow interrupt. Used for PWM implementation
 * Called with TIMER_OVERFLOW_FREQUENCY frequency 
 */
ISR(TIM0_OVF_vect){
	static uint8_t cnt_0 = 0;		// PWM counter
	static uint16_t cnt_1 = 0;		// counter for next color recalculation
	
	if ( cnt_0 == 0 ) {
		// recalculate bright
		currentR = calculateColor(startR, nextR, cnt_1);
		currentG = calculateColor(startG, nextG, cnt_1);
		currentB = calculateColor(startB, nextB, cnt_1);
		
		cnt_1++;
		if ( cnt_1 >= tickBeforeChange ) {
			cnt_1 = 0;
			calcNextPoint();
		}
	}
	
	// update channels
	uint8_t output = 0;
	if ( currentR >= cnt_0 ) {
		output |= _BV(0);
	}
	if ( currentG >= cnt_0 ) {
		output |= _BV(1);
	}
	if ( currentB >= cnt_0 ) {
		output |= _BV(2);
	}
	PORTB = output; 
	
	cnt_0++;
}


static uint8_t calculateColor(uint8_t from, uint8_t to, uint16_t tm) {
	uint32_t percent = 0xff;
	percent *= tm;
	percent /= tickBeforeChange;

	int res = from + (to - from) * percent / 0xff;
	return (uint8_t)res;
}

static uint8_t rndColor() {
	return 30 + (random() % 220);
}

static void calcNextPoint() {
	startR = nextR;
	startG = nextG;
	startB = nextB;

	nextR = rndColor();
	nextG = rndColor();
	nextB = rndColor();

	uint8_t rnd = random();



	uint8_t indx = rnd % 3;
	nextColor[indx] = 0;

	rnd = 30 + rnd % 120;	// time to change color, sec/10
	tickBeforeChange = (TIMER_OVERFLOW_FREQUENCY/0xff)*rnd/10;
}



int main(void) {
	nextR = 0;
	nextG = 0;
	nextB = 0;

	calcNextPoint();
	
	DDRB = 0xff;
	TCCR0B = _BV(CS00);		// disable prescaler for timer
	TIMSK0 = _BV(TOIE0);	// enable timer overflow interrupts
	sei();					// enable global interrupts

    while (1) {		
    }
}