Windows 串行端口传输错误数据和写入文件返回错误写入字节数的原因?
错误修复更新: 截至2013年6月,FTDI向我承认该漏洞是真实的。此后,他们发布了新版本的驱动程序(2.8.30.0,日期为2013年7月12日),解决了这个问题。该驱动程序于2013年8月1日左右通过WHQL发布,目前可通过Windows Update获得 我已经运行相同的测试代码进行了重新测试,但无法用新的驱动程序重现问题,因此目前的解决方案似乎是“升级驱动程序” 原问题: 我有一个8端口USB串行设备(来自VsCOM),它基于FTDI FT2232D芯片。当我从一个端口以特定设置进行传输,并使用硬件握手停止和启动另一端的数据流时,我会出现两个症状: 1) 输出数据有时会变成垃圾。将有NUL字符,几乎任何你能想到的随机事件 2) WriteFile调用有时返回的字节数大于我要求它写入的字节数。那不是打字错误。我请求传输30个字节,发送的字节数返回8192(是的,在我打电话之前,我确实清除了发送到0的字节数) 有关事实: 使用FTDI驱动程序2.8.24.0,这是今天最新的。 串行端口设置为19200,7个数据位,奇数奇偶校验,1个停止位。 我用另一个基于FTDI的串行设备得到了同样的行为,这次是单端口设备。 我得到同样的行为与另一个8端口设备的相同类型。 当在内置串行端口(COM1)上传输时,我没有这种行为。 我有一个非常简单的“Writer”程序,可以连续传输,还有一个非常简单的“Toggler”程序,可以每秒切换一次RTS。这些因素加在一起似乎能在60秒内引发问题。 我已经向设备制造商提出了一个问题,但他们还没有太多时间作出回应。 编译器是mingw32,Qt4.8.1(GCC4.4.0)的Qt安装程序附带的编译器 首先我想知道,是否有任何人能想到我能做什么来触发这种行为。我什么都想不出来,但总有一些事情我不知道 其次,我附加了Writer和Toggler测试程序。如果有人能发现一些可能触发该计划的问题,我很乐意听听。我很难想象有一个驱动程序错误(特别是来自像FTDI芯片这样成熟的东西),但这种情况迫使我认为至少有一些驱动程序参与。至少,不管我对它做什么,它返回的字节数不应该大于我要求它写入的字节数 编写程序:Windows 串行端口传输错误数据和写入文件返回错误写入字节数的原因?,windows,serial-port,usb,Windows,Serial Port,Usb,错误修复更新: 截至2013年6月,FTDI向我承认该漏洞是真实的。此后,他们发布了新版本的驱动程序(2.8.30.0,日期为2013年7月12日),解决了这个问题。该驱动程序于2013年8月1日左右通过WHQL发布,目前可通过Windows Update获得 我已经运行相同的测试代码进行了重新测试,但无法用新的驱动程序重现问题,因此目前的解决方案似乎是“升级驱动程序” 原问题: 我有一个8端口USB串行设备(来自VsCOM),它基于FTDI FT2232D芯片。当我从一个端口以特定设置进行传输
#include <iostream>
#include <string>
using std::cerr;
using std::endl;
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
cerr << "COM Writer, ctrl-c to end" << endl;
if (argc != 2) {
cerr << "Please specify a COM port for parameter 2";
return 1;
}
char fixedbuf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
std::string portName = "\\\\.\\";
portName += argv[1];
cerr << "Transmitting on port " << portName << endl;
HANDLE ph = CreateFileA( portName.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // overlapped I/O
NULL ); // hTemplate must be NULL for comm devices
if (ph == INVALID_HANDLE_VALUE) {
cerr << "CreateFile " << portName << " failed, error " << GetLastError() << endl;
return 1;
}
COMMCONFIG ccfg;
DWORD ccfgSize = sizeof(COMMCONFIG);
ccfg.dwSize = ccfgSize;
GetCommConfig(ph, &ccfg, &ccfgSize);
GetCommState(ph, &(ccfg.dcb));
ccfg.dcb.fBinary=TRUE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
ccfg.dcb.fAbortOnError=FALSE;
ccfg.dcb.fNull=FALSE;
// Camino is 19200 7-O-1
ccfg.dcb.BaudRate = 19200;
ccfg.dcb.Parity = ODDPARITY;
ccfg.dcb.fParity = TRUE;
ccfg.dcb.ByteSize = 7;
ccfg.dcb.StopBits = ONESTOPBIT;
// HW flow control
ccfg.dcb.fOutxCtsFlow=TRUE;
ccfg.dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
COMMTIMEOUTS ctimeout;
DWORD tout = 10;// 10 ms
ctimeout.ReadIntervalTimeout = tout;
ctimeout.ReadTotalTimeoutConstant = tout;
ctimeout.ReadTotalTimeoutMultiplier = 0;
ctimeout.WriteTotalTimeoutMultiplier = tout;
ctimeout.WriteTotalTimeoutConstant = 0;
SetCommConfig(ph, &ccfg, sizeof(COMMCONFIG));
SetCommTimeouts(ph, &ctimeout);
DWORD nwrite = 1;
for(;;) {
nwrite++;
if (nwrite > 30) nwrite = 1;
DWORD nwritten = 0;
if (!WriteFile(ph, fixedbuf, nwrite, &nwritten, NULL)) {
cerr << "f" << endl;
}
if ((nwritten != 0) && (nwritten != nwrite)) {
cerr << "nwrite: " << nwrite << " written: " << nwritten << endl;
}
}
return 0;
}
#include <iostream>
#include <string>
using std::cerr;
using std::endl;
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
cerr << "COM Toggler, ctrl-c to end" << endl;
cerr << "Flips the RTS line every second." << endl;
if (argc != 2) {
cerr << "Please specify a COM port for parameter 2";
return 1;
}
std::string portName = "\\\\.\\";
portName += argv[1];
cerr << "Toggling RTS on port " << portName << endl;
HANDLE ph = CreateFileA( portName.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // overlapped I/O
NULL ); // hTemplate must be NULL for comm devices
if (ph == INVALID_HANDLE_VALUE) {
cerr << "CreateFile " << portName << " failed, error " << GetLastError() << endl;
return 1;
}
COMMCONFIG ccfg;
DWORD ccfgSize = sizeof(COMMCONFIG);
ccfg.dwSize = ccfgSize;
GetCommConfig(ph, &ccfg, &ccfgSize);
GetCommState(ph, &(ccfg.dcb));
ccfg.dcb.fBinary=TRUE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
ccfg.dcb.fAbortOnError=FALSE;
ccfg.dcb.fNull=FALSE;
// Camino is 19200 7-O-1
ccfg.dcb.BaudRate = 19200;
ccfg.dcb.Parity = ODDPARITY;
ccfg.dcb.fParity = TRUE;
ccfg.dcb.ByteSize = 7;
ccfg.dcb.StopBits = ONESTOPBIT;
// no flow control (so we can do manually)
ccfg.dcb.fOutxCtsFlow=FALSE;
ccfg.dcb.fRtsControl=RTS_CONTROL_DISABLE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
COMMTIMEOUTS ctimeout;
DWORD tout = 10;// 10 ms
ctimeout.ReadIntervalTimeout = tout;
ctimeout.ReadTotalTimeoutConstant = tout;
ctimeout.ReadTotalTimeoutMultiplier = 0;
ctimeout.WriteTotalTimeoutMultiplier = tout;
ctimeout.WriteTotalTimeoutConstant = 0;
SetCommConfig(ph, &ccfg, sizeof(COMMCONFIG));
SetCommTimeouts(ph, &ctimeout);
bool rts = true;// true for set
for(;;) {
if (rts)
EscapeCommFunction(ph, SETRTS);
else
EscapeCommFunction(ph, CLRRTS);
rts = !rts;
Sleep(1000);// 1 sec wait.
}
return 0;
}
#包括
#包括
使用std::cerr;
使用std::endl;
#包括
#包括
int main(int argc,字符**argv)
{
cerr我还没有FTDI的好答案,但我有以下建议供任何处理此问题的人参考:
< P > 1)考虑切换到非FTDI USB串行转换器。这是我的公司所做的,但当然这不是每个人的选择(我们把芯片放在我们自己的产品中)。我们现在使用的是硅实验室芯片,但我认为还有另外一个或两个供应商。< /P>
2) 根据Hans Passant的评论-重新考虑RTS/CTS信令的使用。如果写操作没有因为阻塞而失败,那么您不应该触发此错误
3) 将所有写入设置为无限超时。同样,不会因阻塞而失败,不会触发错误。当然,这可能不适用于所有应用程序
请注意,如果执行策略#3,如果使用重叠IO进行写入,那么如果需要,可以使用和它的新表亲来消除写入。我还没有尝试过这样做,但我怀疑这样的取消也可能导致触发此错误。如果它们只在关闭端口时使用,那么您可能可以侥幸逃脱即使它们真的触发了这个bug,我也无法从FTDI那里得到一个好的答案,但我有以下建议供任何处理这个问题的人参考:
< P > 1)考虑切换到非FTDI USB串行转换器。这是我的公司所做的,但当然这不是每个人的选择(我们把芯片放在我们自己的产品中)。我们现在使用的是硅实验室芯片,但我认为还有另外一个或两个供应商。< /P>
2) 根据Hans Passant的评论-重新考虑RTS/CTS信令的使用。如果写操作没有因为阻塞而失败,那么您不应该触发此错误
3) 将所有写入设置为无限超时。同样,不会因阻塞而失败,不会触发错误。当然,这可能不适用于所有应用程序
请注意,如果执行策略#3,如果使用重叠IO进行写入,那么如果需要,可以使用和它的新表亲来消除写入。我还没有尝试过这样做,但我怀疑这样的取消也可能导致触发此错误。如果它们只在关闭端口时使用,那么您可能可以侥幸逃脱即使它们确实触发了该错误,也会被删除。如果其他人仍看到此情况,请将FTDI驱动程序更新到2.8.30.0或更高版本,因为这是由早期版本的FTDI驱动程序中的驱动程序错误引起的。如果其他人仍看到此情况,请将FTDI驱动程序更新到2.8.30.0或更高版本,因为这是由早期版本的FTDI驱动程序错误引起的。如果其他人仍看到此情况,请将FTDI驱动程序更新到2.8.30.0或更高版本f FTDI驱动程序。我对微芯片编程是出于一种爱好,发现其中一个带有板载串行端口的微芯片程序员无法使用usb-rs232电缆,因为usb端口产生的电压不符合真正的rs232规范。这可能不是你的问题,但这是众所周知的问题。特别是我的问题是bec因为这与握手有关——我相信从内存来看,这与USB读取/写入握手线路的速度太快/太慢有关