53void QNmeaSatelliteInfoSourcePrivate::notifyNewUpdate()
55 if (m_pendingUpdate.isValid() && m_pendingUpdate.isFresh()) {
56 if (m_requestTimer && m_requestTimer->isActive()) {
57 m_requestTimer->stop();
58 emitUpdated(m_pendingUpdate,
true);
59 }
else if (m_invokedStart) {
60 if (m_updateTimer && m_updateTimer->isActive()) {
62 if (m_noUpdateLastInterval) {
68 m_noUpdateLastInterval = !emitUpdated(m_pendingUpdate,
false);
74void QNmeaSatelliteInfoSourcePrivate::processNmeaData(QNmeaSatelliteInfoUpdate &updateInfo)
77 qint64 size = m_device->readLine(buf,
sizeof(buf));
82 const auto satSystemType = m_source->parseSatellitesInUseFromNmea(QByteArrayView{buf,
static_cast<qsizetype>(size)},
84 if (satSystemType != QGeoSatelliteInfo::Undefined) {
85 const bool res = updateInfo.setSatellitesInUse(satSystemType, satInUse);
86#if USE_SATELLITE_NMEA_PIMPL
88 updateInfo.gsa = QByteArray(buf, size);
89 auto &info = updateInfo.m_satellites[satSystemType];
90 if (!info.satellitesInUse.isEmpty()) {
91 for (
auto &s : info.satellitesInUse) {
92 static_cast<QGeoSatelliteInfoPrivateNmea *>(QGeoSatelliteInfoPrivate::get(s))
93 ->nmeaSentences.append(updateInfo.gsa);
95 for (
auto &s : info.satellitesInView) {
96 static_cast<QGeoSatelliteInfoPrivateNmea *>(QGeoSatelliteInfoPrivate::get(s))
97 ->nmeaSentences.append(updateInfo.gsa);
107 auto systemType = QGeoSatelliteInfo::Undefined;
108 const auto parserStatus = m_source->parseSatelliteInfoFromNmea(
109 QByteArrayView{buf,
static_cast<qsizetype>(size)}, updateInfo.m_satellitesInViewParsed, systemType);
110 if (parserStatus == QNmeaSatelliteInfoSource::PartiallyParsed) {
111 updateInfo.m_satellites[systemType].updatingGSV =
true;
112#if USE_SATELLITE_NMEA_PIMPL
113 updateInfo.gsv.append(QByteArray(buf, size));
115 }
else if (parserStatus == QNmeaSatelliteInfoSource::FullyParsed) {
116#if USE_SATELLITE_NMEA_PIMPL
117 updateInfo.gsv.append(QByteArray(buf, size));
118 for (
int i = 0; i < updateInfo.m_satellitesInViewParsed.size(); i++) {
119 const QGeoSatelliteInfo &s = updateInfo.m_satellitesInViewParsed.at(i);
120 QGeoSatelliteInfoPrivateNmea *pimpl =
121 new QGeoSatelliteInfoPrivateNmea(*QGeoSatelliteInfoPrivate::get(s));
122 pimpl->nmeaSentences.append(updateInfo.gsa);
123 pimpl->nmeaSentences.append(updateInfo.gsv);
124 updateInfo.m_satellitesInViewParsed.replace(i, QGeoSatelliteInfo(*pimpl));
126 updateInfo.gsv.clear();
128 updateInfo.setSatellitesInView(systemType, updateInfo.m_satellitesInViewParsed);
138void QNmeaSatelliteInfoSourcePrivate::startUpdates()
143 m_satelliteError = QGeoSatelliteInfoSource::NoError;
145 m_invokedStart =
true;
146 m_pendingUpdate.clear();
147 m_noUpdateLastInterval =
false;
149 bool initialized = initialize();
153 if (m_updateMode == QNmeaSatelliteInfoSource::UpdateMode::RealTimeMode) {
156 if (m_device->bytesAvailable()) {
157 if (m_device->isSequential())
160 m_device->seek(m_device->bytesAvailable());
165 m_updateTimer->stop();
167 if (m_source->updateInterval() > 0) {
169 m_updateTimer =
new QBasicTimer;
170 m_updateTimer->start(m_source->updateInterval(),
this);
174 prepareSourceDevice();
186void QNmeaSatelliteInfoSourcePrivate::requestUpdate(
int msec)
188 if (m_requestTimer && m_requestTimer->isActive())
191 m_satelliteError = QGeoSatelliteInfoSource::NoError;
193 if (msec <= 0 || msec < m_source->minimumUpdateInterval()) {
194 m_source->setError(QGeoSatelliteInfoSource::UpdateTimeoutError);
198 if (!m_requestTimer) {
199 m_requestTimer =
new QTimer(
this);
200 connect(m_requestTimer, SIGNAL(timeout()), SLOT(updateRequestTimeout()));
203 bool initialized = initialize();
205 m_source->setError(QGeoSatelliteInfoSource::UpdateTimeoutError);
209 m_requestTimer->start(msec);
210 prepareSourceDevice();
219void QNmeaSatelliteInfoSourcePrivate::emitPendingUpdate()
221 if (m_pendingUpdate.isValid() && m_pendingUpdate.isFresh()) {
222 m_updateTimeoutSent =
false;
223 m_noUpdateLastInterval =
false;
224 if (!emitUpdated(m_pendingUpdate,
false))
225 m_noUpdateLastInterval =
true;
228 if (m_noUpdateLastInterval && !m_updateTimeoutSent) {
229 m_updateTimeoutSent =
true;
230 m_source->setError(QGeoSatelliteInfoSource::UpdateTimeoutError);
232 m_noUpdateLastInterval =
true;
248bool QNmeaSatelliteInfoSourcePrivate::openSourceDevice()
251 qWarning(
"QNmeaSatelliteInfoSource: no QIODevice data source, call setDevice() first");
255 if (!m_device->isOpen() && !m_device->open(QIODevice::ReadOnly)) {
256 qWarning(
"QNmeaSatelliteInfoSource: cannot open QIODevice data source");
260 connect(m_device, SIGNAL(aboutToClose()), SLOT(sourceDataClosed()));
261 connect(m_device, SIGNAL(readChannelFinished()), SLOT(sourceDataClosed()));
262 connect(m_device, SIGNAL(destroyed()), SLOT(sourceDataClosed()));
283void QNmeaSatelliteInfoSourcePrivate::prepareSourceDevice()
286 if (m_updateMode == QNmeaSatelliteInfoSource::UpdateMode::SimulationMode) {
287 if (m_nmeaReader && m_device->bytesAvailable())
288 m_nmeaReader->readAvailableData();
291 if (!m_connectedReadyRead) {
292 connect(m_device, SIGNAL(readyRead()), SLOT(readyRead()));
293 m_connectedReadyRead =
true;
297bool QNmeaSatelliteInfoSourcePrivate::emitUpdated(QNmeaSatelliteInfoUpdate &update,
298 bool fromRequestUpdate)
300 bool emitted =
false;
301 if (!update.isFresh())
305 bool inUseUpdated =
false;
306 bool inViewUpdated =
false;
307 if (!fromRequestUpdate) {
310 for (
auto it = update.m_satellites.cbegin(); it != update.m_satellites.cend(); ++it) {
312 it->satellitesInUse != m_lastUpdate.m_satellites[it.key()].satellitesInUse;
314 it->satellitesInView != m_lastUpdate.m_satellites[it.key()].satellitesInView;
320 inViewUpdated =
true;
323 m_lastUpdate = update;
324 if (update.m_validInUse && inUseUpdated) {
325 emit m_source->satellitesInUseUpdated(update.allSatellitesInUse());
328 if (update.m_validInView && inViewUpdated) {
329 emit m_source->satellitesInViewUpdated(update.allSatellitesInView());
496bool QNmeaSatelliteInfoSource::setBackendProperty(
const QString &name,
const QVariant &value)
498 if (name == SimulationUpdateInterval && d->m_updateMode == UpdateMode::SimulationMode) {
500 const int interval = value.toInt(&ok);
502 auto *reader =
dynamic_cast<QNmeaSatelliteSimulationReader *>(d->m_nmeaReader.get());
504 reader->setUpdateInterval(interval);
507 d->m_simulationUpdateInterval = interval;
518QVariant QNmeaSatelliteInfoSource::backendProperty(
const QString &name)
const
520 if (name == SimulationUpdateInterval && d->m_updateMode == UpdateMode::SimulationMode) {
521 auto *reader =
dynamic_cast<QNmeaSatelliteSimulationReader *>(d->m_nmeaReader.get());
523 return reader->updateInterval();
525 return d->m_simulationUpdateInterval;
582QNmeaSatelliteInfoSource::parseSatellitesInUseFromNmea(QByteArrayView data,
583 QList<
int> &pnrsInUse)
585#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
586 return parseSatellitesInUseFromNmea(data.data(),
static_cast<
int>(data.size()), pnrsInUse);
588 return QLocationUtils::getSatInUseFromNmea(data, pnrsInUse);
629 QLocationUtils::getSatInfoFromNmea(QByteArrayView{data, size}, infos, system));
631 return parseSatelliteInfoFromNmea(QByteArrayView{data, size}, infos, system);
637QNmeaSatelliteInfoSource::parseSatelliteInfoFromNmea(QByteArrayView data,
638 QList<QGeoSatelliteInfo> &infos,
639 QGeoSatelliteInfo::SatelliteSystem &system)
641#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
642 return parseSatelliteInfoFromNmea(data.data(),
static_cast<
int>(data.size()), infos, system);
644 return static_cast<SatelliteInfoParseStatus>(
645 QLocationUtils::getSatInfoFromNmea(data, infos, system));
649void QNmeaSatelliteInfoSource::setError(QGeoSatelliteInfoSource::Error satelliteError)
651 d->m_satelliteError = satelliteError;
652 if (d->m_satelliteError != QGeoSatelliteInfoSource::NoError)
653 emit QGeoSatelliteInfoSource::errorOccurred(satelliteError);
672void QNmeaSatelliteInfoUpdate::setSatellitesInView(QGeoSatelliteInfo::SatelliteSystem system,
673 const QList<QGeoSatelliteInfo> &inView)
675 auto &info = m_satellites[system];
676 info.updatingGSV =
false;
678 info.satellitesInView = inView;
679 info.validInView =
true;
681 if (!info.satellitesInUseReceived) {
690 info.satellitesInUse.clear();
691 info.inUseIds.clear();
692 info.validInUse =
true;
694 info.satellitesInUseReceived =
false;
696 if (info.satellitesInView.isEmpty()) {
701 info.satellitesInUse.clear();
702 info.inUseIds.clear();
703 info.validInUse =
true;
704 }
else if (!info.inUseIds.isEmpty()) {
707 info.satellitesInUse.clear();
708 info.validInUse =
false;
709 bool corrupt =
false;
710 for (
const auto id : info.inUseIds) {
712 for (
const auto &s : info.satellitesInView) {
713 if (s.satelliteIdentifier() == id) {
714 info.satellitesInUse.append(s);
722 info.satellitesInUse.clear();
727 info.validInUse = !corrupt;
728 info.inUseIds.clear();
731 m_validInUse = calculateValidInUse();
732 m_validInView = calculateValidInView();
736bool QNmeaSatelliteInfoUpdate::setSatellitesInUse(QGeoSatelliteInfo::SatelliteSystem system,
737 const QList<
int> &inUse)
739 if (system == QGeoSatelliteInfo::Undefined || system == QGeoSatelliteInfo::Multiple)
742 SatelliteInfo &info = m_satellites[system];
743 info.satellitesInUse.clear();
745 info.satellitesInUseReceived =
true;
746 info.inUseIds = inUse;
748 if (info.updatingGSV) {
749 info.validInView =
false;
750 m_validInView =
false;
754 for (
const auto id : inUse) {
756 for (
const auto &s : info.satellitesInView) {
757 if (s.satelliteIdentifier() == id) {
758 info.satellitesInUse.append(s);
765 info.satellitesInView.clear();
766 info.validInView =
false;
767 m_validInView =
false;
772 info.inUseIds.clear();
774 info.validInUse =
true;
776 m_validInUse = calculateValidInUse();
849QNmeaSatelliteSimulationReader::QNmeaSatelliteSimulationReader(QNmeaSatelliteInfoSourcePrivate *sourcePrivate)
850 : QNmeaSatelliteReader(sourcePrivate)
852 m_timer.reset(
new QTimer);
853 QObject::connect(m_timer.get(), &QTimer::timeout, m_timer.get(), [
this]() {
857 qMax(m_proxy->m_simulationUpdateInterval, m_proxy->m_source->minimumUpdateInterval());
860void QNmeaSatelliteSimulationReader::readAvailableData()
862 if (!m_timer->isActive()) {
867 m_timer->start(m_updateInterval);
876 int numSatInUseMsgs = 0;
877 int numSatInViewMsgs = 0;
878 while (!m_proxy->m_device->atEnd() && (!numSatInUseMsgs || !numSatInViewMsgs)) {
879 m_proxy->processNmeaData(m_proxy->m_pendingUpdate);
880 if (m_proxy->m_pendingUpdate.m_validInUse)
882 if (m_proxy->m_pendingUpdate.m_validInView)
888 if (numSatInUseMsgs > 2 || numSatInViewMsgs > 2) {
889 const QString msgType = (numSatInUseMsgs > numSatInViewMsgs)
890 ? QStringLiteral(
"GSA")
891 : QStringLiteral(
"GSV");
892 qWarning() <<
"nmea simulation reader: possibly incorrect message order. Got too "
894 << msgType <<
"messages";
898 m_proxy->notifyNewUpdate();