//************************************************************************
// NMEA LOAD FROM rx GPS

#include <stdint.h>
#include <math.h>
#include <stdlib.h>
#include "nmea_scan.h"
#include "gps.h"

enum {ID_RX_GGA,ID_RX_GSA,ID_RX_GSV,ID_RX_RMC,ID_RX_VTG,ID_RX_LOAD,ID_RX_FIND}; 

uint8_t nmea_start_load(char data)
{
        enum {NM_G,NM_P,NM_GP,NM_GPG,NM_GPR,NM_GPV,NM_GPGG,NM_GPGS,NM_GPRM,NM_GPVT};
        static uint8_t ptr = NM_G;
        
        switch (ptr)
        {
                case NM_G: if (data == 'G') ptr = NM_P;                                 //G
                                else { ptr = NM_G; return ID_RX_FIND;}
                                break; 
                case NM_P: if (data == 'P') ptr = NM_GP;                                //P
                                else { ptr = NM_G; return ID_RX_FIND;}
                                break; 
                case NM_GP: switch (data)                                                               //GPG || GPR || GPV
                                {       
                                        case 'G': ptr=NM_GPG;break;
                                        case 'R': ptr=NM_GPR;break;
                                        case 'V': ptr=NM_GPV;break;
                                        default : ptr = NM_G; return ID_RX_FIND;
                                }
                                break;
                case NM_GPG: switch(data)                                                               //GPGG || GPGS
                                {       
                                        case 'G': ptr=NM_GPGG;break;
                                        case 'S': ptr=NM_GPGS;break;
                                        default : ptr = NM_G; return ID_RX_FIND;
                                }
                                break;
                case NM_GPR: if (data == 'M') ptr = NM_GPRM;                    //GPRM
                                else { ptr = NM_G; return ID_RX_FIND;}
                                break;                  
                case NM_GPV: if (data == 'T') ptr = NM_GPVT;                    //GPVT
                                else { ptr = NM_G; return ID_RX_FIND;}
                                break;
                case NM_GPGG: ptr = NM_G;                                                               //GPGGA
                                if (data == 'A') return ID_RX_GGA;                      
                                return ID_RX_FIND;
                case NM_GPGS: ptr = NM_G;
                                switch(data)                                                            //GPGG || GPGS
                                {       
                                        case 'A': return ID_RX_GSA;
                                        case 'V': return ID_RX_GSV;
                                }
                                return ID_RX_FIND;
                case NM_GPRM: ptr = NM_G;                                                               //GPRMC
                                if (data == 'C') return ID_RX_RMC;                      
                                return ID_RX_FIND;
                case NM_GPVT: ptr = NM_G;                                                               //GPVTG
                                if (data == 'G') return ID_RX_VTG;                      
                                return ID_RX_FIND;
                default: ptr = NM_G; return ID_RX_FIND;
                                
        }
        return ID_RX_LOAD;
}

uint8_t  load_nmea(uint8_t rx_shift, char *rx_buf,char *scan_buf)
{
        static uint8_t id_rx_msg = ID_RX_FIND;
        static uint8_t rx_now = 0;
        static uint8_t ptr = 0;
        char data;

        while (1)
        {
        if (rx_shift == rx_now) return RETURN_RX;
        if(++rx_now >= MAX_RX_BUF) rx_now = 0;  
        data = *(rx_buf + rx_now);

        switch (id_rx_msg)
        {
                case ID_RX_GGA:         *(scan_buf+ptr++) = data;
                                                        if (data == '*') {id_rx_msg = ID_RX_FIND; return RETURN_GGA;}
                                                        if (ptr >= MAX_NMEA_LOAD) id_rx_msg = ID_RX_FIND;
                                                        break;
                case ID_RX_GSA:         *(scan_buf+ptr++) = data;
                                                        if (data == '*') {id_rx_msg = ID_RX_FIND; return RETURN_GSA;}
                                                        if (ptr >= MAX_NMEA_LOAD) id_rx_msg = ID_RX_FIND;
                                                        break;
                case ID_RX_GSV:         *(scan_buf+ptr++) = data;
                                                        if (data == '*') {id_rx_msg = ID_RX_FIND; return RETURN_GSV;}
                                                        if (ptr >= MAX_NMEA_LOAD) id_rx_msg = ID_RX_FIND;
                                                        break;  
                case ID_RX_RMC:         *(scan_buf+ptr++) = data;
                                                        if (data == '*') {id_rx_msg = ID_RX_FIND; return RETURN_RMC;}
                                                        if (ptr >= MAX_NMEA_LOAD) id_rx_msg = ID_RX_FIND;
                                                        break;  
                case ID_RX_VTG:         *(scan_buf+ptr++) = data;
                                                        if (data == '*') {id_rx_msg = ID_RX_FIND;return RETURN_VTG;}
                                                        if (ptr >= MAX_NMEA_LOAD) id_rx_msg = ID_RX_FIND;
                                                        break;
                case ID_RX_LOAD:        id_rx_msg = nmea_start_load(data);      break;  
                case ID_RX_FIND:
                default:                        ptr=0;if (data == '$') id_rx_msg = ID_RX_LOAD;
                        
        }
        }
        return 0 ;
}

