/*
    Title:    Countdown Timer
    Author:   Daniel Schramm
    Date:     3/2002
    Purpose:  Timer up to 9min 59sec
    needed
    Software: AVR-GCC
    needed
    Hardware: ATMega8 on selfmade board
    Note:     To contact me, mail to
                  daniel.schramm@gmx.de
*/

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


/*    hex
 * 0: 0x40 
 * 1: 0x79
 * 2: 0x24
 * 3: 0x30
 * 4: 0x19
 * 5: 0x12
 * 6: 0x02
 * 7: 0x78
 * 8: 0x00
 * 9: 0x10
 * _: 0x77
 * r: 0x2f
 * d: 0x21
 * y: 0x11
 * off:	0x7f
*/

const uint8_t symbol[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x77,0x2f,0x21,0x11,0x7f};
const uint8_t position[]={0xf8,0xf4,0xec,0xdc};
//const uint8_t position[4]={0x07,0x0B,0x0D,0x0E,}; (fuer PNP statt NPN)

uint8_t TOP=0;
uint8_t BOTTOM=0;
uint8_t relais=0x03;

struct display_t{
	uint8_t val[4];
	uint8_t position;
	uint8_t cursor;
	uint8_t counter;
	uint8_t blinkstatus;
	uint8_t blink;
};


struct display_t display;
uint8_t key[8];
uint8_t newkey[8];

uint16_t time;
uint8_t done;
uint8_t material;


void time2display(void) {
	uint16_t rest;
	display.val[0]=time/60;
	rest=time%60;
	display.val[1]=rest/10;
	rest=rest%10;
	display.val[2]=rest;
}

void display2time(void) {
	time=display.val[0]*60 + display.val[1]*10 +display.val[2];
}


void eeprom_read(uint8_t section) {
	while ( ! eeprom_is_ready() );
	time=eeprom_read_word((uint16_t *)(section*2));
	time2display();

}

void eeprom_write(uint8_t section) {
	while ( ! eeprom_is_ready() );
	eeprom_write_word((uint16_t *)(section*2),time);
	while ( ! eeprom_is_ready() );
}

void sleep (void) {
	uint8_t i;
	for (i=0; i<255; i++) {
		asm volatile("nop");
	}
}

void longsleep (void) {
	uint16_t j;
	for (j=0; j<3000; j++) {
		sleep();
	}
}

void init (void) {
	UCSRA=0x00;
	UCSRB=0x00;
	UCSRC=0x80;
	outp (0xff, DDRB);
	outp (0xff, DDRC);
	outp (0xff, DDRD);
	outp(0xff,PORTB);
	outp(0xdf,PORTC);
	outp(0xff,PORTD);
	display.position=0;
	display.cursor=2;
	display.counter=0;
	display.blinkstatus=0;
	display.blink=0;
//	display2time();
	eeprom_read(0);
	done=0;
	TOP=0;
	BOTTOM=0;
	material=0;
	relais=0x03;
}




void clock_init(void) {
// Sekundentakt
   ASSR=(1<<AS2);
   TCCR2=0x07;
   TCNT2=0;
   OCR2=32;
   TIMSK|=(1<<OCIE2);
   sei();
}

SIGNAL (SIG_OUTPUT_COMPARE2)
{
	TCNT2=0;
	time--;
	time2display();
	if (time==0) {
		done=1;
		BOTTOM=0;
		TOP=0;
		relais=0x03;
		TIMSK=0;  // clock off
		display.val[0]=11;
		display.val[1]=12;
		display.val[2]=13;
		sei();
	}
}

                     

void update_display (void) {
	uint8_t s;

	outp (0xff, DDRB);
	outp (0xff, DDRC);
	outp (0xff, DDRD);
	outp(0xff,PORTB);
	outp(0xdc | relais,PORTC);
	outp(0xff,PORTD);
	
	display.position++;
	if (display.position > 3)
		display.position = 0;
	
	outp(position[display.position] | relais ,PORTC);

	if ( display.position==3) {
		if ( BOTTOM && TOP )
			s=0x08;
		else if ( BOTTOM )
			s=0x20;
		else if ( TOP )
			s=0x01;
		else
			s=0x00;
		if ( material==0 )
			s|=0x04;
		else if ( material==1 )
			s|=0x02;
		else if ( material==2 )
			s|=0x10;
		PORTD=~s;
		// Status LEDs
	} else {
		if ( display.blink )
			if ( display.position == display.cursor ) {
				display.counter++;
				if (display.counter > 200) {
					if ( display.blinkstatus == 1)
					 	display.blinkstatus=0;
					else
						display.blinkstatus=1;
					display.counter = 0;
				}
				if ( display.blinkstatus == 1) {
					if (display.position==0)
						outp(symbol[10],PORTD);
					else
						outp(symbol[10]|0x80,PORTD);
					return;
				}
			}
		if (display.position==0)
			outp(symbol[display.val[display.position]],PORTD);
		else
			outp(symbol[display.val[display.position]]|0x80,PORTD);
	}
	
}

