D:\UNI\proggen\qt\qt-mobility-opensource-src-1.2.0\src\location\qnmeapositioninfosource.cpp D:\UNI\proggen\qt\qt-mobility-opensource-src-1.2.0_sec\src\location\qnmeapositioninfosource.cpp
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved. ** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com) ** Contact: Nokia Corporation (qt-info@nokia.com)
** **
** This file is part of the Qt Mobility Components. ** This file is part of the Qt Mobility Components.
** **
** $QT_BEGIN_LICENSE:LGPL$ ** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage ** No Commercial Usage
** This file contains pre-release code and may not be distributed. ** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions ** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying ** contained in the Technology Preview License Agreement accompanying
** this package. ** this package.
** **
** GNU Lesser General Public License Usage ** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser ** 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 ** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the ** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to ** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements ** 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. ** 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 ** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception ** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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 ** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com. ** Nokia at qt-info@nokia.com.
** **
** **
** **
** **
** **
** **
** **
** **
** $QT_END_LICENSE$ ** $QT_END_LICENSE$
** **
****************************************************************************/  ****************************************************************************/ 
#include "qnmeapositioninfosource_p.h" #include "qnmeapositioninfosource_p.h"
#include "qlocationutils_p.h" #include "qlocationutils_p.h"
   
#include <QIODevice> #include <QIODevice>
#include <QBasicTimer> #include <QBasicTimer>
#include <QTimerEvent> #include <QTimerEvent>
#include <QTimer> #include <QTimer>
#include <QString>    
#include <QRegExp>    
#include <QStringList>    
   
   
   
QTM_BEGIN_NAMESPACE QTM_BEGIN_NAMESPACE
   
QNmeaRealTimeReader::QNmeaRealTimeReader(QNmeaPositionInfoSourcePrivate *sourcePrivate) QNmeaRealTimeReader::QNmeaRealTimeReader(QNmeaPositionInfoSourcePrivate *sourcePrivate)
       : QNmeaReader(sourcePrivate)        : QNmeaReader(sourcePrivate)
{ {
} }
   
void QNmeaRealTimeReader::readAvailableData() void QNmeaRealTimeReader::readAvailableData()
{ {
   QGeoPositionInfo update;    QGeoPositionInfo update;
   bool hasFix = false;    bool hasFix = false;
   
   char buf[1024];    char buf[1024];
   qint64 size = m_proxy->m_device->read(buf, sizeof(buf));    qint64 size = m_proxy->m_device->readLine(buf, sizeof(buf));
     while (size > 0) {  
   //Parse NMEA-Informations         if (m_proxy->parsePosInfoFromNmeaData(buf, size, &update, &hasFix)) 
   QRegExp rx("(\\$.*\\*.{2})");    
   rx.setMinimal(true);    
   QStringList list;    
   int pos = 0;    
   
   while ((pos = rx.indexIn(QString(buf), pos)) != -1) {    
       list << rx.cap(1);    
       pos += rx.matchedLength();    
   }    
   
   foreach (QString str, list) {    
       //Convert QString to valid char*    
       char * data_part;    
       std::string strnm = str.toStdString();    
       data_part = new char [strnm.size()+1];    
       strcpy( data_part, strnm.c_str() );    
   
       size = strnm.size();    
       //Analyse information    
       if (m_proxy->parsePosInfoFromNmeaData(data_part, size, &update, &hasFix))    
           m_proxy->notifyNewUpdate(&update, hasFix);            m_proxy->notifyNewUpdate(&update, hasFix);
       delete data_part;         memset(buf, 0, size); 
         size = m_proxy->m_device->readLine(buf, sizeof(buf));  
   }    }
   memset(buf, 0, size);    
} }
   
   
//============================================================ //============================================================
   
QNmeaSimulatedReader::QNmeaSimulatedReader(QNmeaPositionInfoSourcePrivate *sourcePrivate) QNmeaSimulatedReader::QNmeaSimulatedReader(QNmeaPositionInfoSourcePrivate *sourcePrivate)
       : QNmeaReader(sourcePrivate),        : QNmeaReader(sourcePrivate),
       m_currTimerId(-1),        m_currTimerId(-1),
       m_hasValidDateTime(false)        m_hasValidDateTime(false)
{ {
} }
   
QNmeaSimulatedReader::~QNmeaSimulatedReader() QNmeaSimulatedReader::~QNmeaSimulatedReader()
{ {
   if (m_currTimerId > 0)    if (m_currTimerId > 0)
       killTimer(m_currTimerId);        killTimer(m_currTimerId);
} }
   
