//gps support for COM devices

#include {time.htm}
#include {conio.htm}
#include {string.htm}
#include {pci.htm}
#include {dev.htm}
#include {com.htm}

#include {stdlib.htm}
#include {gl.htm}
#include {msg.htm}

#include {accdis.htm}
//#include {svga.htm}
//#include {vesa.htm}
//#include {vga.htm}

#include {gps1.htm}


UL  hexchar(UL c)
{
    if(c>=0x41){return c-0x41+10;}
    else       {return c-0x30;}
}
UL  hexdigit(UL val);

DB  NMEAreal(CH** eptr)
{
    CH* ptr=*eptr;
    if(!ptr){return 0;}
    if(*ptr==','){ptr++;}
    DB d=strtod(ptr,&ptr);
    *eptr=ptr;
    return d;
}
SL  NMEAint(CH** eptr)
{
    CH* ptr=*eptr;
    if(!ptr){return 0;}
    if(*ptr==','){ptr++;}
    SL d=strtol(ptr,&ptr,10);
    *eptr=ptr;
    return d;
}
CH  NMEAchar(CH** eptr)
{
    CH* ptr=*eptr;
    if(!ptr){return 0;}
    CH  c=0;
    if(*ptr==','){ptr++;c=*ptr;}
    ptr=strchr(ptr,',');
    *eptr=ptr;
    return c;
}

//    GPSNAP  g;


//    GPSNAP gps[GPBUFSIZE];
//    GPSNAP* gp=gps;
//    UL      gpidx;
//    UL      gpdisp;
//    UL      msgtime;
//
//    UL      etrex;
//    UL      sigctr;
//
//    GPSINFO gpsinfo;
//    UL      sats[12];
//    UL      sigctr;
//
//GPSNAP* prev(GPSNAP* g)
//{
//    if(g>gps){return g-1;}
//    return gps+GPBUFSIZE-1;
//}

//functions to decode NMEA strings into usable data
    UL  indecodeGPGGA;
SL  decodeGPGGA(GPS* g,CH* str)
{
    if(indecodeGPGGA){return 1;}
    indecodeGPGGA=1;
    GPSNAP* gp=&g->gp;
//brk
    gp->time=NMEAreal(&str);    //gp->utc filled by GPGGA
    gp->lat= NMEAreal(&str);
    gp->NS=  NMEAchar(&str);
    gp->lng= NMEAreal(&str);
    gp->EW=  NMEAchar(&str);
    gp->fix= NMEAint (&str);
    gp->sats=NMEAint (&str);
    gp->hdp =NMEAreal(&str);
    gp->amsl=NMEAreal(&str);
    indecodeGPGGA=0;
    return 0;
}
    UL  indecodeGPGSA;
SL  decodeGPGSA(GPS* g,CH* str)
{
    if(indecodeGPGSA){return 1;}
    indecodeGPGSA=1;
//brk
    GPSNAP*  gp=&g->gp;
    GPSINFO* gi=&g->gi;
    gp->mode=NMEAchar(&str);
    gp->fixt=NMEAint (&str);
    UL  n,satno;
    for(n=0;n<12;n++)
       {
        g->sats[n]=satno=NMEAint (&str);
        if(satno)
           {
            gi->sat[satno].active=1;
           }
        else
           {
            gi->sat[satno].active=0;
           }
       }
    gi->pDOP=NMEAreal(&str);
    gi->hDOP=NMEAreal(&str);
    gi->vDOP=NMEAreal(&str);

    indecodeGPGSA=0;
    return 0;
}
VD  gpspost(GPS* g)
{
    qmsg(mtGPS,0,0,0,0,(UL)g,0,0);
}

    UL  indecodeGPRMC;
SL  decodeGPRMC(GPS* g,CH* str)
{
    if(indecodeGPRMC){return 1;}
    indecodeGPRMC=1;
    GPSNAP* gp=&g->gp;
//brk
    gp->utc= NMEAreal(&str);    //gp->time filled by GPGGA
    gp->stat=NMEAchar(&str);
    gp->lat= NMEAreal(&str);
    gp->NS=  NMEAchar(&str);
    gp->lng= NMEAreal(&str);
    gp->EW=  NMEAchar(&str);
    gp->gspd=NMEAreal(&str);
    gp->trk =NMEAreal(&str);
    gp->date=NMEAint(&str);
    if(gp->utc==gp->time)
        {//gmsg is copy of live info for message
         //(gp continues to be updated during interrupt handler)
         g->gmsg=g->gp;
         gpspost(g);
        }
    indecodeGPRMC=0;
    return 0;
}
    UL  indecodeGPGSV;
SL  decodeGPGSV(GPS* g,CH* str)
{
    if(indecodeGPGSV){return 1;}
    indecodeGPGSV=1;
//brk
    GPSNAP*  gp=&g->gp;
    GPSINFO* gi=&g->gi;
    UL total=NMEAint (&str);  //total of GSV sentences
    UL cur=NMEAint   (&str);  //number of this sentence
    if(cur==1){g->sigs=g->sigctr;g->sigctr=0;}
    gi->siv=NMEAint (&str);
    UL  n,satno;
    for(n=0;n<4;n++)
        {
         if(*str!='*')
            {
             satno=NMEAint (&str);
             if(satno<33)
                {
                 gi->sat[satno].elevation=NMEAint (&str);
                 gi->sat[satno].azimuth  =NMEAint (&str);
                 gi->sat[satno].snratio  =NMEAint (&str);
                 if(gi->sat[satno].snratio)
                    {
                     g->sigctr++;
                    }

                 gi->sat[satno].inview   =1;
                 gi->sat[satno].lastutc =gp->utc;
                 gi->sat[satno].lastdate=gp->date;
                }
            }
        }

    indecodeGPGSV=0;
    return 0;
}
SL  decodePGRMZ(GPS* g,CH* str)
{
//brk
    GPSNAP*  gp=&g->gp;
    gp->alt =NMEAreal(&str);
    g->etrex=1;
    return 0;
}
SL  decodeHCHDG(GPS* g,CH* str)
{
//brk
    GPSNAP*  gp=&g->gp;
    gp->mhdg= NMEAreal(&str);
    while(*str==','){str++;}
    gp->mvar= NMEAreal(&str);
    str++;
    if(*str=='W'){gp->mvar=-gp->mvar;}
    g->etrex=1;
    return 0;
}

