diff --git a/external/nmea/parse.c b/external/nmea/parse.c index 79e07d605b3..a7a8456211d 100644 --- a/external/nmea/parse.c +++ b/external/nmea/parse.c @@ -335,6 +335,7 @@ int nmea_parse_GPGSA( const char *buff, int buff_sz, nmeaGPGSA *pack ) int nmea_parse_GPGSV( const char *buff, int buff_sz, nmeaGPGSV *pack ) { int nsen, nsat; + int has_signal_id = 0; NMEA_ASSERT( buff && pack ); @@ -342,29 +343,63 @@ int nmea_parse_GPGSV( const char *buff, int buff_sz, nmeaGPGSV *pack ) nmea_trace_buff( buff, buff_sz ); - nsen = nmea_scanf( buff, buff_sz, - "$%C%CGSV,%d,%d,%d," - "%d,%d,%d,%d," - "%d,%d,%d,%d," - "%d,%d,%d,%d," - "%d,%d,%d,%d*", - &( pack->talkerId[0] ), &( pack->talkerId[1] ), - &( pack->pack_count ), &( pack->pack_index ), &( pack->sat_count ), - &( pack->sat_data[0].id ), &( pack->sat_data[0].elv ), &( pack->sat_data[0].azimuth ), &( pack->sat_data[0].sig ), - &( pack->sat_data[1].id ), &( pack->sat_data[1].elv ), &( pack->sat_data[1].azimuth ), &( pack->sat_data[1].sig ), - &( pack->sat_data[2].id ), &( pack->sat_data[2].elv ), &( pack->sat_data[2].azimuth ), &( pack->sat_data[2].sig ), - &( pack->sat_data[3].id ), &( pack->sat_data[3].elv ), &( pack->sat_data[3].azimuth ), &( pack->sat_data[3].sig ) ); + + // Count the number of fields in the sentence + const char *ptr = buff; + int field_count = 1; + while ( ( ptr = strchr( ptr, ',' ) ) != NULL ) + { + field_count++; + ptr++; + } + + // Check if the number of fields is even, indicating the presence of SIGNAL_ID + has_signal_id = field_count >= 21 ? 1 : 0; + + if ( has_signal_id ) + { + // SIGNAL_ID is present NMEA 4.10 + nsen = nmea_scanf( buff, buff_sz, + "$%C%CGSV,%d,%d,%d," + "%d,%d,%d,%d," + "%d,%d,%d,%d," + "%d,%d,%d,%d," + "%d,%d,%d,%d,%d*", + &( pack->talkerId[0] ), &( pack->talkerId[1] ), + &( pack->pack_count ), &( pack->pack_index ), &( pack->sat_count ), + &( pack->sat_data[0].id ), &( pack->sat_data[0].elv ), &( pack->sat_data[0].azimuth ), &( pack->sat_data[0].sig ), + &( pack->sat_data[1].id ), &( pack->sat_data[1].elv ), &( pack->sat_data[1].azimuth ), &( pack->sat_data[1].sig ), + &( pack->sat_data[2].id ), &( pack->sat_data[2].elv ), &( pack->sat_data[2].azimuth ), &( pack->sat_data[2].sig ), + &( pack->sat_data[3].id ), &( pack->sat_data[3].elv ), &( pack->sat_data[3].azimuth ), &( pack->sat_data[3].sig ), + &( pack->signal_id ) ); + } + else + { + // SIGNAL_ID is not present + nsen = nmea_scanf( buff, buff_sz, + "$%C%CGSV,%d,%d,%d," + "%d,%d,%d,%d," + "%d,%d,%d,%d," + "%d,%d,%d,%d," + "%d,%d,%d,%d*", + &( pack->talkerId[0] ), &( pack->talkerId[1] ), + &( pack->pack_count ), &( pack->pack_index ), &( pack->sat_count ), + &( pack->sat_data[0].id ), &( pack->sat_data[0].elv ), &( pack->sat_data[0].azimuth ), &( pack->sat_data[0].sig ), + &( pack->sat_data[1].id ), &( pack->sat_data[1].elv ), &( pack->sat_data[1].azimuth ), &( pack->sat_data[1].sig ), + &( pack->sat_data[2].id ), &( pack->sat_data[2].elv ), &( pack->sat_data[2].azimuth ), &( pack->sat_data[2].sig ), + &( pack->sat_data[3].id ), &( pack->sat_data[3].elv ), &( pack->sat_data[3].azimuth ), &( pack->sat_data[3].sig ) ); + } nsat = ( pack->pack_index - 1 ) * NMEA_SATINPACK; nsat = ( nsat + NMEA_SATINPACK > pack->sat_count ) ? pack->sat_count - nsat : NMEA_SATINPACK; nsat = nsat * 4 + 3 /* first three sentence`s */; - if ( nsen - 2 < nsat || nsen - 2 > ( NMEA_SATINPACK * 4 + 3 ) ) + int expected_nsen = has_signal_id ? ( NMEA_SATINPACK * 4 + 4 ) : ( NMEA_SATINPACK * 4 + 3 ); + if ( nsen - 2 < nsat || nsen - 2 > expected_nsen ) { nmea_error( "GSV parse error!" ); return 0; } - return 1; } diff --git a/external/nmea/sentence.h b/external/nmea/sentence.h index db1a4c8dd9a..5e3800c5bbc 100644 --- a/external/nmea/sentence.h +++ b/external/nmea/sentence.h @@ -100,6 +100,7 @@ typedef struct _nmeaGPGSV int pack_index; //!< Message number int sat_count; //!< Total number of satellites in view nmeaSATELLITE sat_data[NMEA_SATINPACK]; + char signal_id; //!< NMEA v4.1 - ID of the ranging signal } nmeaGPGSV; diff --git a/src/app/gps/qgsgpsinformationwidget.cpp b/src/app/gps/qgsgpsinformationwidget.cpp index 46640a545e3..9a2d5e313c1 100644 --- a/src/app/gps/qgsgpsinformationwidget.cpp +++ b/src/app/gps/qgsgpsinformationwidget.cpp @@ -43,6 +43,7 @@ #include #include #include +// #include #endif #include @@ -82,18 +83,18 @@ QgsGpsInformationWidget::QgsGpsInformationWidget( QgsAppGpsConnection *connectio // mPlot = new QwtPlot( mpHistogramWidget ); mPlot->setAutoReplot( false ); // plot on demand - //mPlot->setTitle(QObject::tr("Signal Status")); - //mPlot->insertLegend(new QwtLegend(), QwtPlot::BottomLegend); + // mPlot->setTitle(QObject::tr("Signal Status")); + // mPlot->insertLegend(new QwtLegend(), QwtPlot::BottomLegend); // Set axis titles - //mPlot->setAxisTitle(QwtPlot::xBottom, QObject::tr("Satellite")); - //mPlot->setAxisTitle(QwtPlot::yLeft, QObject::tr("Value")); + // mPlot->setAxisTitle(QwtPlot::xBottom, QObject::tr("Satellite")); + // mPlot->setAxisTitle(QwtPlot::yLeft, QObject::tr("Value")); mPlot->setAxisScale( QwtPlot::xBottom, 0, 20 ); mPlot->setAxisScale( QwtPlot::yLeft, 0, 60 ); // max is 50dB SNR, I believe - SLM // add a grid QwtPlotGrid *mGrid = new QwtPlotGrid(); mGrid->enableX( false ); mGrid->attach( mPlot ); - //display satellites first + // display satellites first mCurve = new QwtPlotCurve(); mCurve->setRenderHint( QwtPlotItem::RenderAntialiased ); mCurve->setPen( QPen( Qt::blue ) ); @@ -101,7 +102,7 @@ QgsGpsInformationWidget::QgsGpsInformationWidget( QgsAppGpsConnection *connectio mPlot->enableAxis( QwtPlot::yLeft, true ); mPlot->enableAxis( QwtPlot::xBottom, false ); mCurve->attach( mPlot ); - //ensure all children get removed + // ensure all children get removed mPlot->setAutoDelete( true ); QVBoxLayout *mpHistogramLayout = new QVBoxLayout( mpHistogramWidget ); mpHistogramLayout->setContentsMargins( 0, 0, 0, 0 ); @@ -118,17 +119,17 @@ QgsGpsInformationWidget::QgsGpsInformationWidget( QgsAppGpsConnection *connectio mpSatellitesWidget->setPlotBackground( Qt::white ); // scales mpSatellitesWidget->setScale( QwtPolar::ScaleAzimuth, - 360, //min - reverse the min/max values to get compass orientation - increasing clockwise - 0, //max - 90 //interval - just show cardinal and intermediate (NE, N, NW, etc.) compass points (in degrees) + 360, // min - reverse the min/max values to get compass orientation - increasing clockwise + 0, // max + 90 // interval - just show cardinal and intermediate (NE, N, NW, etc.) compass points (in degrees) ); mpSatellitesWidget->setAzimuthOrigin( M_PI_2 ); // to get compass orientation - need to rotate 90 deg. ccw; this is in Radians (not indicated in QwtPolarPlot docs) - // mpSatellitesWidget->setScaleMaxMinor( QwtPolar::ScaleRadius, 2 ); // seems unnecessary + // mpSatellitesWidget->setScaleMaxMinor( QwtPolar::ScaleRadius, 2 ); // seems unnecessary mpSatellitesWidget->setScale( QwtPolar::ScaleRadius, - 90, //min - reverse the min/max to get 0 at edge, 90 at center - 0, //max - 45 //interval + 90, // min - reverse the min/max to get 0 at edge, 90 at center + 0, // max + 45 // interval ); // grids, axes @@ -138,25 +139,25 @@ QgsGpsInformationWidget::QgsGpsInformationWidget( QgsAppGpsConnection *connectio QPen minorPen( Qt::gray ); // moved outside of for loop; NOTE setting the minor pen isn't necessary if the minor grids aren't shown for ( int scaleId = 0; scaleId < QwtPolar::ScaleCount; scaleId++ ) { - //mpSatellitesGrid->showGrid( scaleId ); - //mpSatellitesGrid->showMinorGrid(scaleId); + // mpSatellitesGrid->showGrid( scaleId ); + // mpSatellitesGrid->showMinorGrid(scaleId); mpSatellitesGrid->setMinorGridPen( scaleId, minorPen ); } - // mpSatellitesGrid->setAxisPen( QwtPolar::AxisAzimuth, QPen( Qt::black ) ); + // mpSatellitesGrid->setAxisPen( QwtPolar::AxisAzimuth, QPen( Qt::black ) ); mpSatellitesGrid->showAxis( QwtPolar::AxisAzimuth, true ); - mpSatellitesGrid->showAxis( QwtPolar::AxisLeft, false ); //alt axis - mpSatellitesGrid->showAxis( QwtPolar::AxisRight, false ); //alt axis - mpSatellitesGrid->showAxis( QwtPolar::AxisTop, false ); //alt axis - mpSatellitesGrid->showAxis( QwtPolar::AxisBottom, false ); //alt axis + mpSatellitesGrid->showAxis( QwtPolar::AxisLeft, false ); // alt axis + mpSatellitesGrid->showAxis( QwtPolar::AxisRight, false ); // alt axis + mpSatellitesGrid->showAxis( QwtPolar::AxisTop, false ); // alt axis + mpSatellitesGrid->showAxis( QwtPolar::AxisBottom, false ); // alt axis mpSatellitesGrid->showGrid( QwtPolar::ScaleAzimuth, false ); // hide the grid; just show ticks at edge mpSatellitesGrid->showGrid( QwtPolar::ScaleRadius, true ); - // mpSatellitesGrid->showMinorGrid( QwtPolar::ScaleAzimuth, true ); + // mpSatellitesGrid->showMinorGrid( QwtPolar::ScaleAzimuth, true ); mpSatellitesGrid->showMinorGrid( QwtPolar::ScaleRadius, true ); // for 22.5, 67.5 degree circles mpSatellitesGrid->attach( mpSatellitesWidget ); - //QwtLegend *legend = new QwtLegend; - //mpSatellitesWidget->insertLegend(legend, QwtPolarPlot::BottomLegend); + // QwtLegend *legend = new QwtLegend; + // mpSatellitesWidget->insertLegend(legend, QwtPolarPlot::BottomLegend); QVBoxLayout *mpPolarLayout = new QVBoxLayout( mpPolarWidget ); mpPolarLayout->setContentsMargins( 0, 0, 0, 0 ); mpPolarLayout->addWidget( mpSatellitesWidget ); @@ -366,41 +367,36 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in { QVector data; - if ( mStackedWidget->currentIndex() == 1 && info.satInfoComplete ) //signal - { - mPlot->setAxisScale( QwtPlot::xBottom, 0, info.satellitesInView.size() ); - } //signal #ifdef WITH_QWTPOLAR - if ( mStackedWidget->currentIndex() == 2 && info.satInfoComplete ) //satellites + if ( mStackedWidget->currentIndex() == 2 && info.satInfoComplete ) // satellites { while ( !mMarkerList.isEmpty() ) { delete mMarkerList.takeFirst(); } - } //satellites + } // satellites #endif - if ( mStackedWidget->currentIndex() == 3 ) //debug + if ( mStackedWidget->currentIndex() == 3 ) // debug { mGPSPlainTextEdit->clear(); - } //debug + } // debug - for ( int i = 0; i < info.satellitesInView.size(); ++i ) //satellite processing loop + for ( int i = 0; i < info.satellitesInView.size(); ++i ) // satellite processing loop { const QgsSatelliteInfo currentInfo = info.satellitesInView.at( i ); - if ( mStackedWidget->currentIndex() == 1 && info.satInfoComplete ) //signal + if ( mStackedWidget->currentIndex() == 1 && info.satInfoComplete ) // signal { data << QPointF( i, 0 ); data << QPointF( i, currentInfo.signal ); data << QPointF( i + 1, currentInfo.signal ); data << QPointF( i + 1, 0 ); - } //signal + } // signal - if ( mStackedWidget->currentIndex() == 2 && info.satInfoComplete ) //satellites + if ( mStackedWidget->currentIndex() == 2 && info.satInfoComplete ) // satellites { QColor bg( Qt::white ); // moved several items outside of the following if block to minimize loop time bg.setAlpha( 200 ); - QColor myColor; // Add a marker to the polar plot if ( currentInfo.id > 0 ) // don't show satellite if id=0 (no satellite indication) @@ -413,22 +409,61 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in mypMarker->setPosition( QwtPointPolar( currentInfo.azimuth, currentInfo.elevation ) ); #endif #endif - if ( currentInfo.signal < 30 ) //weak signal +#ifdef WITH_QWTPOLAR + // QBrush symbolBrush( Qt::black ); + QSize markerSize( 10, 10 ); + QBrush textBgBrush( bg ); + QBrush symbolBrush; + QColor myColor( Qt::black ); + QColor penColor( Qt::black ); + + QwtSymbol::Style symbolStyle; + if ( currentInfo.satType == 'P' ) { - myColor = Qt::red; + symbolStyle = QwtSymbol::Ellipse; // GPS + myColor = QColor( 50, 205, 20 ); // limegreen + } + else if ( currentInfo.satType == 'L' ) + { + symbolStyle = QwtSymbol::Rect; // GLONASS + myColor = QColor( 255, 165, 0 ); // orange + } + else if ( currentInfo.satType == 'B' ) + { + symbolStyle = QwtSymbol::Diamond; // BEIDOU + myColor = QColor( 128, 0, 128 ); // purple + } + else if ( currentInfo.satType == 'A' ) + { + symbolStyle = QwtSymbol::Triangle; // GALILEO + myColor = QColor( 0, 0, 255 ); // blue + } + else if ( currentInfo.satType == 'Q' ) + { + symbolStyle = QwtSymbol::Cross; // QZSS + myColor = QColor( 255, 0, 255 ); // magenta } else { - myColor = Qt::black; //strong signal + symbolStyle = QwtSymbol::Ellipse; // N, S + myColor = QColor( 128, 128, 128 ); // gray } -#ifdef WITH_QWTPOLAR - QBrush symbolBrush( Qt::black ); - QSize markerSize( 9, 9 ); - QBrush textBgBrush( bg ); + penColor = myColor; + symbolBrush = QBrush( myColor ); + + if ( currentInfo.signal < 30 ) // weak signal + { + penColor = Qt::red; // red border + } + if ( currentInfo.inUse ) + { + penColor = Qt::black; // black border + } + #if ( QWT_POLAR_VERSION < 0x010000 ) - mypMarker->setSymbol( QwtSymbol( QwtSymbol::Ellipse, symbolBrush, QPen( myColor ), markerSize ) ); + mypMarker->setSymbol( QwtSymbol( symbolStyle, symbolBrush, QPen( penColor ), markerSize ) ); #else - mypMarker->setSymbol( new QwtSymbol( QwtSymbol::Ellipse, symbolBrush, QPen( myColor ), markerSize ) ); + mypMarker->setSymbol( new QwtSymbol( symbolStyle, symbolBrush, QPen( penColor ), markerSize ) ); #endif mypMarker->setLabelAlignment( Qt::AlignHCenter | Qt::AlignTop ); @@ -440,19 +475,20 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in mMarkerList << mypMarker; #endif } // currentInfo.id > 0 - } //satellites - } //satellite processing loop + } // satellites + } // satellite processing loop - if ( mStackedWidget->currentIndex() == 1 && info.satInfoComplete ) //signal + if ( mStackedWidget->currentIndex() == 1 && info.satInfoComplete ) // signal { + mPlot->setAxisScale( QwtPlot::xBottom, 0, info.satellitesInView.size() ); mCurve->setSamples( data ); mPlot->replot(); - } //signal + } // signal #ifdef WITH_QWTPOLAR - if ( mStackedWidget->currentIndex() == 2 && info.satInfoComplete ) //satellites + if ( mStackedWidget->currentIndex() == 2 && info.satInfoComplete ) // satellites { mpSatellitesWidget->replot(); - } //satellites + } // satellites #endif const bool validFlag = info.isValid(); @@ -466,7 +502,7 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in myNewCenter = mLastGpsPosition; } - if ( mStackedWidget->currentIndex() == 0 ) //position + if ( mStackedWidget->currentIndex() == 0 ) // position { QString formattedX; QString formattedY; @@ -485,7 +521,7 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in } else { - mTxtDateTime->setText( info.utcDateTime.toString( mDateTimeFormat ) ); //user specified format string for testing the millisecond part of time + mTxtDateTime->setText( info.utcDateTime.toString( mDateTimeFormat ) ); // user specified format string for testing the millisecond part of time } if ( std::isfinite( info.speed ) ) { @@ -548,7 +584,7 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in mTxtQuality->setText( info.qualityDescription() ); mTxtSatellitesUsed->setText( tr( "%1 used (%2 in view)" ).arg( info.satellitesUsed ).arg( info.satellitesInView.size() ) ); mTxtStatus->setText( info.status == 'A' ? tr( "Valid" ) : info.status == 'V' ? tr( "Invalid" ) - : QString() ); + : tr( "Other (%1)" ).arg( info.status ) ); } if ( mLastGpsPosition != myNewCenter ) diff --git a/src/core/gps/qgsgpsinformation.cpp b/src/core/gps/qgsgpsinformation.cpp index 374d6abbd77..4341d43d6f5 100644 --- a/src/core/gps/qgsgpsinformation.cpp +++ b/src/core/gps/qgsgpsinformation.cpp @@ -50,16 +50,15 @@ bool QgsGpsInformation::isValid() const { valid = false; } - else if ( status == 'A' + else if ( status == 'A' || status == 'D' || bestFix == Qgis::GpsFixStatus::Fix2D || bestFix == Qgis::GpsFixStatus::Fix3D - || ( qualityIndicator != Qgis::GpsQualityIndicator::Invalid ) ) // good + || ( qualityIndicator != Qgis::GpsQualityIndicator::Invalid ) ) // good - D=Differential for UM98x { valid = true; } valid &= longitude >= -180.0 && longitude <= 180.0 && latitude >= -90.0 && latitude <= 90.0; - return valid; } diff --git a/src/core/gps/qgsnmeaconnection.cpp b/src/core/gps/qgsnmeaconnection.cpp index 8ab1cfb1fb5..3557ee210ce 100644 --- a/src/core/gps/qgsnmeaconnection.cpp +++ b/src/core/gps/qgsnmeaconnection.cpp @@ -1,3 +1,4 @@ + /*************************************************************************** qgsnmeaconnection.cpp - description --------------------- @@ -177,6 +178,11 @@ void QgsNmeaConnection::processStringBuffer() } emit nmeaSentenceReceived( substring ); // added to be able to save raw data } + else + { + //other text strings that do not start with '$' + mLastGPSInformation.satInfoComplete = true; + } } mStringBuffer.remove( 0, endSentenceIndex + 2 ); } @@ -310,7 +316,8 @@ void QgsNmeaConnection::processRmcSentence( const char *data, int len ) // convert mode to signal (aka quality) indicator // (see https://gitlab.com/fhuberts/nmealib/-/blob/master/src/info.c#L27) - if ( result.status == 'A' ) + // UM98x Status == D (Differential) + if ( result.status == 'A' || result.status == 'D' ) { if ( result.mode == 'A' ) { @@ -358,11 +365,12 @@ void QgsNmeaConnection::processRmcSentence( const char *data, int len ) mLastGPSInformation.qualityIndicator = Qgis::GpsQualityIndicator::Unknown; } } - else + else if ( result.status == 'V' ) { mLastGPSInformation.quality = static_cast( Qgis::GpsQualityIndicator::Invalid ); mLastGPSInformation.qualityIndicator = Qgis::GpsQualityIndicator::Invalid; } + // for other cases: quality and qualityIndicator read by GGA } if ( result.navstatus == 'S' ) @@ -441,11 +449,21 @@ void QgsNmeaConnection::processGsvSentence( const char *data, int len ) bool idAlreadyPresent = false; if ( mLastGPSInformation.satellitesInView.size() > NMEA_SATINPACK ) { - for ( const QgsSatelliteInfo &existingSatInView : std::as_const( mLastGPSInformation.satellitesInView ) ) + for ( int i = 0; i < mLastGPSInformation.satellitesInView.size(); ++i ) { + QgsSatelliteInfo &existingSatInView = mLastGPSInformation.satellitesInView[i]; if ( existingSatInView.id == currentSatellite.id ) { idAlreadyPresent = true; + // Signal averaging + if ( existingSatInView.signal == 0 ) + { + existingSatInView.signal = currentSatellite.sig; + } + else if ( currentSatellite.sig != 0 ) + { + existingSatInView.signal = ( existingSatInView.signal + currentSatellite.sig ) / 2; + } break; } }