d15cbe7ae492799a68468717935ea80110bab0c0
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_hdlc_lite / public / pw_hdlc_lite / decoder.h
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_bytes/span.h"
23 #include "pw_result/result.h"
24 #include "pw_status/status.h"
25
26 namespace pw::hdlc_lite {
27
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
30 // been read.
31 //
32 // For now, the Frame class assumes single-byte address and control fields and a
33 // 32-bit frame check sequence (FCS).
34 class Frame {
35  private:
36   static constexpr size_t kAddressSize = 1;
37   static constexpr size_t kControlSize = 1;
38   static constexpr size_t kFcsSize = sizeof(uint32_t);
39
40  public:
41   // The minimum size of a frame, excluding control bytes (flag or escape).
42   static constexpr size_t kMinSizeBytes =
43       kAddressSize + kControlSize + kFcsSize;
44
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);
50   }
51
52   constexpr unsigned address() const {
53     return std::to_integer<unsigned>(frame_[0]);
54   }
55
56   constexpr std::byte control() const { return frame_[kAddressSize]; }
57
58   constexpr ConstByteSpan data() const {
59     return frame_.subspan(kAddressSize + kControlSize,
60                           frame_.size() - kMinSizeBytes);
61   }
62
63  private:
64   ConstByteSpan frame_;
65 };
66
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.
70 //
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.
74 class Decoder {
75  public:
76   constexpr Decoder(ByteSpan buffer)
77       : buffer_(buffer), current_frame_size_(0), state_(State::kInterFrame) {}
78
79   Decoder(const Decoder&) = delete;
80   Decoder& operator=(const Decoder&) = delete;
81
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:
84   //
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.
92   //
93   Result<Frame> Process(std::byte b);
94
95   // Processes a span of data and calls the provided callback with each frame or
96   // error.
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()) {
102         std::invoke(
103             std::forward<F>(callback), std::forward<Args>(args)..., result);
104       }
105     }
106   }
107
108   // Returns the maximum size of the Decoder's frame buffer.
109   size_t max_size() const { return buffer_.size(); }
110
111   // Clears and resets the decoder.
112   void clear() {
113     current_frame_size_ = 0;
114     state_ = State::kInterFrame;
115   };
116
117  private:
118   // State enum class is used to make the Decoder a finite state machine.
119   enum class State {
120     kInterFrame,
121     kFrame,
122     kFrameEscape,
123   };
124
125   void AppendByte(std::byte new_byte);
126
127   Status CheckFrame() const;
128
129   bool VerifyFrameCheckSequence() const;
130
131   const ByteSpan buffer_;
132
133   size_t current_frame_size_;
134
135   State state_;
136 };
137
138 // DecoderBuffers declare a buffer along with a Decoder.
139 template <size_t size_bytes>
140 class DecoderBuffer : public Decoder {
141  public:
142   DecoderBuffer() : Decoder(frame_buffer_) {}
143
144   // Returns the maximum length of the bytes that can be inserted in the bytes
145   // buffer.
146   static constexpr size_t max_size() { return size_bytes; }
147
148  private:
149   static_assert(size_bytes >= Frame::kMinSizeBytes);
150
151   std::array<std::byte, size_bytes> frame_buffer_;
152 };
153
154 }  // namespace pw::hdlc_lite