OLD | NEW |
---|---|
(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 | |
OLD | NEW |