QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GPSCommandChannel.h
Go to the documentation of this file.
1#pragma once
2
3#include <chrono>
4#include <cstddef>
5#include <cstdint>
6#include <functional>
7#include <optional>
8#include <span>
9#include <variant>
10#include <vector>
11
12#include <QtCore/QByteArrayView>
13#include <QtCore/QString>
14
15#include "GPSCommand.h"
16#include "GPSDeadline.h"
17#include "GPSFamilyProtocol.h"
18#include "GPSProtocolEvent.h"
19
23class GPSStreamDemux;
24
26enum class [[nodiscard]] GPSBaudStatus
27{
31 Error
32};
33
34enum class GPSBaudProbe
35{
36 Found,
37 TryNext,
39 Stop,
40};
41
43{
44 bool found = false;
46 unsigned baud = 0;
48 bool linkFailed = false;
50 std::vector<unsigned> probed{};
51};
52
54[[nodiscard]] QString gpsRateList(std::span<const unsigned> rates);
55
57using GPSBaudProbeFunction = std::function<GPSBaudProbe()>;
58
61class [[nodiscard]] GPSDeadlineScope
62{
63public:
64 GPSDeadlineScope(GPSCommandChannel& channel, std::chrono::milliseconds timeout);
67
68 Q_DISABLE_COPY(GPSDeadlineScope)
69
70private:
71 void _limitUntil(uint64_t untilUs);
72
73 GPSCommandChannel& _channel;
74 GPSDeadline _previous;
75};
76
83{
84public:
86 static constexpr size_t READ_CHUNK_SIZE = 150;
88 static constexpr std::chrono::milliseconds SERVICE_TIMEOUT{5000};
89
90 Q_DISABLE_COPY(GPSCommandChannel)
91
92 // Clock and deadlines
93
94 [[nodiscard]] uint64_t nowUs() const;
95
96 [[nodiscard]] GPSDeadline operationDeadline() const { return _operationDeadline; }
97
99 [[nodiscard]] GPSDeadline commandDeadline() const { return _commandDeadline; }
100
101 [[nodiscard]] GPSDeadlineScope deadlineScope(std::chrono::milliseconds timeout) { return {*this, timeout}; }
102
103 [[nodiscard]] GPSDeadlineScope deadlineScope(GPSDeadline deadline) { return {*this, deadline}; }
104
105 // Sticky failure
106
107 [[nodiscard]] bool failed() const { return _error != GPSProtocolError::None; }
108
109 [[nodiscard]] GPSProtocolError error() const { return _error; }
110
111 [[nodiscard]] const QString& errorDetail() const { return _errorDetail; }
112
113 void setErrorDetail(const QString& detail) { _errorDetail = detail; }
114
118
120 void failControl(const QString& detail);
121
124 void failSequence(const GPSCommandSequence::Result& result);
125
128 void failNoAnswer(std::span<const unsigned> rates);
129
131 [[nodiscard]] GPSCommandOutcome failureOutcome() const;
132
133 // Command evidence
134
138
141
142 void finishCommand(GPSCommandOutcome outcome) { (void) completeCommand(outcome); }
143
144 [[nodiscard]] const GPSConfigurationEvidence& currentCommand() const { return _command; }
145
146 // Blocking operations
147
149 int read(std::span<uint8_t> buffer, std::chrono::milliseconds timeout);
150
154 bool write(QByteArrayView bytes);
155
158 bool setBaudrate(unsigned baudrate);
159
161 void wait(std::chrono::microseconds duration);
162
163 // Commands
164
166 bool writeCommand(GPSConfigurationStep step, QByteArrayView bytes);
167
170
174 {
175 return _transact(std::move(step), bytes, std::monostate{});
176 }
177
180 {
181 return _transact(std::move(step), bytes, std::move(reply));
182 }
183
186 {
187 return _transact(std::move(step), bytes, std::move(reply));
188 }
189
193
196
198 [[nodiscard]] bool runRequired(const GPSCommandSequence& sequence);
199
204 GPSBaudDetection detectBaud(std::span<const unsigned> candidates, unsigned baud, GPSBaudProbeFunction probe);
205
206 // Receiving
207
210 GPSReceiveUpdates receiveCycle(std::chrono::milliseconds timeout);
211
213 void receiveFor(std::chrono::milliseconds duration);
214
217 bool receiveUntil(std::function<bool()> done, std::chrono::milliseconds duration);
218
220 void serviceControls();
221
222 // Decoding without I/O
223
225 GPSReceiveUpdates flush();
226
227 [[nodiscard]] GPSStreamDemux& stream();
228
231 [[nodiscard]] GPSDecodeContext& context();
232
233 [[nodiscard]] GPSLogCategory logCategory() const;
234
235private:
236 friend class GPSDeadlineScope;
237 friend class GPSDecodeContext;
238 friend class GPSProtocolRuntime;
239
240 using ReplyMatcher = std::variant<std::monostate, GPSRawAckMatcher*, GPSTextMatcher, GPSFrameMatcher>;
241
242 explicit GPSCommandChannel(GPSProtocolRuntime& runtime);
243
245 [[nodiscard]] bool _replyPending() const { return _reply == GPSCommandOutcome::Pending; }
246
248 void _resolveReply(GPSCommandOutcome outcome)
249 {
250 if (_replyPending()) {
251 _reply = outcome;
252 }
253 }
254
256 [[nodiscard]] GPSConfigurationEvidence _failedAttempt(GPSConfigurationStep step) const;
257
259 GPSBaudStatus _setBaudrate(unsigned baudrate);
260
262 GPSReceiveUpdates _readAndDecode(std::chrono::milliseconds timeout);
263
264 [[nodiscard]] QString _commandFailure(const QByteArray& label, GPSCommandOutcome outcome) const;
266 void _describeFailure();
267 GPSConfigurationEvidence _transact(GPSConfigurationStep step, QByteArrayView bytes, ReplyMatcher matcher);
268 void _clearReply();
269 void _resetError();
270 void _offerText(std::string_view reply);
271 void _offerFrame(const GPSFrame& frame);
272 void _offerRaw(std::span<const uint8_t> bytes);
273
274 GPSProtocolRuntime& _runtime;
276 QString _errorDetail;
277 GPSDeadline _operationDeadline;
278 bool _commandCompleted = true;
280 GPSDeadline _commandDeadline;
281 std::optional<GPSCommandOutcome> _reply;
282 ReplyMatcher _replyMatcher;
283 unsigned _detectedBaud = 0;
284 bool _servicingControls = false;
285};
GPSBaudProbe
@ Stop
The receiver answered but is not usable, so no other rate is tried.
QString gpsRateList(std::span< const unsigned > rates)
rates as a diagnostic names them, such as "38400, 9600".
GPSBaudStatus
How the link answered a baud rate change.
std::function< GPSBaudProbe()> GPSBaudProbeFunction
Probes the receiver at the rate the link was just set to.
std::function< GPSCommandOutcome(const GPSFrame &frame)> GPSFrameMatcher
Resolves the outstanding command from each dispatched frame, after the family decoded it; Pending kee...
Definition GPSCommand.h:71
std::function< GPSCommandOutcome()> GPSReplyPoll
Polled after each decoded chunk, for replies a family tracks in its own decoder state; Pending keeps ...
Definition GPSCommand.h:73
GPSCommandOutcome
Definition GPSCommand.h:33
GPSProtocolError
Sticky failure of the current receiver session; I/O and control stop until the next configure().
Definition GPSCommand.h:23
@ Protocol
The receiver violated or rejected the control protocol.
std::function< GPSCommandOutcome(std::string_view reply)> GPSTextMatcher
Resolves the outstanding command from one text reply a decoder offers; Pending keeps waiting.
Definition GPSCommand.h:69
const QLoggingCategory &(*)() GPSLogCategory
A family's logging category function, as declared by Q_DECLARE_LOGGING_CATEGORY; usable as qCWarning(...
void wait(std::chrono::microseconds duration)
Waits for duration, capped by the operation deadline.
void beginCommand(GPSConfigurationStep step)
void setErrorDetail(const QString &detail)
void serviceControls()
Runs the family's streaming services once under SERVICE_TIMEOUT, then flushes. Nested calls do nothin...
GPSLogCategory logCategory() const
GPSBaudDetection detectBaud(std::span< const unsigned > candidates, unsigned baud, GPSBaudProbeFunction probe)
uint64_t nowUs() const
GPSReceiveUpdates receiveCycle(std::chrono::milliseconds timeout)
int read(std::span< uint8_t > buffer, std::chrono::milliseconds timeout)
Reads raw bytes without decoding them.
void receiveFor(std::chrono::milliseconds duration)
Repeats the family's full streaming receive until duration has passed or I/O fails.
GPSDeadline operationDeadline() const
GPSDecodeContext & context()
bool setBaudrate(unsigned baudrate)
GPSConfigurationEvidence transact(GPSConfigurationStep step, QByteArrayView bytes, GPSFrameMatcher reply)
As above, also resolved by reply from each dispatched frame.
GPSConfigurationEvidence transact(GPSConfigurationStep step, QByteArrayView bytes, GPSTextMatcher reply)
As above, also resolved by reply from each text reply a decoder offers.
void failSequence(const GPSCommandSequence::Result &result)
GPSDeadline commandDeadline() const
Deadline of the current command attempt, set by beginCommand().
void failControl(GPSProtocolError failure=GPSProtocolError::Protocol)
GPSDeadlineScope deadlineScope(std::chrono::milliseconds timeout)
bool receiveUntil(std::function< bool()> done, std::chrono::milliseconds duration)
static constexpr std::chrono::milliseconds SERVICE_TIMEOUT
Budget of the streaming services that run after each receive.
const QString & errorDetail() const
const GPSConfigurationEvidence & currentCommand() const
GPSDeadlineScope deadlineScope(GPSDeadline deadline)
static constexpr size_t READ_CHUNK_SIZE
Bytes requested by each receive or reply read.
GPSConfigurationEvidence completeCommand(GPSCommandOutcome outcome)
Retires the current attempt and reports it; repeated completion returns the retained evidence unchang...
GPSReceiveUpdates flush()
Flushes decoder state and delivers the resulting batch.
GPSStreamDemux & stream()
bool write(QByteArrayView bytes)
bool runRequired(const GPSCommandSequence &sequence)
Runs sequence and fails control over a failed step as failSequence() does.
GPSCommandSequence::Result runSequence(const GPSCommandSequence &sequence)
Runs sequence in order until a required step fails or I/O fails; failed attempts retry up to their co...
GPSConfigurationEvidence awaitReply(GPSReplyPoll reply)
Decodes received traffic until reply resolves the current command, its deadline expires,...
GPSProtocolError error() const
void failNoAnswer(std::span< const unsigned > rates)
bool writeCommand(GPSConfigurationStep step, QByteArrayView bytes)
Starts one command attempt under its own deadline scope and writes it; awaitReply() waits for its rep...
GPSConfigurationEvidence transact(GPSConfigurationStep step, QByteArrayView bytes)
GPSCommandOutcome failureOutcome() const
The command outcome that reports the sticky failure; Pending while healthy.
void finishCommand(GPSCommandOutcome outcome)
std::vector< unsigned > probed
The rates the link ran at while probing, in order.
unsigned baud
The rate that was found, or the last rate attempted.
bool linkFailed
The link could not be set to the last rate attempted.
Evidence from one configuration command, not a claim of physical receiver operation.
Definition GPSCommand.h:46