C/C++ API Reference
Loading...
Searching...
No Matches
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_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
29namespace pw::hdlc {
30
32
33// Represents the contents of an HDLC frame -- the unescaped data between two
34// flag bytes. Instances of Frame are only created when a full, valid frame has
35// been read.
36class Frame {
37 public:
38 // The minimum size of a frame, excluding control bytes (flag or escape).
39 static constexpr size_t kMinContentSizeBytes =
40 kMinAddressSize + kControlSize + kFcsSize;
41
42 static Result<Frame> Parse(ConstByteSpan frame);
43
44 constexpr uint64_t address() const { return address_; }
45
46 constexpr std::byte control() const { return control_; }
47
48 constexpr ConstByteSpan data() const { return data_; }
49
50 private:
51 // Creates a Frame with the specified data. The data MUST be valid frame data
52 // with a verified frame check sequence.
53 constexpr Frame(uint64_t address, std::byte control, ConstByteSpan data)
54 : data_(data), address_(address), control_(control) {}
55
56 ConstByteSpan data_;
57 uint64_t address_;
58 std::byte control_;
59};
60
66class Decoder {
67 public:
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
90 Result<Frame> Process(std::byte new_byte);
91
95 static constexpr size_t RequiredBufferSizeForFrameSize(
96 size_t max_frame_size) {
97 // Flag bytes aren't stored in the internal buffer, so we can save a couple
98 // bytes.
99 return max_frame_size < Frame::kMinContentSizeBytes
100 ? Frame::kMinContentSizeBytes
101 : max_frame_size - 2;
102 }
103
106 template <typename F, typename... Args>
107 void Process(ConstByteSpan data, F&& callback, Args&&... args) {
108 for (std::byte b : data) {
109 auto result = Process(b);
110 if (result.status() != Status::Unavailable()) {
111 callback(std::forward<Args>(args)..., result);
112 }
113 }
114 }
115
117 size_t max_size() const { return buffer_.size(); }
118
120 void Clear() {
121 state_ = State::kInterFrame;
122 Reset();
123 }
124
125 private:
126 // State enum class is used to make the Decoder a finite state machine.
127 enum class State {
128 kInterFrame,
129 kFrame,
130 kFrameEscape,
131 };
132
133 void Reset() {
134 current_frame_size_ = 0;
135 last_read_bytes_index_ = 0;
136 fcs_.clear();
137 }
138
139 void AppendByte(std::byte new_byte);
140
141 Status CheckFrame() const;
142
143 bool VerifyFrameCheckSequence() const;
144
145 ByteSpan buffer_;
146
147 // Ring buffer of the last four bytes read into the current frame, to allow
148 // calculating the frame's CRC incrementally. As data is evicted from this
149 // buffer, it is added to the running CRC. Once a frame is complete, the
150 // buffer contains the frame's FCS.
151 std::array<std::byte, sizeof(uint32_t)> last_read_bytes_;
152 size_t last_read_bytes_index_;
153
154 // Incremental checksum of the current frame.
155 checksum::Crc32 fcs_;
156
157 size_t current_frame_size_;
158
159 State state_;
160};
161
163template <size_t kSizeBytes>
164class DecoderBuffer : public Decoder {
165 public:
166 DecoderBuffer() : Decoder(frame_buffer_) {}
167
171
175
178 static constexpr size_t max_size() { return kSizeBytes; }
179
180 private:
181 static_assert(kSizeBytes >= Frame::kMinContentSizeBytes);
182
183 std::array<std::byte, kSizeBytes> frame_buffer_;
184};
185
187
188} // namespace pw::hdlc
Definition: result.h:143
static constexpr Status Unavailable()
Definition: status.h:304
Declares a buffer along with a Decoder.
Definition: decoder.h:164
DecoderBuffer & operator=(DecoderBuffer &&)=delete
static constexpr size_t max_size()
Definition: decoder.h:178
DecoderBuffer(DecoderBuffer &&)=delete
Definition: decoder.h:66
Result< Frame > Process(std::byte new_byte)
Parses a single byte of an HDLC stream.
void Process(ConstByteSpan data, F &&callback, Args &&... args)
Processes a span of data and calls the provided callback with each frame or error.
Definition: decoder.h:107
size_t max_size() const
Definition: decoder.h:117
static constexpr size_t RequiredBufferSizeForFrameSize(size_t max_frame_size)
Definition: decoder.h:95
void Clear()
Clears and resets the decoder.
Definition: decoder.h:120
Definition: decoder.h:36