libusb的异步也有这样的问题

1. 最近一直在关注异步机制,不管是网络库asio,libuv,还是libusb库,其实异步机制都是差不多的,都是基于回调函数、系统轮询实现的。

2. 下面是对一款USB产品做得测试结果,Windows环境下,用libusb异步API写的程序:


说明:用 Bus Hound 抓包,查看返回数值发现上面三个命令只有R是成功的(即有返回值),却对应在了B命令上,导致调用了B的回调。这就是异步容易导致的问题,也就是如果不停地发送命令,其中有一条命令失败,而这条命令的超时未过,回来的结果如果没有别的区分,会认为是该条命令的返回数据,而导致调用失败指令的回调函数,而导致比较严重的后果。

#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "libusb.h"

#define EP_IN           (6 | LIBUSB_ENDPOINT_IN)
#define EP_OUT		(2 | LIBUSB_ENDPOINT_OUT)


typedef enum {
    SAVE_IMAGE      = 0x55,
    UPLOAD_IMAGE    = 0xAA
}BULK_REQCODE;

typedef enum {
    SAVE_IMAGE_VAL  = 0x00,
    UPLOAD_B_VAL    = 0x00,
    UPLOAD_G_VAL    = 0x01,
    UPLOAD_R_VAL    = 0x02
}BULK_VALUE;

static struct libusb_device_handle *devh = NULL;
static unsigned char imgbuf_save[8];
static unsigned char imgbuf_upload[8];
static unsigned char imgbuf_R[2048*240];
static unsigned char imgbuf_G[2048*240];
static unsigned char imgbuf_B[2048*240];
static struct libusb_transfer *img_save = NULL;
static struct libusb_transfer *img_R = NULL;
static struct libusb_transfer *img_G = NULL;
static struct libusb_transfer *img_B = NULL;
static struct libusb_transfer *img_R_upload = NULL;
static struct libusb_transfer *img_G_upload = NULL;
static struct libusb_transfer *img_B_upload = NULL;
static int img_idx = 0;
static volatile sig_atomic_t do_exit = 0;
static int ii=0;

static pthread_t poll_thread;
static sem_t exit_sem;

static void request_exit(sig_atomic_t code)
{
	do_exit = code;
	sem_post(&exit_sem);
}

static void *poll_thread_main(void *arg)    //轮询是否main——thread结束
{
	int r = 0;
	printf("poll thread running\n");

	while (!do_exit) {
		struct timeval tv = { 1, 0 };
        r = libusb_handle_events_timeout(NULL, &tv);    //处理任何待以处理的事件
		if (r < 0) {
			request_exit(2);
			break;
		}
	}

	printf("poll thread shutting down\n");
	return NULL;
}

static int find_dpfp_device(void)
{
    devh = libusb_open_device_with_vid_pid(NULL, 0x04b4, 0x8623);
	return devh ? 0 : -EIO;
}

static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
{
    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
        fprintf(stderr, "img transfer status %d?\n", transfer->status);
        request_exit(2);
        return;
    }

    std::cout << "upload_img_R_over callback : " << transfer->status << std::endl;
}

static void LIBUSB_CALL save_img(struct libusb_transfer *transfer)
{
    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
        fprintf(stderr, "img transfer status %d?\n", transfer->status);
        request_exit(2);
        return;
    }

    std::cout << "save Image callback : " << transfer->status << std::endl;
}

static void LIBUSB_CALL upload_img_B(struct libusb_transfer *transfer)
{
    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
        fprintf(stderr, "img transfer status %d?\n", transfer->status);
        request_exit(2);
        return;
    }

    std::cout << "upload_img_B callback : " << transfer->status << std::endl;
}

static void LIBUSB_CALL upload_img_B_over(struct libusb_transfer *transfer)
{
    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
        fprintf(stderr, "img transfer status %d?\n", transfer->status);
        request_exit(2);
        return;
    }

    std::cout << "upload_img_B_over callback : " << transfer->status << std::endl;
}

static void LIBUSB_CALL upload_img_G(struct libusb_transfer *transfer)
{
    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
        fprintf(stderr, "img transfer status %d?\n", transfer->status);
        request_exit(2);
        return;
    }

    std::cout << "upload_img_G callback : " << transfer->status << std::endl;
}

static void LIBUSB_CALL upload_img_G_over(struct libusb_transfer *transfer)
{
    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
        fprintf(stderr, "img transfer status %d?\n", transfer->status);
        request_exit(2);
        return;
    }

    std::cout << "upload_img_G_over callback : " << transfer->status << std::endl;
}

static void LIBUSB_CALL upload_img_R(struct libusb_transfer *transfer)
{
    if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
        fprintf(stderr, "img transfer status %d?\n", transfer->status);
        request_exit(2);
        return;
    }

    std::cout << "upload_img_R callback : " << transfer->status << std::endl;

}