void QNmeaSimulatedReader::readAvailableData() void QNmeaSimulatedReader::readAvailableData()
{ {
   if (m_currTimerId > 0)     // we are already reading    if (m_currTimerId > 0)     // we are already reading
       return;        return;
   
   if (!m_hasValidDateTime) {      // first update    if (!m_hasValidDateTime) {      // first update
       Q_ASSERT(m_proxy->m_device && (m_proxy->m_device->openMode() & QIODevice::ReadOnly));        Q_ASSERT(m_proxy->m_device && (m_proxy->m_device->openMode() & QIODevice::ReadOnly));
   
       if (!setFirstDateTime()) {        if (!setFirstDateTime()) {
           //m_proxy->notifyReachedEndOfFile();            //m_proxy->notifyReachedEndOfFile();
           qWarning("QNmeaPositionInfoSource: cannot find NMEA sentence with valid date & time");            qWarning("QNmeaPositionInfoSource: cannot find NMEA sentence with valid date & time");
           return;            return;
       }        }
   
       m_hasValidDateTime = true;        m_hasValidDateTime = true;
       simulatePendingUpdate();        simulatePendingUpdate();
   
   } else {    } else {
       // previously read to EOF, but now new data has arrived        // previously read to EOF, but now new data has arrived
       processNextSentence();        processNextSentence();
   }    }
} }
   
bool QNmeaSimulatedReader::setFirstDateTime() bool QNmeaSimulatedReader::setFirstDateTime()
{ {
   // find the first update with valid date and time    // find the first update with valid date and time
   QGeoPositionInfo update;    QGeoPositionInfo update;
   bool hasFix = false;    bool hasFix = false;
   while (m_proxy->m_device->bytesAvailable() > 0) {    while (m_proxy->m_device->bytesAvailable() > 0) {
       char buf[1024];        char buf[1024];
       qint64 size = m_proxy->m_device->readLine(buf, sizeof(buf));        qint64 size = m_proxy->m_device->readLine(buf, sizeof(buf));
       if (size <= 0)        if (size <= 0)
           continue;            continue;
       bool ok = m_proxy->parsePosInfoFromNmeaData(buf, size, &update, &hasFix);        bool ok = m_proxy->parsePosInfoFromNmeaData(buf, size, &update, &hasFix);
       if (ok && update.timestamp().isValid()) {        if (ok && update.timestamp().isValid()) {
           QPendingGeoPositionInfo pending;            QPendingGeoPositionInfo pending;
           pending.info = update;            pending.info = update;
           pending.hasFix = hasFix;            pending.hasFix = hasFix;
           m_pendingUpdates.enqueue(pending);            m_pendingUpdates.enqueue(pending);
           return true;            return true;
       }        }
   }    }
   return false;    return false;
} }
   
void QNmeaSimulatedReader::simulatePendingUpdate() void QNmeaSimulatedReader::simulatePendingUpdate()
{ {
   if (m_pendingUpdates.size() > 0) {    if (m_pendingUpdates.size() > 0) {
       // will be dequeued in processNextSentence()        // will be dequeued in processNextSentence()
       QPendingGeoPositionInfo &pending = m_pendingUpdates.head();        QPendingGeoPositionInfo &pending = m_pendingUpdates.head();
       if (pending.info.coordinate().type() != QGeoCoordinate::InvalidCoordinate)        if (pending.info.coordinate().type() != QGeoCoordinate::InvalidCoordinate)
           m_proxy->notifyNewUpdate(&pending.info, pending.hasFix);            m_proxy->notifyNewUpdate(&pending.info, pending.hasFix);
   }    }
   
   processNextSentence();    processNextSentence();
} }
   
void QNmeaSimulatedReader::timerEvent(QTimerEvent *event) void QNmeaSimulatedReader::timerEvent(QTimerEvent *event)
{ {
   killTimer(event->timerId());    killTimer(event->timerId());
   m_currTimerId = -1;    m_currTimerId = -1;
   simulatePendingUpdate();    simulatePendingUpdate();
} }
   
