1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
20 #include <functional> // std::invoke
22 #include "pw_bytes/span.h"
23 #include "pw_result/result.h"
24 #include "pw_status/status.h"
26 namespace pw::hdlc_lite {
28 // Represents the contents of an HDLC frame -- the unescaped data between two
29 // flag bytes. Instances of Frame are only created when a full, valid frame has
32 // For now, the Frame class assumes single-byte address and control fields and a
33 // 32-bit frame check sequence (FCS).
36 static constexpr size_t kAddressSize = 1;
37 static constexpr size_t kControlSize = 1;
38 static constexpr size_t kFcsSize = sizeof(uint32_t);
41 // The minimum size of a frame, excluding control bytes (flag or escape).
42 static constexpr size_t kMinSizeBytes =
43 kAddressSize + kControlSize + kFcsSize;
45 // Creates a Frame with the specified data. The data MUST be valid frame data
46 // with a verified frame check sequence.
47 explicit constexpr Frame(ConstByteSpan data) : frame_(data) {
48 // TODO(pwbug/246): Use PW_DASSERT when available.
49 // PW_DASSERT(data.size() >= kMinSizeBytes);
52 constexpr unsigned address() const {
53 return std::to_integer<unsigned>(frame_[0]);
56 constexpr std::byte control() const { return frame_[kAddressSize]; }
58 constexpr ConstByteSpan data() const {
59 return frame_.subspan(kAddressSize + kControlSize,
60 frame_.size() - kMinSizeBytes);
67 // The Decoder class facilitates decoding of data frames using the HDLC-Lite
68 // protocol, by returning packets as they are decoded and storing incomplete
69 // data frames in a buffer.
71 // The Decoder class does not own the buffer it writes to. It can be used to
72 // write bytes to any buffer. The DecoderBuffer template class, defined below,
73 // allocates a buffer.
76 constexpr Decoder(ByteSpan buffer)
77 : buffer_(buffer), current_frame_size_(0), state_(State::kInterFrame) {}
79 Decoder(const Decoder&) = delete;
80 Decoder& operator=(const Decoder&) = delete;
82 // Parses a single byte of an HDLC stream. Returns a Result with the complete
83 // frame if the byte completes a frame. The status is the following:
85 // OK - A frame was successfully decoded. The Result contains the Frame,
86 // which is invalidated by the next Process call.
87 // UNAVAILABLE - No frame is available.
88 // RESOURCE_EXHAUSTED - A frame completed, but it was too large to fit in
89 // the decoder's buffer.
90 // DATA_LOSS - A frame completed, but it was invalid. The frame was
91 // incomplete or the frame check sequence verification failed.
93 Result<Frame> Process(std::byte b);
95 // Processes a span of data and calls the provided callback with each frame or
97 template <typename F, typename... Args>
98 void Process(ConstByteSpan data, F&& callback, Args&&... args) {
99 for (std::byte b : data) {
100 auto result = Process(b);
101 if (result.status() != Status::Unavailable()) {
103 std::forward<F>(callback), std::forward<Args>(args)..., result);
108 // Returns the maximum size of the Decoder's frame buffer.
109 size_t max_size() const { return buffer_.size(); }
111 // Clears and resets the decoder.
113 current_frame_size_ = 0;
114 state_ = State::kInterFrame;
118 // State enum class is used to make the Decoder a finite state machine.
125 void AppendByte(std::byte new_byte);
127 Status CheckFrame() const;
129 bool VerifyFrameCheckSequence() const;
131 const ByteSpan buffer_;
133 size_t current_frame_size_;
138 // DecoderBuffers declare a buffer along with a Decoder.
139 template <size_t size_bytes>
140 class DecoderBuffer : public Decoder {
142 DecoderBuffer() : Decoder(frame_buffer_) {}
144 // Returns the maximum length of the bytes that can be inserted in the bytes
146 static constexpr size_t max_size() { return size_bytes; }
149 static_assert(size_bytes >= Frame::kMinSizeBytes);
151 std::array<std::byte, size_bytes> frame_buffer_;
154 } // namespace pw::hdlc_lite