| // Copyright (c) 2013 The Chromium OS 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 MIST_USB_TRANSFER_H_ |
| #define MIST_USB_TRANSFER_H_ |
| |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <ostream> // NOLINT(readability/streams) |
| #include <string> |
| |
| #include <base/callback.h> |
| #include <base/macros.h> |
| #include <gtest/gtest_prod.h> |
| |
| #include "mist/usb_constants.h" |
| #include "mist/usb_error.h" |
| |
| struct libusb_transfer; |
| |
| namespace mist { |
| |
| // A base class encapsulating a USB transfer, which wraps a libusb_transfer C |
| // struct from libusb 1.0 into a C++ object. This class does not implement a |
| // specific type of transfer, so it cannot be instantiated and must be extended |
| // for each type of transfer. In particular, a derived class should set up the |
| // wrapped libusb_transfer accordingly for a specific type of transfer. |
| class UsbTransfer { |
| public: |
| using CompletionCallback = base::Callback<void(UsbTransfer* transfer)>; |
| |
| enum State { |
| kIdle, |
| kInProgress, |
| kCancelling |
| }; |
| |
| ~UsbTransfer(); |
| |
| // Submits this USB transfer, which will happen asynchronously. Returns true |
| // on success. If the underlying libusb_transfer struct is not allocated, sets |
| // |error_| to UsbError::kErrorTransferNotAllocated and returns false. If this |
| // transfer has been submitted and is still in progress, sets |error_| to |
| // UsbError::kErrorTransferAlreadySubmitted and returns false. Upon the |
| // completion of this transfer, |completion_callback| is invoked. It is ok to |
| // submit this transfer again after completion. |
| bool Submit(const CompletionCallback& completion_callback); |
| |
| // Cancels this USB transfer if it has been submitted via Submit(). Returns |
| // true on success. If this transfer has not been submitted, sets |error_| to |
| // UsbError::kErrorTransferNotSubmitted and returns false. If a previous |
| // cancellation is already in progress, sets |error_| to |
| // UsbError::kErrorTransferBeingCancelled and returns false. The cancellation |
| // may not have completed when this method returns. Once this transfer is |
| // completely cancelled, |completion_callback_| is invoked. |
| bool Cancel(); |
| |
| // Getters for retrieving fields of the libusb_transfer struct. |
| uint8_t GetEndpointAddress() const; |
| UsbTransferType GetType() const; |
| UsbTransferStatus GetStatus() const; |
| int GetLength() const; |
| int GetActualLength() const; |
| |
| // Returns true if this tranfer is completed with the expected length, i.e. |
| // GetStatus() returns kUsbTransferStatusCompleted and GetActualLength() |
| // returns |expected_length|. |
| bool IsCompletedWithExpectedLength(int expected_length) const; |
| |
| // Returns a string describing the properties of this object for logging |
| // purpose. |
| std::string ToString() const; |
| |
| uint8_t* buffer() { return buffer_.get(); } |
| int buffer_length() const { return buffer_length_; } |
| State state() const { return state_; } |
| const UsbError& error() const { return error_; } |
| |
| protected: |
| UsbTransfer(); |
| |
| // Verifies that the underlying libusb_transfer struct is allocated, |
| // and if so, returns true. Otherwise, set |error_| to |
| // UsbError::kErrorTransferNotAllocated and returns false. |
| bool VerifyAllocated(); |
| |
| // Allocates the underlying libusb_transfer struct with |num_iso_packets| |
| // isochronous packet descriptors. Returns true on success. |
| bool Allocate(int num_iso_packets); |
| |
| // Frees the underlying libusb_transfer struct. |
| void Free(); |
| |
| // Allocates the transfer buffer to hold |length| bytes of data. Return true |
| // on success. |
| bool AllocateBuffer(int length); |
| |
| // Called by libusb upon the completion of the underlying USB transfer. |
| // A derived class associates this callback to the underlying libusb_transfer |
| // struct when setting the transfer. |
| static void OnCompleted(libusb_transfer* transfer); |
| |
| // Completes the transfer by invoking the completion callback. |
| void Complete(); |
| |
| libusb_transfer* transfer() const { return transfer_; } |
| UsbError* mutable_error() { return &error_; } |
| |
| private: |
| friend class UsbTransferTest; |
| FRIEND_TEST(UsbTransferTest, AllocateAfterAllocate); |
| FRIEND_TEST(UsbTransferTest, AllocateBuffer); |
| FRIEND_TEST(UsbTransferTest, AllocateBufferAfterSubmit); |
| FRIEND_TEST(UsbTransferTest, FreeBeforeAllocate); |
| FRIEND_TEST(UsbTransferTest, GetType); |
| FRIEND_TEST(UsbTransferTest, VerifyAllocated); |
| |
| libusb_transfer* transfer_; |
| std::unique_ptr<uint8_t[]> buffer_; |
| int buffer_length_; |
| State state_; |
| CompletionCallback completion_callback_; |
| UsbError error_; |
| |
| DISALLOW_COPY_AND_ASSIGN(UsbTransfer); |
| }; |
| |
| } // namespace mist |
| |
| // Output stream operator provided to facilitate logging. |
| std::ostream& operator<<(std::ostream& stream, |
| const mist::UsbTransfer& transfer); |
| |
| #endif // MIST_USB_TRANSFER_H_ |