QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
NMEAUtils.cc
Go to the documentation of this file.
1#include "NMEAUtils.h"
2
3#include <QtCore/QDateTime>
4
5namespace NMEAUtils {
6
7quint8 computeChecksum(const QByteArray& body)
8{
9 quint8 cksum = 0;
10 for (char ch : body) {
11 cksum ^= static_cast<quint8>(ch);
12 }
13 return cksum;
14}
15
16bool verifyChecksum(const QByteArray& sentence)
17{
18 if (sentence.size() < 6 || sentence.at(0) != '$') {
19 return false;
20 }
21 const int star = sentence.lastIndexOf('*');
22 if (star < 2 || star + 3 > sentence.size()) {
23 return false;
24 }
25 const QByteArray body = sentence.mid(1, star - 1);
26 const QByteArray expected = QByteArray::number(computeChecksum(body), 16).rightJustified(2, '0').toUpper();
27 const QByteArray actual = sentence.mid(star + 1, 2).toUpper();
28 return actual == expected;
29}
30
31QByteArray repairChecksum(const QByteArray& sentence)
32{
33 QByteArray line = sentence;
34
35 if (line.size() >= 5 && line.at(0) == '$') {
36 int star = line.lastIndexOf('*');
37 if (star > 1) {
38 const QByteArray body = line.mid(1, star - 1);
39 const QByteArray calcCks = QByteArray::number(computeChecksum(body), 16).rightJustified(2, '0').toUpper();
40
41 bool needsRepair = false;
42 if (star + 3 > line.size()) {
43 needsRepair = true;
44 } else {
45 const QByteArray txCks = line.mid(star + 1, 2).toUpper();
46 if (txCks != calcCks) {
47 needsRepair = true;
48 }
49 }
50
51 if (needsRepair) {
52 line = line.left(star + 1) + calcCks;
53 }
54 } else {
55 const QByteArray body = line.mid(1);
56 const QByteArray calcCks = QByteArray::number(computeChecksum(body), 16).rightJustified(2, '0').toUpper();
57 line.append('*').append(calcCks);
58 }
59 }
60
61 if (!line.endsWith("\r\n")) {
62 line.append("\r\n");
63 }
64
65 return line;
66}
67
68QByteArray makeGGA(const QGeoCoordinate& coord, double altitudeMsl, int fixQuality, int numSatellites)
69{
70 const QTime utc = QDateTime::currentDateTimeUtc().time();
71 QByteArray hhmmss;
72 hhmmss += QByteArray::number(utc.hour()).rightJustified(2, '0');
73 hhmmss += QByteArray::number(utc.minute()).rightJustified(2, '0');
74 hhmmss += QByteArray::number(utc.second()).rightJustified(2, '0');
75
76 auto dmm = [](double deg, bool lat) -> QByteArray {
77 const double a = qFabs(deg);
78 int d = static_cast<int>(a);
79 double m = (a - d) * 60.0;
80
81 const int m10000 = static_cast<int>(m * 10000.0 + 0.5);
82 double mRounded = m10000 / 10000.0;
83 if (mRounded >= 60.0) {
84 mRounded -= 60.0;
85 d += 1;
86 }
87
88 QByteArray mm = QByteArray::number(mRounded, 'f', 4);
89 if (mRounded < 10.0) {
90 mm.prepend('0');
91 }
92
93 const int dWidth = lat ? 2 : 3;
94 return QByteArray::number(d).rightJustified(dWidth, '0') + mm;
95 };
96
97 const bool latNorth = coord.latitude() >= 0.0;
98 const bool lonEast = coord.longitude() >= 0.0;
99
100 const QByteArray latField = dmm(coord.latitude(), true);
101 const QByteArray lonField = dmm(coord.longitude(), false);
102
103 QByteArray core;
104 core += "GPGGA,";
105 core += hhmmss + ',';
106 core += latField + ',';
107 core += (latNorth ? "N" : "S");
108 core += ',';
109 core += lonField + ',';
110 core += (lonEast ? "E" : "W");
111 core += ',' + QByteArray::number(fixQuality) + ',' + QByteArray::number(numSatellites) + ",1.0,";
112 core += QByteArray::number(altitudeMsl, 'f', 1);
113 core += ",M,0.0,M,,";
114
115 QByteArray sentence;
116 sentence += '$';
117 sentence += core;
118 sentence += '*';
119 sentence += QByteArray::number(computeChecksum(core), 16).rightJustified(2, '0').toUpper();
120 sentence += "\r\n";
121 return sentence;
122}
123
124} // namespace NMEAUtils
QByteArray repairChecksum(const QByteArray &sentence)
Repair or append a valid NMEA checksum and ensure CRLF termination.
Definition NMEAUtils.cc:31
bool verifyChecksum(const QByteArray &sentence)
Definition NMEAUtils.cc:16
QByteArray makeGGA(const QGeoCoordinate &coord, double altitudeMsl, int fixQuality, int numSatellites)
Build a GGA sentence from a coordinate and altitude.
Definition NMEAUtils.cc:68
quint8 computeChecksum(const QByteArray &body)
Compute XOR checksum over NMEA body (between '$' and '*').
Definition NMEAUtils.cc:7