diff -r 000000000000 -r 4e949f03ecc5 locationtriggering/ltstrategyengine/src/lbtcoordinatesupervisor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/locationtriggering/ltstrategyengine/src/lbtcoordinatesupervisor.cpp Wed Nov 03 23:28:39 2010 +0530 @@ -0,0 +1,2104 @@ +/* +* Copyright (c) 2008 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: Implementation of coordinate supervisor class +* +*/ + + + +#include +#include +#include +#include +#include "lbtcelliddatabase.h" +#include "lbtcellchangehandler.h" +#include "lbtlogger.h" +#include "lbtcoordinatesupervisor.h" +#include "lbtstrategyengineobserver.h" +#include "lbtpsychangelistner.h" + +// ==================== CONSTANTS =================================== + +/** + * Constant used to adjust trigger radius to accomodate inaccuracy + * of position fixes + */ +static const TReal32 KAccuracyMultiplier = 0.666667; + +/** + * The cut off value of the ratio of radius to position accuracy. Over this + * value the radius of a trigger will not be expanded. + */ +static const TReal32 KCofftOfHighEdgeLimit = 1.5; + +/** + * Constant used in calculation of trigger hysteresis + */ +static const TUint16 KTriggerRadiusCutoff = 500; + +/** + * Contant time use in calculation of speed + */ +static const TReal32 constantTime = 20; + +/** + * Defines the number of historic speed values that will be stored + * and used for calculation of current speed + */ +static const TUint16 maxObsValues = 10; + +/** + * Minimum calculated speed. If this calculated speed drops below this value + * then the below value is speed as the speed value + */ +static const TReal KMinProjSpeed = 20.0; + +static const TReal KMaxSpeedToUseMvmtDet = 5.0; +/** + * If the estimated sleep interval goes below this value then location request + * will be issued immediately with the estimated interval as the time out value + * for the location rquest + */ +static const TInt KMinSleepInterval = 2; + +/** + * Multiplier used for 10 power 3. Used for conversion of seconds to micro + * seconds + */ +static const TUint KMicroMultiplier = 1000000; + +/** + * Number of seconds to sleep before making location request in cases where + * a location acquisition attempt fails to obtain a fix + */ +static const TUint KSleepTimeOnLocAcqFailure = 10; // 10 seconds + +/** + * Safe range of HA obtained from NPP + */ +//static const TUint KNppSafeHA = 1500; // 1500 meters + +// ============================== MEMBER FUNCTIONS ============================================ + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::NewL +// CLbtCoOrdinateSupervisor instantiation method +// ----------------------------------------------------------------------------- +// +CLbtCoOrdinateSupervisor* CLbtCoOrdinateSupervisor::NewL( TAny* aConstructionParameters, + CLbtTriggerView* aView, + MLbtStrategyEngineObsrvr* aObserver, + CLbtCellChangeHandler* aCellChangeHandler ) + { + CLbtCoOrdinateSupervisor* self = new ( ELeave ) CLbtCoOrdinateSupervisor(); + CleanupStack::PushL( self ); + self->ConstructL( aConstructionParameters, aView,aObserver,aCellChangeHandler ); + CleanupStack::Pop(); + return self; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::~CLbtCoOrdinateSupervisor +// Default destructor +// ----------------------------------------------------------------------------- +// +CLbtCoOrdinateSupervisor::~CLbtCoOrdinateSupervisor() + { + // This is just done as a precautionary measure! + StopSupervision(); + delete iLocationRequestor; + delete iStatusManager; + delete iTimer; + delete iPsyChangeListner; + delete iCellIdDatabase; + iNObservedValues.Close(); + iNearestTriggers.Close(); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::StartSupervision +// +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::StartSupervision() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::StartSupervision"); + iCellChangeHandler->SetObserver( this ); + RequestTerminalPosition( iSettings.iLocationRequestTimeout ); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::StopSupervision +// +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::StopSupervision() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::StopSupervision"); + iCellChangeHandler->Remove( this ); + Term(); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::SettingsChanged +// Handles notification of triggering settings change provided by server +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::SettingsChanged() + { + iEngObserver->RetrieveTriggeringSettings( iSettings ); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::Resume + +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::Resume() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::Resume"); + TInt err = KErrNone; + iCellChangeHandler->SetObserver( this ); + + switch( iProjectedState ) + { + case ELocationAcquisition: + iProjectedState = EIdle; + RequestTerminalPosition( iSettings.iLocationRequestTimeout ); + break; + + case ETriggerEvaluation: + // Reset trigger iterator and start evaluation of all triggers in + // view + iProjectedState = EIdle; + err = ResetViewIterator(); + if( KErrNone != err ) + { + return; + } + iState = ETriggerEvaluation; + SetEvent(); + break; + + case EUpdateIntervalEstimation: + + // Evaluate triggers that have undergone changes during the state + // change. This is to determine any new nearest trigger + iProjectedState = EIdle; + + + iView->DetermineNearestTriggerChanges( &iNearestTriggers ); + if( iNearestTriggers.Count() == 0 ) + { + // This means all known nearest triggers have been modified. + // Reset iterator re-evaluate all triggers in the system. + TInt err = ResetViewIterator(); + if( KErrNone != err ) + { + return; + } + + iState = ETriggerEvaluation; + SetEvent(); + } + else + { + // Evaluate only the modified triggers + TBool makeLocReq = EFalse; + TRAP( err, makeLocReq = EvaluateModifiedTriggersL() ); + if( KErrNone == err ) + { + if( makeLocReq ) + { + // Location request is needed based on evaluating + // modified triggers + RequestTerminalPosition( iSettings.iLocationRequestTimeout ); + return; + } + // Switch to estimation of update interval + iState = EUpdateIntervalEstimation; + SetEvent(); + } + else + { + Term(); + } + } + break; + + case ESleep: + iProjectedState = EIdle; + iState = ESleep; + SetEvent(); + break; + + case EIdle: + if( EIdle == iState && EIdle == iProjectedState + && iView->CoordTriggerCount() ) + { + RequestTerminalPosition( iSettings.iLocationRequestTimeout ); + } + break; + + default: + break; + } + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::Suspend +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::Suspend() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::Suspend"); + iCellChangeHandler->Remove( this ); + switch( iState ) + { + case ELocationAcquisition: + if( iLastLocationFixType == EProperFix ) + { + iLocationRequestor->Cancel(); + } + else + { + iLocationRequestor->CancelFixFromNpp(); + } + + iProjectedState = iState; + iState = EIdle; + break; + + case ETriggerEvaluation: + iProjectedState = ETriggerEvaluation; + iState = EIdle; + break; + + case EUpdateIntervalEstimation: + iProjectedState = EUpdateIntervalEstimation; + iState = EIdle; + break; + + case ESleep: + iTimer->Cancel(); + iProjectedState = iState; + iState = EIdle; + + case EIdle: + break; + + default: + break; + } + + Cancel(); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::Reset +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::Reset() + { + iState = iProjectedState = EIdle; + iNearestTriggers.Reset(); + iLocReqCount = 0; + TPositionInfo posInfo; + iPosInfo = posInfo; + iFixForFiringCloseTriggers = EFalse; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::GetPositionInfo +// Processes the location information obtained from location requestor +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::GetPositionInfoL() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::GetPositionInfo"); + + // Update location acquisition status information + + if( !( (KErrNone == iStatus.Int()) || + (KPositionQualityLoss == iStatus.Int()) ) ) + { + ERROR("Position Information with : %d",iStatus.Int()); + iStatusManager->ReportLocationAcquisitionStatus( iStatus.Int() ); + + // The following check determines if there was a problem using the + // specified positioning technology to retrieve position information + if( KErrNotFound == iStatus.Int() && + iLastLocationFixType == EProperFix ) + { + LOG("Specified PSY not found"); + iAcquisitionStatus = ELocationAcquisitionNoMethod; + + if( iPsyChangeListner == NULL ) + { + iPsyChangeListner = CLbtPsyChangeListner::NewL( *this ); + } + iPsyChangeListner->StartToListen( iModuleId ); + LOG1("Listen to PSY change:%x",iModuleId); + TUid defaultID = { 0XFFFFFFFF }; + if( iLocationRequestor->GetPositionModuleId() != defaultID ) + { + LOG("Use default proxy"); + // switch to using default positioning technology + iModuleId = defaultID; + RequestTerminalPosition( iSettings.iLocationRequestTimeout,EProperFix ); + } + } + else + { + LOG("Location acquisition failed"); + if( iFixForFiringCloseTriggers && + (KErrTimedOut == iStatus.Int())&& + iLastLocationFixType == EProperFix ) + { + LOG("Firing Close triggers"); + FireClosestTriggers(); + RequestTerminalPosition(iSettings.iLocationRequestTimeout, EProperFix); + } + else + { + if( iLastLocationFixType == EProperFix ) + { + // Get fix from NPP PSY + LOG("Timed Out. Taking fix from NPP"); + RequestTerminalPosition( iSettings.iLocationRequestTimeout, EFixFromNpp ); + return; + + /* + iState = ESleep; + iTimer->Set( iStatus, KSleepTimeOnLocAcqFailure, ETrue ); + SetActive(); + + if( KErrAccessDenied == iStatus.Int() ) + { + iAcquisitionStatus = ELocationAcquisitionPrivacyReject; + } + else + { + iAcquisitionStatus = ELocationAcquisitionFailure; + }*/ + } + else + { + LOG("Npp psy failed to provide fix. Sleep now"); + iState = ESleep; + iTimer->Set( iStatus, KSleepTimeOnLocAcqFailure, ETrue ); + SetActive(); + + if( KErrAccessDenied == iStatus.Int() ) + { + iAcquisitionStatus = ELocationAcquisitionPrivacyReject; + } + else + { + iAcquisitionStatus = ELocationAcquisitionFailure; + } + } + } + } + + if( iFixForFiringCloseTriggers ) + { + iFixForFiringCloseTriggers = EFalse; + } + + // Update supervision dynamic info to the strategy class + TLbtStrategySupervisionDynamicInfo supervisionDynamicInfo; + supervisionDynamicInfo.iDistanceToNearestTrigger = 0.0; + supervisionDynamicInfo.iLatestAcquiredPosInfo = iPosInfo; + supervisionDynamicInfo.iLocationAcquisitionStatus = iAcquisitionStatus; + supervisionDynamicInfo.iNearestTriggerId = 0; + + iEngObserver->ReportTriggeringSupervisionStatus( supervisionDynamicInfo ); + return; + } + + if( iStatus.Int() == KPositionQualityLoss ) + { + TPosition currentPosition; + iPosInfo.GetPosition( currentPosition ); + LOG("Received KPositionQualityLoss"); + LOG1("Lat:%f",currentPosition.Latitude()); + LOG1("Long:%f",currentPosition.Longitude()); + LOG1("HA:%f",currentPosition.HorizontalAccuracy()); + } + + iStatusManager->ReportLocationAcquisitionStatus( KErrNone ); + // The fix was taken to fire nearest triggers then reset the flag + // to EFalse since the fix was successful and the nearest triggers will be + // evaluated and will be fired + if(iFixForFiringCloseTriggers) + { + iFixForFiringCloseTriggers = EFalse; + } + + TPosition currentPosition, prevPosition; + iPosInfo.GetPosition( currentPosition ); + iPrevPosInfo.GetPosition( prevPosition ); + + if( Math::IsNaN( currentPosition.Latitude() ) || + Math::IsNaN( currentPosition.Longitude() ) ) + { + LOG("ERROR:Lat/Long is Nan. Sleep now"); + iState = ESleep; + iTimer->Set( iStatus, KSleepTimeOnLocAcqFailure, ETrue ); + SetActive(); + + if( KErrAccessDenied == iStatus.Int() ) + { + iAcquisitionStatus = ELocationAcquisitionPrivacyReject; + } + else + { + iAcquisitionStatus = ELocationAcquisitionFailure; + } + return; + } + + // Record the time at which we got the fix + iLastFixTime.UniversalTime(); + + // Take note of reference time that would be used during estimation of + // sleep interval + iAcquisitionStatus = ELocationAcquisitionActive; + + iLocReqCount++; + iLocationRequestor->GetModuleInfo( iPosInfo.ModuleId() ); + + if( iLocArea.iCellId && iLastCellRequestStatus == KErrNone ) + { + LOG("Writing position to DB"); + LOG1("Cell Id = %d", iLocArea.iCellId ); + LOG1("LAC = %d", iLocArea.iLocationAreaCode ); + // Add current cell id position to cell-id database + TInt countryCode,networkCode; + + TLex lex( iNwInfo.iCountryCode ); + lex.Val( countryCode ); + + lex.Assign( iNwInfo.iNetworkId ); + lex.Val( networkCode ); + + TPosition cellPosition; + iPosInfo.GetPosition( cellPosition ); + if( iLastLocationFixType == EProperFix ) + { + cellPosition.SetHorizontalAccuracy( 3000 ); + } + + iCellIdDatabase->InsertCidLocation( countryCode, + networkCode, + iLocArea.iLocationAreaCode, + iLocArea.iCellId, + cellPosition ); + } + + // Check if there is no movement from last location fix. If true then + // re-evaluate sleep interval + TReal32 dist; + currentPosition.Distance( prevPosition, dist ); + if( dist == 0 ) + { + iState = EUpdateIntervalEstimation; + SetEvent(); + } + + LOG1("Lat:%f",currentPosition.Latitude()); + LOG1("Long:%f",currentPosition.Longitude()); + LOG1("HA:%f",currentPosition.HorizontalAccuracy()); + + // Switch to idle state as refresh is an async operation. Set projected + // state to trigger evaluation which will commence once the refresh + // operation is complete + iState = ETriggerEvaluation; + SetEvent(); + + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::EvaluateTriggersL +// Evaluates triggers based on the location information obtained +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::EvaluateTriggersL() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::EvaluateTriggersL"); + + // Reset nearest trigger array + iNearestTriggers.Reset(); + + // TODO: In case of updates to trigger information do not change state + // else change state to EUpdateIntervalEstimation + CLbtContainerTriggerEntry* conTrigger; + + // ResetViewIterator will switch state to Idle if there are no triggers in + // the system + if( KErrNone != ResetViewIterator() ) + { + return; + } + + while( iViewIterator.NextL( conTrigger ) ) + { + if( conTrigger ) + { + CLbtTriggerEntry* trigger = conTrigger->TriggerEntry(); + if( CLbtTriggerConditionBase::ETriggerConditionArea == + trigger->GetCondition()->Type() ) + { + // Area type trigger + CLbtTriggerConditionArea* triggerConArea = + static_cast< CLbtTriggerConditionArea* > + ( trigger->GetCondition() ); + + switch( triggerConArea->TriggerArea()->Type() ) + { + // Circular area + case CLbtGeoAreaBase::ECircle: + { + if( iLastLocationFixType == EProperFix ) + { + EvalCircularTriggerL( conTrigger ); + } + else if( iLastLocationFixType == EFixFromDb || iLastLocationFixType == EFixFromNpp ) + { + if( EvalCircularTriggerBasedOnCellPositionL( conTrigger ) ) + { + if( iLastLocationFixType == EFixFromNpp ) + { + // Fix is taken from NPP only when Proper Fix fails. Now we should + // sleep for location acquisition failure time our period since there is no point + // in attempting another proper fix + iState = ESleep; + iTimer->Set( iStatus, KSleepTimeOnLocAcqFailure, ETrue ); + SetActive(); + + if( KErrAccessDenied == iStatus.Int() ) + { + iAcquisitionStatus = ELocationAcquisitionPrivacyReject; + } + else + { + iAcquisitionStatus = ELocationAcquisitionFailure; + } + } + else + { + RequestTerminalPosition( iSettings.iLocationRequestTimeout,EProperFix ); + } + return; + } + } + break; + } + default: + break; + } + } + } + } + + // Update supervision dynamic info to the strategy class + TLbtStrategySupervisionDynamicInfo supervisionDynamicInfo; + if( iNearestTriggers.Count() ) + { + supervisionDynamicInfo.iDistanceToNearestTrigger = iNearestTriggers[0].distance; + supervisionDynamicInfo.iNearestTriggerId = iNearestTriggers[0].id; + } + supervisionDynamicInfo.iLatestAcquiredPosInfo = iPosInfo; + supervisionDynamicInfo.iLocationAcquisitionStatus = iAcquisitionStatus; + + + iEngObserver->ReportTriggeringSupervisionStatus( supervisionDynamicInfo ); + + iState = EUpdateIntervalEstimation; + SetEvent(); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::EvaluateTriggers +// Evaluates triggers based on the location information obtained +// ----------------------------------------------------------------------------- +// +TBool CLbtCoOrdinateSupervisor::EvaluateModifiedTriggersL() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::EvaluateModifiedTriggersL"); + + // Retrieve modified trigger list from trigger view to be supervised + RArray< TLbtTriggerId > modifiedTriggers; + iView->GetModifiedTriggers( modifiedTriggers ); + CleanupClosePushL( modifiedTriggers ); + if( modifiedTriggers.Count() ) + { + // TODO: Need to check for the deletion of + // Create an iterator to parse through the modified trigger list + CLbtTriggerView::TTriggerViewIter iter = iView->Begin( &modifiedTriggers, CLbtGeoAreaBase::ECircle ); + + CLbtContainerTriggerEntry* conTrigger; + while( iter.NextL( conTrigger ) ) + { + if( conTrigger ) + { + CLbtTriggerEntry* trigger = conTrigger->TriggerEntry(); + if( CLbtTriggerConditionBase::ETriggerConditionArea == + trigger->GetCondition()->Type() ) + { + // Area type trigger + CLbtTriggerConditionArea* triggerConArea = + static_cast< CLbtTriggerConditionArea* > + ( trigger->GetCondition() ); + + switch( triggerConArea->TriggerArea()->Type() ) + { + // Circular area + case CLbtGeoAreaBase::ECircle: + if( iLastLocationFixType == EProperFix ) + { + EvalCircularTriggerL( conTrigger ); + } + else if( iLastLocationFixType == EFixFromDb || iLastLocationFixType == EFixFromNpp ) + { + if( EvalCircularTriggerBasedOnCellPositionL( conTrigger ) ) + { + CleanupStack::PopAndDestroy(); // modifiedTriggers + return ETrue; + } + } + break; + + default: + break; + } + } + } + } + } + + CleanupStack::PopAndDestroy(); // modifiedTriggers + return EFalse; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::EvalCircularTrigger +// Evaluates triggers with circular area definition +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::EvalCircularTriggerL( + CLbtContainerTriggerEntry* aTrigger ) + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::EvalCircularTrigger"); + + + // Extract strategy data + TStrategyData strategyData = aTrigger->StrategyData(); + + TInt remRearmTime = 0; + TReal distanceToLatestLocation = 0.0; + TBool hasRearmTimeExpired = ETrue; + + LOGSTRING("Trigger: \"%S\" ", &(aTrigger->TriggerEntry()->Name())); + + if( strategyData.iFireTime ) + { + TTime triggerFiredTime( strategyData.iFireTime ); + + TTime currentTime; + currentTime.UniversalTime(); + + TTimeIntervalSeconds interval; + currentTime.SecondsFrom( triggerFiredTime, interval ); + + remRearmTime = aTrigger->TriggerEntry()->TimeToRearm() - interval.Int(); + + + if( remRearmTime <= 0 ) + { + remRearmTime = 0; + strategyData.iFireTime = 0; + } + else + { + LOG("Rearm Time has not expired"); + hasRearmTimeExpired = EFalse; + } + } + + CLbtTriggerConditionArea* trgCondition = + static_cast< CLbtTriggerConditionArea* > + ( ( aTrigger->TriggerEntry() )->GetCondition() ); + + CLbtGeoCircle* circularArea = static_cast< CLbtGeoCircle* > + ( trgCondition->TriggerArea() ); + + // Calculate distance of trigger from current location + TReal32 distanceToCenter; + TPosition currentPosition; + iPosInfo.GetPosition( currentPosition ); + TInt err = currentPosition.Distance( circularArea->Center(), + distanceToCenter ); + if( KErrNone != err ) + { + ERROR("Error in calculating distance:%d",err); + LOG1("Current Lat:%f",currentPosition.Latitude()); + LOG1("Current Long:%f",currentPosition.Longitude()); + LOG1("Trigger Lat:%f",circularArea->Center().Latitude()); + LOG1("Trigger Long:%f",circularArea->Center().Longitude()); + return; + } + + // Determine trigger radius and hysteresis radius to be used for supervision + // based on the accuracy of location fix + TTriggerArea triggerArea; + TReal positionAccuracy = currentPosition.HorizontalAccuracy(); + triggerArea = EstimateTriggerRadii( circularArea->Radius(), + aTrigger->ExtendedTriggerInfo()->HysteresisRadius(), + positionAccuracy ); + + // ENTRY Trigger + // Determine current position of terminal relative to the trigger area and + // set trigger fire status accordingly + if( CLbtTriggerConditionArea::EFireOnEnter == trgCondition->Direction() ) + { + TLbtTriggerDataMask dataMask = 0; + + TReal tolerableRadius = CalculateTolerableRadius( triggerArea.triggerRadius ); + // Terminal is inside trigger area + if( ( distanceToCenter < tolerableRadius ) && + ( ( distanceToCenter + positionAccuracy ) <= triggerArea.hysteresisRadius ) ) + { + LOG("Inside triggerin area"); + // If trigger in active state then fire trigger and set state to + // inactive. If trigger is inactive nothing is to be done other + // than calculating its distance from the hysteresis boundary + if( EActive == strategyData.iActivityStatus ) + { + LOG("Active trigger"); + // Check FireOnCreation flag here. If EFalse then dont + // fire the trigger. Instead only change the activity + // status. + if( aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() && + hasRearmTimeExpired ) + { + // Set trigger state to fired + aTrigger->ExtendedTriggerInfo()->SetTriggerFiredState( ETrue ); + TLbtTriggerFireInfo triggerFireInfo; + TPositionInfo positionInfo; + triggerFireInfo.iTriggerId = aTrigger->TriggerEntry()->Id(); + triggerFireInfo.iFiredPositionInfo = iPosInfo; + + aTrigger->ExtendedTriggerInfo()->SetFiredInfo( triggerFireInfo ); + + // Time at which trigger fired + TTime triggerFiredTime; + triggerFiredTime.UniversalTime(); + LOG("TRIGGER FIRED"); + + strategyData.iFireTime = triggerFiredTime.Int64(); + + remRearmTime = aTrigger->TriggerEntry()->TimeToRearm(); + dataMask |= + CLbtContainerTriggerEntry::EContainerAttributeIsFired | + CLbtContainerTriggerEntry::EContainerAttributeFireInfo ; + } + + // Set trigger to inactive state + strategyData.iActivityStatus = EInactive; + } + + // Calculate distance to current location and update trigger's + // dynamic info. This distance is (rH - D) where D is the distance + // between the two centers and rH is the radius of the hysteresis + // circle. Here the radius of hysteresis boundary is considered for + // distance calculation as this trigger would undergo a state + // change only when it crosses the hysteresis area + distanceToLatestLocation = Abs( triggerArea.hysteresisRadius - distanceToCenter ); + } + + // Terminal is outside hysteresis area + else if( distanceToCenter > ( triggerArea.hysteresisRadius + positionAccuracy ) ) + { + if( EInactive == strategyData.iActivityStatus ) + { + // Reset trigger state to valid + strategyData.iActivityStatus = EActive; + LOG("Trigger activated"); + } + + // Calculate distance of trigger to current location and update + // trigger's dynamic info. This distance is (D - rT) where D is + // the distance between two centers and rT is the radius of trigger. + // State change will occur only when the terminal moves beyond the + // boundary of the trigger + distanceToLatestLocation = Abs( distanceToCenter - triggerArea.triggerRadius ); + } + + // Terminal is inside hysteresis area. + else + { + // Trigger does not undergo any state change in this region. Theres + // only distance to be determined here + if( EActive == strategyData.iActivityStatus ) + { + // Terminal was outside hysteresis area earlier. Distance is + // therefore (D - rT) + distanceToLatestLocation = Abs( distanceToCenter - triggerArea.triggerRadius ); + } + else + { + // Terminal was inside trigger area earlier. Distance is + // therefore (rH - D) + distanceToLatestLocation = Abs( triggerArea.hysteresisRadius - distanceToCenter ); + } + } + + // Set FireOnCreation flag to ETrue here if its not already + // ETrue. This is done to ensure that the trigger is fired + // in the subsequent iterations if the triggering conditions + // are satisfied. + if( !aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() ) + { + aTrigger->ExtendedTriggerInfo()->SetTriggerFireOnCreation( ETrue ); + dataMask |= CLbtContainerTriggerEntry::EContainerAttributeIsTriggerFireOnCreation; + } + + if( dataMask ) + { + iView->UpdateTriggerInfo( CLbtGeoAreaBase::ECircle,iPosInfo, aTrigger, dataMask ); + } + } + + // EXIT Trigger + else + { + TLbtTriggerDataMask dataMask = 0; + // Retrieve boundary information of trigger + TTriggerBoundary boundary = EUndefined; + + // Retrieve boundary information of trigger + ( strategyData.iBoundaryCondition >= 0 && strategyData.iBoundaryCondition <= 2 )?boundary = + TTriggerBoundary( strategyData.iBoundaryCondition ):boundary; + + TReal tolerableRadius = CalculateTolerableRadius( triggerArea.triggerRadius ); + + // Terminal is inside trigger area + if( ( distanceToCenter < tolerableRadius ) && + ( ( distanceToCenter + positionAccuracy ) <= triggerArea.hysteresisRadius ) ) + { + // Check boundary condition to determine if the terminal has moved + // inside the trigger area without having gone beyond the area of + // hysteresis. In this case the trigger shall not be set as active + if( EOutside != boundary && + EInactive == strategyData.iActivityStatus ) + { + // Set trigger state to active + strategyData.iActivityStatus = EActive; + } + + // Set boundary as Outside + strategyData.iBoundaryCondition = TInt( EOutside ); + + if( EActive == strategyData.iActivityStatus ) + { + // Set Distance to the border of trigger area. This distance is + // (rT - D). + distanceToLatestLocation = Abs( triggerArea.triggerRadius - distanceToCenter ); + } + else + { + // Set distance to border of hysteresis area. This distance is + // (rH - D) where rH is the radius of hysteresis and D is the + // distance between the center of trigger and the center of + // location + distanceToLatestLocation = Abs( triggerArea.hysteresisRadius - distanceToCenter ); + } + } + + // Terminal is outside hysteresis area + else if( ( distanceToCenter > triggerArea.hysteresisRadius ) && + ( distanceToCenter > ( triggerArea.triggerRadius + positionAccuracy ) ) ) + { + if( EActive == strategyData.iActivityStatus ) + { + // Check FireOnCreation flag here. If EFalse then dont + // fire the trigger. Instead only change the activity + // status. + if( aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() && + hasRearmTimeExpired ) + { + // Set trigger state to fired + aTrigger->ExtendedTriggerInfo()->SetTriggerFiredState( ETrue ); + + TLbtTriggerFireInfo triggerFireInfo; + TPositionInfo positionInfo; + triggerFireInfo.iTriggerId = aTrigger->TriggerEntry()->Id(); + triggerFireInfo.iFiredPositionInfo = iPosInfo; + + aTrigger->ExtendedTriggerInfo()->SetFiredInfo( triggerFireInfo ); + + // Time at which trigger fired + TTime triggerFiredTime; + triggerFiredTime.UniversalTime(); + strategyData.iFireTime = triggerFiredTime.Int64(); + LOG("TRIGGER FIRED"); + remRearmTime = aTrigger->TriggerEntry()->TimeToRearm(); + dataMask |= + CLbtContainerTriggerEntry::EContainerAttributeIsFired | + CLbtContainerTriggerEntry::EContainerAttributeFireInfo; + } + + // Set the trigger state to inactive + strategyData.iActivityStatus = EInactive; + + } + + // Set boundary as Inside + strategyData.iBoundaryCondition = TInt( EInside ); + + // Calculate distance to border of trigger area. This distance + // is (D - rT) + distanceToLatestLocation = Abs( distanceToCenter - triggerArea.triggerRadius ); + } + + // Terminal is inside hysteresis area + else + { + if( EOutside == boundary && EActive == strategyData.iActivityStatus ) + { + // Check FireOnCreation flag here. If EFalse then dont + // fire the trigger. Instead only change the activity + // status. + if( aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() ) + { + // Set trigger state to fired + aTrigger->ExtendedTriggerInfo()->SetTriggerFiredState( ETrue ); + TLbtTriggerFireInfo triggerFireInfo; + TPositionInfo positionInfo; + triggerFireInfo.iTriggerId = aTrigger->TriggerEntry()->Id(); + triggerFireInfo.iFiredPositionInfo = iPosInfo; + + aTrigger->ExtendedTriggerInfo()->SetFiredInfo( triggerFireInfo ); + + // Time at which trigger fired + TTime triggerFiredTime; + triggerFiredTime.UniversalTime(); + + strategyData.iFireTime = triggerFiredTime.Int64(); + strategyData.iBoundaryCondition = TInt( EOutside ); + + remRearmTime = aTrigger->TriggerEntry()->TimeToRearm(); + dataMask |= + CLbtContainerTriggerEntry::EContainerAttributeIsFired | + CLbtContainerTriggerEntry::EContainerAttributeFireInfo; + } + + // Set the trigger state to inactive + strategyData.iActivityStatus = EInactive; + } + + if( EOutside != boundary ) + { + // Set the trigger state to inactive. This is done here because + // if a trigger was newly created (state is active) and it is + // found to be within hysteresis area, then the activity status + // needs to be set to inactive to enable the trigger to be + // handled appropriately when terminal moves inside trigger + // area. + strategyData.iActivityStatus = EInactive; + // Calclulate distance to border of trigger area. This + // distance is (D - rT) + distanceToLatestLocation = Abs( distanceToCenter - triggerArea.triggerRadius ); + } + else + { + // Calculate distance to the boundary of hysteresis. This + // distance is (rH - D) + distanceToLatestLocation = + Abs( triggerArea.hysteresisRadius - distanceToCenter ); + } + } + + // Set FireOnCreation flag to ETrue here if its not already + // ETrue. This is done to ensure that the trigger is fired + // in the subsequent iterations if the triggering conditions + // are satisfied. + if( !aTrigger->ExtendedTriggerInfo()->IsTriggerFireOnCreation() ) + { + aTrigger->ExtendedTriggerInfo()->SetTriggerFireOnCreation( ETrue ); + dataMask |= CLbtContainerTriggerEntry::EContainerAttributeIsTriggerFireOnCreation; + } + + if( dataMask ) + { + iView->UpdateTriggerInfo( CLbtGeoAreaBase::ECircle,iPosInfo, aTrigger, dataMask ); + } + } + aTrigger->SetStrategyData( strategyData ); + UpdateNearestTriggers( aTrigger->TriggerEntry()->Id(), distanceToLatestLocation , remRearmTime ); + LOG1("DistToTrig:%f",distanceToLatestLocation ); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::EvalCircularTriggerBasedOnCellPosition +// Evaluates triggers with circular area definition +// ----------------------------------------------------------------------------- +// +TBool CLbtCoOrdinateSupervisor::EvalCircularTriggerBasedOnCellPositionL( + CLbtContainerTriggerEntry* aTrigger ) + { + TTime currentTime; + currentTime.UniversalTime(); + + CLbtTriggerConditionArea* trgCondition = + static_cast< CLbtTriggerConditionArea* > + ( ( aTrigger->TriggerEntry() )->GetCondition() ); + + // Extract strategy data + TStrategyData strategyData = aTrigger->StrategyData(); + + TInt remRearmTime = 0; + TReal distanceToLatestLocation = 0.0; + + if( strategyData.iFireTime ) + { + TTime triggerFiredTime( strategyData.iFireTime ); + + TTimeIntervalSeconds interval; + currentTime.SecondsFrom( triggerFiredTime, interval ); + + remRearmTime = aTrigger->TriggerEntry()->TimeToRearm() - interval.Int(); + + if( remRearmTime <= 0 ) + { + remRearmTime = 0; + strategyData.iFireTime = 0; + aTrigger->SetStrategyData( strategyData ); + } + } + + + TPosition currentPosition; + iPosInfo.GetPosition( currentPosition ); + TReal positionAccuracy = currentPosition.HorizontalAccuracy(); + + CLbtGeoCircle* circularArea = static_cast< CLbtGeoCircle* > + ( trgCondition->TriggerArea() ); + + TReal32 distanceToCenter; + TInt err = currentPosition.Distance( circularArea->Center(), + distanceToCenter ); + if( err!=KErrNone ) + { + return ETrue; + } + + // If the trigger is entry type,we calculate distance to the hysterisis radius + if( CLbtTriggerConditionArea::EFireOnEnter == trgCondition->Direction() ) + { + distanceToLatestLocation = distanceToCenter - + ( positionAccuracy+aTrigger->ExtendedTriggerInfo()->HysteresisRadius()); + + if( distanceToLatestLocation < 0 && (remRearmTime == 0) ) + { + // Request fix using any of the available psy + LOG("Request Proper Fix"); + return ETrue; + } + + // Activate the trigger if the trigger is outside Hysteresis area + if( EInactive == strategyData.iActivityStatus && distanceToLatestLocation > 0 ) + { + // Activate the trigger + strategyData.iActivityStatus = EActive; + aTrigger->SetStrategyData( strategyData ); + LOG("Trigger activated based on NPP fix"); + } + UpdateNearestTriggers( aTrigger->TriggerEntry()->Id(), distanceToLatestLocation, remRearmTime ); + } + // If the trigger is exit type,we calculate distance to the radius + else if( CLbtTriggerConditionArea::EFireOnExit == trgCondition->Direction() ) + { + distanceToLatestLocation = distanceToCenter - + ( positionAccuracy+circularArea->Radius() ); + + if( distanceToLatestLocation < 0 && (remRearmTime == 0) ) + { + // Request fix using any of the available psy + LOG("Request Proper Fix"); + return ETrue; + } + UpdateNearestTriggers( aTrigger->TriggerEntry()->Id(), distanceToLatestLocation,remRearmTime ); + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::EstimateSleepInterval +// Calculates the sleep interval +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::EstimateSleepInterval() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::EstimateSleepInterval"); + + TReal maxUserSpeed = iSettings.iMaximumUserSpeed; + + TReal actualEstimatedSpeed = KMinProjSpeed; + // Flag to determine if the nearest trigger is an inactive trigger + TBool nearestTriggerInactive = EFalse; + + // This is first time when there are no previously observed values + if( iLocReqCount == 1 ) + { + // First iteration use the minimum update interval + if( iNearestTriggers.Count() ) + { + iSleepInterval = iNearestTriggers[0].distance / maxUserSpeed; + } + else + { + iSleepInterval = iSettings.iMinimumLocationUpdateInterval; + } + } + else + { + iEstimatedUserSpeed = 0.0; + if( (iLastLocationFixType == EFixFromDb) || + (iLastLocationFixType == EFixFromNpp) ) + { + iEstimatedUserSpeed = (maxUserSpeed + KMinProjSpeed)/2; + } + else if( iLastLocationFixType == EProperFix ) + { + // determine average speed from previous location request which is the + // observed speed + TPosition currentPosition, prevPosition; + iPosInfo.GetPosition( currentPosition ); + iPrevPosInfo.GetPosition( prevPosition ); + + TReal32 avgSpeed = 0.0; + + currentPosition.Speed( prevPosition, avgSpeed ); + TObservedValues obsValue; + obsValue.speed = avgSpeed; + obsValue.time = currentPosition.Time(); + + if( iNObservedValues.Count() == maxObsValues ) + { + iNObservedValues.Remove( 0 ); + } + iNObservedValues.Append( obsValue ); + + TReal num = 0.0; + TReal den = 0.0; + TReal obsSpeed = 0.0; + TReal obsTime = 0.0; + TTime currentTime; + + // Determine average of previously obtained observed speed, time values. + // Use the current time value obtained from the approximation of speed. + currentTime.UniversalTime(); + + for( TInt i = 0; i < iNObservedValues.Count(); i++ ) + { + obsSpeed = maxUserSpeed - ( iNObservedValues[i] ).speed; + TTimeIntervalSeconds timediff; + currentTime.SecondsFrom( ( iNObservedValues[i] ).time, timediff ); + obsTime = timediff.Int() / constantTime; + TReal timeExp = 0.0; + Math::Exp( timeExp, (-1 * obsTime ) ); + + num += obsSpeed * timeExp * timeExp; + den += timeExp; + } + + iEstimatedUserSpeed = maxUserSpeed - ( num / den ); + + if( Math::IsNaN(iEstimatedUserSpeed) ) + { + iEstimatedUserSpeed = maxUserSpeed; + } + + actualEstimatedSpeed = iEstimatedUserSpeed; + LOG1("Actual estimated speed:%f",actualEstimatedSpeed); + + if(iEstimatedUserSpeed < KMinProjSpeed) + { + iEstimatedUserSpeed = KMinProjSpeed; + } + // There are some cases estimate user speed goes to infinty. + else if( iEstimatedUserSpeed > maxUserSpeed ) + { + iEstimatedUserSpeed = maxUserSpeed; + } + } + + /** + * Find the position of the nearest trigger which: - + * + * a) Is Active + * b) Its rearm time has expired + */ + TInt position = -1; + for( TInt i=0;i= 0 ) + { + for( TInt i=0;i<=position;i++ ) + { + // Sleep interval for a trigger is the maximum of time to trigger and rearm time + TInt maxSleepTimeForTrigger; + if( iNearestTriggers[i].remRearmTime < iNearestTriggers[i].minTimeRequired ) + { + maxSleepTimeForTrigger = iNearestTriggers[i].minTimeRequired; + } + else + { + maxSleepTimeForTrigger = iNearestTriggers[i].remRearmTime; + } + + // Sleep interval for system is minimum sleep interval of all triggers + if( ( !iSleepInterval.Int() && maxSleepTimeForTrigger ) || + iSleepInterval.Int() > maxSleepTimeForTrigger ) + { + iSleepInterval = maxSleepTimeForTrigger; + nearestTriggerId = iNearestTriggers[i].id; + } + } + } + // Case where all the triggers are waiting for rearm time to elapse + else + { + for( TInt i=0;i iNearestTriggers[i].remRearmTime )) + { + iSleepInterval = iNearestTriggers[i].remRearmTime; + } + } + } + + LOG1("Estimated speed:%f",iEstimatedUserSpeed); + + + if( nearestTriggerId ) + { + // Update the nearestTriggerInactive flag + CLbtContainerTriggerEntry* trigEntry = NULL; + TBool found = iView->GetTriggerByID( nearestTriggerId, trigEntry ); + + if( found && (trigEntry != NULL) ) + { + TStrategyData strategyData = trigEntry->StrategyData(); + + if( strategyData.iActivityStatus == EInactive ) + { + // Inside triggering area + nearestTriggerInactive = ETrue; + } + else + { + // Outside triggering area + nearestTriggerInactive = EFalse; + } + } + } + + // Reduce the time taken from last position fix + if( iLastLocationFixType == EProperFix ) + { + TTime currentTime; + currentTime.UniversalTime(); + TTimeIntervalSeconds seconds; + currentTime.SecondsFrom(iLastFixTime, seconds); + iProcessingInterval = seconds.Int(); + iSleepInterval = iSleepInterval.Int() - iProcessingInterval; + } + } + + // If sleep interval is less than KMinSleepInterval and the UE is travelling in + // high speed then request terminal position immediately + if( !nearestTriggerInactive && + ( iSleepInterval.Int() <= KMinSleepInterval ) && + ( iLastLocationFixType == EProperFix ) ) + { + LOG1("Requesting time out %d", iSleepInterval.Int()); + iFixForFiringCloseTriggers = ETrue; + // Here we need fix with in the estimated time to reach trigger.Hence setting timeout value to + // estimated sleep interval + RequestTerminalPosition( (KMinSleepInterval * KMicroMultiplier),EProperFix ); + return; + } + + iState = ESleep; + TBool useMvmtDet = ETrue; + if( iLastLocationFixType != EProperFix ) + { + useMvmtDet = ETrue; + } + else if( nearestTriggerInactive ) + { + useMvmtDet = ETrue; + } + else if( iSleepInterval.Int() < 20 ) + { + useMvmtDet = EFalse; + } + else if( actualEstimatedSpeed > KMaxSpeedToUseMvmtDet ) + { + useMvmtDet = EFalse; + } + LOG1("useMvmtDet = %d", useMvmtDet); + iTimer->Set( iStatus, iSleepInterval, useMvmtDet ); + SetActive(); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::ProcessInterrupt +// Evaluates the cause of a timer interrupt and determines the necessary +// actions to be performed +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::ProcessInterrupt() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::ProcessInterrupt"); + + // This is when errors occur while acquiring terminal position + if( !iStatusManager->LocationAcqSuccess() ) + { + // Check sleep interval and determine if sleep mode can continue else + // retry acquiring terminal position. This happens when there are + // changes to triggers in the sleep mode during which the sleep is + // cancelled and trigger view is refreshed. Once the refresh operation + // is completed, this method is invoked. + TTimeIntervalSeconds interval; + if( iTimer->RemainingSleepInterval( interval ) ) + { + iState = ESleep; + if( interval.Int() < 5 ) + { + iTimer->ResetInterval( iStatus, interval,EFalse ); + } + else + { + iTimer->ResetInterval( iStatus, interval,ETrue ); + } + SetActive(); + } + else + { + // If the last location acqusition has failed and the location information for the current cell + // is unavailable then request location from NPP PSY else request from DB itself + if( (iLastCellRequestStatus == KErrNone) && + iLocArea.iCellId ) + { + // Cell information is available + if( !(KErrNone == GetCellIdPosition( iPosInfo ) ) ) + { + RequestTerminalPosition( iSettings.iLocationRequestTimeout, EProperFix ); + } + else + { + RequestTerminalPosition( iSettings.iLocationRequestTimeout, EFixFromDb ); + } + } + else + { + // Current cell information un-available. Make proper fix + RequestTerminalPosition( iSettings.iLocationRequestTimeout, EProperFix ); + } + } + } + + + // This is when sleep mode is interrupted due to notifications from + // container for addition/modification/deletion of triggers in the system + else if( iTimer->SleepIntervalInterrupted() ) + { + TLbtTriggerId nearestTrigger = 0; + if( iNearestTriggers.Count() ) + { + for( TInt i=0;iDetermineNearestTriggerChanges( &iNearestTriggers ); + + if( iNearestTriggers.Count() == 0 ) + { + // This means the nearest 5 triggers have been changed. Reset + // iterator re-evaluate all triggers in the system. + if( KErrNone != ResetViewIterator() ) + { + return; + } + iState = ETriggerEvaluation; + SetEvent(); + } + else + { + TBool makeLocReq = EFalse; + TRAPD( err, makeLocReq = EvaluateModifiedTriggersL( ) ); + + if( KErrNone != err ) + { + ERROR("EvaluateTriggersL leaving with %d", err); + Term(); + return; + } + + if( makeLocReq ) + { + // Location request is needed based on evaluating + // modified triggers + RequestTerminalPosition( iSettings.iLocationRequestTimeout ); + return; + } + + // Check if nearest trigger has changed + TLbtTriggerId nearestTriggerAfterEvaluation = 0; + if( iNearestTriggers.Count() ) + { + for( TInt i=0;iRemainingSleepInterval( remainingInterval ) ) + { + iState = ESleep; + if( remainingInterval.Int() < 5 ) + { + iTimer->ResetInterval( iStatus, remainingInterval,EFalse ); + } + else + { + iTimer->ResetInterval( iStatus, remainingInterval,ETrue ); + } + SetActive(); + } + else + { + RequestTerminalPosition( iSettings.iLocationRequestTimeout ); + } + } + } + } + else if( KErrNone == iStatus.Int() || KErrAbort == iStatus.Int() ) + { + RequestTerminalPosition( iSettings.iLocationRequestTimeout ); + } + else + { + LOG1("Error in timer:%d",iStatus.Int()); + } + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::RequestTerminalPosition +// Issues an asynchronous request to determine terminal's position +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::RequestTerminalPosition( TInt aLocationRequestTimeout, + TLocationFixType aFixLocationFixType ) + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::RequestTerminalPosition"); + iPrevPosInfo = iPosInfo; + LOG1("aFixLocationFixType = %d", aFixLocationFixType); + LOG1("Cell Id = %d", iLocArea.iCellId); + + if( (aFixLocationFixType == EFixFromDb) && + (iLastCellRequestStatus == KErrNone) && + iLocArea.iCellId ) + { + LOG("Taking fix from DB"); + TInt error = GetCellIdPosition( iPosInfo ); + if( KErrNone == error) + { + LOG("Fix From DB"); + TPosition position; + iPosInfo.GetPosition(position); + LOG1("Lat:%f", position.Latitude()); + LOG1("Long:%f", position.Longitude()); + LOG1("HA:%f", position.HorizontalAccuracy()); + iLastLocationFixType = EFixFromDb; + iState = ETriggerEvaluation; + SetEvent(); + return; + } + else + { + LOG1("Failed to get Fix From DB with %d", error); + } + } + else if( aFixLocationFixType == EFixFromNpp ) + { + iLastLocationFixType = EFixFromNpp; + iLocationRequestor->CurrentLocationFromNpp( iPosInfo, iStatus, + TTimeIntervalMicroSeconds( aLocationRequestTimeout ) ); + iState = ELocationAcquisition; + SetActive(); + return; + } + + iLastLocationFixType = EProperFix; + iLocationRequestor->CurrentLocation( iPosInfo, iStatus, + iModuleId, + TTimeIntervalMicroSeconds( aLocationRequestTimeout ) ); + iState = ELocationAcquisition; + SetActive(); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::GetCellIdPosition +// Get the position corresponding to current cell id +// ----------------------------------------------------------------------------- +// +TInt CLbtCoOrdinateSupervisor::GetCellIdPosition( TPositionInfo& aPositionInfo ) + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::GetCellIdPosition"); + TInt countryCode,networkCode; + + TLex lex( iNwInfo.iCountryCode ); + lex.Val( countryCode ); + + lex.Assign( iNwInfo.iNetworkId ); + lex.Val( networkCode ); + + TPosition position; + TInt error = iCellIdDatabase->GetLocationForCid( countryCode,networkCode,iLocArea.iLocationAreaCode, + iLocArea.iCellId,position ); + if( error == KErrNone ) + { + aPositionInfo.SetPosition( position ); + } + return error; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::UpdateNearestTriggers +// Updates the record of nearest triggers +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::UpdateNearestTriggers( TLbtTriggerId aID, TReal aDistance , TInt aRemRearmTime ) + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::UpdateNearestTriggers"); + TNearestTrigger nTrigger; + nTrigger.distance = aDistance; + nTrigger.id = aID; + nTrigger.remRearmTime = aRemRearmTime; + + TLinearOrder< TNearestTrigger > byDistance( CompareByDistance ); + iNearestTriggers.InsertInOrderAllowRepeats( nTrigger, byDistance ); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::EstimateTriggerRadii +// Calculcates the trigger radius and the radius of the hysteresis circle +// ----------------------------------------------------------------------------- +// +CLbtCoOrdinateSupervisor::TTriggerArea CLbtCoOrdinateSupervisor::EstimateTriggerRadii( + TReal aTriggerRadius, TReal aHysteresisRadius, + TReal aPositionAccuracy ) + { + TTriggerArea trgArea; + TReal ratioOfCircularAreas = aPositionAccuracy / aTriggerRadius; + + if( ratioOfCircularAreas >= KCofftOfHighEdgeLimit ) + { + trgArea.triggerRadius = aTriggerRadius; + trgArea.hysteresisRadius = aHysteresisRadius; + } + else + { + // Update radiusOfTrigger and radiusOfHysteresis accordingly + trgArea.triggerRadius = aTriggerRadius +( KAccuracyMultiplier * aPositionAccuracy ); + trgArea.hysteresisRadius = Hysteresis( trgArea.triggerRadius ); + } + + return trgArea; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::Hysteresis +// Calculates the hysteresis radius +// ----------------------------------------------------------------------------- +// +TReal CLbtCoOrdinateSupervisor::Hysteresis( TReal aTriggerRadius ) + { + TReal hysteresis; + if( aTriggerRadius > KTriggerRadiusCutoff ) + { + TReal logRadius; + Math::Ln( logRadius, aTriggerRadius / 10 ); + hysteresis = aTriggerRadius / logRadius; + } + else + { + hysteresis = aTriggerRadius / 4; + } + + return hysteresis + aTriggerRadius; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::DetermineNearestDistances +// Algorithm to determine the shortest distance +// ----------------------------------------------------------------------------- +// +TInt CLbtCoOrdinateSupervisor::CompareByDistance( const TNearestTrigger& src, + const TNearestTrigger& dst ) + { + if( src.distance > dst.distance ) + { + return 1; + } + else if( src.distance < dst.distance ) + { + return -1; + } + return 0; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::CompareByID +// Determine equality of nearest triggers by id +// ----------------------------------------------------------------------------- +// +TBool CLbtCoOrdinateSupervisor::CompareByID( const TNearestTrigger& src, + const TNearestTrigger& dst ) + { + if( src.id > dst.id ) + { + return ETrue; + } + return EFalse; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::ResetViewIterator +// Resets trigger view iterator. +// ----------------------------------------------------------------------------- +// +TInt CLbtCoOrdinateSupervisor::ResetViewIterator() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::ResetViewIterator"); + TInt err = iViewIterator.Reset(); + if( KErrNone != err ) + { + if( KErrNotFound == err ) + { + // determine update interval + iState = iProjectedState = EIdle; + } + else + { + // TODO: Report error to server. This can be done only after + // introducing new state to strategy dynamic info. + Term(); + } + return err; + } + + return KErrNone; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::RunL +// Inherited from CActive - called when the request issued is completed. +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::RunL() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::RunL"); + switch ( iState ) + { + case ELocationAcquisition: + GetPositionInfoL(); + break; + + case ETriggerEvaluation: + EvaluateTriggersL(); + break; + + case EUpdateIntervalEstimation: + EstimateSleepInterval(); + break; + + case ESleep: + LOG("Wakeup"); + ProcessInterrupt(); + break; + + default: + break; + } + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::DoCancel +// Inherited from CActive - called to cancel outanding events. +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::DoCancel() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::DoCancel"); + iFixForFiringCloseTriggers = EFalse; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::RunError +// Handles the event of leave from the request completion event handler RunL() +// ----------------------------------------------------------------------------- +// +TInt CLbtCoOrdinateSupervisor::RunError( TInt /*aError*/ ) + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::RunError"); + Term(); + return KErrNone; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::CLbtCoOrdinateSupervisor +// C++ default constructor. +// ----------------------------------------------------------------------------- +// +CLbtCoOrdinateSupervisor::CLbtCoOrdinateSupervisor() : + CActive( EPriorityHigh ) + { + CActiveScheduler::Add( this ); + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::ConstructL +// Symbian 2nd phase constructor. +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::ConstructL( TAny* /*aConstructionParameters*/, + CLbtTriggerView* aView, + MLbtStrategyEngineObsrvr* aObserver, + CLbtCellChangeHandler* aCellChangeHandler ) + { + iEngObserver = aObserver; + iState = iProjectedState = EIdle; + iEngObserver->RetrieveTriggeringSettings( iSettings ); + iCellChangeHandler = aCellChangeHandler; + + iModuleId = iSettings.iPositioningTechnology; + + iLocationRequestor = CLbtLocationRequestor::NewL(); + + iStatusManager = CLbtStatusManager::NewL(); + iTimer = CLbtStrategyTimer::NewL(); + iView = aView; + + iViewIterator = iView->BeginL( CLbtGeoAreaBase::ECircle ); + iCellIdDatabase = CLbtCellIdDatabase::NewL(); + iLastCellRequestStatus = KErrUnknown; + iLastLocationFixType = EFixUnknown; + iPsyChangeListner = NULL; + iFixForFiringCloseTriggers = EFalse; + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::SetEvent +// Completes the iRequestStatus with KErrNone. +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::SetEvent() + { + if ( !IsActive() ) + { + TRequestStatus* lStatus = &iStatus; + User::RequestComplete( lStatus, KErrNone ); + SetActive(); + } + } + + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::Term +// +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::Term() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::Term"); + + iSupervisionInitiated = EFalse; + + iView->Cancel(); + switch( iState ) + { + case ELocationAcquisition: + if( iLastLocationFixType == EProperFix ) + { + iLocationRequestor->Cancel(); + } + else + { + iLocationRequestor->CancelFixFromNpp(); + } + break; + + case ESleep: + iTimer->Cancel(); + break; + + default: + Cancel(); + break; + } + + iState = iProjectedState = EIdle; + iLastLocationFixType = EFixUnknown; + iFixForFiringCloseTriggers = EFalse; + } + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::FireClosestTriggers +// +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::FireClosestTriggers() + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::FireClosestTriggers"); + LOG1("NT Count = %d", iNearestTriggers.Count()); + for( TInt i=0;iGetTriggerByID( iNearestTriggers[i].id,trigger ) ) + { + LOGSTRING("Trigger: \"%S\" ", &(trigger->TriggerEntry()->Name())); + // check the activity status + TStrategyData strategyData = trigger->StrategyData(); + if( strategyData.iActivityStatus == EActive ) + { + // Fire the trigger + TLbtTriggerDataMask dataMask = 0; + + // Set trigger state to fired + trigger->ExtendedTriggerInfo()->SetTriggerFiredState( ETrue ); + TLbtTriggerFireInfo triggerFireInfo; + TPositionInfo positionInfo; + triggerFireInfo.iTriggerId = trigger->TriggerEntry()->Id(); + triggerFireInfo.iFiredPositionInfo = iPrevPosInfo; + + trigger->ExtendedTriggerInfo()->SetFiredInfo( triggerFireInfo ); + + // Time at which trigger fired + TTime triggerFiredTime; + triggerFiredTime.UniversalTime(); + LOG("NEAREST TRIGGER FIRED"); + + strategyData.iFireTime = triggerFiredTime.Int64(); + // Set trigger to inactive state + strategyData.iActivityStatus = EInactive; + + dataMask |= + CLbtContainerTriggerEntry::EContainerAttributeIsFired | + CLbtContainerTriggerEntry::EContainerAttributeFireInfo ; + + iView->UpdateTriggerInfo( CLbtGeoAreaBase::ECircle,iPosInfo, trigger, dataMask ); + trigger->SetStrategyData( strategyData ); + } + } + else + { + LOG("TRIGGER NOT FOUND ??"); + } + } + else + { + LOG("ELSE"); + // Since the array is in the ascending order of distance( which is directly proportional to time ), + // we can need not search rest of the array. + break; + } + } + } + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::CalculateTolerableRadius +// +// ----------------------------------------------------------------------------- +// +TReal CLbtCoOrdinateSupervisor::CalculateTolerableRadius( TReal aRadius ) + { + // Tolerance can be calculated using the straight line equation. Slope of straight line is 0.07 and + // intercept is 22.2 + TReal tolerableInaccuracy = ( 0.07 * aRadius ) + 22.2; + return ( tolerableInaccuracy + aRadius ); + } + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::HandleCellChangeEvent +// +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::HandleCellChangeEvent( + const TInt aStatus, + const RMobilePhone::TMobilePhoneNetworkInfoV1& aNwInfo, + const RMobilePhone::TMobilePhoneLocationAreaV1& aLocArea) + { + FUNC_ENTER("CLbtCoOrdinateSupervisor::HandleCellChangeEvent"); + if( KErrNone == aStatus ) + { + // validate network info + if (aNwInfo.iMode == RMobilePhone::ENetworkModeGsm || + aNwInfo.iMode == RMobilePhone::ENetworkModeWcdma) + { + TLex lex( aNwInfo.iCountryCode ); + TInt countryCode,networkCode; + lex.Val( countryCode ); + if( countryCode ) + { + lex.Assign( aNwInfo.iNetworkId ); + lex.Val( networkCode ); + if( networkCode ) + { + if( aLocArea.iLocationAreaCode && aLocArea.iCellId ) + { + iLastCellRequestStatus = KErrNone; + iNwInfo = aNwInfo; + iLocArea = aLocArea; + } + } + } + } + } + else + { + iLastCellRequestStatus = aStatus; + } + } + +// ----------------------------------------------------------------------------- +// CLbtCoOrdinateSupervisor::HandlePsyChangeEvent +// +// ----------------------------------------------------------------------------- +// +void CLbtCoOrdinateSupervisor::HandlePsyChangeEvent( TPositionModuleId aModuleId ) + { + LOG("CLbtCoOrdinateSupervisor::HandlePsyChangeEvent"); + if( aModuleId == iSettings.iPositioningTechnology ) + { + LOG("aModuleId == iSettings.iPositioningTechnology"); + iModuleId = aModuleId; + delete iPsyChangeListner; + iPsyChangeListner = NULL; + } + else + { + LOG("aModuleId != iSettings.iPositioningTechnology"); + // We will use defualt proxy + iModuleId = TUid::Uid(0xFFFFFFFF); + iPsyChangeListner->StartToListen( iSettings.iPositioningTechnology ); + } + + // If coordinate supervisor AO is not active,request terminal position + if( !IsActive() ) + { + RequestTerminalPosition( iSettings.iLocationRequestTimeout,EProperFix ); + } + } +// end of file