#include<avr/io.h>
#include<util/delay.h>
#include <avr/interrupt.h>
void sleep(int millisec) {
	while(millisec)
	{
		_delay_ms(1);/* 1 ms delay */
		millisec--;
	}
}
/* ====================================
		TIMER
==================================== */
volatile unsigned int residus=0;
volatile unsigned int ms=0;
volatile unsigned short s=0;
volatile unsigned short mn=0;
volatile unsigned short h=0;
void clock_init(void) {
	TCCR0 |= (1<<CS00); /* This and below set clock0 to normal mode, prescalar 64 */
	TCCR0 |= (1<<CS01);
	TCCR0 &= ~(1<<CS02);

	TIMSK |= (1<<TOIE0); // Enables interrupt for timer 0 overflow
	sei(); //Enables interrupt globally
}

ISR (TIMER0_OVF_vect)  // timer 0 overflow interrupt
{
	// event to be executed every 16.384ms here
	residus += 384;
	if (residus>999) {
		residus -=1000;
		ms++;
	}
	ms += 16;
	if (ms>999) {
		ms-=1000;
		s++;
	}
	if (s>59) {
		s-=60;
		mn++;
	}
	if (mn>59) {
		mn-=60;
		h++;
	}
	if (h>23) {
		h-=24;
	}


}

/* ====================================
	AFFICHEUR 7 SEGMENTS
==================================== */
unsigned short give_bin(unsigned short chiffre) {
	if (chiffre==8){ 
		return 0b00100000;
	} else if (chiffre==0) {
		return 0b00100100;
	} else if (chiffre==1) {
		return 0b11101101;
	} else if (chiffre==2) {
		return 0b00111000;
	} else if (chiffre==3) {
		return 0b01101000;
	} else if (chiffre==4) {
		return 0b11100001;
	} else if (chiffre==5) {
		return 0b01100010;
	} else if (chiffre==6) {
		return 0b00100010;
	} else if (chiffre==7) {
		return 0b11101100;
	} else if (chiffre==9) {
		return 0b01100000;
	} else if (chiffre==10) {
		return 0b10100000;
	}
	return 0xFF;
}

void write_bin(unsigned char bin) {
	if (bin & 1) { PORTC |= (1<<PC0); } else { PORTC &=~(1<<PC0); }
	if (bin & (1<<1)) { PORTC |= (1<<PC1); } else { PORTC &=~(1<<PC1); }
	if (bin & (1<<2)) { PORTC |= (1<<PC2); } else { PORTC &=~(1<<PC2); }
	if (bin & (1<<3)) { PORTC |= (1<<PC3); } else { PORTC &=~(1<<PC3); }
	if (bin & (1<<4)) { PORTC |= (1<<PC4); } else { PORTC &=~(1<<PC4); }
	if (bin & (1<<5)) { PORTC |= (1<<PC5); } else { PORTC &=~(1<<PC5); }
	if (bin & (1<<6)) { PORTD |= (1<<PD0); } else { PORTD &=~(1<<PD0); }
	if (bin & (1<<7)) { PORTD |= (1<<PD1); } else { PORTD &=~(1<<PD1); }
}
void affiche_chiffre(unsigned short chiffre, unsigned short dot) {
	// dot = 0 : pas de dot, dot=1 on affiche le dot, dot=2 j'affiche 2 dots.
	// "chiffre" doit etre entre 00 et 99
	unsigned short dizaines;
	unsigned short unite;
	if (chiffre>99) {
		dizaines = 10;
		unite=10;
	} else {
		dizaines = chiffre/10;
		unite = chiffre-10*dizaines;
	}
	unsigned int i;
	unsigned short res;
	for (i=0; i<990/10;i++) {
		PORTD |= (1<<PD2);
		PORTD &= ~(1<<PD3);
		res = give_bin(dizaines);
		if (dot==2)
			res &= ~(0b00100000);
		write_bin(res);
		sleep(5);
		
		PORTD |= (1<<PD3);
		PORTD &= ~(1<<PD2);
		res = give_bin(unite);
		if (dot>0)
			res &= ~(0b00100000);
		write_bin(res);
		sleep(5);
	}
	PORTD &= ~(1<<PD3);
}


/* ====================================
	MAIN
==================================== */

/* Cablage :
 * = 7 segments de haut gauche a bas droite branches sur PC0-5 puis PD0,1,2,3
 * = Lumieres branches respectivements dur PD5,6,7
 * = Bouton poussoire pour regler l'heure branche (avec pull-down) sur PD4
 */

main() {
	
	DDRC |= (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) ; /*outputs pour le 7 segments*/
	DDRD |= (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3);
	
	DDRD |= (1<<PD5) | (1<<PD6) | (1<<PD7); /* Lights */

	DDRD &= ~(1<<PD4); /* Clock setting */
	PORTD |= (1<<PD4); //pull up resistance 

	//PORTD |= (1<<PD5) | (1<<PD6) | (1<<PD7); /* Turn the lights on */

	clock_init();

	unsigned short mn_inc=1; //increment de minutes lors d'une pression
			
	while(1) {

		//Verification de demande de reglage d'heure
		if ((PIND & (1<<PD4) ) == 0) {
			if (mn_inc<5)
				mn++;
			else
				mn+=10;
			mn_inc++;
			if (mn_inc>10)
				mn_inc=10;
			affiche_chiffre(mn,2);
			//sleep(500);
			affiche_chiffre(mn,0);
			//sleep(1000);
		} else {
			//J'affiche l'heure puisqu'on ne demande pas de la regler.
			mn_inc=1;
			affiche_chiffre(h,0);
			//sleep(1000);
			affiche_chiffre(mn,1);
			//sleep(1000);
			affiche_chiffre(s,2);
			sleep(5000);
		}
		if ((h>7) && (h<20)) {
			PORTD |= (1<<PD5) | (1<<PD6) | (1<<PD7); /* Turn the lights on */
		} else {
			PORTD &= ~ ((1<<PD5) | (1<<PD6) | (1<<PD7)); /* Turn the lights off */
		}
	}
}