/*
void check_keyboard(void) {
	uint8_t read;
	oldkey=newkey;
	read=inp(PINB);
	
	if (read & 0x20)
		newkey.cursor=0;
	else
		newkey.cursor++;
	if (read & 0x40)
		newkey.set=0;
	else
		newkey.set++;
	if (read & 0x80)
		newkey.start=0;
	else
		newkey.start++;

	
	if ( (! newkey.cursor) && ( oldkey.cursor > 5 ))
		key.cursor=1;
	else
		key.cursor=0;
		
	if ( (! newkey.set) && ( oldkey.set > 5 ))
		key.set=1;
	else
		key.set=0;
	if ( (! newkey.start) && ( oldkey.start > 5 ))
		key.start=1;
	else
		key.start=0;
}
*/

void read_keyboard(void) {
	uint8_t input, i;
	DDRD=0x00;
	PORTD=0xff;
	PORTC=0xfc | relais;
	PORTB=0xfe;
	sleep();
	input=~PIND;
	
	if ( input ) {
		for (i=0; i<8; i++)
			if ( input  & (1<<i)  ) {
				newkey[i]++;
			} else
				newkey[i]=0;
	} else {
		for (i=0; i<8; i++) {
			if (newkey[i]>1) { // tastendruck merken, zurueckgesetzt wird in der bearbeitung
				key[i]=1;
				newkey[i]=0;
			}
		}
	}
}

	
void process_keyboard(void) {
	uint8_t i;
	uint8_t keypressed;

	if ( done ) {
		keypressed=0;
		for (i=0; i<8; i++) {
			keypressed+=key[i];
			key[i]=0;
		}
		if ( keypressed > 0 ) {
			done=0;
			eeprom_read(material);
		}
	} else if ( TOP || BOTTOM ) {
		for (i=0; i<8; i++)
			key[i]=0;
	} else {
		if ( key[2] ) {  // material 0
			for (i=0; i<8; i++)
				key[i]=0;
			material=0;
			eeprom_read(material);
		}
		if ( key[1] ) {  // material 1
			for (i=0; i<8; i++)
				key[i]=0;
			material=1;
			eeprom_read(material);
		}
		if ( key[4] ) {  // material 2
			for (i=0; i<8; i++)
				key[i]=0;
			material=2;
			eeprom_read(material);
		}
		
		
		
		if ( key[0] ) {  // Start TOP
			for (i=0; i<8; i++)
				key[i]=0;
			TOP=1;
			relais=0x02;
			display.blink=0;
			eeprom_write(material);
			clock_init();
		}
		if ( key[3] ) {  // Start BOTH
			for (i=0; i<8; i++)
				key[i]=0;
			TOP=1;
			BOTTOM=1;
			relais=0x00;
			display.blink=0;
			eeprom_write(material);
			clock_init();
		}
		if ( key[5] ) {  // Start BOTTOM
			for (i=0; i<8; i++)
				key[i]=0;
			BOTTOM=1;
			relais=0x01;
			display.blink=0;
			eeprom_write(material);
			clock_init();
		}

			
		if ( key[6] ) {  // change value
			for (i=0; i<8; i++)
				key[i]=0;
			
			if ( display.blink) {
				display.val[display.cursor]++;
				if ( display.cursor == 1 ) {
					if ( display.val[display.cursor] > 5 )
						display.val[display.cursor]=0;
				} else {
					if ( display.val[display.cursor] > 9 )
						display.val[display.cursor]=0;
				}
				display2time();
			}
		}
		if ( key[7] ) {  // cursor
			for (i=0; i<8; i++)
				key[i]=0;

			display.cursor++;
			display.blink=1;
			if ( display.cursor > 2 )
				display.cursor=0;
		}
	}

}



int main(void) {
	uint8_t j;
	
	init();
	while (1) {
		read_keyboard();
		process_keyboard();
	
		for (j=0;j<15;j++) {   // slow down keyboard 
			update_display();
			sleep();
		}
	}
}


