xref: /aosp_15_r20/external/pigweed/pw_hdlc/public/pw_hdlc/decoder.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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