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

Generated on Tue Sep 20 03:11:43 2005 for Procyon AVRlib by  doxygen 1.4.2