/*    mija 2008
      demo for LCD NOKIA5110 and MCP9800 and GPS modul

          CPU ATMEGA644P
      fcpu = 7372800

          !! define PIN,PORT,DDR for IOpin !!
*/


//************************************************************************
// defines

#define POINTNAME       "   DOMOV"
#define MY_LAT  48*60+57.7647
#define MY_LON  14*60+28.0836

/*
// 50°7'38.768"N, 13°32'43.132"E
#define POINTNAME       "  ORACOV"
#define MY_LAT  50*60+7.64613
#define MY_LON  13*60+32.7189
*/
/*
// 50°7'38.768"N, 13°32'43.132"E
#define POINTNAME       "   ZAMEK"
#define MY_LAT  50*60+6.191
#define MY_LON  13*60+32.118
*/

#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
        DDRD |= _BV(PD3);               
        PORTD &= (~(_BV(PD3))); 

#ifndef DEBUG
        UBRR1 = 95;
#else 
        UBRR1 = 3;
#endif
        //UCSR0A = 
        UCSR1B = _BV(RXCIE1)  | _BV(RXEN1) | _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 (USB_PIN) USART_PC_ON;
        else USART_PC_OFF;
        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.%01dC",((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(POINTNAME);
                
                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;
                USART_PC_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();

                }

                if (USB_PIN) USART_PC_ON;
                else USART_PC_OFF;

                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);     
        if (USB_PIN) USART_PC_ON;
        else USART_PC_OFF;
        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;
}