53 Claim
claim(uint8_t
byte)
const override
55 if (_framer.hasPartialFrame()) {
64 for (
bool complete = _framer.addByte(
byte); complete; complete = _framer.nextFrame()) {
65 if (!_framer.valid()) {
68 const auto frame = _framer.frame();
77 void reset()
override { _framer.reset(); }
90 Claim
claim(uint8_t
byte)
const override
92 if (!_decoder.idle()) {
100 if (
const auto frame = _decoder.consume(
byte)) {
102 .bytes =
frame->bytes,
103 .payload =
frame->payload,
104 .messageId =
frame->message});
108 void reset()
override { _decoder.reset(); }
120 explicit SBFFramer(
bool shareSync)
122 , _shareSync(shareSync)
125 Claim
claim(uint8_t
byte)
const override
145 _state = State::Sync2;
151 _state = State::Payload;
159 const std::span<const uint8_t> bytes(_wire.data(), _size);
160 const auto header = _header();
162 header.length > _size && header.length % 4 == 0 && header.length <= MAX_SKIPPED_LENGTH
163 ? header.length - _size
166 {.kind =
GPSFrameKind::SBF, .bytes = bytes, .payload = bytes, .messageId = header.number()});
169 _state = State::Skip;
175 if (--_remaining == 0) {
182 void reset()
override
184 _state = State::Sync1;
190 enum class State : uint8_t
200 static constexpr uint16_t MAX_SKIPPED_LENGTH = 4096;
203 SBF::BlockHeader _header()
const {
return Wire::decode<SBF::BlockHeader>(_wire); }
206 bool _add(uint8_t
byte)
208 _wire[_size++] = byte;
209 return (_size >= Wire::SIZE<SBF::BlockHeader> && _size >= _header().length) || _size >= _wire.size();
212 std::array<uint8_t, 110> _wire{};
214 uint16_t _remaining = 0;
215 State _state = State::Sync1;
216 bool _shareSync =
false;
224 , _buffer(BUFFER_SIZE)
232 if (
const size_t length = _framer.addByte(
byte); length > 0) {
233 const std::span<const uint8_t> bytes(_buffer.data(), length);
238 void reset()
override { _framer.reset(); }
241 static constexpr size_t BUFFER_SIZE = 600;
243 std::vector<uint8_t> _buffer;
252 , _buffer(BUFFER_SIZE)
260 if (
const auto line = _framer.addByte(
byte)) {
261 const std::span<const uint8_t> bytes(
reinterpret_cast<const uint8_t*
>(
line->data()),
line->size());
266 void reset()
override { _framer.reset(); }
269 static constexpr size_t BUFFER_SIZE = 4096;
271 std::vector<char> _buffer;
280 _framers[0] = std::make_unique<RTCM3Framer>();
283 _framers[1] = std::make_unique<UBXFramer>();
286 _framers[2] = std::make_unique<SBFFramer>(
config.shareSBFSync);
289 _framers[3] = std::make_unique<NMEASentenceFramer>();
292 _framers[4] = std::make_unique<ASCIILineFramer>();
294 for (
const auto& framer : _framers) {
296 framer->enabled =
config.enabled.testFlag(framer->kind());
305 std::array<Claim, FRAMER_COUNT> claims{};
306 Framer* exclusive =
nullptr;
307 for (
size_t index = 0; index < _framers.size(); ++index) {
308 const auto& framer = _framers[index];
309 if (!framer || !framer->enabled) {
312 claims[index] = framer->claim(
byte);
313 if (claims[index] == Claim::Locked) {
314 exclusive = framer.get();
317 if (claims[index] == Claim::Owns && !exclusive) {
318 exclusive = framer.get();
322 for (
const auto& framer : _framers) {
323 if (framer && framer->enabled && framer.get() != exclusive) {
327 exclusive->
feed(
byte, handler);
330 bool defaultFed =
false;
331 for (
size_t index = 0; index < _framers.size(); ++index) {
332 if (claims[index] == Claim::Watch || (claims[index] == Claim::Default && !defaultFed)) {
333 defaultFed |= claims[index] == Claim::Default;
334 _framers[index]->feed(
byte, handler);
341 for (
const auto& framer : _framers) {
350 for (
const auto& framer : _framers) {
351 if (framer && framer->kind() == kind) {
359 for (
const auto& framer : _framers) {
360 if (framer && framer->kind() == kind) {
362 framer->enabled = enabled;
GPSFrameKind
Wire framings the stream demultiplexer recognises; also the set of framers a receiver family enables.
@ 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.
@ NMEASentence
'$' to a valid "*hh" checksum, without a line ending.
virtual ~Framer()=default
virtual Claim claim(uint8_t byte) const =0
Framer(GPSFrameKind kind)
GPSFrameKind kind() const
virtual void feed(uint8_t byte, Handler &handler)=0
virtual void frame(const GPSFrame &frame)=0
Receives each completed frame; the handler may reset or enable framers.
GPSStreamDemux(const GPSStreamConfig &config)
void push(uint8_t byte, Handler &handler)
void setEnabled(GPSFrameKind kind, bool enabled)
Enables or disables an available framer; either way it restarts from an empty state.
Frames printable ASCII lines. A '$' or '#' restarts the line, so a sentence or log is not lost after ...
static constexpr uint16_t CRC_SIZE
static constexpr uint16_t HEADER_SIZE
static constexpr uint8_t PREAMBLE
static uint16_t frameMessageId(std::span< const uint8_t > bytes)
Message number from a frame header; zero when the header is incomplete.
QByteArray line(std::string_view command)
command as one CR/LF-terminated line.
constexpr std::chrono::microseconds remaining(uint64_t timestampUs, uint64_t nowUs, std::chrono::microseconds lifetime)
Time left before a receipt reaches lifetime; zero for a missing, future or expired one.
std::optional< Frame > frame(std::string_view text)
Septentrio receivers configured as RTK bases with SBF commands; they stream PVTGeodetic blocks and RT...
u-blox receivers over UBX: CFG-VALSET configuration from protocol 27, CFG-MSG and CFG-TMODE3 before i...
The framers of one receiver stream and how they share it.