void QNmeaSimulatedReader::processNextSentence() void QNmeaSimulatedReader::processNextSentence()
{ {
   QGeoPositionInfo info;    QGeoPositionInfo info;
   bool hasFix = false;    bool hasFix = false;
   int timeToNextUpdate = -1;    int timeToNextUpdate = -1;
   QTime prevTime;    QTime prevTime;
   if (m_pendingUpdates.size() > 0)    if (m_pendingUpdates.size() > 0)
       prevTime = m_pendingUpdates.head().info.timestamp().time();        prevTime = m_pendingUpdates.head().info.timestamp().time();
   
   // find the next update with a valid time (as long as the time is valid,    // find the next update with a valid time (as long as the time is valid,
   // we can calculate when the update should be emitted)    // we can calculate when the update should be emitted)
   while (m_proxy->m_device && m_proxy->m_device->bytesAvailable() > 0) {    while (m_proxy->m_device && m_proxy->m_device->bytesAvailable() > 0) {
       char buf[1024];        char buf[1024];
       qint64 size = m_proxy->m_device->readLine(buf, sizeof(buf));        qint64 size = m_proxy->m_device->readLine(buf, sizeof(buf));
       if (size <= 0)        if (size <= 0)
           continue;            continue;
       if (m_proxy->parsePosInfoFromNmeaData(buf, size, &info, &hasFix)) {        if (m_proxy->parsePosInfoFromNmeaData(buf, size, &info, &hasFix)) {
           QTime time = info.timestamp().time();            QTime time = info.timestamp().time();
           if (time.isValid()) {            if (time.isValid()) {
               if (!prevTime.isValid()) {                if (!prevTime.isValid()) {
                   timeToNextUpdate = 0;                    timeToNextUpdate = 0;
                   break;                    break;
               }                }
               timeToNextUpdate = prevTime.msecsTo(time);                timeToNextUpdate = prevTime.msecsTo(time);
               if (timeToNextUpdate >= 0)                if (timeToNextUpdate >= 0)
                   break;                    break;
           }            }
       }        }
   }    }
   
   if (timeToNextUpdate < 0)    if (timeToNextUpdate < 0)
       return;        return;
   
   m_pendingUpdates.dequeue();    m_pendingUpdates.dequeue();
   
   QPendingGeoPositionInfo pending;    QPendingGeoPositionInfo pending;
   pending.info = info;    pending.info = info;
   pending.hasFix = hasFix;    pending.hasFix = hasFix;
   m_pendingUpdates.enqueue(pending);    m_pendingUpdates.enqueue(pending);
   m_currTimerId = startTimer(timeToNextUpdate);    m_currTimerId = startTimer(timeToNextUpdate);
} }
   
   
//============================================================ //============================================================
   
   
QNmeaPositionInfoSourcePrivate::QNmeaPositionInfoSourcePrivate(QNmeaPositionInfoSource *parent) QNmeaPositionInfoSourcePrivate::QNmeaPositionInfoSourcePrivate(QNmeaPositionInfoSource *parent)
       : QObject(parent),        : QObject(parent),
       m_invokedStart(false),        m_invokedStart(false),
       m_source(parent),        m_source(parent),
       m_nmeaReader(0),        m_nmeaReader(0),
       m_updateTimer(0),        m_updateTimer(0),
       m_requestTimer(0),        m_requestTimer(0),
       m_noUpdateLastInterval(false),        m_noUpdateLastInterval(false),
       m_updateTimeoutSent(false),        m_updateTimeoutSent(false),
       m_connectedReadyRead(false)        m_connectedReadyRead(false)
{ {
} }
   
QNmeaPositionInfoSourcePrivate::~QNmeaPositionInfoSourcePrivate() QNmeaPositionInfoSourcePrivate::~QNmeaPositionInfoSourcePrivate()
{ {
   delete m_nmeaReader;    delete m_nmeaReader;
   delete m_updateTimer;    delete m_updateTimer;
} }
   
bool QNmeaPositionInfoSourcePrivate::openSourceDevice() bool QNmeaPositionInfoSourcePrivate::openSourceDevice()
{ {
   if (!m_device) {    if (!m_device) {
       qWarning("QNmeaPositionInfoSource: no QIODevice data source, call setDevice() first");        qWarning("QNmeaPositionInfoSource: no QIODevice data source, call setDevice() first");
       return false;        return false;
   }    }
   
   if (!m_device->isOpen() && !m_device->open(QIODevice::ReadOnly)) {    if (!m_device->isOpen() && !m_device->open(QIODevice::ReadOnly)) {
       qWarning("QNmeaPositionInfoSource: cannot open QIODevice data source");        qWarning("QNmeaPositionInfoSource: cannot open QIODevice data source");
       return false;        return false;
   }    }
   
   connect(m_device, SIGNAL(aboutToClose()), SLOT(sourceDataClosed()));    connect(m_device, SIGNAL(aboutToClose()), SLOT(sourceDataClosed()));
   connect(m_device, SIGNAL(readChannelFinished()), SLOT(sourceDataClosed()));    connect(m_device, SIGNAL(readChannelFinished()), SLOT(sourceDataClosed()));
   connect(m_device, SIGNAL(destroyed()), SLOT(sourceDataClosed()));    connect(m_device, SIGNAL(destroyed()), SLOT(sourceDataClosed()));
   
   return true;    return true;
} }
   
