// Clapper RVB pour ATTiny25 8MHz
// CC furrtek.org 2013

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile uint8_t maxr,maxg,maxb,curr,curg,curb,pwm,pc,to,vb,music;

#define CLAP_HIGH	560
#define CLAP_LOW	540

uint16_t get_adc() {
	uint16_t value;
	ADCSRA |= (1 << ADSC);
	while (ADCSRA & (1 << ADSC)); 
	value = ADCW;
	ADCSRA |= (1 << ADSC);
	while (ADCSRA & (1 << ADSC));
	return ADCW;
}

uint16_t get_mean() {
	uint8_t c;
	uint16_t vm=0;

	for (c=0;c<32;c++) { 	
		vm += get_adc();
		_delay_us(10);
	}
	return vm>>5;
}

ISR(TIMER1_OVF_vect) {
	to++;
	if (to == 2) pc = 0;			// 1.048 secondes de timeout
}

ISR(TIMER0_OVF_vect) {
	uint8_t va;

	if (!pwm) {
		// Tout allumer
		vb = (_BV(PB0) | _BV(PB1) | _BV(PB2));
		if (music) {
			va = get_adc()>>3;
			if (va > 55) 
				curg = ((va-55)*8);	// A ajuster selon l'ampli micro
			else
				curg = 0;
			if (va > 55)
				curb = ((va-55)*8);
			else
				curb = 0;
		}
	}

	// Eteindre en fonction des valeurs PWM
	if (pwm >= curr)
		vb &= ~_BV(PB2);
	if (pwm >= curg)
		vb &= ~_BV(PB1);
	if (pwm >= curb)
		vb &= ~_BV(PB0);

	PORTB = vb;		// Tout mettre a jour en meme temps

	pwm++;
}

int main(void) {
	uint8_t pulse = 0;
	uint8_t times[4];
	uint16_t v;

	WDTCR = (1<<WDCE) | (1<<WDE);	// Watchdog desactive
	WDTCR = 0x00;

	DDRB = 0b00000111;				// Sorties R, V, B

	PORTB = 0b00000000;

	ADMUX = 2;
	ADCSRA = 0b10000011;			// Lecture analogique sur ADC3

	TCCR0A = 0;
	TCCR0B = 0b00000001;			// Timer PWM

	TCCR1 = 0b00001111;
	GTCCR = 0;
	TIMSK = 0b00000110;				// Timer mesure de temps

	sei();

	for (;;) {
		if ((!pulse)) {
			if (get_mean() > CLAP_HIGH) {	// Hysteresis haut, detection de clap
				pulse = 1;
				if (pc > 0) {
					v = (uint16_t)TCNT1+(256*to);
					if (v > 256)
						times[pc-1] = 1;	// Determination clap long/court
					else
						times[pc-1] = 0;
				}
				to = 0;
				TCNT1 = 0;

				pc++;

				if (pc == 2) {
					if (times[0])	// Premier ecart
						music = 1;
					else
						music = 0;
				}

				if (pc == 3) {
					if (times[1])	// Deuxieme
						maxr = 0x0;
					else
						maxr = 0xFF;
				}

				if (pc == 4) {
					if (times[2])	// Troisieme
						maxg = 0x0;
					else
						maxg = 0xFF;
				}

				if (pc == 5) {
					if (times[3])	// Quatrieme
						maxb = 0x0;
					else
						maxb = 0xFF;
					pc = 0;
				}
			}
		} else {
			if (get_mean() < CLAP_LOW) {	// Hysteresis bas
				pulse = 0;
			}
		}

		if (!music) {
			if (curr > maxr) curr--;		// Ajustement progressif
			if (curg > maxg) curg--;
			if (curb > maxb) curb--;
			if (curr < maxr) curr++;
			if (curg < maxg) curg++;
			if (curb < maxb) curb++;
		}
		_delay_ms(5);
	}
}
