| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef TOOLS_BATTOR_AGENT_BATTOR_AGENT_H_ |
| #define TOOLS_BATTOR_AGENT_BATTOR_AGENT_H_ |
| |
| #include <map> |
| |
| #include "base/cancelable_callback.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/threading/thread_checker.h" |
| #include "tools/battor_agent/battor_connection.h" |
| #include "tools/battor_agent/battor_error.h" |
| |
| namespace battor { |
| |
| // A BattOrAgent is a class used to asynchronously communicate with a BattOr for |
| // the purpose of collecting power samples. A BattOr is an external USB device |
| // that's capable of recording accurate, high-frequency (2000Hz) power samples. |
| // |
| // The serial connection is automatically opened when the first command |
| // (e.g. StartTracing(), StopTracing(), etc.) is issued, and automatically |
| // closed when either StopTracing() or the destructor is called. For Telemetry, |
| // this means that the connection must be reinitialized for every command that's |
| // issued because a new BattOrAgent is constructed. For Chromium, we use the |
| // same BattOrAgent for multiple commands and thus avoid having to reinitialize |
| // the serial connection. |
| // |
| // This class is NOT thread safe. Any interactions with this class that involve |
| // IO (i.e. any interactions that require a callback) must be done from the |
| // same IO thread, which must also have a running MessageLoop. |
| class BattOrAgent : public BattOrConnection::Listener, |
| public base::SupportsWeakPtr<BattOrAgent> { |
| public: |
| // The listener interface that must be implemented in order to interact with |
| // the BattOrAgent. |
| class Listener { |
| public: |
| virtual void OnStartTracingComplete(BattOrError error) = 0; |
| virtual void OnStopTracingComplete(const std::string& trace, |
| BattOrError error) = 0; |
| virtual void OnRecordClockSyncMarkerComplete(BattOrError error) = 0; |
| }; |
| |
| BattOrAgent( |
| const std::string& path, |
| Listener* listener, |
| scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner); |
| virtual ~BattOrAgent(); |
| |
| void StartTracing(); |
| void StopTracing(); |
| void RecordClockSyncMarker(const std::string& marker); |
| |
| // Returns whether the BattOr is able to record clock sync markers in its own |
| // trace log. |
| static bool SupportsExplicitClockSync() { return true; } |
| |
| // BattOrConnection::Listener implementation. |
| void OnConnectionOpened(bool success) override; |
| void OnBytesSent(bool success) override; |
| void OnMessageRead(bool success, |
| BattOrMessageType type, |
| std::unique_ptr<std::vector<char>> bytes) override; |
| |
| protected: |
| // The connection that knows how to communicate with the BattOr in terms of |
| // protocol primitives. This is protected so that it can be replaced with a |
| // fake in testing. |
| std::unique_ptr<BattOrConnection> connection_; |
| |
| // Timeout for when an action isn't completed within the allotted time. This |
| // is virtual and protected so that timeouts can be disabled in testing. The |
| // testing task runner that runs delayed tasks immediately deals poorly with |
| // timeouts posted as future tasks. |
| virtual void OnActionTimeout(); |
| |
| private: |
| enum class Command { |
| INVALID, |
| START_TRACING, |
| STOP_TRACING, |
| RECORD_CLOCK_SYNC_MARKER, |
| }; |
| |
| enum class Action { |
| INVALID, |
| |
| // Actions required to connect to a BattOr. |
| REQUEST_CONNECTION, |
| |
| // Actions required for starting tracing. |
| SEND_RESET, |
| SEND_INIT, |
| READ_INIT_ACK, |
| SEND_SET_GAIN, |
| READ_SET_GAIN_ACK, |
| SEND_START_TRACING, |
| READ_START_TRACING_ACK, |
| |
| // Actions required for stopping tracing. |
| SEND_EEPROM_REQUEST, |
| READ_EEPROM, |
| SEND_SAMPLES_REQUEST, |
| READ_CALIBRATION_FRAME, |
| READ_DATA_FRAME, |
| |
| // Actions required for recording a clock sync marker. |
| SEND_CURRENT_SAMPLE_REQUEST, |
| READ_CURRENT_SAMPLE, |
| }; |
| |
| // Performs an action. |
| void PerformAction(Action action); |
| // Performs an action after a delay. |
| void PerformDelayedAction(Action action, base::TimeDelta delay); |
| |
| |
| |
| // Requests a connection to the BattOr. |
| void BeginConnect(); |
| |
| // Sends a control message over the connection. |
| void SendControlMessage(BattOrControlMessageType type, |
| uint16_t param1, |
| uint16_t param2); |
| |
| // Completes the command with the specified error. |
| void CompleteCommand(BattOrError error); |
| |
| // Returns a formatted version of samples_ with timestamps and real units. |
| std::string SamplesToString(); |
| |
| // The listener that handles the commands' results. It must outlive the agent. |
| Listener* listener_; |
| |
| // The last action executed by the agent. This should only be updated in |
| // PerformAction(). |
| Action last_action_; |
| |
| // The tracing command currently being executed by the agent. |
| Command command_; |
| |
| // A map from the sample number (including samples from the calibration frame) |
| // to the ID of the clock sync marker that is associated with that sample |
| // number. If we ever have to store a large number of these, consider using an |
| // unordered map. |
| std::map<uint32_t, std::string> clock_sync_markers_; |
| |
| // The clock sync marker being recorded (if we're currently recording one). |
| std::string pending_clock_sync_marker_; |
| |
| // The time at which the last clock sync marker was recorded. |
| base::TimeTicks last_clock_sync_time_; |
| |
| // Checker to make sure that this is only ever called on the IO thread. |
| base::ThreadChecker thread_checker_; |
| |
| // The BattOr's EEPROM (which is required for calibration). |
| std::unique_ptr<BattOrEEPROM> battor_eeprom_; |
| |
| // The first frame (required for calibration). |
| std::vector<RawBattOrSample> calibration_frame_; |
| |
| // The actual data samples recorded. |
| std::vector<RawBattOrSample> samples_; |
| |
| // The expected sequence number of the next frame. We use this to ensure that |
| // we receive frames in order. |
| uint32_t next_sequence_number_; |
| |
| // The number of times that we've attempted to read the last message. |
| uint8_t num_read_attempts_; |
| |
| // The timeout that's run when an action times out. |
| base::CancelableClosure timeout_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BattOrAgent); |
| }; |
| |
| } // namespace battor |
| |
| #endif // TOOLS_BATTOR_AGENT_BATTOR_AGENT_H_ |