void QNmeaPositionInfoSourcePrivate::sourceDataClosed() void QNmeaPositionInfoSourcePrivate::sourceDataClosed()
{ {
   if (m_nmeaReader && m_device && m_device->bytesAvailable())    if (m_nmeaReader && m_device && m_device->bytesAvailable())
       m_nmeaReader->readAvailableData();        m_nmeaReader->readAvailableData();
} }
   
void QNmeaPositionInfoSourcePrivate::readyRead() void QNmeaPositionInfoSourcePrivate::readyRead()
{ {
   if (m_nmeaReader)    if (m_nmeaReader)
       m_nmeaReader->readAvailableData();        m_nmeaReader->readAvailableData();
} }
   
bool QNmeaPositionInfoSourcePrivate::initialize() bool QNmeaPositionInfoSourcePrivate::initialize()
{ {
   if (m_nmeaReader)    if (m_nmeaReader)
       return true;        return true;
   
   if (!openSourceDevice())    if (!openSourceDevice())
       return false;        return false;
   
   if (m_updateMode == QNmeaPositionInfoSource::RealTimeMode)    if (m_updateMode == QNmeaPositionInfoSource::RealTimeMode)
       m_nmeaReader = new QNmeaRealTimeReader(this);        m_nmeaReader = new QNmeaRealTimeReader(this);
   else    else
       m_nmeaReader = new QNmeaSimulatedReader(this);        m_nmeaReader = new QNmeaSimulatedReader(this);
   
   return true;    return true;
} }
   
void QNmeaPositionInfoSourcePrivate::prepareSourceDevice() void QNmeaPositionInfoSourcePrivate::prepareSourceDevice()
{ {
   // some data may already be available    // some data may already be available
   if (m_updateMode == QNmeaPositionInfoSource::SimulationMode) {    if (m_updateMode == QNmeaPositionInfoSource::SimulationMode) {
       if (m_nmeaReader && m_device->bytesAvailable())        if (m_nmeaReader && m_device->bytesAvailable())
           m_nmeaReader->readAvailableData();            m_nmeaReader->readAvailableData();
   }    }
   
   if (!m_connectedReadyRead) {    if (!m_connectedReadyRead) {
       connect(m_device, SIGNAL(readyRead()), SLOT(readyRead()));        connect(m_device, SIGNAL(readyRead()), SLOT(readyRead()));
       m_connectedReadyRead = true;        m_connectedReadyRead = true;
   }    }
} }
   
bool QNmeaPositionInfoSourcePrivate::parsePosInfoFromNmeaData(const char *data, int size, bool QNmeaPositionInfoSourcePrivate::parsePosInfoFromNmeaData(const char *data, int size,
       QGeoPositionInfo *posInfo, bool *hasFix)        QGeoPositionInfo *posInfo, bool *hasFix)
{ {
   return m_source->parsePosInfoFromNmeaData(data, size, posInfo, hasFix);    return m_source->parsePosInfoFromNmeaData(data, size, posInfo, hasFix);
} }
   
void QNmeaPositionInfoSourcePrivate::startUpdates() void QNmeaPositionInfoSourcePrivate::startUpdates()
{ {
   if (m_invokedStart)    if (m_invokedStart)
       return;        return;
   
   m_invokedStart = true;    m_invokedStart = true;
   m_pendingUpdate = QGeoPositionInfo();    m_pendingUpdate = QGeoPositionInfo();
   m_noUpdateLastInterval = false;    m_noUpdateLastInterval = false;
   
   bool initialized = initialize();    bool initialized = initialize();
   if (!initialized)    if (!initialized)
       return;        return;
   
   if (m_updateMode == QNmeaPositionInfoSource::RealTimeMode) {    if (m_updateMode == QNmeaPositionInfoSource::RealTimeMode) {
       // skip over any buffered data - we only want the newest data        // skip over any buffered data - we only want the newest data
       if (m_device->bytesAvailable()) {        if (m_device->bytesAvailable()) {
           if (m_device->isSequential())            if (m_device->isSequential())
               m_device->readAll();                m_device->readAll();
           else            else
               m_device->seek(m_device->bytesAvailable());                m_device->seek(m_device->bytesAvailable());
       }        }
   }    }
   
   if (m_updateTimer)    if (m_updateTimer)
       m_updateTimer->stop();        m_updateTimer->stop();
   
   if (m_source->updateInterval() > 0) {    if (m_source->updateInterval() > 0) {
       if (!m_updateTimer)        if (!m_updateTimer)
           m_updateTimer = new QBasicTimer;            m_updateTimer = new QBasicTimer;
       m_updateTimer->start(m_source->updateInterval(), this);        m_updateTimer->start(m_source->updateInterval(), this);
   }    }
   
   if (initialized)    if (initialized)
       prepareSourceDevice();        prepareSourceDevice();
} }
   
