/************************************************************************************************
 *	Name:			Avalanche_Beacon.c															*
 *	Author:			J. Mikulastik																*
 *	Created:		2014																		*
 *	Platform:		AVR Atmega32																*
 *  Description:	Avalanche beacon, receiver,transmitter										*
 *	Xtal:			Internal 1MHz																*
 ***********************************************************************************************/ 


#include "Avalanche_Beacon.h"
/*******************************************VARIBLES********************************************/
uchar	UCH_state, UCH_state_old;			//actual state and previous state
volatile uint16_t UI_intcnt;					//interrupt counter
volatile uint16_t UI_intdisp;					//interrupt counter for display;
volatile uint8_t	UI_intblik;					//conter for blinking led
volatile uint16_t	UI_adc_data;				//10 bit adc sample
volatile uint8_t	UI_reccnt;				//transmitt cnt
static volatile uint16_t	UI_adc_buff[ADCBUFFSIZE];
uint16_t  UI_MAAdc;								//moving average of adc

volatile uchar	BT_Light,BT_Disp;					//Button interrupts
volatile uchar  Event_Light,Event_Disp,Event_Meas;	//Checked Event




void ftoa(unsigned char *buf, float f) {
	unsigned int rem;
	unsigned char *s,length=0;
	int i;

	i = (int)((float)f*10);

	s = buf;
	if (i == 0){ 		//print 0.0 with null termination here
		*s++ = '0';
		*s++ = '.';
		*s++ = '0';
		*s=0; 			//null terminate the string
		} else {
		if (i < 0) {
			*buf++ = '-';
			s = buf;
			i = -i;
		}
		//while-loop to "decode" the long integer to ASCII by append '0', string in reverse manner
		//If it is an integer of 124 -> string = {'4', '2', '1'}
		while (i) {
			++length;
			rem = i % 10;
			*s++ = rem + '0';
			i /= 10;
		}
		//reverse the string in this for-loop, string became {'1', '2', '4'} after this for-loop
		for(rem=0; ((unsigned char)rem)<length/2; rem++) {
			*(buf+length) = *(buf+((unsigned char)rem));
			*(buf+((unsigned char)rem)) = *(buf+(length-((unsigned char)rem)-1));
			*(buf+(length-((unsigned char)rem)-1)) = *(buf+length);
		}

		/* Take care of the special case of 0.x if length ==1*/
		if(length==1) {
			*(buf+2) = *buf;
			*buf = '0';
			*(buf+1) = '.';
			*(s+2)=0; 			//null terminate
			} else {
			*(buf+length) = *(buf+length-1);
			*(buf+length-1)='.';
			*(s+1)=0; 			//null terminate
		}
	}
}

/*************************************FUNCTION*DEFINITION**************************************/
//State machine function
unsigned char FC_Init(void)
{
		uint cnt=0;
		
	    DDRA = 0x00;
	    DDRB = 0x18;
	    PORTB|=(1<<BUTTI);		//pull-up on interrupt signal from decoder
	    DDRC = 0xEC;
	    DDRD = 0x3C;

		UI_intcnt=0;		//variable initial cond	
	    UI_intblik=0;
		BT_Light=0;
		BT_Disp=0;				
		Event_Light=0;
		Event_Disp=1;
		Event_Meas=1;
		UI_intdisp=0;
		UI_MAAdc=0;
		UI_reccnt=0;
		
		for (cnt;cnt<ADCBUFFSIZE;cnt++)
		{
		UI_adc_buff[cnt]=0;
		}
		
	    LcdInit();
		 //display image
		LcdContrast(0x7F);
		LcdClear();
		LcdImage(waitImage);
		LcdUpdate();
		
		ADC_Init();
	    PWM_Init();
	    PWM_setDutyA(50);
	    Tim0_Init();
	    Ext_Int_Init();
		Set_IO_Initial_Cond();	  
	    _delay_ms(200);
		Set_IO_Reset();
	 //   sei();							// enable interrupts
	 
	 if((GETSW)==0) 
		return ST_REC;		
	else
		return ST_TRANS;
}