void nmea_gga(char *buf,DATA_GPS *pgps)
{
        uint8_t a;

        if (*(buf++) != ',') return;                                                            // ,
        for (a=0;a<5;a++) while (*(buf++) != ',');                                      // UTC,lat,N,lot,W,
        pgps->fix_position = *(buf++) - 0x30;                                           // fix_position
        if (*(buf++) != ',') return;                                                            // ,
        pgps->satelites_used = 10 * (*(buf++) - 0x30) ;                         // satelites
        pgps->satelites_used += *(buf++)-0x30;
        if (*(buf++) != ',') return;                                                            // ,
        while (*(buf++) != ',');                                                                        // HDOP,
        pgps->altitude = atof(buf++);                                                           // atlitude,
        for (a=0;a<2;a++) while (*(buf++) != ',');                                      // ,M,
        pgps->geoid = atof(buf++);                                                                      // geoid
        for (a=0;a<2;a++) while (*(buf++) != ',');                                      //,M,
        if (*buf != ',')
        {
                pgps->age_diff_corr = atol(buf);                                                // age_dif_corr,
                while (*(buf++) != ',');
        }
        else buf++;
        if (*buf != ',') pgps->diff_id = atol(buf);                                     // ID_diff_station
}

void nmea_gsa(char *buf,DATA_GPS *pgps)
{
        uint8_t a;

        if (*(buf++) != ',') return;                                                            // ,
        pgps->mode1 = *(buf++);                                                                         // mode1
        if (*(buf++) != ',') return;                                                            // ,
        pgps->mode2 = *(buf++);                                                                         // mode2
        if (*(buf++) != ',') return;                                                            // ,
        for (a=0;a<12;a++)
        {
                if (*buf != ',')
                {
                        //pgps->satelite_id[a] = 10*(*(buf++) - 0x30);
                        //pgps->satelite_id[a] += *(buf++)-0x30;
                        //buf++;
                        pgps->satelite_id[a] = atol(buf);
                        while (*(buf++) != ',');
                }
                else
                {
                        pgps->satelite_id[a] = 0;
                        buf++;
                 }
        }
        pgps->PDOP = atof(buf++);
        while (*(buf++) != ',');
        pgps->HDOP = atof(buf++);
        while (*(buf++) != ',');
        pgps->VDOP = atof(buf++);
        while (*(buf++) != ',');
}

