Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Side by Side Diff: tools/battor_agent/battor_connection_impl.cc

Issue 1567683002: Makes the BattOrConnection read messages instead of bytes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "tools/battor_agent/battor_connection_impl.h" 5 #include "tools/battor_agent/battor_connection_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "device/serial/buffer.h" 9 #include "device/serial/buffer.h"
10 #include "device/serial/serial_io_handler.h" 10 #include "device/serial/serial_io_handler.h"
11 #include "net/base/io_buffer.h" 11 #include "net/base/io_buffer.h"
12 12
13 using std::vector; 13 using std::vector;
14 14
15 namespace battor { 15 namespace battor {
16 16
17 namespace { 17 namespace {
18 18
19 // Serial configuration parameters for the BattOr. 19 // Serial configuration parameters for the BattOr.
20 const uint32_t kBattOrBitrate = 2000000; 20 const uint32_t kBattOrBitrate = 2000000;
21 const device::serial::DataBits kBattOrDataBits = 21 const device::serial::DataBits kBattOrDataBits =
22 device::serial::DATA_BITS_EIGHT; 22 device::serial::DATA_BITS_EIGHT;
23 const device::serial::ParityBit kBattOrParityBit = 23 const device::serial::ParityBit kBattOrParityBit =
24 device::serial::PARITY_BIT_NONE; 24 device::serial::PARITY_BIT_NONE;
25 const device::serial::StopBits kBattOrStopBit = device::serial::STOP_BITS_ONE; 25 const device::serial::StopBits kBattOrStopBit = device::serial::STOP_BITS_ONE;
26 const bool kBattOrCtsFlowControl = true; 26 const bool kBattOrCtsFlowControl = true;
27 const bool kBattOrHasCtsFlowControl = true; 27 const bool kBattOrHasCtsFlowControl = true;
28 const uint32_t kMaxMessageSize = 50000; 28 // Max message size of 50kB, accounting for start, type, end, and escape bytes.
29 29 const uint32_t kMaxMessageSize = 2 * 50000 + 3;
30 // MessageHealth describes the possible healthiness states that a partially
31 // received message could be in.
32 enum class MessageHealth {
33 INVALID,
34 INCOMPLETE,
35 COMPLETE,
36 };
37
38 // Parses the specified message.
39 // - message: The incoming message that needs to be parsed.
40 // - parsed_content: Output argument for the message content after removal of
41 // any start, end, type, and escape bytes.
42 // - health: Output argument for the health of the message.
43 // - type: Output argument for the type of message being parsed.
44 // - escape_byte_count: Output argument for the number of escape bytes
45 // removed from the parsed content.
46 void ParseMessage(const vector<char>& message,
47 vector<char>* parsed_content,
48 MessageHealth* health,
49 BattOrMessageType* type,
50 size_t* escape_byte_count) {
51 *health = MessageHealth::INCOMPLETE;
52 *type = BATTOR_MESSAGE_TYPE_CONTROL;
53 *escape_byte_count = 0;
54 parsed_content->reserve(message.size());
55
56 if (message.size() == 0)
57 return;
58
59 // The first byte is the start byte.
60 if (message[0] != BATTOR_CONTROL_BYTE_START) {
61 *health = MessageHealth::INVALID;
62 return;
63 }
64
65 if (message.size() == 1)
66 return;
67
68 // The second byte specifies the message type.
69 *type = static_cast<BattOrMessageType>(message[1]);
70
71 if (*type < static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_CONTROL) ||
72 *type > static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_PRINT)) {
73 *health = MessageHealth::INVALID;
74 return;
75 }
76
77 // After that comes the message data.
78 bool escape_next_byte = false;
79 for (size_t i = 2; i < message.size(); i++) {
80 if (i >= kMaxMessageSize) {
81 *health = MessageHealth::INVALID;
82 return;
83 }
84
85 char next_byte = message[i];
86
87 if (escape_next_byte) {
88 parsed_content->push_back(next_byte);
89 escape_next_byte = false;
90 continue;
91 }
92
93 switch (next_byte) {
94 case BATTOR_CONTROL_BYTE_START:
95 // Two start bytes in a message is invalid.
96 *health = MessageHealth::INVALID;
97 return;
98
99 case BATTOR_CONTROL_BYTE_END:
100 if (i != message.size() - 1) {
101 // We're only parsing a single message here. If we received more bytes
102 // after the end byte, what we've received so far is *not* valid.
103 *health = MessageHealth::INVALID;
104 return;
105 }
106
107 *health = MessageHealth::COMPLETE;
108 return;
109
110 case BATTOR_CONTROL_BYTE_ESCAPE:
111 escape_next_byte = true;
112 (*escape_byte_count)++;
113 continue;
114
115 default:
116 parsed_content->push_back(next_byte);
117 }
118 }
119 }
120 30
121 } // namespace 31 } // namespace
122 32
123 BattOrConnectionImpl::BattOrConnectionImpl( 33 BattOrConnectionImpl::BattOrConnectionImpl(
124 const std::string& path, 34 const std::string& path,
125 BattOrConnection::Listener* listener, 35 BattOrConnection::Listener* listener,
126 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, 36 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner,
127 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) 37 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
128 : BattOrConnection(listener), 38 : BattOrConnection(listener),
129 path_(path), 39 path_(path),
40 pending_read_max_length_(0),
130 file_thread_task_runner_(file_thread_task_runner), 41 file_thread_task_runner_(file_thread_task_runner),
131 ui_thread_task_runner_(ui_thread_task_runner) {} 42 ui_thread_task_runner_(ui_thread_task_runner) {}
132 43
133 BattOrConnectionImpl::~BattOrConnectionImpl() {} 44 BattOrConnectionImpl::~BattOrConnectionImpl() {}
134 45
135 void BattOrConnectionImpl::Open() { 46 void BattOrConnectionImpl::Open() {
136 if (io_handler_) { 47 if (io_handler_) {
137 OnOpened(true); 48 OnOpened(true);
138 return; 49 return;
139 } 50 }
(...skipping 21 matching lines...) Expand all
161 72
162 void BattOrConnectionImpl::Close() { 73 void BattOrConnectionImpl::Close() {
163 io_handler_ = nullptr; 74 io_handler_ = nullptr;
164 } 75 }
165 76
166 void BattOrConnectionImpl::SendBytes(BattOrMessageType type, 77 void BattOrConnectionImpl::SendBytes(BattOrMessageType type,
167 const void* buffer, 78 const void* buffer,
168 size_t bytes_to_send) { 79 size_t bytes_to_send) {
169 const char* bytes = reinterpret_cast<const char*>(buffer); 80 const char* bytes = reinterpret_cast<const char*>(buffer);
170 81
171 // Reserve a send buffer with 3 extra bytes (start, type, and end byte) and 82 // Reserve a send buffer with enough extra bytes for the start, type, end, and
172 // twice as many bytes as we're actually sending, because each raw data byte 83 // escape bytes.
173 // might need to be escaped.
174 vector<char> data; 84 vector<char> data;
175 data.reserve(2 * bytes_to_send + 3); 85 data.reserve(2 * bytes_to_send + 3);
176 86
177 data.push_back(BATTOR_CONTROL_BYTE_START); 87 data.push_back(BATTOR_CONTROL_BYTE_START);
178 data.push_back(type); 88 data.push_back(type);
179 89
180 for (size_t i = 0; i < bytes_to_send; i++) { 90 for (size_t i = 0; i < bytes_to_send; i++) {
181 if (bytes[i] == BATTOR_CONTROL_BYTE_START || 91 if (bytes[i] == BATTOR_CONTROL_BYTE_START ||
182 bytes[i] == BATTOR_CONTROL_BYTE_END) { 92 bytes[i] == BATTOR_CONTROL_BYTE_END) {
183 data.push_back(BATTOR_CONTROL_BYTE_ESCAPE); 93 data.push_back(BATTOR_CONTROL_BYTE_ESCAPE);
184 } 94 }
185 95
186 data.push_back(bytes[i]); 96 data.push_back(bytes[i]);
187 } 97 }
188 98
189 data.push_back(BATTOR_CONTROL_BYTE_END); 99 data.push_back(BATTOR_CONTROL_BYTE_END);
190 100
191 pending_write_length_ = data.size(); 101 pending_write_length_ = data.size();
192 io_handler_->Write(make_scoped_ptr(new device::SendBuffer( 102 io_handler_->Write(make_scoped_ptr(new device::SendBuffer(
193 data, base::Bind(&BattOrConnectionImpl::OnBytesSent, AsWeakPtr())))); 103 data, base::Bind(&BattOrConnectionImpl::OnBytesSent, AsWeakPtr()))));
194 } 104 }
195 105
196 void BattOrConnectionImpl::ReadBytes(size_t bytes_to_read) { 106 void BattOrConnectionImpl::ReadMessage(size_t max_data_bytes_to_read) {
197 // Allocate a read buffer and reserve enough space in it to account for the 107 // Read any bytes we might need to in a single read. Allow for the start,
198 // start, type, end, and escape bytes. 108 // type, and end bytes, as well as escape bytes.
199 pending_read_buffer_.reset(new vector<char>()); 109 size_t max_bytes_to_read = max_data_bytes_to_read * 2 + 3;
200 pending_read_buffer_->reserve(2 * bytes_to_read + 3);
201 pending_read_escape_byte_count_ = 0;
202 110
203 // Add 3 bytes to however many bytes the caller requested because we know 111 // Check the left-over bytes from the last read to make sure that we don't
204 // we'll have to read the start, type, and end bytes. 112 // already have a full message.
205 bytes_to_read += 3; 113 BattOrMessageType type;
114 scoped_ptr<vector<char>> msg(new vector<char>());
115 msg->reserve(max_bytes_to_read);
206 116
207 ReadMoreBytes(bytes_to_read); 117 if (ParseMessage(&type, msg.get())) {
118 listener_->OnMessageRead(true, type, std::move(msg));
119 return;
120 }
121
122 BeginReadBytes(max_bytes_to_read - already_read_buffer_.size());
208 } 123 }
209 124
210 void BattOrConnectionImpl::Flush() { 125 void BattOrConnectionImpl::Flush() {
211 io_handler_->Flush(); 126 io_handler_->Flush();
127 already_read_buffer_.clear();
212 } 128 }
213 129
214 scoped_refptr<device::SerialIoHandler> BattOrConnectionImpl::CreateIoHandler() { 130 scoped_refptr<device::SerialIoHandler> BattOrConnectionImpl::CreateIoHandler() {
215 return device::SerialIoHandler::Create(file_thread_task_runner_, 131 return device::SerialIoHandler::Create(file_thread_task_runner_,
216 ui_thread_task_runner_); 132 ui_thread_task_runner_);
217 } 133 }
218 134
219 void BattOrConnectionImpl::ReadMoreBytes(size_t bytes_to_read) { 135 void BattOrConnectionImpl::BeginReadBytes(size_t max_bytes_to_read) {
220 last_read_buffer_ = make_scoped_refptr(new net::IOBuffer(bytes_to_read)); 136 pending_read_buffer_ =
137 make_scoped_refptr(new net::IOBuffer(max_bytes_to_read));
138 pending_read_max_length_ = max_bytes_to_read;
139
221 auto on_receive_buffer_filled = 140 auto on_receive_buffer_filled =
222 base::Bind(&BattOrConnectionImpl::OnBytesRead, AsWeakPtr()); 141 base::Bind(&BattOrConnectionImpl::OnBytesRead, AsWeakPtr());
223 142
224 pending_read_length_ = bytes_to_read;
225 io_handler_->Read(make_scoped_ptr(new device::ReceiveBuffer( 143 io_handler_->Read(make_scoped_ptr(new device::ReceiveBuffer(
226 last_read_buffer_, bytes_to_read, on_receive_buffer_filled))); 144 pending_read_buffer_, max_bytes_to_read, on_receive_buffer_filled)));
227 } 145 }
228 146
229 void BattOrConnectionImpl::OnBytesRead(int bytes_read, 147 void BattOrConnectionImpl::OnBytesRead(int bytes_read,
230 device::serial::ReceiveError error) { 148 device::serial::ReceiveError error) {
231 if ((static_cast<size_t>(bytes_read) < pending_read_length_) || 149 if (bytes_read == 0 || error != device::serial::RECEIVE_ERROR_NONE) {
232 (error != device::serial::RECEIVE_ERROR_NONE)) { 150 // If we didn't have a message before, and we weren't able to read any
233 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr); 151 // additional bytes, then there's no valid message available.
152 EndReadBytes(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
234 return; 153 return;
235 } 154 }
236 155
237 pending_read_buffer_->insert(pending_read_buffer_->end(), 156 already_read_buffer_.insert(already_read_buffer_.end(),
238 last_read_buffer_->data(), 157 pending_read_buffer_->data(),
239 last_read_buffer_->data() + bytes_read); 158 pending_read_buffer_->data() + bytes_read);
240 159
241 scoped_ptr<vector<char>> parsed_content(new vector<char>());
242 MessageHealth health;
243 BattOrMessageType type; 160 BattOrMessageType type;
244 size_t escape_byte_count; 161 scoped_ptr<vector<char>> bytes(new vector<char>());
162 bytes->reserve(already_read_buffer_.size() + pending_read_max_length_);
245 163
246 ParseMessage(*pending_read_buffer_, parsed_content.get(), &health, &type, 164 if (!ParseMessage(&type, bytes.get())) {
247 &escape_byte_count); 165 // Even after reading the max number of bytes, we still don't have a valid
248 166 // message.
249 if (health == MessageHealth::INVALID) { 167 EndReadBytes(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
250 // If we already have an invalid message, there's no sense in continuing to
251 // process it.
252 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
253 return; 168 return;
254 } 169 }
255 170
256 size_t new_escape_bytes = escape_byte_count - pending_read_escape_byte_count_; 171 EndReadBytes(true, type, std::move(bytes));
257 pending_read_escape_byte_count_ = escape_byte_count; 172 }
258 173
259 if (new_escape_bytes > 0) { 174 void BattOrConnectionImpl::EndReadBytes(bool success,
260 // When the caller requested that we read X additional bytes, they weren't 175 BattOrMessageType type,
261 // taking into account any escape bytes that we received. Because we got 176 scoped_ptr<std::vector<char>> bytes) {
262 // some escape bytes, we need to fire off another read to get the rest of 177 pending_read_buffer_ = nullptr;
263 // the data. 178 pending_read_max_length_ = 0;
264 ReadMoreBytes(new_escape_bytes); 179
265 return; 180 listener_->OnMessageRead(success, type, std::move(bytes));
181 }
182
183 bool BattOrConnectionImpl::ParseMessage(BattOrMessageType* type,
184 vector<char>* bytes) {
185 if (already_read_buffer_.size() <= 3)
186 return false;
187
188 // The first byte is the start byte.
189 if (already_read_buffer_[0] != BATTOR_CONTROL_BYTE_START) {
190 return false;
266 } 191 }
267 192
268 if (health == MessageHealth::INCOMPLETE) 193 // The second byte specifies the message type.
269 // If everything is valid and we didn't see any escape bytes, then we should 194 *type = static_cast<BattOrMessageType>(already_read_buffer_[1]);
270 // have the whole message. If we don't, the message was malformed.
271 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
272 195
273 // If we've gotten this far, we've received the whole, well-formed message. 196 if (*type < static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_CONTROL) ||
274 listener_->OnBytesRead(true, type, std::move(parsed_content)); 197 *type > static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_PRINT)) {
198 return false;
199 }
200
201 // After that comes the message bytes.
202 bool escape_next_byte = false;
203 for (size_t i = 2; i < already_read_buffer_.size(); i++) {
204 if (i >= kMaxMessageSize) // || i >= pending_read_max_length_) // )
nednguyen 2016/01/06 22:03:13 What is the comment on the right for?
charliea (OOO until 10-5) 2016/01/07 16:00:12 Doh, sorry. This is just crud left over from codin
205 return false;
206
207 char next_byte = already_read_buffer_[i];
208
209 if (escape_next_byte) {
210 bytes->push_back(next_byte);
211 escape_next_byte = false;
212 continue;
213 }
214
215 switch (next_byte) {
216 case BATTOR_CONTROL_BYTE_START:
217 // Two start bytes in a message is invalid.
218 return false;
219
220 case BATTOR_CONTROL_BYTE_END:
221 already_read_buffer_.erase(already_read_buffer_.begin(),
222 already_read_buffer_.begin() + i + 1);
223 return true;
224
225 case BATTOR_CONTROL_BYTE_ESCAPE:
226 escape_next_byte = true;
227 continue;
228
229 default:
230 bytes->push_back(next_byte);
231 }
232 }
233
234 // If we made it to the end of the read buffer and no end byte was seen, then
235 // we don't have a complete message.
236 return false;
275 } 237 }
276 238
277 void BattOrConnectionImpl::OnBytesSent(int bytes_sent, 239 void BattOrConnectionImpl::OnBytesSent(int bytes_sent,
278 device::serial::SendError error) { 240 device::serial::SendError error) {
279 bool success = (error == device::serial::SEND_ERROR_NONE) && 241 bool success = (error == device::serial::SEND_ERROR_NONE) &&
280 (pending_write_length_ == static_cast<size_t>(bytes_sent)); 242 (pending_write_length_ == static_cast<size_t>(bytes_sent));
281 listener_->OnBytesSent(success); 243 listener_->OnBytesSent(success);
282 } 244 }
283 245
284 } // namespace battor 246 } // namespace battor
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698