/*    mija 2008
      demo for LCD NOKIA5110 and MCP9800 and GPS modul

	  CPU ATMEGA644P
      fcpu = 1MHz

	  !! define PIN,PORT,DDR for IOpin !!
*/


//************************************************************************
// defines

#define MY_LAT	48*60+57.7647
#define MY_LON	14*60+28.0836

#define KEY_TIME_DEAD	5 			//cca 50ms 8*5
//#define KEY_TIME_START_REPEAT	100 //cca 1s
//#define KEY_TIME_REPEAT			20	//cca 240ms
#define KEY_TIME_FIRST			50

#define TEMP_TIME_REPEAT		100

#define OFF_TIME				200
#define TIME_KEY_LONG			200

#define REFRESH_TIME			100

#define STATUS_REFRESH_TIME		100

#define CLOCK1S					100
#define CLOCK2S					200
#define CLOCK5S					255;
#define CLOCK50MS				5

#define DEBUG

//************************************************************************
//including

#include <avr/io.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include <stdio.h>
#include <math.h>
//#include "ascii_table.h"
#include "lcd.h"		//define PINs LCD
#include "GPS.h"		//define PINs GPS,TL,LED,REF,I2C 
#include "nmea_scan.h"

//************************************************************************
// pomocne

#define WIDTH_CHAR_SIGNALL	8
prog_uint8_t CHAR_SIGNALL[WIDTH_CHAR_SIGNALL]={127,12,30,51,51,30,12,127};

#define WIDTH_CHAR_SIGNALL_D	8
prog_uint8_t CHAR_SIGNALL_D[WIDTH_CHAR_SIGNALL_D]={127,12,30,63,63,30,12,127};

#define WIDTH_CHAR_SIGNALL_2D	7
prog_uint8_t CHAR_SIGNALL_2D[WIDTH_CHAR_SIGNALL_2D]={1,2,4,127,4,2,1};

#define WIDTH_CHAR_SIGNALL_3D	7
prog_uint8_t CHAR_SIGNALL_3D[WIDTH_CHAR_SIGNALL_3D]={124,68,71,69,125,17,31};

#define WIDTH_CHAR_LIGHT	5
prog_uint8_t CHAR_LIGHT[WIDTH_CHAR_LIGHT]={127,65,95,95,127};


#define BOOT() (((void(*)(void))(char *)0x7C00)())
#define RESET() (((void(*)(void))(char *)0x0000)())
//***********************************************************************
// global variables 

extern uint8_t video_buf[504];
extern uint8_t *offset_text;

uint8_t id_mod;
char scan_buf[MAX_NMEA_LOAD];
POINT_T now,max,min;
DATA_GPS gps;
DATA_GPS *pgps;

enum {ID_TIME,ID_LOCATION,ID_COURSE,ID_ALL_POSITION,ID_ALL_SERVICE,ID_SERVICE,ID_TEMP,ID_SATELITES,ID_NORTH,ID_NAV};

static FILE mystdout = FDEV_SETUP_STREAM(lcd_put, NULL,_FDEV_SETUP_WRITE);   // in lcd.h
static FILE mystdout2 = FDEV_SETUP_STREAM(lcd_put2, NULL,_FDEV_SETUP_WRITE); // in lcd.h

//************************************************************************
// prototypes

//(*bootloader)(void) = 0x7C00;
void delay_ms(uint16_t time);
void null_variables(void);

//************************************************************************
// general cpu init

void general_cpu_init(void)
{
	//*** IO_PIN	***
	TL1_INIT;
	TL1_PULLUP;
	TL2_INIT;
	TL2_PULLUP;
	TL3_INIT;
	TL3_PULLUP;

	USB_INIT;
	//USB_PULLUP;

	GPS_INIT;
	GPS_OFF;
	
	REF_INIT;
	REF_OFF;

	nSCLK_INIT;
	nSDIN_INIT;
	nDC_INIT;
	nCS_INIT;
	nRESET_INIT;

	SCL_INIT;
	SDA_FLOAT;

	LED_INIT;
	LED_OFF;

	//*** EXTERNAL PIN INTERRUPTS
	//EICRA = _BV(ISC21);			//pin INT2 - TL2
	//EIMSK = _BV(INT2);			//pin INT2 - TL2
	

	//*** PIN CHANGE INTERRUPTS PCINT29
	PCICR = _BV(PCIE1);									
	PCMSK1 = _BV(PCINT10) | _BV(PCINT11) |_BV(PCINT12);	//pin change TL1,TL2,TL3
	
	PCICR |= _BV(PCIE3);
	PCMSK3 = _BV(PCINT29);		// pin USB

	//*** TIMER1	*** tik for TL fosc/64 /1024(TCNT1) cca 8ms
	TCNT1 = 0;
	OCR1A = 1024;
	TCCR1A = _BV(WGM11) | _BV(WGM10);				
	TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11) | _BV(CS10) ;  // TIMER1 fast PWM 
	TIMSK1 = _BV(TOIE1);

	//*** TIMER2	*** RTC
	ASSR = _BV(AS2);
	TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
	TIMSK2 = _BV(TOIE2);

	//*** SLEEP		***
	SMCR = _BV(SM1) | _BV(SM0) | _BV(SE);	

	//*** WDT		***
	//WDTCSR = _BV(WDCE) | _BV(WDE);
	//WDTCSR = _BV(WDIE) | _BV(WDP3) | _BV(WDP0);

	//*** USART0	*** RX PD0,  TX PD1, GPS
	UBRR0 = 95;
	//UCSR0A = 
	UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0); 

	//*** USART1	*** RX PD2, TX PD3 PC
