STEPBYSTEP设计一个USB调试助手之十一:基于libusb异步传输+FIFO的USB测试工具

原创 嵌入式Lee 2024-04-14 08:00

一. 前言

最开始版本的GUI工具时同步传输实现的,后面我们又实现了异步传输,进一步实现了一步传输+FIFOGUI和底层的解耦。现在我们将这几部分合并起来,实现一个异步传输的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

#include #include #include #include "libusb.h"#include "usbdev.h"#include "fifo.h"#include "usbdev_fifo.h"
#define MAX_DEVS 64#define MAX_DEVS_STR_LEN 256#define MAX_ENDPOINTS 16#define MAX_INTERFACE 16
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;}

一. 测试

3.1单次发送模式

不勾选重复

点击开始接收,点击发送进行一次发送,可以看到收到一次发送的数据,停止发送以便下一次继续发送。

3.2重复发送模式

勾选重复,点击开始可以看到自动重复发送

3.3确认发送间隔时间

设置发送间隔时间1,10,100ms查看发送间隔是否正确

3.4确认发送大小是否正确

设置一次发送100字节,但是编辑框只有10字节,可以看到填充0发送

3.5ASCII/HEX模式

前面都是HEX模式,不勾选HEX ASCII模式显示也正确

3.6其他功能

清楚显示等测试

四. 优化窗口自适应

我们可以优化下界面自适应窗口的大小,得益于我们使用了嵌套layout的模式,所以整个界面就是一个layotu整体。只需要做一下两件事即可实现自动适应窗口大小。

1.确认所有控件的sizePolicy的策略为Expanding

2.界面空白处点击右键-布局-垂直布局

我们最外层的布局一样,这样整个界面作为了一个垂直布局的整体和窗口大小自适应

可以看到缩放的效果

最小化

最大化


五. 总结

目前实现了批量传输/中断传输(异步模式), 控制传输(同步模式)这几项功能的测试,工具基本具备了实用价值,后面我们还有一些继续完善的工作。

1.添加ISO传输功能。

2.实现批量,同步传输的最大效率,即能实现不间断的流,可以通过一开始就挂在多个传输来实现。

3.GUI交互方面的优化,比如提供控制传输的GUI模板,自动选择常见固定的控制请求。

4.其他使用中可以继续优化的问题。






