Skip to content

Commit

Permalink
Move nmea logging responsibility out of gps information widget
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 4, 2022
1 parent 5aeac53 commit aef5865
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 237 deletions.
93 changes: 91 additions & 2 deletions src/app/gps/qgsappgpsdigitizing.cpp
Expand Up @@ -70,6 +70,8 @@ QgsAppGpsDigitizing::QgsAppGpsDigitizing( QgsAppGpsConnection *connection, QgsMa
updateTimestampDestinationFields( mCanvas->currentLayer() );

connect( mConnection, &QgsAppGpsConnection::stateChanged, this, &QgsAppGpsDigitizing::gpsStateChanged );
connect( mConnection, &QgsAppGpsConnection::connected, this, &QgsAppGpsDigitizing::gpsConnected );
connect( mConnection, &QgsAppGpsConnection::disconnected, this, &QgsAppGpsDigitizing::gpsDisconnected );

connect( QgsGui::instance(), &QgsGui::optionsChanged, this, &QgsAppGpsDigitizing::gpsSettingsChanged );
gpsSettingsChanged();
Expand Down Expand Up @@ -325,6 +327,39 @@ void QgsAppGpsDigitizing::setTimeStampDestination( const QString &fieldName )
mTimestampField = fieldName;
}

void QgsAppGpsDigitizing::setNmeaLogFile( const QString &filename )
{
if ( mLogFile )
{
stopLogging();
}

mNmeaLogFile = filename;

if ( mEnableNmeaLogging && !mNmeaLogFile.isEmpty() )
{
startLogging();
}
}

void QgsAppGpsDigitizing::setNmeaLoggingEnabled( bool enabled )
{
if ( enabled == static_cast< bool >( mLogFile ) )
return;

if ( mLogFile && !enabled )
{
stopLogging();
}

mEnableNmeaLogging = enabled;

if ( mEnableNmeaLogging && !mNmeaLogFile.isEmpty() )
{
startLogging();
}
}

void QgsAppGpsDigitizing::gpsSettingsChanged()
{
updateTrackAppearance();
Expand Down Expand Up @@ -405,13 +440,24 @@ void QgsAppGpsDigitizing::switchAcquisition()
}
}

void QgsAppGpsDigitizing::gpsConnected()
{
if ( !mLogFile && mEnableNmeaLogging && !mNmeaLogFile.isEmpty() )
{
startLogging();
}
}

void QgsAppGpsDigitizing::gpsDisconnected()
{
stopLogging();
}

