diff -r a2efdd544abf -r b47902b73a93 datasourceadaptation/gpsdatasourceadaptation/common/src/cadaptationpositioner.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/datasourceadaptation/gpsdatasourceadaptation/common/src/cadaptationpositioner.cpp Fri Jun 04 10:34:15 2010 +0100 @@ -0,0 +1,646 @@ +// Copyright (c) 2008-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: +// + +/** + @file + @InternalComponent +*/ + +#include +#include +#include +#include +#include "utilfunctions.h" + +#include "crequesthandler.h" +#include "cresponsehandler.h" +#include "cadaptationpositioner.h" +#include "psypanic.h" +#include "psylogging.h" +#include "lbsprocessuiddefs.h" +#include "lbsdevloggermacros.h" + +const TUint KWarmDownTimeout = 10000000;//10s + +CAdaptationPositioner::CAdaptationPositioner() + { + LBSLOG(ELogP1, "CAdaptationPositioner::CAdaptationPositioner()"); + iState = ERequestStateInitial; + } + +/** +* Destructor +*/ +CAdaptationPositioner::~CAdaptationPositioner() + { + LBSLOG(ELogP1, "CAdaptationPositioner::~CAdaptationPositioner()"); + + StopMaxFixTimer(); + delete iMaxFixTimer; + iMaxFixTimer = NULL; + StopWarmDownTimer(); + delete iWarmDownTimer; + iWarmDownTimer = NULL; + + CancelNotifyPositionUpdate(); + + if(iEnvironment) + { + iEnvironment->CloseInstance(); + } + } + +/** +* CancelNotifyPositionUpdate implements CAdaptationPositioner::CancelNotifyPositionUpdate +* Cancels position info request. +*/ +void CAdaptationPositioner::CancelNotifyPositionUpdate() + { + LBSLOG(ELogP1, "CAdaptationPositioner::CancelNotifyPositionUpdate()"); + // Stop timers + StopMaxFixTimer(); + StopWarmDownTimer(); + CancelNotifyPositionUpdate(KErrCancel); + } + +/** +* CancelNotifyPositionUpdate implements CAdaptationPositioner::CancelNotifyPositionUpdate(TInt) +* Cancels position info request with reason. This reason allows the S60 Loc Server to distinguish between a real user cancel +* and a timeout - in the case of the latter the LS calls CancelNotifyPositionUpdate(KErrTimedOut), +* in the former he passes no error. +*/ +void CAdaptationPositioner::CancelNotifyPositionUpdate(TInt aError) + { + LBSLOG2(ELogP1, "CAdaptationPositioner::CancelNotifyPositionUpdate(aError) %d", aError); + + if( iActive ) + { + LBSLOG2(ELogP1, "CAdaptationPositioner::Complete request error = %d", aError); + + UpdateFailed(KErrCancel); + TRAP_IGNORE(iRequestHandler->ReMergeWithCancelRequestL(aError)); // Nothing we can do about a leave here + if(aError == KErrTimedOut && IsTracking()) + { + // The last tracking request timedout so we need to schedule one for the next interval + TTime timeNow; + timeNow.UniversalTime(); + iActive = ETrue; + UpdateTrackingTime(timeNow); + TRAPD(error, iRequestHandler->SubmitNewRequestL(this)); // Nothing we can do about a leave here + if(!error) + { + TRAP_IGNORE(StartMaxFixTimerL());// (re)start maxfix timer so that we know when the module has stopped trying + } + } + } + } + + +/** +* Indicate if the PSY has overridden tracking. The default +* implementation returns EFalse. +* @return ETrue if PSY has own timer, otherwise EFalse. +*/ +TBool CAdaptationPositioner::TrackingOverridden() const + { + return ETrue; + } + + +/** +* Initiate a tracking session. +* +* @param aInterval Interval for position requests. +*/ +void CAdaptationPositioner::StartTrackingL(const TTimeIntervalMicroSeconds& aInterval) + { + LBSLOG2(ELogP1, "CAdaptationPositioner::StartTrackingL, interval = %d", aInterval); + + TTime timeNow; + + TTime trackingTime = LbsTimerUtils::AddUpInt64TimersWithOverflowCheck(iTargetTime, aInterval); + timeNow.UniversalTime(); + + iTrackingInterval = aInterval; + + if(! (trackingTime < timeNow)) // if this is not a default proxy call to StartTracking + { + LBSLOG(ELogP1, "Non-DefProxy Start"); + SetupTrackingRequestL(); + iRequestHandler->SubmitNewRequestL(this); + } + } + +/** +* Stop a periodic update session. +*/ +void CAdaptationPositioner::StopTracking() + { + LBSLOG(ELogP1, "CAdaptationPositioner::StopTracking"); + + iTrackingInterval = 0; + } + +/** +* Restart tracking after a missed update +*/ +void CAdaptationPositioner::UpdateTrackingTime(TTime& aTimeNow) + { + LBSLOG(ELogP1, "CAdaptationPositioner::UpdateTrackingTime restarting tracking"); + + TUint multiplier = ( (aTimeNow.Int64() - iTargetTime.Int64()) / iTrackingInterval.Int64() ); + TTimeIntervalMicroSeconds timeToAdd = ( (multiplier + 1) * iTrackingInterval.Int64() ); + + if (timeToAdd < 0) + { + iTargetTime = Time::MaxTTime(); + } + else + { + iTargetTime = LbsTimerUtils::AddUpInt64TimersWithOverflowCheck(iTargetTime, timeToAdd); + } + } + +/** +* Submit a request with the target time in the future. +* The positionerQ will deal with issuing a merged request from +* all active positioners. +*/ +void CAdaptationPositioner::SetupTrackingRequestL() + { + if(IsTracking()) + { + LBSLOG(ELogP1, "CAdaptationPositioner::SetupTrackingRequestL"); + + iPosInfo = NULL; // This will be filled in by the NPUD when it arrives + iActive = ETrue; + + iTargetTime.UniversalTime(); + + #ifdef _DEBUG + TDateTime timeNow = iTargetTime.DateTime(); + LBSLOG3(ELogP1, "Time Now = %d.%d", timeNow.Second(), timeNow.MicroSecond()); + #endif + + iTargetTime = LbsTimerUtils::AddUpInt64TimersWithOverflowCheck(iTargetTime, iTrackingInterval); + + #ifdef _DEBUG + timeNow = iTargetTime.DateTime(); + LBSLOG3(ELogP1, "Target Time = %d.%d", timeNow.Second(), timeNow.MicroSecond()); + #endif + + StartMaxFixTimerL(); + } + } + +/** +* Check if we're tracking. +* +* @return ETrue if we are tracking +*/ +TBool CAdaptationPositioner::IsTracking() + { + return (iTrackingInterval != 0); + } + +/** +* Attempt to use an old position +* +* @param aPosInfo The clients position info +* @return ETrue if the old position was used +*/ +TBool CAdaptationPositioner::UseLastLocation(TPositionInfoBase& aPosInfo) + { + TTime maxAge; + TBool result = EFalse; + + GetMaxAge(maxAge); + + if(maxAge > 0) + { + CResponseHandler* responseHandler = iEnvironment->GetResponseHandler(); + + result = responseHandler->GetLastPosition(aPosInfo, maxAge, IsPartialUpdateAllowed()); + + if( result ) // Use last location + { + TInt err = KErrNone; + TPosition pos; + static_cast(aPosInfo).GetPosition(pos); + if(Partial(pos)) + { + err = KPositionPartialUpdate; + } + LBSLOG(ELogP1, "CAdaptationPositioner::NotifyPositionUpdate returning old position"); + // nb: this will deal with tracking requests properly: + if(CompleteRequest(static_cast(aPosInfo), err)) + { + TRAP_IGNORE(SetupTrackingRequestL()); + } + } + } + + return result; + } + +/** +* Attempt to complete an outstanding request if there is one +* +* @param aPositionInfo The retrieved fix. +* @param aError The error code if the request is failed. +* @param aActualTime time of the location update +*/ +void CAdaptationPositioner::RequestCompleteNotify(const TPositionInfo& aPositionInfo, TInt aError, TTime& aActualTime) + { + LBSLOG(ELogP1, "CAdaptationPositioner::RequestCompleteNotify start..."); + + TBool startWarmDown = EFalse; + TBool completed = EFalse; + + if(iActive) + { + TPositionModuleInfo::TTechnologyType mode = aPositionInfo.PositionMode(); + + if( (aActualTime >= iTargetTime) || (aError == KPositionCalculationFutile) ) + { + // Check if the update is partial and if partial updates are allowed + TPosition pos; + aPositionInfo.GetPosition(pos); + + TBool partial = Partial(pos); + + TBool isFNP = (aPositionInfo.PositionMode() == (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted)); + + if(isFNP) + { + LBSLOG(ELogP1, "Complete with FNP"); + /* removing this for now until we decide how to deal with the qualityloss issue on s60 + * since on s60 qualityloss means no position was generated + if(partial) + { + CompleteRequest(aPositionInfo, KPositionQualityLoss); + } + + else + */ + { + completed = CompleteRequest(aPositionInfo, KErrNone); + + // Stop the AGPS Manager if there are no other outstanding requests + TRAP_IGNORE(iRequestHandler->CancelRequestL()); + } + } + else if(partial && IsPartialUpdateAllowed()) + { + LBSLOG(ELogP1, "Complete with partial"); + completed = CompleteRequest(aPositionInfo, KPositionPartialUpdate); + startWarmDown = ETrue; + } + else if(!partial) + { + LBSLOG(ELogP1, "Complete with non-partial"); + completed = CompleteRequest(aPositionInfo, KErrNone); + + // did the module produce an accurate update or is it still trying? + if(!IsAccurate(aPositionInfo)) + { + startWarmDown = ETrue; + } + else // it might be an accurate reference position + { + TBool isRefPos = (aPositionInfo.ModuleId() == KLbsGpsLocManagerUid) && + (aPositionInfo.PositionMode() == TPositionModuleInfo::ETechnologyNetwork); + if(isRefPos) + { + startWarmDown = ETrue; + } + } + } + else if(aError == KPositionCalculationFutile) + { + // if autonomous return immediately otherwise wait for FNP + if(mode & TPositionModuleInfo::ETechnologyTerminal) + { + LBSLOG(ELogP1, "Complete with futile"); + completed = CompleteRequest(aPositionInfo, KPositionQualityLoss); + } + } + else + { + // position is not futile and is partial but partials are not + // allowed. In this case do nothing and wait for further updates + } + } + else + { + LBSLOG(ELogP1, "CAdaptationPositioner::RequestCompleteNotify Ignoring early response"); + } + } + + if (completed) + { + TRAP_IGNORE(SetupTrackingRequestL()); + } + + if(startWarmDown) // we need to start a warmdown timer + { + TRAP_IGNORE(StartWarmDownTimerL()); // not much we can do here if warmdown timer not started + } + LBSLOG(ELogP1, "CAdaptationPositioner::RequestCompleteNotify end"); + } + +/** +* Attempt to complete an outstanding request if there is one with an error +* +* @param aError The error code if the request is failed. +*/ +void CAdaptationPositioner::UpdateFailed(TInt aError) + { + LBSLOG(ELogP1, "CAdaptationPositioner::UpdateFailed()"); + if(iActive) + { + LBSLOG2(ELogP1, "CAdaptationPositioner::Complete request error = %d", aError); + + iActive = EFalse; + ClearPositionInfo(*iPosInfo); + + if(iClientStatus) + { + User::RequestComplete(iClientStatus, aError); + iClientStatus = NULL; + } + LBSLOG2(ELogP1, "iState -> ERequestStatePostInitial from %d", iState); + iState = ERequestStatePostInitial; + } + } + +/** +* Complete the outstanding request and reset internal state +* +* @param aPositionInfo The retrieved fix. +* @param aError The error code if the request is failed. +*/ +TBool CAdaptationPositioner::CompleteRequest(const TPositionInfo& aPositionInfo, TInt aError) + { + LBSLOG2(ELogP1, "CAdaptationPositioner::CompleteRequest() with error %d", aError); + TBool completed = EFalse; + iActive = EFalse; // Stop another request being sent for this instance of the PSY + + if(iPosInfo) + { + TInt error = CopyPositionTypes(*iPosInfo, aPositionInfo); + __ASSERT_DEBUG(error == KErrNone, + User::Panic(KAdaptationPanicCategory, EPanicPositionCopyFailed)); + error = error; // this is to stop arm build warnings + + SetModuleId(iPosInfo); // Delegate to the derived class + User::RequestComplete(iClientStatus, aError); + iClientStatus = NULL; + LBSLOG2(ELogP1, "iState -> ERequestStatePostInitial from %d", iState); + iState = ERequestStatePostInitial; + completed = ETrue; + } + else + { + LBSLOG(ELogP1, "CAdaptationPositioner::RequestCompleteNotify iPosInfo not set"); + } + + return completed; + } + +/** +* CAdaptationPositioner::ReportStatus +* Reports the PSY status to the MLFW +* +* @param aStatus The new position module status +*/ +void CAdaptationPositioner::ReportStatus(const TPositionModuleStatus& aStatus) + { + MPositionerStatus* statusInf = this->PositionerStatus(); + statusInf->ReportStatus(aStatus); + } + +/** + * Clears the fields of the aPosInfo + * @param aPosInfo The position information to return + */ +void CAdaptationPositioner::ClearPositionInfo(TPositionInfoBase& aPosInfo) + { + if(&aPosInfo != NULL) + { + if (aPosInfo.PositionClassType() & EPositionSatelliteInfoClass) + { + // TPositionSatelliteInfo + (void) new (&aPosInfo) (TPositionSatelliteInfo); + } + else if (aPosInfo.PositionClassType() & EPositionCourseInfoClass) + { + // TPositionCourseInfo + (void) new (&aPosInfo) (TPositionCourseInfo); + } + else if (aPosInfo.PositionClassType() & EPositionGenericInfoClass) + { + // HPositionGenericInfo + HPositionGenericInfo* genInfo = + static_cast ( &aPosInfo ); + + genInfo->ClearPositionData(); + } + else if (aPosInfo.PositionClassType() & EPositionInfoClass) + { + // TPositionInfo + (void) new (&aPosInfo) (TPositionInfo); + } + else + { + // Unknown type, this should never happen + // --> Panic if we get here + __ASSERT_DEBUG(0, User::Panic(KAdaptationPanicCategory, EPanicUnknownPositioningClass)); + } + + aPosInfo.SetModuleId(ImplementationUid()); + } + } + + +TBool CAdaptationPositioner::IsActive() + { + return iActive; + } + +TBool CAdaptationPositioner::IsWarmingDown() + { + if(iWarmDownTimer) + { + return iWarmDownTimer->IsActive(); + } + return EFalse; + } + +void CAdaptationPositioner::StartMaxFixTimerL() + { + LBSLOG(ELogP1, "CAdaptationPositioner::StartMaxFixTimerL()"); + if(iMaxFixTimer) // stop any that's currently running + { + iMaxFixTimer->Cancel(); + } + else + { + iMaxFixTimer = CLbsCallbackTimer::NewL(*this); + } + + iMaxFixTimer->EventAfter(iTimeOutInterval, EMaxFixTimerEvent); + } + +void CAdaptationPositioner::StopMaxFixTimer() + { + LBSLOG(ELogP1, "CAdaptationPositioner::StopMaxFixTimer()"); + if(iMaxFixTimer) + { + iMaxFixTimer->Cancel(); + } + } + +void CAdaptationPositioner::StartWarmDownTimerL() + { + TTimeIntervalMicroSeconds32 timeout = KWarmDownTimeout; + LBSLOG(ELogP1, "CAdaptationPositioner::StartWarmDownTimerL()"); + if(iWarmDownTimer) // stop any that's currently running + { + iWarmDownTimer->Cancel(); + } + else + { + iWarmDownTimer = CLbsCallbackTimer::NewL(*this); + } + iWarmDownTimer->EventAfter(timeout, EWarmDownTimerEvent); + } + +void CAdaptationPositioner::StopWarmDownTimer() + { + LBSLOG(ELogP1, "CAdaptationPositioner::StopWarmDownTimer()"); + if(iWarmDownTimer) + { + iWarmDownTimer->Cancel(); + } + } + +/** +MaxFixTimerEvent handling + +Stop warmdown timer +*/ +void CAdaptationPositioner::MaxFixTimerEvent() + { + LBSLOG(ELogP1, "CAdaptationPositioner::MaxFixTimerEvent()"); + + // Cancel the warmdown timer since the module has stopped trying + StopWarmDownTimer(); + } + +/** +MaxFixTimer error handling +*/ +TInt CAdaptationPositioner::MaxFixTimerError(TInt /*aError*/) + { + return KErrNone; + } + +/** +MaxFixTimerEvent handling + +Stop warmdown timer +*/ +void CAdaptationPositioner::WarmDownTimerEvent() + { + LBSLOG(ELogP1, "CAdaptationPositioner::MaxFixTimerEvent()"); + + // tell positioner Q that our warmdown timer has fired + iRequestHandler->WarmDownTimerExpired(); + } + +/** +WarmDown error handling +*/ +TInt CAdaptationPositioner::WarmDownTimerError(TInt /*aError*/) + { + return KErrNone; + } + + +/** +from MLbsCallbackTimerObserver + +@param aTimerId Time event ID to identify different time events +*/ +void CAdaptationPositioner::OnTimerEventL(TInt aTimerId) + { + switch(aTimerId) + { + case EMaxFixTimerEvent: + MaxFixTimerEvent(); + break; + case EWarmDownTimerEvent: + WarmDownTimerEvent(); + break; + default: + __ASSERT_DEBUG(0, User::Panic(KAdaptationPanicCategory, EPanicUnknownTimerEventId)); + } + } +/** +Timer error handling + +@param aError Time error code +@param aTimerId Time event ID to identify two different time events +*/ +TInt CAdaptationPositioner::OnTimerError(TInt aError, TInt aTimerId) + { + switch(aTimerId) + { + case EMaxFixTimerEvent: + MaxFixTimerError(aError); + break; + case EWarmDownTimerEvent: + WarmDownTimerError(aError); + break; + default: + __ASSERT_DEBUG(0, User::Panic(KAdaptationPanicCategory, EPanicUnknownTimerEventId)); + } + return KErrNone; // we have handled the error locally + } + + +TBool CAdaptationPositioner::IsAccurate(const TPositionInfo& aPositionInfo) + { + TBool accurate = ETrue; + TPositionQuality reqQuality; + iCriteria.GetRequiredQuality(reqQuality); + TPosition pos; + + aPositionInfo.GetPosition(pos); + if(pos.HorizontalAccuracy() > reqQuality.HorizontalAccuracy() ) + { + accurate = EFalse; + } + return accurate; + } + +TUint CAdaptationPositioner::InactivityTimeout() + { + return iInactivityTimeout; + } + + +// End of File