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

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: 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 kBattOrBitrate = 2000000;
Primiano Tucci (use gerrit) 2015/12/15 11:07:20 nit s/uint32/uint32_t/ :the non stdint versions ar
charliea (OOO until 10-5) 2015/12/15 23:50:04 Done.
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 kMaxMessageSize = 50000;
Primiano Tucci (use gerrit) 2015/12/15 11:07:20 ditto uint32_t
charliea (OOO until 10-5) 2015/12/15 23:50:04 Done.
29
30 // Parses the specified message, extracting:
31 //
32 // - The message content (the bytes after the start byte and message type but
33 // before the end byte)
34 // - Whether the message is complete
35 // - Whether the message is valid so far
36 // - The type of the message
37 // - The number of escape bytes contained in the message
Zhen Wang 2015/12/14 23:39:46 Can you make the argument match the explanation? F
charliea (OOO until 10-5) 2015/12/15 23:50:04 Done. I also consolidated is_complete and is_inval
38 void ParseMessage(const vector<char>* message,
Primiano Tucci (use gerrit) 2015/12/15 11:07:20 ordering of arguments: input arguments should come
charliea (OOO until 10-5) 2015/12/15 23:50:04 Done.
39 vector<char>* message_content,
40 bool* is_complete,
41 bool* is_valid_so_far,
42 BattOrMessageType* type,
43 uint16_t* escape_byte_count) {
44 *is_complete = false;
45 *is_valid_so_far = true;
46 *type = BATTOR_MESSAGE_TYPE_CONTROL;
47 *escape_byte_count = 0;
48 message_content->reserve(message->size());
49
50 if (message->size() == 0)
51 return;
52
53 // The first byte is the start byte.
54 if ((*message)[0] != BATTOR_SPECIAL_BYTE_START) {
55 *is_valid_so_far = false;
56 return;
57 }
58
59 if (message->size() == 1)
60 return;
61
62 // The second byte specifies the message type.
63 *type = static_cast<BattOrMessageType>((*message)[1]);
Primiano Tucci (use gerrit) 2015/12/15 11:07:19 shouldn't you CHECK that *type isn't > MESSAGE_TYP
charliea (OOO until 10-5) 2015/12/15 23:50:04 Done. I didn't CHECK though, because it's possible
64
65 // After that comes the message data.
66 bool escape_next_byte = false;
67 for (size_t i = 2; i < message->size(); i++) {
68 if (i >= kMaxMessageSize) {
69 *is_valid_so_far = false;
70 return;
71 }
72
73 char next_byte = (*message)[i];
74
75 if (escape_next_byte) {
76 message_content->push_back(next_byte);
77 escape_next_byte = false;
78 continue;
79 }
80
81 switch (next_byte) {
82 case BATTOR_SPECIAL_BYTE_START:
83 // Two start bytes in a message is invalid.
84 *is_valid_so_far = false;
85 return;
86
87 case BATTOR_SPECIAL_BYTE_END:
88 // We've found the end of the message. Make sure that we're at the end
89 // of the message.
90 *is_complete = true;
91
92 // We're only parsing a single message here. If there are additional
93 // bytes after this byte, what we've received so far is *not* a valid
94 // message.
95 *is_valid_so_far = (i == message->size() - 1);
96 return;
97
98 case BATTOR_SPECIAL_BYTE_ESCAPE:
99 escape_next_byte = true;
100 (*escape_byte_count)++;
101 continue;
102
103 default:
104 message_content->push_back(next_byte);
105 }
106 }
107 }
108
109 } // namespace
110
111 BattOrConnection::BattOrConnection(
112 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner,
113 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
114 : file_thread_task_runner_(file_thread_task_runner),
115 ui_thread_task_runner_(ui_thread_task_runner) {}
116
117 BattOrConnection::~BattOrConnection() {}
118
119 void BattOrConnection::Connect(
120 const std::string& path,
121 const base::Callback<void(bool success)> callback) {
122 io_handler_ = CreateIoHandler();
123
124 device::serial::ConnectionOptions options;
125 options.bitrate = kBattOrBitrate;
126 options.data_bits = kBattOrDataBits;
127 options.parity_bit = kBattOrParityBit;
128 options.stop_bits = kBattOrStopBit;
129 options.cts_flow_control = kBattOrCtsFlowControl;
130 options.has_cts_flow_control = kBattOrHasCtsFlowControl;
131
132 io_handler_->Open(path, options, callback);
133 }
134
135 void BattOrConnection::SendBytes(const SendCallback& callback,
136 BattOrMessageType type,
Zhen Wang 2015/12/14 23:39:46 wrong indent
charliea (OOO until 10-5) 2015/12/15 23:50:04 Doh. Looks like I forgot to rerun git cl format af
137 const char* bytes,
138 uint16_t bytes_to_send) {
Zhen Wang 2015/12/14 23:39:46 DCHECK the length of bytes == bytes_to_send.
Primiano Tucci (use gerrit) 2015/12/15 11:07:19 well, how if they are not a string (read: can gene
charliea (OOO until 10-5) 2015/12/15 23:50:04 Yea, I don't think that it's possible to determine
139 vector<char> data_vector;
Primiano Tucci (use gerrit) 2015/12/15 11:07:19 just "data" should be enough. It's clear its a vec
charliea (OOO until 10-5) 2015/12/15 23:50:04 Ah, sorry about that. At some point, the incoming
140
141 // BattOr messages have the following format:
142 //
143 // 0x00 (1 byte start marker)
144 // uint8_t (1 byte header indicating the message type)
145 // data (message data, with 0x00s and 0x01s escaped with 0x02)
146 // 0x01 (1 byte end marker)
147 //
148 // We have to encode any data we're sending in this format. Because of this,
149 // we should reserve a send buffer with 3 bytes (start, header, end) and twice
150 // as many bytes as we're sending, because each raw data byte might need to be
151 // escaped.
152 data_vector.reserve(2 * bytes_to_send + 3);
153
154 data_vector.push_back(BATTOR_SPECIAL_BYTE_START);
155 data_vector.push_back(type);
156
157 for (int i = 0; i < bytes_to_send; i++) {
158 if (bytes[i] == BATTOR_SPECIAL_BYTE_START ||
159 bytes[i] == BATTOR_SPECIAL_BYTE_END)
160 data_vector.push_back(BATTOR_SPECIAL_BYTE_ESCAPE);
Zhen Wang 2015/12/14 23:39:46 Add {...} when if clause takes more than 1 line.
charliea (OOO until 10-5) 2015/12/15 23:50:04 Done.
161
162 data_vector.push_back(bytes[i]);
163 }
164
165 data_vector.push_back(BATTOR_SPECIAL_BYTE_END);
166
167 io_handler_->Write(make_scoped_ptr(new device::SendBuffer(
168 data_vector, base::Bind(&BattOrConnection::OnBytesSent, AsWeakPtr(),
169 callback, data_vector.size()))));
170 }
171
172 void BattOrConnection::ReadBytes(const ReadCallback& callback,
173 uint16_t bytes_to_read) {
Zhen Wang 2015/12/14 23:39:44 wrong indent
charliea (OOO until 10-5) 2015/12/15 23:50:04 Doh.
174 // Add 3 bytes to however many bytes the caller requested to account for the
175 // start, type, and end bytes that are included in every BattOr message.
176 bytes_to_read += 3;
177
178 scoped_ptr<vector<char>> bytes_already_read(new vector<char>());
179 ReadMoreBytes(callback, bytes_to_read, bytes_already_read.Pass());
180 }
181
182 void BattOrConnection::Flush() {
183 io_handler_->Flush();
184 }
185
186 scoped_refptr<device::SerialIoHandler> BattOrConnection::CreateIoHandler() {
187 return device::SerialIoHandler::Create(file_thread_task_runner_,
188 ui_thread_task_runner_);
189 }
190
191 void BattOrConnection::ReadMoreBytes(
192 const ReadCallback& callback,
193 uint16_t bytes_to_read,
194 scoped_ptr<vector<char>> bytes_already_read) {
Primiano Tucci (use gerrit) 2015/12/15 11:07:19 I wonder if this bytes_alread_read is really an ar
charliea (OOO until 10-5) 2015/12/15 23:50:04 Good point. I added a new private variable named p
195 auto io_buffer = make_scoped_refptr(new net::IOBuffer((size_t)bytes_to_read));
Primiano Tucci (use gerrit) 2015/12/15 11:07:19 no c-style casts, use static_cast? (actually why d
charliea (OOO until 10-5) 2015/12/15 23:50:04 Done, although this did involve some casting in or
196 auto on_receive_buffer_filled =
197 base::Bind(&BattOrConnection::OnBytesRead, AsWeakPtr(), callback,
198 base::Passed(&bytes_already_read), io_buffer, bytes_to_read);
199
200 io_handler_->Read(make_scoped_ptr(new device::ReceiveBuffer(
201 io_buffer, bytes_to_read, on_receive_buffer_filled)));
202 }
203
204 void BattOrConnection::OnBytesSent(
205 const BattOrConnection::SendCallback& callback,
206 int expected_bytes_sent,
207 int bytes_sent,
208 device::serial::SendError error) {
209 bool success = (error == device::serial::SEND_ERROR_NONE) &&
210 (expected_bytes_sent == bytes_sent);
211 callback.Run(success);
212 }
213
214 void BattOrConnection::OnBytesRead(
215 const BattOrConnection::ReadCallback& callback,
216 scoped_ptr<vector<char>> bytes_already_read,
217 scoped_refptr<net::IOBuffer> buffer,
218 int expected_bytes_read,
219 int bytes_read,
220 device::serial::ReceiveError error) {
221 if ((bytes_read < expected_bytes_read) ||
222 (error != device::serial::RECEIVE_ERROR_NONE)) {
223 callback.Run(false, BATTOR_MESSAGE_TYPE_CONTROL, bytes_already_read.Pass());
224 return;
225 }
226
227 scoped_ptr<vector<char>> message_content(new vector<char>());
228 bool is_complete;
229 bool is_valid_so_far;
230 BattOrMessageType type;
231 uint16_t escape_byte_count;
232
233 ParseMessage(bytes_already_read.get(), message_content.get(), &is_complete,
234 &is_valid_so_far, &type, &escape_byte_count);
235
236 // Parse the piece of the message that we already had in order to determine
237 // how many escape bytes we've already read.
Zhen Wang 2015/12/14 23:39:46 Move the comment to above ParseMessage. Some more
charliea (OOO until 10-5) 2015/12/15 23:50:04 I had thought about that, but I was trying to avoi
238 uint16_t escape_byte_already_requested_count = escape_byte_count;
239
240 message_content->clear();
241 bytes_already_read->insert(bytes_already_read->end(), buffer->data(),
242 buffer->data() + bytes_read);
243
244 // Reparse the message with the new bytes added on in order to determine how
245 // many new escape bytes we've received and whether the message is complete.
246 ParseMessage(bytes_already_read.get(), message_content.get(), &is_complete,
247 &is_valid_so_far, &type, &escape_byte_count);
248
249 if (!is_valid_so_far) {
250 // If we already have an invalid message, there's no sense in continuing to
251 // process it.
252 callback.Run(false, BATTOR_MESSAGE_TYPE_CONTROL, bytes_already_read.Pass());
253 return;
254 }
255
256 uint16_t additional_escape_bytes =
257 escape_byte_count - escape_byte_already_requested_count;
258 if (additional_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(callback, additional_escape_bytes, bytes_already_read.Pass());
264 return;
265 }
266
267 if (!is_complete)
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 callback.Run(false, BATTOR_MESSAGE_TYPE_CONTROL, bytes_already_read.Pass());
271
272 // If we've gotten this far, we've received the whole, well-formed message.
273 callback.Run(true, type, message_content.Pass());
274 }
275
276 } // namespace battor
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698