unsigned char FC_Trans(void)
{
	uint temp=0;
	static char str[4];;
	char s[5];
	float fl=0;
	double db=0;
	
	if (BT_Disp)		//button click 
	{
	Event_Disp=!Event_Disp;	
	_delay_ms(1);
	while ((!(GETBUTT1)) && (!(GETBUTT2)))
	{}
	_delay_ms(1);
	cli();
	BT_Disp=0;	
	sei();
	}
	
	if (Event_Disp)
	{
					  LCD_PORT |= _BV( LCD_CE_PIN );
					  LcdSend( 0x21, LCD_CMD ); /* LCD Powersafe Mode */
					  TOGGLELED1G;
					  
					 		if (Event_Meas)		//Disp ON//OFF
					 		{
					
							start_meas();
							_delay_ms(1);
							temp= read_meas();
							fl=(temp)*0.062;		//calculating real temp from DS18B20
							ftoa(s,fl);
							LcdGotoXYFont(7,6);
							LcdStr(FONT_1X,(unsigned char *)s);
							LcdUpdate();
							
							temp=adc_read(ADCBAT);
							db=temp*0.0075;		//((adc* 2.56)/1024)*3 -3delici pomer
							dtostrf(db,4,2,str);
							LcdGotoXYFont(7,5);
							LcdStr(FONT_1X,(unsigned char *)str);
							
// 							temp=adc_read(ADCANTENA);
// 							db=temp*0.975;		//((adc* 2.56)/1024)*39 -39delici pomer
// 							dtostrf(db,4,2,str);
// 							LcdGotoXYFont(7,4);
// 							LcdStr(FONT_1X,(unsigned char *)str);
							
							if (UI_intdisp>=6)					//moovingarrow
							{
								UI_intdisp=0;
								LcdGotoXYFont(1,2);
								LcdFStr(FONT_1X,(unsigned char*)PSTR(" "));
								LcdGotoXYFont(14,2);
								LcdFStr(FONT_1X,(unsigned char*)PSTR(" "));
							}
							LcdGotoXYFont(6-UI_intdisp,2);
							LcdFStr(FONT_1X,(unsigned char*)PSTR("< "));
							LcdGotoXYFont(8+UI_intdisp,2);
							LcdFStr(FONT_1X,(unsigned char*)PSTR(" >"));
							UI_intdisp++;			//increment arrow movement counter
							
							Event_Meas=0;
					 		}

	}
	
	else
	{				
		LcdClear();
		LcdUpdate();
	}
	
		if (Event_Light)	// Backlight ON/OFF
		SETBL;
		else
		CLEARBL;
		
	return ST_TRANS;
}

unsigned char FC_Rec(void)
{
	static char str[4];	
	char s[5];
	float fl=0;
	double db=0;
	uint16_t pom=0;	
	uchar cnt=0;	
	cli();
// 	
// 	UI_adc_buff[0]=adc_read(ADCRSSI);				//moving average
// 	UI_MAAdc+=UI_adc_buff[0];							//new sample
// 	UI_MAAdc-=UI_adc_buff[ADCBUFFSIZE];				//last sample
// 	pom=UI_MAAdc/ADCBUFFSIZE;						//actual MA value
// 	
// 	for (cnt=0;cnt<ADCBUFFSIZE-1;cnt++)
// 	{
// 		UI_adc_buff[cnt+2]=UI_adc_buff[cnt+1];
// 	}
	UI_adc_buff[5]=UI_adc_buff[4];
	UI_adc_buff[4]=UI_adc_buff[3];
	UI_adc_buff[3]=UI_adc_buff[2];
	UI_adc_buff[2]=UI_adc_buff[1];
	UI_adc_buff[1]=UI_adc_buff[0];
	UI_adc_buff[0]=adc_read(ADCRSSI);
	pom=(UI_adc_buff[0]+UI_adc_buff[1]+UI_adc_buff[2]+UI_adc_buff[3]+UI_adc_buff[4]+UI_adc_buff[5])/6;						//actual MA value
	//UI_adc_buff[0]=adc_read(ADCRSSI);
	
	if ((UI_intcnt==100)||(UI_intcnt==200)||(UI_intcnt==300)||(UI_intcnt==400)||(UI_intcnt==500))
	{
		if(UI_adc_buff[0]>233)
		{
		itoa(pom,str,10);
		LcdGotoXYFont(10,3);
		LcdStr(FONT_1X,(unsigned char *)str);
		LcdUpdate();
		}
	}
	
//	UI_adc_buff[1]=UI_adc_buff[0];
	
	if (UI_reccnt>=1)
	{
		start_meas();
		_delay_ms(1);
		pom = read_meas();
		fl=(pom)*0.062;		//calculating real temp from DS18B20
		ftoa(s,fl);
		LcdGotoXYFont(10,6);
		LcdStr(FONT_1X,(unsigned char *)s);
		
		pom=adc_read(ADCBAT);
		db=pom*0.0075;		//((adc* 2.56)/1024)*3 -3delici pomer
		dtostrf(db,4,2,s);
		LcdGotoXYFont(10,5);
		LcdStr(FONT_1X,(unsigned char *)s);
		LcdUpdate();
		UI_reccnt=0;
	}
	
	sei();	
	_delay_ms(2);
    //_delay_ms(300);
	return ST_REC;
	
}

