/*
 * Laser Game V1.3.cpp
 *
 * Created: 15.01.2016 20:51:04
 * Author : Martin Daněk
 */ 

#define F_CPU 8000000UL

//definitions for the auxiliary RGB LED
#define ARGB_RED_ON	      PORTD |=(1<<PORTD2)
#define ARGB_BLUE_ON	  PORTD |=(1<<PORTD0)
#define ARGB_GREEN_ON	  PORTD |=(1<<PORTD1)

#define ARGB_RED_OFF	  PORTD &=~(1<<PORTD2)
#define ARGB_BLUE_OFF	  PORTD &=~(1<<PORTD0)
#define ARGB_GREEN_OFF	  PORTD &=~(1<<PORTD1)

#define ARGB_ALL_OFF	  ARGB_BLUE_OFF; ARGB_GREEN_OFF; ARGB_RED_OFF

//definitions for the main RGB LEDs
#define MRGB_RED_ON		  PORTC |=(1<<PORTC3)
#define MRGB_GREEN_ON	  PORTC |=(1<<PORTC2)
#define MRGB_BLUE_ON	  PORTC |=(1<<PORTC1)

#define MRGB_RED_OFF	  PORTC &=~(1<<PORTC3)
#define MRGB_GREEN_OFF	  PORTC &=~(1<<PORTC2)
#define MRGB_BLUE_OFF	  PORTC &=~(1<<PORTC1)

#define MRGB_ALL_OFF	  MRGB_BLUE_OFF; MRGB_GREEN_OFF; MRGB_RED_OFF

//definitions for flashlight LED
#define PLED_ON			  PORTD |=(1<<PORTD6)
#define PLED_OFF		  PORTD &=~(1<<PORTD6)

//definitions for IR LED
#define IRLED_ON		  PORTD |=(1<<PORTD7)
#define IRLED_OFF		  PORTD &=~(1<<PORTD7)

//definitions for piezo speaker
#define SPK_ON			  PORTD |=(1<<PORTD5)
#define SPK_OFF			  PORTD &=~(1<<PORTD5)

//definitions for buttons
#define AUX1_PRESSED	  !(PINB & (1<<PINB0))
#define AUX2_PRESSED	  !(PINB & (1<<PINB1))
#define TRIG_PRESSED	  !(PINB & (1<<PINB2))

//definitions for IR receiver
#define RECEIVE_LOW		  !(PIND & (1<<PIND3))

//definition of the cutoff voltage of the battery
#define CUTOFF 3.00
unsigned char overflowCount;

//IMPORTANT! Definitions for IR communication
#define CONTROL_BIT		  2400
#define HIGH_BIT		  1200
#define LOW_BIT			  600
#define SPACE			  600
const bool codeAlly[] = {1, 0, 0, 1};
const bool codeEnemy[] = {0, 1, 1, 0};
const bool codeRevive[] = {1, 0, 1, 0};
bool codeReceived[4];
bool playerAlive = true;

float receiveTime[6];
bool timerStarted;
unsigned char arrayPosition;


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>

#include "melody.h"

void IRWrite(unsigned int duration);
void SendData();


int main(void)
{
    //outputs
	DDRD |= (1<<DDD0)|(1<<DDD1)|(1<<DDD2);		
	DDRC |= (1<<DDC1)|(1<<DDC2)|(1<<DDC3);		
	DDRD |= (1<<DDD5)|(1<<DDD6)|(1<<DDD7);		
	
	//pullups for buttons
	PORTB |=(1<<PORTB0)|(1<<PORTB1)|(1<<PORTB2);
		
	//messing with interrupts
	EIMSK |= (1<<INT1);							
	EICRA |= (1<<ISC10);						
	TIMSK1 |= (1<<TOIE1);						
	TCCR2B |= (1<<CS20) | (1<< CS21) | (1<<CS22);	
	TIMSK2 |= (1<<TOIE2);						
	sei();												
	
	//messing with ADC
	ADMUX = (1<<REFS0);							
	ADCSRA = (1<<ADEN);							
	ADCSRA |= (1<<ADPS1) | (1<<ADPS2);			
	
	melodyStart();								
		
	ARGB_BLUE_OFF;
	ARGB_GREEN_ON;
	MRGB_GREEN_ON;
	
	
	while (1) 
    {
		//checking if something is pressed...
		if (TRIG_PRESSED)						
		{
			if (playerAlive == true)			
			{
				PLED_ON;						
				//ARGB_ALL_OFF;
				ARGB_BLUE_ON;
				cli();
				SendData();
				sei();
				melodyFire();
				_delay_ms(30);
				PLED_OFF;
			}
			else
			{
				melodyInvalid();				
			}
			
			while (TRIG_PRESSED)				
			{
				_delay_ms(1);
			}
			
			
			
		}
		
		if (AUX1_PRESSED)
		{
			ARGB_RED_ON;
			ARGB_GREEN_OFF;
			melodyInvalid();
			while (AUX1_PRESSED)
			{
				_delay_ms(1);
			}
			ARGB_RED_OFF;
		}
		
		if (AUX2_PRESSED)
		{
			ARGB_RED_ON;
			ARGB_GREEN_OFF;
			melodyInvalid();
			while (AUX2_PRESSED)
			{
				_delay_ms(1);
			}
			ARGB_RED_OFF;
		}
		
		if (playerAlive == true)
		{
			ARGB_ALL_OFF;
			ARGB_GREEN_ON;
			MRGB_ALL_OFF;
			MRGB_GREEN_ON;
		}
		else
		{
			ARGB_ALL_OFF;
			ARGB_RED_ON;
			MRGB_ALL_OFF;
			MRGB_RED_ON;
		}
	
    }
}

