src/location/qgeosatelliteinfosource_s60.cpp
changeset 0 876b1a06bc25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/location/qgeosatelliteinfosource_s60.cpp	Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,647 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QObject>
+#include <QDateTime>
+#include <limits.h>
+#include "qgeopositioninfosource_s60_p.h"
+#include "qgeosatelliteinfosource_s60_p.h"
+#include "qgeosatelliteinfosource.h"
+#include "qgeosatelliteinfo.h"
+
+#include <QList>
+
+QTM_BEGIN_NAMESPACE
+
+// constructor
+CQGeoSatelliteInfoSourceS60::CQGeoSatelliteInfoSourceS60(QObject* aParent) : QGeoSatelliteInfoSource(aParent),
+        mCurrentModuleId(TUid::Null()),
+        mReqModuleId(TUid::Null()),
+        mDevStatusUpdateAO(NULL),
+        mReqUpdateAO(NULL),
+        mRegUpdateAO(NULL),
+        mListSize(0),
+        mStartUpdates(FALSE),
+        mModuleFlags(0)
+{
+    memset(mList, 0 , MAX_SIZE * sizeof(CSatMethodInfo));
+}
+
+// destructor
+CQGeoSatelliteInfoSourceS60::~CQGeoSatelliteInfoSourceS60()
+{
+    if (mReqUpdateAO)
+        delete mReqUpdateAO;
+
+    if (mRegUpdateAO)
+        delete mRegUpdateAO;
+
+    if (mDevStatusUpdateAO)
+        delete mDevStatusUpdateAO;
+}
+
+// static function NewLC
+CQGeoSatelliteInfoSourceS60* CQGeoSatelliteInfoSourceS60::NewLC(QObject* aParent)
+{
+    CQGeoSatelliteInfoSourceS60* self =
+        new(ELeave) CQGeoSatelliteInfoSourceS60(aParent);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+}
+
+// static function NewL
+CQGeoSatelliteInfoSourceS60* CQGeoSatelliteInfoSourceS60::NewL(QObject * aParent)
+{
+    CQGeoSatelliteInfoSourceS60* self = CQGeoSatelliteInfoSourceS60::NewLC(aParent);
+    CleanupStack::Pop();
+
+    //check if the second phase construction is successful
+    if (!self->isValid()) {
+        delete self;
+        self = NULL;
+    }
+
+    return self;
+}
+
+// 2nd phase constructor
+void CQGeoSatelliteInfoSourceS60::ConstructL()
+{
+    TInt error = mPositionServer.Connect();
+
+    if (error == KErrNone) {
+        CleanupClosePushL(mPositionServer);
+
+        mDevStatusUpdateAO = CQMLBackendAO::NewL(this, DeviceStatus);
+
+        if (mDevStatusUpdateAO == NULL) {
+            CleanupStack::Pop(1);
+
+            return;
+        }
+
+        //update the list array with the available method initially
+        updateDeviceStatus();
+
+        CleanupStack::PushL(mDevStatusUpdateAO);
+
+        /*
+        if(mCurrentModuleId != TUid::Null())
+            mRegUpdateAO = CQMLBackendAOSatellite::NewL(this,RegularUpdate,mCurrentModuleId);
+        */
+        TUint8 bits;
+        TInt index = -1;
+
+        CQMLBackendAO *temp = NULL;
+
+        bits = mModuleFlags;
+
+        do {
+            //error = Get the index of the positioning module based on
+            //priority position module providing the satellite fix
+            index = getIndexPositionModule(bits);
+
+            if (index >= 0) {
+                TRAPD(ret, temp = CQMLBackendAO::NewL(this, RegularUpdate,
+                                                      mList[index].mUid));
+
+                if ((ret == KErrNone) && (temp != NULL))
+                    break;
+
+                bits = bits & (0XFF ^(1 << index));
+            }
+        } while (index >= 0);
+
+        if (index >= 0) {
+            mRegUpdateAO = temp;
+            mRegUpdateAO->setUpdateInterval(0);
+            mCurrentModuleId = mList[index].mUid;
+        } else {
+            delete temp;
+        }
+
+        CleanupStack::Pop(2);
+    }
+
+}
+
+//private function : to retrieve the index of the supplied module id from the mList array
+TInt CQGeoSatelliteInfoSourceS60::checkModule(TPositionModuleId aId)const
+{
+    TInt i;
+    for (i = 0; i < mListSize; i++)
+        if (mList[i].mUid == aId)
+            return i;
+    return -1;
+}
+
+//
+int CQGeoSatelliteInfoSourceS60::minimumUpdateInterval() const
+{
+    if (mCurrentModuleId == TUid::Null())
+        return 0;
+
+    TInt i = checkModule(mCurrentModuleId);
+    if (i != -1)
+        return mList[i].mTimeToNextFix.Int64() / 1000;           //divide by 1000, to convert microsecond to milisecond
+    return 0;
+}
+
+//private function : get the index of the mList that supports the preferred method if
+//available,else returns the index of the default module
+TInt CQGeoSatelliteInfoSourceS60::getIndexPositionModule(TUint8 aBits) const
+{
+    TInt index;
+
+    TPositionModuleId modID = TUid::Null();
+
+    //index = -1 : no methods available in the mList that supports preferred methods
+    index = -1;
+
+    for (TInt i = 0; i < mListSize ; i++) {
+        //check the module properties to select the preferred method,search should not
+        //not select an unavailable method,error device or index matching aLastIndex
+        if ((mList[i].mIsAvailable)
+                && (mList[i].mStatus != TPositionModuleStatus::EDeviceUnknown)
+                && (mList[i].mStatus != TPositionModuleStatus::EDeviceError)
+                && (((aBits >> i) & 1))) {
+            return i;
+        }
+    }
+
+    return index;
+}
+
+//private function : to get the index of the positioning method with time to first fix
+//lesser than timeout
+TInt CQGeoSatelliteInfoSourceS60::getMoreAccurateMethod(TInt aTimeout, TUint8 aBits)
+{
+    TInt index = -1;
+    double temp = -1.0;
+
+    TTimeIntervalMicroSeconds microSeconds;
+
+    //convert the timeout --> micro seconds
+    microSeconds = aTimeout * 1000;
+
+    if (microSeconds == 0)
+        microSeconds = INT_MAX;
+
+    for (TInt i = 0 ; i < mListSize; i++) {
+        if (mList[i].mIsAvailable
+                && (mList[i].mStatus != TPositionModuleStatus::EDeviceUnknown)
+                && (mList[i].mStatus != TPositionModuleStatus::EDeviceError)
+                && (((aBits >> i) & 1))
+                && (mList[i].mTimeToFirstFix < microSeconds)) {
+            if ((temp == -1.0) || (mList[i].mHorizontalAccuracy < temp)) {
+                index = i;
+                temp = mList[i].mHorizontalAccuracy;
+            }
+        }
+    }
+
+    if (index != -1)
+        return index;
+
+    bool minSet = false;
+    microSeconds = 0;
+
+    for (TInt i = 0 ; i < mListSize; i++) {
+        if (mList[i].mIsAvailable
+                && (mList[i].mStatus != TPositionModuleStatus::EDeviceUnknown)
+                && (mList[i].mStatus != TPositionModuleStatus::EDeviceError)
+                && (((aBits >> i) & 1))) {
+            if (!minSet || (mList[i].mTimeToFirstFix < microSeconds)) {
+                index = i;
+                minSet = true;
+                microSeconds = mList[i].mTimeToFirstFix;
+            }
+        }
+    }
+
+    return index;
+}
+
+//private function : to update the mList array
+void CQGeoSatelliteInfoSourceS60::updateStatus(TPositionModuleInfo aModInfo, TInt aStatus)
+{
+
+    TInt i, index;
+    TPositionModuleId id;
+    TBool available;
+    TReal32 accuracy;
+    TTimeIntervalMicroSeconds time_to_first_fix, time_to_next_fix;
+    TPositionQuality quality;
+    CQMLBackendAO *temp = NULL;
+
+    //query for the following parameters
+    id = aModInfo.ModuleId();
+
+    //gets the device availability based on the user settings
+    available = aModInfo.IsAvailable();
+
+    //quality : holds the required metrics
+    aModInfo.GetPositionQuality(quality);
+
+    //Accuracy
+    accuracy = quality.HorizontalAccuracy();
+
+    //time taken for the first fix
+    time_to_first_fix = quality.TimeToFirstFix();
+
+    //time taken for the subsequent fix
+    time_to_next_fix = quality.TimeToNextFix();
+
+    if ((i = checkModule(id)) == -1) {
+        //update the properties of the module
+
+        //TPositionModuleId of the module
+        mList[mListSize].mUid = id;
+
+        //status of the device
+        mList[mListSize].mStatus = aStatus;
+
+        //availablility of the module
+        mList[mListSize].mIsAvailable = available;
+
+        //horizontal accuracy of the module
+        mList[mListSize].mHorizontalAccuracy = accuracy;
+
+        //time required to get the first fix
+        mList[mListSize].mTimeToFirstFix = time_to_first_fix;
+
+        //time required for subsequent fix
+        mList[mListSize].mTimeToNextFix = time_to_next_fix;
+
+        //count on the mList array size
+        mListSize++;
+    } else {
+        //module's status has changed
+        if (mList[i].mStatus != aStatus)
+            mList[i].mStatus = aStatus;
+
+        //module's availability has changed
+        if (mList[i].mIsAvailable != available)
+            mList[i].mIsAvailable = available;
+
+        //module's horizontal accuracy has changed
+        if (mList[i].mHorizontalAccuracy != accuracy)
+            mList[i].mHorizontalAccuracy = accuracy;
+
+        //module's time to first fix has changed
+        if (mList[i].mTimeToFirstFix != time_to_first_fix)
+            mList[i].mTimeToFirstFix = time_to_first_fix;
+
+        //module's time to subsequent fix has changed
+        if (mList[i].mTimeToNextFix != time_to_next_fix)
+            mList[i].mTimeToFirstFix = time_to_next_fix;
+
+        //if the mCurrentModuleId is NULL, try updating the reg update with the available
+        //positioning method
+        if (mCurrentModuleId == TUid::Null() && (available == TRUE) &&
+                (aStatus != TPositionModuleStatus::EDeviceUnknown) &&
+                (aStatus != TPositionModuleStatus::EDeviceError)) {
+            TInt interval = 0;
+
+            TRAPD(ret, temp = CQMLBackendAO::NewL(this, RegularUpdate,
+                                                  mList[i].mUid));
+
+            if ((ret == KErrNone) && (temp != NULL)) {
+                temp->setUpdateInterval(interval);
+
+                if  (mRegUpdateAO)
+                    delete mRegUpdateAO;
+                mRegUpdateAO = temp;
+
+                //to be uncommented when startUpdates are done
+
+                if (mStartUpdates)
+                    mRegUpdateAO->startUpdates();
+
+
+                mCurrentModuleId = mList[i].mUid;
+
+            }
+        }
+
+        //check if the status of the currently used modules for regular update or
+        //request update has changed
+        if (((id == mCurrentModuleId) || (id == mReqModuleId)) &&
+                ((aStatus == TPositionModuleStatus::EDeviceUnknown) ||
+                 (aStatus == TPositionModuleStatus::EDeviceError) ||
+                 (available == FALSE))) {
+            //if the change happened for regular update
+            if (id == mCurrentModuleId) {
+                TInt interval = 0;
+
+                TUint8 bits;
+
+                if (mRegUpdateAO)
+                    delete  mRegUpdateAO;
+
+                bits = mModuleFlags;
+
+                do {
+                    //error = Get the index of the positioning module based on
+                    //priority position module providing the satellite fix
+                    index = getIndexPositionModule(bits);
+
+                    if (index >= 0) {
+                        TRAPD(ret, temp = CQMLBackendAO::NewL(this, RegularUpdate,
+                                                              mList[index].mUid));
+
+                        if ((ret == KErrNone) && (temp != NULL))
+                            break;
+
+                        bits = bits & (0XFF ^(1 << index));
+                    }
+                } while (index >= 0);
+
+
+                if (temp != NULL) {
+                    //successful in creating the subsession for the required
+                    //method
+                    mRegUpdateAO = temp;
+
+                    mRegUpdateAO->setUpdateInterval(interval);
+
+                    if (mStartUpdates)
+                        mRegUpdateAO->startUpdates();
+
+
+                    mCurrentModuleId = mList[index].mUid;
+
+                } else {
+                    //no methods available,clean up the resources
+                    mRegUpdateAO = NULL;
+                    mCurrentModuleId = TUid::Null();
+                }
+
+            }
+
+            //check if device status of the request update module changed
+            if (id == mReqModuleId) {
+                if (mRegUpdateAO)
+                    delete mReqUpdateAO;
+                mReqUpdateAO = NULL;
+                mReqModuleId = TUid::Null();
+                emit requestTimeout();
+            }
+
+        }
+
+    }   //end else
+
+}
+
+
+// Notification methods from active object. Notifies device status changes
+void CQGeoSatelliteInfoSourceS60::updateDeviceStatus(void)
+{
+    TPositionModuleStatus moduleStatus;
+    TPositionModuleInfo moduleInfo;
+
+    //mListSize = 0 : called updateDeviceStatus() first time to initialise the array
+    if (mListSize == 0) {
+        TUint modCount;
+
+        //count on the modules currently supported by the device
+        mPositionServer.GetNumModules(modCount);
+
+        for (TUint i = 0; i < modCount; i++) {
+            //get module information
+            mPositionServer.GetModuleInfoByIndex(i, moduleInfo);
+
+            if (moduleInfo.Capabilities() & TPositionModuleInfo::ECapabilitySatellite) {
+                //get module status
+                mPositionServer.GetModuleStatus(moduleStatus, moduleInfo.ModuleId());
+
+                //update the properties of the module in the mList array
+                updateStatus(moduleInfo, moduleStatus.DeviceStatus());
+
+                mModuleFlags |= (1 << i);
+            }
+        }
+    } else {
+        //UpdateDeviceStatus() called afetr registering for NotifyModuleStatusEvent
+
+        //get the module id from the status event
+        TPositionModuleId id = mStatusEvent.ModuleId();
+
+        //get module information
+        mPositionServer.GetModuleInfoById(id, moduleInfo);
+
+        if (moduleInfo.Capabilities() & TPositionModuleInfo::ECapabilitySatellite) {
+            //get current status of the module
+            mStatusEvent.GetModuleStatus(moduleStatus);
+
+            //update the properties of the module in the mList array
+            updateStatus(moduleInfo, moduleStatus.DeviceStatus());
+        }
+
+    }
+
+    //register for next NotifyModuleStatusEvent
+    mDevStatusUpdateAO->notifyDeviceStatus(mStatusEvent);
+
+}
+
+//
+void CQGeoSatelliteInfoSourceS60::TPositionSatelliteInfo2QGeoSatelliteInfo(
+    TPositionSatelliteInfo  aSatInfo, QList<QGeoSatelliteInfo> &qListSatInView,
+    QList<QGeoSatelliteInfo> &qListSatInUse)
+{
+    TInt satInView = aSatInfo.NumSatellitesInView();
+    TSatelliteData satData;
+    QGeoSatelliteInfo qInfo;
+
+    for (TInt i = 0; i < satInView; i++) {
+        aSatInfo.GetSatelliteData(i, satData);
+        qInfo.setSignalStrength(satData.SignalStrength());
+        qInfo.setPrnNumber(satData.SatelliteId());
+        qInfo.setAttribute(QGeoSatelliteInfo::Elevation, satData.Elevation());
+        qInfo.setAttribute(QGeoSatelliteInfo::Azimuth, satData.Azimuth());
+        if (satData.IsUsed() == TRUE) {
+            qListSatInUse.append(qInfo);
+        }
+        qListSatInView.append(qInfo);
+    }
+}
+//
+void CQGeoSatelliteInfoSourceS60::updatePosition(TPositionSatelliteInfo aSatInfo,
+        int aError, bool isStartUpdate)
+{
+    QList<QGeoSatelliteInfo> qListSatInUse;
+    QList<QGeoSatelliteInfo> qListSatInView;
+    if (aError == KErrNone) {
+        //fill posUpdate
+        TPositionSatelliteInfo2QGeoSatelliteInfo(aSatInfo, qListSatInView,
+                qListSatInUse);
+        if ((receivers(SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo>&))) > 0)) {
+            if ((isStartUpdate == FALSE) || (mqListSatInView != qListSatInView)) {
+                emit satellitesInViewUpdated(qListSatInView);
+                mqListSatInView = qListSatInView;
+            }
+        }
+
+        if ((receivers(SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo>&))) > 0)) {
+            if ((isStartUpdate == FALSE) || (mqListSatInUse != qListSatInUse)) {
+                emit satellitesInUseUpdated(qListSatInUse);
+                mqListSatInUse = qListSatInUse;
+            }
+        }
+    }
+
+    else if (aError == KErrTimedOut) {
+        //request has timed out
+        emit requestTimeout();
+    }
+}
+
+// for request update
+void CQGeoSatelliteInfoSourceS60::requestUpdate(int aTimeout)
+{
+    TInt index = -1;
+    TUint8 bits;
+
+    CQMLBackendAO *temp = NULL;
+
+    //requestupdate
+    //return if already a request update is pending
+    if (mReqUpdateAO && mReqUpdateAO->isRequestPending())
+        return;
+
+    if (aTimeout < 0) {
+        emit requestTimeout();
+        return;
+    }
+
+    bits = mModuleFlags;
+
+    do  {
+
+        //index of the more accurate method in the array
+        index = getMoreAccurateMethod(aTimeout, bits);
+
+        //no positioning method method available : emit requestTimeout
+        if (index < 0) {
+            emit requestTimeout();
+            break;
+        }
+        //if the selected module for request update is same as the previous one reuse the request
+        if (mList[index].mUid == mReqModuleId) {
+            mReqUpdateAO->requestUpdate(aTimeout);
+            return;
+        }
+
+        TRAPD(ret, temp = CQMLBackendAO::NewL(this, OnceUpdate, mList[index].mUid));
+
+        if ((ret == KErrNone) && (temp != NULL)) {
+            //delete the old reqest update
+            if (mReqUpdateAO)
+                delete mReqUpdateAO;
+
+            //set the requestAO to the newly created AO
+            mReqUpdateAO = temp;
+
+            //set the request module ID
+            mReqModuleId = mList[index].mUid;
+
+            //start the update
+            mReqUpdateAO->requestUpdate(aTimeout);
+
+            return;
+        }
+
+        bits = bits & (0XFF ^(1 << index));
+
+    } while (index >= 0);
+
+    //cleanup resources if the invalid requpdate is still stored
+    if (mReqUpdateAO) {
+        delete mReqUpdateAO;
+        mReqUpdateAO = NULL;
+        mReqModuleId = TUid::Null();
+    }
+
+}
+
+// starts the regular updates
+void CQGeoSatelliteInfoSourceS60::startUpdates()
+{
+    if (mRegUpdateAO && ((receivers(SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo>&))) > 0) ||
+                         (receivers(SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo>&))) > 0)))
+        mRegUpdateAO->startUpdates();
+
+    mStartUpdates = true;
+}
+
+// stops the regular updates
+void CQGeoSatelliteInfoSourceS60::stopUpdates()
+{
+    mStartUpdates = false;
+    if (mReqUpdateAO)
+        mRegUpdateAO->cancelUpdate();
+}
+
+
+void CQGeoSatelliteInfoSourceS60::connectNotify(const char *aSignal)
+{
+    // start update if it already connected
+    if (mStartUpdates && mRegUpdateAO && ((QLatin1String(aSignal) == SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo>&))) ||
+                                          (QLatin1String(aSignal) == SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo>&)))))
+        mRegUpdateAO->startUpdates();
+
+}
+
+void CQGeoSatelliteInfoSourceS60::disconnectNotify(const char *aSignal)
+{
+    // Cancel updates if slot is disconnected for the positionUpdate() signal.
+
+    if ((mRegUpdateAO) && (QLatin1String(aSignal) == SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo>&))) && (receivers(SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo>&))) == 0) &&
+            (QLatin1String(aSignal) == SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo>&))) && (receivers(SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo>&))) == 0))
+        mRegUpdateAO->cancelUpdate();
+
+}
+
+QTM_END_NAMESPACE
+