如何将成员函数指针传递给libusb?

时间:2018-12-13 12:00:13

标签: c++ libusb member-function-pointers

我正在编写一个简单的库,该库使用libusb连接到我的自定义硬件,该硬件每50毫秒将信号发送到主机设备一次。它旨在提供一个简单的抽象层,以使用户完全不会被libusb所困扰。我需要将指向非静态类成员函数的指针传递给libusb_fill_bulk_transfer。即我需要为MyDevice的每个实例提供一个单独的回调,而又不向用户暴露libusb逻辑。

基本设计是:

  • 初始化库

    int mylib_init(){
      libusb_init(&context);
    }
  • 找到所有兼容的设备

    int mylib_get_valid_devices(vector devs){
     //...
     libusb_device **devs1;
     int countAll = libusb_get_device_list(context, &devs1);
     //... fill devs
    }
    int mylib_print_device_info(MyDevice* dev); 
  • 连接到用户喜欢的设备

    int mylib_init_device(MyDevice* dev){
       libusb_open(dev->device, &dev->dev_handle);
       // check for kernel driver & remove if needed
       libusb_claim_interface(dev->dev_handle, 0);
       //...
    }
  • 设置回调,以将数据传入连接设备的所有实例

    int mylib_start_transmission_async(MyDevice* dev, MyLibCallbackIn user_cb, unsigned char* buffer_in, int bufferSize){
       libusb_control_transfer(dev->dev_handle, p1, p2, p3, p4, p5, p6, p7);
       // .. rest of libusb_control_transfer -s
    
       //start device:
       int actual;
       unsigned char startSig = 0b00110111;
       libusb_bulk_transfer(dev->dev_handle, (1 | LIBUSB_ENDPOINT_OUT), &tosend, 1, &actual, 100);
    
       dev->user_callback = user_cb;
       dev->buffer_in = buffer_in; 
       dev->bufferSize = bufferSize;
    
       //setup transfer
       dev->transfer_in = libusb_alloc_transfer(0);
       libusb_fill_bulk_transfer(dev->transfer_in, dev->dev_handle, LIBUSB_ENDPOINT_IN, dev->buffer_in,dev->bufferSize, cb_in, NULL, 0);
       libusb_submit_transfer(dev->transfer_in); 
    
    } 
  • 完成后断开连接

    int mylib_disconnect_device(MyDevice* device);

  • 退出lib

    int mylib_exit();

MyDevice定义为:

typedef int (*MyLibdCallbackIn)(unsigned char* buffer, int length);

class MyDevice{

  unsigned char* buffer_in;
  unsigned char* buffer_out;

  libusb_device* device = nullptr;
  libusb_device_handle* dev_handle = nullptr;

  struct libusb_transfer* transfer_in = nullptr;
  struct libusb_transfer* transfer_out = nullptr;

//this obviously wouldn't work because libusb doesn't accept it as a param:
  void LIBUSB_CALL cb_in(struct libusb_transfer* transfer); 
  MyLibCallbackIn user_callback;

  void run();
  //...

}

和cb_in定义为:

void LIBUSB_CALL MyDevice::cb_in(libusb_transfer* transfer){
  int r = libusb_submit_transfer(this->transfer_in);
  callback_in(transfer->buffer, transfered);

}

由于函数指针类型不兼容,我无法将MyDevice::cb_in传递给libusb_fill_bulk_transfer。同时,我不希望我的用户必须编写以libusb_transfer*作为参数(暴露于libusb)的回调函数直接传递给libusb_fill_bulk_transfer

编辑: 我尝试过

void LIBUSB_CALL callback_wrapper(struct libusb_transfer* transfer){
  MyDevice* dev = reinterpret_cast<MyDevice*>(transfer->user_data);
  dev->cb_in(transfer);
}

但出现Sementation fault (Core dumped)错误

1 个答案:

答案 0 :(得分:1)

根据Max Langhof和Sam Varshavchik的评论,解决方案是将MyDevice的实例传递给libusb_fill_bulk_transfer。因此:

int mylib_start_transmission_async(MyDevice* dev, MyLibCallbackIn user_cb, unsigned char* buffer_in, int bufferSize){

   //...
   // setup transfer:
   dev->transfer_in = libusb_alloc_transfer(0);
   libusb_fill_bulk_transfer(dev->transfer_in, dev->dev_handle, LIBUSB_ENDPOINT_IN, dev->buffer_in,dev->bufferSize, cb_in, dev, 0);
   libusb_submit_transfer(dev->transfer_in);                                                                               ^^^

} 

,然后像在Edit中一样使用callback_wrapper。谢谢!