#ifndef DEBUG
	UBRR1 = 95;
#else 
	UBRR1 = 3;
#endif
	//UCSR0A = 
	UCSR1B = _BV(RXCIE1)  | _BV(RXEN0) | _BV(TXEN1); 	

	//*** ADC  		***
	ADMUX = _BV(REFS1) | _BV(MUX0);
	ADCSRA = _BV(ADPS1) | _BV(ADPS2); 	

}

//************************************************************************
// interrupts + RTC / clock 8s ... TIMER2 / 

volatile uint8_t RTC_flag;
volatile uint8_t sRTC,mRTC,hRTC,dRTC,mdRTC,yRTC;

uint8_t modulo(uint8_t h,uint8_t m) //pomocna fce pro modulo x
{
   if (h<m) return (h);
   return(h-m);
}

void set_date(void)         //citac datumu
{
   dRTC++;
   switch (mdRTC)
   {
      case 1:
      case 3:
      case 5:
      case 7:
      case 8:
      case 10:
      case 12: if(dRTC>=32) {dRTC=1;mdRTC++;if(mdRTC==13) {mdRTC =1;yRTC=modulo(yRTC++,100);}} break;
      case 4:
      case 6:
      case 9:
      case 11: if(dRTC>=31) {dRTC=1;mdRTC++;} break;
      case 2:  if (dRTC >= 30) {dRTC=1;mdRTC++;break;}
               if (dRTC ==29) {if (!(yRTC & 0x03)) break;dRTC=1;mdRTC++;}
   }
}


volatile uint8_t timer1_ovf;

ISR(TIMER1_OVF_vect)
{
	timer1_ovf ++;
}


ISR(TIMER2_OVF_vect)
{
	sRTC += 8;
    if (sRTC >= 60)
    {
    	sRTC=modulo(sRTC,60);         	//1min
        if (++mRTC>=60) 
		{
			mRTC=0;        				//1hod
        	if (++hRTC>=24) 
			{
				hRTC=0;
				set_date();    			//1den
			}
		}
    }
}

char rx_buf[MAX_RX_BUF];
volatile uint8_t rx_shift; 

ISR(USART0_RX_vect)
{
	if (++rx_shift >= MAX_RX_BUF) rx_shift =0;
	rx_buf[rx_shift]=UDR0;
	UDR1 = UDR0;
}

uint8_t first_char_usart1 = 0;

ISR(USART1_RX_vect)
{
#ifndef DEBUG
	UDR0 = UDR1;
#else 
	if (TL1_INPUT && TL3_INPUT) BOOT();
	//bootloader();
#endif
}

ISR(PCINT1_vect)
{
	if ((!TL3_INPUT) && (!TL1_INPUT)) RESET();
}

ISR(PCINT3_vect)
{
	if (!TL2_INPUT && USB_INPUT) 
	{
	cli();
	buffer_clr();
	gotoxy(2,3);
	fprintf(&mystdout2,"update");
	gotoxy(2,5);
	fprintf(&mystdout2,"firmware");
	lcd_refresh();
	delay_ms(1000);
	BOOT();
	}
	
}

EMPTY_INTERRUPT(INT0_vect)
EMPTY_INTERRUPT(INT2_vect)
EMPTY_INTERRUPT(WDT_vect)

//************************************************************************
// delay_ms functions /define fcpu /

void delay_ms(uint16_t time)
{
	while(time--) _delay_ms(1);
}
//************************************************************************
// static navigation

void gps_put(char c)
{
	while ( !( UCSR0A & _BV(UDRE0)) );
	UDR0 = c;
}

//************************************************************************
// key + timer1_ovf


volatile uint8_t key_press;
volatile uint8_t key_flag;
volatile uint8_t timer_key;
volatile uint8_t timer_temp;
volatile uint8_t timer_off;
volatile uint8_t timer_refresh;
volatile uint8_t timer_status;
volatile uint8_t timer_key_long;

