/*
 * Wecker1.0.c
 *
 * Created: 24.04.2016 14:33:16
 * Author : Tristan
 * notes:	-all buttons must be connected to ground (pullup-resistors are activated)
 *			-
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define F_CPU 1000000

#define LCD_LINES 2
#define MOVE_CURSOR_AFTER_CHARACTER 1
#define INCREMENT_1_OR_DECREMENT_CURSOR_AFTER_CHARACTER 0
#define _5x10_1_OR_5x7_0_DOTMATRIX 1

#define PORT_REG_RS_LCD PORTD
#define DIR_REG_RS_LCD DDRD
#define REG_NR_RS_LCD 7

#define PORT_REG_ENABLE_LCD PORTD
#define DIR_REG_ENABLE_LCD DDRD
#define REG_NR_ENABLE_LCD 6

#define PORT_REG_DATAPIN7_LCD PORTD
#define DIR_REG_DATAPIN7_LCD DDRD
#define REG_NR_DATAPIN7_LCD 4

#define PORT_REG_DATAPIN6_LCD PORTB
#define DIR_REG_DATAPIN6_LCD DDRB
#define REG_NR_DATAPIN6_LCD 6

#define PORT_REG_DATAPIN5_LCD PORTB
#define DIR_REG_DATAPIN5_LCD DDRB
#define REG_NR_DATAPIN5_LCD 7

#define PORT_REG_DATAPIN4_LCD PORTD
#define DIR_REG_DATAPIN4_LCD DDRD
#define REG_NR_DATAPIN4_LCD 5

//////////////////////////////////////////////////////////////////////////

#define REG_NR_BUT_UP 4
#define PIN_REG_BUT_UP PINC
#define PORT_REG_BUT_UP PORTC
#define DIR_REG_BUT_UP DDRC

#define REG_NR_BUT_DOWN 1
#define PIN_REG_BUT_DOWN PINC
#define PORT_REG_BUT_DOWN PORTC
#define DIR_REG_BUT_DOWN DDRC

#define REG_NR_BUT_LEFT 2
#define PIN_REG_BUT_LEFT PINC
#define PORT_REG_BUT_LEFT PORTC
#define DIR_REG_BUT_LEFT DDRC

#define REG_NR_BUT_RIGHT 5
#define PIN_REG_BUT_RIGHT PINC
#define PORT_REG_BUT_RIGHT PORTC
#define DIR_REG_BUT_RIGHT DDRC

#define REG_NR_BUT_ENTER 3
#define PIN_REG_BUT_ENTER PINC
#define PORT_REG_BUT_ENTER PORTC
#define DIR_REG_BUT_ENTER DDRC

#define DEBOUNCE_DELAY 30

#define PORT_REG_VDD_LCD PORTB
#define DIR_REG_VDD_LCD DDRB
#define REG_NR_VDD_LCD	0

#define PORT_REG_BL_LCD PORTD
#define DIR_REG_BL_LCD DDRD
#define REG_NR_BL_LCD	3

#define DIR_REG_DCF77_SIGNAL DDRD
#define PIN_REG_DCF77_SIGNAL PIND
#define PORT_REG_DCF77_SIGNAL PORTD
#define REG_NR_DCF77_SIGNAL 2

#define DIR_REG_DCF77_VDD DDRD
#define PIN_REG_DCF77_VDD PIND
#define PORT_REG_DCF77_VDD PORTD
#define REG_NR_DCF77_VDD 1

#define DIR_REG_CLOCK_GENERATOR_SIGNAL DDRB	//Interrupt!
#define PIN_REG_CLOCK_GENERATOR_SIGNAL PINB
#define PORT_REG_CLOCK_GENERATOR_SIGNAL PORTB
#define REG_NR_CLOCK_GENERATOR_SIGNAL 2

#define DIR_REG_CLOCK_GENERATOR_RESET DDRC
#define PORT_REG_CLOCK_GENERATOR_RESET PORTC
#define REG_NR_CLOCK_GENERATOR_RESET 0

#define DIR_REG_SPEAKER_OUT DDRB
#define PORT_REG_SPEAKER_OUT PORTB
#define REG_NR_SPEAKER_OUT 1

#define DIR_REG_RELAIS DDRD
#define PORT_REG_RELAIS PORTD
#define REG_NR_RELAIS 0

#define MAXIMUM_DECODING_TRIALS 3

volatile unsigned char current_time_second_unit = 0;
volatile unsigned char current_time_second_tenner = 0;
volatile unsigned char current_time_minute_unit = 0;
volatile unsigned char current_time_minute_tenner = 0;
volatile unsigned char current_time_hour_unit = 2;
volatile unsigned char current_time_hour_tenner = 1;

volatile unsigned char current_date_day_unit = 1;
volatile unsigned char current_date_day_tenner = 0;
volatile unsigned char current_date_month_unit = 1;
volatile unsigned char current_date_month_tenner = 0;
volatile unsigned char current_date_year_unit = 1;
volatile unsigned char current_date_year_tenner = 0;

volatile unsigned char current_weekday = 0;

volatile unsigned char alarm_time_minute_unit  = 0;
volatile unsigned char alarm_time_minute_tenner  = 0;
volatile unsigned char alarm_time_hour_unit = 0;
volatile unsigned char alarm_time_hour_tenner = 0;

volatile unsigned char snooze_time = 0;
volatile unsigned char snooze_time_counter = 0;

volatile unsigned char second0_timer_interrupt_counter = 0;
volatile unsigned char second0_timer_enabled = 0;
volatile unsigned char snooze_time_timer_enabled = 0;
volatile unsigned char ringing_enabled = 0;

volatile unsigned char standby_timer_interrupt_counter = 0;

volatile unsigned char button_up_state = 0;
volatile unsigned char button_down_state = 0;
volatile unsigned char button_left_state = 0;
volatile unsigned char button_right_state = 0;
volatile unsigned char button_enter_state = 0;

volatile unsigned char LCD_was_off_var_1 = 0;
volatile unsigned char LCD_was_off_var_2 = 0;

volatile unsigned char ringing_counter = 0;
volatile unsigned char start_ringing_flag = 0;
volatile unsigned char snooze_enabled_flag = 0;
volatile unsigned char initializing_time_flag = 0;
volatile unsigned char alarm_enabled = 0;
volatile unsigned char start_initialize_time = 0;

#include "Tristans_LCD_lib_4_bit.h"
#include <util/delay.h>
#include <avr/power.h>
#include <avr/wdt.h>

void home_menu ();
void select_menu ();
void alarm_menu ();
void settings_menu ();
void set_alarm_time ();
void set_snooze_time ();

void start_snooze_time_timer();
void stop_snooze_time_timer();

void start_standby_timer();
void stop_standby_timer();
void reset_standy_timer_interrupt_counter ();

void start_sleeping();
void start_ringing();
void initialize_time();
void wait_for_button_release();

int main(void)
{
	//setup for Ports
	//setting Inputs and Outputs
	DIR_REG_BUT_UP &= ~(0x01 << REG_NR_BUT_UP);
	DIR_REG_BUT_DOWN &= ~(0x01 << REG_NR_BUT_DOWN);
	DIR_REG_BUT_LEFT &= ~(0x01 << REG_NR_BUT_LEFT);
	DIR_REG_BUT_RIGHT &= ~(0x01 << REG_NR_BUT_RIGHT);
	DIR_REG_BUT_ENTER &= ~(0x01 << REG_NR_BUT_ENTER);
	
	DIR_REG_DCF77_SIGNAL &= ~(1<<REG_NR_DCF77_SIGNAL);
	PORT_REG_DCF77_SIGNAL &= ~(1<<REG_NR_DCF77_SIGNAL);
	DIR_REG_CLOCK_GENERATOR_SIGNAL &= ~(1<<REG_NR_CLOCK_GENERATOR_SIGNAL);
	DIR_REG_CLOCK_GENERATOR_RESET |= (1<<REG_NR_CLOCK_GENERATOR_RESET);
	PORT_REG_CLOCK_GENERATOR_RESET &= ~(1<<REG_NR_CLOCK_GENERATOR_RESET);
	
	DIR_REG_SPEAKER_OUT |= (1<<REG_NR_SPEAKER_OUT);
	PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
	DIR_REG_RELAIS |= (1<<REG_NR_RELAIS);
	PORT_REG_RELAIS &= ~(1<<REG_NR_RELAIS);
	
	DIR_REG_VDD_LCD |= (1<<REG_NR_VDD_LCD);
	DIR_REG_BL_LCD |= (1<<REG_NR_BL_LCD);
	
	//setting Pullups
	PORT_REG_BUT_UP |= (0x01 << REG_NR_BUT_UP);
	PORT_REG_BUT_DOWN |= (0x01 << REG_NR_BUT_DOWN);
	PORT_REG_BUT_LEFT |= (0x01 << REG_NR_BUT_LEFT);
	PORT_REG_BUT_RIGHT |= (0x01 << REG_NR_BUT_RIGHT);
	PORT_REG_BUT_ENTER |= (0x01 << REG_NR_BUT_ENTER);
	
	//setup for Timer 0 (detects second 0, ringing beat)
	TCCR0A = (1<<WGM01);	//setting operation mode to CTC
	OCR0A = 227;			//setting Output Compare Unit A
	TIMSK0 = (1<<OCIE0A);	//enabling interrupt for Output Compare Unit A, timer is started by a extra routine
	
	//setup for timer 1, who counts the snooze minutes (each Interrupt takes one minute at a frequency of 1 MHz
	TCCR1B |= (1<<WGM12);	//setting CTC mode
	OCR1AH = 0xE4;			//setting Output Compare Register A-> with the presclaer of 1024 it takes 60 seconds, to reach this
	OCR1AL = 0xE2;			//this value is equal to 58594
	TIMSK1 |= (1<<OCIE1A);	//enabling an Interrupt for Compare Register A
	
	//setting Pin Change Interrupts
	PCICR |= (1<<PCIE0) | (1<<PCIE1);
	PCMSK0 = 0x00;
 	PCMSK1 = 0x00;
	
	PCMSK0 |= (1<<PCINT2);	//clock
	PCMSK1 |= (1<<PCINT9) | (1<<PCINT10) | (1<<PCINT11) | (1<<PCINT12) | (1<<PCINT13);	//buttons
	
	sei();
	power_all_disable();
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	wdt_disable();
	
	//powering LCD and Backlight
	PORT_REG_VDD_LCD |= (1<<REG_NR_VDD_LCD);
	PORT_REG_BL_LCD |= (1<<REG_NR_BL_LCD);
	
	initialize_LCD_4bit();
	clear_display_LCD();
	return_home_LCD();
	display_on_off_control_LCD(1,0,0);
	initialize_time();
	home_menu();
}

void home_menu ()
{
	clear_display_LCD();
	return_home_LCD();
	display_on_off_control_LCD(1,0,0);
	start_standby_timer();
	while (1)
	{
		while (LCD_was_off_var_2)
		{
			start_sleeping();
			if (start_ringing_flag)
				break;
			if (start_initialize_time)
			{
				start_initialize_time=0;
				initialize_time();
				start_standby_timer();
			}
		}
		if (start_ringing_flag)
		{
			start_ringing();
			start_ringing_flag = 0;
		}		
		if (LCD_was_off_var_1)
		{
			initialize_LCD_4bit();
			clear_display_LCD();
			return_home_LCD();
			display_on_off_control_LCD(1,0,0);
			LCD_was_off_var_1 = 0;
			wait_for_button_release();
			start_standby_timer();
		}

		set_DDRAM_address_LCD(0x04);					//print time to the LCD
		write_data_to_LCD_as_byte(current_time_hour_tenner+48);
		write_data_to_LCD_as_byte(current_time_hour_unit+48);
		write_data_to_LCD_as_string(":");
		write_data_to_LCD_as_byte(current_time_minute_tenner+48);
		write_data_to_LCD_as_byte(current_time_minute_unit+48);
		write_data_to_LCD_as_string(":");
		write_data_to_LCD_as_byte(current_time_second_tenner+48);
		write_data_to_LCD_as_byte(current_time_second_unit+48);
		set_DDRAM_address_LCD(0x42);					//print date to the LCD
		if (current_weekday == 1)
			write_data_to_LCD_as_string("MON,");
		if (current_weekday == 2)
			write_data_to_LCD_as_string("TUE,");
		if (current_weekday == 3)
			write_data_to_LCD_as_string("WED,");
		if (current_weekday == 4)
			write_data_to_LCD_as_string("THU,");
		if (current_weekday == 5)
			write_data_to_LCD_as_string("FRI,");
		if (current_weekday == 6)
			write_data_to_LCD_as_string("SAT,");
		if (current_weekday == 7)
			write_data_to_LCD_as_string("SUN,");
		
		write_data_to_LCD_as_byte(current_date_day_tenner+48);
		write_data_to_LCD_as_byte(current_date_day_unit+48);
		write_data_to_LCD_as_string(".");
		write_data_to_LCD_as_byte(current_date_month_tenner+48);
		write_data_to_LCD_as_byte(current_date_month_unit+48);
		write_data_to_LCD_as_string(".");
		write_data_to_LCD_as_byte(current_date_year_tenner+48);
		write_data_to_LCD_as_byte(current_date_year_unit+48);
			
		if(button_up_state||button_down_state||button_left_state||button_right_state||button_enter_state)
		{
			if (snooze_enabled_flag)
			{
				wait_for_button_release();
				snooze_enabled_flag = 0;
			}
			else
			{
				stop_standby_timer();
				select_menu();
				clear_display_LCD();						//clear the LCD from older Data when it returns from select_menu
				return_home_LCD();
				display_on_off_control_LCD(1,0,0);
				wait_for_button_release();
				start_standby_timer();
			}
		}
		if (standby_timer_interrupt_counter == 19)
		{
			stop_standby_timer();
			start_sleeping();
		}
	}
}

void select_menu()
{
	unsigned char DDRAM_Adress = 0x00;
	
	return_from_funktion:						//LABEL!
	
	clear_display_LCD();
	set_DDRAM_address_LCD(0x01);
	display_on_off_control_LCD(1,0,0);				//clearing LCD settings from stuff from other functions
	
	write_data_to_LCD_as_string("alarm: ");
	if (alarm_enabled)
	{
		write_data_to_LCD_as_byte(alarm_time_hour_tenner+48);
		write_data_to_LCD_as_byte(alarm_time_hour_unit+48);
		write_data_to_LCD_as_byte(':');
		write_data_to_LCD_as_byte(alarm_time_minute_tenner+48);
		write_data_to_LCD_as_byte(alarm_time_minute_unit+48);
	
	}
	else
		write_data_to_LCD_as_string("OFF");
	set_DDRAM_address_LCD(0x41);
	
	write_data_to_LCD_as_string("settings");
	
	set_DDRAM_address_LCD(0x00);
	DDRAM_Adress = 0x00;
	display_on_off_control_LCD(1,0,1);
	
	wait_for_button_release();
	while (1)
	{
		if (button_up_state||button_down_state)
		{
			(DDRAM_Adress == 0x00)?(set_DDRAM_address_LCD(0x40), (DDRAM_Adress = 0x40)):(set_DDRAM_address_LCD(0x00), (DDRAM_Adress = 0x00));	//change the line, the cursor is blinking so that it is visible which menu point is selected
			wait_for_button_release();
		}
		if (button_left_state)	
			return;
		if (button_enter_state)
		{
			(DDRAM_Adress == 0x00) ? (alarm_menu()) : (settings_menu());
			goto return_from_funktion;				//GOTO!
		}
	}
}

void alarm_menu()
{
	unsigned char DDRAM_Adress = 0;
	
	clear_display_LCD();
	display_on_off_control_LCD(1,0,0);
	set_DDRAM_address_LCD(0x01);
	
	write_data_to_LCD_as_string("alarm:");
	set_DDRAM_address_LCD(0x0A);
	if (alarm_enabled)
	{
		write_data_to_LCD_as_byte(alarm_time_hour_tenner+48);
		write_data_to_LCD_as_byte(alarm_time_hour_unit+48);
		write_data_to_LCD_as_byte(':');
		write_data_to_LCD_as_byte(alarm_time_minute_tenner+48);
		write_data_to_LCD_as_byte(alarm_time_minute_unit+48);
	}
	else
		write_data_to_LCD_as_string("OFF  ");
	
	set_DDRAM_address_LCD(0x41);
	write_data_to_LCD_as_string("snooze:");
	set_DDRAM_address_LCD(0x4A);
	(ringing_enabled) ? (write_data_to_LCD_as_string("reset")) : (write_data_to_LCD_as_byte(snooze_time+48), write_data_to_LCD_as_string("min"));
	return_home_LCD();
	DDRAM_Adress = 0x00;
	
	display_on_off_control_LCD(1,0,1);
	
	wait_for_button_release();
	while (1)
	{		
		if (button_up_state || button_down_state)
		{
			(DDRAM_Adress == 0x00) ? (set_DDRAM_address_LCD(0x40),(DDRAM_Adress = 0x40)) : (return_home_LCD(),(DDRAM_Adress = 0x00));
			wait_for_button_release();
		}
		
		if (button_left_state)
			return;
		
		if (button_right_state && (DDRAM_Adress == 0x00))
		{
			set_DDRAM_address_LCD(0x0A);
			if (alarm_enabled)
			{
				alarm_enabled = 0;
				write_data_to_LCD_as_string("OFF  ");
			}
			else
			{
				alarm_enabled = 1;
				write_data_to_LCD_as_byte(alarm_time_hour_tenner+48);
				write_data_to_LCD_as_byte(alarm_time_hour_unit+48);
				write_data_to_LCD_as_byte(':');
				write_data_to_LCD_as_byte(alarm_time_minute_tenner+48);
				write_data_to_LCD_as_byte(alarm_time_minute_unit+48);
			}
			set_DDRAM_address_LCD(0x00);
			wait_for_button_release();
		}
		
		if (button_enter_state)
		{
			if (DDRAM_Adress == 0x00)
			{
				if (alarm_enabled)
					set_alarm_time();
			}
			else
			{
				if (ringing_enabled)
				{
					stop_snooze_time_timer();
					ringing_enabled = 0;
					return;
				}
				else
					set_snooze_time();
			}
			set_DDRAM_address_LCD(DDRAM_Adress);
			display_on_off_control_LCD(1,0,1);
			wait_for_button_release();
		}
	}
}

void settings_menu()
{
	clear_display_LCD();
	return_home_LCD();
	display_on_off_control_LCD(1,0,0);
	write_data_to_LCD_as_string(" initialize time");
	display_on_off_control_LCD(1,0,1);
	set_DDRAM_address_LCD(0x00);
	wait_for_button_release();
	while(1)
	{
		if (button_left_state)
			return;
		if (button_enter_state)
		{
			initialize_time();
			return;
		}
	}
}

void set_alarm_time()
{
	unsigned char button_was_pressed = 0;
	wait_for_button_release();
	while (1)
	{
		button_was_pressed = 0;
		if (button_enter_state)
			return;
		if (button_left_state)
		{
			alarm_time_minute_tenner--;
			button_was_pressed = 1;
		}
		if (button_right_state)
		{
			alarm_time_minute_tenner++;
			button_was_pressed = 1;
		}
		if (button_down_state)
		{
			alarm_time_hour_unit--;
			button_was_pressed = 1;
		}
		if (button_up_state)
		{
			alarm_time_hour_unit++;
			button_was_pressed = 1;
		}
		
		if ((alarm_time_minute_tenner > 5) && (alarm_time_minute_tenner<255))
		{
			alarm_time_minute_unit = 0;
			alarm_time_minute_tenner = 0;
		}
		
		if (alarm_time_minute_tenner == 255)
		{
			alarm_time_minute_unit = 0;
			alarm_time_minute_tenner = 5;
		}
		
		if ((alarm_time_hour_unit > 9) && (alarm_time_hour_unit < 255))
		{
			alarm_time_hour_unit = 0;
			alarm_time_hour_tenner++;
		}
		
		if (alarm_time_hour_unit == 255)
		{
			alarm_time_hour_unit = 9;
			alarm_time_hour_tenner--;
		}
		
		if ((alarm_time_hour_tenner > 1) && (alarm_time_hour_tenner < 255) && (alarm_time_hour_unit > 3) && (alarm_time_hour_unit < 255))
		{
			alarm_time_hour_unit = 0;
			alarm_time_hour_tenner = 0;
		}
		
		if (alarm_time_hour_tenner == 255)
		{
			alarm_time_hour_unit = 3;
			alarm_time_hour_tenner = 2;
		}
		
		display_on_off_control_LCD(1,0,0);	//disabling the cursor
		set_DDRAM_address_LCD(0x0A);
		
		write_data_to_LCD_as_byte(alarm_time_hour_tenner+48);
		write_data_to_LCD_as_byte(alarm_time_hour_unit+48);
		write_data_to_LCD_as_byte(':');
		write_data_to_LCD_as_byte(alarm_time_minute_tenner+48);
		write_data_to_LCD_as_byte(alarm_time_minute_unit+48);
		if (button_was_pressed)
			wait_for_button_release();
	}
}

void set_snooze_time()
{
	unsigned char button_was_pressed = 0;
	wait_for_button_release();
	while (1)
	{
		button_was_pressed = 0;
		if (button_up_state||button_right_state)
		{
			snooze_time++;
			button_was_pressed = 1;
		}
		
		if (button_down_state||button_left_state)
		{
			snooze_time--;
			button_was_pressed = 1;
		}
		
		if (button_enter_state)
		return;
		
		if ((snooze_time > 9) && (snooze_time < 255))
		snooze_time = 0;
		
		if (snooze_time == 255)
		snooze_time = 9;

		display_on_off_control_LCD(1,0,0);
		set_DDRAM_address_LCD(0x4A);
		write_data_to_LCD_as_byte(snooze_time+48);
		if (button_was_pressed)
			wait_for_button_release();
	}
}

void start_snooze_time_timer()
{
	power_timer1_enable();
	TCCR1B |= (1<<CS12)|(1<<CS10);	//using the 1024 prescaler and starting the timer
	snooze_time_timer_enabled = 1;
}

void stop_snooze_time_timer()
{
	TCCR1B &= ~(0x01 << CS12);
	TCCR1B &= ~(0x01 << CS10);
	snooze_time_timer_enabled = 0;
	snooze_time_counter = 0;
	power_timer1_disable();
}

void start_sleeping()
{
	if (!snooze_time_timer_enabled)
	{
		LCD_was_off_var_1 = 1;
		LCD_was_off_var_2 = 1;
		sei ();
		
		//disabling BOD
		MCUCR |= (0x01 << BODS)|(0x01  << BODSE);
		MCUCR |= (0x01 << BODS);
		MCUCR &= ~(0x01 << BODSE);
		
		//writing Ports to 0 to ensure that the power consumption of the LCD is zero
		PORT_REG_RS_LCD &= ~(1<<REG_NR_RS_LCD);
		PORT_REG_ENABLE_LCD &= ~(1<<REG_NR_ENABLE_LCD);
		PORT_REG_DATAPIN7_LCD &= ~(1<<REG_NR_DATAPIN7_LCD);
		PORT_REG_DATAPIN6_LCD &= ~(1<<REG_NR_DATAPIN6_LCD);
		PORT_REG_DATAPIN5_LCD &= ~(1<<REG_NR_DATAPIN5_LCD);
		PORT_REG_DATAPIN4_LCD &= ~(1<<REG_NR_DATAPIN4_LCD);
		
		//switching LCD off
		PORT_REG_VDD_LCD &= ~(1<<REG_NR_VDD_LCD);
		PORT_REG_BL_LCD &= ~(1<<REG_NR_BL_LCD);	
 		sleep_mode();
	}
}

void start_ringing()
{
	ringing_enabled = 1;
	
	ringing_counter = 0;
	PORT_REG_BL_LCD |= (1<<REG_NR_BL_LCD);
	PORT_REG_VDD_LCD |= (1<<REG_NR_VDD_LCD);
	initialize_LCD_4bit();
	clear_display_LCD();
	return_home_LCD();
	display_on_off_control_LCD(1,0,0);
	LCD_was_off_var_1 = 0;
	
	set_DDRAM_address_LCD(0x04);					//print time to the LCD
	write_data_to_LCD_as_byte(current_time_hour_tenner+48);
	write_data_to_LCD_as_byte(current_time_hour_unit+48);
	write_data_to_LCD_as_string(":");
	write_data_to_LCD_as_byte(current_time_minute_tenner+48);
	write_data_to_LCD_as_byte(current_time_minute_unit+48);
	write_data_to_LCD_as_string(":");
	write_data_to_LCD_as_byte(current_time_second_tenner+48);
	write_data_to_LCD_as_byte(current_time_second_unit+48);
	set_DDRAM_address_LCD(0x44);
	write_data_to_LCD_as_string("WAKE UP!");
	
	while (!(button_up_state || button_down_state || button_left_state || button_right_state || button_enter_state))
	{
		ringing_counter++;
		switch (ringing_counter)
		{
		case 1:
			PORT_REG_SPEAKER_OUT|=(1<<REG_NR_SPEAKER_OUT);
			break;
		case 10:
			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
			break;
		case 30:
			PORT_REG_SPEAKER_OUT|=(1<<REG_NR_SPEAKER_OUT);
			break;
		case 40:
			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
			break;
		case 60:
			PORT_REG_SPEAKER_OUT |= (1<<REG_NR_SPEAKER_OUT);
			break;
		case 70:
			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
			break;
		case 90:
			PORT_REG_SPEAKER_OUT |= (1<<REG_NR_SPEAKER_OUT);
			break;
		case 100:
			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
			break;
		case 150:
			second0_timer_interrupt_counter = 0;
			break;
		default:
			break;
		}
		_delay_ms(5);
	}
	PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
	wait_for_button_release();
}

void initialize_time()
{
	initializing_time_flag = 1;
	
	unsigned char received_time_minute_unit = 0;
	unsigned char received_time_minute_tenner = 0;
	unsigned char received_time_hour_unit = 0;
	unsigned char received_time_hour_tenner = 0;
	unsigned char received_date_day_unit = 0;
	unsigned char received_date_day_tenner = 0;
	unsigned char received_weekday = 0;
	unsigned char received_date_month_unit = 0;
	unsigned char received_date_month_tenner = 0;
	unsigned char received_date_year_unit = 0;
	unsigned char received_date_year_tenner = 0;
	
	unsigned char DCF77_decoding_bit_stead = 0;
	volatile unsigned char bit_value = 0;
	unsigned char parity_sum_minutes = 0;
	unsigned char parity_sum_hours = 0;
	unsigned char parity_sum_date = 0;
	
	unsigned char error_flag = 0;
	unsigned char decoding_trial_counter = 0;
	
	current_time_minute_unit = 0;
	current_time_minute_tenner = 0;
	current_time_hour_unit = 0;
	current_time_hour_tenner = 0;
//////////////////////////////////////////////////////////////////////////
//INITIALIZE
//////////////////////////////////////////////////////////////////////////

//disable Button-interrupts
	PCICR &= ~(1 << PCIE0);
	
//start LCD	
	PORT_REG_VDD_LCD |= (1<<REG_NR_VDD_LCD);
	PORT_REG_BL_LCD |= (1<<REG_NR_BL_LCD);
//print status to LCD
	initialize_LCD_4bit();
	clear_display_LCD();
	return_home_LCD();
	display_on_off_control_LCD(1,0,0);
	write_data_to_LCD_as_string("initializing...");
	set_DDRAM_address_LCD(0x40);
	write_data_to_LCD_as_string("wait for DCF77");
	
//power DCF module
	DIR_REG_DCF77_VDD |= (1 << REG_NR_DCF77_VDD);
	PORT_REG_DCF77_VDD |= (1 << REG_NR_DCF77_VDD);
	
//wait for DCF module
	for (unsigned char i = 0; i < 150; i++)
		_delay_ms(260);
	
	do
	{
	//reset variables
		received_time_minute_unit = 0;
		received_time_minute_tenner = 0;
		received_time_hour_unit = 0;
		received_time_hour_tenner = 0;
		received_date_day_unit = 0;
		received_date_day_tenner = 0;
		received_weekday = 0;
		received_date_month_unit = 0;
		received_date_month_tenner = 0;
		received_date_year_unit = 0;
		received_date_year_tenner = 0;
	
		error_flag = 0;
		DCF77_decoding_bit_stead = 0;
		parity_sum_minutes = 0;
		parity_sum_hours = 0;
		parity_sum_date = 0;
	
	//print status to LCD
		clear_display_LCD();
		return_home_LCD();
		write_data_to_LCD_as_string("initializing...");
		set_DDRAM_address_LCD(0x40);
		write_data_to_LCD_as_string("wait for second0");	

	//start timer 0 to find second 0
		power_timer0_enable();
		TCCR0B |= (1<<CS02);	//setting the prescaler to 256 and start the timer
		second0_timer_enabled = 1;
	
	//find second 0
		second0_timer_interrupt_counter=0;
		while (second0_timer_interrupt_counter < 22)
		{
			if (PIN_REG_DCF77_SIGNAL & (1 << REG_NR_DCF77_SIGNAL))
			second0_timer_interrupt_counter = 0;
		}
	
	//stop timer 0	
		TCCR0B &= ~(1<<CS02);
		power_timer0_disable();
		second0_timer_enabled = 0;
	
	//////////////////////////////////////////////////////////////////////////
	//DECODE THE BITS
	//////////////////////////////////////////////////////////////////////////

	//print status to LCD
		clear_display_LCD();
		return_home_LCD();
		write_data_to_LCD_as_string("initializing...");
		set_DDRAM_address_LCD(0x40);
		write_data_to_LCD_as_string("read data");
		set_DDRAM_address_LCD(0x4C);
		write_data_to_LCD_as_string("/59");
	
		while (DCF77_decoding_bit_stead <= 59)
		{
	//print status to LCD
			set_DDRAM_address_LCD(0x4A);
			unsigned char help_value = DCF77_decoding_bit_stead/10;
			write_data_to_LCD_as_byte(help_value+48);
			help_value = DCF77_decoding_bit_stead - 10*help_value;
			write_data_to_LCD_as_byte(help_value+48);
		
	//wait until DCF goes high		
			while(!(PIN_REG_DCF77_SIGNAL & (1 << REG_NR_DCF77_SIGNAL))); 
			_delay_ms(150);
	//check, whether the bit is H or L
			(PIN_REG_DCF77_SIGNAL & (1 << REG_NR_DCF77_SIGNAL)) ? (bit_value = 1) : (bit_value = 0);
	//wait until DCF is low		
			while (PIN_REG_DCF77_SIGNAL & (1 << REG_NR_DCF77_SIGNAL));
		
			switch (DCF77_decoding_bit_stead)
			{
				case 21: (received_time_minute_unit |= (bit_value << 0x00)); parity_sum_minutes += bit_value; break;
				case 22: (received_time_minute_unit |= (bit_value << 0x01)); parity_sum_minutes += bit_value; break;
				case 23: (received_time_minute_unit |= (bit_value << 0x02)); parity_sum_minutes += bit_value; break;
				case 24: (received_time_minute_unit |= (bit_value << 0x03)); parity_sum_minutes += bit_value; break;
				case 25: (received_time_minute_tenner |= (bit_value << 0x00)); parity_sum_minutes += bit_value; break;
				case 26: (received_time_minute_tenner |= (bit_value << 0x01)); parity_sum_minutes += bit_value; break;
				case 27: (received_time_minute_tenner |= (bit_value << 0x02)); parity_sum_minutes += bit_value; break;
				case 28: 	if ((parity_sum_minutes + bit_value) % 2)
				error_flag = 1;
				break;
				case 29: (received_time_hour_unit |= (bit_value << 0x00)); parity_sum_hours += bit_value; break;
				case 30: (received_time_hour_unit |= (bit_value << 0x01)); parity_sum_hours += bit_value; break;
				case 31: (received_time_hour_unit |= (bit_value << 0x02)); parity_sum_hours += bit_value; break;
				case 32: (received_time_hour_unit |= (bit_value << 0x03)); parity_sum_hours += bit_value; break;
				case 33: (received_time_hour_tenner |= (bit_value << 0x00)); parity_sum_hours += bit_value; break;
				case 34: (received_time_hour_tenner |= (bit_value << 0x01)); parity_sum_hours += bit_value; break;
				case 35:	if ((parity_sum_hours + bit_value) % 2)
				error_flag = 1;
				break;
				case 36: (received_date_day_unit |= (bit_value << 0x00)); parity_sum_date += bit_value; break;
				case 37: (received_date_day_unit |= (bit_value << 0x01)); parity_sum_date += bit_value; break;
				case 38: (received_date_day_unit |= (bit_value << 0x02)); parity_sum_date += bit_value; break;
				case 39: (received_date_day_unit |= (bit_value << 0x03)); parity_sum_date += bit_value; break;
				case 40: (received_date_day_tenner |= (bit_value << 0x00)); parity_sum_date += bit_value; break;
				case 41: (received_date_day_tenner |= (bit_value << 0x01)); parity_sum_date += bit_value; break;
				case 42: (received_weekday |= (bit_value << 0x00)); parity_sum_date += bit_value; break; //weekday
				case 43: (received_weekday |= (bit_value << 0x01)); parity_sum_date += bit_value; break;
				case 44: (received_weekday |= (bit_value << 0x02)); parity_sum_date += bit_value; break;
				case 45: (received_date_month_unit |= (bit_value << 0x00)); parity_sum_date += bit_value; break;
				case 46: (received_date_month_unit |= (bit_value << 0x01)); parity_sum_date += bit_value; break;
				case 47: (received_date_month_unit |= (bit_value << 0x02)); parity_sum_date += bit_value; break;
				case 48: (received_date_month_unit |= (bit_value << 0x03)); parity_sum_date += bit_value; break;
				case 49: (received_date_month_tenner |= (bit_value << 0x00)); parity_sum_date += bit_value; break;
				case 50: (received_date_year_unit |= (bit_value << 0x00)); parity_sum_date += bit_value; break;
				case 51: (received_date_year_unit |= (bit_value << 0x01)); parity_sum_date += bit_value; break;
				case 52: (received_date_year_unit |= (bit_value << 0x02)); parity_sum_date += bit_value; break;
				case 53: (received_date_year_unit |= (bit_value << 0x03)); parity_sum_date += bit_value; break;
				case 54: (received_date_year_tenner |= (bit_value << 0x00)); parity_sum_date += bit_value; break;
				case 55: (received_date_year_tenner |= (bit_value << 0x01)); parity_sum_date += bit_value; break;
				case 56: (received_date_year_tenner |= (bit_value << 0x02)); parity_sum_date += bit_value; break;
				case 57: (received_date_year_tenner |= (bit_value << 0x03)); parity_sum_date += bit_value; break;
				case 58: break;
			}
			DCF77_decoding_bit_stead++;
		}
	//check the received data
		if (received_date_day_unit > 9)
		error_flag = 1;
		if (received_date_day_tenner > 3)
		error_flag = 1;
		if (received_date_month_unit > 9)
		error_flag = 1;
		if (received_date_month_tenner > 1)
		error_flag = 1;
		if (received_date_year_unit > 9)
		error_flag = 1;
		if ((received_date_year_tenner > 9)||(received_date_year_tenner < 1))
		error_flag = 1;
		if ((received_weekday < 1) || (received_weekday > 7))
		error_flag = 1;
	
		decoding_trial_counter++;
		if (decoding_trial_counter == MAXIMUM_DECODING_TRIALS)
		{
			PORT_REG_SPEAKER_OUT |= (1<<REG_NR_SPEAKER_OUT);
			_delay_ms(250);
			_delay_ms(250);
			_delay_ms(250);
			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
			_delay_ms(250);
			_delay_ms(250);
			PORT_REG_SPEAKER_OUT |= (1<<REG_NR_SPEAKER_OUT);
			_delay_ms(250);
			_delay_ms(250);
			_delay_ms(250);
			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);		
			break;
		}
	
	} while (error_flag);	
	
	if (!error_flag)
	{
		current_time_minute_unit = received_time_minute_unit;
		current_time_minute_tenner = received_time_minute_tenner;
		current_time_hour_unit = received_time_hour_unit;
		current_time_hour_tenner = received_time_hour_tenner;
		current_date_day_unit = received_date_day_unit;
		current_date_day_tenner = received_date_day_tenner;
		current_weekday = received_weekday;
		current_date_month_unit = received_date_month_unit;
		current_date_month_tenner = received_date_month_tenner;
		current_date_year_unit = received_date_year_unit;
		current_date_year_tenner = received_date_year_tenner;
//reset and stop external timing circuit
		PORT_REG_CLOCK_GENERATOR_RESET |= (1<<REG_NR_CLOCK_GENERATOR_RESET);
		current_time_second_unit = 0;
		current_time_second_tenner = 0;
//wait until DCF goes high to find the exact start of the next minute
		while(!(PIN_REG_DCF77_SIGNAL & (1 << REG_NR_DCF77_SIGNAL)));
	}
// 	else
// 	{
// 		current_time_minute_unit = 0;
// 		current_time_minute_tenner = 0;
// 		current_time_hour_unit = 0;
// 		current_time_hour_tenner = 0;
// 		current_date_day_unit++;
// 		if (current_date_day_unit == 10)
// 		{
// 			current_date_day_unit = 0;
// 			current_date_day_tenner++;
// 		}
// 		//check whether leap year
// 		unsigned char help_var_lap_year = 0;
// 		help_var_lap_year = current_date_year_unit;
// 		help_var_lap_year += (current_date_year_tenner*10)
// 		if (help_var_lap_year % 4)
// 		{
// 		}
// 		if ((current_date_day_tenner == 2) && (current_date_day_unit == 8) && (current_date_month_tenner == 0) && (current_date_month_unit == 2))
// 		{
// 			current_date_day_unit = 1;
// 			current_date_day_tenner = 0;
// 			current_date_month_unit = 3;
// 		}
// 	}
	
//enable Button-interrupts
	PCICR |= (1<<PCIE0);
//disable DCF
	PORT_REG_DCF77_VDD &= ~(1<<REG_NR_DCF77_VDD);
//start external Clock	
	PORT_REG_CLOCK_GENERATOR_RESET &= ~(1<<REG_NR_CLOCK_GENERATOR_RESET);
	initializing_time_flag = 0;
}

void wait_for_button_release()
{
	while (button_up_state||button_down_state||button_left_state||button_right_state||button_enter_state);
}

void start_standby_timer()
{
	power_timer2_enable();
	standby_timer_interrupt_counter = 0;
	TCCR2A |= (1<<WGM21);	//CTC mode
	TCCR2B |= (1<<CS20)|(1<<CS21)|(1<<CS22);	//setting prescaler to 1024
	OCR2A = 190;
	TIMSK2 |= (1<<OCIE2A);
}

void stop_standby_timer()
{
	TCCR2B &= ~(1<<CS20) & ~(1<<CS21) & ~(1<<CS22);
	TIMSK2 &= ~(1<<OCIE2A);
	standby_timer_interrupt_counter = 0;
	power_timer2_disable();
}

ISR (PCINT0_vect)		//interrupt from external timing circuit
{
	current_time_second_unit++;
	if (current_time_second_unit == 10)
	{
		current_time_second_tenner++;
		current_time_second_unit=0;
	}
	if (current_time_second_tenner==6)
	{
		current_time_minute_unit++;
		current_time_second_tenner = 0;
	}
	if (current_time_minute_unit > 9)
	{
		current_time_minute_tenner++;
		current_time_minute_unit = 0;
	}
	if (current_time_minute_tenner > 5)
	{
		current_time_hour_unit++;
		current_time_minute_tenner = 0;
	}
	if (current_time_hour_unit > 9)
	{
		current_time_hour_tenner++;
		current_time_hour_unit = 0;
	}
	if ((current_time_hour_tenner == 2) && (current_time_hour_unit == 4) && (!initializing_time_flag))
		start_initialize_time=1;

	if (!ringing_enabled && !snooze_time_timer_enabled && alarm_enabled && !initializing_time_flag && (current_time_second_unit==0) && (current_time_second_tenner==0))
	{
		unsigned char minute_unit_fit = 0;
		unsigned char minute_tenner_fit = 0;
		unsigned char hour_unit_fit = 0;
		unsigned char hour_tenner_fit = 0;
		
		(alarm_time_minute_unit == current_time_minute_unit) ? (minute_unit_fit = 1) : (minute_unit_fit = 0);
		(alarm_time_minute_tenner == current_time_minute_tenner) ? (minute_tenner_fit = 1) : (minute_tenner_fit = 0);
		(alarm_time_hour_unit == current_time_hour_unit) ? (hour_unit_fit = 1) : (hour_unit_fit = 0);
		(alarm_time_hour_tenner == current_time_hour_tenner) ? (hour_tenner_fit = 1) : (hour_tenner_fit = 0);
		
		if (minute_unit_fit && minute_tenner_fit && hour_unit_fit && hour_tenner_fit)
			start_ringing_flag = 1;
		if (!snooze_time && (current_time_second_tenner || current_time_second_unit))
			start_ringing_flag = 0;
	}
}

ISR (PCINT1_vect)		//interrupt from buttons
{
	if (ringing_enabled)
		start_snooze_time_timer();	//start snooze time

	if (LCD_was_off_var_2)	//check whether application was in sleep mode
	{
		PORT_REG_VDD_LCD |= (1<<REG_NR_VDD_LCD);
		PORT_REG_BL_LCD |= (1<<REG_NR_BL_LCD);
		LCD_was_off_var_2 = 0;		
	}
	(PIN_REG_BUT_UP & (1<<REG_NR_BUT_UP)) ? (button_up_state=0) : (button_up_state = 1);
	(PIN_REG_BUT_DOWN & (1<<REG_NR_BUT_DOWN)) ? (button_down_state=0) : (button_down_state = 1);
	(PIN_REG_BUT_RIGHT & (1<<REG_NR_BUT_RIGHT)) ? (button_right_state=0) : (button_right_state = 1);
	(PIN_REG_BUT_LEFT & (1<<REG_NR_BUT_LEFT)) ? (button_left_state=0) : (button_left_state=1);
	(PIN_REG_BUT_ENTER & (1<<REG_NR_BUT_ENTER)) ? (button_enter_state=0) : (button_enter_state=1);
}

ISR (TIMER0_COMPA_vect)	//interrupt from Timer for the detecting of second 0 and for the ringing beat
{
	second0_timer_interrupt_counter++;
// 	if (ringing_enabled)
// 	{
// 		switch (second0_timer_interrupt_counter)
// 		{
// 		case 1:
// 			PORT_REG_SPEAKER_OUT|=(1<<REG_NR_SPEAKER_OUT);
// 			break;
// 		case 2:			
// 			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
// 			break;
// 		case 4:
// 			PORT_REG_SPEAKER_OUT|=(1<<REG_NR_SPEAKER_OUT);
// 			break;
// 		case 5:
// 			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
// 			break;
// 		case 7:
// 			PORT_REG_SPEAKER_OUT |= (1<<REG_NR_SPEAKER_OUT);
// 			break;
// 		case 8:
// 			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
// 			break;
// 		case 10:
// 			PORT_REG_SPEAKER_OUT |= (1<<REG_NR_SPEAKER_OUT);
// 			break;
// 		case 11:
// 			PORT_REG_SPEAKER_OUT &= ~(1<<REG_NR_SPEAKER_OUT);
// 			break;
// 		case 26:
// 			second0_timer_interrupt_counter = 0;
// 			break;
// 		default:
// 			break;
// 		}
// 	}
}

ISR (TIMER1_COMPA_vect)	//interrupt from the timer who counts the snooze minutes
{
	snooze_time_counter++;
	if (snooze_time_counter == snooze_time)
	{
		snooze_enabled_flag = 1;
		start_ringing_flag = 1;
		stop_snooze_time_timer();
		snooze_time_counter = 0;
	}
}

ISR (TIMER2_COMPA_vect)	//standby counter interrupt
{
	standby_timer_interrupt_counter++;
}
