Chromium Code Reviews| 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 |