-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathusb_transfer.h
132 lines (103 loc) · 4.79 KB
/
usb_transfer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// 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();
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_; }
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_;
};
} // namespace mist
// Output stream operator provided to facilitate logging.
std::ostream& operator<<(std::ostream& stream,
const mist::UsbTransfer& transfer);
#endif // MIST_USB_TRANSFER_H_