| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "tools/battor_agent/battor_agent.h" | 5 #include "tools/battor_agent/battor_agent.h" |
| 6 | 6 |
| 7 #include <iomanip> | 7 #include <iomanip> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/threading/thread_task_runner_handle.h" | 10 #include "base/threading/thread_task_runner_handle.h" |
| 11 #include "tools/battor_agent/battor_connection_impl.h" | 11 #include "tools/battor_agent/battor_connection_impl.h" |
| 12 #include "tools/battor_agent/battor_sample_converter.h" | 12 #include "tools/battor_agent/battor_sample_converter.h" |
| 13 | 13 |
| 14 using std::vector; | 14 using std::vector; |
| 15 | 15 |
| 16 namespace battor { | 16 namespace battor { |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 // The number of seconds that it takes a BattOr to reset. | 20 // The maximum number of times to retry when init'ing a battor. |
| 21 const uint8_t kBattOrResetTimeSeconds = 5; | 21 const uint8_t kMaxInitAttempts = 20; |
| 22 |
| 23 // The number of milliseconds to wait before trying to init again. |
| 24 const uint16_t kInitRetryDelayMilliseconds = 100; |
| 22 | 25 |
| 23 // The maximum number of times to retry when reading a message. | 26 // The maximum number of times to retry when reading a message. |
| 24 const uint8_t kMaxReadAttempts = 20; | 27 const uint8_t kMaxReadAttempts = 20; |
| 25 | 28 |
| 26 // The number of milliseconds to wait before trying to read a message again. | 29 // The number of milliseconds to wait before trying to read a message again. |
| 27 const uint8_t kReadRetryDelayMilliseconds = 1; | 30 const uint8_t kReadRetryDelayMilliseconds = 1; |
| 28 | 31 |
| 29 // The amount of time we need to wait after recording a clock sync marker in | 32 // The amount of time we need to wait after recording a clock sync marker in |
| 30 // order to ensure that the sample we synced to doesn't get thrown out. | 33 // order to ensure that the sample we synced to doesn't get thrown out. |
| 31 const uint8_t kStopTracingClockSyncDelayMilliseconds = 100; | 34 const uint8_t kStopTracingClockSyncDelayMilliseconds = 100; |
| 32 | 35 |
| 33 // The number of seconds allowed for a given action before timing out. | 36 // The number of seconds allowed for a given action before timing out. |
| 34 const uint8_t kBattOrTimeoutSeconds = 10; | 37 const uint8_t kBattOrTimeoutSeconds = 4; |
| 35 | 38 |
| 36 // Returns true if the specified vector of bytes decodes to a message that is an | 39 // Returns true if the specified vector of bytes decodes to a message that is an |
| 37 // ack for the specified control message type. | 40 // ack for the specified control message type. |
| 38 bool IsAckOfControlCommand(BattOrMessageType message_type, | 41 bool IsAckOfControlCommand(BattOrMessageType message_type, |
| 39 BattOrControlMessageType control_message_type, | 42 BattOrControlMessageType control_message_type, |
| 40 const vector<char>& msg) { | 43 const vector<char>& msg) { |
| 41 if (message_type != BATTOR_MESSAGE_TYPE_CONTROL_ACK) | 44 if (message_type != BATTOR_MESSAGE_TYPE_CONTROL_ACK) |
| 42 return false; | 45 return false; |
| 43 | 46 |
| 44 if (msg.size() != sizeof(BattOrControlMessageAck)) | 47 if (msg.size() != sizeof(BattOrControlMessageAck)) |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 Listener* listener, | 115 Listener* listener, |
| 113 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, | 116 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, |
| 114 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) | 117 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) |
| 115 : connection_(new BattOrConnectionImpl(path, | 118 : connection_(new BattOrConnectionImpl(path, |
| 116 this, | 119 this, |
| 117 file_thread_task_runner, | 120 file_thread_task_runner, |
| 118 ui_thread_task_runner)), | 121 ui_thread_task_runner)), |
| 119 listener_(listener), | 122 listener_(listener), |
| 120 last_action_(Action::INVALID), | 123 last_action_(Action::INVALID), |
| 121 command_(Command::INVALID), | 124 command_(Command::INVALID), |
| 125 num_init_attempts_(0), |
| 122 num_read_attempts_(0) { | 126 num_read_attempts_(0) { |
| 123 // We don't care what thread the constructor is called on - we only care that | 127 // We don't care what thread the constructor is called on - we only care that |
| 124 // all of the other method invocations happen on the same thread. | 128 // all of the other method invocations happen on the same thread. |
| 125 thread_checker_.DetachFromThread(); | 129 thread_checker_.DetachFromThread(); |
| 126 } | 130 } |
| 127 | 131 |
| 128 BattOrAgent::~BattOrAgent() { | 132 BattOrAgent::~BattOrAgent() { |
| 129 DCHECK(thread_checker_.CalledOnValidThread()); | 133 DCHECK(thread_checker_.CalledOnValidThread()); |
| 130 } | 134 } |
| 131 | 135 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 return; | 171 return; |
| 168 timeout_callback_.Cancel(); | 172 timeout_callback_.Cancel(); |
| 169 | 173 |
| 170 if (!success) { | 174 if (!success) { |
| 171 CompleteCommand(BATTOR_ERROR_CONNECTION_FAILED); | 175 CompleteCommand(BATTOR_ERROR_CONNECTION_FAILED); |
| 172 return; | 176 return; |
| 173 } | 177 } |
| 174 | 178 |
| 175 switch (command_) { | 179 switch (command_) { |
| 176 case Command::START_TRACING: | 180 case Command::START_TRACING: |
| 177 // TODO(charliea): Ideally, we'd just like to send an init, and the BattOr | 181 num_init_attempts_ = 1; |
| 178 // firmware can handle whether a reset is necessary or not, sending an | 182 PerformAction(Action::SEND_INIT); |
| 179 // init ack regardless. This reset can be removed once this is true. | |
| 180 // https://github.com/aschulm/battor/issues/30 tracks this. | |
| 181 PerformAction(Action::SEND_RESET); | |
| 182 return; | 183 return; |
| 183 case Command::STOP_TRACING: | 184 case Command::STOP_TRACING: |
| 184 PerformAction(Action::SEND_EEPROM_REQUEST); | 185 PerformAction(Action::SEND_EEPROM_REQUEST); |
| 185 return; | 186 return; |
| 186 case Command::RECORD_CLOCK_SYNC_MARKER: | 187 case Command::RECORD_CLOCK_SYNC_MARKER: |
| 187 PerformAction(Action::SEND_CURRENT_SAMPLE_REQUEST); | 188 PerformAction(Action::SEND_CURRENT_SAMPLE_REQUEST); |
| 188 return; | 189 return; |
| 189 case Command::INVALID: | 190 case Command::INVALID: |
| 190 NOTREACHED(); | 191 NOTREACHED(); |
| 191 } | 192 } |
| 192 } | 193 } |
| 193 | 194 |
| 194 void BattOrAgent::OnBytesSent(bool success) { | 195 void BattOrAgent::OnBytesSent(bool success) { |
| 195 DCHECK(thread_checker_.CalledOnValidThread()); | 196 DCHECK(thread_checker_.CalledOnValidThread()); |
| 196 | 197 |
| 197 // Return immediately if whatever action we were trying to perform already | 198 // Return immediately if whatever action we were trying to perform already |
| 198 // timed out. | 199 // timed out. |
| 199 if (timeout_callback_.IsCancelled()) | 200 if (timeout_callback_.IsCancelled()) |
| 200 return; | 201 return; |
| 201 timeout_callback_.Cancel(); | 202 timeout_callback_.Cancel(); |
| 202 | 203 |
| 203 if (!success) { | 204 if (!success) { |
| 204 CompleteCommand(BATTOR_ERROR_SEND_ERROR); | 205 CompleteCommand(BATTOR_ERROR_SEND_ERROR); |
| 205 return; | 206 return; |
| 206 } | 207 } |
| 207 | 208 |
| 208 switch (last_action_) { | 209 switch (last_action_) { |
| 209 case Action::SEND_RESET: | |
| 210 // TODO(charliea): Ideally, we'd just like to send an init, and the BattOr | |
| 211 // firmware can handle whether a reset is necessary or not, sending an | |
| 212 // init ack regardless. This reset can be removed once this is true. | |
| 213 // https://github.com/aschulm/battor/issues/30 tracks this. | |
| 214 | |
| 215 // Wait for the reset to happen before sending the init message. | |
| 216 PerformDelayedAction(Action::SEND_INIT, base::TimeDelta::FromSeconds( | |
| 217 kBattOrResetTimeSeconds)); | |
| 218 return; | |
| 219 case Action::SEND_INIT: | 210 case Action::SEND_INIT: |
| 220 PerformAction(Action::READ_INIT_ACK); | 211 PerformAction(Action::READ_INIT_ACK); |
| 221 return; | 212 return; |
| 222 case Action::SEND_SET_GAIN: | 213 case Action::SEND_SET_GAIN: |
| 223 PerformAction(Action::READ_SET_GAIN_ACK); | 214 PerformAction(Action::READ_SET_GAIN_ACK); |
| 224 return; | 215 return; |
| 225 case Action::SEND_START_TRACING: | 216 case Action::SEND_START_TRACING: |
| 226 PerformAction(Action::READ_START_TRACING_ACK); | 217 PerformAction(Action::READ_START_TRACING_ACK); |
| 227 return; | 218 return; |
| 228 case Action::SEND_EEPROM_REQUEST: | 219 case Action::SEND_EEPROM_REQUEST: |
| (...skipping 30 matching lines...) Expand all Loading... |
| 259 case Action::READ_CURRENT_SAMPLE: | 250 case Action::READ_CURRENT_SAMPLE: |
| 260 if (++num_read_attempts_ > kMaxReadAttempts) { | 251 if (++num_read_attempts_ > kMaxReadAttempts) { |
| 261 CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR); | 252 CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR); |
| 262 return; | 253 return; |
| 263 } | 254 } |
| 264 | 255 |
| 265 PerformDelayedAction(last_action_, base::TimeDelta::FromMilliseconds( | 256 PerformDelayedAction(last_action_, base::TimeDelta::FromMilliseconds( |
| 266 kReadRetryDelayMilliseconds)); | 257 kReadRetryDelayMilliseconds)); |
| 267 return; | 258 return; |
| 268 | 259 |
| 260 // Retry sending an INIT if it an ACK is not received. |
| 261 case Action::SEND_INIT: |
| 262 case Action::READ_INIT_ACK: |
| 263 if (num_init_attempts_++ < kMaxInitAttempts) { |
| 264 PerformDelayedAction(Action::SEND_INIT, |
| 265 base::TimeDelta::FromMilliseconds(kInitRetryDelayMilliseconds)); |
| 266 } else { |
| 267 CompleteCommand(BATTOR_ERROR_TOO_MANY_INIT_RETRIES); |
| 268 } |
| 269 |
| 270 return; |
| 271 |
| 269 default: | 272 default: |
| 270 CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR); | 273 CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR); |
| 271 return; | 274 return; |
| 272 } | 275 } |
| 273 } | 276 } |
| 274 | 277 |
| 275 switch (last_action_) { | 278 switch (last_action_) { |
| 276 case Action::READ_INIT_ACK: | 279 case Action::READ_INIT_ACK: |
| 277 if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_INIT, | 280 if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_INIT, |
| 278 *bytes)) { | 281 *bytes)) { |
| 279 CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE); | 282 if (num_init_attempts_++ < kMaxInitAttempts) { |
| 283 PerformDelayedAction(Action::SEND_INIT, |
| 284 base::TimeDelta::FromMilliseconds(kInitRetryDelayMilliseconds)); |
| 285 } else { |
| 286 CompleteCommand(BATTOR_ERROR_TOO_MANY_INIT_RETRIES); |
| 287 } |
| 288 |
| 280 return; | 289 return; |
| 281 } | 290 } |
| 282 | 291 |
| 283 PerformAction(Action::SEND_SET_GAIN); | 292 PerformAction(Action::SEND_SET_GAIN); |
| 284 return; | 293 return; |
| 285 | 294 |
| 286 case Action::READ_SET_GAIN_ACK: | 295 case Action::READ_SET_GAIN_ACK: |
| 287 if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN, | 296 if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN, |
| 288 *bytes)) { | 297 *bytes)) { |
| 289 CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE); | 298 CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 base::TimeDelta::FromSeconds(kBattOrTimeoutSeconds)); | 402 base::TimeDelta::FromSeconds(kBattOrTimeoutSeconds)); |
| 394 | 403 |
| 395 last_action_ = action; | 404 last_action_ = action; |
| 396 | 405 |
| 397 switch (action) { | 406 switch (action) { |
| 398 case Action::REQUEST_CONNECTION: | 407 case Action::REQUEST_CONNECTION: |
| 399 BeginConnect(); | 408 BeginConnect(); |
| 400 return; | 409 return; |
| 401 | 410 |
| 402 // The following actions are required for StartTracing: | 411 // The following actions are required for StartTracing: |
| 403 case Action::SEND_RESET: | |
| 404 // Reset the BattOr to clear any preexisting state. After sending the | |
| 405 // reset signal, we need to wait for the reset to finish before issuing | |
| 406 // further commands. | |
| 407 SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 0, 0); | |
| 408 return; | |
| 409 case Action::SEND_INIT: | 412 case Action::SEND_INIT: |
| 410 // After resetting the BattOr, we need to make sure to flush the serial | 413 // Clear out the serial data that may exist from prior init attempts. |
| 411 // stream. Strange data may have been written into it during the reset. | |
| 412 connection_->Flush(); | 414 connection_->Flush(); |
| 413 | 415 |
| 414 SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0); | 416 SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0); |
| 415 return; | 417 return; |
| 416 case Action::READ_INIT_ACK: | 418 case Action::READ_INIT_ACK: |
| 417 connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK); | 419 connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK); |
| 418 return; | 420 return; |
| 419 case Action::SEND_SET_GAIN: | 421 case Action::SEND_SET_GAIN: |
| 420 // Set the BattOr's gain. Setting the gain tells the BattOr the range of | 422 // Set the BattOr's gain. Setting the gain tells the BattOr the range of |
| 421 // power measurements that we expect to see. | 423 // power measurements that we expect to see. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 } | 478 } |
| 477 } | 479 } |
| 478 | 480 |
| 479 void BattOrAgent::PerformDelayedAction(Action action, base::TimeDelta delay) { | 481 void BattOrAgent::PerformDelayedAction(Action action, base::TimeDelta delay) { |
| 480 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 482 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 481 FROM_HERE, base::Bind(&BattOrAgent::PerformAction, AsWeakPtr(), action), | 483 FROM_HERE, base::Bind(&BattOrAgent::PerformAction, AsWeakPtr(), action), |
| 482 delay); | 484 delay); |
| 483 } | 485 } |
| 484 | 486 |
| 485 void BattOrAgent::OnActionTimeout() { | 487 void BattOrAgent::OnActionTimeout() { |
| 486 CompleteCommand(BATTOR_ERROR_TIMEOUT); | 488 switch (last_action_) { |
| 489 case Action::READ_INIT_ACK: |
| 490 if (num_init_attempts_++ < kMaxInitAttempts) { |
| 491 // OnMessageRead() will fail and retry SEND_INIT. |
| 492 connection_->CancelReadMessage(); |
| 493 } else { |
| 494 CompleteCommand(BATTOR_ERROR_TOO_MANY_INIT_RETRIES); |
| 495 } |
| 496 |
| 497 return; |
| 498 |
| 499 default: |
| 500 CompleteCommand(BATTOR_ERROR_TIMEOUT); |
| 501 } |
| 502 |
| 487 timeout_callback_.Cancel(); | 503 timeout_callback_.Cancel(); |
| 488 } | 504 } |
| 489 | 505 |
| 490 void BattOrAgent::SendControlMessage(BattOrControlMessageType type, | 506 void BattOrAgent::SendControlMessage(BattOrControlMessageType type, |
| 491 uint16_t param1, | 507 uint16_t param1, |
| 492 uint16_t param2) { | 508 uint16_t param2) { |
| 493 DCHECK(thread_checker_.CalledOnValidThread()); | 509 DCHECK(thread_checker_.CalledOnValidThread()); |
| 494 | 510 |
| 495 BattOrControlMessage msg{type, param1, param2}; | 511 BattOrControlMessage msg{type, param1, param2}; |
| 496 connection_->SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, &msg, sizeof(msg)); | 512 connection_->SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, &msg, sizeof(msg)); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 561 if (clock_sync_marker != clock_sync_markers_.end()) | 577 if (clock_sync_marker != clock_sync_markers_.end()) |
| 562 trace_stream << " <" << clock_sync_marker->second << ">"; | 578 trace_stream << " <" << clock_sync_marker->second << ">"; |
| 563 | 579 |
| 564 trace_stream << std::endl; | 580 trace_stream << std::endl; |
| 565 } | 581 } |
| 566 | 582 |
| 567 return trace_stream.str(); | 583 return trace_stream.str(); |
| 568 } | 584 } |
| 569 | 585 |
| 570 } // namespace battor | 586 } // namespace battor |
| OLD | NEW |