datasourcemodules/bluetoothgpspositioningmodule/btgpspsy/src/Nmea/BTGPSNmeaParser.cpp
changeset 36 b47902b73a93
parent 0 9cfd9a3ee49c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datasourcemodules/bluetoothgpspositioningmodule/btgpspsy/src/Nmea/BTGPSNmeaParser.cpp	Fri Jun 04 10:34:15 2010 +0100
@@ -0,0 +1,416 @@
+// 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 "BTGPSNmeaParser.h"
+#include "BTGPSMessageDef.h"
+#include "BTGPSPanic.h"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES  
+
+// CONSTANTS
+//NMEA sentence field delimiter
+const TUint8 KNmeaFieldDelimiter = ',';
+
+//NMEA sentecne checksum delimiter
+const TUint8 KNmeaChecksumDelimiter = '*';
+
+//Data start postion of NMEA sentence
+const TInt KNmeaDataStartPos = 1; 
+
+//Minimum length of NMEA sentence(starter and check sum)
+const TInt KNmeaMininumLength = 4;
+
+//Checksum field length
+const TInt KNmeaChecksumFieldLength = 2;
+
+//Maximum length of address field length
+const TInt KNmeaMaxAddressFieldLength = 32;
+
+//Decimal seperator
+const TUint8 KDecimalSeperator = '.';
+
+/** 
+* Structure for address field Id map
+*/
+struct TAddressFieldMessageIdMap
+    {
+    TText8 iField[KNmeaMaxAddressFieldLength];  //Field text
+    TInt iId;                                   //Field id
+    };
+
+/**
+* NMEA and Sirf specific NMEA sentence sId field text and 
+* id mapping defination
+*/
+const struct TAddressFieldMessageIdMap KNmeaAddressIdMap[]=
+    {
+        {"GPGSV", ENmeaGPGSV},
+        {"GPGLL", ENmeaGPGLL},
+        {"GPRMC", ENmeaGPRMC},
+        {"GPVTG", ENmeaGPVTG},
+        {"GPGGA", ENmeaGPGGA},
+        {"GPGSA", ENmeaGPGSA},
+        {"PSRF107", ENmeaPSRF107},
+        {"PSRF103", ENmeaPSRF103},
+        {"PSRF101", ENmeaPSRF101},
+        {"PSRF105", ENmeaPSRF105},
+        {"PSRF201", ENmeaPSRF201},
+        {"PNOK",    ENmeaProprietaryNok}
+    };
+
+/**
+* PNOK message id field text and id mapping defination
+*/
+const struct TAddressFieldMessageIdMap KNmeaPNokAddressIdMap[]=
+    {
+        {"OK",          ENmeaPNokOk},
+        {"RESET",       ENmeaPNokReset},
+        {"MSGS",        ENmeaPNokPeriodicMsgs},
+        {"LOWPWR",      ENmeaPNokLowPwrMode},
+        {"NIGHTMODE",   ENmeaPNokNightMode},
+        {"VER",         ENmeaPNokVersionInfo},
+        {"STAT",        ENmeaPNokPeriodicEvents},
+        {"TIME",        ENmeaPNokReferenceTime}
+     };
+
+
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::TBTGPSNmeaParser
+// -----------------------------------------------------------------------------
+TBTGPSNmeaParser::TBTGPSNmeaParser() : TDelimitedParserBase8()
+    {
+    SetDelimiter(KNmeaFieldDelimiter);
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::SetNmeaSentence
+// -----------------------------------------------------------------------------
+void TBTGPSNmeaParser::SetNmeaSentence(const TDesC8& aNmea)
+    {
+    iNmea.Set(aNmea);
+    iId = ENmeaNull;
+    if(CheckValidity())
+        {
+        Parse(TrimSentence());
+        GetMessageId();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::NmeaSentence
+// -----------------------------------------------------------------------------
+const TDesC8& TBTGPSNmeaParser::NmeaSentence() const
+    {
+    return iNmea;
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::IsValid
+// -----------------------------------------------------------------------------
+TBool TBTGPSNmeaParser::IsValid() const
+    {
+    return iId!=ENmeaNull;
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::MessageId
+// -----------------------------------------------------------------------------
+TInt TBTGPSNmeaParser::MessageId() const
+    {
+    return iId;
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::GetMessageId
+// -----------------------------------------------------------------------------
+void TBTGPSNmeaParser::GetMessageId()
+    {
+    iId = ENmeaUnknown;
+    Reset();
+    TPtrC8 address;
+    if(GetFieldBlock(ENmeaFieldAddressField,address)==KErrNone)
+        {
+        for(TInt i=0; 
+            i<sizeof(KNmeaAddressIdMap)/sizeof(TAddressFieldMessageIdMap);i++)
+            {
+            TPtrC8 knownAddress(KNmeaAddressIdMap[i].iField);
+            if(address.Compare(knownAddress)==KErrNone)
+                {
+                TInt messageId = KNmeaAddressIdMap[i].iId;
+                //If message if Nokia proprietary message, we have to check next field
+                if(messageId == ENmeaProprietaryNok)
+                    {
+                    Reset();
+                    Inc();Inc();
+                    if(GetNext(address)==KErrNone)
+                        {
+                        for(TInt j=0; 
+                            j<sizeof(KNmeaPNokAddressIdMap)/sizeof(TAddressFieldMessageIdMap); 
+                            j++)
+                            {
+                            TPtrC8 nokAddress(KNmeaPNokAddressIdMap[j].iField);
+                            if(address.Compare(nokAddress)==KErrNone)
+                                {
+                                iId = KNmeaPNokAddressIdMap[j].iId;
+                                return;
+                                }
+                            }
+                        }
+                    }
+                iId = messageId;
+                return;
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::GetFieldBlock
+// -----------------------------------------------------------------------------
+TInt TBTGPSNmeaParser::GetFieldBlock(TInt aFieldId, TPtrC8& aField) const
+    {
+    Reset();
+    if(aFieldId != ENmeaFieldAddressField)
+        {
+        TInt messageId = MessageId();
+        //Check fieldId matches message Id
+        if(aFieldId<messageId || aFieldId>=messageId+KNmeaMessageIdSkip)
+            {
+            return KErrNotFound;
+            }
+
+        //Skip address field and other fields
+        if(messageId != ENmeaNull)
+            {
+            for(TInt i=0; i<aFieldId-messageId+2; i++)
+                {
+                Inc();
+                }
+            }
+        }
+    return GetNext(aField);
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::IsNullField
+// -----------------------------------------------------------------------------
+TBool TBTGPSNmeaParser::IsNullField(TInt aFieldId) const
+    {
+    TPtrC8 fieldBlock;
+    if(GetFieldBlock(aFieldId, fieldBlock)==KErrNone)
+        {
+        return fieldBlock.Length()==0;
+        }
+    //error case
+    return ETrue;
+    }
+
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::GetFieldData
+// -----------------------------------------------------------------------------
+template  <>
+TInt TBTGPSNmeaParser::GetFieldData<TReal32>(TInt aFieldId, TReal32& aData) const
+    {
+    TPtrC8 fieldBlock;
+    TInt err = GetFieldBlock(aFieldId, fieldBlock);
+    if(err==KErrNone && fieldBlock.Length()>0)
+        {
+        TLex8 lex(fieldBlock);
+        return lex.Val(aData, KDecimalSeperator);
+        }
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::GetFieldData
+// -----------------------------------------------------------------------------
+template  <>
+TInt TBTGPSNmeaParser::GetFieldData<TReal>(TInt aFieldId, TReal& aData) const
+    {
+    TPtrC8 fieldBlock;
+    TInt err = GetFieldBlock(aFieldId, fieldBlock);
+    if(err==KErrNone && fieldBlock.Length()>0)
+        {
+        TLex8 lex(fieldBlock);
+        return lex.Val(aData, KDecimalSeperator);
+        }
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::GetFieldData
+// -----------------------------------------------------------------------------
+template  <>
+TInt TBTGPSNmeaParser::GetFieldData<TInt>(TInt aFieldId, TInt& aData) const
+    {
+    TPtrC8 fieldBlock;
+    TInt err = GetFieldBlock(aFieldId, fieldBlock);
+    if(err==KErrNone && fieldBlock.Length()>0)
+        {
+        TLex8 lex(fieldBlock);
+        return lex.Val(aData);
+        }
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::GetFieldData<TInt>
+// -----------------------------------------------------------------------------
+#define GetFieldDataImplementation(s) \
+template <> TInt TBTGPSNmeaParser::GetFieldData<s>(TInt aFieldId, s& aData) const \
+    { \
+    TPtrC8 fieldBlock; \
+    TInt err = GetFieldBlock(aFieldId, fieldBlock); \
+    if(err==KErrNone && fieldBlock.Length()>0) \
+        { \
+        TLex8 lex(fieldBlock); \
+        return lex.Val(aData); \
+        } \
+    return err; \
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::NextFieldData
+// -----------------------------------------------------------------------------
+template <class T>
+TInt TBTGPSNmeaParser::NextFieldData(T& aData) const
+    {
+    //This function must be called when the sentence is valid
+    __ASSERT_DEBUG(IsValid(), Panic(EPanicInvalidNmeaSentence));
+
+    TBuf8<KNmeaMaxAddressFieldLength> fieldBuf;
+    TPtrC8 fieldBlock(fieldBuf);
+    TInt err = GetNext(fieldBlock);
+    if(err==KErrNone)
+        {
+        TLex8 lex(fieldBlock);
+        return lex.Val(aData);
+        }
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::CheckValidity
+// -----------------------------------------------------------------------------
+TBool TBTGPSNmeaParser::CheckValidity() const
+    {
+    TInt length = iNmea.Length();
+    
+    //Check the length of the NMEA sentence
+    if(length<KNmeaMininumLength)
+        {
+        return EFalse;
+        }
+
+    //Check checksum
+    TInt checksumDelimiterPos = iNmea.LocateReverse(KNmeaChecksumDelimiter);
+    if((checksumDelimiterPos == KErrNotFound) || (checksumDelimiterPos + KNmeaChecksumFieldLength > length))
+        {
+        return EFalse;
+        }
+
+    //Get checsum field
+    TLex8 lex(iNmea.Mid(checksumDelimiterPos, KNmeaChecksumFieldLength));
+
+    //Check checksum 
+    return VerifyChecksum(iNmea);
+    }
+
+// -----------------------------------------------------------------------------
+// TBTGPSNmeaParser::TrimSentence
+// -----------------------------------------------------------------------------
+const TPtrC8 TBTGPSNmeaParser::TrimSentence() const
+    {
+    //Check checksum
+    TInt checksumDelimiterPos = iNmea.LocateReverse(KNmeaChecksumDelimiter);
+
+    return iNmea.Mid(
+        KNmeaDataStartPos,
+        checksumDelimiterPos-KNmeaDataStartPos);
+    }
+
+
+// ----------------------------------------------------------------------------
+// TBTGPSNmeaParser::VerifyChecksum
+// ----------------------------------------------------------------------------
+//
+TBool TBTGPSNmeaParser::VerifyChecksum(const TDesC8& aSentence) const
+    {
+    TUint8 checksum = 0;
+    TInt i;
+    TInt length = aSentence.Length();
+    for (i = KNmeaDataStartPos; 
+        i < length && aSentence[i] != KNmeaChecksumDelimiter; i++)
+        {
+        checksum ^= aSentence[i];
+        }
+
+    if (++i + KNmeaDataStartPos < aSentence.Length())
+        {
+        TUint8 sum = TUint8((CharToNibble(aSentence[i]) << 4) +
+            CharToNibble(aSentence[i+1]));
+        if (sum == checksum)
+            {
+            return ETrue;
+            }
+        }
+
+    return EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+// TBTGPSNmeaParser::CharToNibble
+// ----------------------------------------------------------------------------
+//
+TUint8 TBTGPSNmeaParser::CharToNibble(const TUint8 aChar) const
+    {
+    if (aChar <= '9')
+        {
+        return TUint8(aChar - '0');
+        }
+    else
+        {
+        return TUint8(aChar - 'A' + 10);
+        }
+    }
+
+//  End of File
+
+
+