我一直在尝试与Arduino Nano(实际上是一个廉价的中文版本)建立通信。
板每秒发送3个字符,我只收到最后2个字符
我发现此文档引用了 MTTY 示例。我继续下去,找到了它作为例子。
我有兴趣了解阅读部分是如何完成的(在 READSTAT.C 中)
这部分让我困惑:
while ( !fThreadDone ) {
//
// If no reading is allowed, then set flag to
// make it look like a read is already outstanding.
//
if (NOREADING( TTYInfo ))
fWaitingOnRead = TRUE;
//
// if no read is outstanding, then issue another one
//
if (!fWaitingOnRead) {
if (!ReadFile(COMDEV(TTYInfo), lpBuf, AMOUNT_TO_READ, &dwRead, &osReader)) {
if (GetLastError() != ERROR_IO_PENDING) // read not delayed?
ErrorInComm("ReadFile in ReaderAndStatusProc");
fWaitingOnRead = TRUE;
}
else { // read completed immediately
if ((dwRead != MAX_READ_BUFFER) && SHOWTIMEOUTS(TTYInfo))
UpdateStatus("Read timed out immediately.\r\n");
if (dwRead)
OutputABuffer(hTTY, lpBuf, dwRead);
}
}
//
// If status flags have changed, then reset comm mask.
// This will cause a pending WaitCommEvent to complete
// and the resultant event flag will be NULL.
//
if (dwStoredFlags != EVENTFLAGS(TTYInfo)) {
dwStoredFlags = EVENTFLAGS(TTYInfo);
if (!SetCommMask(COMDEV(TTYInfo), dwStoredFlags))
ErrorReporter("SetCommMask");
}
//
// If event checks are not allowed, then make it look
// like an event check operation is outstanding
//
if (NOEVENTS(TTYInfo))
fWaitingOnStat = TRUE;
//
// if no status check is outstanding, then issue another one
//
if (!fWaitingOnStat) {
if (NOEVENTS(TTYInfo))
fWaitingOnStat = TRUE;
else {
if (!WaitCommEvent(COMDEV(TTYInfo), &dwCommEvent, &osStatus)) {
if (GetLastError() != ERROR_IO_PENDING) // Wait not delayed?
ErrorReporter("WaitCommEvent");
else
fWaitingOnStat = TRUE;
}
else
// WaitCommEvent returned immediately
ReportStatusEvent(dwCommEvent);
}
}
//
// wait for pending operations to complete
//
if ( fWaitingOnStat && fWaitingOnRead ) {
dwRes = WaitForMultipleObjects(NUM_READSTAT_HANDLES, hArray, FALSE, STATUS_CHECK_TIMEOUT);
switch(dwRes)
{
//
// read completed
//
case WAIT_OBJECT_0:
if (!GetOverlappedResult(COMDEV(TTYInfo), &osReader, &dwRead, FALSE)) {
if (GetLastError() == ERROR_OPERATION_ABORTED)
UpdateStatus("Read aborted\r\n");
else
ErrorInComm("GetOverlappedResult (in Reader)");
}
else { // read completed successfully
if ((dwRead != MAX_READ_BUFFER) && SHOWTIMEOUTS(TTYInfo))
UpdateStatus("Read timed out overlapped.\r\n");
if (dwRead)
OutputABuffer(hTTY, lpBuf, dwRead);
}
fWaitingOnRead = FALSE;
break;
//
// status completed
//
case WAIT_OBJECT_0 + 1:
if (!GetOverlappedResult(COMDEV(TTYInfo), &osStatus, &dwOvRes, FALSE)) {
if (GetLastError() == ERROR_OPERATION_ABORTED)
UpdateStatus("WaitCommEvent aborted\r\n");
else
ErrorInComm("GetOverlappedResult (in Reader)");
}
else // status check completed successfully
ReportStatusEvent(dwCommEvent);
fWaitingOnStat = FALSE;
break;
//
// status message event
//
case WAIT_OBJECT_0 + 2:
StatusMessage();
break;
//
// thread exit event
//
case WAIT_OBJECT_0 + 3:
fThreadDone = TRUE;
break;
case WAIT_TIMEOUT:
//
// timeouts are not reported because they happen too often
// OutputDebugString("Timeout in Reader & Status checking\n\r");
//
//
// if status checks are not allowed, then don't issue the
// modem status check nor the com stat check
//
if (!NOSTATUS(TTYInfo)) {
CheckModemStatus(FALSE); // take this opportunity to do
CheckComStat(FALSE); // a modem status check and
// a comm status check
}
break;
default:
ErrorReporter("WaitForMultipleObjects(Reader & Status handles)");
break;
}
}
}
我认为这段代码很可能会调用
ReadFile
而不调用WaitCommEvent
,这样继续下去是否正确?我也一直尝试:
WaitCommEvent
ReadFile
WaitForSingleObject
GetOverlappedResult
ReadFile
实际获取数据,但似乎没有必要我尝试使用这个例子而不调用
WaitCommEvent
,它有点工作,读取操作总是错过第一个字符。
我使用
GENERIC_WRITE
、GENERIC_READ
、OPEN_EXISTING
、FILE_FLAG_OVERLAPPED
打开端口,并使用 SetCommMask
标志适当地调用 EV_RXCHAR
。
DWORD WINAPI read(LPVOID param) {
CUSTOM_DATA* params = (CUSTOM_DATA*)param;
HANDLE hComm = params->hComm;
OVERLAPPED ov = { 0 };
bool waitingOnStat = FALSE;
int i = 1;
while (1) {
char* buffer = (char*)malloc(100 * sizeof(char));
ZeroMemory(buffer, 100);
DWORD bufferSize = 100;
DWORD nbRead;
DWORD evtMask;
DWORD res;
if (!waitingOnStat) {
ZeroMemory(&ov, sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!ReadFile(hComm, buffer, bufferSize, &nbRead, &ov)) {
if (GetLastError() != ERROR_IO_PENDING) {
printf("ERROR_IO NOT PENDING\n");
}
waitingOnStat = true;
}
else {
std::cout.write(buffer, nbRead) << std::endl;
waitingOnStat = FALSE;
}
}
if (waitingOnStat) {
printf("Waiting");
DWORD res = WaitForSingleObject(ov.hEvent, INFINITE);
switch (res) {
case WAIT_OBJECT_0:
waitingOnStat = FALSE;
DWORD nbBytesTransfered;
if (!GetOverlappedResult(hComm, &ov, &nbBytesTransfered, TRUE)) {
printf("error reading %d\n", GetLastError());
} else {
std::cout.write(buffer, nbRead);
}
break;
default:
printf("waiting read error %d\n", GetLastError());
break;
}
}
i++;
}
}
为什么
ReadFile
不断返回true?
需要打电话吗
WaitCommEvent
在@Ian Abbott 的帮助下,我摆弄了
COMMTIMEOUTS
的参数。
该文档指定了一些行为,例如:
如果应用程序将 ReadIntervalTimeout 和 ReadTotalTimeoutMultiplier 设置为 MAXDWORD 并将 ReadTotalTimeoutConstant 设置为大于零的值,并且 小于 MAXDWORD,当 ReadFile 函数为 称为: 如果输入缓冲区中有任何字节,ReadFile 立即返回 缓冲区中的字节。 如果输入缓冲区中没有字节,则 ReadFile 会等待直到有字节 到达然后立即返回。 如果在 ReadTotalTimeoutConstant 指定的时间内没有字节到达, 读取文件超时。
问题在于我的代码:
GetOverlappedResult
然后忽略 nbBytesRead
参数(因为我读过使用 OVERLAPPED IO
采取以下措施似乎解决了我的问题:
在拨打
nbBytesTransfered
后的时间使用GetOverlappedResu
。虽然如果我将超时设置为:
timeouts.ReadIntervalTimeout = 4294967295;
超时.ReadTotalTimeoutConstant = 4294967294;
超时.ReadTotalTimeoutMultiplier = 4294967295;
对于最终由ReadFile
显示的第一个字符,
FALSE
将返回 GetOverlappedCall
,然后 ReadFile
将返回 TRUE
并显示其余字符(我还没有高速测试过) ).
如果我将超时设置如下:
ReadFile
不返回 TRUE
并且 GetOverlappedResult
读取所有字符(我还没有高速测试过)。