A porting of a GPS decoding and presenting program within the mbos RTOS. It is not a definitive application but a study program to test NMEA full decoding library and a first approach to an RTOS. Many thanks to Andrew Levido for his support and his patience on teaching me the RTOS principles from the other side of the Earth. It uses NMEA library by Tim (xtimor@gmail.com) ported by Ken Todotani (http://mbed.org/users/todotani/) on public mbed library (http://mbed.org/users/todotani/programs/GPS_nmeaLib/5yo4h) also available, as original universal C library, on http://nmea.sourceforge.net

Dependencies:   mbos Watchdog TextLCD mbed ConfigFile

Files at this revision

API Documentation at this revision

Comitter:
guiott
Date:
Sun Jan 29 16:06:12 2012 +0000
Child:
1:360c4a23cb1d
Commit message:

Changed in this revision

Common.h Show annotated file Show diff for this revision Revisions of this file
Init.h Show annotated file Show diff for this revision Revisions of this file
LeonardoMbos.cpp Show annotated file Show diff for this revision Revisions of this file
Prototype.h Show annotated file Show diff for this revision Revisions of this file
Startup.cpp Show annotated file Show diff for this revision Revisions of this file
Startup.h Show annotated file Show diff for this revision Revisions of this file
Tasks.h Show annotated file Show diff for this revision Revisions of this file
TextLCD.lib Show annotated file Show diff for this revision Revisions of this file
Watchdog.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
mbos.lib Show annotated file Show diff for this revision Revisions of this file
nmea/config.h Show annotated file Show diff for this revision Revisions of this file
nmea/context.c Show annotated file Show diff for this revision Revisions of this file
nmea/context.h Show annotated file Show diff for this revision Revisions of this file
nmea/generate.h Show annotated file Show diff for this revision Revisions of this file
nmea/generator.h Show annotated file Show diff for this revision Revisions of this file
nmea/gmath.c Show annotated file Show diff for this revision Revisions of this file
nmea/gmath.h Show annotated file Show diff for this revision Revisions of this file
nmea/info.c Show annotated file Show diff for this revision Revisions of this file
nmea/info.h Show annotated file Show diff for this revision Revisions of this file
nmea/nmea.h Show annotated file Show diff for this revision Revisions of this file
nmea/parse.c Show annotated file Show diff for this revision Revisions of this file
nmea/parse.h Show annotated file Show diff for this revision Revisions of this file
nmea/parser.c Show annotated file Show diff for this revision Revisions of this file
nmea/parser.h Show annotated file Show diff for this revision Revisions of this file
nmea/sentence.c Show annotated file Show diff for this revision Revisions of this file
nmea/sentence.h Show annotated file Show diff for this revision Revisions of this file
nmea/time.c Show annotated file Show diff for this revision Revisions of this file
nmea/time.h Show annotated file Show diff for this revision Revisions of this file
nmea/tok.c Show annotated file Show diff for this revision Revisions of this file
nmea/tok.h Show annotated file Show diff for this revision Revisions of this file
nmea/units.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Common.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,9 @@
+#define PCBAUD 115200
+#define GPSRX p10
+#define GPSBAUD 4800
+#define BUFF_SIZE 256
+
+#define LCD_LIGHT_DIM_TIMER 5000
+#define SHOW_LCD_TIMER 500
+#define TEMP_TIMER 500
+#define WDT_TIMER 5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Init.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,52 @@
+// Ports initialization
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+Serial pc(USBTX, USBRX);
+Serial gps(NC, GPSRX);
+
+PwmOut LcdBklight(p25);
+AnalogIn KeypadIn(p20);
+
+// Globals
+int size;
+int X=0, Y=0;
+char Key='-';
+
+char msgBuff[2][BUFF_SIZE];     // Receive data buffer from GPS module
+                                // Two buffer for double buffering
+volatile int writePointer = 0;  // Write pointer for active data buffer
+volatile unsigned int bufferSelect = 0; // Active buffer selector
+
+double latitude, longitude;
+double degrees, minutes;
+
+int SetTimeOk=0; // is RTC in sync?
+int PcMonitor=0;    // to control serial out on USB serial
+int Menu = 0;
+const char *Lab[]={"MAG", "DIR", "GPS"}; //Label to display in compass view
+int CmpPos[]={0,15,0}; //Compass position
+int Ang[3]; //Compass angle values
+enum DirLab{Mag, Dir, Gps};
+
+nmeaINFO info;                  // Store GPS information 
+nmeaPARSER parser;
+
+typedef struct _DegMinSec
+{
+    int Deg;         
+    int Min; 
+    double Sec;        
+ } DegMinSec;
+
+typedef struct _DistAzimuth
+{
+    double Dist; 
+    double Azimuth[2];
+ } DistAzimuth;
+  
+ DistAzimuth Path;
+ nmeaPOS Pos[2];
+ nmeaINFO Dest;
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LeonardoMbos.cpp	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,925 @@
+/* ////////////////////////////////////////////////////////////////////////////
+** File:      LeonardoMbos.cpp
+*/    
+/*               12345678901234567890                                        */                               
+ char  Ver1[] = "Leonardo's GPS 0.1.0";
+ char  Ver2[] = "  by Guiott  01-12";
+/**
+* \mainpage Leonardo.cpp
+* \author   Guido Ottaviani-->guido@guiott.com<--
+* \version  0.1.0
+* \date     01/2012
+* \details This is a test program to study the capability of a GPS module to
+   control navigation of a robot in an outdoor environment.
+        
+   This version is developed within the mbos RTOS:
+   http://mbed.org/users/AndrewL/libraries/mbos/lqn3ca
+        
+   It uses NMEA library by Tim (xtimor@gmail.com) 
+   available on public mbed library or http://nmea.sourceforge.net
+        
+ The original gmath.c has been modified to fix a bug in nmea_distance_ellipsoid() function
+ according to bug report ID: 2945855
+ 
+ http://sourceforge.net/tracker/?func=detail&aid=2945855&group_id=192054&atid=939854
+ 
+    // while ((delta_lambda > 1e-12) && (remaining_steps > 0))  original by xtimor
+    while (( remaining_steps == 20 ) || ((fabs(delta_lambda) > 1e-12) && (remaining_steps > 0)))
+    
+ the original code always returns a zero distance if the arrival point longitude
+ is equal or smaller than the starting point one.
+    
+ The mbed module is interfaced with a Garmin GPS sensor (used in standard mode)
+ with an external antenna, a 20x4 LCD text display and a 5 keys keypad.
+ A curiosity:
+ All the hardware components of the test set are mounted on the top of a wooden 
+ box, looking like a kind of a steampunk navigator. When my daughter looked at 
+ the box she said: "it looks alike the navigator of the da Vinci car".
+ This is the reason why the name of this project is "Leonardo".
+**
+-------------------------------------------------------------------------------
+* \copyright 2012 Guido Ottaviani
+guido@guiott.com
+
+    LeonardoMbos is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    dsPID33 is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with LeonardoMbos.cpp.  If not, see <http://www.gnu.org/licenses/>.
+    
+-------------------------------------------------------------------------------      
+*/
+#include "Common.h"
+#include "mbed.h"
+#include <string>
+#include "TextLCD.h"
+#include "nmea/nmea.h"
+#include "Init.h" 
+#include "Prototype.h"
+#include "mbos.h"
+#include "Tasks.h"
+#include <Watchdog.h>
+
+TextLCD lcd(p12, p11, p24, p23, p22, p21, TextLCD::LCD20x4); // rs, e, d4-d7
+
+Watchdog wd;
+
+// Set up RTOS;
+mbos os(NUM_TASKS, NUM_TIMERS, NUM_RESOURCES);
+
+int main() 
+{
+    Initialize();
+    if (wd.WatchdogCausedReset())
+    {
+        pc.printf("Watchdog caused reset**********************************\r\n");
+    }
+    wd.Configure(WDT_TIMER);       // sets the timeout interval
+
+    os.Start(); // the RTOS starts now
+}
+
+//functions =====================================================================
+
+int CmpRead(void)
+{/**
+ *\brief Magnetic Compass reading 
+ */
+    int Cmp;
+
+    // To Be Done
+    Cmp = 0; // ************debug
+    return(Cmp);
+}
+
+void mbosIdleTask(void)
+{/**
+ *\brief TASK 0 watchdog kick
+ */
+ while(1)
+ {
+    wd.Service();       // kick the dog before the timeout
+ }
+}
+
+void TempTask(void)
+{/**
+ *\brief TASK 8 used to temporary test some functions 
+ */
+ static int TempAng;
+ while (1)
+ {
+  os.WaitEvent(TEMP_EVT); 
+  
+  if((TempAng+=5) >=360)
+  {
+    TempAng=0;
+  }
+  Ang[Mag]=TempAng;
+  Ang[Dir]=360-TempAng;
+  Ang[Gps]=180-TempAng;
+  printf("%i %i  %i \n", Ang[0], Ang[1], Ang[2]);
+ }
+}
+
+void GpsStringParse(void)
+{/**
+ *\brief parse the GPS string to extract info
+ */
+    gps.attach(NULL);   // Suspend serial interrupt while buffer change
+    size = writePointer;
+    writePointer = 0;
+    bufferSelect++;     // Change buffer
+    gps.attach( &GpsSerialIsr );  // Resume serial interrupt
+    nmea_parse(&parser, msgBuff[(bufferSelect-1)&1], size, &info);
+    Coordinates(); // transform nmea coordinates in decimal degrees
+}
+
+void GpsDist(void)
+{/**
+ *\brief compute the distance and direction (forward and reverse) 
+    from point A to point B on the ellipsoid
+ */
+  
+    nmea_info2pos(&info, &Pos[0]);  // current position  
+    nmea_info2pos(&Dest, &Pos[1]);  // destination 
+
+    Path.Dist = nmea_distance_ellipsoid(&Pos[0], &Pos[1], &Path.Azimuth[1], &Path.Azimuth[0]);
+
+    if(Path.Azimuth[0] > NMEA_PI) 
+    {// reverse direction
+        Path.Azimuth[0] = Path.Azimuth[0] - NMEA_PI; 
+    }
+    else
+    {
+        Path.Azimuth[1] = Path.Azimuth[1] + NMEA_PI; 
+    }
+
+    for(int i=0; i < 2; i++)
+    {
+        Path.Azimuth[i]=(nmea_radian2degree(Path.Azimuth[i]));
+        if(Path.Azimuth[i] > 360)
+        {
+            Path.Azimuth[i] = Path.Azimuth[i] - 360;
+        }
+        if(Path.Azimuth[i] < 0)
+        {
+            Path.Azimuth[i] = Path.Azimuth[i] + 360;
+        }
+    }
+}
+
+void LcdLightDimTask(void)
+{/** 
+ *\brief TASK 7, control the LCD backlight intensity to smoothly
+         switch it on or off
+ */
+ static float LightVal=1;
+        
+ while(1)
+ {       
+    os.WaitEvent(LCD_LIGHT_DIM_ON_EVT | LCD_LIGHT_DIM_OFF_EVT); 
+    if(os.GetEvent()==LCD_LIGHT_DIM_ON_EVT)
+    {
+      if(LightVal<1)
+      {
+        for (LightVal=0; LightVal<=1; LightVal+=0.01f)
+        {
+            LcdBklight=LightVal;
+            wait_ms(10);
+        }
+      }
+    // Set the timer for the power saving backlight switch off
+    os.ClearTimer(LCD_LIGHT_DIM_OFF_TMR);
+    os.SetTimer(LCD_LIGHT_DIM_OFF_TMR, LCD_LIGHT_DIM_TIMER, 0);
+    }
+    else if(os.GetEvent()==LCD_LIGHT_DIM_OFF_EVT)
+    {// The dimming off is slower than lighting up
+        for (LightVal=1; LightVal>=0; LightVal-=0.01f)
+        {
+            LcdBklight=LightVal;           
+            wait_ms(30);
+        }        
+    }
+ }
+}
+
+void Coordinates(void)
+{/**
+ *\brief transform nmea coordinates in decimal degrees
+ */
+    degrees = trunc(info.lat / 100.0);
+    minutes = info.lat - (degrees * 100.0);
+    latitude = degrees + minutes / 60.0;
+    degrees = trunc(info.lon / 100.0);
+    minutes = info.lon - (degrees * 100.0);
+    longitude = degrees + minutes / 60.0;
+ }
+  
+void Deg2DegMinSec(double DecDeg, DegMinSec *DecSec)
+{/**
+ *\brief convert decimalDeg to Deg Min decimalSec
+ */
+    DecSec->Deg = trunc(DecDeg);
+    double MinDec = (DecDeg - DecSec->Deg);
+    DecSec->Min = trunc(MinDec * 60);
+    DecSec->Sec = (MinDec * 3600) - (DecSec->Min * 60);
+ }
+   
+void ShowPcTask(void) 
+{/**
+ *\brief TASK 6, if a PC is connected, debug information can be sent to the console
+ */
+ static int it = 0;
+ int i;
+ DegMinSec DecCoord;
+    
+ os.SetTimer(SHOW_PC_TMR, 1000, 1000);
+ while(1)
+ {
+    os.WaitEvent(SHOW_PC_EVT); 
+
+    if(pc.readable())
+    {// wait for an input
+        PcMonitor = (pc.getc()-48); // digit a number to en/dis-able debug
+     }
+     
+    if( PcMonitor==1 || PcMonitor>5)
+    {// Display Info parameters 
+        pc.printf(
+        "%03d, Lat: %f, Lon: %f, Sig:%d, Fix:%d, Inuse:%d\r\n",
+        it++, latitude, longitude, info.sig, info.fix, info.satinfo.inuse );
+        for (i = 0; i < NMEA_MAXSAT; i++) 
+            {
+            if (info.satinfo.sat[i].sig > 0)
+            pc.printf("  sat_id:%02d, sig:%02d, Inuse:%d\r\n",
+                      info.satinfo.sat[i].id , info.satinfo.sat[i].sig, 
+                      info.satinfo.sat[i].in_use);
+            }
+        pc.printf("\r\n");
+    }
+    
+    if( PcMonitor==2 || PcMonitor>5)
+    {// Display Distance parameters 
+        Deg2DegMinSec(nmea_radian2degree(Pos[0].lat), &DecCoord);
+        pc.printf("Lat1:%d %d\'%.3f\"  ", DecCoord.Deg, DecCoord.Min, DecCoord.Sec);
+        Deg2DegMinSec(nmea_radian2degree(Pos[0].lon), &DecCoord);
+        pc.printf("Lon1:%d %d\'%.3f\"  ", DecCoord.Deg, DecCoord.Min, DecCoord.Sec);
+        Deg2DegMinSec(nmea_radian2degree(Pos[1].lat), &DecCoord);
+        pc.printf("Lat2:%d %d\'%.3f\"  ", DecCoord.Deg, DecCoord.Min, DecCoord.Sec);
+        Deg2DegMinSec(nmea_radian2degree(Pos[1].lon), &DecCoord);
+        pc.printf("Lon2:%d %d\'%.3f\"  \n", DecCoord.Deg, DecCoord.Min, DecCoord.Sec);
+        pc.printf("Dist:%f  Azimuth Start:%f  Azimuth Final:%f \n\n",
+                  Path.Dist, Path.Azimuth[0], Path.Azimuth[1]); 
+    }
+  }   
+}
+
+void ShowLcdTask(void)
+{/**
+ *\brief TASK 3, display desired data on LCD
+ */
+ 
+ static int Previous=0;
+
+ os.SetTimer(SHOW_LCD_TMR, SHOW_LCD_TIMER, 0);
+ while(1)
+ {
+ os.WaitEvent(SHOW_LCD_EVT);
+
+    if(Previous != Menu)
+    {// clear the display when function changes
+        lcd.cls();
+        Previous=Menu;
+    }
+    
+    switch(Menu)
+    {
+        case 0:
+            showSatLcd();
+            Previous=0;
+            break;
+            
+        case 1:
+            if(info.sig != 0)
+            {
+                showInfoLcd();
+            }
+            else
+            {
+                showSatLcd();
+            }
+            Previous=1;    
+            break;
+        
+        case 2:
+            showMenuLcd();
+            Previous=2;    
+            break;
+            
+        case 3:
+            showMenuLcd1();
+            Previous=3;    
+            break;  
+            
+        case 4: 
+            static int ChooseDir=0;
+            Ang[Gps]=info.direction;
+            Ang[Mag]=CmpRead()-info.declination; //Compass reading corrected by declination
+            Ang[Dir]=Path.Azimuth[0];
+
+            ChooseDir++;
+            if(ChooseDir<7)
+            {
+                showDirLcd(Mag);
+            }
+            else if(ChooseDir>=7 && ChooseDir<12)
+            {
+                showDirLcd(Gps);
+            }
+            else if(ChooseDir>=12)
+            {
+                ChooseDir=0;
+            }
+            showDirLcd(Dir);
+
+            Previous=4;    
+            break; 
+            
+        default:
+            showInfoLcd();
+            break;
+    }
+    //restart timer for other options
+    os.SetTimer(SHOW_LCD_TMR, SHOW_LCD_TIMER, 0); 
+ }
+}
+
+void showDirLcd(int Indx)
+{/**
+ *\brief  display a sort of compass on LCD
+ */
+    int Angle;
+
+    Angle=Ang[Indx]/18;
+
+    lcd.locate(CmpPos[Indx],0);
+    lcd.printf("  %c  ",0xA5);
+    lcd.locate(CmpPos[Indx],1);
+    lcd.printf("%c   %c",0xA5, 0xA5);
+    lcd.locate(CmpPos[Indx],2);
+    lcd.printf("%c   %c",0xA5, 0xA5);
+    lcd.locate(CmpPos[Indx],3);
+    lcd.printf("  %c  ",0xA5);
+    
+    lcd.locate(CmpPos[Indx]+1,1);
+    lcd.printf(Lab[Indx]);
+    lcd.locate(CmpPos[Indx]+1,2);
+    lcd.printf("%03i",Ang[Indx]);
+        
+    switch (Angle)
+    {
+        case 0:
+            lcd.locate(CmpPos[Indx]+2,0);
+            lcd.printf("%c",0xFF);
+            break;
+        case 1:
+            lcd.locate(CmpPos[Indx]+2,0);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+3,0);
+            lcd.printf("%c",0xFF);
+            break;
+        case 2:
+            lcd.locate(CmpPos[Indx]+3,0);
+            lcd.printf("%c",0xFF);
+            break;        
+        case 3:
+            lcd.locate(CmpPos[Indx]+3,0);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+4,1);
+            lcd.printf("%c",0xFF);
+            break;        
+        case 4:
+            lcd.locate(CmpPos[Indx]+4,1);
+            lcd.printf("%c",0xFF);
+            break;
+        case 5:       
+            lcd.locate(CmpPos[Indx]+4,1);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+4,2);
+            lcd.printf("%c",0xFF);
+            break;
+        case 6:   
+            lcd.locate(CmpPos[Indx]+4,2);
+            lcd.printf("%c",0xFF);
+            break;
+        case 7:       
+            lcd.locate(CmpPos[Indx]+4,2);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+3,3);
+            lcd.printf("%c",0xFF);
+            break;
+        case 8:   
+            lcd.locate(CmpPos[Indx]+3,3);
+            lcd.printf("%c",0xFF);
+            break;
+        case 9:       
+            lcd.locate(CmpPos[Indx]+3,3);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+2,3);
+            lcd.printf("%c",0xFF);
+            break;
+        case 10:   
+            lcd.locate(CmpPos[Indx]+2,3);
+            lcd.printf("%c",0xFF);
+            break;     
+        case 11:       
+            lcd.locate(CmpPos[Indx]+2,3);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+1,3);
+            lcd.printf("%c",0xFF);
+            break;
+        case 12:   
+            lcd.locate(CmpPos[Indx]+1,3);
+            lcd.printf("%c",0xFF);
+            break;     
+        case 13:       
+            lcd.locate(CmpPos[Indx]+1,3);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+0,2);
+            lcd.printf("%c",0xFF);
+            break;
+        case 14:   
+            lcd.locate(CmpPos[Indx]+0,2);
+            lcd.printf("%c",0xFF);
+            break;  
+        case 15:       
+            lcd.locate(CmpPos[Indx]+0,2);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+0,1);
+            lcd.printf("%c",0xFF);
+            break;
+        case 16:   
+            lcd.locate(CmpPos[Indx]+0,1);
+            lcd.printf("%c",0xFF);
+            break;  
+        case 17:       
+            lcd.locate(CmpPos[Indx]+0,1);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+1,0);
+            lcd.printf("%c",0xFF);
+            break;   
+        case 18:   
+            lcd.locate(CmpPos[Indx]+1,0);
+            lcd.printf("%c",0xFF);
+            break;  
+        case 19:       
+            lcd.locate(CmpPos[Indx]+1,0);
+            lcd.printf("%c",0xFF);
+            lcd.locate(CmpPos[Indx]+2,0);
+            lcd.printf("%c",0xFF);
+            break;   
+    }
+}
+
+void showMenuLcd(void)
+{/**
+ *\brief  display a selection menu on LCD
+ */
+    lcd.locate(0,0);
+    lcd.printf("1 - item 1");
+    lcd.locate(0,1);
+    lcd.printf("2 - item 2");
+    lcd.locate(0,2);
+    lcd.printf("3 - item 3");
+    lcd.locate(0,3);
+    lcd.printf("4 - item 4");    
+}
+
+void showMenuLcd1(void)
+{/**
+ *\brief  display a selection menu on LCD
+ */
+    lcd.locate(0,0);
+    lcd.printf("5 - item 5");
+    lcd.locate(0,1);
+    lcd.printf("6 - item 6");
+    lcd.locate(0,2);
+    lcd.printf("7 - item 7");
+    lcd.locate(0,3);
+    lcd.printf("8 - item 8");    
+}
+
+void showSatLcd(void) 
+{/**
+ *\brief displays satellite informations
+ */
+    for (int i = 0; i < NMEA_MAXSAT; i++) 
+    {
+        if(info.satinfo.sat[i].id < 20)
+        {
+            lcd.locate((info.satinfo.sat[i].id % 20) - 1,0);
+        }
+        else
+        {
+            lcd.locate((info.satinfo.sat[i].id % 20) - 1,1);    
+        }
+        
+        if (info.satinfo.sat[i].sig > 0)
+        {
+            lcd.printf("%d",info.satinfo.sat[i].sig/10);
+        }
+        else
+        {
+            lcd.printf(" ");    
+        }                   
+    }
+    lcd.locate(0,2);
+    lcd.printf("12345678901234567890");
+    lcd.locate(0, 3);
+    lcd.printf("P%2.1f H%2.1f V%2.1f %iD",
+    info.PDOP, info.HDOP, info.VDOP,info.fix);
+}    
+    
+void showInfoLcd(void) 
+{/**
+ *\brief Show nmea info on LCD 
+ */
+
+//    static int lastSat = 0;
+//    int satInview = 0;
+
+ if(info.sig != 0)
+ { 
+    lcd.locate(0, 0);
+    lcd.printf("%2.5f%c %3.5f%c",
+            latitude, info.lat >= 0 ? 'N': 'S',  
+            longitude, info.lon >= 0 ? 'E': 'W');
+  
+    lcd.locate(0, 1);
+    lcd.printf("H%.0f D%.0f_%.1f %iD", info.elv, info.direction, info.declination, info.fix);
+
+    lcd.locate(0, 2);
+    lcd.printf("P%2.1f H%2.1f V%2.1f S%i/%i",
+        info.PDOP, info.HDOP, info.VDOP, info.satinfo.inuse, info.satinfo.inview);
+        
+   /* lcd.locate(0, 3);
+    lcd.printf("%02d-%02d-%04d %02d:%02d:%02d ", 
+        info.utc.day, info.utc.mon + 1, info.utc.year + 1900,
+        info.utc.hour, info.utc.min, info.utc.sec); // Display JST (UTC + 9)
+   */
+
+/*
+    lcd.locate(0, 5);
+    for (int i = 0; i < NMEA_MAXSAT; i++) {
+        if (info.satinfo.sat[i].sig > 0) {
+            satInview++;
+            lcd.printf("  sat_id:%02d, sig:%02d, Inuse:%d \n",
+                      info.satinfo.sat[i].id , info.satinfo.sat[i].sig,
+                      info.satinfo.sat[i].in_use);
+        }
+    }
+    for (int j = satInview; j <= lastSat; j++)
+        lcd.printf("                             \n");     // delete line
+    lastSat = satInview;
+ */
+ 
+ } 
+ else
+ {
+    lcd.cls();
+    lcd.locate(0,0);
+    lcd.printf("NO FIX"); 
+ }
+
+ // Grab a snapshot of the current RTC time.
+ time_t seconds = time(NULL);
+ char buffer[32];
+ if((info.sig != 0)&&(SetTimeOk!=0))  
+ {
+    strftime(buffer, 32, "%x %X", localtime(&seconds));
+ }
+ else
+ {// if GPS time not valid doesn't display seconds
+     strftime(buffer, 32, "%x %H:%M", localtime(&seconds));
+     SetTimeOk = 0; // RTC was not set to a valid time 
+ }
+ lcd.locate(0,3);
+ lcd.printf("%s", buffer);
+}
+
+void SetTimeTask(void)
+{/**
+ *\brief TASK 5, Set RTC system time if the GPS time is valid
+ */
+ struct tm t;
+ 
+ os.SetTimer(SET_TIME_TMR, 60000, 60000);
+ while(1)
+ {  
+ os.WaitEvent(SET_TIME_EVT);
+
+    if(info.sig != 0)    
+    {
+       t.tm_mday=info.utc.day;
+       t.tm_mon=info.utc.mon;
+       t.tm_year=info.utc.year; 
+       t.tm_hour=info.utc.hour;
+       t.tm_min=info.utc.min;
+       t.tm_sec=info.utc.sec;        
+          
+        time_t seconds = mktime(&t);       
+        set_time(seconds);
+        
+        SetTimeOk = 1; // RTC was set 
+    }
+ }    
+}
+
+void LedBlinkTask(void)
+{/**
+ *\brief TASK 4
+         LED 1: Quick blink=NOT fix, Slow blink=fix OK  
+         LED 2: blinks proportionally to HDOP
+         LED 3: blinks proportionally to VDOP
+ */
+
+ static int LedCnt1=0;
+ //    static int LedCnt2=0;
+ int OnH=0;
+ int OnV=0;
+
+ #define MAX 20
+  
+ os.SetTimer(LED_BLINK_TMR, 100, 100);
+
+ while(1)
+ {
+    os.WaitEvent(LED_BLINK_EVT);
+            
+    if((info.HDOP>0)&&(info.HDOP<=2))
+    {
+        OnH=2;
+    }
+    else if((info.HDOP>2)&&(info.HDOP<=4))
+    {
+        OnH=4;    
+    }
+    else if((info.HDOP>4)&&(info.HDOP<=6))
+    {
+        OnH=6;    
+    }
+    else if((info.HDOP>6))
+    {
+        OnH=MAX/2;    
+    }        
+
+    if((info.VDOP>0)&&(info.VDOP<=2))
+    {
+        OnV=2;
+    }
+    else if((info.VDOP>2)&&(info.VDOP<=4))
+    {
+        OnV=4;    
+    }
+    else if((info.VDOP>4)&&(info.VDOP<=6))
+    {
+        OnV=6;    
+    }
+    else if((info.VDOP>6))
+    {
+        OnV=MAX/2;    
+    } 
+           
+    if(info.sig == 0)
+    {
+        led1=!led1;
+        led2=0;
+        led3=0;
+    }
+    else
+    {
+       if(LedCnt1<=MAX/2)
+       {
+            LedCnt1++;
+            led1=0;
+            if(LedCnt1<OnH)
+            {
+               led2=!led2; 
+            }
+            else 
+            {
+                led2=0;
+            }    
+            
+            if(LedCnt1<OnV)
+            {
+               led3=!led3; 
+            }
+            else 
+            {
+                led3=0;
+            }          
+       } 
+       else if((LedCnt1>MAX/2)&&(LedCnt1<=MAX))
+       {
+            LedCnt1++;
+            led1=1;
+            led2=0;
+            led3=0;
+       }
+       else if(LedCnt1>MAX)
+       {
+            LedCnt1=0;       
+       }
+    }
+ }
+}
+
+
+void KeypadTask(void)
+{/**
+ *\brief TASK 2, Keypad management. 
+         It uses just one ADC port. Five keys switch a 5 resistor ladder
+         obtaining a unique voltage for each key, with a priority that 
+         depends from the position of the resistor in the ladder.
+         This function makes an average of 50 analog values (50ms) before 
+         confirming the output, to filter out some noise and debounce keys
+ */
+
+    static float KeypadAcc;         // accumulator to compute average
+    static float KeypadPrev;        // previous value to compute variation 
+    static int KeypadCount;         // all samples number
+    static int KeypadRealCount;     // valid samples only
+    float KeypadVal;  
+    static char KeyPrev='-';
+    
+    os.SetTimer(KEYPAD_TMR, 1, 1);
+    while(1)
+    {
+        os.WaitEvent(KEYPAD_EVT);
+        float InValue = KeypadIn.read();
+        if ((InValue > 0.3) && (abs(InValue - KeypadPrev) < 0.1))
+        {// makes the average only of the values above a threshold 
+         // and within an almost stable range
+            KeypadAcc+=InValue;
+            KeypadRealCount++;
+        }
+            
+        KeypadCount++;
+        KeypadPrev=InValue;
+    
+        if (KeypadCount >=50)
+        {
+            if(KeypadRealCount > 25)
+            {
+                KeypadVal=KeypadAcc/KeypadRealCount;
+            }
+            else
+            {// not enough values to average
+    
+                KeypadVal=0;
+            }
+           
+            KeypadAcc=0;
+            KeypadCount=0;
+            KeypadRealCount=0;
+         
+            if(KeypadVal <0.15)
+            {
+                Key='-';
+            }
+            else if(KeypadVal>=0.3 && KeypadVal<0.35)
+            {
+                Key='E';
+            }
+            else if(KeypadVal>=0.42 && KeypadVal<0.50)
+            {
+                Key='v';
+            }
+            else if(KeypadVal>=0.60 && KeypadVal<0.65)
+            {
+                Key='^';
+            }
+            else if(KeypadVal>=0.74 && KeypadVal<0.78)
+            {
+                Key='>';
+            }        
+            else if(KeypadVal>=0.85)
+            {
+                Key='<';
+            }
+            
+            if (Key!='-' && Key!=KeyPrev)
+            {// switch on the LCD backlight if key pressed
+                os.SetEvent(LCD_LIGHT_DIM_ON_EVT, LCD_LIGHT_DIM_TASK);
+            }
+            KeyPrev=Key;
+            switch (Key)
+            {
+                case '^':
+                    Menu=0;
+                break;
+     
+                case '>':
+                    Menu=1;
+                break;           
+     
+                case 'v':
+                    Menu=2;
+                break;
+                
+                case '<':
+                    Menu=3;
+                break;
+                
+                case 'E':
+                    Menu=4;
+                break;
+            }     
+       }
+   } 
+}
+
+void trace_h(const char *str, int str_size) 
+{/**
+ *\brief output on console what's received on GPS serial
+          Callback function for NMEA parser buffer trace
+ */
+    if( PcMonitor==5 || PcMonitor>5)
+    {
+        for (int i = 0; i < str_size; i++)
+        {
+            pc.putc(*str++);
+        }        
+    }
+}
+
+void error_h(const char *str, int str_size) 
+{/**
+ *\brief Callback function for NMEA parser error
+ */
+    for (int i = 0; i < str_size; i++)
+    {
+        pc.putc(*str++);
+    }    
+}
+
+void GpsSerialTask(void) 
+{/**
+ *\brief TASK 1, wait for the event then get the input char
+ */
+ while(1)
+ {
+    os.WaitEvent(GPS_SERIAL_IN_EVT);
+    GpsStringParse();
+            
+    Dest.lat= 4151.32496; // ***************debug
+    Dest.lon= 1229.34; // *************debug
+
+    GpsDist();
+ }
+}
+
+void GpsSerialIsr(void) 
+{/**
+ *\brief Interrupt handler for serial Rx
+         set the event for the serial task
+ */
+    char c = gps.getc();
+    msgBuff[bufferSelect & 1][writePointer] = c;
+    if (writePointer++ == BUFF_SIZE)
+    {
+        writePointer = 0;
+    }
+    if (writePointer > 200) 
+    {// GPS input buffer full, start computing coordinates
+        os.SetEvent(GPS_SERIAL_IN_EVT, GPS_SERIAL_TASK);
+    }
+}
+
+double trunc(double v) 
+{/**
+ *\brief Return nearest integer vaule less than input
+ *
+ *\parameters double variable to get nearest ingeger
+ *
+ *\return double 
+ */
+    if(v < 0.0) 
+    {
+        v*= -1.0;
+        v = floor(v);
+        v*=-1.0;
+    } else {
+        v = floor(v);
+    }
+    return v;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Prototype.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,26 @@
+//================= Prototypes =================
+int CmpRead(void);
+void TempTask(void);
+void LcdLightDimTask(void);
+void Initialize (void);
+int TimerStart(void);
+void TimerStop(int Tstart, int Index);
+void GpsStringParse(void);
+void GpsDist(void);
+void Deg2DegMinSec(double DecDeg, DegMinSec *DecSec);
+void GpsDist(void);
+void showDirLcd(int Indx);
+void showMenuLcd1(void);
+void showMenuLcd(void);
+void showSatLcd(void);
+void SetTime(void);
+void Coordinates(void);
+void LedBlink(void);
+void GpsSerialIsr(void);
+void showInfoLcd(void);
+void showInfoPc(void);
+void trace_h(const char *str, int str_size);
+void error_h(const char *str, int str_size);
+double trunc(double v);
+//===============================================
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Startup.cpp	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,60 @@
+#include "Startup.h"
+
+void Initialize (void)
+{
+// initialize serial ports
+pc.baud(PCBAUD); // USB/serial
+gps.baud(GPSBAUD);
+
+gps.attach( &GpsSerialIsr );  // Start serial interrupt
+
+nmea_property()->trace_func = &trace_h;
+nmea_property()->error_func = &error_h;
+nmea_zero_INFO(&info);
+nmea_parser_init(&parser);
+     
+LcdBklight = 0;
+wait(0.5);
+lcd.cls();
+LcdBklight=1; // Backlight on
+
+// LCD splash screen
+lcd.locate(0,1);
+lcd.printf(Ver1);
+lcd.locate(0,2);
+lcd.printf(Ver2);
+wait(4.0);
+lcd.cls();
+   
+// Console splash screen
+pc.printf(Ver1); 
+pc.printf("\n");   
+pc.printf(Ver2); 
+pc.printf("\n"); 
+pc.printf("input a number to enable debug, 0 to disable\n");
+
+os.CreateTask(GPS_SERIAL_TASK, GPS_SER_PRIORITY, GPS_SER_STACK_SZ, GpsSerialTask);
+os.CreateTask(KEYPAD_TASK, KEYPAD_PRIORITY, KEYPAD_STACK_SZ, KeypadTask);
+os.CreateTask(SHOW_LCD_TASK, SHOW_LCD_PRIORITY, SHOW_LCD_STACK_SZ, ShowLcdTask);
+os.CreateTask(LED_BLINK_TASK, LED_BLINK_PRIORITY, LED_BLINK_STACK_SZ, LedBlinkTask);
+os.CreateTask(SET_TIME_TASK, SET_TIME_PRIORITY, SET_TIME_STACK_SZ, SetTimeTask);
+os.CreateTask(SHOW_PC_TASK, SHOW_PC_PRIORITY, SHOW_PC_STACK_SZ, ShowPcTask);
+os.CreateTask(LCD_LIGHT_DIM_TASK, LCD_LIGHT_DIM_PRIORITY, LCD_LIGHT_DIM_STACK_SZ, LcdLightDimTask);
+os.CreateTask(TEMP_TASK, TEMP_PRIORITY, TEMP_STACK_SZ, TempTask);
+
+os.CreateResource(GPS_SERIAL,GPS_SERIAL_PRIO);  
+os.CreateResource(PC_SERIAL,PC_SERIAL_PRIO);  
+os.CreateResource(LCD,LCD_PRIO);  
+os.CreateResource(LCD_LIGHT_DIM,LCD_LIGHT_DIM_PRIO);
+
+os.CreateTimer(KEYPAD_TMR, KEYPAD_TASK, KEYPAD_EVT);
+os.CreateTimer(SHOW_LCD_TMR, SHOW_LCD_TASK, SHOW_LCD_EVT);
+os.CreateTimer(LED_BLINK_TMR, LED_BLINK_TASK, LED_BLINK_EVT);
+os.CreateTimer(SET_TIME_TMR, SET_TIME_TASK, SET_TIME_EVT);  
+os.CreateTimer(SHOW_PC_TMR, SHOW_PC_TASK, SHOW_PC_EVT);
+os.CreateTimer(LCD_LIGHT_DIM_OFF_TMR, LCD_LIGHT_DIM_TASK, LCD_LIGHT_DIM_OFF_EVT);
+os.CreateTimer(TEMP_TMR, TEMP_TASK, TEMP_EVT);
+
+os.SetTimer(LCD_LIGHT_DIM_OFF_TMR, LCD_LIGHT_DIM_TIMER, 0);
+// os.SetTimer(TEMP_TMR, TEMP_TIMER, TEMP_TIMER); // enabled just for test or debug
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Startup.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,20 @@
+#include "Common.h"
+#include "TextLCD.h"
+#include "nmea/nmea.h"
+#include "mbos.h"
+#include "Tasks.h"
+
+extern TextLCD lcd;
+extern mbos os;
+extern Serial pc;
+extern Serial gps;
+extern nmeaINFO info;
+extern nmeaPARSER parser;
+extern PwmOut LcdBklight;
+
+void GpsSerialIsr(void);
+void trace_h(const char *str, int str_size);
+void error_h(const char *str, int str_size);
+
+extern  char  Ver1[];
+extern  char  Ver2[];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tasks.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,89 @@
+// tasks -------------------------------
+  
+// Task 1 - GPS Serial Task
+#define GPS_SERIAL_TASK              1
+#define GPS_SER_PRIORITY            50
+#define GPS_SER_STACK_SZ          2048
+void GpsSerialTask(void);  
+
+// Task 2 - Keypad read
+#define KEYPAD_TASK                  2
+#define KEYPAD_PRIORITY             50
+#define KEYPAD_STACK_SZ            256
+void KeypadTask(void);  
+
+// Task 3 - Show LCD
+#define SHOW_LCD_TASK                3
+#define SHOW_LCD_PRIORITY           50
+#define SHOW_LCD_STACK_SZ          256
+void ShowLcdTask(void);  
+
+// Task 4 - Led Blink
+#define LED_BLINK_TASK               4
+#define LED_BLINK_PRIORITY          50
+#define LED_BLINK_STACK_SZ         256
+void LedBlinkTask(void); 
+
+// Task 5 - Set Time
+#define SET_TIME_TASK                5
+#define SET_TIME_PRIORITY           50
+#define SET_TIME_STACK_SZ          256
+void SetTimeTask(void); 
+
+// Task 6 - Show PC
+#define SHOW_PC_TASK                 6
+#define SHOW_PC_PRIORITY            50
+#define SHOW_PC_STACK_SZ           512
+void ShowPcTask(void);  
+
+// Task 7 - LCD backlight dim
+#define LCD_LIGHT_DIM_TASK           7
+#define LCD_LIGHT_DIM_PRIORITY      50
+#define LCD_LIGHT_DIM_STACK_SZ     256
+void LcdLightDimTask(void);  
+
+// Task 8 - Temp task used for tests
+#define TEMP_TASK                    8
+#define TEMP_PRIORITY               50
+#define TEMP_STACK_SZ               32
+void TempTask(void);  
+
+#define NUM_TASKS                    8
+
+// timers ------------------------------
+#define KEYPAD_TMR                   0
+#define SHOW_LCD_TMR                 1
+#define LED_BLINK_TMR                2
+#define SET_TIME_TMR                 3
+#define SHOW_PC_TMR                  4
+#define LCD_LIGHT_DIM_OFF_TMR        5
+#define TEMP_TMR                     6
+
+#define NUM_TIMERS                   7
+
+// resources ---------------------------
+#define PC_SERIAL                    0
+#define PC_SERIAL_PRIO              70
+
+#define GPS_SERIAL                   1
+#define GPS_SERIAL_PRIO             70
+
+#define LCD                          2
+#define LCD_PRIO                    70
+
+#define LCD_LIGHT_DIM                3
+#define LCD_LIGHT_DIM_PRIO          70
+
+#define NUM_RESOURCES                4
+
+// Events ------------------------------
+#define GPS_SERIAL_IN_EVT     0x00000001
+#define KEYPAD_EVT            0x00000002
+#define SHOW_LCD_EVT          0x00000004
+#define LED_BLINK_EVT         0x00000008
+#define SET_TIME_EVT          0x00000010
+#define SHOW_PC_EVT           0x00000020
+#define LCD_LIGHT_DIM_ON_EVT  0x00000040
+#define LCD_LIGHT_DIM_OFF_EVT 0x00000080
+#define TEMP_EVT              0x00000100
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextLCD.lib	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/simon/code/TextLCD/#e4cb7ddee0d3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Watchdog.lib	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/code/Watchdog/#2873f068f325
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/3991a86798e3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbos.lib	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AndrewL/code/mbos/#cf660b28b2a4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/config.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,51 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: config.h 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_CONFIG_H__
+#define __NMEA_CONFIG_H__
+
+#define NMEA_VERSION        ("0.5.3")
+#define NMEA_VERSION_MAJOR  (0)
+#define NMEA_VERSION_MINOR  (5)
+#define NMEA_VERSION_PATCH  (3)
+
+#define NMEA_CONVSTR_BUF    (256)
+#define NMEA_TIMEPARSE_BUF  (256)
+
+#if defined(WINCE) || defined(UNDER_CE)
+#   define  NMEA_CE
+#endif
+
+#if defined(WIN32) || defined(NMEA_CE)
+#   define  NMEA_WIN
+#else
+#   define  NMEA_UNI
+#endif
+
+#if defined(NMEA_WIN) && (_MSC_VER >= 1400)
+# pragma warning(disable: 4996) /* declared deprecated */
+#endif
+
+#if defined(_MSC_VER)
+# define NMEA_POSIX(x)  _##x
+# define NMEA_INLINE    __inline
+#else
+# define NMEA_POSIX(x)  x
+# define NMEA_INLINE    inline
+#endif
+
+#if !defined(NDEBUG) && !defined(NMEA_CE)
+#   include <assert.h>
+#   define NMEA_ASSERT(x)   assert(x)
+#else
+#   define NMEA_ASSERT(x)
+#endif
+
+#endif /* __NMEA_CONFIG_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/context.c	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,67 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: context.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#include "nmea/context.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+nmeaPROPERTY * nmea_property()
+{
+    static nmeaPROPERTY prop = {
+        0, 0, NMEA_DEF_PARSEBUFF
+        };
+
+    return &prop;
+}
+
+void nmea_trace(const char *str, ...)
+{
+    int size;
+    va_list arg_list;
+    char buff[NMEA_DEF_PARSEBUFF];
+    nmeaTraceFunc func = nmea_property()->trace_func;
+
+    if(func)
+    {
+        va_start(arg_list, str);
+        size = NMEA_POSIX(vsnprintf)(&buff[0], NMEA_DEF_PARSEBUFF - 1, str, arg_list);
+        va_end(arg_list);
+
+        if(size > 0)
+            (*func)(&buff[0], size);
+    }
+}
+
+void nmea_trace_buff(const char *buff, int buff_size)
+{
+    nmeaTraceFunc func = nmea_property()->trace_func;
+    if(func && buff_size)
+        (*func)(buff, buff_size);
+}
+
+void nmea_error(const char *str, ...)
+{
+    int size;
+    va_list arg_list;
+    char buff[NMEA_DEF_PARSEBUFF];
+    nmeaErrorFunc func = nmea_property()->error_func;
+
+    if(func)
+    {
+        va_start(arg_list, str);
+        size = NMEA_POSIX(vsnprintf)(&buff[0], NMEA_DEF_PARSEBUFF - 1, str, arg_list);
+        va_end(arg_list);
+
+        if(size > 0)
+            (*func)(&buff[0], size);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/context.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,44 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: context.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_CONTEXT_H__
+#define __NMEA_CONTEXT_H__
+
+#include "config.h"
+
+#define NMEA_DEF_PARSEBUFF  (1024)
+#define NMEA_MIN_PARSEBUFF  (256)
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef void (*nmeaTraceFunc)(const char *str, int str_size);
+typedef void (*nmeaErrorFunc)(const char *str, int str_size);
+
+typedef struct _nmeaPROPERTY
+{
+    nmeaTraceFunc   trace_func;
+    nmeaErrorFunc   error_func;
+    int             parse_buff_size;
+
+} nmeaPROPERTY;
+
+nmeaPROPERTY * nmea_property();
+
+void nmea_trace(const char *str, ...);
+void nmea_trace_buff(const char *buff, int buff_size);
+void nmea_error(const char *str, ...);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_CONTEXT_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/generate.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,44 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: generate.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_GENERATE_H__
+#define __NMEA_GENERATE_H__
+
+#include "sentence.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+int     nmea_generate(
+        char *buff, int buff_sz,    /* buffer */
+        const nmeaINFO *info,       /* source info */
+        int generate_mask           /* mask of sentence`s (e.g. GPGGA | GPGSA) */
+        );
+
+int     nmea_gen_GPGGA(char *buff, int buff_sz, nmeaGPGGA *pack);
+int     nmea_gen_GPGSA(char *buff, int buff_sz, nmeaGPGSA *pack);
+int     nmea_gen_GPGSV(char *buff, int buff_sz, nmeaGPGSV *pack);
+int     nmea_gen_GPRMC(char *buff, int buff_sz, nmeaGPRMC *pack);
+int     nmea_gen_GPVTG(char *buff, int buff_sz, nmeaGPVTG *pack);
+
+void    nmea_info2GPGGA(const nmeaINFO *info, nmeaGPGGA *pack);
+void    nmea_info2GPGSA(const nmeaINFO *info, nmeaGPGSA *pack);
+void    nmea_info2GPRMC(const nmeaINFO *info, nmeaGPRMC *pack);
+void    nmea_info2GPVTG(const nmeaINFO *info, nmeaGPVTG *pack);
+
+int     nmea_gsv_npack(int sat_count);
+void    nmea_info2GPGSV(const nmeaINFO *info, nmeaGPGSV *pack, int pack_idx);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_GENERATE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/generator.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,79 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: generator.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_GENERATOR_H__
+#define __NMEA_GENERATOR_H__
+
+#include "info.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * high level
+ */
+
+struct _nmeaGENERATOR;
+
+enum nmeaGENTYPE
+{
+    NMEA_GEN_NOISE = 0,
+    NMEA_GEN_STATIC,
+    NMEA_GEN_ROTATE,
+
+    NMEA_GEN_SAT_STATIC,
+    NMEA_GEN_SAT_ROTATE,
+    NMEA_GEN_POS_RANDMOVE,
+
+    NMEA_GEN_LAST
+};
+
+struct _nmeaGENERATOR * nmea_create_generator(int type, nmeaINFO *info);
+void    nmea_destroy_generator(struct _nmeaGENERATOR *gen);
+
+int     nmea_generate_from(
+        char *buff, int buff_sz,    /* buffer */
+        nmeaINFO *info,             /* source info */
+        struct _nmeaGENERATOR *gen, /* generator */
+        int generate_mask           /* mask of sentence`s (e.g. GPGGA | GPGSA) */
+        );
+
+/*
+ * low level
+ */
+
+typedef int (*nmeaNMEA_GEN_INIT)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
+typedef int (*nmeaNMEA_GEN_LOOP)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
+typedef int (*nmeaNMEA_GEN_RESET)(struct _nmeaGENERATOR *gen, nmeaINFO *info);
+typedef int (*nmeaNMEA_GEN_DESTROY)(struct _nmeaGENERATOR *gen);
+
+typedef struct _nmeaGENERATOR
+{
+    void                *gen_data;
+    nmeaNMEA_GEN_INIT    init_call;
+    nmeaNMEA_GEN_LOOP    loop_call;
+    nmeaNMEA_GEN_RESET   reset_call;
+    nmeaNMEA_GEN_DESTROY destroy_call;
+    struct _nmeaGENERATOR *next;
+
+} nmeaGENERATOR;
+
+int     nmea_gen_init(nmeaGENERATOR *gen, nmeaINFO *info);
+int     nmea_gen_loop(nmeaGENERATOR *gen, nmeaINFO *info);
+int     nmea_gen_reset(nmeaGENERATOR *gen, nmeaINFO *info);
+void    nmea_gen_destroy(nmeaGENERATOR *gen);
+void    nmea_gen_add(nmeaGENERATOR *to, nmeaGENERATOR *gen);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_GENERATOR_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/gmath.c	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,390 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: gmath.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ The original gmath.c has been modified to fix a bug in:
+  nmea_distance_ellipsoid() function
+  according to bug report ID: 2945855
+ 
+ http://sourceforge.net/tracker/?func=detail&aid=2945855&group_id=192054&atid=939854  
+      
+ // while ((delta_lambda > 1e-12) && (remaining_steps > 0))  original by xtimor
+while (( remaining_steps == 20 ) || ((fabs(delta_lambda) > 1e-12) && (remaining_steps > 0)))
+    
+    the original code always returns a zero distance if the arrival point longitude
+    is equal or smaller than the starting point one.
+
+ */
+
+/*! \file gmath.h */
+
+#include "nmea/gmath.h"
+
+#include <math.h>
+#include <float.h>
+
+/**
+ * \fn nmea_degree2radian
+ * \brief Convert degree to radian
+ */
+double nmea_degree2radian(double val)
+{ return (val * NMEA_PI180); }
+
+/**
+ * \fn nmea_radian2degree
+ * \brief Convert radian to degree
+ */
+double nmea_radian2degree(double val)
+{ return (val / NMEA_PI180); }
+
+/**
+ * \brief Convert NDEG (NMEA degree) to fractional degree
+ */
+double nmea_ndeg2degree(double val)
+{
+    double deg = ((int)(val / 100));
+    val = deg + (val - deg * 100) / 60;
+    return val;
+}
+
+/**
+ * \brief Convert fractional degree to NDEG (NMEA degree)
+ */
+double nmea_degree2ndeg(double val)
+{
+    double int_part;
+    double fra_part;
+    fra_part = modf(val, &int_part);
+    val = int_part * 100 + fra_part * 60;
+    return val;
+}
+
+/**
+ * \fn nmea_ndeg2radian
+ * \brief Convert NDEG (NMEA degree) to radian
+ */
+double nmea_ndeg2radian(double val)
+{ return nmea_degree2radian(nmea_ndeg2degree(val)); }
+
+/**
+ * \fn nmea_radian2ndeg
+ * \brief Convert radian to NDEG (NMEA degree)
+ */
+double nmea_radian2ndeg(double val)
+{ return nmea_degree2ndeg(nmea_radian2degree(val)); }
+
+/**
+ * \brief Calculate PDOP (Position Dilution Of Precision) factor
+ */
+double nmea_calc_pdop(double hdop, double vdop)
+{
+    return sqrt(pow(hdop, 2) + pow(vdop, 2));
+}
+
+double nmea_dop2meters(double dop)
+{ return (dop * NMEA_DOP_FACTOR); }
+
+double nmea_meters2dop(double meters)
+{ return (meters / NMEA_DOP_FACTOR); }
+
+/**
+ * \brief Calculate distance between two points
+ * \return Distance in meters
+ */
+double nmea_distance(
+        const nmeaPOS *from_pos,    /**< From position in radians */
+        const nmeaPOS *to_pos       /**< To position in radians */
+        )
+{
+    double dist = ((double)NMEA_EARTHRADIUS_M) * acos(
+        sin(to_pos->lat) * sin(from_pos->lat) +
+        cos(to_pos->lat) * cos(from_pos->lat) * cos(to_pos->lon - from_pos->lon)
+        );
+    return dist;
+}
+
+/**
+ * \brief Calculate distance between two points
+ * This function uses an algorithm for an oblate spheroid earth model.
+ * The algorithm is described here: 
+ * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ * \return Distance in meters
+ */
+double nmea_distance_ellipsoid(
+        const nmeaPOS *from_pos,    /**< From position in radians */
+        const nmeaPOS *to_pos,      /**< To position in radians */
+        double *from_azimuth,       /**< (O) azimuth at "from" position in radians */
+        double *to_azimuth          /**< (O) azimuth at "to" position in radians */
+        )
+{
+    /* All variables */
+    double f, a, b, sqr_a, sqr_b;
+    double L, phi1, phi2, U1, U2, sin_U1, sin_U2, cos_U1, cos_U2;
+    double sigma, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, sqr_cos_alpha, lambda, sin_lambda, cos_lambda, delta_lambda;
+    int remaining_steps; 
+    double sqr_u, A, B, delta_sigma;
+
+    /* Check input */
+    NMEA_ASSERT(from_pos != 0);
+    NMEA_ASSERT(to_pos != 0);
+
+    if ((from_pos->lat == to_pos->lat) && (from_pos->lon == to_pos->lon))
+    { /* Identical points */
+        if ( from_azimuth != 0 )
+            *from_azimuth = 0;
+        if ( to_azimuth != 0 )
+            *to_azimuth = 0;
+        return 0;    
+    } /* Identical points */
+
+    /* Earth geometry */
+    f = NMEA_EARTH_FLATTENING;
+    a = NMEA_EARTH_SEMIMAJORAXIS_M;
+    b = (1 - f) * a;
+    sqr_a = a * a;
+    sqr_b = b * b;
+
+    /* Calculation */
+    L = to_pos->lon - from_pos->lon;
+    phi1 = from_pos->lat;
+    phi2 = to_pos->lat;
+    U1 = atan((1 - f) * tan(phi1));
+    U2 = atan((1 - f) * tan(phi2));
+    sin_U1 = sin(U1);
+    sin_U2 = sin(U2);
+    cos_U1 = cos(U1);
+    cos_U2 = cos(U2);
+
+    /* Initialize iteration */
+    sigma = 0;
+    sin_sigma = sin(sigma);
+    cos_sigma = cos(sigma);
+    cos_2_sigmam = 0;
+    sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+    sqr_cos_alpha = 0;
+    lambda = L;
+    sin_lambda = sin(lambda);                            
+    cos_lambda = cos(lambda);                       
+    delta_lambda = lambda;
+    remaining_steps = 20; 
+
+  // while ((delta_lambda > 1e-12) && (remaining_steps > 0))  original by xtimor
+    while (( remaining_steps == 20 ) || ((fabs(delta_lambda) > 1e-12) && (remaining_steps > 0)))
+    { /* Iterate */
+        /* Variables */
+        double tmp1, tmp2, tan_sigma, sin_alpha, cos_alpha, C, lambda_prev; 
+
+        /* Calculation */
+        tmp1 = cos_U2 * sin_lambda;
+        tmp2 = cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda;  
+        sin_sigma = sqrt(tmp1 * tmp1 + tmp2 * tmp2);                
+        cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;   
+        tan_sigma = sin_sigma / cos_sigma;                  
+        sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma;  
+        cos_alpha = cos(asin(sin_alpha));                 
+        sqr_cos_alpha = cos_alpha * cos_alpha;                     
+        cos_2_sigmam = cos_sigma - 2 * sin_U1 * sin_U2 / sqr_cos_alpha;
+        sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam; 
+        C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
+        lambda_prev = lambda; 
+        sigma = asin(sin_sigma); 
+        lambda = L + 
+            (1 - C) * f * sin_alpha
+            * (sigma + C * sin_sigma * (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam)));                                                
+        delta_lambda = lambda_prev - lambda; 
+        if ( delta_lambda < 0 ) delta_lambda = -delta_lambda; 
+        sin_lambda = sin(lambda);
+        cos_lambda = cos(lambda);
+        remaining_steps--; 
+    }  /* Iterate */
+
+    /* More calculation  */
+    sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b; 
+    A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
+    B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
+    delta_sigma = B * sin_sigma * ( 
+        cos_2_sigmam + B / 4 * ( 
+        cos_sigma * (-1 + 2 * sqr_cos_2_sigmam) -
+        B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * sqr_cos_2_sigmam)
+        ));
+
+    /* Calculate result */
+    if ( from_azimuth != 0 )
+    {
+        double tan_alpha_1 = cos_U2 * sin_lambda / (cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda);
+        *from_azimuth = atan(tan_alpha_1);
+    }
+    if ( to_azimuth != 0 )
+    {
+        double tan_alpha_2 = cos_U1 * sin_lambda / (-sin_U1 * cos_U2 + cos_U1 * sin_U2 * cos_lambda);
+        *to_azimuth = atan(tan_alpha_2);
+    }
+
+    return b * A * (sigma - delta_sigma);
+}
+
+/**
+ * \brief Horizontal move of point position
+ */
+int nmea_move_horz(
+    const nmeaPOS *start_pos,   /**< Start position in radians */
+    nmeaPOS *end_pos,           /**< Result position in radians */
+    double azimuth,             /**< Azimuth (degree) [0, 359] */
+    double distance             /**< Distance (km) */
+    )
+{
+    nmeaPOS p1 = *start_pos;
+    int RetVal = 1;
+
+    distance /= NMEA_EARTHRADIUS_KM; /* Angular distance covered on earth's surface */
+    azimuth = nmea_degree2radian(azimuth);
+
+    end_pos->lat = asin(
+        sin(p1.lat) * cos(distance) + cos(p1.lat) * sin(distance) * cos(azimuth));
+    end_pos->lon = p1.lon + atan2(
+        sin(azimuth) * sin(distance) * cos(p1.lat), cos(distance) - sin(p1.lat) * sin(end_pos->lat));
+
+    if(NMEA_POSIX(isnan)(end_pos->lat) || NMEA_POSIX(isnan)(end_pos->lon))
+    {
+        end_pos->lat = 0; end_pos->lon = 0;
+        RetVal = 0;
+    }
+
+    return RetVal;
+}
+
+/**
+ * \brief Horizontal move of point position
+ * This function uses an algorithm for an oblate spheroid earth model.
+ * The algorithm is described here: 
+ * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ */
+int nmea_move_horz_ellipsoid(
+    const nmeaPOS *start_pos,   /**< Start position in radians */
+    nmeaPOS *end_pos,           /**< (O) Result position in radians */
+    double azimuth,             /**< Azimuth in radians */
+    double distance,            /**< Distance (km) */
+    double *end_azimuth         /**< (O) Azimuth at end position in radians */
+    )
+{
+    /* Variables */
+    double f, a, b, sqr_a, sqr_b;
+    double phi1, tan_U1, sin_U1, cos_U1, s, alpha1, sin_alpha1, cos_alpha1;
+    double tan_sigma1, sigma1, sin_alpha, cos_alpha, sqr_cos_alpha, sqr_u, A, B;
+    double sigma_initial, sigma, sigma_prev, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, delta_sigma;
+    int remaining_steps;
+    double tmp1, phi2, lambda, C, L;
+    
+    /* Check input */
+    NMEA_ASSERT(start_pos != 0);
+    NMEA_ASSERT(end_pos != 0);
+    
+    if (fabs(distance) < 1e-12)
+    { /* No move */
+        *end_pos = *start_pos;
+        if ( end_azimuth != 0 ) *end_azimuth = azimuth;
+        return ! (NMEA_POSIX(isnan)(end_pos->lat) || NMEA_POSIX(isnan)(end_pos->lon));
+    } /* No move */
+
+    /* Earth geometry */
+    f = NMEA_EARTH_FLATTENING;
+    a = NMEA_EARTH_SEMIMAJORAXIS_M;
+    b = (1 - f) * a;
+    sqr_a = a * a;
+    sqr_b = b * b;
+    
+    /* Calculation */
+    phi1 = start_pos->lat;
+    tan_U1 = (1 - f) * tan(phi1);
+    cos_U1 = 1 / sqrt(1 + tan_U1 * tan_U1);
+    sin_U1 = tan_U1 * cos_U1;
+    s = distance;
+    alpha1 = azimuth;
+    sin_alpha1 = sin(alpha1);
+    cos_alpha1 = cos(alpha1);
+    tan_sigma1 = tan_U1 / cos_alpha1;
+    sigma1 = atan2(tan_U1, cos_alpha1);
+    sin_alpha = cos_U1 * sin_alpha1;
+    sqr_cos_alpha = 1 - sin_alpha * sin_alpha;
+    cos_alpha = sqrt(sqr_cos_alpha);
+    sqr_u = sqr_cos_alpha * (sqr_a - sqr_b) / sqr_b; 
+    A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u)));
+    B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u)));
+    
+    /* Initialize iteration */
+    sigma_initial = s / (b * A);
+    sigma = sigma_initial;
+    sin_sigma = sin(sigma);
+    cos_sigma = cos(sigma);
+    cos_2_sigmam = cos(2 * sigma1 + sigma);
+    sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+    delta_sigma = 0;
+    sigma_prev = 2 * NMEA_PI;
+    remaining_steps = 20;
+
+    while ((fabs(sigma - sigma_prev) > 1e-12) && (remaining_steps > 0))
+    { /* Iterate */
+        cos_2_sigmam = cos(2 * sigma1 + sigma);
+        sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
+        sin_sigma = sin(sigma);
+        cos_sigma = cos(sigma);
+        delta_sigma = B * sin_sigma * ( 
+             cos_2_sigmam + B / 4 * ( 
+             cos_sigma * (-1 + 2 * sqr_cos_2_sigmam) - 
+             B / 6 * cos_2_sigmam * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * sqr_cos_2_sigmam)
+             ));
+        sigma_prev = sigma;
+        sigma = sigma_initial + delta_sigma;
+        remaining_steps --;
+    } /* Iterate */
+    
+    /* Calculate result */
+    tmp1 = (sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_alpha1);
+    phi2 = atan2(
+            sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_alpha1,
+            (1 - f) * sqrt(sin_alpha * sin_alpha + tmp1 * tmp1)
+            );
+    lambda = atan2(
+            sin_sigma * sin_alpha1,
+            cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_alpha1
+            );
+    C = f / 16 * sqr_cos_alpha * (4 + f * (4 - 3 * sqr_cos_alpha));
+    L = lambda -
+        (1 - C) * f * sin_alpha * (
+        sigma + C * sin_sigma *
+        (cos_2_sigmam + C * cos_sigma * (-1 + 2 * sqr_cos_2_sigmam))
+        );
+    
+    /* Result */
+    end_pos->lon = start_pos->lon + L;
+    end_pos->lat = phi2;
+    if ( end_azimuth != 0 )
+    {
+        *end_azimuth = atan2(
+            sin_alpha, -sin_U1 * sin_sigma + cos_U1 * cos_sigma * cos_alpha1
+            );
+    }
+    return ! (NMEA_POSIX(isnan)(end_pos->lat) || NMEA_POSIX(isnan)(end_pos->lon));
+}
+
+/**
+ * \brief Convert position from INFO to radians position
+ */
+void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos)
+{
+    pos->lat = nmea_ndeg2radian(info->lat);
+    pos->lon = nmea_ndeg2radian(info->lon);
+}
+
+/**
+ * \brief Convert radians position to INFOs position
+ */
+void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info)
+{
+    info->lat = nmea_radian2ndeg(pos->lat);
+    info->lon = nmea_radian2ndeg(pos->lon);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/gmath.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,92 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: gmath.h 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_GMATH_H__
+#define __NMEA_GMATH_H__
+
+#include "info.h"
+
+#define NMEA_PI                     (3.141592653589793)             /**< PI value */
+#define NMEA_PI180                  (NMEA_PI / 180)                 /**< PI division by 180 */
+#define NMEA_EARTHRADIUS_KM         (6378)                          /**< Earth's mean radius in km */
+#define NMEA_EARTHRADIUS_M          (NMEA_EARTHRADIUS_KM * 1000)    /**< Earth's mean radius in m */
+#define NMEA_EARTH_SEMIMAJORAXIS_M  (6378137.0)                     /**< Earth's semi-major axis in m according WGS84 */
+#define NMEA_EARTH_SEMIMAJORAXIS_KM (NMEA_EARTHMAJORAXIS_KM / 1000) /**< Earth's semi-major axis in km according WGS 84 */
+#define NMEA_EARTH_FLATTENING       (1 / 298.257223563)             /**< Earth's flattening according WGS 84 */
+#define NMEA_DOP_FACTOR             (5)                             /**< Factor for translating DOP to meters */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * degree VS radian
+ */
+
+double nmea_degree2radian(double val);
+double nmea_radian2degree(double val);
+
+/*
+ * NDEG (NMEA degree)
+ */
+
+double nmea_ndeg2degree(double val);
+double nmea_degree2ndeg(double val);
+
+double nmea_ndeg2radian(double val);
+double nmea_radian2ndeg(double val);
+
+/*
+ * DOP
+ */
+
+double nmea_calc_pdop(double hdop, double vdop);
+double nmea_dop2meters(double dop);
+double nmea_meters2dop(double meters);
+
+/*
+ * positions work
+ */
+
+void nmea_info2pos(const nmeaINFO *info, nmeaPOS *pos);
+void nmea_pos2info(const nmeaPOS *pos, nmeaINFO *info);
+
+double  nmea_distance(
+        const nmeaPOS *from_pos,
+        const nmeaPOS *to_pos
+        );
+
+double  nmea_distance_ellipsoid(
+        const nmeaPOS *from_pos,
+        const nmeaPOS *to_pos,
+        double *from_azimuth,
+        double *to_azimuth
+        );
+
+int     nmea_move_horz(
+        const nmeaPOS *start_pos,
+        nmeaPOS *end_pos,
+        double azimuth,
+        double distance
+        );
+
+int     nmea_move_horz_ellipsoid(
+        const nmeaPOS *start_pos,
+        nmeaPOS *end_pos,
+        double azimuth,
+        double distance,
+        double *end_azimuth
+        );
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_GMATH_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/info.c	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,21 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: info.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#include <string.h>
+
+#include "nmea/info.h"
+
+void nmea_zero_INFO(nmeaINFO *info)
+{
+    memset(info, 0, sizeof(nmeaINFO));
+    nmea_time_now(&info->utc);
+    info->sig = NMEA_SIG_BAD;
+    info->fix = NMEA_FIX_BAD;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/info.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,112 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: info.h 10 2007-11-15 14:50:15Z xtimor $
+ *
+ */
+
+/*! \file */
+
+#ifndef __NMEA_INFO_H__
+#define __NMEA_INFO_H__
+
+#include "time.h"
+
+#define NMEA_SIG_BAD        (0)
+#define NMEA_SIG_LOW        (1)
+#define NMEA_SIG_MID        (2)
+#define NMEA_SIG_HIGH       (3)
+
+#define NMEA_FIX_BAD        (1)
+#define NMEA_FIX_2D         (2)
+#define NMEA_FIX_3D         (3)
+
+#define NMEA_MAXSAT         (12)
+#define NMEA_SATINPACK      (4)
+#define NMEA_NSATPACKS      (NMEA_MAXSAT / NMEA_SATINPACK)
+
+#define NMEA_DEF_LAT        (5001.2621)
+#define NMEA_DEF_LON        (3613.0595)
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Position data in fractional degrees or radians
+ */
+typedef struct _nmeaPOS
+{
+    double lat;         /**< Latitude */
+    double lon;         /**< Longitude */
+
+} nmeaPOS;
+
+/**
+ * Information about satellite
+ * @see nmeaSATINFO
+ * @see nmeaGPGSV
+ */
+typedef struct _nmeaSATELLITE
+{
+    int     id;         /**< Satellite PRN number */
+    int     in_use;     /**< Used in position fix */
+    int     elv;        /**< Elevation in degrees, 90 maximum */
+    int     azimuth;    /**< Azimuth, degrees from true north, 000 to 359 */
+    int     sig;        /**< Signal, 00-99 dB */
+
+} nmeaSATELLITE;
+
+/**
+ * Information about all satellites in view
+ * @see nmeaINFO
+ * @see nmeaGPGSV
+ */
+typedef struct _nmeaSATINFO
+{
+    int     inuse;      /**< Number of satellites in use (not those in view) */
+    int     inview;     /**< Total number of satellites in view */
+    nmeaSATELLITE sat[NMEA_MAXSAT]; /**< Satellites information */
+
+} nmeaSATINFO;
+
+/**
+ * Summary GPS information from all parsed packets,
+ * used also for generating NMEA stream
+ * @see nmea_parse
+ * @see nmea_GPGGA2info,  nmea_...2info
+ */
+typedef struct _nmeaINFO
+{
+    int     smask;      /**< Mask specifying types of packages from which data have been obtained */
+
+    nmeaTIME utc;       /**< UTC of position */
+
+    int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
+    int     fix;        /**< Operating mode, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
+
+    double  PDOP;       /**< Position Dilution Of Precision */
+    double  HDOP;       /**< Horizontal Dilution Of Precision */
+    double  VDOP;       /**< Vertical Dilution Of Precision */
+
+    double  lat;        /**< Latitude in NDEG - +/-[degree][min].[sec/60] */
+    double  lon;        /**< Longitude in NDEG - +/-[degree][min].[sec/60] */
+    double  elv;        /**< Antenna altitude above/below mean sea level (geoid) in meters */
+    double  speed;      /**< Speed over the ground in kilometers/hour */
+    double  direction;  /**< Track angle in degrees True */
+    double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
+
+    nmeaSATINFO satinfo; /**< Satellites information */
+
+} nmeaINFO;
+
+void nmea_zero_INFO(nmeaINFO *info);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_INFO_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/nmea.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,25 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: nmea.h 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_H__
+#define __NMEA_H__
+
+#include "./config.h"
+#include "./units.h"
+#include "./gmath.h"
+#include "./info.h"
+#include "./sentence.h"
+#include "./generate.h"
+#include "./generator.h"
+#include "./parse.h"
+#include "./parser.h"
+#include "./context.h"
+
+#endif /* __NMEA_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/parse.c	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,502 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parse.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/**
+ * \file parse.h
+ * \brief Functions of a low level for analysis of
+ * packages of NMEA stream.
+ *
+ * \code
+ * ...
+ * ptype = nmea_pack_type(
+ *     (const char *)parser->buffer + nparsed + 1,
+ *     parser->buff_use - nparsed - 1);
+ * 
+ * if(0 == (node = malloc(sizeof(nmeaParserNODE))))
+ *     goto mem_fail;
+ * 
+ * node->pack = 0;
+ * 
+ * switch(ptype)
+ * {
+ * case GPGGA:
+ *     if(0 == (node->pack = malloc(sizeof(nmeaGPGGA))))
+ *         goto mem_fail;
+ *     node->packType = GPGGA;
+ *     if(!nmea_parse_GPGGA(
+ *         (const char *)parser->buffer + nparsed,
+ *         sen_sz, (nmeaGPGGA *)node->pack))
+ *     {
+ *         free(node);
+ *         node = 0;
+ *     }
+ *     break;
+ * case GPGSA:
+ *     if(0 == (node->pack = malloc(sizeof(nmeaGPGSA))))
+ *         goto mem_fail;
+ *     node->packType = GPGSA;
+ *     if(!nmea_parse_GPGSA(
+ *         (const char *)parser->buffer + nparsed,
+ *         sen_sz, (nmeaGPGSA *)node->pack))
+ *     {
+ *         free(node);
+ *         node = 0;
+ *     }
+ *     break;
+ * ...
+ * \endcode
+ */
+
+#include "nmea/tok.h"
+#include "nmea/parse.h"
+#include "nmea/context.h"
+#include "nmea/gmath.h"
+#include "nmea/units.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int _nmea_parse_time(const char *buff, int buff_sz, nmeaTIME *res)
+{
+    int success = 0;
+
+    switch(buff_sz)
+    {
+    case sizeof("hhmmss") - 1:
+        success = (3 == nmea_scanf(buff, buff_sz,
+            "%2d%2d%2d", &(res->hour), &(res->min), &(res->sec)
+            ));
+        break;
+    case sizeof("hhmmss.s") - 1:
+    case sizeof("hhmmss.ss") - 1:
+    case sizeof("hhmmss.sss") - 1:
+        success = (4 == nmea_scanf(buff, buff_sz,
+            "%2d%2d%2d.%d", &(res->hour), &(res->min), &(res->sec), &(res->hsec)
+            ));
+        break;
+    default:
+        nmea_error("Parse of time error (format error)!");
+        success = 0;
+        break;
+    }
+
+    return (success?0:-1);        
+}
+
+/**
+ * \brief Define packet type by header (nmeaPACKTYPE).
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @return The defined packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_pack_type(const char *buff, int buff_sz)
+{
+    static const char *pheads[] = {
+        "GPGGA",
+        "GPGSA",
+        "GPGSV",
+        "GPRMC",
+        "GPVTG",
+    };
+
+    NMEA_ASSERT(buff);
+
+    if(buff_sz < 5)
+        return GPNON;
+    else if(0 == memcmp(buff, pheads[0], 5))
+        return GPGGA;
+    else if(0 == memcmp(buff, pheads[1], 5))
+        return GPGSA;
+    else if(0 == memcmp(buff, pheads[2], 5))
+        return GPGSV;
+    else if(0 == memcmp(buff, pheads[3], 5))
+        return GPRMC;
+    else if(0 == memcmp(buff, pheads[4], 5))
+        return GPVTG;
+
+    return GPNON;
+}
+
+/**
+ * \brief Find tail of packet ("\r\n") in buffer and check control sum (CRC).
+ * @param buff a constant character pointer of packets buffer.
+ * @param buff_sz buffer size.
+ * @param res_crc a integer pointer for return CRC of packet (must be defined).
+ * @return Number of bytes to packet tail.
+ */
+int nmea_find_tail(const char *buff, int buff_sz, int *res_crc)
+{
+    static const int tail_sz = 3 /* *[CRC] */ + 2 /* \r\n */;
+
+    const char *end_buff = buff + buff_sz;
+    int nread = 0;
+    int crc = 0;
+
+    NMEA_ASSERT(buff && res_crc);
+
+    *res_crc = -1;
+
+    for(;buff < end_buff; ++buff, ++nread)
+    {
+        if(('$' == *buff) && nread)
+        {
+            buff = 0;
+            break;
+        }
+        else if('*' == *buff)
+        {
+            if(buff + tail_sz <= end_buff && '\r' == buff[3] && '\n' == buff[4])
+            {
+                *res_crc = nmea_atoi(buff + 1, 2, 16);
+                nread = buff_sz - (int)(end_buff - (buff + tail_sz));
+                if(*res_crc != crc)
+                {
+                    *res_crc = -1;
+                    buff = 0;
+                }
+            }
+
+            break;
+        }
+        else if(nread)
+            crc ^= (int)*buff;
+    }
+
+    if(*res_crc < 0 && buff)
+        nread = 0;
+
+    return nread;
+}
+
+/**
+ * \brief Parse GGA packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack)
+{
+    char time_buff[NMEA_TIMEPARSE_BUF];
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGGA));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    if(14 != nmea_scanf(buff, buff_sz,
+        "$GPGGA,%s,%f,%C,%f,%C,%d,%d,%f,%f,%C,%f,%C,%f,%d*",
+        &(time_buff[0]),
+        &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
+        &(pack->sig), &(pack->satinuse), &(pack->HDOP), &(pack->elv), &(pack->elv_units),
+        &(pack->diff), &(pack->diff_units), &(pack->dgps_age), &(pack->dgps_sid)))
+    {
+        nmea_error("GPGGA parse error!");
+        return 0;
+    }
+
+    if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
+    {
+        nmea_error("GPGGA time parse error!");
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * \brief Parse GSA packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPGSA(const char *buff, int buff_sz, nmeaGPGSA *pack)
+{
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGSA));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    if(17 != nmea_scanf(buff, buff_sz,
+        "$GPGSA,%C,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%f*",
+        &(pack->fix_mode), &(pack->fix_type),
+        &(pack->sat_prn[0]), &(pack->sat_prn[1]), &(pack->sat_prn[2]), &(pack->sat_prn[3]), &(pack->sat_prn[4]), &(pack->sat_prn[5]),
+        &(pack->sat_prn[6]), &(pack->sat_prn[7]), &(pack->sat_prn[8]), &(pack->sat_prn[9]), &(pack->sat_prn[10]), &(pack->sat_prn[11]),
+        &(pack->PDOP), &(pack->HDOP), &(pack->VDOP)))
+    {
+        nmea_error("GPGSA parse error!");
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * \brief Parse GSV packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPGSV(const char *buff, int buff_sz, nmeaGPGSV *pack)
+{
+    int nsen, nsat;
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPGSV));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    nsen = nmea_scanf(buff, buff_sz,
+        "$GPGSV,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d,"
+        "%d,%d,%d,%d*",
+        &(pack->pack_count), &(pack->pack_index), &(pack->sat_count),
+        &(pack->sat_data[0].id), &(pack->sat_data[0].elv), &(pack->sat_data[0].azimuth), &(pack->sat_data[0].sig),
+        &(pack->sat_data[1].id), &(pack->sat_data[1].elv), &(pack->sat_data[1].azimuth), &(pack->sat_data[1].sig),
+        &(pack->sat_data[2].id), &(pack->sat_data[2].elv), &(pack->sat_data[2].azimuth), &(pack->sat_data[2].sig),
+        &(pack->sat_data[3].id), &(pack->sat_data[3].elv), &(pack->sat_data[3].azimuth), &(pack->sat_data[3].sig));
+
+    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
+    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;
+    nsat = nsat * 4 + 3 /* first three sentence`s */;
+
+    if(nsen < nsat || nsen > (NMEA_SATINPACK * 4 + 3))
+    {
+        nmea_error("GPGSV parse error!");
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * \brief Parse RMC packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPRMC(const char *buff, int buff_sz, nmeaGPRMC *pack)
+{
+    int nsen;
+    
+    char time_buff[NMEA_TIMEPARSE_BUF];
+
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPRMC));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    nsen = nmea_scanf(buff, buff_sz,
+        "$GPRMC,%s,%C,%f,%C,%f,%C,%f,%f,%2d%2d%2d,%f,%C,%C*",
+        &(time_buff[0]),
+        &(pack->status), &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
+        &(pack->speed), &(pack->direction),
+        &(pack->utc.day), &(pack->utc.mon), &(pack->utc.year),
+        &(pack->declination), &(pack->declin_ew), &(pack->mode));
+
+    if(nsen != 13 && nsen != 14)
+    {
+        nmea_error("GPRMC parse error!");
+        return 0;
+    }
+
+    if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
+    {
+        nmea_error("GPRMC time parse error!");
+        return 0;
+    }
+
+    if(pack->utc.year < 90)
+        pack->utc.year += 100;
+    pack->utc.mon -= 1;
+
+    return 1;
+}
+
+/**
+ * \brief Parse VTG packet from buffer.
+ * @param buff a constant character pointer of packet buffer.
+ * @param buff_sz buffer size.
+ * @param pack a pointer of packet which will filled by function.
+ * @return 1 (true) - if parsed successfully or 0 (false) - if fail.
+ */
+int nmea_parse_GPVTG(const char *buff, int buff_sz, nmeaGPVTG *pack)
+{
+    NMEA_ASSERT(buff && pack);
+
+    memset(pack, 0, sizeof(nmeaGPVTG));
+
+    nmea_trace_buff(buff, buff_sz);
+
+    if(8 != nmea_scanf(buff, buff_sz,
+        "$GPVTG,%f,%C,%f,%C,%f,%C,%f,%C*",
+        &(pack->dir), &(pack->dir_t),
+        &(pack->dec), &(pack->dec_m),
+        &(pack->spn), &(pack->spn_n),
+        &(pack->spk), &(pack->spk_k)))
+    {
+        nmea_error("GPVTG parse error!");
+        return 0;
+    }
+
+    if( pack->dir_t != 'T' ||
+        pack->dec_m != 'M' ||
+        pack->spn_n != 'N' ||
+        pack->spk_k != 'K')
+    {
+        nmea_error("GPVTG parse error (format error)!");
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * \brief Fill nmeaINFO structure by GGA packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info)
+{
+    NMEA_ASSERT(pack && info);
+
+    info->utc.hour = pack->utc.hour;
+    info->utc.min = pack->utc.min;
+    info->utc.sec = pack->utc.sec;
+    info->utc.hsec = pack->utc.hsec;
+    info->sig = pack->sig;
+    info->HDOP = pack->HDOP;
+    info->elv = pack->elv;
+    info->lat = ((pack->ns == 'N')?pack->lat:-(pack->lat));
+    info->lon = ((pack->ew == 'E')?pack->lon:-(pack->lon));
+    info->smask |= GPGGA;
+}
+
+/**
+ * \brief Fill nmeaINFO structure by GSA packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPGSA2info(nmeaGPGSA *pack, nmeaINFO *info)
+{
+    int i, j, nuse = 0;
+
+    NMEA_ASSERT(pack && info);
+
+    info->fix = pack->fix_type;
+    info->PDOP = pack->PDOP;
+    info->HDOP = pack->HDOP;
+    info->VDOP = pack->VDOP;
+
+    for(i = 0; i < NMEA_MAXSAT; ++i)
+    {
+        for(j = 0; j < info->satinfo.inview; ++j)
+        {
+            if(pack->sat_prn[i] && pack->sat_prn[i] == info->satinfo.sat[j].id)
+            {
+                info->satinfo.sat[j].in_use = 1;
+                nuse++;
+            }
+        }
+    }
+
+    info->satinfo.inuse = nuse;
+    info->smask |= GPGSA;
+}
+
+/**
+ * \brief Fill nmeaINFO structure by GSV packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPGSV2info(nmeaGPGSV *pack, nmeaINFO *info)
+{
+    int isat, isi, nsat;
+
+    NMEA_ASSERT(pack && info);
+
+    if(pack->pack_index > pack->pack_count ||
+        pack->pack_index * NMEA_SATINPACK > NMEA_MAXSAT)
+        return;
+
+    if(pack->pack_index < 1)
+        pack->pack_index = 1;
+
+    info->satinfo.inview = pack->sat_count;
+
+    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
+    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;
+
+    for(isat = 0; isat < nsat; ++isat)
+    {
+        isi = (pack->pack_index - 1) * NMEA_SATINPACK + isat;
+        info->satinfo.sat[isi].id = pack->sat_data[isat].id;
+        info->satinfo.sat[isi].elv = pack->sat_data[isat].elv;
+        info->satinfo.sat[isi].azimuth = pack->sat_data[isat].azimuth;
+        info->satinfo.sat[isi].sig = pack->sat_data[isat].sig;
+    }
+
+    info->smask |= GPGSV;
+}
+
+/**
+ * \brief Fill nmeaINFO structure by RMC packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPRMC2info(nmeaGPRMC *pack, nmeaINFO *info)
+{
+    NMEA_ASSERT(pack && info);
+
+    if('A' == pack->status)
+    {
+        if(NMEA_SIG_BAD == info->sig)
+            info->sig = NMEA_SIG_MID;
+        if(NMEA_FIX_BAD == info->fix)
+            info->fix = NMEA_FIX_2D;
+    }
+    else if('V' == pack->status)
+    {
+        info->sig = NMEA_SIG_BAD;
+        info->fix = NMEA_FIX_BAD;
+    }
+
+    info->utc = pack->utc;
+    info->lat = ((pack->ns == 'N')?pack->lat:-(pack->lat));
+    info->lon = ((pack->ew == 'E')?pack->lon:-(pack->lon));
+    info->speed = pack->speed * NMEA_TUD_KNOTS;
+    info->direction = pack->direction;
+    info->smask |= GPRMC;
+}
+
+/**
+ * \brief Fill nmeaINFO structure by VTG packet data.
+ * @param pack a pointer of packet structure.
+ * @param info a pointer of summary information structure.
+ */
+void nmea_GPVTG2info(nmeaGPVTG *pack, nmeaINFO *info)
+{
+    NMEA_ASSERT(pack && info);
+
+    info->direction = pack->dir;
+    info->declination = pack->dec;
+    info->speed = pack->spk;
+    info->smask |= GPVTG;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/parse.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,39 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parse.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_PARSE_H__
+#define __NMEA_PARSE_H__
+
+#include "sentence.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+int nmea_pack_type(const char *buff, int buff_sz);
+int nmea_find_tail(const char *buff, int buff_sz, int *res_crc);
+
+int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack);
+int nmea_parse_GPGSA(const char *buff, int buff_sz, nmeaGPGSA *pack);
+int nmea_parse_GPGSV(const char *buff, int buff_sz, nmeaGPGSV *pack);
+int nmea_parse_GPRMC(const char *buff, int buff_sz, nmeaGPRMC *pack);
+int nmea_parse_GPVTG(const char *buff, int buff_sz, nmeaGPVTG *pack);
+
+void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info);
+void nmea_GPGSA2info(nmeaGPGSA *pack, nmeaINFO *info);
+void nmea_GPGSV2info(nmeaGPGSV *pack, nmeaINFO *info);
+void nmea_GPRMC2info(nmeaGPRMC *pack, nmeaINFO *info);
+void nmea_GPVTG2info(nmeaGPVTG *pack, nmeaINFO *info);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_PARSE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/parser.c	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,403 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parser.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/**
+ * \file parser.h 
+ */
+
+#include "nmea/tok.h"
+#include "nmea/parse.h"
+#include "nmea/parser.h"
+#include "nmea/context.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+typedef struct _nmeaParserNODE
+{
+    int packType;
+    void *pack;
+    struct _nmeaParserNODE *next_node;
+
+} nmeaParserNODE;
+
+/*
+ * high level
+ */
+
+/**
+ * \brief Initialization of parser object
+ * @return true (1) - success or false (0) - fail
+ */
+int nmea_parser_init(nmeaPARSER *parser)
+{
+    int resv = 0;
+    int buff_size = nmea_property()->parse_buff_size;
+
+    NMEA_ASSERT(parser);
+
+    if(buff_size < NMEA_MIN_PARSEBUFF)
+        buff_size = NMEA_MIN_PARSEBUFF;
+
+    memset(parser, 0, sizeof(nmeaPARSER));
+
+    if(0 == (parser->buffer = (unsigned char *)malloc(buff_size)))
+        nmea_error("Insufficient memory!");
+    else
+    {
+        parser->buff_size = buff_size;
+        resv = 1;
+    }    
+
+    return resv;
+}
+
+/**
+ * \brief Destroy parser object
+ */
+void nmea_parser_destroy(nmeaPARSER *parser)
+{
+    NMEA_ASSERT(parser && parser->buffer);
+    free(parser->buffer);
+    nmea_parser_queue_clear(parser);
+    memset(parser, 0, sizeof(nmeaPARSER));
+}
+
+/**
+ * \brief Analysis of buffer and put results to information structure
+ * @return Number of packets wos parsed
+ */
+int nmea_parse(  
+    nmeaPARSER *parser,
+    const char *buff, int buff_sz,
+    nmeaINFO *info
+    )
+{
+    int ptype, nread = 0;
+    void *pack = 0;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    nmea_parser_push(parser, buff, buff_sz);
+
+    while(GPNON != (ptype = nmea_parser_pop(parser, &pack)))
+    {
+        nread++;
+
+        switch(ptype)
+        {
+        case GPGGA:
+            nmea_GPGGA2info((nmeaGPGGA *)pack, info);
+            break;
+        case GPGSA:
+            nmea_GPGSA2info((nmeaGPGSA *)pack, info);
+            break;
+        case GPGSV:
+            nmea_GPGSV2info((nmeaGPGSV *)pack, info);
+            break;
+        case GPRMC:
+            nmea_GPRMC2info((nmeaGPRMC *)pack, info);
+            break;
+        case GPVTG:
+            nmea_GPVTG2info((nmeaGPVTG *)pack, info);
+            break;
+        };
+
+        free(pack);
+    }
+
+    return nread;
+}
+
+/*
+ * low level
+ */
+
+int nmea_parser_real_push(nmeaPARSER *parser, const char *buff, int buff_sz)
+{
+    int nparsed = 0, crc, sen_sz, ptype;
+    nmeaParserNODE *node = 0;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    /* clear unuse buffer (for debug) */
+    /*
+    memset(
+        parser->buffer + parser->buff_use, 0,
+        parser->buff_size - parser->buff_use
+        );
+        */
+
+    /* add */
+    if(parser->buff_use + buff_sz >= parser->buff_size)
+        nmea_parser_buff_clear(parser);
+
+    memcpy(parser->buffer + parser->buff_use, buff, buff_sz);
+    parser->buff_use += buff_sz;
+
+    /* parse */
+    for(;;node = 0)
+    {
+       sen_sz = nmea_find_tail(
+            (const char *)parser->buffer + nparsed,
+            (int)parser->buff_use - nparsed, &crc);
+
+        if(!sen_sz)
+        {
+            if(nparsed)
+            {
+                memcpy(
+                parser->buffer,
+                parser->buffer + nparsed,
+                parser->buff_use -= nparsed);
+            break;
+            }
+        }
+        else if(crc >= 0)
+        {
+            ptype = nmea_pack_type(
+                (const char *)parser->buffer + nparsed + 1,
+                parser->buff_use - nparsed - 1);
+
+            if(0 == (node = (nmeaParserNODE *)malloc(sizeof(nmeaParserNODE))))
+                goto mem_fail;
+
+            node->pack = 0;
+            
+            switch(ptype)
+            {
+            case GPGGA:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGGA))))
+                    goto mem_fail;
+                node->packType = GPGGA;
+                if(!nmea_parse_GPGGA(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGGA *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GPGSA:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGSA))))
+                    goto mem_fail;
+                node->packType = GPGSA;
+                if(!nmea_parse_GPGSA(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGSA *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GPGSV:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPGSV))))
+                    goto mem_fail;
+                node->packType = GPGSV;
+                if(!nmea_parse_GPGSV(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPGSV *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GPRMC:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPRMC))))
+                    goto mem_fail;
+                node->packType = GPRMC;                
+                if(!nmea_parse_GPRMC(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPRMC *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            case GPVTG:
+                if(0 == (node->pack = malloc(sizeof(nmeaGPVTG))))
+                    goto mem_fail;
+                node->packType = GPVTG;
+                if(!nmea_parse_GPVTG(
+                    (const char *)parser->buffer + nparsed,
+                    sen_sz, (nmeaGPVTG *)node->pack))
+                {
+                    free(node);
+                    node = 0;
+                }
+                break;
+            default:
+                free(node);
+                node = 0;
+                break;
+            };
+
+            if(node)
+            {
+                if(parser->end_node)
+                    ((nmeaParserNODE *)parser->end_node)->next_node = node;
+                parser->end_node = node;
+                if(!parser->top_node)
+                    parser->top_node = node;
+                node->next_node = 0;
+            }
+        }
+
+        nparsed += sen_sz;
+    }
+
+    return nparsed;
+
+mem_fail:
+    if(node)
+        free(node);
+
+    nmea_error("Insufficient memory!");
+
+    return -1;
+}
+
+/**
+ * \brief Analysis of buffer and keep results into parser
+ * @return Number of bytes wos parsed from buffer
+ */
+int nmea_parser_push(nmeaPARSER *parser, const char *buff, int buff_sz)
+{
+    int nparse, nparsed = 0;
+
+    do
+    {
+        if(buff_sz > parser->buff_size)
+            nparse = parser->buff_size;
+        else
+            nparse = buff_sz;
+
+        nparsed += nmea_parser_real_push(
+            parser, buff, nparse);
+
+        buff_sz -= nparse;
+
+    } while(buff_sz);
+
+    return nparsed;
+}
+
+/**
+ * \brief Get type of top packet keeped into parser
+ * @return Type of packet
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_top(nmeaPARSER *parser)
+{
+    int retval = GPNON;
+    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    if(node)
+        retval = node->packType;
+
+    return retval;
+}
+
+/**
+ * \brief Withdraw top packet from parser
+ * @return Received packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr)
+{
+    int retval = GPNON;
+    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    if(node)
+    {
+        *pack_ptr = node->pack;
+        retval = node->packType;
+        parser->top_node = node->next_node;
+        if(!parser->top_node)
+            parser->end_node = 0;
+        free(node);
+    }
+
+    return retval;
+}
+
+/**
+ * \brief Get top packet from parser without withdraw
+ * @return Received packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_peek(nmeaPARSER *parser, void **pack_ptr)
+{
+    int retval = GPNON;
+    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    if(node)
+    {
+        *pack_ptr = node->pack;
+        retval = node->packType;
+    }
+
+    return retval;
+}
+
+/**
+ * \brief Delete top packet from parser
+ * @return Deleted packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_drop(nmeaPARSER *parser)
+{
+    int retval = GPNON;
+    nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+    NMEA_ASSERT(parser && parser->buffer);
+
+    if(node)
+    {
+        if(node->pack)
+            free(node->pack);
+        retval = node->packType;
+        parser->top_node = node->next_node;
+        if(!parser->top_node)
+            parser->end_node = 0;
+        free(node);
+    }
+
+    return retval;
+}
+
+/**
+ * \brief Clear cache of parser
+ * @return true (1) - success
+ */
+int nmea_parser_buff_clear(nmeaPARSER *parser)
+{
+    NMEA_ASSERT(parser && parser->buffer);
+    parser->buff_use = 0;
+    return 1;
+}
+
+/**
+ * \brief Clear packets queue into parser
+ * @return true (1) - success
+ */
+int nmea_parser_queue_clear(nmeaPARSER *parser)
+{
+    NMEA_ASSERT(parser);
+    while(parser->top_node)
+        nmea_parser_drop(parser);
+    return 1;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/parser.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,59 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parser.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_PARSER_H__
+#define __NMEA_PARSER_H__
+
+#include "info.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * high level
+ */
+
+typedef struct _nmeaPARSER
+{
+    void *top_node;
+    void *end_node;
+    unsigned char *buffer;
+    int buff_size;
+    int buff_use;
+
+} nmeaPARSER;
+
+int     nmea_parser_init(nmeaPARSER *parser);
+void    nmea_parser_destroy(nmeaPARSER *parser);
+
+int     nmea_parse(
+        nmeaPARSER *parser,
+        const char *buff, int buff_sz,
+        nmeaINFO *info
+        );
+
+/*
+ * low level
+ */
+
+int     nmea_parser_push(nmeaPARSER *parser, const char *buff, int buff_sz);
+int     nmea_parser_top(nmeaPARSER *parser);
+int     nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr);
+int     nmea_parser_peek(nmeaPARSER *parser, void **pack_ptr);
+int     nmea_parser_drop(nmeaPARSER *parser);
+int     nmea_parser_buff_clear(nmeaPARSER *parser);
+int     nmea_parser_queue_clear(nmeaPARSER *parser);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_PARSER_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/sentence.c	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,54 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: sentence.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+#include "nmea/sentence.h"
+
+#include <string.h>
+
+void nmea_zero_GPGGA(nmeaGPGGA *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPGGA));
+    nmea_time_now(&pack->utc);
+    pack->ns = 'N';
+    pack->ew = 'E';
+    pack->elv_units = 'M';
+    pack->diff_units = 'M';
+}
+
+void nmea_zero_GPGSA(nmeaGPGSA *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPGSA));
+    pack->fix_mode = 'A';
+    pack->fix_type = NMEA_FIX_BAD;
+}
+
+void nmea_zero_GPGSV(nmeaGPGSV *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPGSV));
+}
+
+void nmea_zero_GPRMC(nmeaGPRMC *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPRMC));
+    nmea_time_now(&pack->utc);
+    pack->status = 'V';
+    pack->ns = 'N';
+    pack->ew = 'E';
+    pack->declin_ew = 'E';
+}
+
+void nmea_zero_GPVTG(nmeaGPVTG *pack)
+{
+    memset(pack, 0, sizeof(nmeaGPVTG));
+    pack->dir_t = 'T';
+    pack->dec_m = 'M';
+    pack->spn_n = 'N';
+    pack->spk_k = 'K';
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/sentence.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,128 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: sentence.h 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/*! \file */
+
+#ifndef __NMEA_SENTENCE_H__
+#define __NMEA_SENTENCE_H__
+
+#include "info.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * NMEA packets type which parsed and generated by library
+ */
+enum nmeaPACKTYPE
+{
+    GPNON   = 0x0000,   /**< Unknown packet type. */
+    GPGGA   = 0x0001,   /**< GGA - Essential fix data which provide 3D location and accuracy data. */
+    GPGSA   = 0x0002,   /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
+    GPGSV   = 0x0004,   /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
+    GPRMC   = 0x0008,   /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
+    GPVTG   = 0x0010    /**< VTG - Actual track made good and speed over ground. */
+};
+
+/**
+ * GGA packet information structure (Global Positioning System Fix Data)
+ */
+typedef struct _nmeaGPGGA
+{
+    nmeaTIME utc;       /**< UTC of position (just time) */
+    double  lat;        /**< Latitude in NDEG - [degree][min].[sec/60] */
+    char    ns;         /**< [N]orth or [S]outh */
+    double  lon;        /**< Longitude in NDEG - [degree][min].[sec/60] */
+    char    ew;         /**< [E]ast or [W]est */
+    int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
+    int     satinuse;   /**< Number of satellites in use (not those in view) */
+    double  HDOP;       /**< Horizontal dilution of precision */
+    double  elv;        /**< Antenna altitude above/below mean sea level (geoid) */
+    char    elv_units;  /**< [M]eters (Antenna height unit) */
+    double  diff;       /**< Geoidal separation (Diff. between WGS-84 earth ellipsoid and mean sea level. '-' = geoid is below WGS-84 ellipsoid) */
+    char    diff_units; /**< [M]eters (Units of geoidal separation) */
+    double  dgps_age;   /**< Time in seconds since last DGPS update */
+    int     dgps_sid;   /**< DGPS station ID number */
+
+} nmeaGPGGA;
+
+/**
+ * GSA packet information structure (Satellite status)
+ */
+typedef struct _nmeaGPGSA
+{
+    char    fix_mode;   /**< Mode (M = Manual, forced to operate in 2D or 3D; A = Automatic, 3D/2D) */
+    int     fix_type;   /**< Type, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
+    int     sat_prn[NMEA_MAXSAT]; /**< PRNs of satellites used in position fix (null for unused fields) */
+    double  PDOP;       /**< Dilution of precision */
+    double  HDOP;       /**< Horizontal dilution of precision */
+    double  VDOP;       /**< Vertical dilution of precision */
+
+} nmeaGPGSA;
+
+/**
+ * GSV packet information structure (Satellites in view)
+ */
+typedef struct _nmeaGPGSV
+{
+    int     pack_count; /**< Total number of messages of this type in this cycle */
+    int     pack_index; /**< Message number */
+    int     sat_count;  /**< Total number of satellites in view */
+    nmeaSATELLITE sat_data[NMEA_SATINPACK];
+
+} nmeaGPGSV;
+
+/**
+ * RMC packet information structure (Recommended Minimum sentence C)
+ */
+typedef struct _nmeaGPRMC
+{
+    nmeaTIME utc;       /**< UTC of position */
+    char    status;     /**< Status (A = active or V = void) */
+    double  lat;        /**< Latitude in NDEG - [degree][min].[sec/60] */
+    char    ns;         /**< [N]orth or [S]outh */
+    double  lon;        /**< Longitude in NDEG - [degree][min].[sec/60] */
+    char    ew;         /**< [E]ast or [W]est */
+    double  speed;      /**< Speed over the ground in knots */
+    double  direction;  /**< Track angle in degrees True */
+    double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
+    char    declin_ew;  /**< [E]ast or [W]est */
+    char    mode;       /**< Mode indicator of fix type (A = autonomous, D = differential, E = estimated, N = not valid, S = simulator) */
+
+} nmeaGPRMC;
+
+/**
+ * VTG packet information structure (Track made good and ground speed)
+ */
+typedef struct _nmeaGPVTG
+{
+    double  dir;        /**< True track made good (degrees) */
+    char    dir_t;      /**< Fixed text 'T' indicates that track made good is relative to true north */
+    double  dec;        /**< Magnetic track made good */
+    char    dec_m;      /**< Fixed text 'M' */
+    double  spn;        /**< Ground speed, knots */
+    char    spn_n;      /**< Fixed text 'N' indicates that speed over ground is in knots */
+    double  spk;        /**< Ground speed, kilometers per hour */
+    char    spk_k;      /**< Fixed text 'K' indicates that speed over ground is in kilometers/hour */
+
+} nmeaGPVTG;
+
+void nmea_zero_GPGGA(nmeaGPGGA *pack);
+void nmea_zero_GPGSA(nmeaGPGSA *pack);
+void nmea_zero_GPGSV(nmeaGPGSV *pack);
+void nmea_zero_GPRMC(nmeaGPRMC *pack);
+void nmea_zero_GPVTG(nmeaGPVTG *pack);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_SENTENCE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/time.c	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,63 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: time.c 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+/*! \file time.h */
+
+#include "nmea/time.h"
+
+#ifdef NMEA_WIN
+#   pragma warning(disable: 4201)
+#   pragma warning(disable: 4214)
+#   pragma warning(disable: 4115)
+#   include <windows.h>
+#   pragma warning(default: 4201)
+#   pragma warning(default: 4214)
+#   pragma warning(default: 4115)
+#else
+#   include <time.h>
+#endif
+
+#ifdef NMEA_WIN
+
+void nmea_time_now(nmeaTIME *stm)
+{
+    SYSTEMTIME st;
+
+    GetSystemTime(&st);
+
+    stm->year = st.wYear - 1900;
+    stm->mon = st.wMonth - 1;
+    stm->day = st.wDay;
+    stm->hour = st.wHour;
+    stm->min = st.wMinute;
+    stm->sec = st.wSecond;
+    stm->hsec = st.wMilliseconds / 10;
+}
+
+#else /* NMEA_WIN */
+
+void nmea_time_now(nmeaTIME *stm)
+{
+    time_t lt;
+    struct tm *tt;
+
+    time(&lt);
+    tt = gmtime(&lt);
+
+    stm->year = tt->tm_year;
+    stm->mon = tt->tm_mon;
+    stm->day = tt->tm_mday;
+    stm->hour = tt->tm_hour;
+    stm->min = tt->tm_min;
+    stm->sec = tt->tm_sec;
+    stm->hsec = 0;
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/time.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,47 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: time.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+/*! \file */
+
+#ifndef __NMEA_TIME_H__
+#define __NMEA_TIME_H__
+
+#include "config.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Date and time data
+ * @see nmea_time_now
+ */
+typedef struct _nmeaTIME
+{
+    int     year;       /**< Years since 1900 */
+    int     mon;        /**< Months since January - [0,11] */
+    int     day;        /**< Day of the month - [1,31] */
+    int     hour;       /**< Hours since midnight - [0,23] */
+    int     min;        /**< Minutes after the hour - [0,59] */
+    int     sec;        /**< Seconds after the minute - [0,59] */
+    int     hsec;       /**< Hundredth part of second - [0,99] */
+
+} nmeaTIME;
+
+/**
+ * \brief Get time now to nmeaTIME structure
+ */
+void nmea_time_now(nmeaTIME *t);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_TIME_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/tok.c	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,250 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: tok.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/*! \file tok.h */
+
+#include "nmea/tok.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+#define NMEA_TOKS_COMPARE   (1)
+#define NMEA_TOKS_PERCENT   (2)
+#define NMEA_TOKS_WIDTH     (3)
+#define NMEA_TOKS_TYPE      (4)
+
+/**
+ * \brief Calculate control sum of binary buffer
+ */
+int nmea_calc_crc(const char *buff, int buff_sz)
+{
+    int chsum = 0,
+        it;
+
+    for(it = 0; it < buff_sz; ++it)
+        chsum ^= (int)buff[it];
+
+    return chsum;
+}
+
+/**
+ * \brief Convert string to number
+ */
+int nmea_atoi(const char *str, int str_sz, int radix)
+{
+    char *tmp_ptr;
+    char buff[NMEA_CONVSTR_BUF];
+    int res = 0;
+
+    if(str_sz < NMEA_CONVSTR_BUF)
+    {
+        memcpy(&buff[0], str, str_sz);
+        buff[str_sz] = '\0';
+        res = strtol(&buff[0], &tmp_ptr, radix);
+    }
+
+    return res;
+}
+
+/**
+ * \brief Convert string to fraction number
+ */
+double nmea_atof(const char *str, int str_sz)
+{
+    char *tmp_ptr;
+    char buff[NMEA_CONVSTR_BUF];
+    double res = 0;
+
+    if(str_sz < NMEA_CONVSTR_BUF)
+    {
+        memcpy(&buff[0], str, str_sz);
+        buff[str_sz] = '\0';
+        res = strtod(&buff[0], &tmp_ptr);
+    }
+
+    return res;
+}
+
+/**
+ * \brief Formating string (like standart printf) with CRC tail (*CRC)
+ */
+int nmea_printf(char *buff, int buff_sz, const char *format, ...)
+{
+    int retval, add = 0;
+    va_list arg_ptr;
+
+    if(buff_sz <= 0)
+        return 0;
+
+    va_start(arg_ptr, format);
+
+    retval = NMEA_POSIX(vsnprintf)(buff, buff_sz, format, arg_ptr);
+
+    if(retval > 0)
+    {
+        add = NMEA_POSIX(snprintf)(
+            buff + retval, buff_sz - retval, "*%02x\r\n",
+            nmea_calc_crc(buff + 1, retval - 1));
+    }
+
+    retval += add;
+
+    if(retval < 0 || retval > buff_sz)
+    {
+        memset(buff, ' ', buff_sz);
+        retval = buff_sz;
+    }
+
+    va_end(arg_ptr);
+
+    return retval;
+}
+
+/**
+ * \brief Analyse string (specificate for NMEA sentences)
+ */
+int nmea_scanf(const char *buff, int buff_sz, const char *format, ...)
+{
+    const char *beg_tok;
+    const char *end_buf = buff + buff_sz;
+
+    va_list arg_ptr;
+    int tok_type = NMEA_TOKS_COMPARE;
+    int width = 0;
+    const char *beg_fmt = 0;
+    int snum = 0, unum = 0;
+
+    int tok_count = 0;
+    void *parg_target;
+
+    va_start(arg_ptr, format);
+    
+    for(; *format && buff < end_buf; ++format)
+    {
+        switch(tok_type)
+        {
+        case NMEA_TOKS_COMPARE:
+            if('%' == *format)
+                tok_type = NMEA_TOKS_PERCENT;
+            else if(*buff++ != *format)
+                goto fail;
+            break;
+        case NMEA_TOKS_PERCENT:
+            width = 0;
+            beg_fmt = format;
+            tok_type = NMEA_TOKS_WIDTH;
+        case NMEA_TOKS_WIDTH:
+            if(isdigit(*format))
+                break;
+            {
+                tok_type = NMEA_TOKS_TYPE;
+                if(format > beg_fmt)
+                    width = nmea_atoi(beg_fmt, (int)(format - beg_fmt), 10);
+            }
+        case NMEA_TOKS_TYPE:
+            beg_tok = buff;
+
+            if(!width && ('c' == *format || 'C' == *format) && *buff != format[1])
+                width = 1;
+
+            if(width)
+            {
+                if(buff + width <= end_buf)
+                    buff += width;
+                else
+                    goto fail;
+            }
+            else
+            {
+                if(!format[1] || (0 == (buff = (char *)memchr(buff, format[1], end_buf - buff))))
+                    buff = end_buf;
+            }
+
+            if(buff > end_buf)
+                goto fail;
+
+            tok_type = NMEA_TOKS_COMPARE;
+            tok_count++;
+
+            parg_target = 0; width = (int)(buff - beg_tok);
+
+            switch(*format)
+            {
+            case 'c':
+            case 'C':
+                parg_target = (void *)va_arg(arg_ptr, char *);
+                if(width && 0 != (parg_target))
+                    *((char *)parg_target) = *beg_tok;
+                break;
+            case 's':
+            case 'S':
+                parg_target = (void *)va_arg(arg_ptr, char *);
+                if(width && 0 != (parg_target))
+                {
+                    memcpy(parg_target, beg_tok, width);
+                    ((char *)parg_target)[width] = '\0';
+                }
+                break;
+            case 'f':
+            case 'g':
+            case 'G':
+            case 'e':
+            case 'E':
+                parg_target = (void *)va_arg(arg_ptr, double *);
+                if(width && 0 != (parg_target))
+                    *((double *)parg_target) = nmea_atof(beg_tok, width);
+                break;
+            };
+
+            if(parg_target)
+                break;
+            if(0 == (parg_target = (void *)va_arg(arg_ptr, int *)))
+                break;
+            if(!width)
+                break;
+
+            switch(*format)
+            {
+            case 'd':
+            case 'i':
+                snum = nmea_atoi(beg_tok, width, 10);
+                memcpy(parg_target, &snum, sizeof(int));
+                break;
+            case 'u':
+                unum = nmea_atoi(beg_tok, width, 10);
+                memcpy(parg_target, &unum, sizeof(unsigned int));
+                break;
+            case 'x':
+            case 'X':
+                unum = nmea_atoi(beg_tok, width, 16);
+                memcpy(parg_target, &unum, sizeof(unsigned int));
+                break;
+            case 'o':
+                unum = nmea_atoi(beg_tok, width, 8);
+                memcpy(parg_target, &unum, sizeof(unsigned int));
+                break;
+            default:
+                goto fail;
+            };
+
+            break;
+        };
+    }
+
+fail:
+
+    va_end(arg_ptr);
+
+    return tok_count;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/tok.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,30 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: tok.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_TOK_H__
+#define __NMEA_TOK_H__
+
+#include "config.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+int     nmea_calc_crc(const char *buff, int buff_sz);
+int     nmea_atoi(const char *str, int str_sz, int radix);
+double  nmea_atof(const char *str, int str_sz);
+int     nmea_printf(char *buff, int buff_sz, const char *format, ...);
+int     nmea_scanf(const char *buff, int buff_sz, const char *format, ...);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __NMEA_TOK_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nmea/units.h	Sun Jan 29 16:06:12 2012 +0000
@@ -0,0 +1,30 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: units.h 4 2007-08-27 13:11:03Z xtimor $
+ *
+ */
+
+#ifndef __NMEA_UNITS_H__
+#define __NMEA_UNITS_H__
+
+#include "config.h"
+
+/*
+ * Distance units
+ */
+
+#define NMEA_TUD_YARDS      (1.0936)        /**< Yeards, meter * NMEA_TUD_YARDS = yard */
+#define NMEA_TUD_KNOTS      (1.852)         /**< Knots, kilometer / NMEA_TUD_KNOTS = knot */
+#define NMEA_TUD_MILES      (1.609)         /**< Miles, kilometer / NMEA_TUD_MILES = mile */
+
+/*
+ * Speed units
+ */
+
+#define NMEA_TUS_MS         (3.6)           /**< Meters per seconds, (k/h) / NMEA_TUS_MS= (m/s) */
+
+#endif /* __NMEA_UNITS_H__ */