前面实现了设备的打开与关闭的逻辑,现在来继续实现数据的收发。因为控制传输无需解析接口端点等信息,比较直接,打开设备之后就可以进行,所以先实现控制传输部分。
参考API: libusb_control_transfer
https://libusb.sourceforge.io/api-1.0/group__libusb__syncio.html#gadb11f7a761bd12fc77a07f4568d56f38
usbdev.c中添加接口封装,不对外暴漏设备相关信息
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);
}
usbdev.h中声明
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);
SETUP后面的编辑框输入8字节的SETUP数据,
DATA后面的编辑框输入待发送的数据或者显示接收到的数据。
清除显示按钮清除DATA编辑框的数据,开始按钮开始进行传输。
这里使用同步方式进行控制传输,即点击开始按钮后进行控制传输,完成之后再更新数据显示。
右键点击”清除显示”按钮->转到槽->选择clicked()->确认
添加处理函数
void MainWindow::on_pushButton_6_clicked()
{
}
实现逻辑为
按键后修改DATA后面的编辑框这里是textEdit_6的内容为空。
按钮处理实现如下
void MainWindow::on_pushButton_6_clicked()
{
}
按”开始”按钮,需要获取SETUP后编辑框的内容,解析8字节的setup内容,
如果是发送,则需要获取DATA区域的内容,然后调用控制传输接口发送,
如果是接收,则需要将获取到的数据写入DATA区域。
同样添加按钮的处理函数
void MainWindow::on_pushButton_7_clicked()
{
}
该函数中先获取编辑框中的内容
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::StandardButton button = 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 (setup_str.toLatin1().data());
if((bmRequestType & 0x80) == 0)
{
/* OUT传输 获取DATA编辑框的内容 */
if(ctrl_data.size() != wLength)
{
QMessageBox::StandardButton button = 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::StandardButton button = 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);
}
以上获取到数据,转为字符串写入编辑框,需要进行数据转换实现如下
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;
}
需要刷新一次才能显示设备,可以改为初始化时刷新一次,减少操作。
默认SETUP可以填充一个比较常见的获取配置描述符的SETUP。
构造函数中增加一行
on_pushButton_8_clicked();刷新设备
ui->textEdit_5->setText("800600020000FF00"); 设置SETUP默认内容.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
usbdev_init();
ui->setupUi(this);
on_pushButton_8_clicked();
ui->textEdit_5->setText("800600020000FF00");
}
默认是800600020000FF00
获取配置描述符,直接点击开始获取到描述符如下
以上仅测试了控制IN,控制OUT和无数据控制传输等有对应的设备再测试(未测试代码不能保证没问题)。
以上完成了控制传输部分的逻辑,现在我们的工具已经初步具备了使用价值了,就是可以用于控制传输的测试了。后面就是继续进行端点数据传输部分的逻辑开发。