/*ooooooooooooooooooooooooooooooooooooooooooo
oooooooooo                         oooooooooo
oooooooooo  PROGRAM: tinyCLOCK     oooooooooo
oooooooooo  Version: 1.0           oooooooooo
oooooooooo  SOLARSKI (C) 2006/07   oooooooooo
oooooooooo  solarskit.wz.cz        oooooooooo
oooooooooo  solarskit@gmail.com    oooooooooo
oooooooooo  ATtiny26L-8PI          oooooooooo
oooooooooo  XTAL = 4,0000MHz       oooooooooo
oooooooooo  t = 250ns              oooooooooo
oooooooooo                         oooooooooo
ooooooooooooooooooooooooooooooooooooooooooooo*/

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

#define				minSetDelay 100				// opakovaci cas pri nastaveni minut [ms]
#define				hourSetDelay 125			// opakovaci cas pri nastaveni hodin [ms]

// cislice
//const uint8_t		digit[ 10 ] = { 0b01010000 , 0b01011111 , 0b00110010 , 0b00010110 , 0b00011101 , 0b10010100 , 0b10010000 , 0b01011100 , 0b00010000 , 0b00010100 };
const uint8_t		digit[ 10 ] = { 0b00101000 , 0b01101111 , 0b01011000 , 0b01001010 , 0b00001111 , 0b10001010 , 0b10001000 , 0b00101110 , 0b00001000 , 0b00001010 };

volatile uint16_t	waitCt = 0;					// citac pro prodlevu mezi cislicemi

volatile uint8_t	hourSetF = 0;				// priznak povoleni nastaveni hodin
volatile uint16_t	hourSetCt = 0;				// citac pro prodlevu u nastaveni hodin

volatile uint8_t	minSetF = 0;				// priznak povoleni nastaveni minut
volatile uint16_t	minSetCt = 0;				// citac pro prodlevu u nastaveni munut

// citace casu
volatile uint16_t	msec = 0;					// milisekundy
volatile uint8_t	sec = 0;					// sekundy
volatile uint8_t	min = 0;					// minuty
volatile uint8_t	hour = 0;					// hodiny

//---------------------------------------------------------------------- >> Zpozdovaci procedura <<

void delay ( uint32_t time )
{
	while ( time-- );
}

//---------------------------------------------------------------------- >> Zpozdovaci procedura <<
// zpozdeni pro zobrazovani na displeji - doba kdy sviti jedna cislice na 7seg displeji
void wait ( void )
{
	waitCt = 0;									// vynulovani citace
	while ( waitCt < 5 );						// cekat
}

//---------------------------------------------------------------------- >> Nastaveni hodin <<

void hourSet( void )
{
		DDRB  &= 0b11111101;					// nastaveni pinu jako vstup
		PORTB |= 0b00000010;					// pull-up

		delay( 1 );								// nutna prodleva - ustaleni prechodoveho deje

		// pokud je na pinu L a soucasne je povoleno nastaveni hodin
		if ( !( PINB & 0b00000010 ) && hourSetF )
		{
			hourSetF = 0;						// docasne se nastaveni hodin zakaze
			hourSetCt = 0;						//  a vynuluje se citac
			hour++;								// inkrement hodin
			if ( hour >= 24 )					// nelze nastavit vetsi cislo nez 23
				hour = 0;
		}

		if ( hourSetCt > hourSetDelay )					// po teto dobe se muze znova nastavovat hodiny
			hourSetF = 1;

		delay( 1 );

		// navrat do puvodniho stavu
		DDRB  |= 0b00000010;
		PORTB &= 0b11111101;
}

//---------------------------------------------------------------------- >> Nastaveni minut <<

void minSet( void )
{
		DDRB  &= 0b11111011;
		PORTB |= 0b00000100;

		delay( 1 );

		if ( !( PINB & 0b00000100 ) && minSetF )
		{
			minSetF = 0;
			minSetCt = 0;

			min++;
			sec = 0;							// jen pri nastaveni minut se nuluje citace sekund a milisekund
			msec = 0;

			if ( min >= 60 )
				min = 0;
		}

		if ( minSetCt > minSetDelay )
			minSetF = 1;

		delay( 1 );

		DDRB  |= 0b00000100;
		PORTB &= 0b11111011;
}

//====================================================================== >> HLAVNI FUNKCE MAIN <<

int main( void )
{

//---------------------------------------------------------------------- >> I/O PORTY <<
	//0 - VSTUP, 1 - VYSTUP

	DDRA	= 0b11111111;
	PORTA	= 0b11111111;

	DDRB	= 0b00001111;
	PORTB	= 0b00000000;

//---------------------------------------------------------------------- >> T/C1 <<

	TCCR1B |= ( 1 << CTC1 );					// clear timer on compare match
	// CLK / 16
	TCCR1B |= ( 0 << CS13 ) | ( 1 << CS12 ) | ( 0 << CS11 ) | ( 1 << CS10 );
	OCR1C = 249;								// 1ms
	TIMSK |= ( 1 << TOIE1 );

	sei();

	while( 1 )
	{

		PORTA = 0xFF;							// kvuli prepinani cislic se cislice zhasne
		PORTB &= 0b11110000;					// vsechny vypnout
		PORTB |= 0b00001000;					// zapne se jen zobrazanu desitek hodin

		if ( ( hour / 10 ) >= 1 )				// kdyz je 0 tak se nezobrazi
			PORTA = digit[ hour / 10 ];

		minSet();								// nastaveni munut

		wait();									// doba po kterou vzdy sviti jen jedna cislice

		PORTA = 0xFF;
		PORTB &= 0b11110000;
		PORTB |= 0b00000100;					// jednotky hodin
		PORTA = digit[ hour % 10 ];

		if ( sec % 2 )							// blikani desetinne tecky mezi hodinami a minutami
			PORTA &= 0b11110111;
		else
			PORTA |= 0b00001000;

		hourSet();								// nastaveni hodin

		wait();

		PORTA = 0xFF;
		PORTB &= 0b11110000;
		PORTB |= 0b00000010;					// desitky minut
		PORTA = digit[ min / 10 ];

		wait();

		PORTA = 0xFF;
		PORTB &= 0b11110000;
		PORTB |= 0b00000001;					// jednotky minut
		PORTA = digit[ min % 10 ];

		wait();

	}

	return 0;

}

//---------------------------------------------------------------------- >> preruseni/signal od T/C1 <<
// citace inkrementuji kazdou 1ms a ztoho je odvozeno i pocitani casu
SIGNAL ( SIG_OVERFLOW1 )
{

	waitCt++;
	hourSetCt++;
	minSetCt++;

	if ( ++msec >= 1000 )						// 1000ms = 1s
	{
		msec = 0;
		if ( ++sec >= 60 )						// 60s = 1min
		{
			sec = 0;
			if ( ++min >= 60 )					// 60min = 1hod
			{
				min = 0;
				if ( ++hour >= 24 )				// 24hod
					hour = 0;
			}
		}
	}

}
