Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_hdlc / decoder.cc
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
15 #include "pw_hdlc/decoder.h"
16
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"
21
22 using std::byte;
23
24 namespace pw::hdlc {
25
26 Result<Frame> Decoder::Process(const byte new_byte) {
27   switch (state_) {
28     case State::kInterFrame: {
29       if (new_byte == kFlag) {
30         state_ = State::kFrame;
31
32         // Report an error if non-flag bytes were read between frames.
33         if (current_frame_size_ != 0u) {
34           Reset();
35           return Status::DataLoss();
36         }
37       } else {
38         // Count bytes to track how many are discarded.
39         current_frame_size_ += 1;
40       }
41       return Status::Unavailable();  // Report error when starting a new frame.
42     }
43     case State::kFrame: {
44       if (new_byte == kFlag) {
45         const Status status = CheckFrame();
46
47         const size_t completed_frame_size = current_frame_size_;
48         Reset();
49
50         if (status.ok()) {
51           return Frame(buffer_.first(completed_frame_size));
52         }
53         return status;
54       }
55
56       if (new_byte == kEscape) {
57         state_ = State::kFrameEscape;
58       } else {
59         AppendByte(new_byte);
60       }
61       return Status::Unavailable();
62     }
63     case State::kFrameEscape: {
64       // The flag character cannot be escaped; return an error.
65       if (new_byte == kFlag) {
66         state_ = State::kFrame;
67         Reset();
68         return Status::DataLoss();
69       }
70
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;
75
76         // Count the escape byte so that the inter-frame state detects an error.
77         current_frame_size_ += 1;
78       } else {
79         state_ = State::kFrame;
80         AppendByte(Escape(new_byte));
81       }
82       return Status::Unavailable();
83     }
84   }
85   PW_CRASH("Bad decoder state");
86 }
87
88 void Decoder::AppendByte(byte new_byte) {
89   if (current_frame_size_ < max_size()) {
90     buffer_[current_frame_size_] = new_byte;
91   }
92
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_]);
96   }
97
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();
101
102   // Always increase size: if it is larger than the buffer, overflow occurred.
103   current_frame_size_ += 1;
104 }
105
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();
110   }
111
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();
116   }
117
118   if (!VerifyFrameCheckSequence()) {
119     PW_LOG_ERROR("Frame check sequence verification failed");
120     return Status::DataLoss();
121   }
122
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();
128   }
129
130   return OkStatus();
131 }
132
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_;
137
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();
141   }
142
143   uint32_t actual_fcs =
144       bytes::ReadInOrder<uint32_t>(std::endian::little, fcs_buffer);
145   return actual_fcs == fcs_.value();
146 }
147
148 }  // namespace pw::hdlc