windows - Com 端口上的 WriteFile 指示 Tx 完成,但没有数据传输
问题描述
我在 MFC 项目中使用 VS 2013 Professional
使用我的软件从com口接收数据有一段时间了,最近需要添加传输能力初始化代码是:
BOOL PASCAL FAR SetupConnect(pCONNECTION pCon, pCOMCONFIG pCfg) { DCB dcb;
pSERBUF pSB = pCon->BufStruct;
// pSERBUF *ppSB = (pSERBUF*)pCon->BufStruct;
// pSB = *ppSB;
dcb.DCBlength = sizeof(DCB);
CheckComs(); // Gets available COM ports
pCon->Port = pNames[0].PortNames[3] - 0x30;
if (pCon->BufStruct == NULL) // This is a personal Communications structure
{ // Init
pCon->hSB = GlobalAlloc(GHND, sizeof(SERBUF));
if (pCon->hSB == NULL)
{
// return INVALID_HANDLE_VALUE;
return 0;
}
pSB = (pSERBUF)GlobalLock(pCon->hSB);
pSB->idComDev = INVALID_HANDLE_VALUE;
pCon->BufStruct = pSB;
}
else return (0);
if (pSB->idComDev == INVALID_HANDLE_VALUE)
{
pSB->idComDev = CreateFile(pNames[0].PortNames, GENERIC_READ | GENERIC_WRITE,
0, //exclusive access
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
}
// Current configuration
GetCommState(pSB->idComDev, &dcb);
// Setup baudrate, parity, etc.
dcb.BaudRate = pCfg->dwBaudRate;
dcb.ByteSize = pCfg->bDataBits;
dcb.Parity = pCfg->bParity;
dcb.StopBits = pCfg->bStopBits;
// Setup Flow Control
dcb.fOutxDsrFlow = pCfg->handshake_DTR;
dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR high while port open
dcb.fOutxCtsFlow = pCfg->handshake_RTS;
dcb.fRtsControl = RTS_CONTROL_DISABLE; // Toggle RTS with EscapeCommFunction
// XON/XOFF Not Used
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
//return TRUE if everything looks cool
return (SetCommState(pSB->idComDev, &dcb));
}
和:
CSerCom::CSerCom() { pCon = &Con; pCfg = &Cfg; m_SerHwnd = 这个;pCfg->dwBaudRate = 115200;pCfg->bDataBits = 8;pCfg->bParity = NOPARITY;pCfg->bStopBits = TWOSTOPBITS;// 这里
SetupConnect(pCon, pCfg);
pSERBUF pSB = pCon->BufStruct; // pSB is set in SetUpConnect
if (pSB->idComDev == INVALID_HANDLE_VALUE)
{
// device open failure
// hardware not there or someone else controls it!
GlobalUnlock(pCon->hSB);
GlobalFree(pCon->hSB);
pCon->BufStruct = NULL;
// TODO stop this from going any further
HandleFailure();
}
else // Only continue if Port is available
{
// Clear Buffer
SetupComm(pSB->idComDev, 4096, 4096);
PurgeComm(pSB->idComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
// create the overlapped events
memset(&(pSB->osRead), 0, sizeof(OVERLAPPED));
memset(&(pSB->osWrite), 0, sizeof(OVERLAPPED));
pSB->osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pSB->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if ((pSB->osRead.hEvent == NULL) || (pSB->osWrite.hEvent == NULL))
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
// allocate & lock the mem
// (used to contain data points to & from the MODBUS
// as well as the receive buffer for incoming serial data)
pSB->hRcv = GlobalAlloc(GHND, MAX_RX_LEN);
if (pSB->hRcv == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
pSB->pRcv = (char *)GlobalLock(pSB->hRcv);
pSB->hTx = (char *)GlobalAlloc(GHND, MAX_TX_LEN);
if (pSB->hTx == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
pSB->pTx = (char *)GlobalLock(pSB->hTx);
// remember the setup params
pSB->TimeOut = 3; //CalculateTimeOut(pCfg->dwBaudRate);
// pSB->TimerId = TimerId;
// initialize the status counters
// pSB->ValidCt = 0;
// pSB->InvalidCt = 0;
pSB->RxInIdx = 0;
// pSB->RTS_Delay[0] = pCfg->RTS_Delay[0];
// pSB->RTS_Delay[1] = pCfg->RTS_Delay[1];
pSB->RTS_Delay[0] = 100;
pSB->RTS_Delay[1] = 100;
// setup the Comm Timeouts
CommTimeOuts.ReadIntervalTimeout = 0xffffffff;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 1000;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts(pSB->idComDev, &CommTimeOuts);
// if everything looks good to here
// create the Receive Thread & return the CONNECT handle
pSB->hIOThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)SerProc,
(LPVOID)pCon,
0,
&dwThreadID);
if (pSB->hIOThread == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
hIOT = pSB->hIOThread;
}
}
因此,通过该设置,我进入了一个线程循环,其中有以下内容
// wait indefinitely for somthing to happen
WaitCommEvent(pSB->idComDev, &dwEvtMask, NULL);
// Catch Rx event
if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
{
Edit1_txt.Format(_T("Rx'd"));
E1->SetWindowText(Edit1_txt);
CMFCView->UpdateWindow();
// only try to read number of bytes in queue
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
dwLength = ComStat.cbInQue;
// Read data bytes into connection Rcv Buffer at current RxInIdx
if (dwLength > 0)
{
fReadStat = ReadFile(pSB->idComDev,
&(pSB->pRcv[pSB->RxInIdx]),
dwLength,
&bytesread,
&(pSB->osRead));
if (!fReadStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
// We have to wait for read to complete.
while (!GetOverlappedResult(pSB->idComDev,
&(pSB->osRead), &bytesread, FALSE))
{
dwErrorFlags = GetLastError();
if (dwErrorFlags != ERROR_IO_INCOMPLETE)
// an error occurred, try to recover
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
}
else
{
// some other error occurred
dwLength = 0;
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
} // End of Read Error
} // End of Read Char
if (ComStat.cbInQue < 500)
{
// update the receive index
pSB->RxInIdx += dwLength;
wSleepime = GetTickCount(); // hkk 7/16/99 for console app
ParseAPI(pSB);
}
else
ComStat.cbInQue = 0;
}
// At some point in the program pSB->TxOutIdx is set to some positive value
if (pSB->TxOutIdx > 0)
{
dwLength = pSB->TxOutIdx;
fWriteStat = WriteFile(pSB->idComDev,
&(pSB->pTx[pSB->TxOutIdx]),
dwLength,
&byteswritten,
&(pSB->osWrite));
if (!fWriteStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
while (!GetOverlappedResult(pSB->idComDev,
&(pSB->osWrite), &byteswritten, FALSE))
{
dwErrorFlags = GetLastError();
if (dwErrorFlags != ERROR_IO_INCOMPLETE)
// an error occurred, try to recover
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
}
pSB->TxOutIdx -= byteswritten;
}
}
}
这会检测到 Tx 缓冲区已满 (pSB->TxOutIdx > 0) 并发送数据
传输因 IO 挂起错误而失败,但在执行 GetOverlappedResult 后,写入的字节显示所需的长度。
但是,没有数据输出端口。我检查了,发现和使用的端口是正确的。
废话?
解决方案
推荐阅读
- linux - 将 bash 输出重定向到 bash 脚本中的文件
- android - 多插入符号android studio快捷方式
- asp.net-core - 在 ASP.NET Core Identity 中,什么是票证?
- r - R遍历光栅对象对象
- emacs - 从 elisp 调用 Emacs 的 Eshell 的 eshell-previous-matching-input-from-input
- python - APScheduler 随机关闭
- php - 感染引发异常,但为什么以及如何处理呢?
- flutter - List.map() 中的递增计数
- javascript - JS计算器不输出也不运行函数
- kotlin - 在 Kotlin 中将十六进制的十进制表示转换为 unicode 字符