void timer1_tik(void)
{
	uint8_t key_temp;
	
	while (timer1_ovf)
	{
		timer1_ovf--;
		if (timer_status) timer_status--;
		if (timer_refresh) timer_refresh--;
		if (timer_off) timer_off--;
		if (timer_key_long) timer_key_long--;
		if (timer_temp) timer_temp--;
		if (timer_key) timer_key--;
		else 
		{
			key_temp = 0;
			if (!TL1_INPUT) key_temp = _BV(KEY1);
			if (!TL2_INPUT) key_temp |= _BV(KEY2); 
			if (!TL3_INPUT) key_temp |= _BV(KEY3); 
			//if (key_temp != key_press) 
			{
				if (key_temp != key_press)
				{
					timer_off= OFF_TIME;
					timer_key_long=TIME_KEY_LONG;
				}
				timer_key = KEY_TIME_DEAD; 
				key_press = key_temp;
				if (!key_flag) key_flag = key_press;
				
			}
		}
	}
}

uint8_t key_read(void)
{
	uint8_t key_send;

	key_send = key_flag;
	key_flag = 0;
	return key_send;
}

//************************************************************************
// SW I2C /define SDA, SCL; tested for fosc 1Mhz/

void I2C_start(void)
{
	SDA_OUT;
	SDA_L;
	SCL_L;
}

void I2C_stop(void)
{
	SCL_H;
	SDA_OUT;
	SDA_H;
	SDA_FLOAT;
}

void I2C_write(uint8_t data)
{
	uint8_t a;
	
	SDA_OUT;
	for(a=0;a<8;a++)
	{	
		SCL_L;
		if (data & 0x80) SDA_H;
		else SDA_L;
		SCL_H;
		data <<= 1;
	} 
	SCL_L;
	SDA_FLOAT;
	SCL_H;
	SCL_L;
}

uint8_t I2C_read(uint8_t ack)
{
	uint8_t a;
	uint8_t data;

	SDA_IN;
	data=0;
	for(a=0;a<8;a++)
	{	
		SCL_H;
		if (SDA_INPUT) data |=1;
		SCL_L;
		if (a != 7)data <<= 1;
	} 
	
	if (ack) {SDA_OUT;SDA_L;}
	else SDA_FLOAT;
	SCL_H;
	SCL_L;
	SDA_FLOAT;
	return data;
}

//************************************************************************
// temperature sensor MCP9800 of MICROCHIP

void start_MCP9800(void)
{
	I2C_start();
	I2C_write(0x90);
	I2C_write(0x1);		// configuration pointer MCP9800
	//I2C_write(0xE1);	// 12bit + only 1 convert and then sleep
	I2C_write(0x81);	// 9bit + only 1 convert and then sleep
	I2C_stop();
	I2C_start();
	I2C_write(0x90);
	I2C_write(0x0);		// temperature pointer
	I2C_stop();
}

uint16_t read_temp(void)
{
	uint16_t temp;

	I2C_start();
 	I2C_write(0x91);
   	temp = I2C_read(1) << 8;
   	temp |= I2C_read(0);
   	I2C_stop();
	return temp;
}

//************************************************************************
// templota

void print_temp(int16_t teplota)
{
	printf("%d.%01dC",((teplota>>8) & 0x807F) | (teplota  & 0x8000),5*((teplota>>7)& 0x1));
}

void print_time(TIME_T time)
{
	uint8_t temp;	
	
	temp = time.hour/10;
	if (temp == 0) lcd_put(' ',0);
	else lcd_put(temp + 0x30,0);
	lcd_put(time.hour%10 + 0x30,0);
	//put_lcd(':');
	*(offset_text++) =  0x36;
	offset_text++;
	lcd_put(time.min/10 + 0x30,0);
	lcd_put(time.min%10 + 0x30,0);
	//put_lcd(':');
	//put_lcd(sRTC/10 + 0x30);
	//put_lcd(sRTC%10 + 0x30);
}

void print_date(DATE_T date)
{
	uint8_t temp;	
	
	temp = date.day/10;
	if (temp == 0) lcd_put(' ',0);
	else lcd_put(temp + 0x30,0);
	lcd_put(date.day%10 + 0x30,0);
	//put_lcd('/');
	*(offset_text++) =  0x60;
	offset_text++;
	temp = date.mon/10;
	if (temp != 0) lcd_put(temp + 0x30,0);
	lcd_put(date.mon%10 + 0x30,0);
	if (temp == 0) 
	{
		*(offset_text++) =  0x60;
		offset_text++;
	}
	//put_lcd('/');
	//put_lcd(yRTC/10 + 0x30);
	//put_lcd(yRTC%10 + 0x30);
}

TIME_T actual_time(void)
{
	TIME_T time;

	time.sec=sRTC;
	time.min=mRTC;
	time.hour=hRTC;
	return time;
}

