summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2019-05-10 19:55:33 +0200
committerpaolo <paolo.angelelli@qt.io>2019-08-15 10:08:13 +0200
commitf613eb3a6031d6d4f3e5ee230fab3056314fa9a4 (patch)
tree804e4d47b2eed988c1af0847f023b81dae4afc96
parent3334c6f6d00255f6fd5690e4b9cb05416950fd4d (diff)
downloadqtlocation-f613eb3a6031d6d4f3e5ee230fab3056314fa9a4.tar.gz
Add Satellite support to serialnmea plugin
This adds a new class, QNmeaSatelliteInfoSource, locally to the plugin, that behaves similarly to QNmeaPositionInfoSource in the way of handling the IODevice and producing the updates. Change-Id: Id594152dd70514974ac79c7757ce6f0da4631191 Fixes: QTBUG-59274 Reviewed-by: Paolo Angelelli <paolo.angelelli@qt.io>
-rw-r--r--src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp67
-rw-r--r--src/plugins/position/serialnmea/qnmeasatelliteinfosource.cpp558
-rw-r--r--src/plugins/position/serialnmea/qnmeasatelliteinfosource_p.h96
-rw-r--r--src/plugins/position/serialnmea/serialnmea.pro4
-rw-r--r--src/positioning/qgeosatelliteinfo.cpp61
-rw-r--r--src/positioning/qgeosatelliteinfo.h2
-rw-r--r--src/positioning/qgeosatelliteinfo_p.h67
-rw-r--r--src/positioning/qgeosatelliteinfosource.cpp108
-rw-r--r--src/positioning/qgeosatelliteinfosource.h6
-rw-r--r--src/positioning/qgeosatelliteinfosource_p.h70
-rw-r--r--src/positioning/qlocationutils.cpp102
-rw-r--r--src/positioning/qlocationutils_p.h27
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 &parameters)
+ : 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 &parameters)
{
- 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 &parameters)
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 &parameters, 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 &parameters, 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 &parameters, 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 &parameters, QObject *parent);
+ static QGeoSatelliteInfoSource *createSource(const QString &sourceName, const QVariantMap &parameters, 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);