datasourcemodules/simulationpositioningmodule/src/EPos_TPosDataSimulator.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 16 Apr 2010 16:28:16 +0300
changeset 19 bdd4df282e3e
parent 0 9cfd9a3ee49c
permissions -rw-r--r--
Revision: 201011 Kit: 201015

// 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 <e32math.h>
#include <lbspositioninfo.h>
#include "EPos_TPosDataSimulator.h"
#include "EPos_TDesTokeniser.h"
#include "EPos_SimPsyConstants.h"

// CONSTANTS
const TUint8 KPosDataSeparator = '=';
const TUint8 KPosDefaultDataEndMarker = ';';

_LIT8(KHacc, "Horizontal accuracy");
_LIT8(KVacc, "Vertical accuracy");
_LIT8(KPowerupTime, "Powerup time");
_LIT8(KLongitude, "Longitude");
_LIT8(KLatitude, "Latitude");
_LIT8(KSpeed, "Speed");
_LIT8(KCourse, "Course");
_LIT8(KRandom, "Random");
_LIT8(KDeterministic, "Deterministic");
_LIT8(KTimeToFixMin, "TimeToFix min");
_LIT8(KTimeToFixMax, "TimeToFix max");

// ================= MEMBER FUNCTIONS =======================

// C++ default constructor can NOT contain any code, that
// might leave.
//
TPosDataSimulator::TPosDataSimulator() :
    iHAcc(0),
    iVAcc(0),
    iLonErrorRadius(0),
    iLatErrorRadius(0),
    iErrorAngle(0),
    iSpeed(0),
    iTrueCourse(0),
    iOrigLatitude(0),
    iOrigLongitude(0),
    iLatitude(0),
    iLongitude(0),
    iAltError(0),
    iPowerupTime(0),
    iRandomMode(EFalse),
    iTTFMin(0),
    iTTFMax(0),
    iFailFrequency(0),
    iRandomTTF(0),
    iSeed(0)
    {
    TTime time;
    time.UniversalTime();
    iSeed = time.Int64();
    }

// ---------------------------------------------------------
// TPosDataSimulator::ComputeNewPositionL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt TPosDataSimulator::ComputeNewPositionL(
    TPosition& aPosition,
    const TTime& aRequestStartTime,
    const TTime& aLastRequestTime)
    {
    if (iSpeed != 0)
        {
        TReal cHdng1;
        TReal cLat1;
        TReal sAlpha;
        TReal sLat1;
        TReal cAlpha;

        TReal latitude = aPosition.Latitude() - iLatErrorRadius;
        TReal delay = (static_cast<TReal>
            (aRequestStartTime.MicroSecondsFrom(aLastRequestTime).
            Int64()))/KToSeconds;
        if (delay == 0)
            {
            delay = 1;
            }
        TReal alpha = (iSpeed*delay)/KEarthRadius;

        // Compute new latitude
        User::LeaveIfError(Math::Cos(cHdng1, iTrueCourse * KToRadians));
        User::LeaveIfError(Math::Cos(cLat1,  latitude * KToRadians));
        User::LeaveIfError(Math::Sin(sAlpha, alpha));
        User::LeaveIfError(Math::Sin(sLat1,  latitude * KToRadians));
        User::LeaveIfError(Math::Cos(cAlpha, alpha));

        TReal sLat2 = cHdng1 * cLat1 * sAlpha + sLat1 * cAlpha;
        TReal lat2;
        User::LeaveIfError(Math::ASin(lat2, sLat2));

        iLatitude = lat2 * KToDegrees;

        // Compute new longitude
        TReal cLat2;
        User::LeaveIfError(Math::Cos(cLat2, lat2));
        TReal tmp =(cAlpha - sLat1 * sLat2) / (cLat1 * cLat2);
        TReal newLong;
        ModifyCosArgIfNeeded(tmp);
        User::LeaveIfError(Math::ACos(newLong, tmp));

        newLong *= KToDegrees;

        // newLong will always be positive. If the course indicates that
        // longitude should be decreased (sin(course) < 0), the sign should
        // be changed.
        TReal sCourse;
        User::LeaveIfError(Math::Sin(sCourse, iTrueCourse * KToRadians));
        if (sCourse < 0)
            {
            newLong = -newLong;
            }

        iLongitude = aPosition.Longitude() + newLong;
        LongitudeBoundsCheck(iLongitude);

        ComputeNewErrorForLatLonAltL(iLatitude, iLongitude,
            iLatitude, iLongitude);

        // Compute new course
        TReal newCourse;
        tmp = (sLat1 - sLat2*cAlpha) / (cLat2 * sAlpha);
        ModifyCosArgIfNeeded(tmp);
        User::LeaveIfError(Math::ACos(newCourse, tmp));
        newCourse *= KToDegrees;
        }
    else
        {
        ComputeNewErrorForLatLonAltL(iOrigLatitude, iOrigLongitude,
            iLatitude, iLongitude);
        }

    // Set position
    aPosition.SetCoordinate(iLatitude, iLongitude, iAltError);
    aPosition.SetAccuracy(iHAcc, iVAcc);

    return KErrNone;
    }

