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 Decoder(Decoder&&) = default; 78 Decoder& operator=(Decoder&&) = default; 79 80 /// @brief Parses a single byte of an HDLC stream. 81 /// 82 /// @returns @rst 83 /// A ``pw::Result`` with the complete frame if the byte completes a 84 /// frame. The status can be one of the following: 85 /// 86 /// .. pw-status-codes:: 87 /// 88 /// OK: A frame was successfully decoded. The ``Result`` contains 89 /// the ``Frame``, which is invalidated by the next ``Process()`` call. 90 /// 91 /// UNAVAILABLE: No frame is available. 92 /// 93 /// RESOURCE_EXHAUSTED: A frame completed, but it was too large 94 /// to fit in the decoder's buffer. 95 /// 96 /// DATA_LOSS: A frame completed, but it was invalid. The frame 97 /// was incomplete or the frame check sequence verification failed. 98 /// 99 /// @endrst 100 Result<Frame> Process(std::byte new_byte); 101 102 // Returns the buffer space required for a `Decoder` to successfully decode a 103 // frame whose on-the-wire HDLC encoded size does not exceed `max_frame_size`. RequiredBufferSizeForFrameSize(size_t max_frame_size)104 static constexpr size_t RequiredBufferSizeForFrameSize( 105 size_t max_frame_size) { 106 // Flag bytes aren't stored in the internal buffer, so we can save a couple 107 // bytes. 108 return max_frame_size < Frame::kMinContentSizeBytes 109 ? Frame::kMinContentSizeBytes 110 : max_frame_size - 2; 111 } 112 113 /// @brief Processes a span of data and calls the provided callback with each 114 /// frame or error. 115 template <typename F, typename... Args> Process(ConstByteSpan data,F && callback,Args &&...args)116 void Process(ConstByteSpan data, F&& callback, Args&&... args) { 117 for (std::byte b : data) { 118 auto result = Process(b); 119 if (result.status() != Status::Unavailable()) { 120 callback(std::forward<Args>(args)..., result); 121 } 122 } 123 } 124 125 // Returns the maximum size of the Decoder's frame buffer. max_size()126 size_t max_size() const { return buffer_.size(); } 127 128 // Clears and resets the decoder. Clear()129 void Clear() { 130 state_ = State::kInterFrame; 131 Reset(); 132 } 133 134 private: 135 // State enum class is used to make the Decoder a finite state machine. 136 enum class State { 137 kInterFrame, 138 kFrame, 139 kFrameEscape, 140 }; 141 Reset()142 void Reset() { 143 current_frame_size_ = 0; 144 last_read_bytes_index_ = 0; 145 fcs_.clear(); 146 } 147 148 void AppendByte(std::byte new_byte); 149 150 Status CheckFrame() const; 151 152 bool VerifyFrameCheckSequence() const; 153 154 ByteSpan buffer_; 155 156 // Ring buffer of the last four bytes read into the current frame, to allow 157 // calculating the frame's CRC incrementally. As data is evicted from this 158 // buffer, it is added to the running CRC. Once a frame is complete, the 159 // buffer contains the frame's FCS. 160 std::array<std::byte, sizeof(uint32_t)> last_read_bytes_; 161 size_t last_read_bytes_index_; 162 163 // Incremental checksum of the current frame. 164 checksum::Crc32 fcs_; 165 166 size_t current_frame_size_; 167 168 State state_; 169 }; 170 171 // DecoderBuffers declare a buffer along with a Decoder. 172 template <size_t kSizeBytes> 173 class DecoderBuffer : public Decoder { 174 public: DecoderBuffer()175 DecoderBuffer() : Decoder(frame_buffer_) {} 176 177 /// DecoderBuffer is not movable, as the decoder stores pointers into the 178 /// frame buffer. 179 DecoderBuffer(DecoderBuffer&&) = delete; 180 181 /// DecoderBuffer is not movable, as the decoder stores pointers into the 182 /// frame buffer. 183 DecoderBuffer& operator=(DecoderBuffer&&) = delete; 184 185 // Returns the maximum length of the bytes that can be inserted in the bytes 186 // buffer. max_size()187 static constexpr size_t max_size() { return kSizeBytes; } 188 189 private: 190 static_assert(kSizeBytes >= Frame::kMinContentSizeBytes); 191 192 std::array<std::byte, kSizeBytes> frame_buffer_; 193 }; 194 195 } // namespace pw::hdlc 196