void QNmeaPositionInfoSourcePrivate::stopUpdates() void QNmeaPositionInfoSourcePrivate::stopUpdates()
{ {
   m_invokedStart = false;    m_invokedStart = false;
   if (m_updateTimer)    if (m_updateTimer)
       m_updateTimer->stop();        m_updateTimer->stop();
   m_pendingUpdate = QGeoPositionInfo();    m_pendingUpdate = QGeoPositionInfo();
   m_noUpdateLastInterval = false;    m_noUpdateLastInterval = false;
} }
   
void QNmeaPositionInfoSourcePrivate::requestUpdate(int msec) void QNmeaPositionInfoSourcePrivate::requestUpdate(int msec)
{ {
   if (m_requestTimer && m_requestTimer->isActive())    if (m_requestTimer && m_requestTimer->isActive())
       return;        return;
   
   if (msec <= 0 || msec < m_source->minimumUpdateInterval()) {    if (msec <= 0 || msec < m_source->minimumUpdateInterval()) {
       emit m_source->updateTimeout();        emit m_source->updateTimeout();
       return;        return;
   }    }
   
   if (!m_requestTimer) {    if (!m_requestTimer) {
       m_requestTimer = new QTimer(this);        m_requestTimer = new QTimer(this);
       connect(m_requestTimer, SIGNAL(timeout()), SLOT(updateRequestTimeout()));        connect(m_requestTimer, SIGNAL(timeout()), SLOT(updateRequestTimeout()));
   }    }
   
   bool initialized = initialize();    bool initialized = initialize();
   if (!initialized) {    if (!initialized) {
       emit m_source->updateTimeout();        emit m_source->updateTimeout();
       return;        return;
   }    }
   
   m_requestTimer->start(msec);    m_requestTimer->start(msec);
   
   if (initialized)    if (initialized)
       prepareSourceDevice();        prepareSourceDevice();
} }
   
void QNmeaPositionInfoSourcePrivate::updateRequestTimeout() void QNmeaPositionInfoSourcePrivate::updateRequestTimeout()
{ {
   m_requestTimer->stop();    m_requestTimer->stop();
   emit m_source->updateTimeout();    emit m_source->updateTimeout();
} }
   
void QNmeaPositionInfoSourcePrivate::notifyNewUpdate(QGeoPositionInfo *update, bool hasFix) void QNmeaPositionInfoSourcePrivate::notifyNewUpdate(QGeoPositionInfo *update, bool hasFix)
{ {
   // include <QDebug> before uncommenting    // include <QDebug> before uncommenting
   //qDebug() << "QNmeaPositionInfoSourcePrivate::notifyNewUpdate()" << update->timestamp() << hasFix << m_invokedStart << (m_requestTimer && m_requestTimer->isActive());    //qDebug() << "QNmeaPositionInfoSourcePrivate::notifyNewUpdate()" << update->timestamp() << hasFix << m_invokedStart << (m_requestTimer && m_requestTimer->isActive());
   
   QDate date = update->timestamp().date();    QDate date = update->timestamp().date();
   if (date.isValid()) {    if (date.isValid()) {
       m_currentDate = date;        m_currentDate = date;
   } else {    } else {
       // some sentence have time but no date        // some sentence have time but no date
       QTime time = update->timestamp().time();        QTime time = update->timestamp().time();
       if (time.isValid() && m_currentDate.isValid())        if (time.isValid() && m_currentDate.isValid())
           update->setTimestamp(QDateTime(m_currentDate, time, Qt::UTC));            update->setTimestamp(QDateTime(m_currentDate, time, Qt::UTC));
   }    }
   
   if (hasFix && update->isValid()) {    if (hasFix && update->isValid()) {
       if (m_requestTimer && m_requestTimer->isActive()) {        if (m_requestTimer && m_requestTimer->isActive()) {
           m_requestTimer->stop();            m_requestTimer->stop();
           emitUpdated(*update);            emitUpdated(*update);
       } else if (m_invokedStart) {        } else if (m_invokedStart) {
           if (m_updateTimer && m_updateTimer->isActive()) {            if (m_updateTimer && m_updateTimer->isActive()) {
               // for periodic updates, only want the most recent update                // for periodic updates, only want the most recent update
               m_pendingUpdate = *update;                m_pendingUpdate = *update;
               if (m_noUpdateLastInterval) {                if (m_noUpdateLastInterval) {
                   emitPendingUpdate();                    emitPendingUpdate();
                   m_noUpdateLastInterval = false;                    m_noUpdateLastInterval = false;
               }                }
           } else {            } else {
               emitUpdated(*update);                emitUpdated(*update);
           }            }
       }        }
       m_lastUpdate = *update;        m_lastUpdate = *update;
   }    }
} }
   