// ---------------------------------------------------------
// TPosDataSimulator::ParseAndCreatePosObjectL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::ParseAndCreatePosObjectL(
    TPosition& aPosition,
    const CDesC8Array* aDataArray)
    {
    TInt itemsFound = 0;
    for (TInt i = 0; i < aDataArray->Count(); i++)
        {
        TDesTokeniser tokeniser(aDataArray->MdcaPoint(i));
        TPtrC8 field = tokeniser.NextToken(KPosDataSeparator);
        TPtrC8 value = tokeniser.NextToken(KPosDefaultDataEndMarker);
        
        // trim any trailing spaces off the field:
        const TText8* first = field.Ptr();
        const TText8* last = first + field.Length() - 1;

        while ((last >= first) && TChar(*last).IsSpace() )
        	{
        	last--;
        	}

        TUint8 len = (last + 1 - first);
        TPtrC8  fieldTrimmed(first, len);   
        
        if (fieldTrimmed.MatchF(KHacc) == 0)
            { // {float} 0 -
            LeaveIfNegativeRealL(value);
            iHAcc = DesToFloatL(value);
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KVacc) == 0)
            { // {float} 0 -
            LeaveIfNegativeRealL(value);
            iVAcc = DesToFloatL(value);
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KTimeToFixMin) == 0)
            { // {integer} 0 -
            LeaveIfNegativeIntL(value);
            iTTFMin = DesToIntL(value);
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KTimeToFixMax) == 0)
            { // {integer} 0 -
            LeaveIfNegativeIntL(value);
            iTTFMax = DesToIntL(value);
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KPowerupTime) == 0)
            { // {integer} 0 -
            LeaveIfNegativeIntL(value);
            iPowerupTime = DesToIntL(value);
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KLongitude) == 0)
            { // {float} - 180 - 180
            CheckLatLonBoundariesL(value, TReal(180));
            iOrigLongitude = DesToRealL(value);
            LongitudeBoundsCheck(iOrigLongitude);
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KLatitude) == 0)
            { // {float} - 90 - 90
            CheckLatLonBoundariesL(value, TReal(90));
            iOrigLatitude = DesToRealL(value);
            if (iOrigLatitude == 90 || iOrigLatitude == -90)
                {
                iOrigLatitude = 89.9999;
                }
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KSpeed) == 0)
            { // {float} 0 -
            LeaveIfNegativeRealL(value);
            // Speed NOT used in current supported classes
            iSpeed = DesToFloatL(value);
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KCourse) == 0)
            { // {float} 0 - 360
            // TrueCourse NOT used in current supported classes
            CheckCourseBoundariesL(value);
            iTrueCourse = DesToFloatL(value);
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KRandom) == 0)
            { // {integer} 0 -
            LeaveIfNegativeIntL(value);
            iFailFrequency = DesToIntL(value);
            iRandomMode = ETrue;
            itemsFound++;
            }
        else if (fieldTrimmed.MatchF(KDeterministic) == 0)
            { // {integer} 0 -
            LeaveIfNegativeIntL(value);
            iFailFrequency = DesToIntL(value);
            iRandomMode = EFalse;
            itemsFound++;
            }
        }

    if (itemsFound != KNoOfSimulatedDataItems)
        {
        User::Leave(KErrCorrupt);
        }

    aPosition.SetCoordinate(iOrigLatitude, iOrigLongitude, iAltError);
    aPosition.SetAccuracy(iHAcc, iVAcc);
    }