void QgsAppGpsDigitizing::gpsStateChanged( const QgsGpsInformation &info )
{
if ( mBlockGpsStateChanged )
return;

QVector<QPointF> data;

const bool validFlag = info.isValid();
QgsPointXY myNewCenter;
nmeaPOS newNmeaPosition;
Expand Down Expand Up @@ -485,6 +531,49 @@ void QgsAppGpsDigitizing::updateTimestampDestinationFields( QgsMapLayer *mapLaye
emit timeStampDestinationChanged( mTimestampField );
}

void QgsAppGpsDigitizing::logNmeaSentence( const QString &nmeaString )
{
if ( mEnableNmeaLogging && mLogFile && mLogFile->isOpen() )
{
mLogFileTextStream << nmeaString << "\r\n"; // specifically output CR + LF (NMEA requirement)
}
}

void QgsAppGpsDigitizing::startLogging()
{
if ( !mLogFile )
{
mLogFile = std::make_unique< QFile >( mNmeaLogFile );
}

if ( mLogFile->open( QIODevice::Append ) ) // open in binary and explicitly output CR + LF per NMEA
{
mLogFileTextStream.setDevice( mLogFile.get() );

// crude way to separate chunks - use when manually editing file - NMEA parsers should discard
mLogFileTextStream << "====" << "\r\n";

connect( mConnection, &QgsAppGpsConnection::nmeaSentenceReceived, this, &QgsAppGpsDigitizing::logNmeaSentence ); // added to handle raw data
}
else // error opening file
{
mLogFile.reset();

// need to indicate why - this just reports that an error occurred
QgisApp::instance()->messageBar()->pushCritical( QString(), tr( "Error opening log file." ) );
}
}

void QgsAppGpsDigitizing::stopLogging()
{
if ( mLogFile && mLogFile->isOpen() )
{
disconnect( mConnection, &QgsAppGpsConnection::nmeaSentenceReceived, this, &QgsAppGpsDigitizing::logNmeaSentence );
mLogFile->close();
mLogFile.reset();
}
}

void QgsAppGpsDigitizing::createRubberBand()
{
delete mRubberBand;
Expand Down
18 changes: 18 additions & 0 deletions src/app/gps/qgsappgpsdigitizing.h
Expand Up @@ -24,6 +24,7 @@
#include "qgscoordinatetransform.h"
#include "qgsdistancearea.h"
#include "qgis_app.h"
#include <QTextStream>

class QgsAppGpsConnection;
class QgsMapCanvas;
Expand All @@ -32,6 +33,7 @@ class QgsPoint;
class QgsGpsInformation;
class QgsVectorLayer;
class QTimer;
class QFile;

class APP_EXPORT QgsAppGpsDigitizing: public QObject
{
Expand All @@ -52,6 +54,9 @@ class APP_EXPORT QgsAppGpsDigitizing: public QObject

void setTimeStampDestination( const QString &fieldName );

void setNmeaLogFile( const QString &filename );
void setNmeaLoggingEnabled( bool enabled );

signals:

void timeStampDestinationChanged( const QString &fieldName );
Expand All @@ -61,12 +66,19 @@ class APP_EXPORT QgsAppGpsDigitizing: public QObject
void updateTrackAppearance();
void switchAcquisition();

void gpsConnected();
void gpsDisconnected();

void gpsStateChanged( const QgsGpsInformation &info );

/**
* Updates compatible fields for timestamp recording
*/
void updateTimestampDestinationFields( QgsMapLayer *mapLayer );
void logNmeaSentence( const QString &nmeaString ); // added to handle 'raw' data

void startLogging();
void stopLogging();

private:
void createRubberBand();
Expand Down Expand Up @@ -108,6 +120,12 @@ class APP_EXPORT QgsAppGpsDigitizing: public QObject
QMap<QString, QString> mPreferredTimestampFields;
QString mTimestampField;

QString mNmeaLogFile;
bool mEnableNmeaLogging = false;

std::unique_ptr< QFile > mLogFile;
QTextStream mLogFileTextStream;

friend class TestQgsGpsIntegration;
};

Expand Down
36 changes: 35 additions & 1 deletion src/app/gps/qgsappgpssettingsmenu.cpp
Expand Up @@ -16,13 +16,16 @@
#include "qgsappgpssettingsmenu.h"
#include "qgssettings.h"
#include "qgisapp.h"
#include "qgsapplication.h"
#include "qgsfieldproxymodel.h"
#include "qgsfieldmodel.h"
#include "qgsgpsinformationwidget.h"
#include "qgsfileutils.h"
#include "qgsapplication.h"

#include <QRadioButton>
#include <QButtonGroup>
#include <QGridLayout>
#include <QFileDialog>

QgsGpsMapRotationAction::QgsGpsMapRotationAction( QWidget *parent )
: QWidgetAction( parent )
Expand Down Expand Up @@ -181,6 +184,37 @@ QgsAppGpsSettingsMenu::QgsAppGpsSettingsMenu( QWidget *parent )
addMenu( mTimeStampFieldMenu );

addSeparator();

mActionNmeaLog = new QAction( "Log NMEA Sentences…" );
mActionNmeaLog->setCheckable( true );
connect( mActionNmeaLog, &QAction::toggled, this, [ = ]( bool checked )
{
if ( checked )
{
const QString lastLogFolder = QgsGpsInformationWidget::settingLastLogFolder.value();
const QString initialFolder = lastLogFolder.isEmpty() ? QDir::homePath() : lastLogFolder;

QString fileName = QFileDialog::getSaveFileName( this, tr( "GPS Log File" ), initialFolder, tr( "NMEA files" ) + " (*.nmea)" );
if ( fileName.isEmpty() )
{
mActionNmeaLog->setChecked( false );
emit enableNmeaLog( false );
return;
}

fileName = QgsFileUtils::ensureFileNameHasExtension( fileName, { QStringLiteral( "nmea" ) } );
QgsGpsInformationWidget::settingLastLogFolder.setValue( QFileInfo( fileName ).absolutePath() );

emit nmeaLogFileChanged( fileName );
emit enableNmeaLog( true );
}
else
{
emit enableNmeaLog( false );
}
} );
addAction( mActionNmeaLog );

QAction *settingsAction = new QAction( tr( "GPS Settings…" ), this );
settingsAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOptions.svg" ) ) );
connect( settingsAction, &QAction::triggered, this, [ = ]
Expand Down
3 changes: 3 additions & 0 deletions src/app/gps/qgsappgpssettingsmenu.h
Expand Up @@ -78,6 +78,8 @@ class APP_EXPORT QgsAppGpsSettingsMenu : public QMenu
void autoAddTrackPointsChanged( bool enabled );
void autoAddFeatureChanged( bool enabled );
void timeStampDestinationChanged( const QString &fieldName );
void enableNmeaLog( bool enabled );
void nmeaLogFileChanged( const QString &filename );

private slots:

Expand All @@ -90,6 +92,7 @@ class APP_EXPORT QgsAppGpsSettingsMenu : public QMenu
QAction *mRotateMapAction = nullptr;
QAction *mAutoAddTrackPointAction = nullptr;
QAction *mAutoSaveAddedFeatureAction = nullptr;
QAction *mActionNmeaLog = nullptr;

QRadioButton *mRadioAlwaysRecenter = nullptr;
QRadioButton *mRadioRecenterWhenOutside = nullptr;
Expand Down
69 changes: 3 additions & 66 deletions src/app/gps/qgsgpsinformationwidget.cpp
Expand Up @@ -64,26 +64,13 @@ QgsGpsInformationWidget::QgsGpsInformationWidget( QgsAppGpsConnection *connectio
connect( mBtnPosition, &QToolButton::clicked, this, &QgsGpsInformationWidget::mBtnPosition_clicked );
connect( mBtnSignal, &QToolButton::clicked, this, &QgsGpsInformationWidget::mBtnSignal_clicked );
connect( mBtnSatellites, &QToolButton::clicked, this, &QgsGpsInformationWidget::mBtnSatellites_clicked );
connect( mBtnOptions, &QToolButton::clicked, this, &QgsGpsInformationWidget::mBtnOptions_clicked );
connect( mBtnDebug, &QToolButton::clicked, this, &QgsGpsInformationWidget::mBtnDebug_clicked );

mBtnPopupOptions->setAutoRaise( true );
mBtnPopupOptions->setToolTip( tr( "Settings" ) );
mBtnPopupOptions->setMenu( QgisApp::instance()->gpsSettingsMenu() );
mBtnPopupOptions->setPopupMode( QToolButton::InstantPopup );

mLogFilename->setDialogTitle( tr( "GPS Log File" ) );
mLogFilename->setStorageMode( QgsFileWidget::SaveFile );
mLogFilename->setFilter( tr( "NMEA files" ) + " (*.nmea)" );
mLogFilename->lineEdit()->setShowClearButton( false );
const QString lastLogFolder = settingLastLogFolder.value();
mLogFilename->setDefaultRoot( lastLogFolder.isEmpty() ? QDir::homePath() : lastLogFolder );
connect( mLogFilename, &QgsFileWidget::fileChanged, this, [ = ]
{
settingLastLogFolder.setValue( QFileInfo( mLogFilename->filePath() ).absolutePath() );
} );


QWidget *mpHistogramWidget = mStackedWidget->widget( 1 );
#ifndef WITH_QWTPOLAR
mBtnSatellites->setVisible( false );
Expand Down Expand Up @@ -187,10 +174,7 @@ QgsGpsInformationWidget::QgsGpsInformationWidget( QgsAppGpsConnection *connectio
// status = unknown
setStatusIndicator( Qgis::GpsFixStatus::NoData );

//SLM - added functionality
mLogFile = nullptr;

mStackedWidget->setCurrentIndex( 3 ); // force to Options
mStackedWidget->setCurrentIndex( 0 );
mBtnPosition->setFocus( Qt::TabFocusReason );

connect( mConnection, &QgsAppGpsConnection::connecting, this, &QgsGpsInformationWidget::gpsConnecting );
Expand Down Expand Up @@ -256,14 +240,9 @@ void QgsGpsInformationWidget::mBtnSatellites_clicked()
displayGPSInformation( connection->currentGPSInformation() );
}

void QgsGpsInformationWidget::mBtnOptions_clicked()
{
mStackedWidget->setCurrentIndex( 3 );
}

void QgsGpsInformationWidget::mBtnDebug_clicked()
{
mStackedWidget->setCurrentIndex( 4 );
mStackedWidget->setCurrentIndex( 3 );
}

void QgsGpsInformationWidget::mConnectButton_toggled( bool flag )
Expand Down Expand Up @@ -307,44 +286,10 @@ void QgsGpsInformationWidget::timedout()
void QgsGpsInformationWidget::gpsConnected()
{
mGPSPlainTextEdit->appendPlainText( tr( "Connected!" ) );

if ( mLogFileGroupBox->isChecked() && !mLogFilename->filePath().isEmpty() )
{
if ( !mLogFile )
{
mLogFile = new QFile( mLogFilename->filePath() );
}

if ( mLogFile->open( QIODevice::Append ) ) // open in binary and explicitly output CR + LF per NMEA
{
mLogFileTextStream.setDevice( mLogFile );

// crude way to separate chunks - use when manually editing file - NMEA parsers should discard
mLogFileTextStream << "====" << "\r\n";

connect( mConnection, &QgsAppGpsConnection::nmeaSentenceReceived, this, &QgsGpsInformationWidget::logNmeaSentence ); // added to handle raw data
}
else // error opening file
{
delete mLogFile;
mLogFile = nullptr;

// need to indicate why - this just reports that an error occurred
showStatusBarMessage( tr( "Error opening log file." ) );
}
}
}

void QgsGpsInformationWidget::gpsDisconnected()
{
if ( mLogFile && mLogFile->isOpen() )
{
disconnect( mConnection, &QgsAppGpsConnection::nmeaSentenceReceived, this, &QgsGpsInformationWidget::logNmeaSentence );
mLogFile->close();
delete mLogFile;
mLogFile = nullptr;
}

mGPSPlainTextEdit->appendPlainText( tr( "Disconnected…" ) );
}

Expand All @@ -365,7 +310,7 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in
}
} //satellites
#endif
if ( mStackedWidget->currentIndex() == 4 ) //debug
if ( mStackedWidget->currentIndex() == 3 ) //debug
{
mGPSPlainTextEdit->clear();
} //debug
Expand Down Expand Up @@ -541,14 +486,6 @@ void QgsGpsInformationWidget::displayGPSInformation( const QgsGpsInformation &in
}
}

void QgsGpsInformationWidget::logNmeaSentence( const QString &nmeaString )
{
if ( mLogFileGroupBox->isChecked() && mLogFile && mLogFile->isOpen() )
{
mLogFileTextStream << nmeaString << "\r\n"; // specifically output CR + LF (NMEA requirement)
}
}

void QgsGpsInformationWidget::setStatusIndicator( Qgis::GpsFixStatus statusValue )
{
// the pixmap will be expanded to the size of the label
Expand Down

0 comments on commit aef5865

Please sign in to comment.