最开始版本的GUI工具时同步传输实现的,后面我们又实现了异步传输,进一步实现了一步传输+FIFO的GUI和底层的解耦。现在我们将这几部分合并起来,实现一个异步传输的GUI工具。
前面已经分别实现了异步传输+FIFO,以及GUI,先把他们放在一起即可,不在赘述,直接
贴出关键代码。
mainwindow.cpp
#include
#include
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "usbdev.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
usbdev_init();
ui->setupUi(this);
this->on_pushButton_8_clicked();
ui->textEdit_5->setText("800600020000FF00");
ui->checkBox->setChecked(true);
ui->checkBox_2->setChecked(true);
ui->checkBox_3->setChecked(true);
ui->lineEdit_2->setText("10");
ui->lineEdit_3->setText("10");
ui->lineEdit->setText("1000");
ui->textEdit_3->setText("11223344556677889900");
tx_status = 0;
rx_status = 0;
tx_time = 0;
tx_num = 0;
rx_time = 0;
/* 创建定时器1ms执行一次 */
timer_update = new QTimer(this);
timer_update->setInterval(1);
timer_update->setSingleShot(false);
connect(timer_update,SIGNAL(timeout()),this,SLOT(timer_update_cb()));
timer_update->start(1);
}
MainWindow::~MainWindow()
{
usbdev_deinit();
delete timer_update;
delete ui;
}
void MainWindow::on_pushButton_8_clicked()
{
int devsnum = 0;
char* devstr = 0;
usbdev_get_device_list();
devsnum = usbdev_get_device_num();
ui->comboBox->clear();
for(int i=0; i
{
devstr = usbdev_get_device_name(i);
if(devstr == 0)
{
break;
}
else
{
ui->comboBox->addItems(QStringList(devstr));
}
}
}
void MainWindow::on_pushButton_clicked()
{
int res;
int index = ui->comboBox->currentIndex();
if(index < 0)
{
return;
}
if(0 == usbdev_get_openstatus())
{
printf("to open dev %d\r\n",index);
if(0 == (res = usbdev_open(index)))
{
ui->pushButton->setText("关闭");
/* 这里更新显示接口下拉框的内容 */
ui->comboBox_3->clear();
ui->comboBox_4->clear();
ui->comboBox_2->clear();
ui->comboBox_5->clear();
usbdev_update_interface_endpoint_list(); /* 更新接口和端点信息 */
int int_num = usbdev_get_interface_num();
int itf_id;
int alt_id;
for(int i = 0; i
{
if(0 == usbdev_get_interface_id(i,&itf_id,&alt_id))
{
QString itfstr= QString::number(i)+":"+QString::number(itf_id)+":"+QString::number(alt_id);
ui->comboBox_3->addItems(QStringList(itfstr));
ui->comboBox_4->addItems(QStringList(itfstr));
}
}
}
else
{
QMessageBox::information(nullptr, "information", "打开设备失败"+QString::number(res),
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton);
return;
}
}
else
{
usbdev_close();
ui->pushButton->setText("打开");
/* 这里清除显示接口下拉框的内容 */
ui->comboBox_3->clear();
ui->comboBox_4->clear();
ui->comboBox_2->clear();
ui->comboBox_5->clear();
}
}
void MainWindow::on_pushButton_6_clicked()
{
ui->textEdit_6->setText(QString(""));
}
QString ByteArrayToHexString(QByteArray &ba)
{
QDataStream out(&ba,QIODevice::ReadWrite); //将str的数据 读到out里面去
QString buf;
while(!out.atEnd())
{
qint8 outChar = 0;
out >> outChar; //每次一个字节的填充到 outchar
QString str =QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')).toUpper() + QString(" "); //2 字符宽度
buf += str;
}
return buf;
}
void MainWindow::on_pushButton_7_clicked()
{
QString setup_str = ui->textEdit_5->toPlainText();
QByteArray setup_data = QByteArray::fromHex (setup_str.toLatin1().data());
if(setup_data.size() != 8)
{
QMessageBox::information(nullptr, "information", "SETUP必须是8字节",
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton);
return;
}
uint8_t bmRequestType = setup_data[0];
uint8_t bRequest = setup_data[1];
uint16_t wValue = ((uint16_t)(setup_data[2]) & 0x00FF) | (((uint16_t)(setup_data[3])<<8) & 0xFF00);
uint16_t wIndex = ((uint16_t)(setup_data[4]) & 0x00FF) | (((uint16_t)(setup_data[5])<<8) & 0xFF00);
uint16_t wLength = ((uint16_t)(setup_data[6]) & 0x00FF) | (((uint16_t)(setup_data[7])<<8) & 0xFF00);
unsigned int timeout = 1000; /* 超时时间单位mS */
unsigned char* data = (unsigned char*)malloc(wLength);
if(data == NULL)
{
return;
}
QString ctrl_str = ui->textEdit_6->toPlainText();
QByteArray ctrl_data = QByteArray::fromHex (ctrl_str.toLatin1().data());
if((bmRequestType & 0x80) == 0)
{
printf("CONTROL OUT:%02X, %d\r\n",ctrl_data.size(),wLength);
printf("[SETUP]\r\n");
for(int i=0; i
{
printf("%02x ",setup_data[i]);
}
printf("\r\n");
printf("[DATA]\r\n");
for(int i=0; i
{
printf("%02x ",ctrl_data[i]);
}
printf("\r\n");
/* OUT传输 获取DATA编辑框的内容 */
if(ctrl_data.size() != wLength)
{
QMessageBox::information(nullptr, "information", "wLength != DATA长度",
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton);
return;
}
memcpy(data, ctrl_data, ctrl_data.size());
}
int res = usbdev_control_transfer(bmRequestType,bRequest,
wValue,wIndex,
data,
wLength,
timeout);
if(res < 0)
{
QMessageBox::information(nullptr, "information", "控制传输失败",
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton);
}
else
{
if((bmRequestType & 0x80) != 0)
{
/* IN传输 获取数据到DATA编辑框 */
ctrl_data.resize(res);
memcpy(ctrl_data.data(), data,res);
//ctrl_str = QString(ctrl_data);
ctrl_str = ByteArrayToHexString(ctrl_data);
ui->textEdit_6->setText(ctrl_str);
}
}
free(data);
}
void MainWindow::on_comboBox_3_activated(int index)
{
int epnum = usbdev_get_endpoint_num(index);
ui->comboBox_2->clear();
for(int i=0; i< epnum; i++)
{
int address;
int type;
int mps;
if(0 == usbdev_get_endpoint_info(index, i, &address, &type, &mps))
{
QString epstr;
if((address & 0x80) != 0)
{
epstr= QString::number(i)+":IN"+
QString("%1").arg(address & 0xFF, 2, 16, QLatin1Char('0'))+":"+
QString("%1").arg(mps & 0xFF, 2, 16, QLatin1Char('0'))+":";
}
else
{
epstr= QString::number(i)+":OUT"+
QString("%1").arg(address & 0xFF, 2, 16, QLatin1Char('0'))+":"+
QString("%1").arg(mps & 0xFF, 2, 16, QLatin1Char('0'))+":";
}
switch(type & 0x03)
{
case 0:
epstr = epstr + "CTRL";
break;
case 1:
epstr = epstr + "ISOC";
break;
case 2:
epstr = epstr + "BULK";
break;
case 3:
epstr = epstr + "INT";
break;
}
ui->comboBox_2->addItems(QStringList(epstr));
}
}
}
void MainWindow::on_comboBox_4_activated(int index)
{
int epnum = usbdev_get_endpoint_num(index);
ui->comboBox_5->clear();
for(int i=0; i< epnum; i++)
{
int address;
int type;
int mps;
if(0 == usbdev_get_endpoint_info(index, i, &address, &type, &mps))
{
QString epstr;
if((address & 0x80) != 0)
{
epstr= QString::number(i)+":IN"+
QString("%1").arg(address & 0xFF, 2, 16, QLatin1Char('0'))+":"+
QString("%1").arg(mps & 0xFF, 2, 16, QLatin1Char('0'))+":";
}
else
{
epstr= QString::number(i)+":OUT"+
QString("%1").arg(address & 0xFF, 2, 16, QLatin1Char('0'))+":"+
QString("%1").arg(mps & 0xFF, 2, 16, QLatin1Char('0'))+":";
}
switch(type & 0x03)
{
case 0:
epstr = epstr + "CTRL";
break;
case 1:
epstr = epstr + "ISOC";
break;
case 2:
epstr = epstr + "BULK";
break;
case 3:
epstr = epstr + "INT";
break;
}
ui->comboBox_5->addItems(QStringList(epstr));
}
}
}
void MainWindow::on_pushButton_3_clicked()
{
ui->textEdit_3->setText("");
}
void MainWindow::on_pushButton_4_clicked()
{
ui->textEdit_4->setText("");
}
/* 开始/停止发送按钮处理 */
void MainWindow::on_pushButton_2_clicked()
{
int address;
int type;
int mps;
int ep_index;
int itf_index;
int len;
ep_index = ui->comboBox_2->currentIndex();
itf_index = ui->comboBox_3->currentIndex();
len = ui->lineEdit_2->text().toUInt();
if(0 != usbdev_get_endpoint_info(itf_index, ep_index, &address, &type, &mps))
{
QMessageBox::information(nullptr, "information", "不能获取当前接口和端点的信息",
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton);
return;
}
if((address & 0x80) != 0)
{
QMessageBox::information(nullptr, "information", "不是OUT端点,不能发送",
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton);
return;
}
if(tx_status == 0)
{
tx_status = 1;
tx_time = 0;
tx_num = 0;
ui->pushButton_2->setText("停止发送");
usbdev_start_tx_transfer(itf_index, ep_index,len);
}
else
{
tx_status = 0;
tx_time = 0;
tx_num = 0;
ui->pushButton_2->setText("开始发送");
usbdev_stop_tx_transfer();
}
}
/* 开始/停止接收按钮处理 */
void MainWindow::on_pushButton_5_clicked()
{
int address;
int type;
int mps;
int ep_index;
int itf_index;
int len;
ep_index = ui->comboBox_5->currentIndex();
itf_index = ui->comboBox_4->currentIndex();
len = ui->lineEdit_3->text().toUInt();
if(0 != usbdev_get_endpoint_info(itf_index, ep_index, &address, &type, &mps))
{
QMessageBox::information(nullptr, "information", "不能获取当前接口和端点的信息",
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton);
return;
}
if((address & 0x80) == 0)
{
QMessageBox::information(nullptr, "information", "不是IN端点,不能接收",
QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton);
return;
}
if(rx_status == 0)
{
rx_status = 1;
rx_time = 0;
ui->pushButton_5->setText("停止接收");
usbdev_start_rx_transfer(itf_index, ep_index,len);
}
else
{
rx_status = 0;
rx_time = 0;
ui->pushButton_5->setText("开始接收");
usbdev_stop_rx_transfer();
}
}
/**
* @brief MainWindow::timer_update_cb
* 1ms进行一次处理刷新显示等。
* 1. 如果使能发送,则按指定时间将数据写入tx fifo。
* 2. 如果是能接收,则从rx fifo读出数据显示。
*/
void MainWindow::timer_update_cb()
{
/* 发送处理 */
if(tx_status != 0)
{
tx_time++;
uint32_t tx_tick = ui->lineEdit->text().toUInt();
bool iscontinue = ui->checkBox_3->isChecked();
/* 只有一次都没有发送过,或者是重复发送模式才进行发送 */
if((tx_num == 0) || iscontinue)
{
if(tx_time >= tx_tick)
{
tx_num = 1; /* 只有发送一次才置位 */
/* 只有时间间隔到才发送 */
bool ishex;
int len;
int textlen;
int ep_index;
int itf_index;
int address;
int type;
int mps;
int transferred;
int res;
int itf_id;
int itf_alt_id;
QString data_str;
QByteArray data;
tx_time = 0;
ishex = ui->checkBox->isChecked();
len = ui->lineEdit_2->text().toUInt();
data_str = ui->textEdit_3->toPlainText();
/* 获取编辑框的内容根据是否16进制数据转为QByteArray */
if(ishex)
{
data = QByteArray::fromHex(data_str.toLatin1().data());
}
else
{
data = QByteArray::fromRawData(data_str.toLatin1().data(),data_str.size());
}
textlen = data.size();
/* 分配指定长度的缓存 */
unsigned char* buffer = (unsigned char*)calloc(len,1);
if(buffer != NULL)
{
/* 拷贝数据到缓存,最多指定长度,不够则填充0 */
memcpy(buffer, data, (textlen>len)?len:textlen);
/* 数据写入tx fifo */
usbdev_put_tx_transfer_data(buffer, len);
/* 释放缓存 */
free(buffer);
}
}
}
}
/* 接收处理 */
if(rx_status != 0)
{
/* 先获取编辑框原有的数据 */
bool ishex;
QString data_str;
QString data_add_str;
QByteArray data;
uint32_t len;
uint8_t* buffer = 0;
uint32_t rxlen;
ishex = ui->checkBox_2->isChecked();
data_str = ui->textEdit_4->toPlainText();
/* 从接收缓冲区读出数据显示 */
len = usbdev_get_rx_transfer_datalen();
if(len > 0)
{
/* 分配内存存储接收缓冲区读出的数据 */
buffer = (uint8_t*)malloc(len);
if(buffer != 0)
{
rxlen = usbdev_get_rx_transfer_data(buffer, len);
printf("rx len:%d\r\n",rxlen);
if(rxlen > 0)
{
/* 将buffer中新的数据添加到data 根据是否16进制转为字符串 */
data.resize(rxlen);
memcpy(data.data(), buffer, rxlen);
if(ishex)
{
data_add_str = ByteArrayToHexString(data);
}
else
{
data_add_str = QString(data);
}
/* 追加到编辑框,限制编辑框最大长度 */
if(data_str.size() > 1024*1024ul)
{
ui->textEdit_4->setText(data_add_str);
}
else
{
ui->textEdit_4->setText(data_str + data_add_str);
}
}
free(buffer);
}
}
}
}
usbdev.c
static void* usb_event_thread(void *arg); /* USB事件线程处理函数 */
static void* usb_handle_thread(void *arg); /* USB业务线程处理函数 */
pthread_t s_usb_event_thread; /* USB事件处理线程句柄 */
pthread_t s_usb_handle_thread; /* USB业务处理线程句柄 */
char s_devs_str[MAX_DEVS][MAX_DEVS_STR_LEN];
libusb_device **s_devs = NULL;
libusb_device_handle *s_opened_handle = NULL;
libusb_device *s_opened_dev = NULL;
int s_devs_num = 0;
int s_interface_num = 0; /* 打开的设备的接口数 */
int s_tx_itf_idx = -1; /* 当前打开的发送接口 */
int s_tx_busy = 0; /* 发送忙标志 */
int s_tx_ep_idx = -1; /* 当前发送的端点 */
uint32_t s_tx_size = 0; /* 一次发送的大小 */
int s_rx_itf_idx = -1; /* 当前打开的接收接口 */
int s_rx_busy = 0; /* 接收忙标志 */
int s_rx_ep_idx = -1; /* 当前发送的端点 */
uint32_t s_rx_size = 0; /* 一次接收的大小 */
/**
* 记录接口信息结构体
*/
typedef struct
{
int interfacenumber;
int alternateSetting;
int numendpoints;
struct libusb_endpoint_descriptor endpoints[MAX_ENDPOINTS];
} usbddev_interface_info_st;
usbddev_interface_info_st s_interface_info[MAX_INTERFACE];
int usbdev_init(void)
{
int r;
r = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);
if (r < 0)
{
return r;
}
usbdev_fifo_init();
/* 创建usb事件处理线程 */
r = pthread_create(&s_usb_event_thread,0,usb_event_thread,0);
if (r != 0)
{
return r;
}
/* 创建usb业务处理线程 */
r = pthread_create(&s_usb_handle_thread,0,usb_handle_thread,0);
if (r != 0)
{
return r;
}
}
int usbdev_deinit(void)
{
usbdev_close();
libusb_exit(NULL);
usbdev_fifo_deinit();
return 0;
}
int usbdev_get_device_num(void)
{
return s_devs_num;
}
char* usbdev_get_device_name(int index)
{
if(index >= s_devs_num)
{
return 0;
}
else
{
return s_devs_str[index];
}
}
int usbdev_get_device_list(void)
{
ssize_t cnt;
cnt = libusb_get_device_list(NULL, &s_devs);
if (cnt < 0)
{
//libusb_exit(NULL);
return (int) cnt;
}
libusb_device *dev;
int i = 0, j = 0;
uint8_t path[8];
memset(path,0,sizeof(path));
memset(s_devs_str,0,sizeof(s_devs_str));
s_devs_num = 0;
while ((dev = s_devs[i]) != NULL)
{
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0)
{
fprintf(stderr, "failed to get device descriptor");
return -1;
}
printf("%04x:%04x (bus %d, device %d)",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
r = libusb_get_port_numbers(dev, path, sizeof(path));
if (r > 0)
{
printf(" path: %d", path[0]);
for (j = 1; j < r; j++)
printf(".%d", path[j]);
}
printf("\n");
snprintf(s_devs_str[i],MAX_DEVS_STR_LEN,"%04x:%04x (bus %d, device %d) path: %d .%d .%d .%d .%d .%d .%d .%d",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev),
path[0],path[1],path[2],path[3],path[4],path[5],path[6],path[7]);
i++;
s_devs_num++;
}
libusb_free_device_list(s_devs, 1);
}
int usbdev_open(int index)
{
int vid;
int pid;
printf("index=%d,s_devs_num=%d\r\n",index,s_devs_num);
if(index >= s_devs_num)
{
return -1;
}
if(s_opened_handle != NULL)
{
return 0;
}
sscanf(s_devs_str[index],"%04x:%04x",&vid,&pid);
s_opened_handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
if (s_opened_handle == NULL)
{
printf("Open device %d vid:%x,pid:%x failed.\n",index,vid,pid);
return -2;
}
else
{
printf("dev opened\r\n");
}
s_opened_dev = libusb_get_device(s_opened_handle);
uint8_t bus = libusb_get_bus_number(s_opened_dev);
return 0;
}
int usbdev_close(void)
{
if(s_opened_handle != NULL)
{
libusb_close(s_opened_handle);
s_opened_handle = NULL;
printf("dev closed\r\n");
}
s_tx_busy = 0;
s_tx_ep_idx = -1;
s_tx_itf_idx = -1;
s_tx_size = 0;
s_rx_busy = 0;
s_rx_ep_idx = -1;
s_rx_itf_idx = -1;
s_rx_size = 0;
return 0;
}
int usbdev_get_openstatus(void)
{
printf("get dev status\r\n");
if(s_opened_handle == NULL)
{
return 0;
}
else
{
return 1;
}
}
int usbdev_control_transfer (uint8_t bmRequestType,
uint8_t bRequest,
uint16_t wValue,
uint16_t wIndex,
unsigned char * data,
uint16_t wLength,
unsigned int timeout)
{
if(s_opened_handle == NULL)
{
return -1;
}
printf("bmRequestType:%d\r\n",bmRequestType);
printf("bRequest:%d\r\n",bRequest);
printf("wValue:%d\r\n",wValue);
printf("wIndex:%d\r\n",wIndex);
printf("wLength:%d\r\n",wLength);
return libusb_control_transfer(s_opened_handle,
bmRequestType,bRequest,
wValue,wIndex,
data,wLength,timeout);
}
int usbdev_update_interface_endpoint_list(void)
{
struct libusb_config_descriptor * config;
struct libusb_interface * interface;
struct libusb_interface_descriptor* altsetting;
struct libusb_endpoint_descriptor * endpoint;
if(s_opened_dev != NULL)
{
memset(&s_interface_info,0,sizeof(s_interface_info));
if(0 == libusb_get_active_config_descriptor(s_opened_dev,&config))
{
s_interface_num = 0;
if(config != NULL)
{
interface = config->interface;
for(int i=0; i< config->bNumInterfaces; i++)
{
for(int j=0; j
{
altsetting = interface[i].altsetting;
s_interface_info[s_interface_num].interfacenumber = altsetting[j].bInterfaceNumber;
s_interface_info[s_interface_num].alternateSetting = altsetting[j].bAlternateSetting;
s_interface_info[s_interface_num].numendpoints = altsetting[j].bNumEndpoints;
for(int k=0; k
{
endpoint = altsetting[j].endpoint;
s_interface_info[s_interface_num].endpoints[k] = endpoint[k];
}
s_interface_num++;
}
}
libusb_free_config_descriptor(config);
}
}
else
{
return -2;
}
}
else
{
return -1;
}
return 0;
}
int usbdev_get_interface_num(void)
{
return s_interface_num;
}
int usbdev_get_interface_id(int itf_index, int* interface, int* altsetting)
{
if((itf_index >= s_interface_num) || (itf_index == -1))
{
return -1;
}
*interface = s_interface_info[itf_index].interfacenumber;
*altsetting = s_interface_info[itf_index].alternateSetting;
return 0;
}
int usbdev_get_endpoint_num(int itf_index)
{
if((itf_index >= s_interface_num) || (itf_index == -1))
{
return -1;
}
return s_interface_info[itf_index].numendpoints;
}
int usbdev_get_endpoint_info(int itf_index, int ep_index, int* address, int* type, int* mps)
{
struct libusb_endpoint_descriptor* endpoint;
if((itf_index >= s_interface_num) || (itf_index == -1))
{
return -1;
}
if((ep_index >= s_interface_info[itf_index].numendpoints) || (ep_index == -1))
{
return -1;
}
endpoint = s_interface_info[itf_index].endpoints;
*address = endpoint[ep_index].bEndpointAddress;
*type = endpoint[ep_index].bmAttributes;
*mps = endpoint[ep_index].wMaxPacketSize;
return 0;
}
int usbdev_bulk_transfer(int itf_id,unsigned char endpoint, unsigned char *data, int length, int* transferred, unsigned int timeout)
{
int res;
if(s_opened_handle == NULL)
{
return -1;
}
if(0 != libusb_claim_interface(s_opened_handle,itf_id))
{
return -1;
}
res = libusb_bulk_transfer(s_opened_handle, endpoint, data, length, transferred, timeout);
libusb_release_interface(s_opened_handle,itf_id);
return res;
}
int usbdev_interrupt_transfer(int itf_id,unsigned char endpoint, unsigned char *data, int length, int* transferred, unsigned int timeout)
{
int res;
if(s_opened_handle == NULL)
{
return -1;
}
if(0 != libusb_claim_interface(s_opened_handle,itf_id))
{
return -1;
}
res = libusb_interrupt_transfer(s_opened_handle, endpoint, data, length, transferred, timeout);
libusb_release_interface(s_opened_handle,itf_id);
return res;
}
int usbdev_start_tx_transfer(int itf_index, int ep_index, uint32_t size)
{
if(itf_index == -1)
{
return -1;
}
int itf_id;
int itf_alt_id;
s_tx_size = size;
if(itf_index==s_tx_itf_idx)
{
/* 如果和tx接口一样,且已经打开(s_tx_itf_idx!=-1),无需处理接口,只需要修改端点即可 */
s_tx_ep_idx = ep_index;
}
else
{
/* 如果和tx接口不一样,要看是不是和rx接口一样 */
if(itf_index==s_rx_itf_idx)
{
/* 如果和rx接口一样,说明接口也已经打开,无需再打开
* 此时如果原来tx接口是打开的需要关闭,并更新
*/
s_tx_ep_idx = ep_index;
if(s_tx_itf_idx != -1)
{
usbdev_get_interface_id(s_tx_itf_idx, &itf_id, &itf_alt_id);
libusb_release_interface(s_opened_handle,itf_id);
}
s_tx_itf_idx = itf_index;
}
else
{
/* 如果和rx接口也不一样,则是全新的接口,需要先关闭原来的tx接口,再打开新的接口
* 此时如果原来tx接口是打开的需要关闭,并更新
*/
if(s_tx_itf_idx != -1)
{
usbdev_get_interface_id(s_tx_itf_idx, &itf_id, &itf_alt_id);
libusb_release_interface(s_opened_handle,itf_id);
}
usbdev_get_interface_id(itf_index, &itf_id, &itf_alt_id);
if(0 == libusb_claim_interface(s_opened_handle,itf_id))
{
//libusb_clear_halt(s_opened_handle,s_interface_info[itf_index].endpoints[ep_index].bEndpointAddress);
s_tx_itf_idx = itf_index;
s_tx_ep_idx = ep_index;
}
else
{
s_tx_itf_idx = -1;
return -1;
}
}
}
return 0;
}
int usbdev_stop_tx_transfer(void)
{
int itf_id;
int itf_alt_id;
s_tx_busy = 0;
/* 只有tx接口已经打开,且rx没有在用才关闭*/
if(s_tx_itf_idx != -1)
{
if(s_tx_itf_idx != s_rx_itf_idx)
{
usbdev_get_interface_id(s_tx_itf_idx, &itf_id, &itf_alt_id);
libusb_release_interface(s_opened_handle,itf_id);
s_tx_itf_idx = -1;
}
}
return 0;
}
int usbdev_start_rx_transfer(int itf_index, int ep_index, uint32_t size)
{
if(itf_index == -1)
{
return -1;
}
int itf_id;
int itf_alt_id;
s_rx_size = size;
if(itf_index==s_rx_itf_idx)
{
/* 如果和rx接口一样,且已经打开(s_rx_itf_idx!=-1),无需处理接口,只需要修改端点即可 */
s_rx_ep_idx = ep_index;
}
else
{
/* 如果和rx接口不一样,要看是不是和tx接口一样 */
if(itf_index==s_tx_itf_idx)
{
/* 如果和tx接口一样,说明接口也已经打开,无需再打开
* 此时如果原来rx接口是打开的需要关闭,并更新
*/
s_rx_ep_idx = ep_index;
if(s_rx_itf_idx != -1)
{
usbdev_get_interface_id(s_rx_itf_idx, &itf_id, &itf_alt_id);
libusb_release_interface(s_opened_handle,itf_id);
}
s_rx_itf_idx = itf_index;
}
else
{
/* 如果和tx接口也不一样,则是全新的接口,需要先关闭原来的rx接口,再打开新的接口
* 此时如果原来rx接口是打开的需要关闭,并更新
*/
if(s_rx_itf_idx != -1)
{
usbdev_get_interface_id(s_rx_itf_idx, &itf_id, &itf_alt_id);
libusb_release_interface(s_opened_handle,itf_id);
}
usbdev_get_interface_id(itf_index, &itf_id, &itf_alt_id);
if(0 == libusb_claim_interface(s_opened_handle,itf_id))
{
//libusb_clear_halt(s_opened_handle,s_interface_info[itf_index].endpoints[ep_index].bEndpointAddress);
s_rx_itf_idx = itf_index;
s_rx_ep_idx = ep_index;
}
else
{
s_rx_itf_idx = -1;
return -1;
}
}
}
return 0;
}
int usbdev_stop_rx_transfer(void)
{
int itf_id;
int itf_alt_id;
s_rx_busy = 0;
/* 只有rx接口已经打开,且tx没有在用才关闭*/
if(s_rx_itf_idx != -1)
{
if(s_rx_itf_idx != s_tx_itf_idx)
{
usbdev_get_interface_id(s_rx_itf_idx, &itf_id, &itf_alt_id);
libusb_release_interface(s_opened_handle,itf_id);
s_rx_itf_idx = -1;
}
}
return 0;
}
uint32_t usbdev_get_rx_transfer_data(uint8_t* buffer, uint32_t len)
{
return usbdev_rx_fifo_get(buffer,len);
}
uint32_t usbdev_get_rx_transfer_datalen(void)
{
return usbdev_rx_fifo_datalen();
}
uint32_t usbdev_put_tx_transfer_data(uint8_t* buffer, uint32_t len)
{
return usbdev_tx_fifo_put(buffer,len);
}
void tx_cb(struct libusb_transfer *transfer)
{
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
{
/* 成功 */
printf("tx_cb ok\r\n");
}
else
{
/* 失败 */
printf("tx_cb err %d\r\n",transfer->status);
//libusb_submit_transfer(transfer);
}
free(transfer->buffer); /* 在free传输之前 */
libusb_free_transfer(transfer);
s_tx_busy = 0;
}
void rx_cb(struct libusb_transfer *transfer)
{
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
{
/* 成功 */
printf("rx_cb ok\r\n");
}
else
{
/* 失败 */
printf("rx_cb err %d\r\n",transfer->status);
}
if(transfer->actual_length > 0)
{
printf("rx len %d\r\n",transfer->actual_length);
usbdev_rx_fifo_put(transfer->buffer,transfer->actual_length);
}
free(transfer->buffer); /* 在free传输之前 */
libusb_free_transfer(transfer);
s_rx_busy = 0;
}
static void* usb_handle_thread(void *arg)
{
while(1)
{
/* 发送处理 */
if((s_tx_itf_idx != -1) && (s_tx_busy == 0))
{
int address;
int type;
int mps;
int rc = 0;
uint32_t sendlen;
struct libusb_transfer* transfer;
uint8_t* buffer = malloc(s_tx_size);
if(buffer != NULL)
{
sendlen = usbdev_tx_fifo_get(buffer,s_tx_size);
if(sendlen > 0)
{
transfer = libusb_alloc_transfer(0);
if(transfer != NULL)
{
if(0 == usbdev_get_endpoint_info(s_tx_itf_idx, s_tx_ep_idx, &address, &type, &mps))
{
switch(type & 0x03)
{
case 0:
//epstr = epstr + "CTRL";
break;
case 1:
//epstr = epstr + "ISOC";
break;
case 2:
libusb_fill_bulk_transfer(transfer,s_opened_handle,address,buffer,sendlen,&tx_cb,0,100);
break;
case 3:
libusb_fill_interrupt_transfer(transfer,s_opened_handle,address,buffer,sendlen,&tx_cb,0,100);
break;
}
s_tx_busy = 1;
if(libusb_submit_transfer(transfer) < 0)
{
s_tx_busy = 0;
libusb_free_transfer(transfer);
free(buffer);
}
}
else
{
libusb_free_transfer(transfer);
free(buffer);
}
}
else
{
free(buffer);
}
}
else
{
free(buffer);
}
}
}
/* 接收处理 */
if((s_rx_itf_idx != -1) && (s_rx_busy == 0))
{
int address;
int type;
int mps;
uint32_t sendlen;
struct libusb_transfer* transfer;
uint8_t* buffer = malloc(s_rx_size);
if(buffer != NULL)
{
transfer = libusb_alloc_transfer(0);
if(transfer != NULL)
{
if(0 == usbdev_get_endpoint_info(s_rx_itf_idx, s_rx_ep_idx, &address, &type, &mps))
{
switch(type & 0x03)
{
case 0:
//epstr = epstr + "CTRL";
break;
case 1:
//epstr = epstr + "ISOC";
break;
case 2:
libusb_fill_bulk_transfer(transfer,s_opened_handle,address,buffer,s_rx_size,&rx_cb,0,100);
break;
case 3:
libusb_fill_interrupt_transfer(transfer,s_opened_handle,address,buffer,s_rx_size,&rx_cb,0,100);
break;
}
s_rx_busy = 1;
if(libusb_submit_transfer(transfer) < 0)
{
s_rx_busy = 0;
libusb_free_transfer(transfer);
free(buffer);
}
else
{
}
}
else
{
libusb_free_transfer(transfer);
free(buffer);
}
}
else
{
free(buffer);
}
}
}
const struct timespec interval=
{
.tv_nsec = 1000000,
.tv_sec = 0,
};
pthread_delay_np(&interval);
}
return 0;
}
static void* usb_event_thread(void *arg)
{
while(1)
{
/* 至少打开了一个设备才进行事件循环 */
if(s_opened_handle != 0)
{
libusb_handle_events(0);
}
const struct timespec interval=
{
.tv_nsec = 1000000,
.tv_sec = 0,
};
pthread_delay_np(&interval);
}
return 0;
}
不勾选重复
点击开始接收,点击发送进行一次发送,可以看到收到一次发送的数据,停止发送以便下一次继续发送。
勾选重复,点击开始可以看到自动重复发送
设置发送间隔时间1,10,100ms查看发送间隔是否正确
设置一次发送100字节,但是编辑框只有10字节,可以看到填充0发送
前面都是HEX模式,不勾选HEX ASCII模式显示也正确
清楚显示等测试
我们可以优化下界面自适应窗口的大小,得益于我们使用了嵌套layout的模式,所以整个界面就是一个layotu整体。只需要做一下两件事即可实现自动适应窗口大小。
1.确认所有控件的sizePolicy的策略为Expanding
2.界面空白处点击右键-布局-垂直布局
我们最外层的布局一样,这样整个界面作为了一个垂直布局的整体和窗口大小自适应
可以看到缩放的效果
最小化
最大化
目前实现了批量传输/中断传输(异步模式), 控制传输(同步模式)这几项功能的测试,工具基本具备了实用价值,后面我们还有一些继续完善的工作。
1.添加ISO传输功能。
2.实现批量,同步传输的最大效率,即能实现不间断的流,可以通过一开始就挂在多个传输来实现。
3.GUI交互方面的优化,比如提供控制传输的GUI模板,自动选择常见固定的控制请求。
4.其他使用中可以继续优化的问题。