// ---------------------------------------------------------
// TPosDataSimulator::TimeToWait
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TTimeIntervalMicroSeconds TPosDataSimulator::TimeToWait(
    const TTime& aRequestStartTime)
    {
    // 500 ms as execution time after wait.
    //
    TInt executionTimeAfterWait = 500000;
    TInt timetowait = iTTFMin;

    iRandomTTF = (iTTFMin + (Math::Rand(iSeed) % (iTTFMax-iTTFMin+1)))
        * KToMicroSeconds;
    TTime now;
    now.UniversalTime();
    TInt delay = I64INT(now.MicroSecondsFrom(aRequestStartTime).Int64());
    if (delay < iRandomTTF)
        {
        timetowait = Min(iTTFMax * KToMicroSeconds - executionTimeAfterWait,
                        Max(iTTFMin * KToMicroSeconds + executionTimeAfterWait,
                            iRandomTTF - delay));
        }
    else
        {
        timetowait = Max(iTTFMin * KToMicroSeconds + executionTimeAfterWait,
            iRandomTTF - delay);
        }
    return TTimeIntervalMicroSeconds(TInt64(timetowait));
    }

// ---------------------------------------------------------
// TPosDataSimulator::FailThisRequest
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt TPosDataSimulator::FailThisRequest(TInt aNumberOfRequests)
    {
    TInt err = KErrNone;
    if (iFailFrequency != 0)
        {
        if (iRandomMode)
            {
            TInt randomNum = Math::Rand(iSeed);
            TInt res = KMaxTInt/iFailFrequency;
            if (randomNum < res)
                {
                err = KErrorCodeForFailedRequest;
                }
            }
        else
            {
            if (aNumberOfRequests % iFailFrequency == 0)
                {
                err = KErrorCodeForFailedRequest;
                }
            }
        }
    return err;
    }

// ---------------------------------------------------------
// TPosDataSimulator::PowerupTime
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TTimeIntervalMicroSeconds TPosDataSimulator::PowerupTime()
    {
    TInt powerUp = iPowerupTime * KToMicroSeconds;
    return TTimeIntervalMicroSeconds(TInt64(powerUp));
    }

// ---------------------------------------------------------
// TPosDataSimulator::GetRandomError
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TReal TPosDataSimulator::GetRandomError()
    {
    TReal error = 0;
    for (TInt j = 0; j < KTimesToRandom; j++)
        {
        error += Math::FRand(iSeed);
        }
    error -= KTimesToRandom/2;
    return error;
    }

// ---------------------------------------------------------
// TPosDataSimulator::ComputeNewErrorForLatLonAltL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::ComputeNewErrorForLatLonAltL(
    TReal& aFromLatitude,
    TReal& aFromLongitude,
    TReal& aToLatitude,
    TReal& aToLongitude)
    {
    // Add random error to lon and lat
    // Latitude
    TReal error = GetRandomError();
    error *= iHAcc;
    iLatErrorRadius = (error * 360) / (2 * KEarthRadius * KPi);

    // Longitude
    error = GetRandomError();
    error *= iHAcc;
    iLonErrorRadius = (error * 360) / (2 * KEarthRadius * KPi);

    // Angle
    TReal rand = Math::FRand(iSeed);
    iErrorAngle = rand * 360;

    TReal cosAlpha;
    User::LeaveIfError(Math::Cos(cosAlpha, iErrorAngle * KToRadians));
    TReal sinAlpha;
    User::LeaveIfError(Math::Sin(sinAlpha, iErrorAngle * KToRadians));

    // Add error to latitude
    aToLatitude = aFromLatitude + iLatErrorRadius * sinAlpha;
    // Add error to longitude
    aToLongitude = aFromLongitude + iLonErrorRadius * cosAlpha;

    // Add random error to altitude
    iAltError = (TReal32) GetRandomError();
    iAltError *= iVAcc;
    }

