1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
15 #include "pw_hdlc/decoder.h"
17 #include "pw_assert/assert.h"
18 #include "pw_bytes/endian.h"
19 #include "pw_hdlc_private/protocol.h"
20 #include "pw_log/log.h"
26 Result<Frame> Decoder::Process(const byte new_byte) {
28 case State::kInterFrame: {
29 if (new_byte == kFlag) {
30 state_ = State::kFrame;
32 // Report an error if non-flag bytes were read between frames.
33 if (current_frame_size_ != 0u) {
35 return Status::DataLoss();
38 // Count bytes to track how many are discarded.
39 current_frame_size_ += 1;
41 return Status::Unavailable(); // Report error when starting a new frame.
44 if (new_byte == kFlag) {
45 const Status status = CheckFrame();
47 const size_t completed_frame_size = current_frame_size_;
51 return Frame(buffer_.first(completed_frame_size));
56 if (new_byte == kEscape) {
57 state_ = State::kFrameEscape;
61 return Status::Unavailable();
63 case State::kFrameEscape: {
64 // The flag character cannot be escaped; return an error.
65 if (new_byte == kFlag) {
66 state_ = State::kFrame;
68 return Status::DataLoss();
71 if (new_byte == kEscape) {
72 // Two escape characters in a row is illegal -- invalidate this frame.
73 // The frame is reported abandoned when the next flag byte appears.
74 state_ = State::kInterFrame;
76 // Count the escape byte so that the inter-frame state detects an error.
77 current_frame_size_ += 1;
79 state_ = State::kFrame;
80 AppendByte(Escape(new_byte));
82 return Status::Unavailable();
85 PW_CRASH("Bad decoder state");
88 void Decoder::AppendByte(byte new_byte) {
89 if (current_frame_size_ < max_size()) {
90 buffer_[current_frame_size_] = new_byte;
93 if (current_frame_size_ >= last_read_bytes_.size()) {
94 // A byte will be ejected. Add it to the running checksum.
95 fcs_.Update(last_read_bytes_[last_read_bytes_index_]);
98 last_read_bytes_[last_read_bytes_index_] = new_byte;
99 last_read_bytes_index_ =
100 (last_read_bytes_index_ + 1) % last_read_bytes_.size();
102 // Always increase size: if it is larger than the buffer, overflow occurred.
103 current_frame_size_ += 1;
106 Status Decoder::CheckFrame() const {
107 // Empty frames are not an error; repeated flag characters are okay.
108 if (current_frame_size_ == 0u) {
109 return Status::Unavailable();
112 if (current_frame_size_ < Frame::kMinSizeBytes) {
113 PW_LOG_ERROR("Received %lu-byte frame; frame must be at least 6 bytes",
114 static_cast<unsigned long>(current_frame_size_));
115 return Status::DataLoss();
118 if (!VerifyFrameCheckSequence()) {
119 PW_LOG_ERROR("Frame check sequence verification failed");
120 return Status::DataLoss();
123 if (current_frame_size_ > max_size()) {
124 PW_LOG_ERROR("Frame size [%lu] exceeds the maximum buffer size [%lu]",
125 static_cast<unsigned long>(current_frame_size_),
126 static_cast<unsigned long>(max_size()));
127 return Status::ResourceExhausted();
133 bool Decoder::VerifyFrameCheckSequence() const {
134 // De-ring the last four bytes read, which at this point contain the FCS.
135 std::array<std::byte, sizeof(uint32_t)> fcs_buffer;
136 size_t index = last_read_bytes_index_;
138 for (size_t i = 0; i < fcs_buffer.size(); ++i) {
139 fcs_buffer[i] = last_read_bytes_[index];
140 index = (index + 1) % last_read_bytes_.size();
143 uint32_t actual_fcs =
144 bytes::ReadInOrder<uint32_t>(std::endian::little, fcs_buffer);
145 return actual_fcs == fcs_.value();
148 } // namespace pw::hdlc