SL  gpssvc  (DEV* d,UL service)
{
//GPS handler
    GPS* g=(GPS*)d->usr;

    UL  n,ck,ck1,ck2;
switch(service)
    {//Mandatory message support//////////////////
     case DM_IDENT:
        return 0;               //COM DEV decides is this device is present
     case DM_PREINIT:
        d->usr=(GPS*)calloc(sizeof(GPS),1);
        if(!d->usr){return 1;}
        return 0;               //device MUST support DM_PREINIT
     case DM_INIT:
        initbuf(d,256,1);    //debug version has larger buffer
//        d->flg|=DF_POLL;
//        d->pollfreq=5;
        return 0;
     case DM_TERM:
        free(d->usr);
        termbuf(d);
        return 0;
     case DM_CHILDHANDLER:
        if(d->sv0=='$')
            {
             d->buf[d->bufin]=0;
//             clidisplay((CH*)d->buf);
             ck=0;ck2=0;
             for(n=1;nbufin;n++)
                {
                 if(d->buf[n]=='*'){break;}
                 ck^=d->buf[n];
                 ck2+=d->buf[n];
                }
             ck1= hexchar(d->buf[n+1])<<4;
             ck1+=hexchar(d->buf[n+2]);
             if(ck==ck1)
                {//NMEA strings interpreted only if valid checksum
                 //see gpsdebug.htm to watch NMEA strings
                 if(!memicmp((CH*)d->buf,"$GPRMC",6))
                     {
                      decodeGPRMC(g,(CH*)d->buf+0x06);
                     }
                  else if(!memicmp((CH*)d->buf,"$GPGGA",6))
                     {
                      decodeGPGGA(g,(CH*)d->buf+0x06);
                     }
                  else if(!memicmp((CH*)d->buf,"$GPGSA",6))
                     {
                      decodeGPGSA(g,(CH*)d->buf+0x06);
                     }
                  else if(!memicmp((CH*)d->buf,"$GPGSV,3,1",10))
                     {
                      decodeGPGSV(g,(CH*)d->buf+0x06);
                     }
                  else if(!memicmp((CH*)d->buf,"$GPGSV,3,2",10))
                     {
                      decodeGPGSV(g,(CH*)d->buf+0x06);
                     }
                  else if(!memicmp((CH*)d->buf,"$GPGSV,3,3",10))
                     {
                      decodeGPGSV(g,(CH*)d->buf+0x06);
                     }
                  else if(!memicmp((CH*)d->buf,"$PGRMZ",6))
                     {
                      decodePGRMZ(g,(CH*)d->buf+0x06);
                     }
                  else if(!memicmp((CH*)d->buf,"$HCHDG",6))
                     {
                      decodeHCHDG(g,(CH*)d->buf+0x06);
                     }
//                  else
//                     {//future extra decodes go here
//                     }
                }
             d->bufin=0;memset(d->buf,0,d->buflen);
            }
        writebuf(d,(UC*)&d->sv0,1);
        return 0;
     case DM_POLL:
        //debug version only:
        //examine parsing buffer at buf+0x80 for NMEA strings we want
        return 0;
     case DM_CLIDISPINFO:
        GPSNAP*  gp=&g->gp;
        GPSINFO* gi=&g->gi;
        CH* ptr1;
        switch(gp->fixt)
            {
             default:
             case 1:ptr1="(no fix)";break;
             case 2:ptr1="(2D fix)";break;
             case 3:ptr1="(3D fix)";break;
            }
        clidisplay("GPS %s> Lat[%10.4d%1s]Long[%10.4d%1s][%8.2d]m      %1l",ptr1,&gp->lat,&gp->NS,&gp->lng,&gp->EW,&gp->amsl,&gp->fix);
        clidisplay("Sats %2l,%2l,%2l,%2l,%2l,%2l,%2l,%2l,%2l,%2l,%2l,%2l,pDOP %+6.2d hDOP %+6.2d vDOP %+6.2d",g->sats,g->sats+1,g->sats+2,g->sats+3,g->sats+4,g->sats+5,g->sats+6,g->sats+7,g->sats+8,g->sats+9,g->sats+10,g->sats+11,g->sats+12,&gi->pDOP,&gi->hDOP,&gi->vDOP);
        clidisplay("SATS (%2l)        [%06l]    at   [%10.3d] [%8.2d]knots [Trk%8.2d]",&gp->sats,&gp->date,&gp->utc,&gp->gspd,&gp->trk);
        clidisplay("SatNo Elev Azim S/n ");
        for(n=0;n<12;n++)
            {
             SATELLITE* s=&gi->sat[g->sats[n]];
             clidisplay("(%2l)  %3l  %3l  %3l ",g->sats+n,&s->elevation,&s->azimuth,&s->snratio);
            }
        return 0;
    }
}