DATE_T actual_date(void)
{
	DATE_T date;

	date.day=dRTC;
	date.mon=mdRTC;
	date.year=yRTC;
	return date;
}

//*********************************************************************
// key	

uint8_t test_key(void)
{
	static uint8_t key_next = 0;

	if (key_press)
	{
		if (key_next)
		{
			key_read();
			return 0;
		}

		if(!timer_key_long)
		{
			key_next = 1;
			timer_key = KEY_TIME_FIRST;
			switch(key_read())
			{
				case _BV(KEY1): return KEY1_LONG;
				case _BV(KEY2): return KEY2_LONG;
				case _BV(KEY3): return KEY3_LONG;
			}
		}
		return 0;
	}
	key_next=0;
	switch(key_read())
	{
		case _BV(KEY1): return KEY1_SHORT;
		case _BV(KEY2): return KEY2_SHORT;
		case _BV(KEY3): return KEY3_SHORT;
	}	
	return 0;
}

//*********************************************************************
//status

void status(void)
{
	uint8_t a,b;
	uint8_t *ptr;
	
	start_MCP9800();
	REF_ON;
	ADC_ON;
	ADCSRA |= _BV(ADSC);
	while (!(ADCSRA & _BV(ADIF)));
	
	gotoxy(1,1);
		printf("%0.1fV %2d",1024.0*25/ADC/10,read_temp()>>8);
	offset_text = video_buf + LCD_WIDTH - WIDTH_CHAR_LIGHT - 2*CHAR_WIDTH - WIDTH_CHAR_SIGNALL_3D - WIDTH_CHAR_SIGNALL - 2;
	if (gps.fix_position)									
	{
		
		ptr= CHAR_SIGNALL_3D;b=WIDTH_CHAR_SIGNALL_3D;//offset_text++;
		if (gps.mode2 == '3')
			for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
				
		offset_text = video_buf + LCD_WIDTH - WIDTH_CHAR_LIGHT - 2*CHAR_WIDTH - WIDTH_CHAR_SIGNALL_3D - 2;
		switch (gps.fix_position)
		{
			case 1: ptr= CHAR_SIGNALL;b=WIDTH_CHAR_SIGNALL;break;
			case 2: ptr= CHAR_SIGNALL_D;b=WIDTH_CHAR_SIGNALL_D;break;
			case 0: 
			default:ptr= CHAR_SIGNALL;b=0;
		}
		for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
		
		
	}	
	offset_text = video_buf + LCD_WIDTH - WIDTH_CHAR_LIGHT-2*CHAR_WIDTH;
			printf("%d",gps.satelites_used); 
	if (LED_INPUT)
	{
		ptr= CHAR_LIGHT;b=WIDTH_CHAR_LIGHT;
		offset_text = video_buf + LCD_WIDTH - WIDTH_CHAR_LIGHT;
		for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
	}
	
}

//************************************************************************
// mod

void displ_time(void)
{
	GPS_ON;
	
	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}	

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		status();
		//gotoxy(1,2);
		//	printf("time & date");
		gotoxy(1,3);
				fprintf(&mystdout2,"   %2d:%02d:%02d",gps.hour+2,gps.minute,gps.second);
		gotoxy(1,5);
				fprintf(&mystdout2,"  %2d.%02d.20%02d",gps.day,gps.month,gps.year);
		lcd_refresh();
	}
}

void displ_location(void)
{
	uint8_t a,b;
	uint8_t *ptr;	

	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}	

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		status();

		gotoxy(8,2);
		offset_text -=2;
		ptr= CHAR_SIGNALL_3D;b=WIDTH_CHAR_SIGNALL_3D;//offset_text++;
		for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
		
		//gotoxy(9,2);
		printf("%4.0fm",gps.altitude);
		
		gotoxy(1,3);
		//gps.latitude = 14.5;
			fprintf(&mystdout2,"%c %3d%.4f'",gps.ns_indicator,(uint8_t)gps.latitude,(gps.latitude - 1.0*(uint8_t)gps.latitude)*60);
		gotoxy(1,5);
		//gps.longitude = 48.25;
			fprintf(&mystdout2,"%c %3d%.4f'",gps.we_indicator,(uint8_t)gps.longitude,(gps.longitude - 1.0*(uint8_t)gps.longitude)*60);
		lcd_refresh();
	}
}

void displ_speed(void)
{
	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}	

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		status();
		gotoxy(1,2);
			printf("speed");
		gotoxy(1,4);
			fprintf(&mystdout2,"    %3.1f km/h",gps.speed);
		lcd_refresh();
	}
}

void displ_course(void)
{
	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}		

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		status();
		//gotoxy(1,2);
			//printf("course");
		gotoxy(1,3);
			fprintf(&mystdout2,"    %3.1f km/h",gps.speed);
		gotoxy(6,5);
			fprintf(&mystdout2,"%3.0f",gps.course);
		lcd_refresh();
	}
}