// ---------------------------------------------------------
// TPosDataSimulator::DesToIntL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt TPosDataSimulator::DesToIntL(const TDesC8& aDes)
    {
    TLex8   lexer(aDes);
    TInt    integer;
    User::LeaveIfError(lexer.Val(integer));
    return integer;
    }

// ---------------------------------------------------------
// TPosDataSimulator::DesToFloatL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TReal32 TPosDataSimulator::DesToFloatL(const TDesC8& aDes)
    {
    TLex8       lexer(aDes);
    TReal32     floatNumber;
    User::LeaveIfError(lexer.Val(floatNumber, TChar('.')));
    return floatNumber;
    }

// ---------------------------------------------------------
// TPosDataSimulator::DesToRealL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TReal TPosDataSimulator::DesToRealL(const TDesC8& aDes)
    {
    TLex8 lexer(aDes);
    TReal realNumber;
    User::LeaveIfError(lexer.Val(realNumber, TChar('.')));
    return realNumber;
    }

// ---------------------------------------------------------
// TPosDataSimulator::LeaveIfNegativeIntL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::LeaveIfNegativeIntL(const TDesC8& aDes)
    {
    TLex8 lexer(aDes);
    TInt  number;
    User::LeaveIfError(lexer.Val(number));
    if (number < 0)
        {
        User::Leave(KErrCorrupt);
        }
    CheckEosL(lexer);
    }

// ---------------------------------------------------------
// TPosDataSimulator::LeaveIfNegativeRealL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::LeaveIfNegativeRealL(const TDesC8& aDes)
    {
    TLex8 lexer(aDes);
    TReal  number;
    User::LeaveIfError(lexer.Val(number, TChar('.')));
    if (number < 0)
        {
        User::Leave(KErrCorrupt);
        }
    CheckEosL(lexer);
    }

// ---------------------------------------------------------
// TPosDataSimulator::CheckLatLonBoundariesL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::CheckLatLonBoundariesL(
    const TDesC8& aDes, TReal aMinMaxValue)
    {
    TLex8 lexer(aDes);
    TReal lat;
    User::LeaveIfError(lexer.Val(lat, TChar('.')));
    if (lat < -aMinMaxValue || lat > aMinMaxValue)
        {
        User::Leave(KErrCorrupt);
        }
    CheckEosL(lexer);
    }

// ---------------------------------------------------------
// TPosDataSimulator::CheckEosL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::CheckEosL(TLex8& aLexer)
    {
    aLexer.SkipSpace();
    if (!aLexer.Eos())
        {
        User::Leave(KErrCorrupt);
        }
    }

// ---------------------------------------------------------
// TPosDataSimulator::CheckCourseBoundariesL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::CheckCourseBoundariesL(
    const TDesC8& aDes)
    {
    TLex8 lexer(aDes);
    TReal32  course;
    User::LeaveIfError(lexer.Val(course, TChar('.')));
    if (course < 0 || course > 360)
        {
        User::Leave(KErrCorrupt);
        }
    CheckEosL(lexer);
    }

// ---------------------------------------------------------
// TPosDataSimulator::ModifyCosArgIfNeeded
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::ModifyCosArgIfNeeded(TReal& aCosArg)
    {
    if (aCosArg > 1.0)
        {
        aCosArg = 1.0;
        }
    else if (aCosArg < -1.0)
        {
        aCosArg = -1.0;
        }
    }

// ---------------------------------------------------------
// TPosDataSimulator::LongitudeBoundsCheck
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void TPosDataSimulator::LongitudeBoundsCheck(TReal& aLong)
    {
    // Make sure -180.0 < aLong =< 180.0
    while (aLong < -KLongitudeUpperBound)
        {
        aLong += KFullCircle;
        }
    while (aLong >= KLongitudeUpperBound)
        {
        aLong -= KFullCircle;
        }
    }

//  End of File