diff options
-rw-r--r-- | src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp | 67 | ||||
-rw-r--r-- | src/plugins/position/serialnmea/qnmeasatelliteinfosource.cpp | 558 | ||||
-rw-r--r-- | src/plugins/position/serialnmea/qnmeasatelliteinfosource_p.h | 96 | ||||
-rw-r--r-- | src/plugins/position/serialnmea/serialnmea.pro | 4 | ||||
-rw-r--r-- | src/positioning/qgeosatelliteinfo.cpp | 61 | ||||
-rw-r--r-- | src/positioning/qgeosatelliteinfo.h | 2 | ||||
-rw-r--r-- | src/positioning/qgeosatelliteinfo_p.h | 67 | ||||
-rw-r--r-- | src/positioning/qgeosatelliteinfosource.cpp | 108 | ||||
-rw-r--r-- | src/positioning/qgeosatelliteinfosource.h | 6 | ||||
-rw-r--r-- | src/positioning/qgeosatelliteinfosource_p.h | 70 | ||||
-rw-r--r-- | src/positioning/qlocationutils.cpp | 102 | ||||
-rw-r--r-- | src/positioning/qlocationutils_p.h | 27 |
12 files changed, 1110 insertions, 58 deletions
diff --git a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp index bebf7230..d56f1d46 100644 --- a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp +++ b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp @@ -45,6 +45,7 @@ #include <QSet> #include "qiopipe_p.h" #include <QSharedPointer> +#include "qnmeasatelliteinfosource_p.h" Q_LOGGING_CATEGORY(lcSerial, "qt.positioning.serialnmea") @@ -172,6 +173,67 @@ NmeaSource::~NmeaSource() deviceContainer->releaseSerial(m_portName, m_port); } + + +class NmeaSatelliteSource : public QNmeaSatelliteInfoSource +{ +public: + NmeaSatelliteSource(QObject *parent, const QVariantMap ¶meters) + : QNmeaSatelliteInfoSource(parent) + { + QByteArray requestedPort; + if (parameters.contains(QStringLiteral("serialnmea.serial_port"))) + requestedPort = parameters.value(QStringLiteral("serialnmea.serial_port")).toString().toLatin1(); + else + requestedPort = qgetenv("QT_NMEA_SERIAL_PORT"); + QString portName; + if (requestedPort.isEmpty()) { + const QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts(); + qCDebug(lcSerial) << "Found" << ports.count() << "serial ports"; + if (ports.isEmpty()) { + qWarning("serialnmea: No serial ports found"); + return; + } + + // Try to find a well-known device. + QSet<int> supportedDevices; + supportedDevices << 0x67b; // GlobalSat (BU-353S4 and probably others) + supportedDevices << 0xe8d; // Qstarz MTK II + foreach (const QSerialPortInfo& port, ports) { + if (port.hasVendorIdentifier() && supportedDevices.contains(port.vendorIdentifier())) { + portName = port.portName(); + break; + } + } + + if (portName.isEmpty()) { + qWarning("serialnmea: No known GPS device found. Specify the COM port via QT_NMEA_SERIAL_PORT."); + return; + } + m_portName = portName; + } else { + m_portName = QString::fromUtf8(requestedPort); + } + + m_port = deviceContainer->serial(m_portName); + if (!m_port) + return; + + setDevice(m_port.data()); + } + + ~NmeaSatelliteSource() + { + deviceContainer->releaseSerial(m_portName, m_port); + } + + bool isValid() const { return !m_port.isNull(); } + +private: + QSharedPointer<QIOPipe> m_port; + QString m_portName; +}; + QGeoPositionInfoSource *QGeoPositionInfoSourceFactorySerialNmea::positionInfoSource(QObject *parent) { return positionInfoSourceWithParameters(parent, QVariantMap()); @@ -195,9 +257,8 @@ QGeoPositionInfoSource *QGeoPositionInfoSourceFactorySerialNmea::positionInfoSou QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactorySerialNmea::satelliteInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters) { - Q_UNUSED(parent); - Q_UNUSED(parameters) - return nullptr; + QScopedPointer<NmeaSatelliteSource> src(new NmeaSatelliteSource(parent, parameters)); + return src->isValid() ? src.take() : nullptr; } QGeoAreaMonitorSource *QGeoPositionInfoSourceFactorySerialNmea::areaMonitorWithParameters(QObject *parent, const QVariantMap ¶meters) diff --git a/src/plugins/position/serialnmea/qnmeasatelliteinfosource.cpp b/src/plugins/position/serialnmea/qnmeasatelliteinfosource.cpp new file mode 100644 index 00000000..d31106fc --- /dev/null +++ b/src/plugins/position/serialnmea/qnmeasatelliteinfosource.cpp @@ -0,0 +1,558 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnmeasatelliteinfosource_p.h" +#include <QtPositioning/private/qgeosatelliteinfo_p.h> +#include <QtPositioning/private/qgeosatelliteinfosource_p.h> +#include <QtPositioning/private/qlocationutils_p.h> + +#include <QIODevice> +#include <QBasicTimer> +#include <QTimerEvent> +#include <QTimer> +#include <array> +#include <QDebug> +#include <QtCore/QtNumeric> + + +//QT_BEGIN_NAMESPACE + +#define USE_NMEA_PIMPL 1 + +#if USE_NMEA_PIMPL +class QGeoSatelliteInfoPrivateNmea : public QGeoSatelliteInfoPrivate +{ +public: + QGeoSatelliteInfoPrivateNmea(const QGeoSatelliteInfoPrivate &other); + QGeoSatelliteInfoPrivateNmea(const QGeoSatelliteInfoPrivateNmea &other); + virtual ~QGeoSatelliteInfoPrivateNmea(); + virtual QGeoSatelliteInfoPrivate *clone() const; + + QList<QByteArray> nmeaSentences; +}; + +QGeoSatelliteInfoPrivateNmea::QGeoSatelliteInfoPrivateNmea(const QGeoSatelliteInfoPrivate &other) +: QGeoSatelliteInfoPrivate(other) +{ +} + +QGeoSatelliteInfoPrivateNmea::QGeoSatelliteInfoPrivateNmea(const QGeoSatelliteInfoPrivateNmea &other) +: QGeoSatelliteInfoPrivate(other) +{ + nmeaSentences = other.nmeaSentences; +} + +QGeoSatelliteInfoPrivateNmea::~QGeoSatelliteInfoPrivateNmea() {} + +QGeoSatelliteInfoPrivate *QGeoSatelliteInfoPrivateNmea::clone() const +{ + return new QGeoSatelliteInfoPrivateNmea(*this); +} +#else +typedef QGeoSatelliteInfoPrivate QGeoSatelliteInfoPrivateNmea; +#endif + +class QNmeaSatelliteInfoSourcePrivate : public QObject, public QGeoSatelliteInfoSourcePrivate +{ + Q_OBJECT +public: + QNmeaSatelliteInfoSourcePrivate(QNmeaSatelliteInfoSource *parent); + ~QNmeaSatelliteInfoSourcePrivate(); + + void startUpdates(); + void stopUpdates(); + void requestUpdate(int msec); + void notifyNewUpdate(); + +public slots: + void readyRead(); + void emitPendingUpdate(); + void sourceDataClosed(); + void updateRequestTimeout(); + + +public: + QGeoSatelliteInfoSource *m_source = nullptr; + QGeoSatelliteInfoSource::Error m_satelliteError = QGeoSatelliteInfoSource::NoError; + QPointer<QIODevice> m_device; + struct Update { + QList<QGeoSatelliteInfo> m_satellitesInView; + QList<QGeoSatelliteInfo> m_satellitesInUse; + QList<int> m_inUse; // temp buffer for GSA received before GSV + bool m_validInView = false; + bool m_validInUse = false; + bool m_fresh = false; + bool m_updatingGsv = false; +#if USE_NMEA_PIMPL + QByteArray gsa; + QList<QByteArray> gsv; +#endif + void setSatellitesInView(const QList<QGeoSatelliteInfo> &inView) + { + m_updatingGsv = false; + m_satellitesInView = inView; + m_validInView = m_fresh = true; + if (m_inUse.size()) { + m_satellitesInUse.clear(); + m_validInUse = false; + bool corrupt = false; + for (const auto i: m_inUse) { + bool found = false; + for (const auto &s: m_satellitesInView) { + if (s.satelliteIdentifier() == i) { + m_satellitesInUse.append(s); + found = true; + } + } + if (!found) { // received a GSA before a GSV, but it was incorrect or something. Unrelated to this GSV at least. + m_satellitesInUse.clear(); + corrupt = true; + break; + } + } + m_validInUse = !corrupt; + m_inUse.clear(); + } + } + +// void setSatellitesInUse(const QList<QGeoSatelliteInfo> &inUse) +// { +// m_satellitesInUse = inUse; +// m_validInUse = true; +// m_inUse.clear(); +// } + + bool setSatellitesInUse(const QList<int> &inUse) + { + m_satellitesInUse.clear(); + m_validInUse = false; + m_inUse = inUse; + if (m_updatingGsv) { + m_satellitesInUse.clear(); + m_validInView = false; + return false; + } + for (const auto i: inUse) { + bool found = false; + for (const auto &s: m_satellitesInView) { + if (s.satelliteIdentifier() == i) { + m_satellitesInUse.append(s); + found = true; + } + } + if (!found) { // if satellites in use aren't in view, the related GSV is still to be received. + m_inUse = inUse; // So clear outdated data, buffer the info, and set it later. + m_satellitesInUse.clear(); + m_satellitesInView.clear(); + m_validInView = false; + return false; + } + } + m_validInUse = m_fresh = true; + return true; + } + + void consume() + { + m_fresh = false; + } + + bool isFresh() + { + return m_fresh; + } + + QSet<int> inUse() const + { + QSet<int> res; + for (const auto &s: m_satellitesInUse) + res.insert(s.satelliteIdentifier()); + return res; + } + + void clear() + { + m_satellitesInView.clear(); + m_satellitesInUse.clear(); + m_validInView = m_validInUse = false; + } + + bool isValid() + { + return m_validInView || m_validInUse; // GSV without GSA is valid. GSA with outdated but still matching GSV also valid. + } + } m_pendingUpdate, m_lastUpdate; + bool m_fresh = false; + bool m_invokedStart = false; + bool m_noUpdateLastInterval = false; + bool m_updateTimeoutSent = false; + bool m_connectedReadyRead = false; + int m_pushDelay = 20; + QBasicTimer *m_updateTimer = nullptr; // the timer used in startUpdates() + QTimer *m_requestTimer = nullptr; // the timer used in requestUpdate() + +protected: + void readAvailableData(); + bool openSourceDevice(); + bool initialize(); + void prepareSourceDevice(); + bool emitUpdated(Update &update); + void timerEvent(QTimerEvent *event) override; +}; + +QNmeaSatelliteInfoSourcePrivate::QNmeaSatelliteInfoSourcePrivate(QNmeaSatelliteInfoSource *parent) +: m_source(parent) +{ +} + +void QNmeaSatelliteInfoSourcePrivate::notifyNewUpdate() +{ + if (m_pendingUpdate.isValid() && m_pendingUpdate.isFresh()) { + if (m_requestTimer && m_requestTimer->isActive()) { // User called requestUpdate() + m_requestTimer->stop(); + emitUpdated(m_pendingUpdate); + } else if (m_invokedStart) { // user called startUpdates() + if (m_updateTimer && m_updateTimer->isActive()) { // update interval > 0 + // for periodic updates, only want the most recent update + if (m_noUpdateLastInterval) { + // if the update was invalid when timerEvent was last called, a valid update + // should be sent ASAP + emitPendingUpdate(); // m_noUpdateLastInterval handled in there. + } + } else { // update interval <= 0, send anything new ASAP + m_noUpdateLastInterval = !emitUpdated(m_pendingUpdate); + } + } + } +} + +QNmeaSatelliteInfoSourcePrivate::~QNmeaSatelliteInfoSourcePrivate() +{ + delete m_updateTimer; +} + +void QNmeaSatelliteInfoSourcePrivate::startUpdates() +{ + if (m_invokedStart) + return; + + m_invokedStart = true; + m_pendingUpdate.clear(); + m_noUpdateLastInterval = false; + + bool initialized = initialize(); + if (!initialized) + return; + + // Do not support simulation just yet +// if (m_updateMode == QNmeaPositionInfoSource::RealTimeMode) + { + // skip over any buffered data - we only want the newest data. + // Don't do this in requestUpdate. In that case bufferedData is good to have/use. + if (m_device->bytesAvailable()) { + if (m_device->isSequential()) + m_device->readAll(); + else + m_device->seek(m_device->bytesAvailable()); + } + } + + if (m_updateTimer) + m_updateTimer->stop(); + + if (m_source->updateInterval() > 0) { + if (!m_updateTimer) + m_updateTimer = new QBasicTimer; + m_updateTimer->start(m_source->updateInterval(), this); + } + + if (initialized) + prepareSourceDevice(); +} + +void QNmeaSatelliteInfoSourcePrivate::stopUpdates() +{ + m_invokedStart = false; + if (m_updateTimer) + m_updateTimer->stop(); + m_pendingUpdate.clear(); + m_noUpdateLastInterval = false; +} + +void QNmeaSatelliteInfoSourcePrivate::requestUpdate(int msec) +{ + if (m_requestTimer && m_requestTimer->isActive()) + return; + + if (msec <= 0 || msec < m_source->minimumUpdateInterval()) { + emit m_source->requestTimeout(); + return; + } + + if (!m_requestTimer) { + m_requestTimer = new QTimer(this); + connect(m_requestTimer, SIGNAL(timeout()), SLOT(updateRequestTimeout())); + } + + bool initialized = initialize(); + if (!initialized) { + emit m_source->requestTimeout(); + return; + } + + m_requestTimer->start(msec); + prepareSourceDevice(); +} + +void QNmeaSatelliteInfoSourcePrivate::readyRead() +{ + readAvailableData(); +} + +void QNmeaSatelliteInfoSourcePrivate::emitPendingUpdate() +{ + if (m_pendingUpdate.isValid() && m_pendingUpdate.isFresh()) { + m_updateTimeoutSent = false; + m_noUpdateLastInterval = false; + if (!emitUpdated(m_pendingUpdate)) + m_noUpdateLastInterval = true; +// m_pendingUpdate.clear(); // Do not clear, it will be incrementally updated + } else { // invalid or not fresh update + if (m_noUpdateLastInterval && !m_updateTimeoutSent) { + m_updateTimeoutSent = true; + emit m_source->requestTimeout(); + } + m_noUpdateLastInterval = true; + } +} + +void QNmeaSatelliteInfoSourcePrivate::sourceDataClosed() +{ + if (m_device && m_device->bytesAvailable()) + readAvailableData(); +} + +void QNmeaSatelliteInfoSourcePrivate::updateRequestTimeout() +{ + m_requestTimer->stop(); + emit m_source->requestTimeout(); +} + +void QNmeaSatelliteInfoSourcePrivate::readAvailableData() +{ + while (m_device->canReadLine()) { + char buf[1024]; + qint64 size = m_device->readLine(buf, sizeof(buf)); + QList<int> satInUse; + const bool satInUseParsed = QLocationUtils::getSatInUseFromNmea(buf, size, satInUse); + if (satInUseParsed) { + m_pendingUpdate.setSatellitesInUse(satInUse); +#if USE_NMEA_PIMPL + m_pendingUpdate.gsa = QByteArray(buf, size); + if (m_pendingUpdate.m_satellitesInUse.size()) { + for (auto &s: m_pendingUpdate.m_satellitesInUse) + static_cast<QGeoSatelliteInfoPrivateNmea *>(QGeoSatelliteInfoPrivate::get(s))->nmeaSentences.append(m_pendingUpdate.gsa); + for (auto &s: m_pendingUpdate.m_satellitesInView) + static_cast<QGeoSatelliteInfoPrivateNmea *>(QGeoSatelliteInfoPrivate::get(s))->nmeaSentences.append(m_pendingUpdate.gsa); + } +#endif + } else { + const QLocationUtils::GSVParseStatus parserStatus = QLocationUtils::getSatInfoFromNmea(buf, size, m_pendingUpdate.m_satellitesInView); + if (parserStatus == QLocationUtils::GSVPartiallyParsed) { + m_pendingUpdate.m_updatingGsv = true; +#if USE_NMEA_PIMPL + m_pendingUpdate.gsv.append(QByteArray(buf, size)); +#endif + } else if (parserStatus == QLocationUtils::GSVFullyParsed) { +#if USE_NMEA_PIMPL + m_pendingUpdate.gsv.append(QByteArray(buf, size)); + for (int i = 0; i < m_pendingUpdate.m_satellitesInView.size(); i++) { + const QGeoSatelliteInfo &s = m_pendingUpdate.m_satellitesInView.at(i); + QGeoSatelliteInfoPrivateNmea *pimpl = new QGeoSatelliteInfoPrivateNmea(*QGeoSatelliteInfoPrivate::get(s)); + pimpl->nmeaSentences.append(m_pendingUpdate.gsa); + pimpl->nmeaSentences.append(m_pendingUpdate.gsv); + m_pendingUpdate.m_satellitesInView.replace(i, QGeoSatelliteInfo(*pimpl)); + } + m_pendingUpdate.gsv.clear(); +#endif + m_pendingUpdate.setSatellitesInView(m_pendingUpdate.m_satellitesInView); + } + } + } + notifyNewUpdate(); +} + +bool QNmeaSatelliteInfoSourcePrivate::openSourceDevice() +{ + if (!m_device) { + qWarning("QNmeaSatelliteInfoSource: no QIODevice data source, call setDevice() first"); + return false; + } + + if (!m_device->isOpen() && !m_device->open(QIODevice::ReadOnly)) { + qWarning("QNmeaSatelliteInfoSource: cannot open QIODevice data source"); + return false; + } + + connect(m_device, SIGNAL(aboutToClose()), SLOT(sourceDataClosed())); + connect(m_device, SIGNAL(readChannelFinished()), SLOT(sourceDataClosed())); + connect(m_device, SIGNAL(destroyed()), SLOT(sourceDataClosed())); + + return true; +} + +bool QNmeaSatelliteInfoSourcePrivate::initialize() +{ + if (!openSourceDevice()) + return false; + + return true; +} + +void QNmeaSatelliteInfoSourcePrivate::prepareSourceDevice() +{ + if (!m_connectedReadyRead) { + connect(m_device, SIGNAL(readyRead()), SLOT(readyRead())); + m_connectedReadyRead = true; + } +} + +bool QNmeaSatelliteInfoSourcePrivate::emitUpdated(QNmeaSatelliteInfoSourcePrivate::Update &update) +{ + bool emitted = false; + if (!update.isFresh()) + return emitted; + + update.consume(); + const bool inUseUpdated = update.m_satellitesInUse != m_lastUpdate.m_satellitesInUse; + const bool inViewUpdated = update.m_satellitesInView != m_lastUpdate.m_satellitesInView; + + + m_lastUpdate = update; + if (update.m_validInUse && inUseUpdated) { + emit m_source->satellitesInUseUpdated(update.m_satellitesInUse); + emitted = true; + } + if (update.m_validInView && inViewUpdated) { + emit m_source->satellitesInViewUpdated(update.m_satellitesInView); + emitted = true; + } + return emitted; +} + +void QNmeaSatelliteInfoSourcePrivate::timerEvent(QTimerEvent * /*event*/) +{ + emitPendingUpdate(); +} + + +// currently supports only realtime +QNmeaSatelliteInfoSource::QNmeaSatelliteInfoSource(QObject *parent) +: QGeoSatelliteInfoSource(*new QNmeaSatelliteInfoSourcePrivate(this), parent) +{ + d = static_cast<QNmeaSatelliteInfoSourcePrivate *>(QGeoSatelliteInfoSourcePrivate::get(*this)); +} + +QNmeaSatelliteInfoSource::~QNmeaSatelliteInfoSource() +{ + // d deleted in superclass destructor +} + +void QNmeaSatelliteInfoSource::setDevice(QIODevice *device) +{ + if (device != d->m_device) { + if (!d->m_device) + d->m_device = device; + else + qWarning("QNmeaPositionInfoSource: source device has already been set"); + } +} + +QIODevice *QNmeaSatelliteInfoSource::device() const +{ + return d->m_device; +} + +void QNmeaSatelliteInfoSource::setUpdateInterval(int msec) +{ + int interval = msec; + if (interval != 0) + interval = qMax(msec, minimumUpdateInterval()); + QGeoSatelliteInfoSource::setUpdateInterval(interval); + if (d->m_invokedStart) { + d->stopUpdates(); + d->startUpdates(); + } +} + +int QNmeaSatelliteInfoSource::minimumUpdateInterval() const +{ + return 2; // Some chips are capable of over 100 updates per seconds. +} + +QGeoSatelliteInfoSource::Error QNmeaSatelliteInfoSource::error() const +{ + return d->m_satelliteError; +} + +void QNmeaSatelliteInfoSource::startUpdates() +{ + d->startUpdates(); +} + +void QNmeaSatelliteInfoSource::stopUpdates() +{ + d->stopUpdates(); +} + +void QNmeaSatelliteInfoSource::requestUpdate(int msec) +{ + d->requestUpdate(msec == 0 ? 60000 * 5 : msec); // 5min default timeout +} + +void QNmeaSatelliteInfoSource::setError(QGeoSatelliteInfoSource::Error satelliteError) +{ + d->m_satelliteError = satelliteError; + emit QGeoSatelliteInfoSource::error(satelliteError); +} + + +//QT_END_NAMESPACE + +#include "qnmeasatelliteinfosource.moc" diff --git a/src/plugins/position/serialnmea/qnmeasatelliteinfosource_p.h b/src/plugins/position/serialnmea/qnmeasatelliteinfosource_p.h new file mode 100644 index 00000000..2f7469c6 --- /dev/null +++ b/src/plugins/position/serialnmea/qnmeasatelliteinfosource_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNMESATELLITEINFOSOURCE_P_H +#define QNMESATELLITEINFOSOURCE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +//#include <QtPositioning/private/qpositioningglobal_p.h> +#include <QtPositioning/qgeosatelliteinfosource.h> +#include <QtPositioning/qgeosatelliteinfo.h> + +#include <QObject> +#include <QQueue> +#include <QPointer> +#include <QtCore/qiodevice.h> +#include <QtCore/qtimer.h> + +//QT_BEGIN_NAMESPACE + +class QNmeaSatelliteInfoSourcePrivate; +class /*Q_POSITIONING_PRIVATE_EXPORT*/ QNmeaSatelliteInfoSource : public QGeoSatelliteInfoSource +{ + Q_OBJECT +public: + explicit QNmeaSatelliteInfoSource( QObject *parent = nullptr); + ~QNmeaSatelliteInfoSource() override; + + void setDevice(QIODevice *source); + QIODevice *device() const; + + void setUpdateInterval(int msec) override; + int minimumUpdateInterval() const override; + Error error() const override; + +public Q_SLOTS: + void startUpdates() override; + void stopUpdates() override; + void requestUpdate(int timeout = 0) override; + +protected: + QNmeaSatelliteInfoSourcePrivate *d; + void setError(QGeoSatelliteInfoSource::Error satelliteError); + + friend class QNmeaSatelliteInfoSourcePrivate; + Q_DISABLE_COPY(QNmeaSatelliteInfoSource) +}; + +//QT_END_NAMESPACE + +#endif diff --git a/src/plugins/position/serialnmea/serialnmea.pro b/src/plugins/position/serialnmea/serialnmea.pro index e5677e99..4e0088bb 100644 --- a/src/plugins/position/serialnmea/serialnmea.pro +++ b/src/plugins/position/serialnmea/serialnmea.pro @@ -3,10 +3,10 @@ TARGET = qtposition_serialnmea QT = core-private positioning-private serialport HEADERS += \ - qgeopositioninfosourcefactory_serialnmea.h qiopipe_p.h + qgeopositioninfosourcefactory_serialnmea.h qnmeasatelliteinfosource_p.h qiopipe_p.h SOURCES += \ - qgeopositioninfosourcefactory_serialnmea.cpp qiopipe.cpp + qgeopositioninfosourcefactory_serialnmea.cpp qnmeasatelliteinfosource.cpp qiopipe.cpp OTHER_FILES += \ plugin.json diff --git a/src/positioning/qgeosatelliteinfo.cpp b/src/positioning/qgeosatelliteinfo.cpp index e62bd164..91ebfa85 100644 --- a/src/positioning/qgeosatelliteinfo.cpp +++ b/src/positioning/qgeosatelliteinfo.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ #include "qgeosatelliteinfo.h" +#include "qgeosatelliteinfo_p.h" #include <QHash> #include <QDebug> @@ -44,16 +45,6 @@ QT_BEGIN_NAMESPACE -class QGeoSatelliteInfoPrivate -{ -public: - int signal; - int satId; - QGeoSatelliteInfo::SatelliteSystem system; - QHash<int, qreal> doubleAttribs; -}; - - /*! \class QGeoSatelliteInfo \inmodule QtPositioning @@ -103,6 +94,10 @@ QGeoSatelliteInfo::QGeoSatelliteInfo(const QGeoSatelliteInfo &other) operator=(other); } +QGeoSatelliteInfo::QGeoSatelliteInfo(QGeoSatelliteInfoPrivate &dd) : d(&dd) +{ +} + /*! Destroys a satellite information object. */ @@ -119,10 +114,9 @@ QGeoSatelliteInfo &QGeoSatelliteInfo::operator=(const QGeoSatelliteInfo & other) if (this == &other) return *this; - d->signal = other.d->signal; - d->satId = other.d->satId; - d->system = other.d->system; - d->doubleAttribs = other.d->doubleAttribs; + delete d; + d = other.d->clone(); + return *this; } @@ -132,10 +126,7 @@ QGeoSatelliteInfo &QGeoSatelliteInfo::operator=(const QGeoSatelliteInfo & other) */ bool QGeoSatelliteInfo::operator==(const QGeoSatelliteInfo &other) const { - return d->signal == other.d->signal - && d->satId == other.d->satId - && d->system == other.d->system - && d->doubleAttribs == other.d->doubleAttribs; + return *d == *other.d; } /*! @@ -309,6 +300,40 @@ QDataStream &operator>>(QDataStream &stream, QGeoSatelliteInfo &info) info.d->system = (QGeoSatelliteInfo::SatelliteSystem)system; return stream; } + +QGeoSatelliteInfoPrivate::QGeoSatelliteInfoPrivate() +{ + +} + +QGeoSatelliteInfoPrivate::QGeoSatelliteInfoPrivate(const QGeoSatelliteInfoPrivate &other) +{ + signal = other.signal; + satId = other.satId; + system = other.system; + doubleAttribs = other.doubleAttribs; +} + +QGeoSatelliteInfoPrivate::~QGeoSatelliteInfoPrivate() {} + +QGeoSatelliteInfoPrivate *QGeoSatelliteInfoPrivate::clone() const +{ + return new QGeoSatelliteInfoPrivate(*this); +} + +bool QGeoSatelliteInfoPrivate::operator==(const QGeoSatelliteInfoPrivate &other) const +{ + return signal == other.signal + && satId == other.satId + && system == other.system + && doubleAttribs == other.doubleAttribs; +} + +QGeoSatelliteInfoPrivate *QGeoSatelliteInfoPrivate::get(const QGeoSatelliteInfo &info) +{ + return info.d; +} + #endif QT_END_NAMESPACE diff --git a/src/positioning/qgeosatelliteinfo.h b/src/positioning/qgeosatelliteinfo.h index e68d8d9f..28766257 100644 --- a/src/positioning/qgeosatelliteinfo.h +++ b/src/positioning/qgeosatelliteinfo.h @@ -63,6 +63,7 @@ public: QGeoSatelliteInfo(); QGeoSatelliteInfo(const QGeoSatelliteInfo &other); + QGeoSatelliteInfo(QGeoSatelliteInfoPrivate &dd); ~QGeoSatelliteInfo(); QGeoSatelliteInfo &operator=(const QGeoSatelliteInfo &other); @@ -96,6 +97,7 @@ private: friend Q_POSITIONING_EXPORT QDataStream &operator>>(QDataStream &stream, QGeoSatelliteInfo &info); #endif QGeoSatelliteInfoPrivate *d; + friend class QGeoSatelliteInfoPrivate; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/positioning/qgeosatelliteinfo_p.h b/src/positioning/qgeosatelliteinfo_p.h new file mode 100644 index 00000000..6320bf2e --- /dev/null +++ b/src/positioning/qgeosatelliteinfo_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGEOSATELLITEINFO_P_H +#define QGEOSATELLITEINFO_P_H + +#include <QtPositioning/private/qpositioningglobal_p.h> +#include <QtPositioning/qgeosatelliteinfo.h> +#include <QHash> + +QT_BEGIN_NAMESPACE + +class Q_POSITIONING_PRIVATE_EXPORT QGeoSatelliteInfoPrivate +{ +public: + QGeoSatelliteInfoPrivate(); + QGeoSatelliteInfoPrivate(const QGeoSatelliteInfoPrivate &other); + virtual ~QGeoSatelliteInfoPrivate(); + virtual QGeoSatelliteInfoPrivate *clone() const; + virtual bool operator==(const QGeoSatelliteInfoPrivate &other) const; + static QGeoSatelliteInfoPrivate *get(const QGeoSatelliteInfo &info); + + int signal; + int satId; + QGeoSatelliteInfo::SatelliteSystem system; + QHash<int, qreal> doubleAttribs; +}; + +QT_END_NAMESPACE + +#endif // QGEOSATELLITEINFO_P_H diff --git a/src/positioning/qgeosatelliteinfosource.cpp b/src/positioning/qgeosatelliteinfosource.cpp index c55c36d3..6796b921 100644 --- a/src/positioning/qgeosatelliteinfosource.cpp +++ b/src/positioning/qgeosatelliteinfosource.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ #include <qgeosatelliteinfosource.h> +#include <qgeosatelliteinfosource_p.h> #include "qgeopositioninfosourcefactory.h" #include "qgeopositioninfosource_p.h" #include <QPluginLoader> @@ -84,16 +85,20 @@ QT_BEGIN_NAMESPACE update intervals, as returned by minimumUpdateInterval(). */ -class QGeoSatelliteInfoSourcePrivate -{ -public: - int interval; - QString providerName; -}; - /*! Creates a satellite source with the specified \a parent. */ + +QGeoSatelliteInfoSourcePrivate::~QGeoSatelliteInfoSourcePrivate() +{ + +} + +QGeoSatelliteInfoSourcePrivate *QGeoSatelliteInfoSourcePrivate::get(QGeoSatelliteInfoSource &source) +{ + return source.d; +} + QGeoSatelliteInfoSource::QGeoSatelliteInfoSource(QObject *parent) : QObject(parent), d(new QGeoSatelliteInfoSourcePrivate) @@ -101,6 +106,13 @@ QGeoSatelliteInfoSource::QGeoSatelliteInfoSource(QObject *parent) d->interval = 0; } +QGeoSatelliteInfoSource::QGeoSatelliteInfoSource(QGeoSatelliteInfoSourcePrivate &dd, QObject *parent) +: QObject(parent), + d(&dd) +{ + +} + /*! Destroys the satellite source. */ @@ -153,7 +165,21 @@ int QGeoSatelliteInfoSource::updateInterval() const return d->interval; } - +static QGeoSatelliteInfoSource* createSource_real(const QJsonObject &meta, const QVariantMap ¶meters, QObject *parent) +{ + QGeoPositionInfoSourcePrivate d; + d.metaData = meta; + d.loadPlugin(); + QGeoSatelliteInfoSource *s = nullptr; + if (!parameters.isEmpty() && d.factoryV2) + s = d.factoryV2->satelliteInfoSourceWithParameters(parent, parameters); + else if (d.factory) + s = d.factory->satelliteInfoSource(parent); + if (s) + QGeoSatelliteInfoSourcePrivate::get(*s)->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); + + return s; +} /*! Creates and returns a source with the specified \a parent that reads @@ -165,6 +191,34 @@ int QGeoSatelliteInfoSource::updateInterval() const */ QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createDefaultSource(QObject *parent) { + return createDefaultSource(QVariantMap(), parent); +} + +/*! + Creates and returns a source with the given \a parent, + by loading the plugin named \a sourceName. + + Returns 0 if the plugin cannot be found. +*/ +QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createSource(const QString &sourceName, QObject *parent) +{ + return createSource(sourceName, QVariantMap(), parent); +} + +/*! + Creates and returns a satellite source with the given \a parent that + reads from the system's default sources of satellite data, or the plugin + with the highest available priority. + + Returns nullptr if the system has no default satellite source, no valid plugins + could be found or the user does not have the permission to access the satellite information. + + This method passes \a parameters to the factory to configure the source. + + \since Qt 5.14 +*/ +QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createDefaultSource(const QVariantMap ¶meters, QObject *parent) +{ QList<QJsonObject> plugins = QGeoPositionInfoSourcePrivate::pluginsSorted(); foreach (const QJsonObject &obj, plugins) { if (obj.value(QStringLiteral("Satellite")).isBool() @@ -176,43 +230,29 @@ QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createDefaultSource(QObject *p if (inTest) continue; } - QGeoPositionInfoSourcePrivate d; - d.metaData = obj; - d.loadPlugin(); - QGeoSatelliteInfoSource *s = 0; - if (d.factory) - s = d.factory->satelliteInfoSource(parent); - if (s) - s->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); - return s; + return createSource_real(obj, parameters, parent); } } - return 0; + return nullptr; } /*! - Creates and returns a source with the given \a parent, + Creates and returns a satellite source with the given \a parent, by loading the plugin named \a sourceName. - Returns 0 if the plugin cannot be found. + Returns nullptr if the plugin cannot be found. + + This method passes \a parameters to the factory to configure the source. + + \since Qt 5.14 */ -QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createSource(const QString &sourceName, QObject *parent) +QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createSource(const QString &sourceName, const QVariantMap ¶meters, QObject *parent) { QHash<QString, QJsonObject> plugins = QGeoPositionInfoSourcePrivate::plugins(); - if (plugins.contains(sourceName)) { - QGeoPositionInfoSourcePrivate d; - d.metaData = plugins.value(sourceName); - d.loadPlugin(); - QGeoSatelliteInfoSource *src = 0; - if (d.factory) - src = d.factory->satelliteInfoSource(parent); - if (src) - src->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); - return src; - } - - return 0; + if (plugins.contains(sourceName)) + return createSource_real(plugins.value(sourceName), parameters, parent); + return nullptr; } /*! diff --git a/src/positioning/qgeosatelliteinfosource.h b/src/positioning/qgeosatelliteinfosource.h index 391eefcf..4f073864 100644 --- a/src/positioning/qgeosatelliteinfosource.h +++ b/src/positioning/qgeosatelliteinfosource.h @@ -67,6 +67,8 @@ public: static QGeoSatelliteInfoSource *createDefaultSource(QObject *parent); static QGeoSatelliteInfoSource *createSource(const QString &sourceName, QObject *parent); + static QGeoSatelliteInfoSource *createDefaultSource(const QVariantMap ¶meters, QObject *parent); + static QGeoSatelliteInfoSource *createSource(const QString &sourceName, const QVariantMap ¶meters, QObject *parent); static QStringList availableSources(); QString sourceName() const; @@ -88,9 +90,13 @@ Q_SIGNALS: void requestTimeout(); void error(QGeoSatelliteInfoSource::Error); +protected: + QGeoSatelliteInfoSource(QGeoSatelliteInfoSourcePrivate &dd, QObject *parent); + private: Q_DISABLE_COPY(QGeoSatelliteInfoSource) QGeoSatelliteInfoSourcePrivate *d; + friend class QGeoSatelliteInfoSourcePrivate; }; QT_END_NAMESPACE diff --git a/src/positioning/qgeosatelliteinfosource_p.h b/src/positioning/qgeosatelliteinfosource_p.h new file mode 100644 index 00000000..58001b21 --- /dev/null +++ b/src/positioning/qgeosatelliteinfosource_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGEOSATELLITEINFOSOURCE_P_H +#define QGEOSATELLITEINFOSOURCE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtPositioning/private/qpositioningglobal_p.h> +#include <QString> + +QT_BEGIN_NAMESPACE +class QGeoSatelliteInfoSource; +class Q_POSITIONING_PRIVATE_EXPORT QGeoSatelliteInfoSourcePrivate +{ +public: + virtual ~QGeoSatelliteInfoSourcePrivate(); + static QGeoSatelliteInfoSourcePrivate *get(QGeoSatelliteInfoSource &source); + int interval; + QString providerName; +}; + +QT_END_NAMESPACE + +#endif // QGEOSATELLITEINFOSOURCE_P_H diff --git a/src/positioning/qlocationutils.cpp b/src/positioning/qlocationutils.cpp index f5062eb6..fec8ccba 100644 --- a/src/positioning/qlocationutils.cpp +++ b/src/positioning/qlocationutils.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qlocationutils_p.h" #include "qgeopositioninfo.h" +#include "qgeosatelliteinfo.h" #include <QTime> #include <QList> @@ -124,6 +125,25 @@ static void qlocationutils_readGsa(const char *data, int size, QGeoPositionInfo } } +static void qlocationutils_readGsa(const char *data, + int size, + QList<int> &pnrsInUse) +{ + QList<QByteArray> parts = QByteArray::fromRawData(data, size).split(','); + pnrsInUse.clear(); + if (parts.count() <= 2) + return; + bool ok; + for (int i = 3; i <= qMin(14, parts.size()); ++i) { + const QByteArray &pnrString = parts.at(i); + if (pnrString.isEmpty()) + continue; + int pnr = pnrString.toInt(&ok); + if (ok) + pnrsInUse.append(pnr); + } +} + static void qlocationutils_readGll(const char *data, int size, QGeoPositionInfo *info, bool *hasFix) { QByteArray sentence(data, size); @@ -269,6 +289,9 @@ QLocationUtils::NmeaSentence QLocationUtils::getNmeaSentenceType(const char *dat if (data[3] == 'G' && data[4] == 'S' && data[5] == 'A') return NmeaSentenceGSA; + if (data[3] == 'G' && data[4] == 'S' && data[5] == 'V') + return NmeaSentenceGSV; + if (data[3] == 'G' && data[4] == 'L' && data[5] == 'L') return NmeaSentenceGLL; @@ -329,6 +352,85 @@ bool QLocationUtils::getPosInfoFromNmea(const char *data, int size, QGeoPosition } } +QLocationUtils::GSVParseStatus QLocationUtils::getSatInfoFromNmea(const char *data, int size, QList<QGeoSatelliteInfo> &infos) +{ + if (!data || !size) + return GSVNotParsed; + + NmeaSentence nmeaType = getNmeaSentenceType(data, size); + if (nmeaType != NmeaSentenceGSV) + return GSVNotParsed; + + QList<QByteArray> parts = QByteArray::fromRawData(data, size).split(','); + + if (parts.count() <= 3) { + infos.clear(); + return GSVFullyParsed; // Malformed sentence. + } + bool ok; + const int totalSentences = parts.at(1).toInt(&ok); + if (!ok) { + infos.clear(); + return GSVFullyParsed; // Malformed sentence. + } + + const int sentence = parts.at(2).toInt(&ok); + if (!ok) { + infos.clear(); + return GSVFullyParsed; // Malformed sentence. + } + + const int totalSats = parts.at(3).toInt(&ok); + if (!ok) { + infos.clear(); + return GSVFullyParsed; // Malformed sentence. + } + + if (sentence == 1) + infos.clear(); + + const int numSatInSentence = qMin(sentence * 4, totalSats) - (sentence - 1) * 4; + + int field = 4; + for (int i = 0; i < numSatInSentence; ++i) { + QGeoSatelliteInfo info; + const int prn = parts.at(field++).toInt(&ok); + info.setSatelliteIdentifier((ok) ? prn : 0); + const int elevation = parts.at(field++).toInt(&ok); + info.setAttribute(QGeoSatelliteInfo::Elevation, (ok) ? elevation : 0); + const int azimuth = parts.at(field++).toInt(&ok); + info.setAttribute(QGeoSatelliteInfo::Azimuth, (ok) ? azimuth : 0); + const int snr = parts.at(field++).toInt(&ok); + info.setSignalStrength((ok) ? snr : -1); + infos.append(info); + } + + if (sentence == totalSentences) + return GSVFullyParsed; + return GSVPartiallyParsed; +} + +bool QLocationUtils::getSatInUseFromNmea(const char *data, int size, QList<int> &pnrsInUse) +{ + pnrsInUse.clear(); + if (!data || !size) + return false; + + NmeaSentence nmeaType = getNmeaSentenceType(data, size); + if (nmeaType != NmeaSentenceGSA) + return false; + + // Adjust size so that * and following characters are not parsed by the following functions. + for (int i = 0; i < size; ++i) { + if (data[i] == '*') { + size = i; + break; + } + } + qlocationutils_readGsa(data, size, pnrsInUse); + return true; +} + bool QLocationUtils::hasValidNmeaChecksum(const char *data, int size) { int asteriskIndex = -1; diff --git a/src/positioning/qlocationutils_p.h b/src/positioning/qlocationutils_p.h index e3881f6f..e2d739e7 100644 --- a/src/positioning/qlocationutils_p.h +++ b/src/positioning/qlocationutils_p.h @@ -65,6 +65,7 @@ class QTime; class QByteArray; class QGeoPositionInfo; +class QGeoSatelliteInfo; class Q_POSITIONING_PRIVATE_EXPORT QLocationUtils { public: @@ -94,7 +95,8 @@ public: NmeaSentenceGLL, // Lat/Lon data NmeaSentenceRMC, // Recommended minimum data for gps NmeaSentenceVTG, // Vector track an Speed over the Ground - NmeaSentenceZDA // Date and Time + NmeaSentenceZDA, // Date and Time + NmeaSentenceGSV // Per-Satellite Info }; inline static bool isValidLat(double lat) { @@ -282,6 +284,29 @@ public: bool *hasFix = nullptr); /* + Retruns a list of QGeoSatelliteInfo in the view. + + Note: this function has to be called repeatedly until it returns true. + Reason being that GSV sentences can be split into multiple samples, so getting the full data + requires parsing multiple sentences. + */ + enum GSVParseStatus { + GSVNotParsed, + GSVPartiallyParsed, + GSVFullyParsed + }; + static GSVParseStatus getSatInfoFromNmea(const char *data, + int size, + QList<QGeoSatelliteInfo> &infos); + + /* + Parses GSA for satellites in use. + */ + static bool getSatInUseFromNmea(const char *data, + int size, + QList<int> &pnrsInUse); + + /* Returns true if the given NMEA sentence has a valid checksum. */ static bool hasValidNmeaChecksum(const char *data, int size); |