void QNmeaPositionInfoSourcePrivate::timerEvent(QTimerEvent *) void QNmeaPositionInfoSourcePrivate::timerEvent(QTimerEvent *)
{ {
   emitPendingUpdate();    emitPendingUpdate();
} }
   
void QNmeaPositionInfoSourcePrivate::emitPendingUpdate() void QNmeaPositionInfoSourcePrivate::emitPendingUpdate()
{ {
   if (m_pendingUpdate.isValid()) {    if (m_pendingUpdate.isValid()) {
       m_updateTimeoutSent = false;        m_updateTimeoutSent = false;
       m_noUpdateLastInterval = false;        m_noUpdateLastInterval = false;
       emitUpdated(m_pendingUpdate);        emitUpdated(m_pendingUpdate);
       m_pendingUpdate = QGeoPositionInfo();        m_pendingUpdate = QGeoPositionInfo();
   } else {    } else {
       if (m_noUpdateLastInterval && !m_updateTimeoutSent) {        if (m_noUpdateLastInterval && !m_updateTimeoutSent) {
           m_updateTimeoutSent = true;            m_updateTimeoutSent = true;
           m_pendingUpdate = QGeoPositionInfo();            m_pendingUpdate = QGeoPositionInfo();
           emit m_source->updateTimeout();            emit m_source->updateTimeout();
       }        }
       m_noUpdateLastInterval = true;        m_noUpdateLastInterval = true;
   }    }
} }
   
void QNmeaPositionInfoSourcePrivate::emitUpdated(const QGeoPositionInfo &update) void QNmeaPositionInfoSourcePrivate::emitUpdated(const QGeoPositionInfo &update)
{ {
   m_lastUpdate = update;    m_lastUpdate = update;
   emit m_source->positionUpdated(update);    emit m_source->positionUpdated(update);
} }
   
//========================================================= //=========================================================
   
