QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GPSProvider.cc
Go to the documentation of this file.
1#include "GPSProvider.h"
3#include "RTCMMavlink.h"
4
5#include <ashtech.h>
6#include <base_station.h>
7#include <definitions.h>
8#include <femtomes.h>
9#include <sbf.h>
10#include <ubx.h>
11
12#ifdef Q_OS_ANDROID
13#include "qserialport.h"
14#else
15#include <QtSerialPort/QSerialPort>
16#endif
17
18QGC_LOGGING_CATEGORY(GPSProviderLog, "GPS.GPSProvider")
19QGC_LOGGING_CATEGORY(GPSDriversLog, "GPS.Drivers")
20
21GPSProvider::GPSProvider(const QString &device, GPSType type, const rtk_data_s &rtkData, const std::atomic_bool &requestStop, QObject *parent)
22 : QThread(parent)
23 , _device(device)
24 , _type(type)
25 , _requestStop(requestStop)
26 , _rtkData(rtkData)
27{
28 // qCDebug(GPSProviderLog) << Q_FUNC_INFO << this;
29
30 qCDebug(GPSProviderLog) << QString("Survey in accuracy: %1 | duration: %2").arg(_rtkData.surveyInAccMeters).arg(_rtkData.surveyInDurationSecs);
31}
32
34{
35 delete _serial;
36
37 // qCDebug(GPSProviderLog) << Q_FUNC_INFO << this;
38}
39
40void GPSProvider::_publishSatelliteInfo()
41{
42 emit satelliteInfoUpdate(_satelliteInfo);
43}
44
45void GPSProvider::_publishSensorGNSSRelative()
46{
47 emit sensorGnssRelativeUpdate(_sensorGnssRelative);
48}
49
50void GPSProvider::_publishSensorGPS()
51{
52 emit sensorGpsUpdate(_sensorGps);
53}
54
55void GPSProvider::_gotRTCMData(const uint8_t *data, size_t len)
56{
57 const QByteArray message(reinterpret_cast<const char*>(data), len);
58 emit RTCMDataUpdate(message);
59}
60
61int GPSProvider::_callbackEntry(GPSCallbackType type, void *data1, int data2, void *user)
62{
63 GPSProvider* const gps = reinterpret_cast<GPSProvider*>(user);
64 return gps->callback(type, data1, data2);
65}
66
67int GPSProvider::callback(GPSCallbackType type, void *data1, int data2)
68{
69 switch (type) {
70 case GPSCallbackType::readDeviceData:
71 if (_serial->bytesAvailable() == 0) {
72 const int timeout = *(reinterpret_cast<int*>(data1));
73 if (!_serial->waitForReadyRead(timeout)) {
74 return 0;
75 }
76 }
77 return _serial->read(reinterpret_cast<char*>(data1), data2);
78 case GPSCallbackType::writeDeviceData:
79 if (_serial->write(reinterpret_cast<char*>(data1), data2) >= 0) {
80 if (_serial->waitForBytesWritten(-1)) {
81 return data2;
82 }
83 }
84 return -1;
85 case GPSCallbackType::setBaudrate:
86 return (_serial->setBaudRate(data2) ? 0 : -1);
87 case GPSCallbackType::gotRTCMMessage:
88 _gotRTCMData(reinterpret_cast<uint8_t*>(data1), data2);
89 break;
90 case GPSCallbackType::surveyInStatus:
91 {
92 const SurveyInStatus* const status = reinterpret_cast<SurveyInStatus*>(data1);
93 qCDebug(GPSProviderLog) << "Position:" << status->latitude << status->longitude << status->altitude;
94
95 const bool valid = status->flags & 1;
96 const bool active = (status->flags >> 1) & 1;
97
98 qCDebug(GPSProviderLog) << QString("Survey-in status: %1s cur accuracy: %2mm valid: %3 active: %4").arg(status->duration).arg(status->mean_accuracy).arg(valid).arg(active);
99 emit surveyInStatus(status->duration, status->mean_accuracy, status->latitude, status->longitude, status->altitude, valid, active);
100 break;
101 }
102 case GPSCallbackType::setClock:
103 case GPSCallbackType::gotRelativePositionMessage:
104 // _sensorGnssRelative
105 default:
106 break;
107 }
108
109 return 0;
110}
111
112void GPSProvider::run()
113{
114#ifdef SIMULATE_RTCM_OUTPUT
115 _sendRTCMData();
116#endif
117
118 _connectSerial();
119
120 GPSBaseStationSupport *gpsDriver = nullptr;
121
122 while (!_requestStop) {
123 if (gpsDriver) {
124 delete gpsDriver;
125 gpsDriver = nullptr;
126 }
127
128 gpsDriver = _connectGPS();
129 if (gpsDriver) {
130 (void) memset(&_sensorGps, 0, sizeof(_sensorGps));
131
132 uint8_t numTries = 0;
133 while (!_requestStop && (numTries < 3)) {
134 const int helperRet = gpsDriver->receive(kGPSReceiveTimeout);
135
136 if (helperRet > 0) {
137 numTries = 0;
138
139 if (helperRet & GPSReceiveType::Position) {
140 _publishSensorGPS();
141 numTries = 0;
142 }
143
144 if (helperRet & GPSReceiveType::Satellite) {
145 _publishSatelliteInfo();
146 numTries = 0;
147 }
148 } else {
149 ++numTries;
150 }
151 }
152
153 if ((_serial->error() != QSerialPort::NoError) && (_serial->error() != QSerialPort::TimeoutError)) {
154 break;
155 }
156 }
157 }
158
159 delete gpsDriver;
160 gpsDriver = nullptr;
161
162 delete _serial;
163 _serial = nullptr;
164
165 qCDebug(GPSProviderLog) << Q_FUNC_INFO << "Exiting GPS thread";
166}
167
168bool GPSProvider::_connectSerial()
169{
170 _serial = new QSerialPort();
171 _serial->setPortName(_device);
172 if (!_serial->open(QIODevice::ReadWrite)) {
173 // Give the device some time to come up. In some cases the device is not
174 // immediately accessible right after startup for some reason. This can take 10-20s.
175 uint32_t retries = 60;
176 while ((retries-- > 0) && (_serial->error() == QSerialPort::PermissionError)) {
177 qCDebug(GPSProviderLog) << "Cannot open device... retrying";
178 msleep(500);
179 if (_serial->open(QIODevice::ReadWrite)) {
180 _serial->clearError();
181 break;
182 }
183 }
184
185 if (_serial->error() != QSerialPort::NoError) {
186 qCWarning(GPSProviderLog) << "GPS: Failed to open Serial Device" << _device << _serial->errorString();
187 return false;
188 }
189 }
190
191 (void) _serial->setBaudRate(QSerialPort::Baud9600);
192 (void) _serial->setDataBits(QSerialPort::Data8);
193 (void) _serial->setParity(QSerialPort::NoParity);
194 (void) _serial->setStopBits(QSerialPort::OneStop);
196
197 return true;
198}
199
200GPSBaseStationSupport *GPSProvider::_connectGPS()
201{
202 GPSBaseStationSupport *gpsDriver = nullptr;
203 uint32_t baudrate = 0;
204 switch(_type) {
205 case GPSType::trimble:
206 gpsDriver = new GPSDriverAshtech(&_callbackEntry, this, &_sensorGps, &_satelliteInfo);
207 baudrate = 115200;
208 break;
210 gpsDriver = new GPSDriverSBF(&_callbackEntry, this, &_sensorGps, &_satelliteInfo, kGPSHeadingOffset);
211 baudrate = 0;
212 break;
213 case GPSType::u_blox:
214 gpsDriver = new GPSDriverUBX(GPSDriverUBX::Interface::UART, &_callbackEntry, this, &_sensorGps, &_satelliteInfo);
215 baudrate = 0;
216 break;
217 case GPSType::femto:
218 gpsDriver = new GPSDriverFemto(&_callbackEntry, this, &_sensorGps, &_satelliteInfo);
219 baudrate = 0;
220 break;
221 default:
222 // GPSDriverEmlidReach, GPSDriverMTK, GPSDriverNMEA
223 qCWarning(GPSProviderLog) << "Unsupported GPS Type:" << static_cast<int>(_type);
224 return nullptr;
225 }
226
227 switch(_rtkData.useFixedBaseLocation){
229 gpsDriver->setBasePosition(_rtkData.fixedBaseLatitude, _rtkData.fixedBaseLongitude, _rtkData.fixedBaseAltitudeMeters, _rtkData.fixedBaseAccuracyMeters * 1000.0f);
230 break;
231
233 default:
234 gpsDriver->setSurveyInSpecs(_rtkData.surveyInAccMeters * 10000.f, _rtkData.surveyInDurationSecs);
235 break;
236 }
237
238 _gpsConfig.output_mode = GPSHelper::OutputMode::RTCM;
239
240 if (gpsDriver->configure(baudrate, _gpsConfig) != 0) {
241 return nullptr;
242 }
243
244 return gpsDriver;
245}
246
247void GPSProvider::_sendRTCMData()
248{
249 RTCMMavlink *const rtcm = new RTCMMavlink(this);
250
251 const int fakeMsgLengths[3] = { 30, 170, 240 };
252 const uint8_t* const fakeData = new uint8_t[fakeMsgLengths[2]];
253 while (!_requestStop) {
254 for (int i = 0; i < 3; ++i) {
255 const QByteArray message(reinterpret_cast<const char*>(fakeData), fakeMsgLengths[i]);
256 rtcm->RTCMDataUpdate(message);
257 msleep(4);
258 }
259 msleep(100);
260 }
261 delete[] fakeData;
262}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void RTCMDataUpdate(const QByteArray &message)
void sensorGnssRelativeUpdate(const sensor_gnss_relative_s &message)
int callback(GPSCallbackType type, void *data1, int data2)
void sensorGpsUpdate(const sensor_gps_s &message)
void satelliteInfoUpdate(const satellite_info_s &message)
void surveyInStatus(float duration, float accuracyMM, double latitude, double longitude, float altitude, bool valid, bool active)
Provides functions to access serial ports.
Definition qserialport.h:17
bool open(OpenMode mode) override
bool setStopBits(StopBits stopBits)
void setPortName(const QString &name)
bool waitForBytesWritten(int msecs=30000) override
bool waitForReadyRead(int msecs=30000) override
void clearError()
SerialPortError error() const
the error status of the serial port
bool setBaudRate(qint32 baudRate, Directions directions=AllDirections)
bool setDataBits(DataBits dataBits)
bool setParity(Parity parity)
qint64 bytesAvailable() const override
bool setFlowControl(FlowControl flowControl)
BaseModeDefinition::Mode useFixedBaseLocation
Definition GPSProvider.h:37