• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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