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

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: Added missing dep 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 // - 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
121 } // namespace
122
123 BattOrConnection::BattOrConnection(
124 const std::string& path,
125 Listener* listener,
126 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner,
127 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
128 : path_(path),
129 listener_(listener),
130 file_thread_task_runner_(file_thread_task_runner),
131 ui_thread_task_runner_(ui_thread_task_runner) {}
132
133 BattOrConnection::~BattOrConnection() {}
134
135 void BattOrConnection::Open() {
136 io_handler_ = CreateIoHandler();
137
138 device::serial::ConnectionOptions options;
139 options.bitrate = kBattOrBitrate;
140 options.data_bits = kBattOrDataBits;
141 options.parity_bit = kBattOrParityBit;
142 options.stop_bits = kBattOrStopBit;
143 options.cts_flow_control = kBattOrCtsFlowControl;
144 options.has_cts_flow_control = kBattOrHasCtsFlowControl;
145
146 io_handler_->Open(path_, options,
147 base::Bind(&BattOrConnection::OnOpened, AsWeakPtr()));
148 }
149
150 void BattOrConnection::OnOpened(bool success) {
151 if (!success)
152 Close();
153
154 listener_->OnConnectionOpened(success);
155 }
156
157 bool BattOrConnection::IsOpen() {
158 return io_handler_;
159 }
160
161 void BattOrConnection::Close() {
162 io_handler_ = nullptr;
163 }
164
165 void BattOrConnection::SendBytes(BattOrMessageType type,
166 const void* buffer,
167 size_t bytes_to_send) {
168 const char* bytes = reinterpret_cast<const char*>(buffer);
169
170 // Reserve a send buffer with 3 extra bytes (start, type, and end byte) and
171 // twice as many bytes as we're actually sending, because each raw data byte
172 // might need to be escaped.
173 vector<char> data;
174 data.reserve(2 * bytes_to_send + 3);
175
176 data.push_back(BATTOR_CONTROL_BYTE_START);
177 data.push_back(type);
178
179 for (size_t i = 0; i < bytes_to_send; i++) {
180 if (bytes[i] == BATTOR_CONTROL_BYTE_START ||
181 bytes[i] == BATTOR_CONTROL_BYTE_END) {
182 data.push_back(BATTOR_CONTROL_BYTE_ESCAPE);
183 }
184
185 data.push_back(bytes[i]);
186 }
187
188 data.push_back(BATTOR_CONTROL_BYTE_END);
189
190 pending_write_length_ = data.size();
191 io_handler_->Write(make_scoped_ptr(new device::SendBuffer(
192 data, base::Bind(&BattOrConnection::OnBytesSent, AsWeakPtr()))));
193 }
194
195 void BattOrConnection::ReadBytes(size_t bytes_to_read) {
196 // Allocate a read buffer and reserve enough space in it to account for the
197 // start, type, end, and escape bytes.
198 pending_read_buffer_.reset(new vector<char>());
199 pending_read_buffer_->reserve(2 * bytes_to_read + 3);
200 pending_read_escape_byte_count_ = 0;
201
202 // Add 3 bytes to however many bytes the caller requested because we know
203 // we'll have to read the start, type, and end bytes.
204 bytes_to_read += 3;
205
206 ReadMoreBytes(bytes_to_read);
207 }
208
209 void BattOrConnection::Flush() {
210 io_handler_->Flush();
211 }
212
213 scoped_refptr<device::SerialIoHandler> BattOrConnection::CreateIoHandler() {
214 return device::SerialIoHandler::Create(file_thread_task_runner_,
215 ui_thread_task_runner_);
216 }
217
218 void BattOrConnection::ReadMoreBytes(size_t bytes_to_read) {
219 last_read_buffer_ = make_scoped_refptr(new net::IOBuffer(bytes_to_read));
220 auto on_receive_buffer_filled =
221 base::Bind(&BattOrConnection::OnBytesRead, AsWeakPtr());
222
223 pending_read_length_ = bytes_to_read;
224 io_handler_->Read(make_scoped_ptr(new device::ReceiveBuffer(
225 last_read_buffer_, bytes_to_read, on_receive_buffer_filled)));
226 }
227
228 void BattOrConnection::OnBytesRead(int bytes_read,
229 device::serial::ReceiveError error) {
230 if ((static_cast<size_t>(bytes_read) < pending_read_length_) ||
231 (error != device::serial::RECEIVE_ERROR_NONE)) {
232 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
233 return;
234 }
235
236 pending_read_buffer_->insert(pending_read_buffer_->end(),
237 last_read_buffer_->data(),
238 last_read_buffer_->data() + bytes_read);
239
240 scoped_ptr<vector<char>> parsed_content(new vector<char>());
241 MessageHealth health;
242 BattOrMessageType type;
243 size_t escape_byte_count;
244
245 ParseMessage(*pending_read_buffer_, parsed_content.get(), &health, &type,
246 &escape_byte_count);
247
248 if (health == MessageHealth::INVALID) {
249 // If we already have an invalid message, there's no sense in continuing to
250 // process it.
251 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
252 return;
253 }
254
255 size_t new_escape_bytes = escape_byte_count - pending_read_escape_byte_count_;
256 pending_read_escape_byte_count_ = escape_byte_count;
257
258 if (new_escape_bytes > 0) {
259 // When the caller requested that we read X additional bytes, they weren't
260 // taking into account any escape bytes that we received. Because we got
261 // some escape bytes, we need to fire off another read to get the rest of
262 // the data.
263 ReadMoreBytes(new_escape_bytes);
264 return;
265 }
266
267 if (health == MessageHealth::INCOMPLETE)
268 // If everything is valid and we didn't see any escape bytes, then we should
269 // have the whole message. If we don't, the message was malformed.
270 listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr);
271
272 // If we've gotten this far, we've received the whole, well-formed message.
273 listener_->OnBytesRead(true, type, parsed_content.Pass());
274 }
275
276 void BattOrConnection::OnBytesSent(int bytes_sent,
277 device::serial::SendError error) {
278 bool success = (error == device::serial::SEND_ERROR_NONE) &&
279 (pending_write_length_ == static_cast<size_t>(bytes_sent));
280 listener_->OnBytesSent(success);
281 }
282
283 } // namespace battor
OLDNEW
« no previous file with comments | « tools/battor_agent/battor_connection.h ('k') | tools/battor_agent/battor_connection_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698