unsigned char FC_Err(void)
{
	return ST_ERR;
}

//Transient function
unsigned char FC_Init2Trans(void)
{
	SETBL;
	LcdClear();
	LcdGotoXYFont(2,4);
	LcdFStr(FONT_1X,(unsigned char*)PSTR("Transmitting"));
	LcdUpdate();
	_delay_ms(500);
	Draw_Transmitt(PIXEL_ON);
	LcdUpdate();
	_delay_ms(400);
	Draw_Transmitt(PIXEL_OFF);
	LcdUpdate();
	_delay_ms(400);
	Draw_Transmitt(PIXEL_ON);
	LcdUpdate();
	_delay_ms(400);
	CLEARBL;
	LcdClear();
	LcdGotoXYFont(1,1);
	LcdFStr(FONT_1X,(unsigned char*)PSTR("<Transmitting>"));
	LcdGotoXYFont(2,3);
	LcdFStr(FONT_1X,(unsigned char*)PSTR("Stats:"));
	LcdGotoXYFont(2,4);
	LcdFStr(FONT_1X,(unsigned char*)PSTR("Pwr=     V"));
	LcdGotoXYFont(2,5);
	LcdFStr(FONT_1X,(unsigned char*)PSTR("Batt=     V"));
	LcdGotoXYFont(2,6);
	LcdFStr(FONT_1X,(unsigned char*)PSTR("Temp=    C"));
	LcdUpdate();
	sei();
	return ST_TRANS;
}

unsigned char FC_Init2Rec(void)
{
	uchar cnt;
	UI_adc_data=0;
	
	for (cnt=0;cnt<ADCBUFFSIZE;cnt++)		//clear ADC buff
		UI_adc_buff[cnt]=0;
	
	SETBL;
	//Adc_Init_Rec();
	LcdClear();
	LcdGotoXYFont(4,4);
	LcdFStr(FONT_1X,(unsigned char*)PSTR("Receiving"));
	LcdUpdate();
	Set_Arrow(ARR_CENTER);
	_delay_ms(500);
	Set_Arrow(ARR_LEFT);
	_delay_ms(500);
	Set_Arrow(ARR_RIGHT);
	_delay_ms(500);
	//CLEARBL;
	
		//display string
		LcdClear();
		LcdGotoXYFont(8,3);
		LcdFStr(FONT_1X,(unsigned char*)PSTR("X=0"));
		LcdGotoXYFont(8,4);
		LcdFStr(FONT_1X,(unsigned char*)PSTR("Y=0"));
		LcdGotoXYFont(8,5);
		LcdFStr(FONT_1X,(unsigned char*)PSTR("V=0,00V"));
		LcdGotoXYFont(8,6);
		LcdFStr(FONT_1X,(unsigned char*)PSTR("T=00,0C"));
		LcdGotoXYFont(1,4);
		LcdFStr(FONT_2X,(unsigned char*)PSTR("0"));
		LcdGotoXYFont(5,4);
		LcdFStr(FONT_1X,(unsigned char*)PSTR("m"));
		LcdUpdate();
		_delay_ms(1000);
		CLEARSIRENA;
		
		 SETATT;	 
		 CLEARDISTOP;
		 CLEARDISBOT;
		
		sei();		
	return ST_REC;
}

unsigned char FC_Trans2Rec(void)
{
	return ST_REC;
}

unsigned char FC_Rec2Trans(void)
{
	return ST_TRANS;
}

