QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
UBXReceiverController.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cstddef>
5#include <cstdint>
6#include <optional>
7#include <span>
8#include <utility>
9
10#include "GPSCommand.h"
11#include "UBX/UBXConfigKeys.h"
12#include "UBX/UBXFrame.h"
13
14namespace UBX {
15
17{
18 uint16_t message;
20};
21
24{
25 uint16_t message;
26 std::array<uint8_t, 6> rates;
27};
28
31{
32public:
34 void requireConfigurationReadback(uint16_t message) { _unacknowledgedConfiguration = message; }
35
36 bool configurationReadbackRequired() const { return _unacknowledgedConfiguration.has_value(); }
37
38 void beginAcknowledgement(uint16_t message)
39 {
40 _lastMessage.reset();
41 _lateRejection = false;
42 _awaitingMessage = message;
43 _acknowledgement = GPSCommandOutcome::Pending;
44 }
45
47 {
48 _lastMessage = _awaitingMessage;
49 _awaitingMessage.reset();
50 }
51
52 bool lateRejection() const { return _lateRejection; }
53
54 bool awaitingAcknowledgement() const { return _awaitingMessage.has_value(); }
55
56 GPSCommandOutcome acknowledgement() const { return _acknowledgement; }
57
58 void accept(Acknowledgement response)
59 {
60 if (!response.accepted &&
61 (_lastMessage == response.message || _unacknowledgedConfiguration == response.message)) {
62 _lateRejection = true;
63 }
64 if (_awaitingMessage == response.message && _acknowledgement != GPSCommandOutcome::Rejected) {
66 }
67 if (response.message == Msg::CFG_VALGET.value() && !response.accepted) {
68 // A VALGET with an unknown key is rejected, so the VALSET with it was rejected too.
69 if (_takeReadbackReply()) {
70 _readbackRejected = true;
71 }
72 }
73 if (_ratePoll && response.message == Msg::CFG_MSG.value()) {
74 if (_ratePoll->rates) {
75 _ratePoll->acknowledged = true;
76 } else {
77 ++_ratePoll->repliesBeforeRates;
78 _ratePoll->rejected = _ratePoll->rejected || !response.accepted;
79 }
80 }
81 }
82
83 void beginReadback(std::span<const uint32_t> keys)
84 {
85 _readback = {};
86 _readbackPending = !keys.empty() && keys.size() <= _readback.values.size();
87 _readbackReady = false;
88 _readbackRejected = false;
89 _readbackReplied = false;
90 if (_readbackPending) {
91 _readback.count = keys.size();
92 for (size_t index = 0; index < keys.size(); ++index) {
93 _readback.values[index].key = keys[index];
94 }
95 }
96 }
97
99 {
100 // A readback settled by an earlier reply, or by its timeout, still has its own reply to come.
101 if (_readbackPending && !_readbackReplied) {
102 _readbackReplyOutstanding = true;
103 }
104 _readbackPending = false;
105 }
106
107 bool readbackPending() const { return _readbackPending; }
108
110 bool readbackReplyOutstanding() const { return _readbackReplyOutstanding; }
111
112 bool readbackReady() const { return _readbackReady; }
113
115 bool readbackRejected() const { return _readbackRejected; }
116
117 const ConfigurationValues& readback() const { return _readback; }
118
120 void accept(const std::optional<ConfigurationValues>& response)
121 {
122 // Values name their keys, so they are matched whichever poll they answer.
123 _takeReadbackReply();
124 if (!_readbackPending || !response || response->count != _readback.count) {
125 return;
126 }
127 std::array<ConfigurationValue, ConfigurationValues::MAX_KEYS> values{};
128 uint16_t seen = 0;
129 for (size_t entry = 0; entry < response->count; ++entry) {
130 size_t index = 0;
131 while (index < _readback.count && _readback.values[index].key != response->values[entry].key) {
132 ++index;
133 }
134 if (index == _readback.count || (seen & (1u << index))) {
135 return;
136 }
137 values[index] = response->values[entry];
138 seen |= 1u << index;
139 }
140 _readback.values = values;
141 _readbackReady = true;
142 _readbackReplied = true;
143 }
144
148 void beginRatePoll(uint16_t message) { _ratePoll = RatePoll{.message = message}; }
149
150 void finishRatePoll() { _ratePoll.reset(); }
151
152 bool ratePollPending() const { return _ratePoll.has_value(); }
153
155 std::optional<std::array<uint8_t, 6>> polledRates() const { return _ratePoll ? _ratePoll->rates : std::nullopt; }
156
158 bool ratePollRejected() const { return _ratePoll && _ratePoll->rejected; }
159
162 bool ratePollSettled() const
163 {
164 return _ratePoll && ((_ratePoll->rates && _ratePoll->acknowledged) || _ratePoll->repliesBeforeRates >= 2);
165 }
166
167 void accept(const MessageRates& response)
168 {
169 if (_ratePoll && response.message == _ratePoll->message && !_ratePoll->rates) {
170 _ratePoll->rates = response.rates;
171 }
172 }
173
174private:
175 struct RatePoll
176 {
177 uint16_t message = 0;
178 std::optional<std::array<uint8_t, 6>> rates{};
179 unsigned repliesBeforeRates = 0;
180 bool rejected = false;
181 bool acknowledged = false;
182 };
183
186 bool _takeReadbackReply()
187 {
188 if (std::exchange(_readbackReplyOutstanding, false) || !_readbackPending) {
189 return false;
190 }
191 _readbackReplied = true;
192 return true;
193 }
194
195 std::optional<uint16_t> _unacknowledgedConfiguration;
196 std::optional<uint16_t> _awaitingMessage;
197 std::optional<uint16_t> _lastMessage;
198 bool _lateRejection = false;
200 ConfigurationValues _readback;
201 bool _readbackPending = false;
202 bool _readbackReady = false;
203 bool _readbackRejected = false;
204 bool _readbackReplied = false;
205 bool _readbackReplyOutstanding = false;
206 std::optional<RatePoll> _ratePoll;
207};
208
209} // namespace UBX
GPSCommandOutcome
Definition GPSCommand.h:33
std::array< MsgOutKey, 4 > keys
Definition UBXPlan.cc:13
Owns control-response correlation: decoding reports replies through accept(); only configuration open...
bool readbackRejected() const
The receiver rejected the pending readback: at least one of its keys is unknown.
void beginAcknowledgement(uint16_t message)
bool readbackReplyOutstanding() const
A reply to a readback settled without it can still arrive.
std::optional< std::array< uint8_t, 6 > > polledRates() const
The polled rates, once they arrived.
void accept(const std::optional< ConfigurationValues > &response)
A CFG-VALGET response; nullopt when it is malformed.
bool ratePollRejected() const
A NAK came before the polled rates: the receiver rejected the rate or the poll.
void accept(Acknowledgement response)
GPSCommandOutcome acknowledgement() const
void beginReadback(std::span< const uint32_t > keys)
void requireConfigurationReadback(uint16_t message)
A baud change can lose its ACK on UART; subsequent VALSETs must prove their values by readback.
void accept(const MessageRates &response)
void beginRatePoll(uint16_t message)
const ConfigurationValues & readback() const
constexpr MessageId CFG_VALGET
Definition UBXFrame.h:67
constexpr MessageId CFG_MSG
Definition UBXFrame.h:62
u-blox receivers over UBX: CFG-VALSET configuration from protocol 27, CFG-MSG and CFG-TMODE3 before i...
The values of one CFG-VALGET poll or response.
std::array< ConfigurationValue, MAX_KEYS > values
constexpr uint16_t value() const
Definition UBXFrame.h:27
The CFG-MSG output rates of one message on each I/O port, as a poll returns them.
std::array< uint8_t, 6 > rates