54void QNmeaSatelliteInfoSourcePrivate::notifyNewUpdate()
56 if (m_pendingUpdate.isValid() && m_pendingUpdate.isFresh()) {
57 if (m_requestTimer && m_requestTimer->isActive()) {
58 m_requestTimer->stop();
59 emitUpdated(m_pendingUpdate,
true);
60 }
else if (m_invokedStart) {
61 if (m_updateTimer && m_updateTimer->isActive()) {
63 if (m_noUpdateLastInterval) {
69 m_noUpdateLastInterval = !emitUpdated(m_pendingUpdate,
false);
75void QNmeaSatelliteInfoSourcePrivate::processNmeaData(QNmeaSatelliteInfoUpdate &updateInfo)
78 qint64 size = m_device->readLine(buf,
sizeof(buf));
83 const auto satSystemType = m_source->parseSatellitesInUseFromNmea(QByteArrayView{buf,
static_cast<qsizetype>(size)},
85 if (satSystemType != QGeoSatelliteInfo::Undefined) {
86 const bool res = updateInfo.setSatellitesInUse(satSystemType, satInUse);
87#if USE_SATELLITE_NMEA_PIMPL
89 updateInfo.gsa = QByteArray(buf, size);
90 auto &info = updateInfo.m_satellites[satSystemType];
91 if (!info.satellitesInUse.isEmpty()) {
92 for (
auto &s : info.satellitesInUse) {
93 static_cast<QGeoSatelliteInfoPrivateNmea *>(QGeoSatelliteInfoPrivate::get(s))
94 ->nmeaSentences.append(updateInfo.gsa);
96 for (
auto &s : info.satellitesInView) {
97 static_cast<QGeoSatelliteInfoPrivateNmea *>(QGeoSatelliteInfoPrivate::get(s))
98 ->nmeaSentences.append(updateInfo.gsa);
108 auto systemType = QGeoSatelliteInfo::Undefined;
109 const auto parserStatus = m_source->parseSatelliteInfoFromNmea(
110 QByteArrayView{buf,
static_cast<qsizetype>(size)}, updateInfo.m_satellitesInViewParsed, systemType);
111 if (parserStatus == QNmeaSatelliteInfoSource::PartiallyParsed) {
112 updateInfo.m_satellites[systemType].updatingGSV =
true;
113#if USE_SATELLITE_NMEA_PIMPL
114 updateInfo.gsv.append(QByteArray(buf, size));
116 }
else if (parserStatus == QNmeaSatelliteInfoSource::FullyParsed) {
117#if USE_SATELLITE_NMEA_PIMPL
118 updateInfo.gsv.append(QByteArray(buf, size));
119 for (
int i = 0; i < updateInfo.m_satellitesInViewParsed.size(); i++) {
120 const QGeoSatelliteInfo &s = updateInfo.m_satellitesInViewParsed.at(i);
121 QGeoSatelliteInfoPrivateNmea *pimpl =
122 new QGeoSatelliteInfoPrivateNmea(*QGeoSatelliteInfoPrivate::get(s));
123 pimpl->nmeaSentences.append(updateInfo.gsa);
124 pimpl->nmeaSentences.append(updateInfo.gsv);
125 updateInfo.m_satellitesInViewParsed.replace(i, QGeoSatelliteInfo(*pimpl));
127 updateInfo.gsv.clear();
129 updateInfo.setSatellitesInView(systemType, updateInfo.m_satellitesInViewParsed);
139void QNmeaSatelliteInfoSourcePrivate::startUpdates()
144 m_satelliteError = QGeoSatelliteInfoSource::NoError;
146 m_invokedStart =
true;
147 m_pendingUpdate.clear();
148 m_noUpdateLastInterval =
false;
150 bool initialized = initialize();
154 if (m_updateMode == QNmeaSatelliteInfoSource::UpdateMode::RealTimeMode) {
157 if (m_device->bytesAvailable()) {
158 if (m_device->isSequential())
161 m_device->seek(m_device->bytesAvailable());
166 m_updateTimer->stop();
168 if (m_source->updateInterval() > 0) {
170 m_updateTimer =
new QBasicTimer;
171 m_updateTimer->start(m_source->updateInterval(),
this);
175 prepareSourceDevice();
187void QNmeaSatelliteInfoSourcePrivate::requestUpdate(
int msec)
189 if (m_requestTimer && m_requestTimer->isActive())
192 m_satelliteError = QGeoSatelliteInfoSource::NoError;
194 if (msec <= 0 || msec < m_source->minimumUpdateInterval()) {
195 m_source->setError(QGeoSatelliteInfoSource::UpdateTimeoutError);
199 if (!m_requestTimer) {
200 m_requestTimer =
new QTimer(
this);
201 connect(m_requestTimer, SIGNAL(timeout()), SLOT(updateRequestTimeout()));
204 bool initialized = initialize();
206 m_source->setError(QGeoSatelliteInfoSource::UpdateTimeoutError);
210 m_requestTimer->start(msec);
211 prepareSourceDevice();
220void QNmeaSatelliteInfoSourcePrivate::emitPendingUpdate()
222 if (m_pendingUpdate.isValid() && m_pendingUpdate.isFresh()) {
223 m_updateTimeoutSent =
false;
224 m_noUpdateLastInterval =
false;
225 if (!emitUpdated(m_pendingUpdate,
false))
226 m_noUpdateLastInterval =
true;
229 if (m_noUpdateLastInterval && !m_updateTimeoutSent) {
230 m_updateTimeoutSent =
true;
231 m_source->setError(QGeoSatelliteInfoSource::UpdateTimeoutError);
233 m_noUpdateLastInterval =
true;
249bool QNmeaSatelliteInfoSourcePrivate::openSourceDevice()
252 qWarning(
"QNmeaSatelliteInfoSource: no QIODevice data source, call setDevice() first");
256 if (!m_device->isOpen() && !m_device->open(QIODevice::ReadOnly)) {
257 qWarning(
"QNmeaSatelliteInfoSource: cannot open QIODevice data source");
261 connect(m_device, SIGNAL(aboutToClose()), SLOT(sourceDataClosed()));
262 connect(m_device, SIGNAL(readChannelFinished()), SLOT(sourceDataClosed()));
263 connect(m_device, SIGNAL(destroyed()), SLOT(sourceDataClosed()));
284void QNmeaSatelliteInfoSourcePrivate::prepareSourceDevice()
287 if (m_updateMode == QNmeaSatelliteInfoSource::UpdateMode::SimulationMode) {
288 if (m_nmeaReader && m_device->bytesAvailable())
289 m_nmeaReader->readAvailableData();
292 if (!m_connectedReadyRead) {
293 connect(m_device, SIGNAL(readyRead()), SLOT(readyRead()));
294 m_connectedReadyRead =
true;
298bool QNmeaSatelliteInfoSourcePrivate::emitUpdated(QNmeaSatelliteInfoUpdate &update,
299 bool fromRequestUpdate)
301 bool emitted =
false;
302 if (!update.isFresh())
306 bool inUseUpdated =
false;
307 bool inViewUpdated =
false;
308 if (!fromRequestUpdate) {
311 for (
auto it = update.m_satellites.cbegin(); it != update.m_satellites.cend(); ++it) {
313 it->satellitesInUse != m_lastUpdate.m_satellites[it.key()].satellitesInUse;
315 it->satellitesInView != m_lastUpdate.m_satellites[it.key()].satellitesInView;
321 inViewUpdated =
true;
324 m_lastUpdate = update;
325 if (update.m_validInUse && inUseUpdated) {
326 emit m_source->satellitesInUseUpdated(update.allSatellitesInUse());
329 if (update.m_validInView && inViewUpdated) {
330 emit m_source->satellitesInViewUpdated(update.allSatellitesInView());
497bool QNmeaSatelliteInfoSource::setBackendProperty(
const QString &name,
const QVariant &value)
499 if (name == SimulationUpdateInterval && d->m_updateMode == UpdateMode::SimulationMode) {
501 const int interval = value.toInt(&ok);
503 auto *reader =
dynamic_cast<QNmeaSatelliteSimulationReader *>(d->m_nmeaReader.get());
505 reader->setUpdateInterval(interval);
508 d->m_simulationUpdateInterval = interval;
519QVariant QNmeaSatelliteInfoSource::backendProperty(
const QString &name)
const
521 if (name == SimulationUpdateInterval && d->m_updateMode == UpdateMode::SimulationMode) {
522 auto *reader =
dynamic_cast<QNmeaSatelliteSimulationReader *>(d->m_nmeaReader.get());
524 return reader->updateInterval();
526 return d->m_simulationUpdateInterval;
583QNmeaSatelliteInfoSource::parseSatellitesInUseFromNmea(QByteArrayView data,
584 QList<
int> &pnrsInUse)
586#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
587 return parseSatellitesInUseFromNmea(data.data(),
static_cast<
int>(data.size()), pnrsInUse);
589 return QLocationUtils::getSatInUseFromNmea(data, pnrsInUse);
630 QLocationUtils::getSatInfoFromNmea(QByteArrayView{data, size}, infos, system));
632 return parseSatelliteInfoFromNmea(QByteArrayView{data, size}, infos, system);
638QNmeaSatelliteInfoSource::parseSatelliteInfoFromNmea(QByteArrayView data,
639 QList<QGeoSatelliteInfo> &infos,
640 QGeoSatelliteInfo::SatelliteSystem &system)
642#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
643 return parseSatelliteInfoFromNmea(data.data(),
static_cast<
int>(data.size()), infos, system);
645 return static_cast<SatelliteInfoParseStatus>(
646 QLocationUtils::getSatInfoFromNmea(data, infos, system));
650void QNmeaSatelliteInfoSource::setError(QGeoSatelliteInfoSource::Error satelliteError)
652 d->m_satelliteError = satelliteError;
653 if (d->m_satelliteError != QGeoSatelliteInfoSource::NoError)
654 emit QGeoSatelliteInfoSource::errorOccurred(satelliteError);
673void QNmeaSatelliteInfoUpdate::setSatellitesInView(QGeoSatelliteInfo::SatelliteSystem system,
674 const QList<QGeoSatelliteInfo> &inView)
676 auto &info = m_satellites[system];
677 info.updatingGSV =
false;
679 info.satellitesInView = inView;
680 info.validInView =
true;
682 if (!info.satellitesInUseReceived) {
691 info.satellitesInUse.clear();
692 info.inUseIds.clear();
693 info.validInUse =
true;
695 info.satellitesInUseReceived =
false;
697 if (info.satellitesInView.isEmpty()) {
702 info.satellitesInUse.clear();
703 info.inUseIds.clear();
704 info.validInUse =
true;
705 }
else if (!info.inUseIds.isEmpty()) {
708 info.satellitesInUse.clear();
709 info.validInUse =
false;
710 bool corrupt =
false;
711 const auto inUseIds = std::exchange(info.inUseIds, {});
712 for (
const auto id : inUseIds) {
714 for (
const auto &s : std::as_const(info.satellitesInView)) {
715 if (s.satelliteIdentifier() == id) {
716 info.satellitesInUse.append(s);
724 info.satellitesInUse.clear();
729 info.validInUse = !corrupt;
732 m_validInUse = calculateValidInUse();
733 m_validInView = calculateValidInView();
737bool QNmeaSatelliteInfoUpdate::setSatellitesInUse(QGeoSatelliteInfo::SatelliteSystem system,
738 const QList<
int> &inUse)
740 if (system == QGeoSatelliteInfo::Undefined || system == QGeoSatelliteInfo::Multiple)
743 SatelliteInfo &info = m_satellites[system];
744 info.satellitesInUse.clear();
746 info.satellitesInUseReceived =
true;
747 info.inUseIds = inUse;
749 if (info.updatingGSV) {
750 info.validInView =
false;
751 m_validInView =
false;
755 for (
const auto id : inUse) {
757 for (
const auto &s : std::as_const(info.satellitesInView)) {
758 if (s.satelliteIdentifier() == id) {
759 info.satellitesInUse.append(s);
766 info.satellitesInView.clear();
767 info.validInView =
false;
768 m_validInView =
false;
773 info.inUseIds.clear();
775 info.validInUse =
true;
777 m_validInUse = calculateValidInUse();
850QNmeaSatelliteSimulationReader::QNmeaSatelliteSimulationReader(QNmeaSatelliteInfoSourcePrivate *sourcePrivate)
851 : QNmeaSatelliteReader(sourcePrivate)
853 m_timer.reset(
new QTimer);
854 QObject::connect(m_timer.get(), &QTimer::timeout, m_timer.get(), [
this]() {
858 qMax(m_proxy->m_simulationUpdateInterval, m_proxy->m_source->minimumUpdateInterval());
861void QNmeaSatelliteSimulationReader::readAvailableData()
863 if (!m_timer->isActive()) {
868 m_timer->start(m_updateInterval);
877 int numSatInUseMsgs = 0;
878 int numSatInViewMsgs = 0;
879 while (!m_proxy->m_device->atEnd() && (!numSatInUseMsgs || !numSatInViewMsgs)) {
880 m_proxy->processNmeaData(m_proxy->m_pendingUpdate);
881 if (m_proxy->m_pendingUpdate.m_validInUse)
883 if (m_proxy->m_pendingUpdate.m_validInView)
889 if (numSatInUseMsgs > 2 || numSatInViewMsgs > 2) {
890 const QString msgType = (numSatInUseMsgs > numSatInViewMsgs)
891 ? QStringLiteral(
"GSA")
892 : QStringLiteral(
"GSV");
893 qWarning() <<
"nmea simulation reader: possibly incorrect message order. Got too "
895 << msgType <<
"messages";
899 m_proxy->notifyNewUpdate();