EDN Admin
Well-known member
Hi,
I want to read data from serial port. The packet are variable size (12 to 1024 bytes). Before we poll data byte to byte, but it seems too much to use CPU and I think it is not very effective.<br/>
<br/>
Here is what I have so far in my Server RX Thread:<br/>
<pre class="prettyprint // Main thread loop
DWORD dwErrors = NO_ERROR;
DWORD dwNumberOfReceiving = 0;
BYTE arbChars[8] = {0};
DWORD dwWaitTimeout = 0;
BOOL bSuccess = TRUE;
BOOL bLastCharWasDLE = FALSE;
BOOL bStartOfFrameDetected = TRUE;
COMSTAT comStat;
OVERLAPPED ovInternal = {0};
ovInternal.hEvent = m_hComReceiveOverlappedEvent;
BOOL bNeedWaitingOnStatusHandle = FALSE;
HANDLE hWaitKillEventAndOverlappedEvent[2] = {m_hEventKill, m_hComReceiveOverlappedEvent};
while (WaitForSingleObject(m_hEventKill, dwWaitTimeout) != WAIT_OBJECT_0)
{
// Initiate a read operation
bSuccess = ReadFile(m_hCom, &arbChars, TOOL_MEMORY_COUNT_OF(arbChars), &dwNumberOfReceiving, &ovInternal);
if (bSuccess == FALSE)
{
// Test for error
dwErrors = GetLastError();
if (dwErrors == ERROR_IO_PENDING)
{
// Operation delayed...
bNeedWaitingOnStatusHandle = TRUE;
}
else
{
// Error in ReadFile
dwWaitTimeout = 20;
continue;
}
}
else
{
// No need to wait on the overlapped handle, data is ready
bNeedWaitingOnStatusHandle = FALSE;
}
// Test if we need to wait on the overlapped handle
if (bNeedWaitingOnStatusHandle == TRUE)
{
// Wait for the thread kill event at index 0
// Wait for the read event of the serial com at index 1
switch (WaitForMultipleObjects(TOOL_MEMORY_COUNT_OF(hWaitKillEventAndOverlappedEvent), hWaitKillEventAndOverlappedEvent, FALSE, INFINITE))
{
// Kill event occurred
case WAIT_OBJECT_0:
{
// Can IO operation
CancelIo(m_hCom);
continue;
// Thread will be shutdown...
}
break;
// Overlapped event occurred
case WAIT_OBJECT_0 + 1:
{
// Get read overlapped result
if (GetOverlappedResult(m_hCom, &ovInternal, &dwNumberOfReceiving, TRUE) == FALSE)
{
// An error occurred in the overlapped operation...
dwWaitTimeout = 20;
continue;
}
else
{
// Data has been properly received
}
}
break;
default:
{
// Unknown error in the WaitForSingleObject
dwWaitTimeout = 20;
continue;
}
}
}
// No error, then no delay to add on the Wait for KillEvent
dwWaitTimeout = 0;
// Is there any char read on the serial COM
if (dwNumberOfReceiving <= 0)
{
continue;
}
// Handle read serial data
handleSerialRead(arbChars, dwNumberOfReceiving);
}
// Return result
return 0;
}[/code]
Now, this is well working in general. However, if the serial COM client send a packet of
12 bytes using multiple WriteFile , then heres what happens in the server RX thread.<br/>
<br/>
1 - [Server Thread RX] - First a ReadFile is initiated<br/>
<br/>
2 - [Server Thread RX] - I get a ERROR_IO_PENDING error, so it calling WaitForMultipleObject where he get stuck until an event occured...<br/>
<br/>
3 - [Client] - Send a packet having a size of <span style="text-decoration:underline 12 bytes using multiple WriteFile.
Im presuming that server will start reading before client finished sending the whole packet. <br/>
<br/>
4 - [Server Thread RX] - Unblock from the WaitForMultipleObject and return WAIT_OBJECT_0 + 1. This mean that something happen on the the Read operation.<br/>
<br/>
5 - [Server Thread RX] - GetOverlappedResult is called and it returns
TRUE , with 8 bytes ready to read . Now I process those 8 bytes.<br/>
<br/>
6 - [Server Thread RX] - Another call to ReadFile is done, getting ERROR_IO_PENDING but after that Im stuck forever in the
WaitForMultipleObject . Yet other 2 bytes are available !!!<br/>
<br/>
The reason why Im stuck in the WaitForMultipleObjects is probably because Im asking for
8 bytes in the ReadFile but there only 2 bytes ready in the COM. It is ?<br/>
<br/>
<span class="x_x_x_x_t-marker Now, what to do to get thoses 2 bytes remaining ???<br/>
<br/>
Ive play a little with the CommTimeOut
<pre class="prettyprint COMMTIMEOUTS commTimeOuts;
commTimeOuts.ReadIntervalTimeout = 0;
commTimeOuts.ReadTotalTimeoutConstant = 100;
commTimeOuts.ReadTotalTimeoutMultiplier = 1 + (8 / m_dwBaudRate);
commTimeOuts.ReadTotalTimeoutConstant = 0;
commTimeOuts.ReadTotalTimeoutMultiplier = 0;
commTimeOuts.WriteTotalTimeoutConstant = 0;
commTimeOuts.WriteTotalTimeoutMultiplier = 0;[/code]
presuming that after 100 milliseconds plus the multiplier I should get *<span style="text-decoration:underline unstuck* <span style="text-decoration: from the WaitForMultipleObjects, but
NO !<br/>
<br/>
Another idea was to set a timeout value in the WaitForMultipleObjects instead of using
INFINITE . But after that I will get a WAIT_TIMEOUT result and what can I do to get the
<span style="text-decoration:underline 2 remaining bytes<span style="text-decoration: if I cannot read it by anyway ?<br/>
<br/>
Im really out of idea on that. I hope someone will help me because its been three days that Im wasting my time on this problem
<br/>
<br/>
Best regards,<br/>
Martin<br/>
<br/>
<br/>
<br/>
View the full article
I want to read data from serial port. The packet are variable size (12 to 1024 bytes). Before we poll data byte to byte, but it seems too much to use CPU and I think it is not very effective.<br/>
<br/>
Here is what I have so far in my Server RX Thread:<br/>
<pre class="prettyprint // Main thread loop
DWORD dwErrors = NO_ERROR;
DWORD dwNumberOfReceiving = 0;
BYTE arbChars[8] = {0};
DWORD dwWaitTimeout = 0;
BOOL bSuccess = TRUE;
BOOL bLastCharWasDLE = FALSE;
BOOL bStartOfFrameDetected = TRUE;
COMSTAT comStat;
OVERLAPPED ovInternal = {0};
ovInternal.hEvent = m_hComReceiveOverlappedEvent;
BOOL bNeedWaitingOnStatusHandle = FALSE;
HANDLE hWaitKillEventAndOverlappedEvent[2] = {m_hEventKill, m_hComReceiveOverlappedEvent};
while (WaitForSingleObject(m_hEventKill, dwWaitTimeout) != WAIT_OBJECT_0)
{
// Initiate a read operation
bSuccess = ReadFile(m_hCom, &arbChars, TOOL_MEMORY_COUNT_OF(arbChars), &dwNumberOfReceiving, &ovInternal);
if (bSuccess == FALSE)
{
// Test for error
dwErrors = GetLastError();
if (dwErrors == ERROR_IO_PENDING)
{
// Operation delayed...
bNeedWaitingOnStatusHandle = TRUE;
}
else
{
// Error in ReadFile
dwWaitTimeout = 20;
continue;
}
}
else
{
// No need to wait on the overlapped handle, data is ready
bNeedWaitingOnStatusHandle = FALSE;
}
// Test if we need to wait on the overlapped handle
if (bNeedWaitingOnStatusHandle == TRUE)
{
// Wait for the thread kill event at index 0
// Wait for the read event of the serial com at index 1
switch (WaitForMultipleObjects(TOOL_MEMORY_COUNT_OF(hWaitKillEventAndOverlappedEvent), hWaitKillEventAndOverlappedEvent, FALSE, INFINITE))
{
// Kill event occurred
case WAIT_OBJECT_0:
{
// Can IO operation
CancelIo(m_hCom);
continue;
// Thread will be shutdown...
}
break;
// Overlapped event occurred
case WAIT_OBJECT_0 + 1:
{
// Get read overlapped result
if (GetOverlappedResult(m_hCom, &ovInternal, &dwNumberOfReceiving, TRUE) == FALSE)
{
// An error occurred in the overlapped operation...
dwWaitTimeout = 20;
continue;
}
else
{
// Data has been properly received
}
}
break;
default:
{
// Unknown error in the WaitForSingleObject
dwWaitTimeout = 20;
continue;
}
}
}
// No error, then no delay to add on the Wait for KillEvent
dwWaitTimeout = 0;
// Is there any char read on the serial COM
if (dwNumberOfReceiving <= 0)
{
continue;
}
// Handle read serial data
handleSerialRead(arbChars, dwNumberOfReceiving);
}
// Return result
return 0;
}[/code]
Now, this is well working in general. However, if the serial COM client send a packet of
12 bytes using multiple WriteFile , then heres what happens in the server RX thread.<br/>
<br/>
1 - [Server Thread RX] - First a ReadFile is initiated<br/>
<br/>
2 - [Server Thread RX] - I get a ERROR_IO_PENDING error, so it calling WaitForMultipleObject where he get stuck until an event occured...<br/>
<br/>
3 - [Client] - Send a packet having a size of <span style="text-decoration:underline 12 bytes using multiple WriteFile.
Im presuming that server will start reading before client finished sending the whole packet. <br/>
<br/>
4 - [Server Thread RX] - Unblock from the WaitForMultipleObject and return WAIT_OBJECT_0 + 1. This mean that something happen on the the Read operation.<br/>
<br/>
5 - [Server Thread RX] - GetOverlappedResult is called and it returns
TRUE , with 8 bytes ready to read . Now I process those 8 bytes.<br/>
<br/>
6 - [Server Thread RX] - Another call to ReadFile is done, getting ERROR_IO_PENDING but after that Im stuck forever in the
WaitForMultipleObject . Yet other 2 bytes are available !!!<br/>
<br/>
The reason why Im stuck in the WaitForMultipleObjects is probably because Im asking for
8 bytes in the ReadFile but there only 2 bytes ready in the COM. It is ?<br/>
<br/>
<span class="x_x_x_x_t-marker Now, what to do to get thoses 2 bytes remaining ???<br/>
<br/>
Ive play a little with the CommTimeOut
<pre class="prettyprint COMMTIMEOUTS commTimeOuts;
commTimeOuts.ReadIntervalTimeout = 0;
commTimeOuts.ReadTotalTimeoutConstant = 100;
commTimeOuts.ReadTotalTimeoutMultiplier = 1 + (8 / m_dwBaudRate);
commTimeOuts.ReadTotalTimeoutConstant = 0;
commTimeOuts.ReadTotalTimeoutMultiplier = 0;
commTimeOuts.WriteTotalTimeoutConstant = 0;
commTimeOuts.WriteTotalTimeoutMultiplier = 0;[/code]
presuming that after 100 milliseconds plus the multiplier I should get *<span style="text-decoration:underline unstuck* <span style="text-decoration: from the WaitForMultipleObjects, but
NO !<br/>
<br/>
Another idea was to set a timeout value in the WaitForMultipleObjects instead of using
INFINITE . But after that I will get a WAIT_TIMEOUT result and what can I do to get the
<span style="text-decoration:underline 2 remaining bytes<span style="text-decoration: if I cannot read it by anyway ?<br/>
<br/>
Im really out of idea on that. I hope someone will help me because its been three days that Im wasting my time on this problem

<br/>
Best regards,<br/>
Martin<br/>
<br/>
<br/>
<br/>
View the full article