void displ_satelites(void)
{
	#define WIDTH_REC 60

	uint8_t a,x,y,b;
	static uint8_t d = 0;
	static uint8_t c = 0;
	double elevace,azimut;

	switch(test_key())
	{
		case KEY1_LONG:if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: c=0;id_mod=ID_OFF;return;
		case KEY3_LONG: c=0;return;
		case KEY1_SHORT:c=0;timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:c=0;d++;timer_refresh = 0;break;
		case KEY3_SHORT: break;
	}		

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		if (c--) return;
		c=5;
		buffer_clr();
		//status();
	#ifdef DEBUG 
		if(gps.gsv_satelites_view > 12)
		{
			printf("error view satelites");
			lcd_refresh();
			c=5;
			return;
		}
	#endif
		if (d >= gps.gsv_satelites_view) d = 0;
		gotoxy(12,1);
		printf("%d",gps.gsv_satelites_view);
		gotoxy(12,2);
		printf("%d",gps.satelit_detail[d].id);
		gotoxy(12,3);
		printf("%d",gps.satelit_detail[d].azimut);
		gotoxy(12,4);
		printf("%d",gps.satelit_detail[d].elevation);
		gotoxy(12,5);
		printf("%d",gps.satelit_detail[d].SNR);
		gotoxy(12,6);

		for (a=0;a<gps.gsv_satelites_view;a++)
		{
			azimut = (double)gps.satelit_detail[a].azimut;
			elevace = (double)gps.satelit_detail[a].elevation;
			
			x=(uint8_t)((WIDTH_REC-4)/2.0/90.0*(90.0-elevace)*sin(M_PI/180*azimut) + WIDTH_REC/2.0);
			y=(uint8_t)((LCD_HEIGHT-4)/2.0/90.0*(90.0-elevace)*cos(M_PI/180*azimut) + LCD_HEIGHT/2.0);
			if (gps.satelit_detail[a].SNR) 
			{
				lcd_plot(x-1,y);lcd_plot(x+1,y);lcd_plot(x,y-1);lcd_plot(x,y+1);
				for (b=0;b<gps.satelites_used;b++)
					if (gps.satelit_detail[a].id == gps.satelite_id[b])
						 lcd_plot(x,y);
			}
			else  lcd_plot(x,y);
			
			if (d == a)
			{
				lcd_line(x-2,y-2,x-2,y+2);
				lcd_line(x+2,y+2,x+2,y-2);
				lcd_line(x+2,y+2,x-2,y+2);
				lcd_line(x-2,y-2,x+2,y-2);
			}
		}		

		lcd_line(0,0,WIDTH_REC,0);
		lcd_line(0,LCD_HEIGHT-1,WIDTH_REC,LCD_HEIGHT-1);
		lcd_line(0,0,0,LCD_HEIGHT-1);
		lcd_line(WIDTH_REC,0,WIDTH_REC,LCD_HEIGHT-1);

		lcd_refresh();
	}
}

void displ_all_position()
{
	
	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}		

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		status();
		
		gotoxy(1,2);
			printf("%c %3d%.4f'",gps.ns_indicator,(uint8_t)gps.latitude,(gps.latitude - 1.0*(uint8_t)gps.latitude)*60);
		gotoxy(1,3);
			printf("%c %3d%.4f'",gps.we_indicator,(uint8_t)gps.longitude,(gps.longitude - 1.0*(uint8_t)gps.longitude)*60);
		gotoxy(1,4);
			printf("alt%4.0fm V%2.1f",gps.altitude,gps.VDOP);
		gotoxy(1,5);
			printf("geo%4.1fm H%2.1f",gps.geoid,gps.HDOP);
		gotoxy(1,6);
			printf("%3.0fkm/h %3.0f",gps.speed,gps.course);
		lcd_refresh();
	}
}

