-
Notifications
You must be signed in to change notification settings - Fork 21
Basic Usage
Creating a libusb device is easy simply call the appropriate LibUSB::FindDevice(...)
to filter by vendorID, productID, and (optionally) serial descriptor. Or simply call LibUSB::FindAllDevices()
to get every USB device attached to the system.
All of these functions accept a LibUSB::DeviceFactory_t
function pointer to a factory method, to be used if you're using a class that inherits from class LibUSB::Device
. Leaving it as null (default) will cause the method to simply return a LibUSB::Device
object.
Note: Don't let your device shared_ptr go out of scope until you're done using it.
To use your device's basic descriptors, simply call its methods! Note, that to retrieve string descriptors, call Device::Open()
first!
Many times, a configuration will already be active. If so, Device::getActiveConfiguration()
will return it. If this returns NULL, use Device::getConfiguration(config value) to obtain a LibUSB::Configuration
object.
Note Configuration objects are recalled by config value, as defined by your device descriptors. They are NOT automatically zero indexed.
Device::NumConfigurations()
does return the number of configurations reported, however.)
Once you've obtained a Configuration object, you can use it's methods to determine if it's suitable. To set it as the active configuration, simply call Configuration::SetAsActive()
. (You do not have to keep your own copy of the configuration, your Device will always hold a shared_ptr to its active configuration object)
You can examine the interfaces on any Configuration object, even ones that aren't currently selected as active. Simply use Configuration::NumInterfaces()
, Configuration::getInterfaceByIndex(index)
, and Configuration::getInterface(interfaceNumber)
Once you've obtained your desired LibUSB::Interface, simply call it's Claim() method.
If you wish to browse the interfaces alternate settings, use Interface::NumAlternateSettings()
to get the number of alt settings, and Interface::SetAlternate(setting)
to choose an alternate setting. This can be done before or after calling Interface::Claim()
on the interface.
Endpoints are required in order to obtain a LibUSB::Transfer
object.
The required control endpoint doesn't require most of the steps above. You can simply call Device::Open(), followed by Device::getControlEndpoint()
. No other objects or steps are required in-between.
If you have an any Interface object already, calling Interface::getEndpoint(0)
will also return the default USB control endpoint.
Otherwise you can call Interface::NumEndpoints()
to get the number of endpoints in the current interface/altsetting, and Interface::getEndpoint()
to get the actual endpoint object.
Once you have an endpoint, you're almost ready to transfer data! But first, you need to get the appropriate LibUSB::Transfer object.
std::shared_ptr<LibUSB::**TRANSFERCLASSHERE**> pTransfer = std::static_pointer_cast<LibUSB::**TRANSFERCLASSHERE**>(pEndpoint->CreateTransfer());
Where TRANSFERCLASSHERE is one of the intuitive four transfer types:
- Control Transfers -
LibUSB::ControlTransfer
- Interrupt Transfers -
LibUSB::InterruptTransfer
- Bulk Transfers -
LibUSB::BulkTransfer
- Isochronous Transfers -
LibUSB::IsochronousTransfer
You can use Endpoint::TransferType()
to determine the proper type pragmatically. (Note: If you have suggestions on implementing a helper to make this a bit smoother, syntactically, Feel free to suggest/add-on.)
Congrats! You're now ready to perform a transfer! Essentially, every transfer is either going to send or receive data from a buffer that you provide. (Be sure to check out the doxygen/html documentation before starting, or examine the LibusbTest.cpp file to see an example.) But here's an overview:
Common to all transfers is the Transfer::setTransferBuffer(pBuffer, transfersize)
method.
If performing an OUT (to the device transfer, You simply allocate a block of memory containing your data structure that you want to transfer OUT, and cast it to a std::shared_ptr<unsigned char>
. If transfersize is 0, no data will be transferred!
If performing an IN transfer, provide a buffer that you wish the data to be placed in. If transfersize is 0, no data will be transferred!
Note: For control transfers with data, you must provide 8 additional bytes at the beginning of your data block for the setup packet!! When providing the transfersize, do NOT include those bytes, they are assumed!
To set your timeout, simply call Transfer::SetTimeout(chrono)
If performing a control transfer, you must call ControlTransfer::SetupPacket(...)
to create your setup packet data.
To begin your transfer, simply call Transfer::Start()
If you have not set a transfer buffer, a default for your transfer type one will be created at this time, or an exception will be thrown.
To start your transfer in a background thread, call Transfer::AsyncStart()
instead. Check the transfer's status using Transfer::isComplete()
, block on completion by calling Transfer::WaitForCompletion()
.
Failed transfers tend to throw exceptions. All are derived from the standard exception classes. Use Transfer::isSuccessful()
to obtain the exception for asynchronous transfers, and Transfer::Result()
for actual information, and Transfer::BytesTransferred()
and to determine exactly how much data was transferred.
Transfer::getTransferBuffer()
will return your original shared_ptr object to the data transferred.
To reuse the same transfer object again, you can call Transfer::Reset()