void IRWrite(unsigned int duration)				//used to modulate the IR transmission at the frequency of 38 000 Hz
{
	for (unsigned int i = 0; i <= duration/26; i++)
	{
		IRLED_ON;
		_delay_us(13);
		IRLED_OFF;
		_delay_us(13);
	}
}

void SendData(void)								//used to send data from the IR diode
{
	IRWrite(CONTROL_BIT);
	_delay_us(SPACE);
		
	for (int i = 0; i < 4; i++)
	{
		if (codeAlly[i] == 0)
		{
			IRWrite(LOW_BIT);
		}
		else
		{
			IRWrite(HIGH_BIT);
		}
		_delay_us(SPACE);
	}
	
	IRWrite(CONTROL_BIT);
	
}



ISR(INT1_vect)									//receiving data from IR receivers
{
	if (timerStarted == false)					
	{
		timerStarted = true;
		TCCR1B |= (1 << CS10);					
	}
	else
	{
		if (RECEIVE_LOW)						
		{
			TCNT1 = 0;
		}
		else
		{
			receiveTime[arrayPosition] = (TCNT1 * 0.125);
			arrayPosition++;
			TCNT1 = 0;
		}	
	}
}

ISR(TIMER1_OVF_vect)							//evaluations of received data
{
	TCCR1B = 0;									
	timerStarted = false;
	arrayPosition = 0;

	
	if (!(receiveTime[0] > (CONTROL_BIT - 100)) || !(receiveTime[5] > (CONTROL_BIT - 100)))
	{
		MRGB_BLUE_ON;
		_delay_ms(300);
		MRGB_BLUE_OFF;
	}
	else
	{
		for (int i = 1; i < 5; i ++)
		{
			if (receiveTime[i] < 1100)
			{
				codeReceived[arrayPosition] = 0;
				arrayPosition++;
			}
			else if (receiveTime[i] > 1100)
			{
				codeReceived[arrayPosition] = 1;
				arrayPosition++;
			}
		}
		
		
		if ((codeReceived[0] == codeEnemy[0]) && (codeReceived[1] == codeEnemy[1]) && (codeReceived[2] == codeEnemy[2]) && (codeReceived[3] == codeEnemy[3]))
		{
			if (playerAlive == true)
			{
				playerAlive = false;
				MRGB_ALL_OFF;
				MRGB_RED_ON;
				ARGB_ALL_OFF;
				ARGB_RED_ON;
				melodyHit();
			}
		}
		else if ((codeReceived[0] == codeRevive[0]) && (codeReceived[1] == codeRevive[1]) && (codeReceived[2] == codeRevive[2]) && (codeReceived[3] == codeRevive[3]))
		{
			playerAlive = true;
			MRGB_GREEN_ON;
			ARGB_GREEN_ON;
			melodyStart();
		}
		else
		{
			melodyInvalid();
		}
		
	}
	
	memset(receiveTime, 0, 6);
	memset(codeReceived, 0, 4);
	arrayPosition = 0;
	 
}

ISR (TIMER2_OVF_vect)		//regulary measures battery voltage
{
	overflowCount++;
	
	if (overflowCount > 200)
	{
		overflowCount = 0;
		ADCSRA |= (1<<ADSC);					
		while(ADCSRA & (1<<ADSC));				
		
		if ((ADC * 0.0048828125) < CUTOFF)		
		{
			ARGB_ALL_OFF;
			MRGB_ALL_OFF;
			cli();
			while (1)							
			{
				ARGB_RED_ON;
				_delay_ms(500);
				ARGB_RED_OFF;
				_delay_ms(500);
			}
			
		}
	}
	
}






