blob: 846eda44bf499c2cbd863f635c7ec9d13ce7ef3a [file] [log] [blame]
// 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.
#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 {
using CompletionCallback = base::Callback<void(UsbTransfer* transfer)>;
enum State { kIdle, kInProgress, kCancelling };
// 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_; }
UsbTransfer(const UsbTransfer&) = delete;
UsbTransfer& operator=(const UsbTransfer&) = delete;
// 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_; }
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_;
} // namespace mist
// Output stream operator provided to facilitate logging.
std::ostream& operator<<(std::ostream& stream,
const mist::UsbTransfer& transfer);