评论 (0)
  • 及时生产 JIT(Just In Time)的起源JIT 起源于 20 世纪 70 年代爆发的全球石油危机和由此引发的自然资源短缺,这对仰赖进口原物料发展经济的日本冲击最大。当时日本的生产企业为了增强竞争力、提高产品利润,在原物料成本难以降低的情况下,只能从生产和流通过程中寻找利润源,降低库存、库存和运输等方面的生产性费用。根据这种思想,日本丰田汽车公司创立的一种具有特色的现代化生产方式,即 JIT,并由此取得了意想不到的成果。由于它不断地用于汽车生产,随后被越来越多的许多行业和企业所采用,为日
    优思学院 2025-04-07 11:56 93浏览
  • 贞光科技作为三星电机车规电容代理商,针对电动汽车领域日益复杂的电容选型难题,提供全方位一站式解决方案。面对高温稳定性、高可靠性、高纹波电流和小型化等严苛要求,三星车规电容凭借完整产品矩阵和卓越技术优势,完美满足BMS、电机控制器和OBC等核心系统需求。无论技术选型、供应链保障、样品测试还是成本优化,贞光科技助力客户在电动汽车产业高速发展中占据技术先机。在电动汽车技术高速发展的今天,作为汽车电子系统中不可或缺的关键元器件,电容的选型已成为困扰许多工程师和采购人员的难题。如何在众多参数和型号中找到最
    贞光科技 2025-04-07 17:06 36浏览
  • 在万物互联时代,智能化安防需求持续升级,传统报警系统已难以满足实时性、可靠性与安全性并重的要求。WT2003H-16S低功耗语音芯片方案,以4G实时音频传输、超低功耗设计、端云加密交互为核心,重新定义智能报警设备的性能边界,为家庭、工业、公共安防等领域提供高效、稳定的安全守护。一、技术内核:五大核心突破,构建全场景安防基座1. 双模音频传输,灵活应对复杂场景实时音频流传输:内置高灵敏度MIC,支持环境音实时采集,通过4G模块直接上传至云端服务器,响应速度低至毫秒级,适用于火灾警报、紧急呼救等需即
    广州唯创电子 2025-04-08 08:59 68浏览
  •     在研究Corona现象时发现:临界电压与介电材料表面的清洁程度有关。表面越清洁的介电材料,临界电压越高;表面污染物越多的地方,越容易“爬电”。关于Corona现象,另见基础理论第007篇。    这里说的“污染物”,定义为——可能影响介电强度或表面电阻率的固体、液体或气体(电离气体)的任何情况。    IEC 60664-1 (对应GB/T 16935.1-2023) 定义了 Pollution Degree,中文术语是“污染等
    电子知识打边炉 2025-04-07 22:06 45浏览
  • 在全球电子产业面临供应链波动、技术迭代和市场需求变化等多重挑战的背景下,安博电子始终秉持“让合作伙伴赢得更多一点”的核心理念,致力于打造稳健、高效、可持续的全球供应链体系。依托覆盖供应商管理、品质检测、智能交付的全链路品控体系,安博电子不仅能确保电子元器件的高可靠性与一致性,更以高透明的供应链管理模式,助力客户降低风险、提升运营效率,推动行业标准升级,与全球合作伙伴共同塑造更具前瞻性的产业生态。动态优选机制:构建纯净供应链生态安博电子将供应商管理视为供应链安全的根基。打造动态优选管控体系,以严格
    电子资讯报 2025-04-07 17:06 49浏览
  • 曾几何时,汽车之家可是汽车资讯平台领域响当当的“扛把子”。2005 年成立之初,它就像一位贴心的汽车小助手,一下子就抓住了大家的心。它不仅吸引了海量用户,更是成为汽车厂商和经销商眼中的“香饽饽”,广告投放、合作推广不断,营收和利润一路高歌猛进,2013年成功在纽交所上市,风光无限。2021年更是在香港二次上市,达到了发展的巅峰,当年3月15日上市首日,港股股价一度高达184.6港元,市值可观。然而,如今的汽车之家却陷入了困境,业务下滑明显。业务增长瓶颈从近年来汽车之家公布的财报数据来看,情况不容
    用户1742991715177 2025-04-07 21:48 57浏览
  • 在追求环境质量升级与产业效能突破的当下,温湿度控制正成为横跨多个行业领域的核心命题。作为环境参数中的关键指标,温湿度的精准调控不仅承载着人们对舒适人居环境的期待,更深度关联着工业生产、科研实验及仓储物流等场景的运营效率与安全标准。从应用场景上看,智能家居领域要求温湿度系统实现与人体节律的协同调节,半导体洁净车间要求控制温湿度范围及其波动以保障良品率,而现代化仓储物流体系则依赖温湿度的实时监测预防各种产品的腐损与锈化。温湿度传感器作为实现温湿度监测的关键元器件,其重要性正在各行各业中凸显而出。温湿
    华普微HOPERF 2025-04-07 10:05 88浏览
  • 文/Leon编辑/cc孙聪颖‍转手绢、跳舞、骑车、后空翻,就在宇树、智元等独角兽企业率领“机器人大军”入侵短视频时,却有资本和科技大佬向此产业泼了一盆冷水。金沙江创投管理合伙人朱啸虎近日突然对人形机器人发难,他表示“最近几个月正在批量退出人形机器人公司”。“只是买回去做研究的,或者买回去做展示的,这种都不是我们意义上的商业化,谁会花十几万买一个机器人去干这些活?”朱啸虎吐槽。不过,朱啸虎的观点很快就遭到驳斥,众擎机器人的创始人、董事长赵同阳回怼道:“(朱啸虎)甚至问出了人形机器人在这个阶段有什么
    华尔街科技眼 2025-04-07 19:24 74浏览
  •   工业自动化领域电磁兼容与接地系统深度剖析   一、电磁兼容(EMC)基础认知   定义及关键意义   电磁兼容性(EMC),指的是设备或者系统在既定的电磁环境里,不但能按预期功能正常运转,而且不会对周边其他设备或系统造成难以承受的电磁干扰。在工业自动化不断发展的当下,大功率电机、变频器等设备被大量应用,现场总线、工业网络等技术也日益普及,致使工业自动化系统所处的电磁环境变得愈发复杂,电磁兼容(EMC)问题也越发严峻。   ​电磁兼容三大核心要素   屏蔽:屏蔽旨在切断电磁波的传播路
    北京华盛恒辉软件开发 2025-04-07 22:55 72浏览
  •     根据 IEC术语,瞬态过电压是指持续时间几个毫秒及以下的过高电压,通常是以高阻尼(快速衰减)形式出现,波形可以是振荡的,也可以是非振荡的。    瞬态过电压的成因和机理,IEC 60664-1给出了以下四种:    1. 自然放电,最典型的例子是雷击,感应到电力线路上,并通过电网配电系统传输,抵达用户端;        2. 电网中非特定感性负载通断。例如热处理工厂、机加工工厂对
    电子知识打边炉 2025-04-07 22:59 48浏览
  • 在人工智能技术飞速发展的今天,语音交互正以颠覆性的方式重塑我们的生活体验。WTK6900系列语音识别芯片凭借其离线高性能、抗噪远场识别、毫秒级响应的核心优势,为智能家居领域注入全新活力。以智能风扇为起点,我们开启一场“解放双手”的科技革命,让每一缕凉风都随“声”而至。一、核心技术:精准识别,无惧环境挑战自适应降噪,听懂你的每一句话WTK6900系列芯片搭载前沿信号处理技术,通过自适应降噪算法,可智能过滤环境噪声干扰。无论是家中电视声、户外虫鸣声,还是厨房烹饪的嘈杂声,芯片均能精准提取有效指令,识
    广州唯创电子 2025-04-08 08:40 79浏览
  • 医疗影像设备(如CT、MRI、超声诊断仪等)对PCB的精度、可靠性和信号完整性要求极高。这类设备需要处理微伏级信号、高频数据传输,同时需通过严格的EMC/EMI测试。制造此类PCB需从材料选择、层叠设计、工艺控制等多维度优化。以下是关键技术与经验分享。 1. 材料选择:高频与生物兼容性优先医疗影像设备PCB常采用 Rogers RO4000系列 或 Isola FR4高速材料,以降低介电损耗并保证信号稳定性。例如,捷多邦在客户案例中曾为某超声探头厂商推荐 Rogers RO4350B
    捷多邦 2025-04-07 10:22 93浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