/*! /*!
   \class QNmeaPositionInfoSource    \class QNmeaPositionInfoSource
   \brief The QNmeaPositionInfoSource class provides positional information using a NMEA data source.    \brief The QNmeaPositionInfoSource class provides positional information using a NMEA data source.
   
   \inmodule QtLocation    \inmodule QtLocation
   \since 1.0    \since 1.0
   
   \ingroup location    \ingroup location
   
   NMEA is a commonly used protocol for the specification of one's global    NMEA is a commonly used protocol for the specification of one's global
   position at a certain point in time. The QNmeaPositionInfoSource class reads NMEA    position at a certain point in time. The QNmeaPositionInfoSource class reads NMEA
   data and uses it to provide positional data in the form of    data and uses it to provide positional data in the form of
   QGeoPositionInfo objects.    QGeoPositionInfo objects.
   
   A QNmeaPositionInfoSource instance operates in either \l {RealTimeMode} or    A QNmeaPositionInfoSource instance operates in either \l {RealTimeMode} or
   \l {SimulationMode}. These modes allow NMEA data to be read from either a    \l {SimulationMode}. These modes allow NMEA data to be read from either a
   live source of positional data, or replayed for simulation purposes from    live source of positional data, or replayed for simulation purposes from
   previously recorded NMEA data.    previously recorded NMEA data.
   
   The source of NMEA data is set with setDevice().    The source of NMEA data is set with setDevice().
   
   Use startUpdates() to start receiving regular position updates and stopUpdates() to stop these    Use startUpdates() to start receiving regular position updates and stopUpdates() to stop these
   updates.  If you only require updates occasionally, you can call requestUpdate() to request a    updates.  If you only require updates occasionally, you can call requestUpdate() to request a
   single update.    single update.
   
   In both cases the position information is received via the positionUpdated() signal and the    In both cases the position information is received via the positionUpdated() signal and the
   last known position can be accessed with lastKnownPosition().    last known position can be accessed with lastKnownPosition().
*/  */ 
   
   
/*! /*!
   \enum QNmeaPositionInfoSource::UpdateMode    \enum QNmeaPositionInfoSource::UpdateMode
   Defines the available update modes.    Defines the available update modes.
   
   \value RealTimeMode Positional data is read and distributed from the data source as it becomes available. Use this mode if you are using a live source of positional data (for example, a GPS hardware device).    \value RealTimeMode Positional data is read and distributed from the data source as it becomes available. Use this mode if you are using a live source of positional data (for example, a GPS hardware device).
   \value SimulationMode The data and time information in the NMEA source data is used to provide positional updates at the rate at which the data was originally recorded. Use this mode if the data source contains previously recorded NMEA data and you want to replay the data for simulation purposes.    \value SimulationMode The data and time information in the NMEA source data is used to provide positional updates at the rate at which the data was originally recorded. Use this mode if the data source contains previously recorded NMEA data and you want to replay the data for simulation purposes.
*/  */ 
   
   
/*! /*!
   Constructs a QNmeaPositionInfoSource instance with the given \a parent    Constructs a QNmeaPositionInfoSource instance with the given \a parent
   and \a updateMode.    and \a updateMode.
*/  */ 
QNmeaPositionInfoSource::QNmeaPositionInfoSource(UpdateMode updateMode, QObject *parent) QNmeaPositionInfoSource::QNmeaPositionInfoSource(UpdateMode updateMode, QObject *parent)
       : QGeoPositionInfoSource(parent),        : QGeoPositionInfoSource(parent),
       d(new QNmeaPositionInfoSourcePrivate(this))        d(new QNmeaPositionInfoSourcePrivate(this))
{ {
   d->m_updateMode = updateMode;    d->m_updateMode = updateMode;
   d->m_device = 0;    d->m_device = 0;
} }
   
/*! /*!
   Destroys the position source.    Destroys the position source.
*/  */ 
QNmeaPositionInfoSource::~QNmeaPositionInfoSource() QNmeaPositionInfoSource::~QNmeaPositionInfoSource()
{ {
   delete d;    delete d;
} }
   
/*! /*!
   Parses an NMEA sentence string into a QGeoPositionInfo.    Parses an NMEA sentence string into a QGeoPositionInfo.
   
   The default implementation will parse standard NMEA sentences.    The default implementation will parse standard NMEA sentences.
   This method should be reimplemented in a subclass whenever the need to deal with non-standard    This method should be reimplemented in a subclass whenever the need to deal with non-standard
   NMEA sentences arises.    NMEA sentences arises.
   
   The parser reads \a size bytes from \a data and uses that information to setup \a posInfo and    The parser reads \a size bytes from \a data and uses that information to setup \a posInfo and
   \a hasFix.  If \a hasFix is set to false then \a posInfo may contain only the time or the date    \a hasFix.  If \a hasFix is set to false then \a posInfo may contain only the time or the date
   and the time.    and the time.
   
   Returns true if the sentence was succsesfully parsed, otherwise returns false and should not    Returns true if the sentence was succsesfully parsed, otherwise returns false and should not
   modifiy \a posInfo or \a hasFix.    modifiy \a posInfo or \a hasFix.
*/  */ 
bool QNmeaPositionInfoSource::parsePosInfoFromNmeaData(const char *data, int size, bool QNmeaPositionInfoSource::parsePosInfoFromNmeaData(const char *data, int size,
       QGeoPositionInfo *posInfo, bool *hasFix)        QGeoPositionInfo *posInfo, bool *hasFix)
{ {
   return QLocationUtils::getPosInfoFromNmea(data, size, posInfo, hasFix);    return QLocationUtils::getPosInfoFromNmea(data, size, posInfo, hasFix);
} }
   
/*! /*!
   Returns the update mode.    Returns the update mode.
*/  */ 
QNmeaPositionInfoSource::UpdateMode QNmeaPositionInfoSource::updateMode() const QNmeaPositionInfoSource::UpdateMode QNmeaPositionInfoSource::updateMode() const
{ {
   return d->m_updateMode;    return d->m_updateMode;
} }
   
