Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

# nmea.c

Go to the documentation of this file.

    00001 /*! \file nmea.c \brief NMEA protocol function library. */
    00002 //*****************************************************************************
    00003 //
    00004 // File Name    : 'nmea.c'
    00005 // Title        : NMEA protocol function library
    00006 // Author       : Pascal Stang - Copyright (C) 2002
    00007 // Created      : 2002.08.27
    00008 // Revised      : 2002.08.27
    00009 // Version      : 0.1
    00010 // Target MCU   : Atmel AVR Series
    00011 // Editor Tabs  : 4
    00012 //
    00013 // NOTE: This code is currently below version 1.0, and therefore is considered
    00014 // to be lacking in some functionality or documentation, or may not be fully
    00015 // tested.  Nonetheless, you can expect most functions to work.
    00016 //
    00017 // This code is distributed under the GNU Public License
    00018 //      which can be found at http://www.gnu.org/licenses/gpl.txt
    00019 //
    00020 //*****************************************************************************
    00021
    00022 #ifndef WIN32
    00023     #include <avr/io.h>
    00024     #include <avr/interrupt.h>
    00025     #include <avr/pgmspace.h>
    00026 #endif
    00027 #include <string.h>
    00028 #include <stdlib.h>
    00029 #include <math.h>
    00030
    00031 #include "global.h"
    00032 #include "buffer.h"
    00033 #include "rprintf.h"
    00034 #include "gps.h"
    00035
    00036 #include "nmea.h"
    00037
    00038 // Program ROM constants
    00039
    00040 // Global variables
    00041 extern GpsInfoType GpsInfo;
    00042 u08 NmeaPacket[NMEA_BUFFERSIZE];
    00043
    00044 void nmeaInit(void)
    00045 {
    00046 }
    00047
    00048 u08* nmeaGetPacketBuffer(void)
    00049 {
    00050     return NmeaPacket;
    00051 }
    00052
    00053 u08 nmeaProcess(cBuffer* rxBuffer)
    00054 {
    00055     u08 foundpacket = NMEA_NODATA;
    00056     u08 startFlag = FALSE;
    00057     //u08 data;
    00058     u16 i,j;
    00059
    00060     // process the receive buffer
    00061     // go through buffer looking for packets
    00062     while(rxBuffer->datalength)
    00063     {
    00064         // look for a start of NMEA packet
    00065         if(bufferGetAtIndex(rxBuffer,0) == '$')
    00066         {
    00067             // found start
    00068             startFlag = TRUE;
    00069             // when start is found, we leave it intact in the receive buffer
    00070             // in case the full NMEA string is not completely received.  The
    00071             // start will be detected in the next nmeaProcess iteration.
    00072
    00073             // done looking for start
    00074             break;
    00075         }
    00076         else
    00077             bufferGetFromFront(rxBuffer);
    00078     }
    00079
    00080     // if we detected a start, look for end of packet
    00081     if(startFlag)
    00082     {
    00083         for(i=1; i<(rxBuffer->datalength)-1; i++)
    00084         {
    00085             // check for end of NMEA packet <CR><LF>
    00086             if((bufferGetAtIndex(rxBuffer,i) == '\r') && (bufferGetAtIndex(rxBuffer,i+1) == '\n'))
    00087             {
    00088                 // have a packet end
    00089                 // dump initial '$'
    00090                 bufferGetFromFront(rxBuffer);
    00091                 // copy packet to NmeaPacket
    00092                 for(j=0; j<(i-1); j++)
    00093                 {
    00094                     // although NMEA strings should be 80 characters or less,
    00095                     // receive buffer errors can generate erroneous packets.
    00096                     // Protect against packet buffer overflow
    00097                     if(j<(NMEA_BUFFERSIZE-1))
    00098                         NmeaPacket[j] = bufferGetFromFront(rxBuffer);
    00099                     else
    00100                         bufferGetFromFront(rxBuffer);
    00101                 }
    00102                 // null terminate it
    00103                 NmeaPacket[j] = 0;
    00104                 // dump <CR><LF> from rxBuffer
    00105                 bufferGetFromFront(rxBuffer);
    00106                 bufferGetFromFront(rxBuffer);
    00107
    00108                 #ifdef NMEA_DEBUG_PKT
    00109                 rprintf("Rx NMEA packet type: ");
    00110                 rprintfStrLen(NmeaPacket, 0, 5);
    00111                 rprintfStrLen(NmeaPacket, 5, (i-1)-5);
    00112                 rprintfCRLF();
    00113                 #endif
    00114                 // found a packet
    00115                 // done with this processing session
    00116                 foundpacket = NMEA_UNKNOWN;
    00117                 break;
    00118             }
    00119         }
    00120     }
    00121
    00122     if(foundpacket)
    00123     {
    00124         // check message type and process appropriately
    00125         if(!strncmp(NmeaPacket, "GPGGA", 5))
    00126         {
    00127             // process packet of this type
    00128             nmeaProcessGPGGA(NmeaPacket);
    00129             // report packet type
    00130             foundpacket = NMEA_GPGGA;
    00131         }
    00132         else if(!strncmp(NmeaPacket, "GPVTG", 5))
    00133         {
    00134             // process packet of this type
    00135             nmeaProcessGPVTG(NmeaPacket);
    00136             // report packet type
    00137             foundpacket = NMEA_GPVTG;
    00138         }
    00139     }
    00140     else if(rxBuffer->datalength >= rxBuffer->size)
    00141     {
    00142         // if we found no packet, and the buffer is full
    00143         // we're logjammed, flush entire buffer
    00144         bufferFlush(rxBuffer);
    00145     }
    00146     return foundpacket;
    00147 }
    00148
    00149 void nmeaProcessGPGGA(u08* packet)
    00150 {
    00151     u08 i;
    00152     char* endptr;
    00153     double degrees, minutesfrac;
    00154
    00155     #ifdef NMEA_DEBUG_GGA
    00156     rprintf("NMEA: ");
    00157     rprintfStr(packet);
    00158     rprintfCRLF();
    00159     #endif
    00160
    00161     // start parsing just after "GPGGA,"
    00162     i = 6;
    00163     // attempt to reject empty packets right away
    00164     if(packet[i]==',' && packet[i+1]==',')
    00165         return;
    00166
    00167     // get UTC time [hhmmss.sss]
    00168     GpsInfo.PosLLA.TimeOfFix.f = strtod(&packet[i], &endptr);
    00169     while(packet[i++] != ',');              // next field: latitude
    00170
    00171     // get latitude [ddmm.mmmmm]
    00172     GpsInfo.PosLLA.lat.f = strtod(&packet[i], &endptr);
    00173     // convert to pure degrees [dd.dddd] format
    00174     minutesfrac = modf(GpsInfo.PosLLA.lat.f/100, &degrees);
    00175     GpsInfo.PosLLA.lat.f = degrees + (minutesfrac*100)/60;
    00176     // convert to radians
    00177     GpsInfo.PosLLA.lat.f *= (M_PI/180);
    00178     while(packet[i++] != ',');              // next field: N/S indicator
    00179
    00180     // correct latitute for N/S
    00181     if(packet[i] == 'S') GpsInfo.PosLLA.lat.f = -GpsInfo.PosLLA.lat.f;
    00182     while(packet[i++] != ',');              // next field: longitude
    00183
    00184     // get longitude [ddmm.mmmmm]
    00185     GpsInfo.PosLLA.lon.f = strtod(&packet[i], &endptr);
    00186     // convert to pure degrees [dd.dddd] format
    00187     minutesfrac = modf(GpsInfo.PosLLA.lon.f/100, &degrees);
    00188     GpsInfo.PosLLA.lon.f = degrees + (minutesfrac*100)/60;
    00189     // convert to radians
    00190     GpsInfo.PosLLA.lon.f *= (M_PI/180);
    00191     while(packet[i++] != ',');              // next field: E/W indicator
    00192
    00193     // correct latitute for E/W
    00194     if(packet[i] == 'W') GpsInfo.PosLLA.lon.f = -GpsInfo.PosLLA.lon.f;
    00195     while(packet[i++] != ',');              // next field: position fix status
    00196
    00197     // position fix status
    00198     // 0 = Invalid, 1 = Valid SPS, 2 = Valid DGPS, 3 = Valid PPS
    00199     // check for good position fix
    00200     if( (packet[i] != '0') && (packet[i] != ',') )
    00201         GpsInfo.PosLLA.updates++;
    00202     while(packet[i++] != ',');              // next field: satellites used
    00203
    00204     // get number of satellites used in GPS solution
    00205     GpsInfo.numSVs = atoi(&packet[i]);
    00206     while(packet[i++] != ',');              // next field: HDOP (horizontal dilution of precision)
    00207     while(packet[i++] != ',');              // next field: altitude
    00208
    00209     // get altitude (in meters)
    00210     GpsInfo.PosLLA.alt.f = strtod(&packet[i], &endptr);
    00211
    00212     while(packet[i++] != ',');              // next field: altitude units, always 'M'
    00213     while(packet[i++] != ',');              // next field: geoid seperation
    00214     while(packet[i++] != ',');              // next field: seperation units
    00215     while(packet[i++] != ',');              // next field: DGPS age
    00216     while(packet[i++] != ',');              // next field: DGPS station ID
    00217     while(packet[i++] != '*');              // next field: checksum
    00218 }
    00219
    00220 void nmeaProcessGPVTG(u08* packet)
    00221 {
    00222     u08 i;
    00223     char* endptr;
    00224
    00225     #ifdef NMEA_DEBUG_VTG
    00226     rprintf("NMEA: ");
    00227     rprintfStr(packet);
    00228     rprintfCRLF();
    00229     #endif
    00230
    00231     // start parsing just after "GPVTG,"
    00232     i = 6;
    00233     // attempt to reject empty packets right away
    00234     if(packet[i]==',' && packet[i+1]==',')
    00235         return;
    00236
    00237     // get course (true north ref) in degrees [ddd.dd]
    00238     GpsInfo.VelHS.heading.f = strtod(&packet[i], &endptr);
    00239     while(packet[i++] != ',');              // next field: 'T'
    00240     while(packet[i++] != ',');              // next field: course (magnetic north)
    00241
    00242     // get course (magnetic north ref) in degrees [ddd.dd]
    00243     //GpsInfo.VelHS.heading.f = strtod(&packet[i], &endptr);
    00244     while(packet[i++] != ',');              // next field: 'M'
    00245     while(packet[i++] != ',');              // next field: speed (knots)
    00246
    00247     // get speed in knots
    00248     //GpsInfo.VelHS.speed.f = strtod(&packet[i], &endptr);
    00249     while(packet[i++] != ',');              // next field: 'N'
    00250     while(packet[i++] != ',');              // next field: speed (km/h)
    00251
    00252     // get speed in km/h
    00253     GpsInfo.VelHS.speed.f = strtod(&packet[i], &endptr);
    00254     while(packet[i++] != ',');              // next field: 'K'
    00255     while(packet[i++] != '*');              // next field: checksum
    00256
    00257     GpsInfo.VelHS.updates++;
    00258 }
    00259