'What is passed as the user_data in libusb_fill_bulk_transfer?
I have a working code which seems to be correctly reading the data through the usb using libusb_fill_bulk_transfer(libusb_transfer* transfer, libusb_device_handle * dev_handle, unsigned char endpoint, unsigned char* buffer, int length, libusb_transfer_cb_fn callback, void* user_data, unsigned int timeout ), however i didn't quiet understand what value should be used for user_data and how the transfer call back mechanism works for the libusb.
Prologue, i have a class UsbCommunicator which manages the Usb context and the device handle(s) .
It has function UsbCommunicator::Activate which populates the transfer structure and then submits it.In the code below, note the statement **STATEMENT 1 **, where for the user_data of type void*, this pointer is passed. I agree it is allowed, but i am not really sure how the callback i.e. libusb_transfer_cb_fn which is typedef void( * libusb_transfer_cb_fn) (struct libusb_transfer *transfer) casts this to libusb_transfer* transfer My guess (from cppreference.com) is it is possible because Two objects a and b are pointer-interconvertible if: one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, any base class sub object of that object
QUESTION 1: Is it possible to cast this to libusb_transfer* p_transfer because of the reason mentioned above?
QUESTION 2: If the above is false, how is the callback called ?
Here is the function UsbCommunicator::Activate
void UsbCommunicator::Activate()
{
// Start the timer for the first set of transfers.
start_timestamp_ = common::CurrentTimeStampInMilliseconds();
// Launch all transfers.
INFO(p_logger_, StartUsbService, id_ + ": Starting USB transfers with size " + std::to_string(bytes_per_transfer_));
for (unsigned int i = 0; i < num_transfers_; i++)
{
// Populate the transfer structure.
auto data_buffer = reinterpret_cast<unsigned char*>(data_buffers_[i].get());
// Pass "this" as user data, so the callback function can pass on the received data. **STATEMENT 1 **
libusb_fill_bulk_transfer(transfers_[i], p_device_handle, endpoint_address_, data_buffer,
bytes_per_transfer_, LibusbTransferCallback, this, transfer_timeout_);
// Submit the transfer.
int ret = libusb_submit_transfer(transfers_[i]);
if (ret == 0)
{
rqts_in_flight_++;
}
else
{
WARNING(p_logger_, StartUsbService,
id_ + ": Failed to submit libusb transfer request number: " + std::to_string(i) + ". Ret: " + std::to_string(ret));
continue;
}
}
initialised_ = true;
}
I have further has LibusbTransferCallback, which has the type typedef void( * libusb_transfer_cb_fn) (struct libusb_transfer *transfer) like so:. I think it works based on the assumption i made in Question 2 that this call is possible after some internal casting of void* data to libusb_transfer* p_transfer, is that right again ?
//! @brief Call-back function called by libusb upon completion of a queued data transfer.
//! @param[in] p_transfer Libusb transfer structure.
static void LibusbTransferCallback(struct libusb_transfer* p_transfer)
{
// Handle the transfer within the USB Communicator.
UsbCommunicator* p_usb_comm = static_cast<UsbCommunicator*>(p_transfer->user_data);
p_usb_comm->HandleTransferCallback(p_transfer);
}
And finally UsbCommunicator::HandleTransferCallback like so:
void UsbCommunicator::HandleTransferCallback(libusb_transfer* p_transfer)
{
std::unique_ptr<common::DataPacket> x_data_packet = std::make_unique<common::DataPacket>();
x_data_packet->status = common::DataPacketStatus::Success;
int bytes_received = p_transfer->actual_length;
rqts_in_flight_--;
if (p_transfer->status == LIBUSB_TRANSFER_COMPLETED)
{
x_data_packet->size = bytes_received;
x_data_packet->x_data = std::make_unique<uint8_t[]>(bytes_received);
std::memcpy(x_data_packet->x_data.get(), p_transfer->buffer, bytes_received);
x_data_packet->timestamp_ms = common::CurrentTimeStampInMilliseconds();
success_count_++;
}
// Some more lines
//..
}
Solution 1:[1]
You can pass in anything and access it within the callback via transfer->user_data.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