void displ_nav(void)
{

	double lon,lat,temp;	
	double course;
	uint8_t x,y,xl,yl,xp,yp;
	uint8_t a,b;
	uint8_t *ptr;

	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}		

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		status();
      
	  	const float gc_lat= MY_LAT,gc_lon=MY_LON; // DOMA

		lon=(gc_lon-gps.longitude*60)*1214;
     	lat=(gc_lat-gps.latitude*60)*1854;
		temp = sqrt((lon*lon) + (lat*lat));
	  	
		gotoxy(9,3);
		offset_text -=2;
		ptr= CHAR_SIGNALL_3D;b=WIDTH_CHAR_SIGNALL_3D;
		for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);
		//offset_text++;		

		//gotoxy(10,3);
		printf("%4.0fm",gps.altitude);

		gotoxy(7,2);
		printf("go home");
		
		gotoxy(9,4);
	  	if (temp < 10000)
	  	{
	  		if (temp<1000) fprintf(&mystdout2,"%.1f ",temp);
			else
			{
				fprintf(&mystdout2,"%.3f ",temp/1000);
				gotoxy(12,6);
				printf("k");
			}
	  		gotoxy(13,6);
			printf("m");
	  	}
	  	else
	  	{
	  		temp=temp/1000;
      		if (temp < 1000)
			{ 
				if (temp < 100)
				{
					fprintf(&mystdout2,"%.2f ",temp); 
				}
				else 
				{
					fprintf(&mystdout2,"%.1f ",temp); 
				}
      		}
			else fprintf(&mystdout2,"%5.0f ",temp); 
	  		gotoxy(12,6);
			printf("km");	  
	  	}

      	if (lat==0) lat=0.001;
      	lon=M_PI/2.0-(atan2(lat,lon));
      	if (lon<0) lon+=2*M_PI;
      	if (lon>(2*M_PI)) lon-=2*M_PI;
      	//printf(lcd_putc,"BE%2.0g*",lon);
      	lat=M_PI/180*gps.course;
      	lon=lon-lat;
      	if (lon<0) lon+=2*M_PI;
      	if (lon>2*M_PI) lon-=2*M_PI;
      	//printf(lcd_putc,"HE%2.0g*AZ%2.0g* ",lon,lat);
   
   		#define WIDTH_REC_NAV 43
		#define LCD_HEIGHT_NAV 35
		
		course = lon;
		x=(uint8_t)(WIDTH_REC_NAV/2.0*sin(course) +WIDTH_REC_NAV/2);
		y=(uint8_t)((LCD_HEIGHT_NAV)/2.0*cos(course) +(LCD_HEIGHT_NAV)/2);

		xl=(uint8_t)(WIDTH_REC_NAV/2.0*sin((course-2.62))+WIDTH_REC_NAV/2 );
		yl=(uint8_t)((LCD_HEIGHT_NAV)/2.0*cos((course-2.62))+(LCD_HEIGHT_NAV)/2 );

		xp=(uint8_t)(WIDTH_REC_NAV/2.0*sin((course+2.62))+WIDTH_REC_NAV/2 );
		yp=(uint8_t)((LCD_HEIGHT_NAV)/2.0*cos((course+2.62)) +(LCD_HEIGHT_NAV)/2);

			//xs=(uint8_t)((WIDTH_REC_NORTH-26)/2.0*sin(M_PI/180*(course+180.0))+WIDTH_REC_NORTH/2 );
			//ys=(uint8_t)(((LCD_HEIGHT_NORTH-20))/2.0*cos(M_PI/180*(course+180.0)) +(LCD_HEIGHT_NORTH)/2);

		lcd_line( x,y,xl,yl);
		lcd_line( x,y,xp,yp);
			//lcd_line( xp,yp,xl,yl);
		lcd_line(xl,yl,WIDTH_REC_NAV/2,(LCD_HEIGHT_NAV)/2);
		lcd_line(xp,yp,WIDTH_REC_NAV/2,(LCD_HEIGHT_NAV)/2);
			
			//lcd_line(xl,yl,xs,ys);
			//lcd_line(xp,yp,xs,ys);
		lcd_refresh();
	}
}

void displ_service(char *buf)
{
	uint8_t a;	
	
	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}	
	
	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		for (a = 0; a<80; a++) putchar(*(buf++));
		lcd_refresh();
	}
}

