38 for (
const uint8_t
byte : bytes) {
39 _demux.
push(
byte, *
this);
47 _framedTraffic =
false;
50void GPSReceiverSignatures::frame(
const GPSFrame& frame)
53 for (
const auto* family : _families) {
54 const QLatin1StringView evidence = family->signature ? family->signature(frame) : QLatin1StringView();
55 if (!evidence.isEmpty()) {
56 _match = Match{.family = family, .evidence = evidence};
68 , _signatures(families)
70 , _commandFinished(std::move(commandFinished))
73 _io.
read = [
this, read = std::move(_io.
read)](std::span<uint8_t> buffer,
GPSDeadline deadline) {
76 static_cast<size_t>(result.
bytesRead) <= buffer.size()) {
77 _signatures.
push(buffer.first(
static_cast<size_t>(result.
bytesRead)));
85 std::vector<unsigned> listed;
86 for (
const auto* family : families) {
87 listed.insert(listed.end(), family->baudCandidates.begin(), family->baudCandidates.end());
89 std::ranges::sort(listed);
90 listed.erase(std::ranges::unique(listed).begin(), listed.end());
91 std::vector<unsigned> rates;
93 if (std::ranges::binary_search(listed, rate)) {
94 rates.push_back(rate);
97 for (
const unsigned rate : listed) {
99 rates.push_back(rate);
107 const std::vector<unsigned> rates = baud ? std::vector<unsigned>{baud} :
baudCandidates(_families);
110 std::vector<unsigned> tried;
111 for (
const unsigned rate : rates) {
112 if (_stopped(result)) {
120 qCDebug(GPSReceiverDetectorLog) <<
"Link cannot run at" << rate <<
"baud; skipped";
128 : QStringLiteral(
"Cannot set the receiver link to %1 baud").arg(rate);
131 tried.push_back(rate);
133 switch (_listen(rate, untilUs, result)) {
136 case Listen::Identified:
137 return _identified(*_signatures.
match()->family, rate, _signatures.
match()->evidence);
141 for (
const auto* family : _families) {
142 if (family->baudCandidates.empty() || (!baud && !supportsRate(*family, rate))) {
146 if (now >= untilUs) {
149 qCDebug(GPSReceiverDetectorLog)
150 <<
"Probing" <<
gpsReceiverName(family->type) <<
"identity at" << rate <<
"baud";
154 result.
error = runtime.error();
159 return _identified(*family, rate, QStringLiteral(
"identity query"));
161 if (
const auto& match = _signatures.
match()) {
162 return _identified(*match->family, rate, match->evidence);
168 "The receiver sends standard NMEA or RTCM at %1 baud, but no supported "
169 "receiver family answered its identification query")
171 qCDebug(GPSReceiverDetectorLog).noquote() << result.
errorDetail;
175 if (_stopped(result)) {
180 result.
errorDetail = QStringLiteral(
"The receiver link cannot run at any rate a supported receiver uses");
182 result.
errorDetail = QStringLiteral(
"Receiver detection timed out after %1 s")
183 .arg(std::chrono::duration_cast<std::chrono::seconds>(
TIMEOUT).count());
187 qCDebug(GPSReceiverDetectorLog).noquote() << result.
errorDetail;
191GPSReceiverDetector::Listen GPSReceiverDetector::_listen(
unsigned baud, uint64_t untilUs,
GPSReceiverDetection& result)
193 qCDebug(GPSReceiverDetectorLog) <<
"Listening at" << baud <<
"baud";
195 std::array<uint8_t, GPSCommandChannel::READ_CHUNK_SIZE> buffer{};
196 Listen outcome = Listen::Quiet;
197 while (outcome == Listen::Quiet && !_signatures.
match() && _io.
clock.
nowUs() < listenUntilUs) {
198 if (_stopped(result)) {
199 outcome = Listen::Failed;
203 switch (
read.status) {
209 outcome = Listen::Failed;
214 outcome = Listen::Failed;
218 if (outcome == Listen::Quiet && _signatures.
match()) {
219 outcome = Listen::Identified;
237 QString evidence)
const
239 qCDebug(GPSReceiverDetectorLog).noquote() << QStringLiteral(
"Detected %1 receiver at %2 baud from %3")
244 detection.
family = &family;
245 detection.
baud = baud;
246 detection.
evidence = std::move(evidence);
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.
@ Protocol
The receiver violated or rejected the control protocol.
@ Cancelled
A stop was requested; not a receiver or link fault.
@ Transport
The link could not read, write, or change its baud rate.
QString gpsReceiverName(GPSType type)
The name of type's receiver family as shown to users; empty when no descriptor exists.
@ SBF
Septentrio "$@" block candidates, up to the first 110 bytes; the decoder checks the CRC.
@ UBX
u-blox 0xB5 0x62 frames with a valid Fletcher checksum.
@ ASCIILine
Printable lines up to CR/LF, without the terminator; the decoder checks checksums.
@ RTCM3
0xD3 frames with a valid CRC-24Q.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
bool isCancelled() const
Safe to call from any thread.
bool probe(std::chrono::milliseconds budget)
static constexpr std::chrono::milliseconds TIMEOUT
static constexpr std::chrono::milliseconds LISTEN_WINDOW
GPSReceiverDetection detect(unsigned baud=0)
Identifies the receiver at baud, which then every family is probed at, or else at each baudCandidates...
static std::vector< unsigned > baudCandidates(std::span< const GPSReceiverFamily *const > families)
The rates detection tries without a fixed rate: every candidate rate of families, in likelihood order...
static constexpr std::array< unsigned, 8 > BAUD_PRIORITY
GPSReceiverDetector(std::span< const GPSReceiverFamily *const > families, GPSRuntimeIO io, std::function< void(const GPSConfigurationEvidence &)> commandFinished={})
GPSReceiverSignatures(std::span< const GPSReceiverFamily *const > families)
void push(std::span< const uint8_t > bytes)
const std::optional< Match > & match() const
The first family signature since the last reset.
void reset()
Forgets partial frames and findings, as after a rate change.
bool framedTraffic() const
Standard NMEA sentences or RTCM3 frames arrived, so the link runs at the receiver's rate.
void push(uint8_t byte, Handler &handler)
QByteArray read(int deviceId, int length, int timeout)
bool isStandardSentence(std::string_view text)
A checked sentence from a standard talker, not a proprietary $P... sentence.
std::optional< Frame > frame(std::string_view text)
std::function< uint64_t()> nowUs
Evidence from one configuration command, not a claim of physical receiver operation.
static GPSDeadline after(uint64_t nowUs, std::chrono::microseconds timeout)
A negative timeout is already due at nowUs.
std::chrono::milliseconds remaining(uint64_t nowUs) const
Rounded up to whole milliseconds and capped at INT32_MAX milliseconds.
The receiver detection found, or why it found none.
const GPSReceiverFamily * family
Null when no family was identified.
GPSProtocolError error
Protocol when nothing was identified; Cancelled or Transport when the link ended detection.
unsigned baud
The rate the receiver answered at.
QString evidence
What identified it: a signature such as "UBX frames", or "identity query".
std::span< const unsigned > baudCandidates
std::function< GPSReadResult(std::span< uint8_t >, GPSDeadline)> read
GPSCancelToken cancelToken
Checked before each write and baud change; reads observe it in the transport.
GPSClock clock
Without a wait, the runtime sleeps in short slices until the duration elapses or cancelToken is cance...
std::function< GPSBaudStatus(unsigned)> setBaudrate
The framers of one receiver stream and how they share it.
GPSFrameKinds framers
Framers the family can use; only these can be enabled later.