reason
As you know, I had made a project by FT232H to transfer data. But the driver made by me is awful, so I have to optimize it. And this page is share and wise your suggestion.
source code
#include "widget.h"
#include "ui_widget.h"
#include <Qfile>
#include <QString>
#include <QThread>
#include <QTextStream>
#include <QMessageBox>
#include "ftd2xx.h"
#include "QDebug"
FT_DEVICE_LIST_INFO_NODE *devInfo;
FT_STATUS ftStatus;
FT_HANDLE ftHandle;
DWORD numDevs;
bool bContinue = FALSE;
UCHAR Mask = 0xff;
//Single Channel Synchrocnous 245 FIFO Mode (FT2232H and FT232H devices only)
UCHAR Mode = 0x40;
QThread *rxthread = new QThread;
void Widget::CheakNum()
{
ui->comboBox->clear();
ui->textBrowser->clear();
ftStatus = FT_CreateDeviceInfoList(&numDevs);
if (ftStatus == FT_OK) {
ui->label->setNum((int)numDevs);
// int i = 10;
// QString dev = QString("Dev %1");
// dev = dev.arg(i);
// ui->textBrowser->append(dev);
// ui->textBrowser->append("Dev");
if (numDevs > 0)
{
devInfo =
(FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs);
// get the device information list
ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs);
if (ftStatus == FT_OK) {
for (int i = 0; i < (int)numDevs; i++) {
// printf("Dev %d:\n", i);
// printf(" Flags=0x%x\n", devInfo[i].Flags);
// printf(" Type=0x%x\n", devInfo[i].Type);
// printf(" ID=0x%x\n", devInfo[i].ID);
// printf(" LocId=0x%x\n", devInfo[i].LocId);
// printf(" SerialNumber=%s\n", devInfo[i].SerialNumber);
// printf(" Description=%s\n", devInfo[i].Description);
// printf(" ftHandle=0x%x\n", devInfo[i].ftHandle);
QString dev = QString("Dev %1");
dev = dev.arg(i);
ui->textBrowser->append(dev);
QString SerialNumber = QString::fromLocal8Bit(devInfo[i].SerialNumber);
ui->textBrowser->append(" SerialNumber=");
ui->textBrowser->insertPlainText(SerialNumber);
QString Description = QString::fromLocal8Bit(devInfo[i].Description);
ui->textBrowser->append(" Description=");
ui->textBrowser->insertPlainText(Description);
QString str;
str = QString::fromLocal8Bit(devInfo[i].Description);
ui->comboBox->addItem(str);
}
}
}
}
else {
QMessageBox::warning(NULL, "test", "CheakNum ERROR!");
}
qDebug() << numDevs;
}
void Widget::OpenPort()
{
if (numDevs > 0)
{
int iSelIndex = ui->comboBox->currentIndex();
if (iSelIndex >= 0)
{
ftStatus = FT_Open(iSelIndex , &ftHandle);
if (ftStatus == FT_OK)
{
ui->label->setText("connect!");
bContinue = TRUE;
ftStatus = FT_SetBitMode(ftHandle, Mask, Mode);
if (ftStatus == FT_OK) {
// 0xff written to device
}
else {
// FT_SetBitMode FAILED!
QMessageBox::warning(NULL, "test", "FT_SetBitMode FAILED!");
}
rxthread->start();
qDebug() << rxthread;
}
else
{
QMessageBox::warning(NULL, "test", "OpenPort ERROR!");
}
}
}
}
void Widget::ClosePort()
{
if (ftHandle)
{
ftStatus = FT_Close(ftHandle);
ftHandle = NULL;
if (ftStatus == FT_OK)
{
ui->label->setText("no connect!");
bContinue = FALSE;
}
else
{
QMessageBox::warning(NULL, "test", "ClosePort ERROR!");
}
}
}
void Widget::ReadingProc()
{
DWORD RxBytes;
DWORD dwRXBytes;
//QChar rx_char;
QChar rx_char;
//从QT获取文件名称
QString filepath;
filepath = ui->PathEdit->text();
QFile file(filepath);
file.open(QIODevice::WriteOnly);
QTextStream out(&file);
while (bContinue)
{
FT_GetQueueStatus(ftHandle, &RxBytes);
if ((ftStatus == FT_OK) && (RxBytes > 0))
{
ftStatus = FT_Read(ftHandle, &rx_char, 1, &dwRXBytes);
if (ftStatus == FT_OK)
{
//printf("%x\n",rx_char);
/*ui.textBrowser->insertPlainText(QString(rx_char));*/
//out << hex << rx_char;
//QByteArray byteArray(&rx_char, 1);
//QString hexString = byteArray.toHex();
char data = rx_char.toLatin1();
QByteArray byteArray(&data, 1);
QString hexString = byteArray.toHex();
out << hexString << ' ';
}
else
{
QMessageBox::warning(NULL, "test", "ReadingProc ERROR!");
}
}
}
// rxthread->quit();
}
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(rxthread, &QThread::started, [=]() {
ReadingProc();
rxthread->exit();
});
connect(rxthread, &QThread::finished, [=]() {
qDebug() << "rxthread finish!";
});
connect(ui->SearchButton , &QPushButton::clicked , [&](){
CheakNum();
});
connect(ui->ConnectButton , &QPushButton::clicked , [&](){
OpenPort();
});
connect(ui->CloseButton , &QPushButton::clicked , [&](){
ClosePort();
ui->textBrowser->clear();
ui->textBrowser->append("rxthread finish!");
});
}
Widget::~Widget()
{
delete ui;
}
code interpretation
In this part I want to interpret my code for I will remember this project quickly in the future.
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(rxthread, &QThread::started, [=]() {
ReadingProc();
rxthread->exit();
});
connect(rxthread, &QThread::finished, [=]() {
qDebug() << "rxthread finish!";
});
connect(ui->SearchButton , &QPushButton::clicked , [&](){
CheakNum();
});
connect(ui->ConnectButton , &QPushButton::clicked , [&](){
OpenPort();
});
connect(ui->CloseButton , &QPushButton::clicked , [&](){
ClosePort();
ui->textBrowser->clear();
ui->textBrowser->append("rxthread finish!");
});
}
This function is created by QT, it's used to creat ui on widget.
There are three functions is created by me and tie up on different buttons, they will be used when click particular button.
And there is a thread start when receive data.
void Widget::CheakNum()
{
ui->comboBox->clear();
ui->textBrowser->clear();
ftStatus = FT_CreateDeviceInfoList(&numDevs);
if (ftStatus == FT_OK) {
ui->label->setNum((int)numDevs);
// int i = 10;
// QString dev = QString("Dev %1");
// dev = dev.arg(i);
// ui->textBrowser->append(dev);
// ui->textBrowser->append("Dev");
if (numDevs > 0)
{
devInfo =
(FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs);
// get the device information list
ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs);
if (ftStatus == FT_OK) {
for (int i = 0; i < (int)numDevs; i++) {
// printf("Dev %d:\n", i);
// printf(" Flags=0x%x\n", devInfo[i].Flags);
// printf(" Type=0x%x\n", devInfo[i].Type);
// printf(" ID=0x%x\n", devInfo[i].ID);
// printf(" LocId=0x%x\n", devInfo[i].LocId);
// printf(" SerialNumber=%s\n", devInfo[i].SerialNumber);
// printf(" Description=%s\n", devInfo[i].Description);
// printf(" ftHandle=0x%x\n", devInfo[i].ftHandle);
QString dev = QString("Dev %1");
dev = dev.arg(i);
ui->textBrowser->append(dev);
QString SerialNumber = QString::fromLocal8Bit(devInfo[i].SerialNumber);
ui->textBrowser->append(" SerialNumber=");
ui->textBrowser->insertPlainText(SerialNumber);
QString Description = QString::fromLocal8Bit(devInfo[i].Description);
ui->textBrowser->append(" Description=");
ui->textBrowser->insertPlainText(Description);
QString str;
str = QString::fromLocal8Bit(devInfo[i].Description);
ui->comboBox->addItem(str);
}
}
}
}
else {
QMessageBox::warning(NULL, "test", "CheakNum ERROR!");
}
qDebug() << numDevs;
}
This function is cheak wheter have USB2.0 devices connected.
ftStatus = FT_CreateDeviceInfoList(&numDevs);
This code will check how many USB2.0 devices connected. If run correctly will return FT_OK and put the connected number into parameter numDevs.
devInfo =
(FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs);
// get the device information list
ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs);
FT_GetDeviceInfoList should only be called after calling FT_CreateDeviceInfoList. If the devices connected to the system change, the device info list will not be updated until FT_CreateDeviceInfoList is called again.
Location ID information is not returned for devices that are open when FT_CreateDeviceInfoList is called. FT_GetDeviceInfoList can get the ID information.
Malloc: This is a function in the C used to allocate memory. Its parameter is the number of bytes to be allocated, and the return value is a pointer to the allocated memory.
There is a sample:
int *array = (int*)malloc(10 * sizeof(int));
Other code is used to prase USB ID information.
void Widget::OpenPort()
{
if (numDevs > 0)
{
int iSelIndex = ui->comboBox->currentIndex();
if (iSelIndex >= 0)
{
ftStatus = FT_Open(iSelIndex , &ftHandle);
if (ftStatus == FT_OK)
{
ui->label->setText("connect!");
bContinue = TRUE;
ftStatus = FT_SetBitMode(ftHandle, Mask, Mode);
if (ftStatus == FT_OK) {
// 0xff written to device
}
else {
// FT_SetBitMode FAILED!
QMessageBox::warning(NULL, "test", "FT_SetBitMode FAILED!");
}
rxthread->start();
qDebug() << rxthread;
}
else
{
QMessageBox::warning(NULL, "test", "OpenPort ERROR!");
}
}
}
}
These code is used to open USB2.0 device and start transfer data.
ftStatus = FT_Open(iSelIndex , &ftHandle);
FT_OK if successful, otherwise the return value is an FT error code.
ftStatus = FT_SetBitMode(ftHandle, Mask, Mode);
Set data transfer mode.
0x40 = Single Channel Synchronous 245 FIFO Mode (FT2232H and FT232H devices only)
Note that to use Single Channel Synchronous 245 FIFO mode for the FT2232H, channel A must be configured for FT245 FIFO mode in the EEPROM.
And start the rxthread to transfer data from FPGA.
void Widget::ClosePort()
{
if (ftHandle)
{
ftStatus = FT_Close(ftHandle);
ftHandle = NULL;
if (ftStatus == FT_OK)
{
ui->label->setText("no connect!");
bContinue = FALSE;
}
else
{
QMessageBox::warning(NULL, "test", "ClosePort ERROR!");
}
}
}
Use FT_Close() to close USB2.0 data transfer channel.
And when bContinue change to FALSE, the rxthread will be shut down.
void Widget::ReadingProc()
{
DWORD RxBytes;
DWORD dwRXBytes;
//QChar rx_char;
QChar rx_char;
//从QT获取文件名称
QString filepath;
filepath = ui->PathEdit->text();
QFile file(filepath);
file.open(QIODevice::WriteOnly);
QTextStream out(&file);
while (bContinue)
{
FT_GetQueueStatus(ftHandle, &RxBytes);
if ((ftStatus == FT_OK) && (RxBytes > 0))
{
ftStatus = FT_Read(ftHandle, &rx_char, 1, &dwRXBytes);
if (ftStatus == FT_OK)
{
//printf("%x\n",rx_char);
/*ui.textBrowser->insertPlainText(QString(rx_char));*/
//out << hex << rx_char;
//QByteArray byteArray(&rx_char, 1);
//QString hexString = byteArray.toHex();
char data = rx_char.toLatin1();
QByteArray byteArray(&data, 1);
QString hexString = byteArray.toHex();
out << hexString << ' ';
}
else
{
QMessageBox::warning(NULL, "test", "ReadingProc ERROR!");
}
}
}
// rxthread->quit();
}
At first, this function creat or open a file to write data.
Use FT_GetQueueStatus() to see the number of bytes in the receive queue.
Use FT_Read() to read data from the receive queue.
It's easy to find that the problem of the driver is here, and I will to fix it.