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 29 namespace pw::hdlc { 30 31 // Represents the contents of an HDLC frame -- the unescaped data between two 32 // flag bytes. Instances of Frame are only created when a full, valid frame has 33 // been read. 34 class Frame { 35 public: 36 // The minimum size of a frame, excluding control bytes (flag or escape). 37 static constexpr size_t kMinContentSizeBytes = 38 kMinAddressSize + kControlSize + kFcsSize; 39 40 static Result<Frame> Parse(ConstByteSpan frame); 41 address()42 constexpr uint64_t address() const { return address_; } 43 control()44 constexpr std::byte control() const { return control_; } 45 data()46 constexpr ConstByteSpan data() const { return data_; } 47 48 private: 49 // Creates a Frame with the specified data. The data MUST be valid frame data 50 // with a verified frame check sequence. Frame(uint64_t address,std::byte control,ConstByteSpan data)51 constexpr Frame(uint64_t address, std::byte control, ConstByteSpan data) 52 : data_(data), address_(address), control_(control) {} 53 54 ConstByteSpan data_; 55 uint64_t address_; 56 std::byte control_; 57 }; 58 59 // The Decoder class facilitates decoding of data frames using the HDLC 60 // protocol, by returning packets as they are decoded and storing incomplete 61 // data frames in a buffer. 62 // 63 // The Decoder class does not own the buffer it writes to. It can be used to 64 // write bytes to any buffer. The DecoderBuffer template class, defined below, 65 // allocates a buffer. 66 class Decoder { 67 public: Decoder(ByteSpan buffer)68 constexpr Decoder(ByteSpan buffer) 69 : buffer_(buffer), 70 last_read_bytes_({}), 71 last_read_bytes_index_(0), 72 current_frame_size_(0), 73 state_(State::kInterFrame) {} 74 75 Decoder(const Decoder&) = delete; 76 Decoder& operator=(const Decoder&) = delete; 77 78 // Parses a single byte of an HDLC stream. Returns a Result with the complete 79 // frame if the byte completes a frame. The status is the following: 80 // 81 // OK - A frame was successfully decoded. The Result contains the Frame, 82 // which is invalidated by the next Process call. 83 // UNAVAILABLE - No frame is available. 84 // RESOURCE_EXHAUSTED - A frame completed, but it was too large to fit in 85 // the decoder's buffer. 86 // DATA_LOSS - A frame completed, but it was invalid. The frame was 87 // incomplete or the frame check sequence verification failed. 88 // 89 Result<Frame> Process(std::byte new_byte); 90 91 // Returns the buffer space required for a `Decoder` to successfully decode a 92 // frame whose on-the-wire HDLC encoded size does not exceed `max_frame_size`. RequiredBufferSizeForFrameSize(size_t max_frame_size)93 static constexpr size_t RequiredBufferSizeForFrameSize( 94 size_t max_frame_size) { 95 // Flag bytes aren't stored in the internal buffer, so we can save a couple 96 // bytes. 97 return max_frame_size < Frame::kMinContentSizeBytes 98 ? Frame::kMinContentSizeBytes 99 : max_frame_size - 2; 100 } 101 102 // Processes a span of data and calls the provided callback with each frame or 103 // error. 104 template <typename F, typename... Args> Process(ConstByteSpan data,F && callback,Args &&...args)105 void Process(ConstByteSpan data, F&& callback, Args&&... args) { 106 for (std::byte b : data) { 107 auto result = Process(b); 108 if (result.status() != Status::Unavailable()) { 109 std::invoke( 110 std::forward<F>(callback), std::forward<Args>(args)..., result); 111 } 112 } 113 } 114 115 // Returns the maximum size of the Decoder's frame buffer. max_size()116 size_t max_size() const { return buffer_.size(); } 117 118 // Clears and resets the decoder. Clear()119 void Clear() { 120 state_ = State::kInterFrame; 121 Reset(); 122 } 123 124 private: 125 // State enum class is used to make the Decoder a finite state machine. 126 enum class State { 127 kInterFrame, 128 kFrame, 129 kFrameEscape, 130 }; 131 Reset()132 void Reset() { 133 current_frame_size_ = 0; 134 last_read_bytes_index_ = 0; 135 fcs_.clear(); 136 } 137 138 void AppendByte(std::byte new_byte); 139 140 Status CheckFrame() const; 141 142 bool VerifyFrameCheckSequence() const; 143 144 const ByteSpan buffer_; 145 146 // Ring buffer of the last four bytes read into the current frame, to allow 147 // calculating the frame's CRC incrementally. As data is evicted from this 148 // buffer, it is added to the running CRC. Once a frame is complete, the 149 // buffer contains the frame's FCS. 150 std::array<std::byte, sizeof(uint32_t)> last_read_bytes_; 151 size_t last_read_bytes_index_; 152 153 // Incremental checksum of the current frame. 154 checksum::Crc32 fcs_; 155 156 size_t current_frame_size_; 157 158 State state_; 159 }; 160 161 // DecoderBuffers declare a buffer along with a Decoder. 162 template <size_t kSizeBytes> 163 class DecoderBuffer : public Decoder { 164 public: DecoderBuffer()165 DecoderBuffer() : Decoder(frame_buffer_) {} 166 167 // Returns the maximum length of the bytes that can be inserted in the bytes 168 // buffer. max_size()169 static constexpr size_t max_size() { return kSizeBytes; } 170 171 private: 172 static_assert(kSizeBytes >= Frame::kMinContentSizeBytes); 173 174 std::array<std::byte, kSizeBytes> frame_buffer_; 175 }; 176 177 } // namespace pw::hdlc 178