//Peripherial function
void Set_Arrow (LcdArrow arrow)
{
	switch (arrow)
	{
	case ARR_LEFT:
				{
					LcdRect(0,14,0,6,PIXEL_ON);
					LcdRect(0,7,6,13,PIXEL_ON);
					
					LcdRect(69,83,0,6,PIXEL_OFF);
					LcdRect(76,83,6,13,PIXEL_OFF);
					LcdRect(35,48,0,6,PIXEL_OFF);
					LcdRect(28,35,6,13,PIXEL_OFF);
					LcdRect(48,55,6,13,PIXEL_OFF);
					break;}
	case ARR_RIGHT:
				{
					LcdRect(69,83,0,6,PIXEL_ON);
					LcdRect(76,83,6,13,PIXEL_ON);
					
					LcdRect(0,14,0,6,PIXEL_OFF);
					LcdRect(0,7,6,13,PIXEL_OFF);
					LcdRect(35,48,0,6,PIXEL_OFF);
					LcdRect(28,35,6,13,PIXEL_OFF);
					LcdRect(48,55,6,13,PIXEL_OFF);
					break;}
	case ARR_CENTER:
				{
					LcdRect(35,48,0,6,PIXEL_ON);
					LcdRect(28,35,6,13,PIXEL_ON);
					LcdRect(48,55,6,13,PIXEL_ON);
					
					LcdRect(0,14,0,6,PIXEL_OFF);
					LcdRect(0,7,6,13,PIXEL_OFF);
					LcdRect(69,83,0,6,PIXEL_OFF);
					LcdRect(76,83,6,13,PIXEL_OFF);
					break;}
	}
		LcdUpdate();
}

void Set_IO_Initial_Cond (void)
{
	 // Initial condition
	 SETLED1G;
	 SETLED1R;
	 SETLED2;
	 SETVDRV;
	 SETDISTOP;
	 SETDISBOT;
	 SETMOD;
	 CLEARATT;
	 CLEARSIRENA;
	 CLEARBL;
	
}

void Set_IO_Reset (void)
{
	    //Device reset indication
	    CLEARLED1R;
		CLEARLED1G;
		CLEARLED2;
		SETSIRENA;
	    _delay_ms(200);
	    SETLED1R;
		SETLED2;
	    _delay_ms(200);
		CLEARSIRENA;
		CLEARLED1R;
	    SETLED1G;
		_delay_ms(200);
	    SETLED1R;
	    _delay_ms(200);	
		SETSIRENA;
		_delay_ms(400);	
		CLEARSIRENA;
}

void PWM_Init(void){
	 TCCR1A |= 1<<WGM11  |              // Fast PWM
	           1<<COM1A1;	// oc1a reserved, oc1bdisabled
	 
	 TCCR1B |= 1<<WGM12  | 1<<WGM13 |   // Fast PWM
	           1<<CS10;					// 1-prescaler 
	 ICR1=3905;					// Sets the period, using Timer 1 =((F_CPU/(prescaler*PWMFREG))-1);
}
void ADC_Init (void)
{
	UI_adc_data=0;
	// AREF = internal 2.56V
	ADMUX |= (1 << REFS1) | (1 << REFS0);
	// ADC Enable and prescaler of 128
	// 16000000/128 = 125000
	ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
	
}
void Adc_Init_Rec(void)
{
UI_adc_data=0;
ADCSRA |= (1 << ADPS2)| (1 << ADPS1) | (1 << ADPS0);						//divisor factor 128
ADMUX |= (1 << REFS1) | (1 << REFS0)  | (1<<ADLAR) | (1<<MUX0)  ;		//Internal 2,56V ref, and  right adjust, mux adc1
SFIOR &= ~((1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0)); //Set ADC to free run mode
ADCSRA |= (1 << ADEN); // Enables ADC for use
ADCSRA |= (1 << ADIE); // Enable ADC Interrupt
ADCSRA |= (1 << ADATE); // ADC Auto Trigger Enable

ADCSRA |= (1 << ADSC);                           //adc start
}

uint16_t adc_read(uint8_t ch)
{
	// select the corresponding channel 0~7
	// ANDing with 7? will always keep the value
	// of ch between 0 and 7
	ch &= 0b00000111;  // AND operation with 7
	ADMUX = (ADMUX & 0xF8)|ch; // clears the bottom 3 bits before ORing	
	// start single convertion
	// write 1? to ADSC
	ADCSRA |= (1<<ADSC);
	// wait for conversion to complete
	// ADSC becomes 0? again
	// till then, run loop continuously
	while(ADCSRA & (1<<ADSC));
	
	return (ADC);
}