void nmea_gsv(char *buf,DATA_GPS *pgps)
{
        uint8_t a,i,b;

        if (*(buf++) != ',') return;                                                                    // ,
        pgps->gsv_num_msg = (*(buf++) - 0x30);                                                  // num of msg
        if (*(buf++) != ',') return;                                                                    //,
        pgps->gsv_msg = (*(buf++) - 0x30);                                                              // num msg
        if (*(buf++) != ',') return;                                                                    //,
        pgps->gsv_satelites_view = 10*(*(buf++) - 0x30);                                // satelites view
        pgps->gsv_satelites_view +=(*(buf++) - 0x30);
        if (*(buf++) != ',') return;                                                                    // ,
        a = 4 * (pgps->gsv_msg - 1);
        for (i= 0; i<4; i++)
        {
                /*pgps->satelit_detail[a].id = 10*(*(buf++) - 0x30);                    
                 pgps->satelit_detail[a].id += *(buf++) - 0x30;                         
                buf++;
                pgps->satelit_detail[a].elevation = 10*(*(buf++) - 0x30);
                 pgps->satelit_detail[a].elevation += *(buf++) - 0x30;
                buf++;
                pgps->satelit_detail[a].azimut = 100*(*(buf++) - 0x30);
                 pgps->satelit_detail[a].azimut += 10*(*(buf++) - 0x30);
                 pgps->satelit_detail[a].azimut += *(buf++) - 0x30;
                buf++;*/
                pgps->satelit_detail[a].id = atol(buf);
                 while (*(buf++) != ',');
                pgps->satelit_detail[a].elevation = atol(buf);
                 while (*(buf++) != ',');
                pgps->satelit_detail[a].azimut = atol(buf);
                 while (*(buf++) != ',');

                if ((*buf) != ',')
                {
                        if (*(buf) == '*')
                        {
                                pgps->satelit_detail[a].SNR =0;
                                return;
                        }
                        //pgps->satelit_detail[a].SNR = 10*(*(buf++) - 0x30);
                         //pgps->satelit_detail[a].SNR += *(buf++) - 0x30;
                         pgps->satelit_detail[a].SNR = atol(buf);
                          b= *(buf++);
                          while ((b != ',') && (b != '*') ) b=*(buf++);
                         if (b == '*') return;
                }
                else 
                {
                        pgps->satelit_detail[a].SNR =0;
                        buf++;
                }
                if ( ++a >= pgps->gsv_satelites_view ) return;
                
        }                                                               
}

//$GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598, ,*10
void nmea_rmc(char *buf,DATA_GPS *pgps)
{
        uint8_t a;      

        if (*(buf++) != ',') return;                                                                    // ,
        pgps->hour = (10* (*(buf++) - 0x30));                                                   //hour
         pgps->hour += (*(buf++) - 0x30);
        pgps->minute = 10* (*(buf++) - 0x30);                                                   //minute
         pgps->minute += (*(buf++) - 0x30);
        pgps->second = 10* (*(buf++) - 0x30);                                                   //second
         pgps->second += (*(buf++) - 0x30);
        while (*(buf++) != ',');                                                                                //.xxx  
        pgps->status = *(buf++);
        if (*(buf++) != ',') return;                                                                    //A,                                    
        pgps->latitude =10.0 * (*(buf++) - 0x30);
         pgps->latitude += 1.0 * (*(buf++) - 0x30);
         pgps->latitude += atof(buf)/60.0;
         while (*(buf++) != ',');                                                                               //latitude,
        pgps->ns_indicator =  *(buf++);                                                                 // N/S
        if (*(buf++) != ',') return;                                                                    //,
        pgps->longitude = 100.0 * (*(buf++) - 0x30);
         pgps->longitude += 10.0 * (*(buf++) - 0x30);
         pgps->longitude += 1.0 * (*(buf++) - 0x30);
         pgps->longitude += atof(buf)/60.0;
        while (*(buf++) != ',');                                                                                //longitude,
        pgps->we_indicator =  *(buf++);                                                                 // E/W
        for (a=0;a<3;a++) while (*(buf++) != ',');                                              // ,speed,course,
        pgps->day = 10* (*(buf++) - 0x30);      
         pgps->day += *(buf++) - 0x30;                                                                  // day
        pgps->month = 10* (*(buf++) - 0x30);    
         pgps->month += *(buf++) - 0x30;                                                                // month
        pgps->year = 10* (*(buf++) - 0x30);
         pgps->year += *(buf) - 0x30;                                                                   // year
                
}

void nmea_vtg(char *buf,DATA_GPS *pgps)
{
        uint8_t a;

        if (*(buf++) != ',') return;                                                    // ,
        pgps->course = atof(buf++);                                                             // course
        for (a=0;a<6;a++) while (*(buf++) != ',');                              // ,T,course,M,speed,N,
        pgps->speed = atof(buf++);
}