//由于该设备处理多命令异步发送过来的时候,只处理最后一条
static int LIBUSB_CALL submit_trans()
{
    int r=0;

    r = libusb_submit_transfer(img_save);   //提交一个传输并立即返回
    if (r < 0) {
        libusb_cancel_transfer(img_save);   //异步取消之前提交传输
        printf("1");
    }

    r = libusb_submit_transfer(img_B_upload);   //提交一个传输并立即返回
    if (r < 0) {
        libusb_cancel_transfer(img_B_upload);   //异步取消之前提交传输
        printf("1");
    }

    r = libusb_submit_transfer(img_B);   //提交一个传输并立即返回
    if (r < 0) {
        libusb_cancel_transfer(img_B);   //异步取消之前提交传输
        printf("1");
    }

    r = libusb_submit_transfer(img_G_upload);   //提交一个传输并立即返回
    if (r < 0) {
        libusb_cancel_transfer(img_G_upload);   //异步取消之前提交传输
        printf("1");
    }

    r = libusb_submit_transfer(img_G);   //提交一个传输并立即返回
    if (r < 0) {
        libusb_cancel_transfer(img_G);   //异步取消之前提交传输
        printf("1");
    }

    r = libusb_submit_transfer(img_R_upload);   //提交一个传输并立即返回
    if (r < 0) {
        libusb_cancel_transfer(img_R_upload);   //异步取消之前提交传输
        printf("1");
    }

    r = libusb_submit_transfer(img_R);   //提交一个传输并立即返回
    if (r < 0) {
        libusb_cancel_transfer(img_R);   //异步取消之前提交传输
        printf("1");
    }

    return r;
}

static int alloc_transfers(void)
{
    img_save = libusb_alloc_transfer(0);    //0参数表明配置一个异步传输
    if (!img_save)
		return -ENOMEM;
    img_R = libusb_alloc_transfer(0);    //0参数表明配置一个异步传输
    if (!img_R)
        return -ENOMEM;
    img_R_upload = libusb_alloc_transfer(0);    //0参数表明配置一个异步传输
    if (!img_R_upload)
        return -ENOMEM;
    img_G = libusb_alloc_transfer(0);    //0参数表明配置一个异步传输
    if (!img_G)
        return -ENOMEM;
    img_G_upload = libusb_alloc_transfer(0);    //0参数表明配置一个异步传输
    if (!img_G_upload)
        return -ENOMEM;
    img_B = libusb_alloc_transfer(0);    //0参数表明配置一个异步传输
    if (!img_B)
        return -ENOMEM;
    img_B_upload = libusb_alloc_transfer(0);    //0参数表明配置一个异步传输
    if (!img_B_upload)
        return -ENOMEM;

    imgbuf_save[0] = (u_char)(SAVE_IMAGE);
    imgbuf_save[1] = 0x00;
    imgbuf_save[2] = 0x00;
    imgbuf_save[3] = 0x00;
    imgbuf_save[4] = (uchar)((0xff00 & 0x00f0)>>8);
    imgbuf_save[5] = (uchar)(0x00ff & 0x00f0);
    imgbuf_save[6] = 0x00;
    imgbuf_save[7] = (u_char)(SAVE_IMAGE_VAL);
    libusb_fill_bulk_transfer(img_save, devh, EP_OUT, imgbuf_save,
        sizeof(imgbuf_save), save_img, NULL, 5000);   //该辅助函数来填充所需的libusb_transfer批量传输字段

    imgbuf_upload[0] = (u_char)UPLOAD_IMAGE;
    imgbuf_upload[1] = 0x00;
    imgbuf_upload[2] = 0x00;
    imgbuf_upload[3] = 0x00;
    imgbuf_upload[4] = (uchar)((0xff00 & 0x00f0)>>8);
    imgbuf_upload[5] = (uchar)(0x00ff & 0x00f0);
    imgbuf_upload[6] = 0x00;
    imgbuf_upload[7] = (u_char)UPLOAD_B_VAL;
    libusb_fill_bulk_transfer(img_B_upload, devh, EP_OUT, imgbuf_upload,
        sizeof(imgbuf_upload), upload_img_B, NULL, 5000);   //该辅助函数来填充所需的libusb_transfer批量传输字段
    libusb_fill_bulk_transfer(img_B, devh, EP_IN, imgbuf_B,
        sizeof(imgbuf_B), upload_img_B_over, NULL, 5000);   //该辅助函数来填充所需的libusb_transfer批量传输字段

    imgbuf_upload[0] = (u_char)UPLOAD_IMAGE;
    imgbuf_upload[1] = 0x00;
    imgbuf_upload[2] = 0x00;
    imgbuf_upload[3] = 0x00;
    imgbuf_upload[4] = (uchar)((0xff00 & 0x00f0)>>8);
    imgbuf_upload[5] = (uchar)(0x00ff & 0x00f0);
    imgbuf_upload[6] = 0x00;
    imgbuf_upload[7] = (u_char)UPLOAD_G_VAL;
    libusb_fill_bulk_transfer(img_G_upload, devh, EP_OUT, imgbuf_upload,
        sizeof(imgbuf_upload), upload_img_G, NULL, 5000);   //该辅助函数来填充所需的libusb_transfer批量传输字段
    libusb_fill_bulk_transfer(img_G, devh, EP_IN, imgbuf_G,
        sizeof(imgbuf_G), upload_img_G_over, NULL, 5000);   //该辅助函数来填充所需的libusb_transfer批量传输字段

    imgbuf_upload[0] = (u_char)UPLOAD_IMAGE;
    imgbuf_upload[1] = 0x00;
    imgbuf_upload[2] = 0x00;
    imgbuf_upload[3] = 0x00;
    imgbuf_upload[4] = (uchar)((0xff00 & 0x00f0)>>8);
    imgbuf_upload[5] = (uchar)(0x00ff & 0x00f0);
    imgbuf_upload[6] = 0x00;
    imgbuf_upload[7] = (u_char)UPLOAD_R_VAL;
    libusb_fill_bulk_transfer(img_R_upload, devh, EP_OUT, imgbuf_upload,
        sizeof(imgbuf_upload), upload_img_R, NULL, 5000);   //该辅助函数来填充所需的libusb_transfer批量传输字段
    libusb_fill_bulk_transfer(img_R, devh, EP_IN, imgbuf_R,
        sizeof(imgbuf_R), cb_img, NULL, 5000);   //该辅助函数来填充所需的libusb_transfer批量传输字段

	return 0;
}