//PWM input is the percentage that you need 
void PWM_setDutyA(double x){
	//Timer 1 function that sets the width of the pulse
	OCR1A = x*ICR1/100; //50Hz
}

//timer used fo periodic interrupt
void Tim0_Init (void)
{
		
	TCCR0 |= ((1 << WGM01) | (1 << CS01) | (1 << CS00));		// Configure timer 0 for CTC mode and clock=Fcpu/64
	TIMSK |= (1 << OCIE0);		// Enable CTC interrupt
	OCR0=250;	// Set CTC compare value to 500Hz at 8MHz AVR clock, with a prescaler of 64 =F_CPU/prescaler/freg;	
	TCNT0=0x00;					// set timer0 counter initial value to 0
}
 
void Ext_Int_Init (void)
{
	MCUCSR&=~(1<<ISC2);		//set INT2 on falling edge
	GICR|=(1<<INT2);		//Enable INT2
}	 

void Draw_Transmitt (LcdPixelMode p)
{
	uint8_t x=0;
	for(x=0;x<LCD_X_RES;x+=4)
		LcdLine(LCD_X_RES/2,x,LCD_Y_RES/2,1,p);
}


/*************************************INTERRUPT*FUNCTIONS**************************************/

ISR(TIMER0_COMP_vect) {
	cli();
	/*______________________timing of AM modulation________________________________*/
	if (UI_intcnt>=INTFREG)		//perioda 500=1s
	UI_intcnt=0;
	
	if (UI_intcnt==0)	//rise edge
	{
		UI_intblik++;
		CLEARMOD;
		UI_reccnt=1;
		if (UI_intblik>=BLINKX) // blink every blinx second
			{
			CLEARLED2;
			UI_intblik=0;
			}
	}
	
	if (UI_intcnt==INTDC)	//faling edge
	{
		SETLED2;
		SETMOD;
		Event_Meas=1;			//event for start measure
	}
	UI_intcnt++;
	
	
	if(UCH_state==ST_REC)
	{
		
	}
	
	sei();
}

ISR(INT2_vect)
{
	cli();
	if ((!(GETBUTT1)) && (!(GETBUTT2)))
	BT_Disp=1;
	//Event_Disp=!Event_Disp;
	
	if (((GETBUTT1)) && (!(GETBUTT2)))
	BT_Light=1;
	//Event_Light=!Event_Light;
	TOGGLELED1R;
	sei();
}

/*ADC Conversion Complete Interrupt Service Routine (ISR)*/
ISR(ADC_vect)
{
  UI_adc_data=(ADCH<<2);       //slepeni obou registru
  UI_adc_data+=ADCL>>7;
}
/*****************************************MAIN*ROUTINE*****************************************/

int main(void)
{
	cli();							//disable interrupt
	
	UCH_state=ST_INIT;	//set state INIT
	
	while(1) //infinity loop
	{
		
		switch ( UCH_state ) //state machine
		{
			case ST_INIT:{		UCH_state_old=UCH_state;
								UCH_state=FC_Init();		
								break;
						}
	
			case ST_TRANS:{
								if(UCH_state_old==ST_TRANS) 
									{	UCH_state_old=UCH_state;
										UCH_state=FC_Trans();	}
									else if(UCH_state_old==ST_INIT) 
										{	UCH_state_old=UCH_state;
											UCH_state=FC_Init2Trans();	}
										else if(UCH_state_old==ST_REC)
											{	UCH_state_old=UCH_state;
												UCH_state=FC_Rec2Trans();	}
											else
												{	UCH_state_old=UCH_state;
													UCH_state=FC_Init();	}				
								break;
							}
			
			case ST_REC:	{
									if(UCH_state_old==ST_REC)
										{	UCH_state_old=UCH_state;
											UCH_state=FC_Rec();	}
										else if(UCH_state_old==ST_INIT)
											{	UCH_state_old=UCH_state;
												UCH_state=FC_Init2Rec();	}
											else if(UCH_state_old==ST_TRANS)
												{	UCH_state_old=UCH_state;
													UCH_state=FC_Trans2Rec();	}
												else
													{	UCH_state_old=UCH_state;
														UCH_state=FC_Init();	}
								break;
								}
			
			case ST_ERR:		UCH_state=FC_Err();				break;
			//default:			UCH_state=		break;
		}
		
	}
	
}