datasourcemodules/simulationpositioningmodule/src/EPos_TNmeaSentenceParser.cpp
changeset 0 9cfd9a3ee49c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datasourcemodules/simulationpositioningmodule/src/EPos_TNmeaSentenceParser.cpp	Tue Feb 02 01:50:39 2010 +0200
@@ -0,0 +1,956 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+
+// INCLUDE FILES
+#include "EPos_TNmeaSentenceParser.h"
+
+// CONSTANTS
+const signed int KCoordTokenS = 'S';
+const signed int KCoordTokenW = 'W';
+const signed int KCoordTokenDot = '.';
+
+const TReal32 KPosUERE = 10.0;
+
+const TNmeaSentence KPosUnknownSentence = 0;
+const TNmeaSentence KPosGGASentence = ('G'<<16) + ('G'<<8) + 'A';
+const TNmeaSentence KPosGSASentence = ('G'<<16) + ('S'<<8) + 'A';
+const TNmeaSentence KPosGSVSentence = ('G'<<16) + ('S'<<8) + 'V';
+const TNmeaSentence KPosRMCSentence = ('R'<<16) + ('M'<<8) + 'C';
+const TNmeaSentence KPosGLLSentence = ('G'<<16) + ('L'<<8) + 'L';
+
+// PGRMM - propriatary GARMIN sentence
+const TNmeaSentence KPosPGRMMSentence = ('G'<<24) + ('R'<<16) + ('M'<<8) + 'M';
+
+const TInt KPosMinSentenceLength = 7;
+const TUint KPosNMEASentenceStartToken = '$';
+const TInt KPosNofSatelliteSlotsInGSA = 12;
+
+const TReal32 KKnotsToMetrePerSecFactor = 1.852F / 3.6F;
+
+const TInt KMaxSatellitesPerSentence = 4;
+
+// ================= MEMBER FUNCTIONS =======================
+
+TNmeaSentenceParser::TNmeaSentenceParser() :
+    iProgress(KPosNotParsed),
+    iGSVIndex(1),
+    iNumNmeaSentences(0)
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::ParseSentenceL
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::ParseSentence(
+    const TDesC8& aSentence,
+    TPositionInfo& aPosInfo, TBool aConst)
+    {
+    if (aSentence.Length() == 0 ||
+        !(aSentence[0] == KPosNMEASentenceStartToken) ||
+        !VerifyChecksum(aSentence))
+        {
+        // Return KPosErrorNotValidNMEASentence since this
+        // sentence won't be set as parsed
+        // and therefore PSY should make another try to get a full fix.
+        return KPosErrorNotValidNMEASentence;
+        }
+
+    TNmeaSentence type = SentenceType(aSentence);
+
+    // Do not permit duplicate sentences of the types GLL, GGA, GSA and RMC
+    if(!aConst)
+    	{
+		if (type == KPosGLLSentence && (iProgress & KPosGLLParsed) ||
+			type == KPosGGASentence && (iProgress & KPosGGAParsed) ||
+			type == KPosGSASentence && (iProgress & KPosGSAParsed) ||
+			type == KPosRMCSentence && (iProgress & KPosRMCParsed))
+			{
+			return KPosErrorAlreadyParsed;
+			}
+    	}
+    
+    if (aPosInfo.PositionClassType() & EPositionGenericInfoClass)
+        {
+        // Store raw NMEA sentence in position info
+        HPositionGenericInfo& genInfo =
+            static_cast<HPositionGenericInfo&> (aPosInfo);
+        AddNmeaSentence(genInfo, aSentence);
+        }
+
+    switch (type)
+        {
+        case KPosGLLSentence:
+            iProgress |= KPosGLLParsed;
+            return KErrNone;
+        case KPosGGASentence:
+            return ParseGGA(aSentence, aPosInfo);
+        case KPosRMCSentence:
+            return ParseRMC(aSentence, aPosInfo);
+        case KPosGSASentence:
+            return ParseGSA(aSentence, aPosInfo);
+        case KPosGSVSentence:
+            return ParseGSV(aSentence, aPosInfo, aConst);
+        case KPosPGRMMSentence:
+            return ParsePGRMM(aSentence, aPosInfo);
+        default:
+            return KErrNone;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::Progress
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::Progress()
+    {
+    return iProgress;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::Reset
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+void TNmeaSentenceParser::Reset()
+    {
+    iProgress = KPosNotParsed;
+    iGSVIndex = 1;
+    iNumNmeaSentences = 0;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::SentenceType
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TNmeaSentence TNmeaSentenceParser::SentenceType(const TDesC8& aSentence)
+    {
+    if (aSentence.Length() <= KPosMinSentenceLength)
+        {
+        return KPosUnknownSentence;
+        }
+
+    TInt type = (aSentence[3]<<16) + (aSentence[4]<<8) + aSentence[5];
+
+    if (aSentence[1] == 'P')
+        {
+        type += (aSentence[2]<<24);
+        }
+
+    return type;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::ParseGGA
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::ParseGGA(
+    const TDesC8& aSentence,
+    TPositionInfo& aPositionInfo)
+    {
+    TDesTokeniser tokeniser(aSentence);
+
+    tokeniser.SkipToken(2); // Initial token, timestamp
+
+    TPtrC8 latitude = tokeniser.NextToken();
+    TPtrC8 dLat = tokeniser.NextToken();
+
+    TPtrC8 longitude = tokeniser.NextToken();
+    TPtrC8 dLong = tokeniser.NextToken();
+
+    TInt quality = DesToInt(tokeniser.NextToken());
+
+    if (quality == 0)
+        {
+        // Return KPosErrorNotValidNMEASentence since this
+        // sentence won't be set as parsed
+        // and therefore PSY should make another try to get a full fix.
+        return KPosErrorNotValidNMEASentence;
+        }
+
+    TRealX nan;
+    nan.SetNaN();
+
+    // Number of tracked satellites, Horizontal dilution
+    tokeniser.SkipToken(2);
+
+    TPtrC8 altitudeC = tokeniser.NextToken(); // // Mean-sea altitude
+    TReal32 altitude = nan;
+    if (altitudeC.Length() > 0)
+        {
+        altitude = DesToFloat(altitudeC);
+        }
+
+    TReal latCoord = nan;
+    ToCoordinate(latitude, dLat, latCoord);
+    TReal longCoord = nan;
+    ToCoordinate(longitude, dLong, longCoord);
+
+    tokeniser.SkipToken();  // Unit (meters)
+
+    TPtrC8 gsValueC = tokeniser.NextToken(); // Geoidal Separation
+    TReal32 gsValue = nan;
+    if (gsValueC.Length() > 0)
+        {
+        gsValue = DesToFloat(gsValueC);
+        }
+
+    TReal32 wgs84alt = nan;
+    if (!Math::IsNaN(TRealX(altitude)) && !Math::IsNaN(TRealX(gsValue)))
+        {
+        // Wgs84-altitude = Mean-sea level altitude + Geoidal separation
+        wgs84alt = altitude + gsValue;
+        }
+    else
+        {
+        // If there is no altitude, there should not be a vertical accuracy.
+        TPosition pos;
+        aPositionInfo.GetPosition(pos);
+        pos.SetVerticalAccuracy(nan);
+        aPositionInfo.SetPosition(pos);
+        }
+
+    // Set position
+    TPosition pos;
+    aPositionInfo.GetPosition(pos);
+    pos.SetCoordinate(latCoord, longCoord, wgs84alt);
+    if (!Math::IsNaN(latCoord) || !Math::IsNaN(longCoord))
+        {
+        pos.SetCurrentTime();
+        }
+    aPositionInfo.SetPosition(pos);
+
+    // Check if generic info class
+    if (aPositionInfo.PositionClassType() & EPositionGenericInfoClass)
+        {
+        HPositionGenericInfo& genInfo =
+            static_cast<HPositionGenericInfo&> (aPositionInfo);
+        TInt err = KErrNone;
+        if (genInfo.IsRequestedField(
+                EPositionFieldSatelliteGeoidalSeparation) &&
+                !Math::IsNaN(TRealX(gsValue)))
+            {
+            err = genInfo.SetValue(EPositionFieldSatelliteGeoidalSeparation,
+                gsValue);
+            }
+        if (genInfo.IsRequestedField(
+                EPositionFieldSatelliteSeaLevelAltitude) &&
+                !Math::IsNaN(TRealX(altitude)))
+            {
+            err = genInfo.SetValue(EPositionFieldSatelliteSeaLevelAltitude,
+                altitude);
+            }
+        if (err != KErrNone)
+            {
+            return err;
+            }
+        }
+
+    iProgress |= KPosGGAParsed;
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::ParseRMC
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::ParseRMC(
+    const TDesC8& aSentence,
+    TPositionInfo& aPositionInfo)
+    {
+    // Check if generic, course or satellite info class
+    if (aPositionInfo.PositionClassType() & (EPositionGenericInfoClass |
+            EPositionCourseInfoClass | EPositionSatelliteInfoClass))
+        {
+        TDesTokeniser tokeniser(aSentence);
+
+        tokeniser.SkipToken(); // Initial token
+
+        TReal timestamp = DesToReal(tokeniser.NextToken()); // Timestamp
+        tokeniser.SkipToken(5); // status, latitude * 2, longitude * 2
+
+        TRealX nan;
+        nan.SetNaN();
+
+        TPtrC8 speedC = tokeniser.NextToken(); // Speed
+        TReal32 speed = nan;
+        if (speedC.Length() > 0)
+            {
+            speed = DesToFloat(speedC);
+            // Speed is in knots. Transform to metres/sec
+            speed *= KKnotsToMetrePerSecFactor;
+            }
+
+        TPtrC8 trueCourseC = tokeniser.NextToken(); // True course
+        TReal32 trueCourse = nan;
+        if (trueCourseC.Length() > 0)
+            {
+            trueCourse = DesToFloat(trueCourseC);
+            }
+
+        TInt date = DesToInt(tokeniser.NextToken()); // Date
+
+        TPtrC8 magVarC = tokeniser.NextToken(); // Magnetic variation
+        TReal32 magVar = nan;
+        if (magVarC.Length() > 0)
+            {
+            magVar = DesToFloat(magVarC);
+            }
+        TPtrC8 dirMagVar = tokeniser.NextToken(); // Magnetic direction
+        TPtrC8 modeIndicator = tokeniser.NextToken('*'); // Mode indicator
+
+        _LIT8(KDataNotValid, "N");
+        if (modeIndicator.Compare(KDataNotValid) == 0)
+            {
+            return KPosErrorNotValidNMEASentence;
+            }
+
+        if (dirMagVar.Length() && dirMagVar[0] == 'E' && !Math::IsNaN(TRealX(magVar)))
+            {
+            magVar = -magVar;
+            }
+
+        TInt hours = static_cast<TInt> (timestamp / 10000);
+        TInt minutes = (static_cast<TInt> (timestamp / 100)) % 100;
+        TInt seconds = (static_cast<TInt> (timestamp)) % 100;
+        TInt microSeconds =
+            ((static_cast<TInt> (timestamp * 100)) % 100) * 10000;
+
+        const TInt KInitialYear = 2000;
+        TInt days = (date / 10000) % 100;
+        TInt months = (date / 100) % 100;
+        TInt years = date % 100 + KInitialYear;
+
+        if (timestamp < 0 || hours > 23 || minutes > 59 || seconds > 59 ||
+            date < 0 || days < 1 || days > 31 || months < 1 ||
+            months > 12 || years > 2099)
+            {
+            return KErrCorrupt;
+            }
+
+        TDateTime time =  TDateTime
+            (years, static_cast<TMonth> (months - 1), days, hours, minutes,
+            seconds, microSeconds);
+
+        // Check if generic info class
+        if (aPositionInfo.PositionClassType() & EPositionGenericInfoClass)
+            {
+            HPositionGenericInfo& genInfo =
+                static_cast<HPositionGenericInfo&> (aPositionInfo);
+            TInt err = KErrNone;
+            if (genInfo.IsRequestedField(EPositionFieldTrueCourse) &&
+                !Math::IsNaN(TRealX(trueCourse)))
+                {
+                err = genInfo.SetValue(EPositionFieldTrueCourse, trueCourse);
+                }
+            if (genInfo.IsRequestedField(EPositionFieldHorizontalSpeed) &&
+                !Math::IsNaN(TRealX(speed)))
+                {
+                err = genInfo.SetValue(EPositionFieldHorizontalSpeed, speed);
+                }
+            if (genInfo.IsRequestedField(EPositionFieldMagneticCourse) &&
+                !Math::IsNaN(TRealX(magVar)) &&
+                !Math::IsNaN(TRealX(trueCourse)))
+                {
+                err = genInfo.SetValue(EPositionFieldMagneticCourse,
+                    magVar + trueCourse);
+                }
+            if (genInfo.IsRequestedField(EPositionFieldSatelliteTime))
+                {
+                err = genInfo.SetValue(EPositionFieldSatelliteTime,
+                    TTime(time));
+                }
+            if (err != KErrNone)
+                {
+                return err;
+                }
+            }
+        // course info, sat info
+        else
+            {
+            TPositionCourseInfo& courseInfo =
+                static_cast<TPositionCourseInfo&> (aPositionInfo);
+            TCourse course;
+            course.SetHeading(trueCourse);
+            course.SetSpeed(speed);
+            courseInfo.SetCourse(course);
+            // satellite info
+            if (aPositionInfo.PositionClassType() &
+                EPositionSatelliteInfoClass)
+                {
+                TPositionSatelliteInfo& satInfo =
+                    static_cast<TPositionSatelliteInfo&> (aPositionInfo);
+                satInfo.SetSatelliteTime(TTime(time));
+                }
+            }
+        }
+    iProgress |= KPosRMCParsed;
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::ParseGSA
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::ParseGSA(
+    const TDesC8& aSentence,
+    TPositionInfo& aPositionInfo)
+    {
+    TDesTokeniser tokeniser(aSentence);
+
+    tokeniser.SkipToken(2); // Initial token, Selection
+
+    TInt twoDthreeD = DesToInt(tokeniser.NextToken());
+    if (twoDthreeD == 1)
+        {
+        // Return KPosErrorNotValidNMEASentence since this
+        // sentence won't be set as parsed
+        // and therefore PSY should make another try to get a full fix.
+        return KPosErrorNotValidNMEASentence;
+        }
+
+    TInt8 numUsedSatellites = 0;
+    for (TInt i = 0; i < KPosNofSatelliteSlotsInGSA; i++)
+        {
+        // Satelite Id nr used for fix
+        TPtrC8 satIdNrC = tokeniser.NextToken();
+        if (satIdNrC.Length() > 0)
+            {
+            // Check if satellite info class
+            if (aPositionInfo.PositionClassType() &
+                EPositionSatelliteInfoClass)
+                {
+                TPositionSatelliteInfo& satInfo =
+                    static_cast<TPositionSatelliteInfo&> (aPositionInfo);
+
+                TSatelliteData satData;
+                TInt satIndex = 0;
+                TInt satId = DesToInt(satIdNrC);
+                TInt err = GetSatelliteListIndex(satInfo, satId, satIndex);
+                if (err == KErrNotFound)
+                    {
+                    satData.SetSatelliteId(satId);
+                    satData.SetIsUsed(ETrue);
+                    err = satInfo.AppendSatelliteData(satData);
+                    if (err != KErrNone)
+                        {
+                        return err;
+                        }
+                    }
+                else // Satellite already exists
+                    {
+                    satInfo.GetSatelliteData(satIndex, satData);
+                    satData.SetIsUsed(ETrue);
+                    err = UpdateSatDataInList(satInfo, satData, satIndex);
+                    if (err != KErrNone)
+                        {
+                        return err;
+                        }
+                    }
+                }
+            numUsedSatellites++;
+            }
+        }
+
+    TRealX nan;
+    nan.SetNaN();
+    TPtrC8 pdopC = tokeniser.NextToken(); // PDop
+    TReal32 pdop = nan;
+    TPtrC8 hdopC = tokeniser.NextToken(); // HDop
+    TReal32 hdop = nan;
+    TPtrC8 vdopC = tokeniser.NextToken('*'); // VDop
+    TReal32 vdop = nan;
+
+    if (pdopC.Length() > 0)
+        {
+        pdop = DesToFloat(pdopC);
+        }
+
+    if (hdopC.Length() > 0)
+        {
+        hdop = DesToFloat(hdopC);
+        // Set basic info
+        TPosition pos;
+        aPositionInfo.GetPosition(pos);
+        pos.SetHorizontalAccuracy(KPosUERE * hdop);
+
+        // Set vertical accuracy, but only if we have altitude, or if we may get
+        // altitude in later NMEA sentences.
+        if (twoDthreeD == 3 &&
+            !((iProgress & KPosGGAParsed) &&
+            Math::IsNaN(TRealX(pos.Altitude()))))
+            {
+            pos.SetVerticalAccuracy(1.5f * KPosUERE * hdop);
+            }
+        aPositionInfo.SetPosition(pos);
+        }
+
+    if (vdopC.Length() > 0)
+        {
+        vdop = DesToFloat(vdopC);
+        }
+
+    // Check if generic info class
+    if (aPositionInfo.PositionClassType() & EPositionGenericInfoClass)
+        {
+        HPositionGenericInfo& genInfo =
+                    static_cast<HPositionGenericInfo&> (aPositionInfo);
+        TInt err = KErrNone;
+
+        if (TRealX(pdop).IsNaN() &&
+            !TRealX(vdop).IsNaN() &&
+            !TRealX(hdop).IsNaN())
+            {
+            TReal trg(pdop);
+            err = Math::Sqrt(trg, TReal(hdop * hdop + vdop * vdop));
+            pdop = TReal32(trg);
+            }
+
+        if (genInfo.IsRequestedField(EPositionFieldSatelliteHorizontalDoP) &&
+            !Math::IsNaN(TRealX(hdop)))
+            {
+            err = genInfo.SetValue(EPositionFieldSatelliteHorizontalDoP, hdop);
+            }
+        if (genInfo.IsRequestedField(EPositionFieldSatelliteVerticalDoP) &&
+            !Math::IsNaN(TRealX(vdop)))
+            {
+            err = genInfo.SetValue(EPositionFieldSatelliteVerticalDoP, vdop);
+            }
+        if (genInfo.IsRequestedField(EPositionFieldSatellitePositionDoP) &&
+            !Math::IsNaN(TRealX(pdop)))
+            {
+            err = genInfo.SetValue(EPositionFieldSatellitePositionDoP, pdop);
+            }
+        if (genInfo.IsRequestedField(EPositionFieldSatelliteNumUsed))
+            {
+            err = genInfo.SetValue(EPositionFieldSatelliteNumUsed,
+                numUsedSatellites);
+            }
+        if (err != KErrNone)
+            {
+            return err;
+            }
+        }
+    // satellite info
+    else if (aPositionInfo.PositionClassType() & EPositionSatelliteInfoClass)
+        {
+        TPositionSatelliteInfo& satInfo =
+                static_cast<TPositionSatelliteInfo&> (aPositionInfo);
+        satInfo.SetHorizontalDoP(hdop);
+        satInfo.SetVerticalDoP(vdop);
+        }
+
+    iProgress |= KPosGSAParsed;
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::ParseGSV
+//
+// Must be called in sequence for each GSV sentence
+// otherwise an error code will be returned.
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::ParseGSV(
+    const TDesC8& aSentence,
+    TPositionInfo& aPositionInfo,
+    TBool aConst)
+    {
+    TDesTokeniser tokeniser(aSentence);
+
+    tokeniser.SkipToken(2); // Initial token, Number of sentences
+
+    TInt sentenceIndex = DesToInt(tokeniser.NextToken()); // Message number
+
+    // OK to try to parse a sentence with the wrong index, but progress
+    // will not be updated.
+    //
+    // Because iGSVIndex is incremented each time function is called with aConst = EFalse
+    // then to get same result like for previous read we have to temporary decrement
+    // this value. Then if aConst is ETrue we are decrementing iGSVIndex
+    TInt tempGSVIndex = iGSVIndex;
+    if(aConst)
+    	{
+    	tempGSVIndex--;
+    	}
+    if (sentenceIndex != tempGSVIndex)
+        {
+        iGSVIndex = 1;
+        return KErrNone;
+        }
+    if(!aConst)
+    	{
+    	iGSVIndex++;
+    	}
+
+    // Number of satellites in view
+    TInt8 satInView = static_cast<TInt8> (DesToInt(tokeniser.NextToken()));
+
+    // Check if generic info class
+    if (aPositionInfo.PositionClassType() & EPositionGenericInfoClass)
+        {
+        HPositionGenericInfo& genInfo =
+                    static_cast<HPositionGenericInfo&> (aPositionInfo);
+        TInt err = KErrNone;
+        if (genInfo.IsRequestedField(EPositionFieldSatelliteNumInView))
+            {
+            err = genInfo.SetValue(EPositionFieldSatelliteNumInView,
+                satInView);
+            if (err != KErrNone)
+                {
+                return err;
+                }
+            }
+        }
+    // satellite info
+    else if (aPositionInfo.PositionClassType() & EPositionSatelliteInfoClass)
+        {
+        TPositionSatelliteInfo& satInfo =
+                static_cast<TPositionSatelliteInfo&> (aPositionInfo);
+
+        for (TInt n = 0; n < KMaxSatellitesPerSentence; n++)
+            {
+            TPtrC8 prnPtrC = tokeniser.NextToken(); // PRN
+            TPtrC8 elevationPtrC = tokeniser.NextToken(); // Elevation
+            TPtrC8 azimuthPtrC = tokeniser.NextToken(); // Azimuth
+
+            if (prnPtrC.Length() > 0)
+                {
+                TPtrC8 signalStrengtPtrC;
+                // Last satellite in sentence
+                if (n == (KMaxSatellitesPerSentence - 1))
+                    {
+                    signalStrengtPtrC.Set(tokeniser.NextToken('*')); // SNR
+                    }
+                else
+                    {
+                    signalStrengtPtrC.Set(tokeniser.NextToken()); // SNR
+                    }
+
+                TSatelliteData satSata;
+                TInt satIndex;
+                TInt satId = DesToInt(prnPtrC);
+                TInt err = GetSatelliteListIndex(satInfo, satId, satIndex);
+                if (err == KErrNotFound)
+                    {
+                    satSata.SetSatelliteId(satId);
+                    if (elevationPtrC.Length() > 0)
+                        {
+                        satSata.SetElevation(DesToFloat(elevationPtrC));
+                        }
+                    if (azimuthPtrC.Length() > 0)
+                        {
+                        satSata.SetAzimuth(DesToFloat(azimuthPtrC));
+                        }
+                    if (signalStrengtPtrC.Length() > 0)
+                        {
+                         satSata.SetSignalStrength(DesToInt(signalStrengtPtrC));
+                        }
+                    err = satInfo.AppendSatelliteData(satSata);
+                    if (err != KErrNone)
+                        {
+                        return err;
+                        }
+                    }
+                else // Satellite already exists
+                    {
+                    satInfo.GetSatelliteData(satIndex, satSata);
+                    satSata.SetSatelliteId(DesToInt(prnPtrC));
+                    if (elevationPtrC.Length() > 0)
+                        {
+                        satSata.SetElevation(DesToFloat(elevationPtrC));
+                        }
+                    if (azimuthPtrC.Length() > 0)
+                        {
+                        satSata.SetAzimuth(DesToFloat(azimuthPtrC));
+                        }
+                    if (signalStrengtPtrC.Length() > 0)
+                        {
+                        satSata.SetSignalStrength(DesToInt(signalStrengtPtrC));
+                        }
+                    err = UpdateSatDataInList(satInfo, satSata, satIndex);
+                    if (err != KErrNone)
+                        {
+                        return err;
+                        }
+                    }
+                }
+            }
+        }
+
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::ParsePGRMM
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::ParsePGRMM(
+    const TDesC8& aSentence,
+    TPositionInfo& /*aPositionInfo*/)
+    {
+    _LIT8(KWgs84, "WGS 84");
+    TDesTokeniser tokeniser(aSentence);
+
+    tokeniser.SkipToken(); // initial token
+
+    TPtrC8 datum = tokeniser.NextToken('*');
+    if (datum.Compare(KWgs84) != 0)
+        {
+        return KErrNotSupported;
+        }
+
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::AddNmeaSentence
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::AddNmeaSentence(
+    HPositionGenericInfo& aPositionGenericInfo,
+    const TDesC8& aSentence, TBool aConst)
+    {
+    TInt err = KErrNone;
+
+    // Check if NMEA data is requested
+    if (aPositionGenericInfo.IsRequestedField(EPositionFieldNMEASentences))
+        {
+        TUint16 sentenceNumber =
+            static_cast<TUint16> (EPositionFieldNMEASentencesStart +
+            iNumNmeaSentences);
+        err = aPositionGenericInfo.SetValue(sentenceNumber, aSentence);
+        if(!aConst)
+        	++iNumNmeaSentences;
+        TUint8 sentences = static_cast<TUint8> (iNumNmeaSentences);
+        err = aPositionGenericInfo.SetValue(EPositionFieldNMEASentences,
+            sentences);
+        }
+    return err;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::ToCoordinate
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+void TNmeaSentenceParser::ToCoordinate(
+    const TDesC8& aDes,
+    const TDesC8& aDir,
+    TReal& aCoordinate)
+    {
+    const TInt  KPosMinutesIntegerLength = 2;
+    const TReal KPosMinutesPerDegree = 60.0;
+
+    TInt point = aDes.Locate(KCoordTokenDot);
+
+    if (point >= KPosMinutesIntegerLength)
+        {
+        TInt deg = DesToInt(aDes.Left(point - KPosMinutesIntegerLength));
+        TReal min = DesToReal(aDes.Mid(point - KPosMinutesIntegerLength));
+        aCoordinate = TReal(deg) + min / KPosMinutesPerDegree;
+
+        if (aDir.Length() && (aDir[0] == KCoordTokenS || aDir[0] == KCoordTokenW))
+            {
+            aCoordinate = - aCoordinate;
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::DesToInt
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::DesToInt(const TPtrC8& aDes)
+    {
+    TLex8 lexer(aDes);
+    TInt integer;
+
+    lexer.Val(integer);
+    return integer;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::DesToFloat
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TReal32 TNmeaSentenceParser::DesToFloat(const TPtrC8& aDes)
+    {
+    TLex8 lexer(aDes);
+    TReal32 floatNumber;
+
+    lexer.Val(floatNumber, TChar(KCoordTokenDot));
+    return floatNumber;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::DesToReal
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TReal TNmeaSentenceParser::DesToReal(const TPtrC8& aDes)
+    {
+    TLex8 lexer(aDes);
+    TReal realNumber;
+
+    lexer.Val(realNumber, TChar('.'));
+    return realNumber;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::VerifyChecksum
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TBool TNmeaSentenceParser::VerifyChecksum(const TDesC8& aSentence)
+    {
+    TUint8 checksum = 0;
+    TInt i;
+    for (i = 1; i < aSentence.Length() && aSentence[i] != '*'; i++)
+        {
+        checksum ^= aSentence[i];
+        }
+
+    if (++i + 1 < aSentence.Length())
+        {
+        TUint8 sum = TUint8((CharToNibble(aSentence[i]) << 4) +
+            CharToNibble(aSentence[i+1]));
+        if (sum == checksum)
+            {
+            return ETrue;
+            }
+        }
+
+    return EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::CharToNibble
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TUint8 TNmeaSentenceParser::CharToNibble(const TUint8 aChar)
+    {
+    if (aChar <= '9')
+        {
+        return TUint8(aChar - '0');
+        }
+    else
+        {
+        return TUint8(aChar - 'A' + 10);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::GetSatelliteListIndex
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::GetSatelliteListIndex(
+    const TPositionSatelliteInfo& aSatInfo,
+    TInt aPrnNumber,
+    TInt& aIndex)
+    {
+    TSatelliteData satData;
+
+    for (TInt i = 0; i < aSatInfo.NumSatellitesInView(); i++)
+        {
+        aSatInfo.GetSatelliteData(i, satData);
+        if (satData.SatelliteId() == aPrnNumber)
+            {
+            aIndex = i;
+            return KErrNone;
+            }
+        }
+    return KErrNotFound;
+    }
+
+// ----------------------------------------------------------------------------
+// TNmeaSentenceParser::UpdateSatDataInList
+//
+// (other items were commented in a header).
+// ----------------------------------------------------------------------------
+//
+TInt TNmeaSentenceParser::UpdateSatDataInList(
+    TPositionSatelliteInfo& aSatInfo,
+    TSatelliteData aSatData,
+    TInt aIndex)
+    {
+    TInt nrOfSat = aSatInfo.NumSatellitesInView();
+    RArray<TSatelliteData> satList;
+    TInt i;
+    TInt err;
+    for (i = 0; i < nrOfSat; i++)
+        {
+        TSatelliteData satData;
+        aSatInfo.GetSatelliteData(i,satData);
+        err = satList.Append(satData);
+        if (err != KErrNone)
+            {
+            satList.Close();
+            return err;
+            }
+        }
+
+    if (aIndex < nrOfSat)
+        {
+        satList[aIndex] = aSatData;
+        }
+
+    // Re-create satellite list in SatelliteInfo
+    aSatInfo.ClearSatellitesInView();
+    for (i = 0; i < satList.Count(); i++)
+        {
+        err = aSatInfo.AppendSatelliteData(satList[i]);
+        if (err != KErrNone)
+            {
+            satList.Close();
+            return err;
+            }
+        }
+    satList.Close();
+    return KErrNone;
+    }
+
+//  End of File