QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
qgsgpsdetector.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgpsdetector.cpp - description
3 --------------------
4 begin : January 13th, 2009
5 copyright : (C) 2009 by Juergen E. Fischer
6 email : jef at norbit dot de
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsgpsdetector.h"
19#include "moc_qgsgpsdetector.cpp"
20#include "qgsgpsconnection.h"
21#include "qgsnmeaconnection.h"
22#include "qgsgpsdconnection.h"
23#include "qgssettingstree.h"
25#include "qgslogger.h"
26
27#if defined(QT_POSITIONING_LIB)
29#endif
30
31#include <QStringList>
32#include <QFileInfo>
33#include <QTimer>
34
35#if defined( HAVE_QTSERIALPORT )
36#include <QSerialPortInfo>
37#include <QSerialPort>
38
39const QgsSettingsEntryEnumFlag<QSerialPort::FlowControl> *QgsGpsDetector::settingsGpsFlowControl = new QgsSettingsEntryEnumFlag<QSerialPort::FlowControl>( QStringLiteral( "flow-control" ), QgsSettingsTree::sTreeGps, QSerialPort::NoFlowControl );
40const QgsSettingsEntryEnumFlag<QSerialPort::StopBits> *QgsGpsDetector::settingsGpsStopBits = new QgsSettingsEntryEnumFlag<QSerialPort::StopBits>( QStringLiteral( "stop-bits" ), QgsSettingsTree::sTreeGps, QSerialPort::OneStop );
41const QgsSettingsEntryEnumFlag<QSerialPort::DataBits> *QgsGpsDetector::settingsGpsDataBits = new QgsSettingsEntryEnumFlag<QSerialPort::DataBits>( QStringLiteral( "data-bits" ), QgsSettingsTree::sTreeGps, QSerialPort::Data8 );
42const QgsSettingsEntryEnumFlag<QSerialPort::Parity> *QgsGpsDetector::settingsGpsParity = new QgsSettingsEntryEnumFlag<QSerialPort::Parity>( QStringLiteral( "parity" ), QgsSettingsTree::sTreeGps, QSerialPort::NoParity );
43#endif
44
45QList< QPair<QString, QString> > QgsGpsDetector::availablePorts()
46{
47 QList< QPair<QString, QString> > devs;
48
49 // try local QtLocation first
50#if defined(QT_POSITIONING_LIB)
51 devs << QPair<QString, QString>( QStringLiteral( "internalGPS" ), tr( "internal GPS" ) );
52#endif
53
54 // try local gpsd first
55 devs << QPair<QString, QString>( QStringLiteral( "localhost:2947:" ), tr( "local gpsd" ) );
56
57 // try serial ports
58#if defined( HAVE_QTSERIALPORT )
59 for ( const QSerialPortInfo &p : QSerialPortInfo::availablePorts() )
60 {
61 devs << QPair<QString, QString>( p.portName(), tr( "%1: %2" ).arg( p.portName(), p.description() ) );
62 }
63#endif
64
65 return devs;
66}
67
68QgsGpsDetector::QgsGpsDetector( const QString &portName, bool useUnsafeSignals )
69 : mUseUnsafeSignals( useUnsafeSignals )
70{
71#if defined( HAVE_QTSERIALPORT )
72 mBaudList << QSerialPort::Baud4800 << QSerialPort::Baud9600 << QSerialPort::Baud38400 << QSerialPort::Baud57600 << QSerialPort::Baud115200; //add 57600 for SXBlueII GPS unit
73#endif
74
75 if ( portName.isEmpty() )
76 {
77 QgsDebugMsgLevel( QStringLiteral( "Attempting to autodetect GPS connection" ), 2 );
78 mPortList = availablePorts();
79 }
80 else
81 {
82 QgsDebugMsgLevel( QStringLiteral( "Attempting GPS connection for %1" ).arg( portName ), 2 );
83 mPortList << QPair<QString, QString>( portName, portName );
84 }
85
86 mTimeoutTimer = new QTimer( this );
87 mTimeoutTimer->setSingleShot( true );
88 connect( mTimeoutTimer, &QTimer::timeout, this, &QgsGpsDetector::connectionTimeout );
89}
90
92{
93 QgsDebugMsgLevel( QStringLiteral( "Destroying GPS detector" ), 2 );
94}
95
97{
98 if ( mUseUnsafeSignals )
99 {
100 QgsDebugError( QStringLiteral( "QgsGpsDetector::takeConnection() incorrectly called when useUnsafeSignals option is in effect" ) );
101 return nullptr;
102 }
103
104 if ( mConn )
105 {
106 // this is NOT the detectors connection anymore, so disconnect all signals from the connection
107 // to the detector so that there's no unwanted interaction with the detector
108 mConn->disconnect( this );
109 }
110
111#ifdef QGISDEBUG
112 if ( mConn )
113 {
114 QgsDebugMsgLevel( QStringLiteral( "Detected GPS connection is being taken by caller" ), 2 );
115 }
116 else
117 {
118 QgsDebugError( QStringLiteral( "Something is trying to take the GPS connection, but it doesn't exist!" ) );
119 }
120#endif
121
122 return mConn.release();
123}
124
126{
127 if ( mConn )
128 {
129 QgsDebugMsgLevel( QStringLiteral( "Destroying existing connection to attempt next configuration combination" ), 2 );
130 mConn.reset();
131 }
132
133 QgsDebugMsgLevel( QStringLiteral( "Trying to find a connection..." ), 2 );
134
135 while ( !mConn )
136 {
137 mBaudIndex++;
138 if ( mBaudIndex == mBaudList.size() )
139 {
140 mBaudIndex = 0;
141 mPortIndex++;
142 }
143
144 if ( mPortIndex == mPortList.size() )
145 {
146 QgsDebugError( QStringLiteral( "No more devices to try!" ) );
147 emit detectionFailed();
148 deleteLater();
149 return;
150 }
151
152 QgsDebugMsgLevel( QStringLiteral( "Attempting connection to device %1 @ %2" ).arg( mPortIndex ).arg( mBaudIndex ), 2 );
153
154 if ( mPortList.at( mPortIndex ).first.contains( ':' ) )
155 {
156 mBaudIndex = mBaudList.size() - 1;
157
158 QStringList gpsParams = mPortList.at( mPortIndex ).first.split( ':' );
159
160 Q_ASSERT( gpsParams.size() >= 3 );
161 QgsDebugMsgLevel( QStringLiteral( "Connecting to GPSD device %1" ).arg( gpsParams.join( ',' ) ), 2 );
162
163 mConn = std::make_unique< QgsGpsdConnection >( gpsParams[0], gpsParams[1].toShort(), gpsParams[2] );
164 }
165 else if ( mPortList.at( mPortIndex ).first.contains( QLatin1String( "internalGPS" ) ) )
166 {
167#if defined(QT_POSITIONING_LIB)
168 QgsDebugMsgLevel( QStringLiteral( "Connecting to QtLocation service device" ), 2 );
169 mConn = std::make_unique< QgsQtLocationConnection >();
170#else
171 QgsDebugError( QStringLiteral( "QT_POSITIONING_LIB not found and mPortList matches internalGPS, this should never happen" ) );
172 qWarning( "QT_POSITIONING_LIB not found and mPortList matches internalGPS, this should never happen" );
173#endif
174 }
175 else
176 {
177#if defined( HAVE_QTSERIALPORT )
178 std::unique_ptr< QSerialPort > serial = std::make_unique< QSerialPort >( mPortList.at( mPortIndex ).first );
179
180 serial->setBaudRate( mBaudList[ mBaudIndex ] );
181
182 serial->setFlowControl( QgsGpsDetector::settingsGpsFlowControl->value() );
183 serial->setParity( QgsGpsDetector::settingsGpsParity->value() );
184 serial->setDataBits( QgsGpsDetector::settingsGpsDataBits->value() );
185 serial->setStopBits( QgsGpsDetector::settingsGpsStopBits->value() );
186
187 QgsDebugMsgLevel( QStringLiteral( "Connecting to serial GPS device %1 (@ %2)" ).arg( mPortList.at( mPortIndex ).first ).arg( mBaudList[ mBaudIndex ] ), 2 );
188
189 if ( serial->open( QIODevice::ReadOnly ) )
190 {
191 QgsDebugMsgLevel( QStringLiteral( "Successfully opened, have a port connection ready" ), 2 );
192 mConn = std::make_unique< QgsNmeaConnection >( serial.release() );
193 }
194 else
195 {
196 QgsDebugError( QStringLiteral( "Serial port could NOT be opened" ) );
197 }
198#else
199 QgsDebugError( QStringLiteral( "QT5SERIALPORT not found and mPortList matches serial port, this should never happen" ) );
200 qWarning( "QT5SERIALPORT not found and mPortList matches serial port, this should never happen" );
201#endif
202 }
203
204 if ( !mConn )
205 {
206 QgsDebugError( QStringLiteral( "Got to end of connection handling loop, but have no connection!" ) );
207 }
208 }
209
210 QgsDebugMsgLevel( QStringLiteral( "Have a connection, now listening for messages" ), 2 );
211
212 connect( mConn.get(), &QgsGpsConnection::stateChanged, this, qOverload< const QgsGpsInformation & >( &QgsGpsDetector::detected ) );
213 if ( mUseUnsafeSignals )
214 {
215 connect( mConn.get(), &QObject::destroyed, this, &QgsGpsDetector::connDestroyed );
216 }
217
218 // leave 2s to pickup a valid string
219 mTimeoutTimer->start( 2000 );
220}
221
223{
224 QgsDebugMsgLevel( QStringLiteral( "Detected information" ), 2 );
225
226 if ( !mConn )
227 {
228 mTimeoutTimer->stop();
229
230 // advance if connection was destroyed
231 QgsDebugError( QStringLiteral( "Got information, but CONNECTION WAS DESTROYED EXTERNALLY!" ) );
232 advance();
233 }
234 else if ( mConn->status() == QgsGpsConnection::GPSDataReceived )
235 {
236 mTimeoutTimer->stop();
237 // stop listening for state changed signals, we've already validated this connection and don't want subsequent calls
238 // to QgsGpsDetector::detected being made
239 disconnect( mConn.get(), &QgsGpsConnection::stateChanged, this, qOverload< const QgsGpsInformation & >( &QgsGpsDetector::detected ) );
240
241 // signal detected
242 QgsDebugMsgLevel( QStringLiteral( "Connection status IS GPSDataReceived" ), 2 );
243
244 if ( mUseUnsafeSignals )
245 {
246 // let's hope there's a single, unique connection to this signal... otherwise... boom!
248 emit detected( mConn.release() );
250 }
251 else
252 {
253 emit connectionDetected();
254 }
255
256 deleteLater();
257 }
258 else
259 {
260 // don't stop timeout, we keep waiting to see if later we get the desired connection status...
261 QgsDebugMsgLevel( QStringLiteral( "Connection status is NOT GPSDataReceived. It is %1" ).arg( mConn->status() ), 2 );
262 }
263}
264
265void QgsGpsDetector::connectionTimeout()
266{
267 QgsDebugMsgLevel( QStringLiteral( "No data received within max listening time" ), 2 );
268 advance();
269}
270
272{
273 QgsDebugError( QStringLiteral( "CONNECTION WAS DESTROYED EXTERNALLY!" ) );
274
275 // WTF? This whole class needs re-writing...
276 if ( obj == mConn.get() )
277 {
278 mConn.release(); // cppcheck-suppress ignoredReturnValue
279 }
280}
Abstract base class for connection to a GPS device.
void stateChanged(const QgsGpsInformation &info)
Emitted whenever the GPS state is changed.
~QgsGpsDetector() override
void connDestroyed(QObject *)
void detected(const QgsGpsInformation &)
static QList< QPair< QString, QString > > availablePorts()
QgsGpsConnection * takeConnection()
Returns the detected GPS connection, and removes it from the detector.
void connectionDetected()
Emitted when a GPS connection is successfully detected.
QgsGpsDetector(const QString &portName=QString(), bool useUnsafeSignals=true)
Constructor for QgsGpsDetector.
void detectionFailed()
Emitted when the detector could not find a valid GPS connection.
Encapsulates information relating to a GPS position fix.
A template class for enum and flag settings entry.
static QgsSettingsTreeNode * sTreeGps
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:6494
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6493
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38