QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 "qgslogger.h"
20 #include "qgsgpsconnection.h"
21 #include "qgsnmeaconnection.h"
22 #include "qgsgpsdconnection.h"
23 #include "qgssettings.h"
24 
25 #if defined(HAVE_QT_MOBILITY_LOCATION ) || defined(QT_POSITIONING_LIB)
27 #endif
28 
29 #include <QStringList>
30 #include <QFileInfo>
31 #include <QTimer>
32 
33 #if defined( HAVE_QT5SERIALPORT )
34 #include <QSerialPortInfo>
35 #include <QSerialPort>
36 #endif
37 
38 QList< QPair<QString, QString> > QgsGpsDetector::availablePorts()
39 {
40  QList< QPair<QString, QString> > devs;
41 
42  // try local QtLocation first
43 #if defined(HAVE_QT_MOBILITY_LOCATION ) || defined(QT_POSITIONING_LIB)
44  devs << QPair<QString, QString>( QStringLiteral( "internalGPS" ), tr( "internal GPS" ) );
45 #endif
46 
47  // try local gpsd first
48  devs << QPair<QString, QString>( QStringLiteral( "localhost:2947:" ), tr( "local gpsd" ) );
49 
50  // try serial ports
51 #if defined( HAVE_QT5SERIALPORT )
52  for ( auto p : QSerialPortInfo::availablePorts() )
53  {
54  devs << QPair<QString, QString>( p.portName(), tr( "%1: %2" ).arg( p.portName(), p.description() ) );
55  }
56 #endif
57 
58  return devs;
59 }
60 
61 QgsGpsDetector::QgsGpsDetector( const QString &portName )
62 {
63 #if defined( HAVE_QT5SERIALPORT )
64  mBaudList << QSerialPort::Baud4800 << QSerialPort::Baud9600 << QSerialPort::Baud38400 << QSerialPort::Baud57600 << QSerialPort::Baud115200; //add 57600 for SXBlueII GPS unit
65 #endif
66 
67  if ( portName.isEmpty() )
68  {
69  mPortList = availablePorts();
70  }
71  else
72  {
73  mPortList << QPair<QString, QString>( portName, portName );
74  }
75 }
76 
78 
80 {
81  mConn.reset();
82 
83  QgsSettings settings;
84 
85  while ( !mConn )
86  {
87  mBaudIndex++;
88  if ( mBaudIndex == mBaudList.size() )
89  {
90  mBaudIndex = 0;
91  mPortIndex++;
92  }
93 
94  if ( mPortIndex == mPortList.size() )
95  {
96  emit detectionFailed();
97  deleteLater();
98  return;
99  }
100 
101  if ( mPortList.at( mPortIndex ).first.contains( ':' ) )
102  {
103  mBaudIndex = mBaudList.size() - 1;
104 
105  QStringList gpsParams = mPortList.at( mPortIndex ).first.split( ':' );
106 
107  Q_ASSERT( gpsParams.size() >= 3 );
108 
109  mConn = std::make_unique< QgsGpsdConnection >( gpsParams[0], gpsParams[1].toShort(), gpsParams[2] );
110  }
111  else if ( mPortList.at( mPortIndex ).first.contains( QLatin1String( "internalGPS" ) ) )
112  {
113 #if defined(HAVE_QT_MOBILITY_LOCATION ) || defined(QT_POSITIONING_LIB)
114  mConn = std::make_unique< QgsQtLocationConnection >();
115 #else
116  qWarning( "QT_MOBILITY_LOCATION not found and mPortList matches internalGPS, this should never happen" );
117 #endif
118  }
119  else
120  {
121 #if defined( HAVE_QT5SERIALPORT )
122  std::unique_ptr< QSerialPort > serial = std::make_unique< QSerialPort >( mPortList.at( mPortIndex ).first );
123 
124  serial->setBaudRate( mBaudList[ mBaudIndex ] );
125 
126  serial->setFlowControl( settings.enumValue( QStringLiteral( "gps/flow_control" ), QSerialPort::NoFlowControl, QgsSettings::Core ) );
127  serial->setParity( settings.enumValue( QStringLiteral( "gps/parity" ), QSerialPort::NoParity, QgsSettings::Core ) );
128  serial->setDataBits( settings.enumValue( QStringLiteral( "gps/data_bits" ), QSerialPort::Data8, QgsSettings::Core ) );
129  serial->setStopBits( settings.enumValue( QStringLiteral( "gps/stop_bits" ), QSerialPort::OneStop, QgsSettings::Core ) );
130 
131  if ( serial->open( QIODevice::ReadOnly ) )
132  {
133  mConn = std::make_unique< QgsNmeaConnection >( serial.release() );
134  }
135 #else
136  qWarning( "QT5SERIALPORT not found and mPortList matches serial port, this should never happen" );
137 #endif
138  }
139  }
140 
141  connect( mConn.get(), &QgsGpsConnection::stateChanged, this, static_cast < void ( QgsGpsDetector::* )( const QgsGpsInformation & ) >( &QgsGpsDetector::detected ) );
142  connect( mConn.get(), &QObject::destroyed, this, &QgsGpsDetector::connDestroyed );
143 
144  // leave 2s to pickup a valid string
145  QTimer::singleShot( 2000, this, &QgsGpsDetector::advance );
146 }
147 
149 {
150  Q_UNUSED( info )
151 
152  if ( !mConn )
153  {
154  // advance if connection was destroyed
155  advance();
156  }
157  else if ( mConn->status() == QgsGpsConnection::GPSDataReceived )
158  {
159  // signal detected
160 
161  // let's hope there's a single, unique connection to this signal... otherwise... boom
162  emit detected( mConn.release() );
163 
164  deleteLater();
165  }
166 }
167 
168 void QgsGpsDetector::connDestroyed( QObject *obj )
169 {
170  // WTF? This whole class needs re-writing...
171  if ( obj == mConn.get() )
172  {
173  mConn.release();
174  }
175 }
void stateChanged(const QgsGpsInformation &info)
Class to detect the GPS port.
~QgsGpsDetector() override
void connDestroyed(QObject *)
void detected(const QgsGpsInformation &)
static QList< QPair< QString, QString > > availablePorts()
QgsGpsDetector(const QString &portName)
void detectionFailed()
Encapsulates information relating to a GPS position fix.