void displ_north(void)
{
	uint8_t a,b;
	uint8_t *ptr;
	uint8_t x,y;
	uint8_t xp,yp;
	uint8_t xl,yl;
	//uint8_t xs,ys;
	double course;	

	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}		

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		status();

		gotoxy(9,3);
		offset_text -=2;
		ptr= CHAR_SIGNALL_3D;b=WIDTH_CHAR_SIGNALL_3D;//offset_text++;
		for (a=0;a<b;a++) *(offset_text++) =pgm_read_byte(ptr++);		

		//gotoxy(10,3);
		printf("%4.0fm",gps.altitude);

		gotoxy(9,2);
		printf("north");		

		gotoxy(9,4);
		fprintf(&mystdout2,"%3.1f",gps.speed);		
		gotoxy(10,6);
		printf("km/h");
		
		#define WIDTH_REC_NORTH 43
		#define LCD_HEIGHT_NORTH 35

		course = 360-gps.course;
		x=(uint8_t)(WIDTH_REC_NORTH/2.0*sin(M_PI/180*course) +WIDTH_REC_NORTH/2);
		y=(uint8_t)((LCD_HEIGHT_NORTH)/2.0*cos(M_PI/180*course) +(LCD_HEIGHT_NORTH)/2);

		xl=(uint8_t)(WIDTH_REC_NORTH/2.0*sin(M_PI/180*(course-150.0))+WIDTH_REC_NORTH/2 );
		yl=(uint8_t)((LCD_HEIGHT_NORTH)/2.0*cos(M_PI/180*(course-150.0))+(LCD_HEIGHT_NORTH)/2 );

		xp=(uint8_t)(WIDTH_REC_NORTH/2.0*sin(M_PI/180*(course+150.0))+WIDTH_REC_NORTH/2 );
		yp=(uint8_t)((LCD_HEIGHT_NORTH)/2.0*cos(M_PI/180*(course+150.0)) +(LCD_HEIGHT_NORTH)/2);

			//xs=(uint8_t)((WIDTH_REC_NORTH-26)/2.0*sin(M_PI/180*(course+180.0))+WIDTH_REC_NORTH/2 );
			//ys=(uint8_t)(((LCD_HEIGHT_NORTH-20))/2.0*cos(M_PI/180*(course+180.0)) +(LCD_HEIGHT_NORTH)/2);

		lcd_line( x,y,xl,yl);
		lcd_line( x,y,xp,yp);
			//lcd_line( xp,yp,xl,yl);
		lcd_line(xl,yl,WIDTH_REC_NORTH/2,(LCD_HEIGHT_NORTH)/2);
		lcd_line(xp,yp,WIDTH_REC_NORTH/2,(LCD_HEIGHT_NORTH)/2);
			
			//lcd_line(xl,yl,xs,ys);
			//lcd_line(xp,yp,xs,ys);
		lcd_refresh();
	}
}

void displ_all_service(void)
{
	uint8_t a;	

	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;++id_mod;return;
		case KEY2_SHORT:
		case KEY3_SHORT:break;
	}		

	if (!timer_refresh)
	{
		timer_refresh = CLOCK1S;
		buffer_clr();
		status();

		gotoxy(1,2);
			printf("d=%d %ds",gps.diff_id,gps.age_diff_corr);
		gotoxy(1,3);
			printf("%c st=%cD ",gps.mode1,gps.mode2);
			switch (gps.fix_position)
			{
				case 0: printf("nofix");break;
				case 1: printf("SPSfix");break;
				case 2: printf(" Dfix");break;
				default: printf("nopref");
			}
		gotoxy(1,4);
			printf("GSV %d %d %d",gps.gsv_num_msg,gps.gsv_msg,gps.gsv_satelites_view);
		gotoxy(1,5);
		for(a=0;a<6;a++)
		{
			printf("%2d",gps.satelite_id[a]);
			offset_text+=2;
		}
		gotoxy(1,6);
		for(a=6;a<12;a++)
		{
			printf("%2d",gps.satelite_id[a]);
			if (a != 11) offset_text+=2;
		}		
		lcd_refresh();
	}
}

void temp(void)
{
	timer_temp = TEMP_TIME_REPEAT;
		now.temperature=read_temp();
		now.time=actual_time();
		now.date=actual_date();
		
		buffer_clr();
		gotoxy(1,1);
			stdout = &mystdout2;
			print_temp(now.temperature);
			stdout = &mystdout;
		gotoxy(11,1);
			offset_text-= 2;
			print_time(now.time);
		gotoxy(11,2);
			offset_text-= 2;
			print_date(now.date);
		gotoxy(1,4);
			if (now.temperature > max.temperature) max=now;
			print_temp(max.temperature);
		gotoxy(11,4);
			offset_text-= 2;
			print_date(max.date);
		gotoxy(6,3);
			printf("max");
		gotoxy(11,3);
			offset_text-= 2;
			print_time(max.time);
		gotoxy(1,6);
			if (now.temperature < min.temperature) min=now;
			print_temp(min.temperature);
		gotoxy(11,6);
			offset_text-= 2;
			print_date(min.date);
		gotoxy(6,5);
			printf("min");
		gotoxy(11,5);
			offset_text-= 2;
			print_time(min.time);
		lcd_refresh();
		start_MCP9800();
}

void displ_temp()
{
	//GPS_OFF;
	//ADC_OFF;
	//REF_OFF;

	switch(test_key())
	{
		case KEY1_LONG: timer_refresh = 0;if (LED_INPUT) LED_OFF;else LED_ON;break;
		case KEY2_LONG: id_mod=ID_OFF;return;
		case KEY3_LONG: return;
		case KEY1_SHORT:timer_refresh = 0;id_mod++;return;
		case KEY2_SHORT:timer_temp = 0; max.temperature=0x8000;min.temperature=0x7FFF;
			if (GPS_INPUT && (gps.status == 'A'))
			{
				sRTC=gps.second;
				mRTC=gps.minute;
				hRTC=gps.hour+2;

				dRTC=gps.day;
				mdRTC=gps.month;
				yRTC=gps.year;
			}break;
		case KEY3_SHORT: break;
	}		

	if(!timer_temp)
	{		
	 	temp();	
	}
}


