/** Calculates a difference between the system UTC time and the GPS based UTC time. Accuracy of the calculations is affected by: - time required to process the satellite information in the GPS HW - time required to transfer the information over a HW link from the GPS HW to a mobile phone - time required to receive the information by a Symbian OS drivers and decode by the AGPS integration module @param aSatInfo A satellite information with the GPS based UTC time @param aTimeCorr A time correction that must be applied to the System UTC time. Not valid if the method returns an error. @return KErrNone if sucedded. KErrNotSupported if the satellite (GPS based UTC time) or the position reception time is not present (0). @see TPositionSatelliteInfo @internalComponent */ TInt CAutoClockAdjust::CalculateTimeCorrection(const TPositionSatelliteInfo &aSatInfo, TTimeIntervalMicroSeconds &aTimeCorr) { LBSLOG(ELogP1, "CAutoClockAdjust::CalculateTimeCorrection()\n"); // The System UTC time when the location has been received from a GPS TTime recTime; // GPS based UTC time (satellite time) TTime satTime; TPosition pos; TInt err = KErrNone; aSatInfo.GetPosition(pos); recTime = pos.Time(); satTime = aSatInfo.SatelliteTime(); if ((recTime == 0) || (satTime == 0)) { err = KErrNotSupported; } else { aTimeCorr = satTime.MicroSecondsFrom(recTime); } return err; }
/** Adjusts system time if required. The decision whether the adjustment is needed or not is based on the following criterias: - satellite time must be present in the location update - time threshold must be exceeded - time from a last adjustment is greater than a defined interval. @param aStatus An error code. @param TPositionSatelliteInfo Position and time information. If clock adjustment takes place the TPosition::iTime is re-set to the satellite time. @see CLbsAdmin @see TPositionSatelliteInfo */ void CAutoClockAdjust::LocationUpdate(TInt aStatus, TPositionSatelliteInfo& aPosInfo) { LBSLOG(ELogP1, "CAutoClockAdjust::LocationUpdate()\n"); TTimeIntervalMicroSeconds timeCorr; TTime sysTime; TInt err; // If adjustment on, no error, and satellite information present if ((iClockAdjustSetting == CLbsAdmin::EClockAdjustOn) && (aStatus == KErrNone) && ((aPosInfo.PositionClassType() & EPositionSatelliteInfoClass) == EPositionSatelliteInfoClass)) { // Is is time do do another time adjustment? sysTime.UniversalTime(); if (Abs(sysTime.MicroSecondsFrom(iLastAdjustment).Int64()) > (1000*iAdjustInterval)) { const TPositionSatelliteInfo& satInfo = static_cast<const TPositionSatelliteInfo&>(aPosInfo); err = CalculateTimeCorrection(satInfo, timeCorr); if (err == KErrNone) { // Is threshold exceeded? if (Abs(timeCorr.Int64()) > (1000*iAdjustThreshold)) { sysTime.UniversalTime(); sysTime += timeCorr; LBSLOG(ELogP9, "->S CGpsSetClockBase::SetUTCTime() ClockModule\n"); LBSLOG5(ELogP9, " > TTime sysTime = %02d:%02d:%02d.%06d\n", sysTime.DateTime().Hour(), sysTime.DateTime().Minute(), sysTime.DateTime().Second(), sysTime.DateTime().MicroSecond()); err = iSetClockImpl->SetUTCTime(sysTime); LBSLOG2(ELogP9, " Return = %d\n", err); if (err == KErrNone) { // Sync the position time with the satellite time // to avoid re-adjusting the system time by the manual clock adjustment component. TPosition pos; aPosInfo.GetPosition(pos); pos.SetTime(aPosInfo.SatelliteTime()); aPosInfo.SetPosition(pos); LBSLOG2(ELogP2, "ACTION: Clock Adjusted by %ld\n", timeCorr.Int64()); } } if (err == KErrNone) { // Remember the current time even if threshold not exceeded iLastAdjustment = sysTime; } else { LBSLOG_WARN2(ELogP3, "Clock Adjustment failed. Error: %d\n", err); } } } } }
void XQLocationPrivate::DeliverPositionerResults(TPositionSatelliteInfo aPositionInfo) { TPosition pos; aPositionInfo.GetPosition(pos); // Handle speed reporting float speed = 0; if (speedAvailable) { // Positioning module is able to offer speed information TCourse course; aPositionInfo.GetCourse(course); speed = course.Speed(); if (isnan(speed)) { speed = 0; } } else { // Positioning module does not offer speed information // => Speed is calculated using position information & timestamps TTime posTime; TTimeIntervalSeconds interval; for (int i = iPositions.Count()-1 ; i >= 0; i--) { if (pos.Time().SecondsFrom(iPositions[i].Time(),interval) == KErrNone) { if (interval.Int() > 10) { pos.Speed(iPositions[i], speed); break; } } } while (iPositions.Count() > 0) { if (pos.Time().SecondsFrom(iPositions[0].Time(),interval) == KErrNone) { if (interval.Int() > 60) { iPositions.Remove(0); } else { break; } } } if (iPositions.Count() > 0) { if (pos.Time().SecondsFrom(iPositions[iPositions.Count()-1].Time(),interval) == KErrNone) { if (interval.Int() > 1) { iPositions.Append(pos); } } } else { iPositions.Append(pos); } // Accept speed from range 0.01 m/s (0.036 km/h) to 200 m/s (720 km/h) if (speed < 0.01 || speed > 200) { speed = 0; } } if (speed != iPreviousSpeed) { emit ipParent->speedChanged(speed); } iPreviousSpeed = speed; // Handle satellite information reporting if (satelliteInfoAvailable) { if (aPositionInfo.NumSatellitesInView() != iPreviousNumSatellitesInView) { emit ipParent->numberOfSatellitesInViewChanged(aPositionInfo.NumSatellitesInView()); } iPreviousNumSatellitesInView = aPositionInfo.NumSatellitesInView(); if (aPositionInfo.NumSatellitesUsed() != iPreviousNumSatellitesUsed) { emit ipParent->numberOfSatellitesUsedChanged(aPositionInfo.NumSatellitesUsed()); } iPreviousNumSatellitesUsed = aPositionInfo.NumSatellitesUsed(); } // Handle position information reporting if (iPreviousPosition.Latitude() != pos.Latitude() || iPreviousPosition.Longitude() != pos.Longitude() || iPreviousPosition.Altitude() != pos.Altitude()) { if (!isnan(pos.Latitude()) || !isnan(pos.Longitude()) || !isnan(pos.Altitude())) { emit ipParent->locationChanged(pos.Latitude(),pos.Longitude(),pos.Altitude(),speed); } if (iPreviousPosition.Latitude() != pos.Latitude()) { if (!isnan(pos.Latitude())) { emit ipParent->latitudeChanged(pos.Latitude(),pos.HorizontalAccuracy()); } } if (iPreviousPosition.Longitude() != pos.Longitude()) { if (!isnan(pos.Longitude())) { emit ipParent->longitudeChanged(pos.Longitude(),pos.HorizontalAccuracy()); } } if (iPreviousPosition.Altitude() != pos.Altitude()) { if (!isnan(pos.Altitude())) { emit ipParent->altitudeChanged(pos.Altitude(),pos.VerticalAccuracy()); } } } iPreviousPosition = pos; if (iSingleUpdate) { stopUpdates(); iSingleUpdate = EFalse; } }
TVerdict CT_LbsHybridUEAssistedX3PAccurateGPS::doTestStepL() { // Generic test step used to test the LBS Client Notify position update API. INFO_PRINTF1(_L("CT_LbsHybridUEAssistedX3PAccurateGPS::doTestStepL()")); // Stop the test if the preamble failed TESTL(TestStepResult() == EPass); const TInt KTimeOut = 30*1000*1000; const TInt KAdviceSystemStatusTimeout = 40*1000*1000; const TInt KSmallTimeOut = 3*1000*1000; // >> AdviceSystemStatus(0) TESTL(iProxy->WaitForResponse(KAdviceSystemStatusTimeout) == ENetMsgGetCurrentCapabilitiesResponse); CLbsNetworkProtocolBase::TLbsSystemStatus status; TInt cleanupCnt; cleanupCnt = iProxy->GetArgsLC(ENetMsgGetCurrentCapabilitiesResponse, &status); TESTL(status == CLbsNetworkProtocolBase::ESystemStatusNone); CleanupStack::PopAndDestroy(cleanupCnt); //Initiate X3P start // TransmitPosition() _LIT(KThirdParty,"+4407463842101"); const TInt KPriority= 6; TLbsTransmitPositionOptions options(TTimeIntervalMicroSeconds(50*1000*1000)); TRequestStatus refPosStatus=KRequestPending; TRequestStatus transPosStatus=KRequestPending; TPositionInfo refPosInfo; TPositionInfo transPosInfo; iTransmitter.SetTransmitOptions(options); iTransmitter.TransmitPosition(KThirdParty, KPriority, refPosStatus, refPosInfo, transPosStatus, transPosInfo); // RequestTransmitLocation() TESTL(iProxy->WaitForResponse(KTimeOut) == ENetMsgRequestTransmitLocation); TBufC16<14> thirdParty(KThirdParty); TPtr16 ptr = thirdParty.Des(); HBufC16* getThirdParty = NULL; TLbsNetSessionId* getSessionId = NULL; TInt getPriority(0); cleanupCnt = iProxy->GetArgsLC(ENetMsgRequestTransmitLocation, &getSessionId, &getThirdParty, &getPriority); TESTL(ptr.Compare(*getThirdParty)==KErrNone); TESTL(getPriority == KPriority); iSessionId = *getSessionId; //session ID is initialised by LBS CleanupStack::PopAndDestroy(cleanupCnt); // ProcessStatusUpdate() MLbsNetworkProtocolObserver::TLbsNetProtocolService service = MLbsNetworkProtocolObserver::EServiceTransmitThirdParty; iProxy->CallL(ENetMsgProcessStatusUpdate, &service); //End Initiate //Reference Position Notification Start // ProcessLocationUpdate() refPosInfo = ArgUtils::ReferencePositionInfo(); iProxy->CallL(ENetMsgProcessLocationUpdate, &iSessionId, &refPosInfo); //Reference Position Notification End //Assistance Data Notification Start // ProcessAssistanceData() TLbsAsistanceDataGroup dataRequestMask = EAssistanceDataReferenceTime; RLbsAssistanceDataBuilderSet assistanceData; ArgUtils::PopulateLC(assistanceData); TInt reason = KErrNone; iProxy->CallL(ENetMsgProcessAssistanceData, &dataRequestMask, &assistanceData, &reason); CleanupStack::PopAndDestroy(1); //assistanceData // Assistance Data Notification End // Network Location Request Start // ProcessLocationRequest() const TBool emergency(EFalse); TLbsNetPosRequestQuality quality = ArgUtils::QualityAlpha2(); TLbsNetPosRequestMethod method = ArgUtils::RequestHybridMethod(); iProxy->CallL(ENetMsgProcessLocationRequest, &iSessionId, &emergency, &service, &quality, &method); // Network Location Request Stop //Start the timer TTime timerStart; timerStart.HomeTime(); // RequestAssistanceData(0) TESTL(iProxy->WaitForResponse(KSmallTimeOut) == ENetMsgRequestAssistanceData); TLbsAsistanceDataGroup dataGroup; cleanupCnt = iProxy->GetArgsLC(ENetMsgRequestAssistanceData, &dataGroup); TESTL(dataGroup == EAssistanceDataNone); CleanupStack::PopAndDestroy(cleanupCnt); // now wait for either to complete - but we will expect only the asynchrous request // waiting for the REF position to complete with KErrNone User::WaitForRequest(refPosStatus, transPosStatus); TESTL(refPosStatus==KErrNone); TESTL(transPosStatus.Int() == KRequestPending); //Find the time elapsed from timer TTimeIntervalMicroSeconds microseconds; TTime timerStop; timerStop.HomeTime(); microseconds = timerStop.MicroSecondsFrom(timerStart); TInt64 timeElapsed = microseconds.Int64(); /*** NRH's Alpha2 timer expires. We enter Hybrid mode.***/ //Test that we do not get response before alpha2 has expired TESTL(iProxy->WaitForResponse(KAlpha2Timeout-timeElapsed-KDelta) == ENetMsgTimeoutExpired); TESTL(iProxy->WaitForResponse(2*KDelta) == ENetMsgRespondLocationRequest); getSessionId = NULL; TInt getReason = KErrNone; TPositionSatelliteInfo* getPositionInfo = NULL; cleanupCnt = iProxy->GetArgsLC(ENetMsgRespondLocationRequest, &getSessionId, &getReason, &getPositionInfo); TESTL(getSessionId->SessionNum() == iSessionId.SessionNum()); TESTL(getReason==KErrNone); CleanupStack::PopAndDestroy(cleanupCnt); // no need for looping, we assume that the next update location from GPS will give accurate fix quality = ArgUtils::Quality(); iProxy->CallL(ENetMsgProcessLocationRequest, &iSessionId, &emergency, &service, &quality, &method); // RequestAssistanceData(0) TESTL(iProxy->WaitForResponse(KSmallTimeOut) == ENetMsgRequestAssistanceData); cleanupCnt = iProxy->GetArgsLC(ENetMsgRequestAssistanceData, &dataGroup); TESTL(dataGroup == EAssistanceDataNone); CleanupStack::PopAndDestroy(cleanupCnt); // GPS positions meets required accuracy. This is sent immediately to protocol module // The ini file should contain accurate gps fix for this test case to work TESTL(iProxy->WaitForResponse(KTTimeout) == ENetMsgRespondLocationRequest); getSessionId = NULL; getReason = KErrNone; getPositionInfo = NULL; cleanupCnt = iProxy->GetArgsLC(ENetMsgRespondLocationRequest, &getSessionId, &getReason, &getPositionInfo); TESTL(getSessionId->SessionNum() == iSessionId.SessionNum()); TESTL(getReason == KErrNone); // Test position is the same as in the ini file data fed to the GPS module // $update,1,2,51.5015,-0.105,50,2,3* TPosition gpsPos; getPositionInfo->GetPosition(gpsPos); TESTL(gpsPos.Latitude()==51.5015 && gpsPos.Longitude()==-0.105 && gpsPos.Altitude()==50 && gpsPos.HorizontalAccuracy()==2 && gpsPos.VerticalAccuracy()==3); CleanupStack::PopAndDestroy(cleanupCnt); // Network Result Notification Start // ProcessLocationUpdate() //Final Network Position is the GPS position TPositionInfo gpsPosInfo; gpsPosInfo.SetPosition(gpsPos); gpsPosInfo.SetUpdateType(EPositionUpdateGeneral); gpsPosInfo.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted); gpsPosInfo.SetPositionModeReason(EPositionModeReasonNone); iProxy->CallL(ENetMsgProcessLocationUpdate, &iSessionId, &gpsPosInfo); // Network Result Notification Stop // Session Complete Start reason = KErrNone; iProxy->CallL(ENetMsgProcessSessionComplete, &iSessionId, &reason); MLbsNetworkProtocolObserver::TLbsNetProtocolServiceMask activeServiceMask = MLbsNetworkProtocolObserver::EServiceNone; iProxy->CallL(ENetMsgProcessStatusUpdate, &activeServiceMask); // Session Complete Stop // the REF position request has completed, so now, after injecting the FNP and Session Complete // we expect that the other request to complete with KErrNone User::WaitForRequest(transPosStatus); TESTL(transPosStatus==KErrNone); return TestStepResult(); }