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

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

Issue 1524873002: Creates a BattOrConnection for communicating with the BattOr (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Code review Created 5 years 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "tools/battor_agent/battor_connection.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "device/serial/buffer.h"
10 #include "device/serial/serial_io_handler.h"
11 #include "net/base/io_buffer.h"
12
13 using std::vector;
14
15 namespace battor {
16
17 namespace {
18
19 // Serial configuration parameters for the BattOr.
20 const uint32_t kBattOrBitrate = 2000000;
21 const device::serial::DataBits kBattOrDataBits =
22 device::serial::DATA_BITS_EIGHT;
23 const device::serial::ParityBit kBattOrParityBit =
24 device::serial::PARITY_BIT_NONE;
25 const device::serial::StopBits kBattOrStopBit = device::serial::STOP_BITS_ONE;
26 const bool kBattOrCtsFlowControl = true;
27 const bool kBattOrHasCtsFlowControl = true;
28 const uint32_t kMaxMessageSize = 50000;
29
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 //
Zhen Wang 2015/12/16 18:01:41 nit: remove the empty line.
charliea (OOO until 10-5) 2015/12/16 18:27:55 Done.
40 // - message: The incoming message that needs to be parsed.
41 // - parsed_content: Output argument for the message content after removal of
42 // any start, end, type, and escape bytes.
43 // - health: Output argument for the health of the message.
44 // - type: Output argument for the type of message being parsed.
45 // - escape_byte_count: Output argument for the number of escape bytes
46 // removed from the parsed content.
47 void ParseMessage(const vector<char>& message,
48 vector<char>* parsed_content,
49 MessageHealth* health,
50 BattOrMessageType* type,
51 size_t* escape_byte_count) {
52 *health = MessageHealth::INCOMPLETE;
53 *type = BATTOR_MESSAGE_TYPE_CONTROL;
54 *escape_byte_count = 0;
55 parsed_content->reserve(message.size());
56
57 if (message.size() == 0)
58 return;
59
60 // The first byte is the start byte.
61 if (message[0] != BATTOR_CONTROL_BYTE_START) {
62 *health = MessageHealth::INVALID;
63 return;
64 }
65
66 if (message.size() == 1)
67 return;
68
69 // The second byte specifies the message type.
70 *type = static_cast<BattOrMessageType>(message[1]);
71
72 if (*type < static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_CONTROL) ||
73 *type > static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_PRINT)) {
74 *health = MessageHealth::INVALID;
75 return;
76 }
77
78 // After that comes the message data.
79 bool escape_next_byte = false;
80 for (size_t i = 2; i < message.size(); i++) {
81 if (i >= kMaxMessageSize) {
82 *health = MessageHealth::INVALID;
83 return;
84 }
85
86 char next_byte = message[i];
87
88 if (escape_next_byte) {
89 parsed_content->push_back(next_byte);
90 escape_next_byte = false;
91 continue;
92 }
93
94 switch (next_byte) {
95 case BATTOR_CONTROL_BYTE_START:
96 // Two start bytes in a message is invalid.
97 *health = MessageHealth::INVALID;
98 return;
99
100 case BATTOR_CONTROL_BYTE_END:
101 if (i != message.size() - 1) {
102 // We're only parsing a single message here. If we received more bytes
103 // after the end byte, what we've received so far is *not* valid.
104 *health = MessageHealth::INVALID;
105 return;
106 }
107
108 *health = MessageHealth::COMPLETE;
109 return;
110
111 case BATTOR_CONTROL_BYTE_ESCAPE:
112 escape_next_byte = true;
113 (*escape_byte_count)++;
114 continue;
115
116 default:
117 parsed_content->push_back(next_byte);
118 }
119 }
120 }
121
122 } // namespace
123
124 BattOrConnection::BattOrConnection(
125 const std::string& path,
126 base::WeakPtr<Listener> listener,
127 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner,
128 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
129 : path_(path),
130 listener_(listener),
131 file_thread_task_runner_(file_thread_task_runner),
132 ui_thread_task_runner_(ui_thread_task_runner) {}
133
134 BattOrConnection::~BattOrConnection() {}
135
136 void BattOrConnection::Open() {
137 io_handler_ = CreateIoHandler();
138
139 device::serial::ConnectionOptions options;
140 options.bitrate = kBattOrBitrate;
141 options.data_bits = kBattOrDataBits;
142 options.parity_bit = kBattOrParityBit;
143 options.stop_bits = kBattOrStopBit;
144 options.cts_flow_control = kBattOrCtsFlowControl;
145 options.has_cts_flow_control = kBattOrHasCtsFlowControl;
146
147 io_handler_->Open(path_, options,
148 base::Bind(&BattOrConnection::OnOpened, AsWeakPtr()));
149 }
150
151 void BattOrConnection::OnOpened(bool success) {
152 if (!success)
153 Close();
154
155 listener_->OnConnectionOpened(success);
156 }
157
158 bool BattOrConnection::IsOpen() {
159 return io_handler_;
160 }
161
162 void BattOrConnection::Close() {
163 io_handler_ = nullptr;
164 }
165
166 void BattOrConnection::SendBytes(BattOrMessageType type,
167 const void* buffer,
168 size_t bytes_to_send) {
169 const char* bytes = reinterpret_cast<const char*>(buffer);
170
171 // Reserve a send buffer with 3 extra bytes (start, type, and end byte) and
172 // twice as many bytes as we're actually sending, because each raw data byte
173 // might need to be escaped.
174 vector<char> data;
175 data.reserve(2 * bytes_to_send + 3);
176
177 data.push_back(BATTOR_CONTROL_BYTE_START);
178 data.push_back(type);
179
180 for (size_t i = 0; i < bytes_to_send; i++) {
181 if (bytes[i] == BATTOR_CONTROL_BYTE_START ||
182 bytes[i] == BATTOR_CONTROL_BYTE_END) {
183 data.push_back(BATTOR_CONTROL_BYTE_ESCAPE);
184 }
185
186 data.push_back(bytes[i]);
187 }
188
189 data.push_back(BATTOR_CONTROL_BYTE_END);
190
191 pending_write_length_ = data.size();
192 io_handler_->Write(make_scoped_ptr(new device::SendBuffer(
193 data, base::Bind(&BattOrConnection::OnBytesSent, AsWeakPtr()))));
194 }
195
196 void BattOrConnection::ReadBytes(size_t bytes_to_read) {
197 // Allocate a read buffer and reserve enough space in it to account for the
198 // start, type, end, and escape bytes.
199 pending_read_buffer_.reset(new vector<char>());
200 pending_read_buffer_->reserve(2 * bytes_to_read + 3);
201 pending_read_escape_byte_count_ = 0;
202
203 // Add 3 bytes to however many bytes the caller requested because we know
204 // we'll have to read the start, type, and end bytes.
205 bytes_to_read += 3;
206
207 ReadMoreBytes(bytes_to_read);
208 }
209
210 void BattOrConnection::Flush() {
211 io_handler_->Flush();
212 }
213
214 scoped_refptr<device::SerialIoHandler> BattOrConnection::CreateIoHandler() {
215 return device::SerialIoHandler::Create(file_thread_task_runner_,
216 ui_thread_task_runner_);
217 }
218
219 void BattOrConnection::ReadMoreBytes(size_t bytes_to_read) {
220 last_read_buffer_ = make_scoped_refptr(new net::IOBuffer(bytes_to_read));
221 auto on_receive_buffer_filled =
222 base::Bind(&BattOrConnection::OnBytesRead, AsWeakPtr());
223
224 pending_read_length_ = bytes_to_read;
225 io_handler_->Read(make_scoped_ptr(new device::ReceiveBuffer(
226 last_read_buffer_, bytes_to_read, on_receive_buffer_filled)));
227 }
228
229 void BattOrConnection::OnBytesSent(int bytes_sent,
230 device::serial::SendError error) {
231 bool success = (error == device::serial::SEND_ERROR_NONE) &&
232 (pending_write_length_ == static_cast<size_t>(bytes_sent));
233 listener_->OnBytesSent(success);
234 }
235
236 void BattOrConnection::OnBytesRead(int bytes_read,
Primiano Tucci (use gerrit) 2015/12/16 16:47:43 nit: you probably want to reorder this so that OnB
charliea (OOO until 10-5) 2015/12/16 18:27:55 Done (here and in the header file).
237 device::serial::ReceiveError error) {
238 if ((static_cast<size_t>(bytes_read) < pending_read_length_) ||
239 (error != device::serial::RECEIVE_ERROR_NONE)) {
240 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
241 return;
242 }
243
244 pending_read_buffer_->insert(pending_read_buffer_->end(),
245 last_read_buffer_->data(),
246 last_read_buffer_->data() + bytes_read);
247
248 scoped_ptr<vector<char>> parsed_content(new vector<char>());
249 MessageHealth health;
250 BattOrMessageType type;
251 size_t escape_byte_count;
252
253 ParseMessage(*pending_read_buffer_, parsed_content.get(), &health, &type,
254 &escape_byte_count);
255
256 if (health == MessageHealth::INVALID) {
257 // If we already have an invalid message, there's no sense in continuing to
258 // process it.
259 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
260 return;
261 }
262
263 size_t new_escape_bytes = escape_byte_count - pending_read_escape_byte_count_;
264 pending_read_escape_byte_count_ = escape_byte_count;
265
266 if (new_escape_bytes > 0) {
267 // When the caller requested that we read X additional bytes, they weren't
268 // taking into account any escape bytes that we received. Because we got
269 // some escape bytes, we need to fire off another read to get the rest of
270 // the data.
271 ReadMoreBytes(new_escape_bytes);
272 return;
273 }
274
275 if (health != MessageHealth::COMPLETE)
Zhen Wang 2015/12/16 18:01:41 nit: I think (health == MessageHealth::INCOMPLETE)
charliea (OOO until 10-5) 2015/12/16 18:27:55 Ah, yea, I agree. Done.
276 // If everything is valid and we didn't see any escape bytes, then we should
277 // have the whole message. If we don't, the message was malformed.
278 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
279
280 // If we've gotten this far, we've received the whole, well-formed message.
281 listener_->OnBytesRead(true, type, parsed_content.Pass());
Primiano Tucci (use gerrit) 2015/12/16 16:47:43 One general comment about callbacks: think about r
charliea (OOO until 10-5) 2015/12/16 18:27:55 Ah, interesting! Thanks for the explanation. I'd s
282 }
283
284 } // namespace battor
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698