void displ_start(void)
{
	buffer_clr();
	gotoxy(6,3);
	fprintf(&mystdout2,"GPS");
	lcd_refresh();
	delay_ms(1000);
	id_mod = ID_TEMP;
}

void all_off(void)
{
		uint8_t temp_wiev;		

		buffer_clr();
		gotoxy(6,3);
		fprintf(&mystdout2,"OFF");
		lcd_refresh();
		GPS_OFF;
		REF_OFF;
		ADC_OFF;
		delay_ms(1000);
		LED_OFF;
		N5110_send_command(POWER_DOWN);
		
		temp_wiev = 0;
		while (TL2_INPUT)
		{
			sleep_cpu();
			if (!TL1_INPUT) 
			{
				if (!temp_wiev) N5110_send_command(ACTIVE_CHIP);
				temp_wiev = 1;
				timer1_ovf = 0;
				while ((!TL1_INPUT) && (timer1_ovf<200));
				if (timer1_ovf==200) 
				{
					max.temperature=0x8000;
					min.temperature=0x7FFF;
				}
			}
			if (!TL3_INPUT) {N5110_send_command(POWER_DOWN);temp_wiev = 0;}
			if (temp_wiev) temp();

		}
		null_variables();
		LCD_N5110_INIT();
		displ_start();
}

//************************************************************************
// spol key

uint8_t key(uint8_t mod)
{
	if(key_press)
	{
		if (!timer_off) 
		{
			if (key_read() == _BV(KEY2)) 
			{
				timer_refresh = 0;
				timer_key = CLOCK2S;
				key_read();
				return ID_OFF;
			}
		}
	}
	else 
	{
		if (key_flag == _BV(KEY1)) 
		{
			timer_key = KEY_TIME_FIRST;
			key_read();
			timer_refresh = 0;
			++mod;
		}
		if (key_flag == _BV(KEY2))
		{
			if (LED_INPUT) LED_OFF;
			else LED_ON;
			timer_key = KEY_TIME_FIRST;
			key_read(); 
		}
		if (key_flag == _BV(KEY3))
		{
			max.temperature=0x8000;
			min.temperature=0x7FFF;
			if (GPS_INPUT && (gps.status == 'A'))
			{
				sRTC=gps.second;
				mRTC=gps.minute;
				hRTC=gps.hour+2;

				dRTC=gps.day;
				mdRTC=gps.month;
				yRTC=gps.year;
			}

			timer_key = KEY_TIME_FIRST;
			key_read(); 
		}
	}
	return mod;
}

void null_variables(void)
{
	key_press = 0;
	key_flag = 0;

	timer_key = 0;
	timer_temp = 0;
	timer_off = OFF_TIME;
	timer_refresh = 0;
	timer_status = 0;
	timer1_ovf =0;

	//max.temperature=0x8000;
	//min.temperature=0x7FFF;
	
	//sRTC=0;
	//mRTC=15;
	//hRTC=17;

	//dRTC=25;
	//mdRTC=7;
	//yRTC=8;
	
	id_mod = ID_START;	
}

//************************************************************************
// main 

int main(void)
{		

	pgps = &gps;
	
	null_variables();

	general_cpu_init();
	//GPS_ON;
	LCD_N5110_INIT();

	//set_static_navigation(0);	
	
	stdout = &mystdout;
	sei();
	
	for (;;)
	{
		switch(id_mod)
		{
			case ID_TIME: 			displ_time();	break;
			case ID_LOCATION:	 	displ_location();break;
			//case ID_SPEED:		displ_speed();	break;
			case ID_SATELITES:		displ_satelites();break;
			case ID_COURSE:			id_mod++;break;displ_course();	break;
			case ID_ALL_POSITION:	displ_all_position();	break;
			case ID_ALL_SERVICE:	id_mod++;break;displ_all_service();break;
			case ID_SERVICE:		id_mod++;break;displ_service(scan_buf);break;
			case ID_TEMP:			displ_temp();	break;
			case ID_OFF:			all_off();		break;
			case ID_START:			displ_start();	break;
			case ID_NAV:			displ_nav();break;
			case ID_NORTH:			displ_north();break;
			default : id_mod = 0;
		}


		switch (load_nmea(rx_shift,rx_buf,scan_buf))
		{
			case RETURN_GGA: nmea_gga(scan_buf,pgps);break;
			case RETURN_GSA: nmea_gsa(scan_buf,pgps);break;
			case RETURN_GSV: nmea_gsv(scan_buf,pgps);break;
			case RETURN_RMC: nmea_rmc(scan_buf,pgps);break;
			case RETURN_VTG: nmea_vtg(scan_buf,pgps);break;
		}

		timer1_tik();

		//id_mod = key(id_mod);

	}
	return 0;
}

