datasourcemodules/bluetoothgpspositioningmodule/btgpspsy/src/BTGPSFix.cpp
changeset 36 b47902b73a93
parent 0 9cfd9a3ee49c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datasourcemodules/bluetoothgpspositioningmodule/btgpspsy/src/BTGPSFix.cpp	Fri Jun 04 10:34:15 2010 +0100
@@ -0,0 +1,1088 @@
+// Copyright (c) 2004-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 <e32std.h>
+#include <e32math.h>
+#include <lbspositioninfo.h> 
+#include <lbssatellite.h>            // TPositionSatelliteInfo
+#include "BTGPSLogging.h"
+#include "BTGPSRequestHandler.h"
+#include "BTGPSConstantsManager.h"
+#include "BTGPSFix.h"
+#include "BTGPSLogging.h"
+#include "BTGPSNmeaParser.h"
+#include "BTGPSNmeaBuffer.h"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES  
+
+// CONSTANTS
+
+//The knots to m/s conversion multiplier
+const TReal64 KKnotInMetersPerSecond = 0.5144;
+
+//Hardcoded accuracy
+const TReal32 KHorizontalAccuracy = 10.0;
+const TReal32 KVerticalAccuracy = 30.0;
+
+//Decimal seperator
+const TUint8 KDecimalSeperator = '.';
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::CBTGPSFix
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+CBTGPSFix::CBTGPSFix()
+    {
+    Reset();
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::SetNmeaBuffer
+// Set NMEA Buffer
+// -----------------------------------------------------------------------------
+void CBTGPSFix::SetNmeaBuffer(CBTGPSNmeaBuffer* aNmeaBuffer)
+    {
+    iNmeaBuffer = aNmeaBuffer;
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::Reset
+// Reset the fix parameters.
+// -----------------------------------------------------------------------------
+void CBTGPSFix::Reset()
+    {
+    TRACESTRING("CBTGPSFix::Reset")
+    ResetFix();
+    
+    ResetGSVTime();
+    
+    iNumberOfSatellites = 0;
+    iSatelliteArray.Reset();
+    for(TInt i=0; i<KMaxGSVMessageNumber; i++)
+        {
+        iNMEAGSVCache[i].Zero();
+        }
+        
+    //Reset NMEA Buffer
+    if(iNmeaBuffer!=NULL)
+        {
+        iNmeaBuffer->ResetBuffer();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ResetFix
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ResetFix()
+    {
+    TRACESTRING("CBTGPSFix::ResetFix start...")
+    TRealX nan;
+    nan.SetNaN();
+    
+    ResetPosition();
+    
+    iSpeed=nan;
+    iHeading=nan;
+    
+    iUsedSatellitesArray.Reset();
+    iSatelliteTime = TTime(0);
+    
+    iHorizontalDoP = nan;
+    iVerticalDoP = nan;
+    iPositionDoP = nan;
+    iSatellitesUsed = 0;
+    
+    //Clear the mask
+    iReceivedMsgMask = 0;
+    
+    iGpsMode = EGpsModeSatellite;
+    TRACESTRING("CBTGPSFix::ResetFix end")
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ResetGSVTime
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ResetGSVTime()
+    {
+    TRACESTRING("CBTGPSFix::ResetGSVTime start...")
+    iGsvTime = TTime(0);
+    TRACESTRING("CBTGPSFix::ResetGSVTime end");
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ResetPosition
+// 
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ResetPosition()
+    {
+    TRACESTRING("CBTGPSFix::ResetPosition start...")
+    TRealX nan;
+    nan.SetNaN();
+    
+    iLatitude = nan;
+    iLongitude = nan;
+    iAltitude = nan;
+    iTime = TTime(0);
+    
+    iValid = CBTGPSFix::EFixValidityUnkown;
+    TRACESTRING("CBTGPSFix::ResetPosition end")
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::FixState
+// -----------------------------------------------------------------------------
+CBTGPSFix::TState CBTGPSFix::FixState() const
+    {
+    return iValid;
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::IsFixValid
+// 
+// -----------------------------------------------------------------------------
+TBool CBTGPSFix::IsFixValid() const
+    {
+    return (iValid == EFixValid2D || iValid == EFixValid3D);
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::IfFullNmeaPatternReceived
+// 
+// -----------------------------------------------------------------------------
+TBool CBTGPSFix::IfFullNmeaPatternReceived() const
+    {
+    return iReceivedMsgMask == (EReceivedGSA|EReceivedGGA|EReceivedRMC);
+    }
+        
+// -----------------------------------------------------------------------------
+// CBTGPSFix::FixTime
+// 
+// -----------------------------------------------------------------------------
+TTime CBTGPSFix::FixTime() const
+    {
+    return iTime;
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::GsvTime
+// 
+// -----------------------------------------------------------------------------
+TTime CBTGPSFix::GsvTime() const
+    {
+    return iGsvTime;
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ParseMessage
+// Fills the information available from a command to the fix
+// -----------------------------------------------------------------------------
+CBTGPSFix::TParsingStatus CBTGPSFix::ParseMessage(const TBTGPSNmeaParser& aParser)
+    {
+    TRACESTRING("CBTGPSFix::ParseMessage start...")
+    TRAPD(err, ParseMessageL(aParser));
+    TParsingStatus ret = EUnkown;
+    switch(err)
+        {
+        case KErrNone:
+            ret = EInfoUpdated;
+            break;
+        case KErrNotSupported:
+            ret = EUnkown;
+            break;
+        default:
+            ret = EInvalid;
+        }
+    TRACESTRING("CBTGPSFix::ParseMessage end")
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ParseMessageL
+// Fills the information available from a command to the fix
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ParseMessageL(const TBTGPSNmeaParser& aParser)
+    {
+    if(!aParser.IsValid())
+        {
+        User::Leave(KErrCorrupt);
+        }
+        
+    switch (aParser.MessageId())
+        {
+        case ENmeaGPGSV: 
+            ParseGSVSentenceL(aParser);
+            break;
+            
+        case ENmeaGPRMC:
+            ParseRMCSentenceL(aParser);
+            break;
+            
+        case ENmeaGPGGA:
+            ParseGGASentenceL(aParser);
+            break;
+            
+        case ENmeaGPGSA:
+            ParseGSASentenceL(aParser);
+            break;
+            
+        default:
+            User::Leave(KErrNotSupported);
+            break;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ParseGGASentenceL
+// 
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ParseGGASentenceL(
+        const TBTGPSNmeaParser& aParser)
+    {
+    
+    GetLatitudeLongitude(aParser, ENmeaFieldGPGGALatitude);
+    
+    //Get GPS Quality indicator. 
+    //By default, assume GPS works in normal mode
+    TInt gpsQualityIndicator(EGpsQualitySPS); 
+    if(aParser.GetFieldData(ENmeaFieldGPGGAFix, gpsQualityIndicator)==KErrNone)
+        {
+        //Get satellite mode
+        switch(gpsQualityIndicator)
+            {
+            case EGpsQualityManualInput:
+                iGpsMode = EGpsModeManualInput;
+                break;
+            case EGpsQualityNotValid:
+                iGpsMode = EGpsModeInvalid;
+                break;
+            case EGpsQualityEstimated:
+                iGpsMode = EGpsModeEstimated;
+                break;
+            case EGpsQualitySimulation:
+                iGpsMode = EGpsModeSimulator;
+                break;
+            case EGpsQualitySPS:
+            case EGpsQualityDGPS:
+            case EGpsQualityPPS:
+            case EGpsQualityRTK:
+            case EGpsQualityFloatRTK:
+            default:
+                //Specify any value other than those defined in NMEA spec as 
+                //Satellite mode. This will enable PSY working with mal-functioning
+                //GPS and future GPS technology.
+                iGpsMode = EGpsModeSatellite;
+                break;
+            }
+        }
+        
+    //Get number of satellites in use
+    aParser.GetFieldData(
+        ENmeaFieldGPGGASatellitesUsed,
+        iSatellitesUsed);
+        
+    //Get HDOP
+    aParser.GetFieldData(
+        ENmeaFieldGPGGAHDOP,
+        iHorizontalDoP);
+    
+    //Acquire altitude over msl
+    TReal tempVal32(0); 
+    aParser.GetFieldData(
+        ENmeaFieldGPGGAMSLAltitude,
+        tempVal32);
+
+    //Get Geoidal seperation
+    aParser.GetFieldData(
+        ENmeaFieldGPGGAGeoidalSeperation,
+        iGeoidalSeperation);
+        
+    //Caculate altitude over WGS84
+    iAltitude = tempVal32+iGeoidalSeperation;
+    
+    //GGA received
+    iReceivedMsgMask = iReceivedMsgMask | EReceivedGGA; 
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ParseGSVSentenceL
+// 
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ParseGSVSentenceL(
+        const TBTGPSNmeaParser& aParser)
+    {
+    //Get message number
+    TInt messageNumber(1);
+    User::LeaveIfError(aParser.GetFieldData(
+        ENmeaFieldGPGSVMessageNumber,
+        messageNumber));
+        
+    //Check validity of message number
+    if(messageNumber>KMaxGSVMessageNumber)
+        {
+        User::Leave(KErrCorrupt);
+        }
+    
+    if(messageNumber == 1)
+        {
+        //Get total number messages
+        TInt totalNumberOfMessages(iGsvTotalNumberOfMessage);
+        User::LeaveIfError(aParser.GetFieldData(
+            ENmeaFieldGPGSVNumberOfMessage,
+            totalNumberOfMessages));
+        iGsvTotalNumberOfMessage = totalNumberOfMessages;
+        
+        //Get satellites in view
+        TInt satellitesInView(iGsvSatelliteInView); 
+        aParser.GetFieldData(
+            ENmeaFieldGPGSVSatellitesInView,
+            satellitesInView);
+    
+        iGsvSatelliteInView = satellitesInView;
+        
+        //Clear cache
+        for(TInt i=0; i<KMaxGSVMessageNumber; i++)
+            {
+            iNMEAGSVCache[i].Zero();
+            }
+        }
+        
+    if(iGsvTotalNumberOfMessage == 0)
+        {
+        //Wait until we get the message number 1
+        return;
+        }
+        
+    //copy NMEA sentence to cache
+    SecureCopy(iNMEAGSVCache[messageNumber-1], aParser.NmeaSentence());
+    if(messageNumber == iGsvTotalNumberOfMessage)
+        {
+        //Extract satellite info from all the cached messages.
+        iNumberOfSatellites = 0;
+        iSatelliteArray.Reset();
+        
+        //Extract sat info from cache
+        for(TInt i=0; i<iGsvTotalNumberOfMessage-1; i++)
+            {
+            TBTGPSNmeaParser cacheMsgParser;
+            cacheMsgParser.SetNmeaSentence(iNMEAGSVCache[i]);
+            if(cacheMsgParser.IsValid())
+                {
+                ExtractSatInfoL(cacheMsgParser);
+                }
+            }
+            
+        //Extract sat info from this message
+        ExtractSatInfoL(aParser);
+        
+        
+        //Reset total number of message and number of sat in view
+        iGsvTotalNumberOfMessage = 0;
+        iGsvSatelliteInView = 0;
+
+        //Clear cache
+        for(TInt i=0; i<KMaxGSVMessageNumber; i++)
+            {
+            iNMEAGSVCache[i].Zero();
+            }
+            
+        //Set GSV time
+        iGsvTime.UniversalTime();
+        TRACESTRING2("CBTGPSFix:: Set GSV Time=%d", iGsvTime.Int64())
+
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ExtractSatInfo
+// 
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ExtractSatInfoL(const TBTGPSNmeaParser& aParser)
+    {
+    //get message number
+    TInt messageNumber(1);
+    User::LeaveIfError(aParser.GetFieldData(
+        ENmeaFieldGPGSVMessageNumber,
+        messageNumber));
+    
+
+    //Detect the number of satellites in this message
+    if( (((messageNumber - 1) * 4) + 1) <= iGsvSatelliteInView )
+        {
+        ExtractSatelliteDataL(aParser,
+            ENmeaFieldGPGSVSatelliteID1,
+            ENmeaFieldGPGSVElevation1,
+            ENmeaFieldGPGSVAzimuth1,
+            ENmeaFieldGPGSVSNR1);
+        }            
+    
+    //Detect the number of satellites in this message
+    if ( (((messageNumber - 1) * 4) + 2) <= iGsvSatelliteInView )
+        {
+        ExtractSatelliteDataL(aParser,
+            ENmeaFieldGPGSVSatelliteID2,
+            ENmeaFieldGPGSVElevation2,
+            ENmeaFieldGPGSVAzimuth2,
+            ENmeaFieldGPGSVSNR2);
+        }            
+    
+    //Detect the number of satellites in this message
+    if ( (((messageNumber - 1) * 4) + 3) <= iGsvSatelliteInView )
+        {
+        ExtractSatelliteDataL(aParser,
+            ENmeaFieldGPGSVSatelliteID3,
+            ENmeaFieldGPGSVElevation3,
+            ENmeaFieldGPGSVAzimuth3,
+            ENmeaFieldGPGSVSNR3);
+        }            
+    
+    //Detect the number of satellites in this message
+    if ( (((messageNumber - 1) * 4) + 4) <= iGsvSatelliteInView )
+        {
+        ExtractSatelliteDataL(aParser,
+            ENmeaFieldGPGSVSatelliteID4,
+            ENmeaFieldGPGSVElevation4,
+            ENmeaFieldGPGSVAzimuth4,
+            ENmeaFieldGPGSVSNR4);
+        }            
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ParseGSASentenceL
+// 
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ParseGSASentenceL(
+        const TBTGPSNmeaParser& aParser)
+    {
+    TInt err = KErrNone;
+    
+    // Acquire fix status
+    TInt validity(CBTGPSFix::EFixValidityUnkown);
+    aParser.GetFieldData(
+        ENmeaFieldGPGSAMode2,
+        validity);
+
+    // 2D fix
+    if ( 2 == validity )
+        {
+        iValid = CBTGPSFix::EFixValid2D;
+        }
+    // 3D fix
+    else if ( 3 == validity )
+        {
+        iValid = CBTGPSFix::EFixValid3D;
+        }
+    // No fix
+    else
+        {
+        iValid = CBTGPSFix::EFixNotValid;
+        }   
+    
+    //Get number of used satellites
+    iSatellitesUsed = 0;
+    
+    for ( TInt i = ENmeaFieldGPGSASatellitesUsedCH1; 
+            i <= ENmeaFieldGPGSASatellitesUsedCH12; i++ )
+        {
+        TInt usedSatelliteId=0;
+        err = aParser.GetFieldData(
+            i,
+            usedSatelliteId);
+        if(err==KErrNone && usedSatelliteId !=0)
+            {
+            iUsedSatellitesArray[iSatellitesUsed] = usedSatelliteId;
+            iSatellitesUsed++;
+            }
+        }
+    
+    //Get HDOP
+    aParser.GetFieldData(
+        ENmeaFieldGPGSAHDOP,
+        iHorizontalDoP);
+        
+    //Get VDOP
+    aParser.GetFieldData(
+        ENmeaFieldGPGSAVDOP,
+        iVerticalDoP);
+    
+    //Get PDOP
+    aParser.GetFieldData(
+        ENmeaFieldGPGSAPDOP,
+        iPositionDoP);
+
+    //GSA received
+    iReceivedMsgMask = iReceivedMsgMask | EReceivedGSA; 
+
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ParseRMCSentenceL
+// 
+// -----------------------------------------------------------------------------
+void CBTGPSFix::ParseRMCSentenceL(
+        const TBTGPSNmeaParser& aParser)
+    {
+    //Do the hairy time conversion and
+    //add the 2000 to the year
+    
+    //The format for Set YYYYMMDD:HHMMSS.SSSSSS
+    TBuf16<9+10+3> time;
+    
+    //Get date and time field
+    TPtrC8 dateField;
+    aParser.GetFieldBlock(
+        ENmeaFieldGPRMCDate,
+        dateField);
+
+    //Get time field
+    TPtrC8 timeField;
+    aParser.GetFieldBlock(
+        ENmeaFieldGPRMCUTCTime,
+        timeField);
+    
+    if(dateField.Length()==6 && 
+            timeField.Length()>0 && 
+            timeField.Length()<=10)
+        {
+        //Date consist of DDMMYY
+        TBuf16<6> date;
+        date.Copy(dateField);
+
+        time.Append(_L("20"));
+        time.Append(date.Mid(4,2));
+
+        //Take care that the month is indexed from zero
+        TInt tempVal(1);
+        TLex tempLexer = date.Mid(2,2);
+        tempLexer.Val(tempVal); //error ignored
+        tempVal = tempVal - 1;
+        time.AppendNumFixedWidth(tempVal,EDecimal,2);
+    
+        //Take care that the date is indexed from zero
+        tempLexer = date.Mid(0,2);
+        tempVal = 1;
+        tempLexer.Val(tempVal); //error ignored
+        tempVal = tempVal - 1;
+        time.AppendNumFixedWidth(tempVal,EDecimal,2);
+        time.Append(_L(":"));           
+    
+        //Time consist of HHMMSS.SSS
+        TBuf16<10> times;
+    
+        times.Copy(timeField);
+        time.Append(times);
+    
+        iSatelliteTime.Set(time);//error ignored
+        }
+
+    //Get latitude and longitude
+    GetLatitudeLongitude(aParser, ENmeaFieldGPRMCLatitude);
+    
+    //Get speed
+    TReal32 tempVal32(0);
+    if(aParser.GetFieldData(
+        ENmeaFieldGPRMCSpeedOverGround, 
+        tempVal32)==KErrNone)
+        {
+        iSpeed = KKnotInMetersPerSecond*tempVal32;
+        }
+    
+    //Get heading
+    aParser.GetFieldData(
+        ENmeaFieldGPRMCCourseOverGround,
+        iHeading);
+        
+    //Get GPS Mode
+    TPtrC8 gpsMode;
+    aParser.GetFieldBlock(
+        ENmeaFieldGPRMCModeIndicator,
+        gpsMode);
+    if(gpsMode.Length()!=0)
+        {
+        switch(gpsMode[0])
+            {
+            case 'A':
+            case 'D':
+                iGpsMode = EGpsModeSatellite;
+                break;
+            case 'E':
+                iGpsMode = EGpsModeEstimated;
+                break;
+            case 'M':
+                iGpsMode = EGpsModeManualInput;
+                break;
+            case 'S':
+                iGpsMode = EGpsModeSimulator;
+                break;
+            case 'N':
+            default:
+                iGpsMode = EGpsModeInvalid;
+                break;
+            }
+        }
+
+    //RMC received
+    iReceivedMsgMask = iReceivedMsgMask | EReceivedRMC;
+
+    }
+
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::GetLatitudeLongitude
+// -----------------------------------------------------------------------------
+void CBTGPSFix::GetLatitudeLongitude(
+            const TBTGPSNmeaParser& aParser,
+            TInt aStartId)
+    {
+    TPtrC8 nsField;
+    TPtrC8 latField;
+    TPtrC8 ewField;
+    TPtrC8 logField;
+    
+    aParser.GetFieldBlock(aStartId, latField);
+    aParser.GetFieldBlock(aStartId+1, nsField);
+    aParser.GetFieldBlock(aStartId+2, logField);
+    aParser.GetFieldBlock(aStartId+3, ewField);
+    
+    //We retrieve position only when all fields are valid
+    if(nsField.Length()!=0 && latField.Length()!=0 &&
+        ewField.Length()!=0 && logField.Length()!=0)
+        {
+        TReal latitude, longitude;
+        if( GetDegrees(nsField, latField, latitude) == KErrNone &&
+            GetDegrees(ewField, logField, longitude) == KErrNone)
+            {
+            iLatitude = latitude;
+            iLongitude = longitude;
+            TRACESTRING2("lat=%f", latitude);
+            TRACESTRING2("lon=%f", longitude);
+            }
+        }
+    //Set fix time
+    iTime.UniversalTime();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::GetDegrees
+// Transforms from degrees and minutes string to degree float
+// -----------------------------------------------------------------------------
+TInt CBTGPSFix::GetDegrees(
+        const TDesC8& aSide,
+        const TDesC8& aDegreesMinutes,
+        TReal64& aDegrees)
+    {
+    TInt err = KErrNone;
+    
+    _LIT8(compNS, "S");
+    _LIT8(compEW, "W");
+    _LIT8(decimalPoint, ".");
+    
+    aDegrees = 0.0;
+    TReal64 sign = 1.0;
+    
+    // Create sign multiplier according to N/S field
+    if ( 0 == aSide.Compare(compNS) || 0 == aSide.Compare(compEW) )
+        {
+        sign = -1;
+        }
+    
+    TInt loop = aDegreesMinutes.Find(decimalPoint);
+    
+    //Check that the decimal point was in right place
+    //There could be 1-3 chars in degrees ([[D]D]DMM.MMMM)
+    if ( (KErrNotFound != loop) && (loop > 2) && (loop < 6) )
+        {
+        loop -= 2;
+        
+        //Get the degrees (MM.MMM)
+        TLex8 numberLexer = aDegreesMinutes.Mid(loop);
+        err = numberLexer.Val(aDegrees, KDecimalSeperator);
+        
+        //Get the minutes (DDD)
+        numberLexer = aDegreesMinutes.Left(loop);
+        TReal64 temp = 0.0;
+        err |= numberLexer.Val( temp, KDecimalSeperator );
+        
+        if(err!=KErrNone)
+            {
+            return err;
+            }
+            
+        //Degrees are calculate as sign*(DD+(MM.MMM/60))
+        aDegrees = (temp) + aDegrees/60;
+        aDegrees = aDegrees * sign;
+        }
+    return err;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::AppendSatelliteData
+// Fills the internal vector with satellite data
+// -----------------------------------------------------------------------------
+void CBTGPSFix::AppendSatelliteData(TSatelliteInfo& aSatInfo)
+    {
+    //Prevent over indexing
+    if ( KMaxNumberOfSatellites > iNumberOfSatellites ) 
+        {
+        iSatelliteArray[iNumberOfSatellites] = aSatInfo;
+        ++iNumberOfSatellites;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ExtractSatelliteDataL
+// ------------------------------------------------------------------------------
+void CBTGPSFix::ExtractSatelliteDataL (
+        const TBTGPSNmeaParser& aParser,
+        TInt aField1,
+        TInt aField2,
+        TInt aField3,
+        TInt aField4)
+    {
+    TSatelliteInfo satInfo;
+    
+    satInfo.iSatelliteId = -1;
+    satInfo.iElevation = -1;
+    satInfo.iAzimuth = -1;
+    satInfo.iSNR = -1;
+    
+    TInt err = KErrNone;
+    err = aParser.GetFieldData(aField1, satInfo.iSatelliteId);
+    
+    err |= aParser.GetFieldData(aField2, satInfo.iElevation); 
+        
+    err |= aParser.GetFieldData(aField3, satInfo.iAzimuth); 
+    
+    err |= aParser.GetFieldData(aField4, satInfo.iSNR);
+    
+    if(err==KErrNone)
+        {
+        AppendSatelliteData(satInfo);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::SecureCopy
+// ------------------------------------------------------------------------------
+TBool CBTGPSFix::SecureCopy(TDes8& aTo,const TDesC8& aFrom)
+    {
+    //Prevent overflow
+    if ( aFrom.Length() > aTo.MaxLength() )
+        {
+        //Cut the message
+        aTo.Copy(aFrom.Left(aTo.MaxLength()));
+        return EFalse;
+        }
+    else
+        {
+        aTo.Copy(aFrom);
+        return ETrue;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::FillPositionInfo
+// ------------------------------------------------------------------------------
+TInt CBTGPSFix::FillPositionInfo(
+            TPositionInfoBase& aPosInfo,
+            TInt* aNmeaIndex) const
+    {
+    TRAPD(err, FillPositionInfoL(aPosInfo,aNmeaIndex));
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::FillPositionInfoL
+// ------------------------------------------------------------------------------
+void CBTGPSFix::FillPositionInfoL(
+    TPositionInfoBase& aPosInfo,
+    TInt* aNmeaIndex ) const
+    {
+    TRACESTRING("CBTGPSFix::FillPositionInfo start...")
+    //HPositionGenericInfo
+    //---------------------------------------------------------------
+    if ( aPosInfo.PositionClassType() & EPositionGenericInfoClass )
+        {
+        HPositionGenericInfo* posInfo =
+            static_cast<HPositionGenericInfo*>(&aPosInfo);
+
+        if ( posInfo->IsRequestedField(EPositionFieldHorizontalSpeed) )
+            {
+            if ( IsFixValid() )
+                {
+                User::LeaveIfError(posInfo->SetValue(EPositionFieldHorizontalSpeed,
+                    static_cast<TReal32>(iSpeed)));
+                }
+            }
+
+        if ( posInfo->IsRequestedField(EPositionFieldHeading) )
+            {
+            if ( IsFixValid() )
+                {
+                User::LeaveIfError(posInfo->SetValue(EPositionFieldHeading,
+                    static_cast<TReal32>(iHeading)));
+                }
+            }
+
+        if ( posInfo->IsRequestedField(EPositionFieldNMEASentences) )
+            {
+            TUint8 messageNum=0;
+            if(aNmeaIndex!=NULL)
+                {
+				TRACESTRING("CBTGPSFix::FillPositionInfo fill nmea sentences")
+				TRACESTRING2("begining = %d", *aNmeaIndex)
+				TRACESTRING2("bottom   = %d", iNmeaBuffer->CurrentIndex())
+                TInt beginning = *aNmeaIndex;
+                TBuf8<KMaxNmeaMessageSize> nmeaBuf;
+                while(iNmeaBuffer->ReadSentences(
+                    nmeaBuf,
+                    beginning) == KErrNone)
+                    {
+                    User::LeaveIfError(posInfo->SetValue(static_cast<TUint16>(
+                        EPositionFieldNMEASentencesStart+messageNum),
+                        nmeaBuf));
+                    ++messageNum;
+                    }
+                    
+                *aNmeaIndex = beginning;
+                }
+
+            User::LeaveIfError(posInfo->SetValue(EPositionFieldNMEASentences,
+                static_cast<TUint8>(messageNum)));
+            }
+
+        if ( posInfo->IsRequestedField(EPositionFieldSatelliteNumInView) )
+            {
+            User::LeaveIfError(posInfo->SetValue(EPositionFieldSatelliteNumInView,
+                static_cast<TInt8>(iNumberOfSatellites)));
+            }
+
+        if ( posInfo->IsRequestedField(EPositionFieldSatelliteNumUsed) )
+            {
+            User::LeaveIfError(posInfo->SetValue(EPositionFieldSatelliteNumUsed,
+                static_cast<TInt8>(iSatellitesUsed)));
+            }
+
+        if ( posInfo->IsRequestedField(EPositionFieldSatelliteTime) )
+            {
+            User::LeaveIfError(
+                posInfo->SetValue(
+                    EPositionFieldSatelliteTime,
+                    iSatelliteTime));
+            }
+
+        if ( posInfo->IsRequestedField(EPositionFieldSatelliteHorizontalDoP) )
+            {
+            User::LeaveIfError(
+                posInfo->SetValue(
+                    EPositionFieldSatelliteHorizontalDoP,
+                    static_cast<TReal32>(iHorizontalDoP)));
+            }
+
+        if ( posInfo->IsRequestedField(EPositionFieldSatelliteVerticalDoP) )
+            {
+            User::LeaveIfError(
+                posInfo->SetValue(
+                    EPositionFieldSatelliteVerticalDoP,
+                    static_cast<TReal32>(iVerticalDoP)));
+            }
+
+        if ( posInfo->IsRequestedField(EPositionFieldSatellitePositionDoP) )
+            {
+            User::LeaveIfError(
+                posInfo->SetValue(
+                    EPositionFieldSatellitePositionDoP,
+                    static_cast<TReal32>(iPositionDoP)));
+            }
+        }
+
+    
+    //TpositionSatelliteInfo
+    //---------------------------------------------------------------
+    if ( aPosInfo.PositionClassType() & EPositionSatelliteInfoClass )
+        {
+        TPositionSatelliteInfo* posInfo =
+            static_cast<TPositionSatelliteInfo*>(&aPosInfo);
+        posInfo->ClearSatellitesInView();
+        TSatelliteData satData;
+
+        //Iterate through the satellites
+        for ( TInt i = 0; i < iNumberOfSatellites;++i )
+            {
+            satData.SetSatelliteId(iSatelliteArray[i].iSatelliteId);
+            satData.SetAzimuth(iSatelliteArray[i].iAzimuth);
+            satData.SetElevation(iSatelliteArray[i].iElevation);
+            satData.SetIsUsed(EFalse);
+
+            //Find out if the this satellite was used in fix calculation
+            for ( TInt ii = 0; ii < iSatellitesUsed; ii++)
+                {
+                 if ( iUsedSatellitesArray[ii] == 
+                        iSatelliteArray[i].iSatelliteId )
+                    {
+                    //This satellite is used in solution
+                    satData.SetIsUsed(ETrue);
+                    ii = iSatellitesUsed; //Break the loop
+                    }
+                }
+
+            satData.SetSignalStrength(iSatelliteArray[i].iSNR);
+            posInfo->AppendSatelliteData(satData);
+            }
+
+        posInfo->SetSatelliteTime(iSatelliteTime);
+        posInfo->SetVerticalDoP(iVerticalDoP);
+        posInfo->SetHorizontalDoP(iHorizontalDoP);
+        }
+
+
+    //TPositionCourseInfo
+    //---------------------------------------------------------------
+    if ( aPosInfo.PositionClassType() & EPositionCourseInfoClass )
+        {
+        TPositionCourseInfo* posInfo =
+            static_cast<TPositionCourseInfo*>(&aPosInfo);
+        TCourse cos;
+
+        if ( IsFixValid() )
+            {   
+            cos.SetSpeed(iSpeed);
+            cos.SetHeading(iHeading);
+            }
+
+        posInfo->SetCourse(cos);
+        }
+
+
+
+    //TPositionInfo
+    //---------------------------------------------------------------
+    if ( aPosInfo.PositionClassType() & EPositionInfoClass )
+        {
+        TPositionInfo * posInfo = static_cast<TPositionInfo*>(&aPosInfo);
+        TPosition pos;
+
+        if ( IsFixValid() )
+            {
+            if ( iValid == CBTGPSFix::EFixValid2D ) 
+                {
+                pos.SetCoordinate(iLatitude,iLongitude);
+                }
+            else
+                {
+                pos.SetCoordinate(iLatitude,iLongitude,iAltitude);
+                }
+
+            //Do a sanity check for the DOP values. If they are not valid,
+            //use hard coded values instead.
+            if ( (iHorizontalDoP > 0.0) && (iVerticalDoP > 0.0) )
+                {
+                pos.SetAccuracy(
+                    CBTGPSRequestHandler::ConstantsManager().iUserEquivalentRangeError
+                        * iHorizontalDoP,
+                    CBTGPSRequestHandler::ConstantsManager().iUserEquivalentRangeError
+                        * iVerticalDoP);
+                }
+            else
+                {
+                pos.SetAccuracy(KHorizontalAccuracy,KVerticalAccuracy);
+                }
+            }
+
+        pos.SetTime(iTime);
+        pos.SetDatum(KPositionDatumWgs84);
+        posInfo->SetPosition(pos);
+        }
+    TRACESTRING("CBTGPSFix::FillPositionInfo end");
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::ValidateNmeaBufferIndex
+// ------------------------------------------------------------------------------
+void CBTGPSFix::ValidateNmeaBufferIndex(
+            TInt& aNmeaIndex,
+            TInt& aBottom) const
+    {
+    TRACESTRING("CBTGPSFix::ValidateNmeaBufferIndex: start");
+    TRACESTRING2("aNmeaIndex: %d", aNmeaIndex);
+    TRACESTRING2("aBottom   : %d", aBottom);
+    TRACESTRING2("currentBot: %d", iNmeaBuffer->CurrentIndex());
+    
+    TInt currentBottom = iNmeaBuffer->CurrentIndex();
+    
+    //when aNmeaIndex==KBTGPSNmeaIndexNotSet, client shall
+    //get all NMEA data in the buffer
+
+    //aBottom is the bottom of the NMEA buffer that the client
+    //last time seen. 
+    //When aBottom==KBTGPSNmeaIndexNotSet, it means the client
+    //has just constructed. At this time, we don't need to check
+    //the index
+
+    if(aNmeaIndex != KBTGPSNmeaIndexNotSet 
+        && aBottom != KBTGPSNmeaIndexNotSet)
+        {
+        
+        //If index falles in the middle of aBottom and currentBottom,
+        //we shall invalidate the index
+
+        if( ( aNmeaIndex>aBottom && aNmeaIndex<currentBottom ) ||
+            ( aBottom>currentBottom && aNmeaIndex > aBottom ) ||
+            ( currentBottom > aNmeaIndex && aBottom > currentBottom ) )
+            {
+            //Invalidate aNmeaIndex
+            aNmeaIndex = KBTGPSNmeaIndexNotSet;
+            
+            TRACESTRING("CBTGPSFix::ValidateNmeaBufferIndex: Index reset");
+            }
+        }
+
+    //Update aBottom
+    aBottom = currentBottom;
+    }
+
+// -----------------------------------------------------------------------------
+// CBTGPSFix::operator =
+// ------------------------------------------------------------------------------
+void CBTGPSFix::operator =(const CBTGPSFix& aFix)
+    {
+    //This class is flat. We can just copy memory
+    Mem::Copy(this, &aFix, sizeof(CBTGPSFix));
+    }
+
+
+//  End of File
+