C/C++ API Reference
Loading...
Searching...
No Matches
decoder.h
1// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <algorithm>
17#include <array>
18#include <cstddef>
19#include <cstring>
20#include <functional> // std::invoke
21
22#include "pw_assert/assert.h"
23#include "pw_bytes/span.h"
24#include "pw_checksum/crc32.h"
25#include "pw_hdlc/internal/protocol.h"
26#include "pw_result/result.h"
27#include "pw_status/status.h"
28
29namespace pw::hdlc {
30
32
33// Represents the contents of an HDLC frame -- the unescaped data between two
34// flag bytes. Instances of Frame are only created when a full, valid frame has
35// been read.
36class Frame {
37 public:
38 // The minimum size of a frame, excluding control bytes (flag or escape).
39 static constexpr size_t kMinContentSizeBytes =
40 kMinAddressSize + kControlSize + kFcsSize;
41
42 static Result<Frame> Parse(ConstByteSpan frame);
43
44 constexpr uint64_t address() const { return address_; }
45
46 constexpr std::byte control() const { return control_; }
47
48 constexpr ConstByteSpan data() const { return data_; }
49
50 private:
51 // Creates a Frame with the specified data. The data MUST be valid frame data
52 // with a verified frame check sequence.
53 constexpr Frame(uint64_t address, std::byte control, ConstByteSpan data)
54 : data_(data), address_(address), control_(control) {}
55
56 ConstByteSpan data_;
57 uint64_t address_;
58 std::byte control_;
59};
60
61// The Decoder class facilitates decoding of data frames using the HDLC
62// protocol, by returning packets as they are decoded and storing incomplete
63// data frames in a buffer.
64//
65// The Decoder class does not own the buffer it writes to. It can be used to
66// write bytes to any buffer. The DecoderBuffer template class, defined below,
67// allocates a buffer.
68class Decoder {
69 public:
70 constexpr Decoder(ByteSpan buffer)
71 : buffer_(buffer),
72 last_read_bytes_({}),
73 last_read_bytes_index_(0),
74 current_frame_size_(0),
75 state_(State::kInterFrame) {}
76
77 Decoder(const Decoder&) = delete;
78 Decoder& operator=(const Decoder&) = delete;
79 Decoder(Decoder&&) = default;
80 Decoder& operator=(Decoder&&) = default;
81
102 Result<Frame> Process(std::byte new_byte);
103
104 // Returns the buffer space required for a `Decoder` to successfully decode a
105 // frame whose on-the-wire HDLC encoded size does not exceed `max_frame_size`.
106 static constexpr size_t RequiredBufferSizeForFrameSize(
107 size_t max_frame_size) {
108 // Flag bytes aren't stored in the internal buffer, so we can save a couple
109 // bytes.
110 return max_frame_size < Frame::kMinContentSizeBytes
111 ? Frame::kMinContentSizeBytes
112 : max_frame_size - 2;
113 }
114
117 template <typename F, typename... Args>
118 void Process(ConstByteSpan data, F&& callback, Args&&... args) {
119 for (std::byte b : data) {
120 auto result = Process(b);
121 if (result.status() != Status::Unavailable()) {
122 callback(std::forward<Args>(args)..., result);
123 }
124 }
125 }
126
127 // Returns the maximum size of the Decoder's frame buffer.
128 size_t max_size() const { return buffer_.size(); }
129
130 // Clears and resets the decoder.
131 void Clear() {
132 state_ = State::kInterFrame;
133 Reset();
134 }
135
136 private:
137 // State enum class is used to make the Decoder a finite state machine.
138 enum class State {
139 kInterFrame,
140 kFrame,
141 kFrameEscape,
142 };
143
144 void Reset() {
145 current_frame_size_ = 0;
146 last_read_bytes_index_ = 0;
147 fcs_.clear();
148 }
149
150 void AppendByte(std::byte new_byte);
151
152 Status CheckFrame() const;
153
154 bool VerifyFrameCheckSequence() const;
155
156 ByteSpan buffer_;
157
158 // Ring buffer of the last four bytes read into the current frame, to allow
159 // calculating the frame's CRC incrementally. As data is evicted from this
160 // buffer, it is added to the running CRC. Once a frame is complete, the
161 // buffer contains the frame's FCS.
162 std::array<std::byte, sizeof(uint32_t)> last_read_bytes_;
163 size_t last_read_bytes_index_;
164
165 // Incremental checksum of the current frame.
166 checksum::Crc32 fcs_;
167
168 size_t current_frame_size_;
169
170 State state_;
171};
172
173// DecoderBuffers declare a buffer along with a Decoder.
174template <size_t kSizeBytes>
175class DecoderBuffer : public Decoder {
176 public:
177 DecoderBuffer() : Decoder(frame_buffer_) {}
178
182
186
187 // Returns the maximum length of the bytes that can be inserted in the bytes
188 // buffer.
189 static constexpr size_t max_size() { return kSizeBytes; }
190
191 private:
192 static_assert(kSizeBytes >= Frame::kMinContentSizeBytes);
193
194 std::array<std::byte, kSizeBytes> frame_buffer_;
195};
196
197} // namespace pw::hdlc
Definition: poll.h:25
Definition: decoder.h:175
Definition: decoder.h:68
Definition: decoder.h:36
Result< Frame > Process(std::byte new_byte)
Parses a single byte of an HDLC stream.
void Process(ConstByteSpan data, F &&callback, Args &&... args)
Processes a span of data and calls the provided callback with each frame or error.
Definition: decoder.h:118
DecoderBuffer & operator=(DecoderBuffer &&)=delete
DecoderBuffer(DecoderBuffer &&)=delete
Serial comms library.
Definition: decoder.h:29