Libusb接收有两种方式,同步和异步。同步比异步用法简单多了,所以我首先用的也是同步。后一直有丢包问题,所以换异步接收了。
1 同步
部分代码:
bool UsbHelper::usbBulkTrans(unsigned char* data,libusb_device_handle* dev_handle,unsigned char endpoint,int len, int *actual_len,int timeout)
{
int ret = -1;
ret = libusb_bulk_transfer(dev_handle,endpoint, data, len, actual_len,timeout);
if(ret < 0)
{
if(ret != LIBUSB_ERROR_TIMEOUT)
{
lastErroeMsg = libusb_error_name(ret);
//lastErroeMsg = "usb bulk:"+ std::to_string(ret)+ libusb_error_name(ret);
return false;
}
}
return true;
}
void UsbDebug::startThread()
{
while (isDoing)
{
if(!isRun)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
unsigned char recvdata[512] = "\0";
int len = 0;
if(!usbHelper.usbBulkTrans(recvdata,dev_handle,usbSetting.EndPointOut,512,&len,0))
{
std::this_thread::sleep_for(std::chrono::milliseconds(2));
continue;
}
//memset(signalData,0,sizeof(signalData));
if(len > 0)
{
#ifdef DEBUG
// logger->info("usb receive data:");
// char hexValue[3];
// std::string strval = "";
// for(int i=0; i< len; i++)
// {
// sprintf(hexValue,"%02X",recvdata[i]);
// strval = strval + hexValue;
// if(i%16==15 || i== len-1)
// {
// logger->info("data{}:{} ",i/16,strval);
// strval = "";
// }
// }
#endif
SubPack(recvdata, len);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
2 异步部分代码
void UsbHelper::usbBulkTransSync(libusb_device_handle* dev_handle,unsigned char endpoint,
int timeout,libusb_transfer_cb_fn callback)
{
int ret = -1;
for(int i=0; i< 50; i++) //此处一开始是100丢,加到200、1000都是丢,后改到50
{
libusb_transfer *transfer = libusb_alloc_transfer(0);
transfer->actual_length = 0;
unsigned char *recvdata = new unsigned char[BUFFERSIZE];//一定要new
memset(recvdata,0,BUFFERSIZE);
libusb_fill_bulk_transfer(transfer,dev_handle,endpoint,recvdata,BUFFERSIZE,callback, NULL,timeout);
ret = libusb_submit_transfer(transfer);
if(ret != 0)
{
lastErroeMsg = "usb submit transfer error:" + std::to_string(ret)+ libusb_error_name(ret);
//libusb_cancel_transfer(transfer);
libusb_free_transfer(transfer);
continue;
}
transferList.push_back(transfer);
}
isRun = true;
// libusb_cancel_transfer(transfer);
//libusb_free_transfer(transfer);
//libusb_release_interface(dev_handle,0);
//libusb_close(dev_handle);
}
异步依然存在丢包问题。
void async_callback(libusb_transfer *transfer)
{
if(transfer->status == LIBUSB_TRANSFER_COMPLETED)
{
if(transfer->actual_length > 0)
{
buffermtx.lock();
std::array<unsigned char,BUFFERSIZE> buffer;
std::copy(transfer->buffer,transfer->buffer+BUFFERSIZE, buffer.begin());
transferlist.push_back(buffer);
buffermtx.unlock();
}
// if (libusb_submit_transfer(transfer) < 0)
// {
// libusb_cancel_transfer(transfer);
// }
}
else if(transfer->status == LIBUSB_TRANSFER_CANCELLED)
{
libusb_free_transfer(transfer);
}
else
{
if (libusb_submit_transfer(transfer) < 0)
{
libusb_cancel_transfer(transfer);
}
}
}
3 调试工具
usbmon 是usb调试的一个内核工具,默认都是已安装的。
先查看需要监听的usb的bus端口和device号,用lsusb命令,查看,我需要监测的是bus 002,device 003
输入sudo cat /sys/kernel/debug/usb/usbmon/2u |grep "2:003",其中2u表示监测bus2,bus1就是1u, 后面表示过滤,只检测设备号3.
此时终端开始刷数,需要退出ctrl+C
监测查看可以看到接收到1024数据包,但是显示不全。不知道某些包是否接收到了。
使用tcpdump 可以显示全部数据。这个工具也是默认安装的,我一开始用的下面命令usbmon2 表示监测bus2,-s -0 表示显示全部数据 -A表示在终端显示,因为我的是byte包十六进制,在终端显示乱码,所以还得存储文件用wireshark查看。
安装wireshark
监听数据存文件
Wireshark打开文件,发现确实有的包没接收到。都是接收了连续的几个576的包,然后有几个64字节的包,不知道干啥的,中间就丢包了。
返回usbmon查看接收中间是什么过程。
下面前两个字段不用管,是设备码和时间戳,S 表示submit,提交transfer; C表示callback回调中读取数据。Ci表示control包input;Bi表示bulk包input; 我主要用这两个包。
分析下面先是提交了(S Bi 512< )好多条,然后C回调中读取数据,C后面又跟了几个S提交,这时候丢包了。我认为是处理不过来了,所以把回调函数里的重新提交buffer 去掉了,这时候丢包少了一点。既然提交buffer是占用资源的,一开始开辟的transfer数量也不能一味的大,太大也是会丢包,一开始我设置200丢包,设置为50就不丢了。实际中我只会用到13个包左右,只不过包间距基本没有,属于高频包。
我的包里有计数,每一个512第一个包比上一个包应该差8.
结论:
1、 提交transfer时 unsigned char *recvdata = new unsigned char[BUFFERSIZE];一定要new,因为需要后期释放。用数组为崩溃。
2、提交transfer数量只是1个时会丢包,也不能一味的大,太大也是会丢包,合适了最好。
异步编写感谢: