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 

Generated on Sun Oct 29 03:41:07 2006 for Procyon AVRlib by  doxygen 1.4.2