Skip to content

Commit

Permalink
Update GxGSV NMEA 4.10 - Add Signal averaging - Update gpsinformation…
Browse files Browse the repository at this point in the history
…widget (qgis#58357)

* Add signal_id; //!< NMEA v4.1 - ID of the ranging signal
NMEA RMC - Set qualitydescription only for status: A or V in  processRmcSentence
NMEA GSV - Add Signal averaging processGsvSentence
Update for Status not A, V  - for UM982 Status = D - Differential when it becomes RTKfix
  • Loading branch information
bettellam authored Feb 10, 2025
1 parent c55e712 commit 2027519
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 74 deletions.
63 changes: 49 additions & 14 deletions external/nmea/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,36 +335,71 @@ 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 );

memset( pack, 0, sizeof( nmeaGPGSV ) );

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;
}

Expand Down
1 change: 1 addition & 0 deletions external/nmea/sentence.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
144 changes: 90 additions & 54 deletions src/app/gps/qgsgpsinformationwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <qwt_polar_grid.h>
#include <qwt_polar_curve.h>
#include <qwt_scale_engine.h>
// #include <qwt_symbol.h>
#endif

#include <QMessageBox>
Expand Down Expand Up @@ -82,26 +83,26 @@ 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 ) );
mCurve->setBrush( QBrush( Qt::blue ) );
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 );
Expand All @@ -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
Expand All @@ -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 );
Expand Down Expand Up @@ -366,41 +367,36 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in
{
QVector<QPointF> 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)
Expand All @@ -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' )
{
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' )
{
myColor = Qt::red;
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 );
Expand All @@ -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();
Expand All @@ -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;
Expand All @@ -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 ) )
{
Expand Down Expand Up @@ -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 )
Expand Down
5 changes: 2 additions & 3 deletions src/core/gps/qgsgpsinformation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Loading

0 comments on commit 2027519

Please sign in to comment.