/*! /*!
   Sets the NMEA data source to \a device. If the device is not open, it    Sets the NMEA data source to \a device. If the device is not open, it
   will be opened in QIODevice::ReadOnly mode.    will be opened in QIODevice::ReadOnly mode.
   
   The source device can only be set once and must be set before calling    The source device can only be set once and must be set before calling
   startUpdates() or requestUpdate().    startUpdates() or requestUpdate().
   
   \bold {Note:} The \a device must emit QIODevice::readyRead() for the    \bold {Note:} The \a device must emit QIODevice::readyRead() for the
   source to be notified when data is available for reading.    source to be notified when data is available for reading.
   QNmeaPositionInfoSource does not assume the ownership of the device,    QNmeaPositionInfoSource does not assume the ownership of the device,
   and hence does not deallocate it upon destruction.    and hence does not deallocate it upon destruction.
*/  */ 
void QNmeaPositionInfoSource::setDevice(QIODevice *device) void QNmeaPositionInfoSource::setDevice(QIODevice *device)
{ {
   if (device != d->m_device) {    if (device != d->m_device) {
       if (!d->m_device)        if (!d->m_device)
           d->m_device = device;            d->m_device = device;
       else        else
           qWarning("QNmeaPositionInfoSource: source device has already been set");            qWarning("QNmeaPositionInfoSource: source device has already been set");
   }    }
} }
   
/*! /*!
   Returns the NMEA data source.    Returns the NMEA data source.
*/  */ 
QIODevice *QNmeaPositionInfoSource::device() const QIODevice *QNmeaPositionInfoSource::device() const
{ {
   return d->m_device;    return d->m_device;
} }
   
/*! /*!
   \reimp    \reimp
*/  */ 
void QNmeaPositionInfoSource::setUpdateInterval(int msec) void QNmeaPositionInfoSource::setUpdateInterval(int msec)
{ {
   int interval = msec;    int interval = msec;
   if (interval != 0)    if (interval != 0)
       interval = qMax(msec, minimumUpdateInterval());        interval = qMax(msec, minimumUpdateInterval());
   QGeoPositionInfoSource::setUpdateInterval(interval);    QGeoPositionInfoSource::setUpdateInterval(interval);
   if (d->m_invokedStart) {    if (d->m_invokedStart) {
       d->stopUpdates();        d->stopUpdates();
       d->startUpdates();        d->startUpdates();
   }    }
} }
   
/*! /*!
   \reimp    \reimp
*/  */ 
void QNmeaPositionInfoSource::startUpdates() void QNmeaPositionInfoSource::startUpdates()
{ {
   d->startUpdates();    d->startUpdates();
} }
   
/*! /*!
   \reimp    \reimp
*/  */ 
void QNmeaPositionInfoSource::stopUpdates() void QNmeaPositionInfoSource::stopUpdates()
{ {
   d->stopUpdates();    d->stopUpdates();
} }
   
/*! /*!
   \reimp    \reimp
*/  */ 
void QNmeaPositionInfoSource::requestUpdate(int msec) void QNmeaPositionInfoSource::requestUpdate(int msec)
{ {
   d->requestUpdate(msec == 0 ? 60000 * 5 : msec);    d->requestUpdate(msec == 0 ? 60000 * 5 : msec);
} }
   
/*! /*!
   \reimp    \reimp
*/  */ 
QGeoPositionInfo QNmeaPositionInfoSource::lastKnownPosition(bool) const QGeoPositionInfo QNmeaPositionInfoSource::lastKnownPosition(bool) const
{ {
   // the bool value does not matter since we only use satellite positioning    // the bool value does not matter since we only use satellite positioning
   return d->m_lastUpdate;    return d->m_lastUpdate;
} }
   
/*! /*!
   \reimp    \reimp
*/  */ 
QGeoPositionInfoSource::PositioningMethods QNmeaPositionInfoSource::supportedPositioningMethods() const QGeoPositionInfoSource::PositioningMethods QNmeaPositionInfoSource::supportedPositioningMethods() const
{ {
   return SatellitePositioningMethods;    return SatellitePositioningMethods;
} }
   
/*! /*!
   \reimp    \reimp
*/  */ 
int QNmeaPositionInfoSource::minimumUpdateInterval() const int QNmeaPositionInfoSource::minimumUpdateInterval() const
{ {
   return 100;    return 100;
} }
   
#include "moc_qnmeapositioninfosource.cpp" #include "moc_qnmeapositioninfosource.cpp"
#include "moc_qnmeapositioninfosource_p.cpp" #include "moc_qnmeapositioninfosource_p.cpp"
   
QTM_END_NAMESPACE QTM_END_NAMESPACE