clibusblibusb-1.0

Error when using "user_data" in libusb_fill_interrupt_transfer callback


I'm using libusb-1.0 to pair a BLE dongle to an RCU.

For this, I write a pairing request to the dongle interface succesfully. To listen to the dongle response I'm using the function libusb_fill_interrupt_transfer and I pass a callback, which will be executed when receiving the response. This function accepts a parameter, as mentionned in the documentation (void *user_data), that can be used in the callback. But when I try to use this parameter, I get a compilation error.

undeclared (first use in this function)

Following the call of the previous function and the declaration of my callback :

libusb_fill_interrupt_transfer(pairing->transfer, dctx->devh, 0x84, pairing->buffer,
    sizeof(pairing->buffer), cb_aknowledgement, pairing, 0);

static void cb_aknowledgement(struct libusb_transfer *transfer)
{
    if (pairing->transfer->status != LIBUSB_TRANSFER_COMPLETED) {
        printf( "img transfer status %d?\n", pairing->transfer->status);
        libusb_free_transfer(pairing->transfer);
        pairing->transfer = NULL;
        return;
    }

    if(pairing->buffer[0]!=0x05 || pairing->buffer[1]!=0x21)
    {
        printf( "wrong command recieved\n");
        libusb_free_transfer(pairing->transfer);
        pairing->transfer = NULL;
        return;
    }

    printf("I've read data  \n");
    printf("USB Report Id           =  0x%x \n",pairing->buffer[0]);
    printf("Command                 =  0x%x \n",pairing->buffer[1]);
    printf("Acknowledgement type    =  0x%x \n",pairing->buffer[2]);
    return ;
}

The question is: How can I use the user_data I passed as a parameter to the callback?


Solution

  • Use transfer->user_data. From libusb_transfer structure doc :

    Data Fields
    void * user_data
    User context data to pass to the callback function.

    I don't know what is the type of pairing but it would look like this:

    int main() {
       ...
       struct pairing_type_s *pairing = pairing_init();
       ...
       libusb_fill_interrupt_transfer(pairing->transfer, dctx->devh, 0x84, pairing->buffer,
        sizeof(pairing->buffer), cb_aknowledgement, pairing, 0);
        ...
    }
    
    // Then later:
    
    static void cb_aknowledgement(struct libusb_transfer *transfer)
    {
         assert(transfer != NULL);
         struct pairing_type_s *pairing = transfer->user_data;
         assert(pairing != NULL);
         // use pairing like a pro
         ...
    }
    

    But you can also be more pro, if you ensure that you always call libusb_fill_interrupt_transfer with pairing->transfer with cb_aknowledgement and use container_of macro:

    int main() {
       ...
       struct pairing_type_s *pairing = pairing_init();
       ...
       libusb_fill_interrupt_transfer(pairing->transfer, dctx->devh, 0x84, pairing->buffer,
        sizeof(pairing->buffer), cb_aknowledgement, NULL, 0);
        ...
    }
    
    // Then later:
    
    static void cb_aknowledgement(struct libusb_transfer *transfer)
    {
         assert(transfer != NULL);
         struct pairing_type_s *pairing = container_of(transfer, struct pairing_type_s, transfer);
         assert(pairing != NULL);
         // use pairing like a pro
         ...
    }
    

    But I would prefer the first method in this case, as it's more readable and more errorless.