/*	paris.c
 *
 *	Paris 3 LED lamp mod
 *	for Atmel 4433 or mega8 microcontrollers
 *
 *	(c) 2003 by daduke <daduke@daduke.org>
 *
 *	GPL license - use at your own risk
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#define LENGTH 43
#define LEDS 8
#define STEPS 10

volatile void set_led(uint8_t led);
volatile void del_led(uint8_t led);
volatile uint8_t get_phase(uint8_t led);

volatile uint8_t i;		//led counter
volatile uint8_t ctr;	//loop counter
volatile uint8_t keyctr;	//key counter

volatile uint8_t pwm[LEDS];
volatile uint8_t phase[LEDS];
volatile uint8_t phase_f[LEDS];
volatile uint8_t speed[LEDS];
static uint8_t table[LENGTH+1] = {1, 2, 3, 4, 5, 6, 8, 10, 11, 13, 16, 18, 21, 24, 28, 31, 35, 40, 44, 49, 55, 60, 66, 73, 80, 87, 95, 103, 111, 121, 130, 140, 151, 162, 173, 185, 198, 211, 225, 240, 255, 255, 255};
const static uint8_t speeds[STEPS] = {0, 12, 18, 26, 37, 79, 128, 129, 130, 255};


SIGNAL (SIG_OVERFLOW0)	//generates 16'000 interrupts/sec
{
			for (i=0; i < LEDS; i++) {	//for each LED
					  if (ctr == pwm[i]) {	//if time has come
								 set_led(i);	//turn it on
					  }
			}

			if (++ctr == 255) { 	//62.5 times a second
					  ctr = 0;
					  outp(0, PORTD);	//all LEDs are turned off
					  for (i=0; i < LEDS; i++) {
								pwm[i] = get_phase(i);
								if (speed[i] == 0) {
										  pwm[i] = 255;
								} else if (speed[i] == STEPS-1) {
										  pwm[i] = 0;
								}
					  }
					  keyctr++;
			}
}


volatile int main( void )
{
	uint8_t old, byte, in;

	outp(0xFF,DDRD);    /* use all pins on PORTD for output: 8 LEDs */
	outp(0x00,DDRC);    /* use PORTC for input */
	outp(0x00,DDRB);    /* use PORTB for input */

	outp(1,TCCR0);    /* prescale clk/1 */
	outp((1<<TOIE0),TIMSK); /* enables the T/C0 overflow interrupt in the T/C interrupt mask register for */
	outp(0,TCNT0);    /* start value of T/C0 */

	speed[0] = 2;
	speed[1] = 4;
	speed[2] = 3;
	speed[3] = 5;
	speed[4] = 1;
	speed[5] = 2;
	speed[6] = 5;
	speed[7] = 3;

	phase[0] = 0;
	phase[1] = 14;
	phase[2] = 49;
	phase[3] = 21;
	phase[4] = 31;
	phase[5] = 58;
	phase[6] = 2;
	phase[7] = 38;

	ctr = 0;
	table[LENGTH] = 255;

	sei();    /* set global interrupt enable */

	while(1) {	//main loop
			  in = inp(PINB);
			  byte = old ^ in;
			  for (old=0; old<3; old++) {
						 if (byte == 1<<old) {
									  if (keyctr > 15) {
												 if (++speed[old] == STEPS) speed[old] = 0;
									  } else {
												 if (++speed[0] == STEPS) speed[0] = 0;
												 speed[1] = speed[0];
												 speed[2] = speed[0];

											    phase[0] = 0;
											    phase[1] = LENGTH*2/3;
											    phase[2] = LENGTH*4/3;
									  }
									  keyctr = 0;
						 }
			  }
			  old = in;

			  for (in=0; in<255; in++) {	//wait some
						 byte = in * in;
			  }
	}
}

volatile void set_led(uint8_t led) {	//turn on led
		  sbi(PORTD, led);
}

volatile void del_led(uint8_t led) {	//turn off led
		  cbi(PORTD, led);
}

volatile uint8_t get_phase(uint8_t led) {
	uint16_t lphase, out;

	lphase = phase_f[led];	//fractional part of phase
	if (speeds[speed[led]] <= 127) {
			  lphase += speeds[speed[led]];	//increase by speed
			  if (lphase > 254) {		//when full,
						 phase_f[led] = 0;	//reset and
						 phase[led]++;		//inc integer part
			  } else {
						 phase_f[led] = lphase;	//otherwise continue
			  }
	} else {
			  phase[led] += (speeds[speed[led]] - 127);		//inc integer part
	}


	if (phase[led] >= 2*LENGTH) phase[led] = 0;	//reset integer part when full

	lphase = phase[led];	//get integer and
	out = phase_f[led];	//fractional part of phase
	if (lphase < LENGTH) {	//first half of cycly
			  out = 255 - ( (table[lphase]*(255-out)) + (table[lphase+1]*out) )/255;	//linear interpolation
	} else {					//sencond half
			  out = 255 - ( (table[2*LENGTH-1 - lphase]*out) + (table[2*LENGTH - lphase]*(255-out)) )/255;
	}

	return out;
}
