QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
RTCMFramer.cc
Go to the documentation of this file.
1#include "RTCMFramer.h"
2
3#include <algorithm>
4
5#include <QtCore/QByteArrayView>
6
8
9QGC_LOGGING_CATEGORY(RTCMFrameDecoderLog, "GPS.RTCM.RTCMFrameDecoder")
10
12{
13 qCDebug(RTCMFrameDecoderLog) << this;
14}
15
17{
18 qCDebug(RTCMFrameDecoderLog) << this;
19}
20
21bool RTCMFramer::addByte(uint8_t byte)
22{
23 const uint16_t validatedFrameSize = _frameSize ? _discardCandidate() : 0;
24 if (!_size && byte != PREAMBLE) {
25 return false;
26 }
27 _bytes[_size++] = byte;
28 return _inspect(validatedFrameSize);
29}
30
32{
33 if (!_frameSize) {
34 return false;
35 }
36 return _inspect(_discardCandidate());
37}
38
39void RTCMFramer::_discardPrefix(uint16_t count)
40{
41 if (count) {
42 std::move(_bytes.begin() + count, _bytes.begin() + _size, _bytes.begin());
43 _size -= count;
44 _recoverySize -= (std::min) (_recoverySize, count);
45 }
46}
47
48uint16_t RTCMFramer::_discardCandidate()
49{
50 uint16_t validatedFrameSize = 0;
51 uint16_t searchOffset = _frameSize;
52 if (!valid()) {
53 _recoverySize = (std::max) (_recoverySize, _frameSize);
54 searchOffset = 1;
55 }
56 uint16_t discardSize = _frameSize;
57 if (searchOffset < _recoverySize) {
58 discardSize = _recoverySize;
59 // Fresh bytes may belong to an incomplete outer frame.
60 const std::span<const uint8_t> bytes{_bytes.data(), _recoverySize};
61 for (uint16_t offset = searchOffset; offset < _recoverySize; ++offset) {
62 const auto suffix = bytes.subspan(offset);
63 if (suffix[0] != PREAMBLE || (suffix.size() >= 2 && (suffix[1] & 0xfc))) {
64 continue;
65 }
66 if (suffix.size() < HEADER_SIZE) {
67 discardSize = (std::min) (discardSize, offset);
68 continue;
69 }
70 const size_t payloadSize = ((suffix[1] & 3) << 8) | suffix[2];
71 if (payloadSize < 2) {
72 continue;
73 }
74 const size_t length = HEADER_SIZE + payloadSize + CRC_SIZE;
75 if (length > suffix.size()) {
76 discardSize = (std::min) (discardSize, offset);
77 continue;
78 }
79 if (isValidFrame(suffix.first(length))) {
80 discardSize = offset;
81 validatedFrameSize = static_cast<uint16_t>(length);
82 break;
83 }
84 }
85 }
86 _discardPrefix(discardSize);
87 _frameSize = 0;
88 _valid = false;
89 return validatedFrameSize;
90}
91
92bool RTCMFramer::_inspect(uint16_t validatedFrameSize)
93{
94 _valid = false;
95 _frameSize = 0;
96 _payloadSize = 0;
97 const auto preamble = std::find(_bytes.begin(), _bytes.begin() + _size, PREAMBLE);
98 _discardPrefix(static_cast<uint16_t>(preamble - _bytes.begin()));
99 if (_size >= 2 && (_bytes[1] & 0xfc)) {
100 _frameSize = 2;
101 return true;
102 }
103 if (_size < HEADER_SIZE) {
104 return false;
105 }
106 _payloadSize = ((_bytes[1] & 3) << 8) | _bytes[2];
107 if (_payloadSize < 2) {
108 _frameSize = HEADER_SIZE;
109 return true;
110 }
111 const uint16_t expectedSize = HEADER_SIZE + _payloadSize + CRC_SIZE;
112 if (_size < expectedSize) {
113 return false;
114 }
115 _frameSize = expectedSize;
116 _valid = validatedFrameSize == _frameSize || isValidFrame(frame());
117 return true;
118}
119
120std::optional<RTCMDecodedFrame> RTCMFrameDecoder::addByte(uint8_t byte, qint64 receivedAtMs)
121{
122 _receiptTimes[_nextReceiptIndex] = receivedAtMs;
123 _nextReceiptIndex = (_nextReceiptIndex + 1) % _receiptTimes.size();
124 if (!_framer.addByte(byte)) {
125 return std::nullopt;
126 }
127 return _result();
128}
129
130std::optional<RTCMDecodedFrame> RTCMFrameDecoder::nextFrame()
131{
132 if (!_framer.nextFrame()) {
133 return std::nullopt;
134 }
135 return _result();
136}
137
138RTCMDecodedFrame RTCMFrameDecoder::_result() const
139{
140 const auto frame = _framer.frame();
141 const size_t firstReceiptIndex =
142 (_nextReceiptIndex + _receiptTimes.size() - _framer.bufferedSize()) % _receiptTimes.size();
143 RTCMDecodedFrame result{QByteArrayView(frame).toByteArray(), _framer.messageId(), _receiptTimes[firstReceiptIndex]};
144 result.valid = _framer.valid();
145 result.filtered = result.valid && !_whitelist.isEmpty() && !_whitelist.contains(result.messageId);
146 return result;
147}
148
150{
151 _framer.reset();
152 _nextReceiptIndex = 0;
153}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Frames RTCM bytes while retaining the first fragment's monotonic receipt time.
Definition RTCMFramer.h:102
std::optional< RTCMDecodedFrame > nextFrame()
Drain after addByte() returns a result, before feeding more bytes.
std::optional< RTCMDecodedFrame > addByte(uint8_t byte, qint64 receivedAtMs)
static constexpr uint16_t CRC_SIZE
Definition RTCMFramer.h:23
uint16_t messageId() const
Definition RTCMFramer.h:49
std::span< const uint8_t > frame() const
Complete candidate, including malformed headers; empty while incomplete.
Definition RTCMFramer.h:42
bool nextFrame()
Definition RTCMFramer.cc:31
uint16_t bufferedSize() const
Retained suffix length, including bytes beyond the current candidate.
Definition RTCMFramer.h:45
void reset()
Definition RTCMFramer.h:27
static constexpr uint16_t HEADER_SIZE
Definition RTCMFramer.h:22
static constexpr uint8_t PREAMBLE
Definition RTCMFramer.h:21
static bool isValidFrame(std::span< const uint8_t > bytes)
Definition RTCMFramer.h:63
bool addByte(uint8_t byte)
Definition RTCMFramer.cc:21
bool valid() const
Definition RTCMFramer.h:61