int main(void)
{
    libusb_init(NULL);  //初始libusb库

    int r = find_dpfp_device();
    if(r!=0)
    {
        printf("%s\n", "not found dev" );
        return 0;
    }

    r = libusb_claim_interface(devh, 0);    //声明设备接口
    if (r < 0) {
        fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
        goto out;
    }
    std::cout << "claimed interface" << std::endl;

    r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL); //子线程poll_thread_main用来处理USB事件
    if (r)
        goto out;

    r = alloc_transfers();  //配置一个异步bulk传输和一个中断传输,先alloc然后fill_XX_transfer
    if (r < 0) {
        request_exit(1);
        pthread_join(poll_thread, NULL);    //函数pthread_join用来等待一个线程的结束
        goto out;
    }

    r = submit_trans(); //submit一个传输
    if (r < 0) {
        request_exit(1);
        pthread_join(poll_thread, NULL);    //失败等待线程结束
        goto out;
    }

    while (!do_exit)
        sem_wait(&exit_sem);    //等待退出信号量

    printf("shutting down...\n");
    pthread_join(poll_thread, NULL);

out_release:
    libusb_release_interface(devh, 0);
out:
    libusb_close(devh);
    libusb_exit(NULL);
    sem_destroy(&exit_sem);
    return r >= 0 ? r : -r;
}


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: libusb是一个用户态的通用USB驱动程序库,用于在操作系统中进行USB设备的访问和控制。异步传输是指在进行USB数据传输时,不需要等待传输完成再进行下一步操作,而是可以同时进行其他操作。 对于摄像头来说,使用libusb进行异步传输可以带来一些好处。首先,异步传输可以提高摄像头的数据传输效率。传统的同步传输会等待每一帧数据传输完成后再进行下一帧的传输,而异步传输可以在当前传输进行的同时开始下一帧的传输,极大地提高了数据传输速度和帧率。 其次,异步传输还可以降低摄像头与计算机之间的延迟。由于异步传输不需要等待传输完成才能进行下一步操作,因此可以更早地对接收到的数据进行处理和分析,从而减少处理延迟。 另外,使用libusb进行异步传输还可以提高对摄像头的控制灵活性。通过异步传输,可以同时进行数据传输和控制命令的发送,例如对摄像头进行设置或调整参数。这样可以实现更加复杂的场景和功能,例如实时调节摄像头的焦距、曝光等参数。 总之,libusb异步传输可以提高摄像头的数据传输效率和控制灵活性,并降低延迟,对于需要高效地传输和控制摄像头数据的应用场景来说,是一个非常有用的工具。 ### 回答2: libusb是一个开源的跨平台的USB访问库,它允许开发人员通过USB接口与USB设备进行通信。摄像头通常通过USB接口与计算机连接,因此可以使用libusb异步传输摄像头数据。 异步传输意味着在进行数据传输时,计算机可以同时执行其他任务,而不必等待传输完成。在摄像头应用中,异步传输能够提高数据传输的效率和响应速度,使得图像和视频流可以更加流畅地展示。 当使用libusb进行异步传输时,首先需要打开摄像头设备并初始化libusb库。然后,可以使用libusb提供的接口函数将传输任务添加到传输队列中,并指定回调函数来处理传输完成后的数据。 在传输过程中,libusb会负责与摄像头设备进行通信,并在数据传输完成后调用回调函数来处理接收到的数据。开发人员可以在回调函数中对数据进行处理,比如解码、显示、保存等操作。 使用libusb进行摄像头数据的异步传输可以提高系统的性能和响应速度,特别适用于需要实时展示摄像头图像或者进行实时图像处理的应用。另外,libusb提供了丰富的接口函数和示例代码,使得开发人员可以轻松实现对摄像头数据的异步传输,并根据自身需求进行二次开发。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值