【问题标题】:How to pass a member function pointer to libusb?如何将成员函数指针传递给 libusb?
【发布时间】:2018-12-13 12:00:12
【问题描述】:

我正在编写一个简单的库,它使用libusb 连接到我的自定义硬件,该硬件每 50 毫秒向主机设备发送一次信号。它旨在提供一个简单的抽象层,这样用户就不会被libusb 所困扰。我需要将指向非静态类成员函数的指针传递给libusb_fill_bulk_transfer。 IE。我需要对 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);
     //... 填充开发者
    }
    int mylib_print_device_info(MyDevice* dev); 
  • 连接到用户喜欢的任意数量的设备

    int mylib_init_device(MyDevice* dev){
       libusb_open(dev->device, &dev->dev_handle);
       // 检查内核驱动程序并在需要时删除
       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);
       // .. libusb_control_transfer -s 的其余部分
    
       //启动设备:
       诠释实际;
       无符号字符 startSig = 0b00110111;
       libusb_bulk_transfer(dev->dev_handle, (1 | LIBUSB_ENDPOINT_OUT), &tosend, 1, &actual, 100);
    
       dev->user_callback = user_cb;
       开发->buffer_in = buffer_in;
       开发->缓冲区大小 = 缓冲区大小;
    
       //设置传输
       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);

  • 退出库

    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) 错误

【问题讨论】:

  • 查看user_data参数的说明。使用它将this 传递给静态回调函数,该函数将其转换回对象指针,然后调用类方法。
  • 关于您的编辑:您是否将dev 作为用户数据传递?您前面的代码仍然将void* user_data 参数显示为NULL,这肯定会给您带来段错误...另外,请确保在回调发生时有问题的设备对象仍然存在(而不仅仅是它的副本) .
  • 是的,做到了。赞!

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


【解决方案1】:

根据 Max Langhof 和 Sam Varshavchik 的 cmets,解决方案是将 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);                                                                               ^^^

} 

然后像在编辑中一样使用 callback_wrapper。谢谢!

【讨论】:

    猜你喜欢
    • 2021-11-29
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多