How can I check whether the input buffer is empty? - c++

I'm trying to write a simple class for operating a Serial Port on Windows, using standart windows library .
I need to check whether the input buffer is empty.
So far I've tried to use SetCommEvent, using EV_RXCHAR option, however this method doesn't work. The function seems to wait for arrival of new char. If I tried to send char, sleep for a second and the apply this, the function would not return - it keeps waiting.
bool isEmpty()
{
DWORD dwEventMask = 0;
DWORD Status = 0;
if (CheckAsyncRead())
return false;
if (!SetCommMask(hPort, EV_RXCHAR)) //wait for char receival
std::cout << "Error in creating Overlapped event" << std::endl;
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (WaitCommEvent(hPort, &dwEventMask, &osReader))
{
//close event handle
return false;
}
Status = WaitForSingleObject(osReader.hEvent, 10);
//I wait for 10 ms in case the function doesn't return immediately
//Close event handle
if (Status == WAIT_OBJECT_0)
{
return false;
}
else
return true;
}
I hoped the WaitCommEvent or WaitForSingleObject would return in case any chars were present in buffer but the does not happen if there is a longer pause between receival of a character and calling of Wait function.

You can use the ClearCommError function to find out the size of the data stored in the buffer.
As a result of calling, cbInQue of the COMSTAT structure to be notified has the size of the data stored in the input buffer.

You can use ReadFile() with a handle opened with CreateFile() with the FILE_FLAG_OVERLAPPED flag. If the ReadFile() function has nothing to return, it will return a last error ERROR_IO_PENDING which means that your buffer is currently empty.

Related

Serial WriteFile returns before completion

I've been working on a program which dialog with an external device via a serial RS422 bus. The goal is to send commands to the device, which send an answer back.
So far, the code for sending a message look like this:
OVERLAPPED osWrite = {0};
void init()
{
// Create this write operation's OVERLAPPED structure's hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
// error creating overlapped event handle
std::cout << "Error osWrite.hEvent" << std::endl; // Error in communications; report it.
*hPort = CreateFile("\\\\.\\COM18", (GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (*hPort == INVALID_HANDLE_VALUE) {
std::cout << "Invalid port com handle" << GetLastError() << std::endl;
return;
}
COMMTIMEOUTS commTimeout;
if (GetCommTimeouts(*hPort, &commTimeout)) {
commTimeout.ReadIntervalTimeout = 10;
commTimeout.ReadTotalTimeoutConstant = 10;
commTimeout.ReadTotalTimeoutMultiplier = 10;
commTimeout.WriteTotalTimeoutConstant = 10;
commTimeout.WriteTotalTimeoutMultiplier = 10;
} else
return;
if (!SetCommTimeouts(*hPort, &commTimeout)) {
std::cout << "Error comm timeout" << std::endl;
}
DCB dcb;
if (!GetCommState(*hPort, &dcb)) {
std::cout << "Invalid port com settings" << std::endl;
return;
}
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommMask(*hPort, EV_RXCHAR);
SetCommState(*hPort, &dcb);
return;
}
DWORD serial_send(HANDLE *hPort, char *msg, int length) {
DWORD dwWritten;
DWORD dwRes;
BOOL fRes;
PurgeComm(*hPort, PURGE_TXCLEAR);
ResetEvent(osWrite.hEvent);
// Issue write.
if (!WriteFile(*hPort, msg, length, &dwWritten, &osWrite)) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
fRes = FALSE;
} else {
fRes = FALSE;
while (!fRes) {
// Write is pending.
dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
switch (dwRes) {
// OVERLAPPED structure's event has been signaled.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(*hPort, &osWrite, &dwWritten, FALSE))
fRes = FALSE;
else
// Write operation completed successfully.
fRes = TRUE;
break;
default:
// An error has occurred in WaitForSingleObject.
// This usually indicates a problem with the
// OVERLAPPED structure's event handle.
fRes = FALSE;
break;
}
}
}
} else {
// WriteFile completed immediately.
fRes = TRUE;
}
return dwWritten;
}
The last function can't return until the write operation is successful. The init() function load without error.
I've used a lot of code from here : https://learn.microsoft.com/en-us/previous-versions/ff802693(v=msdn.10)
Each message is 210 bytes long, and the serial port is running at 115200 bit/s, meaning that I should send a message every ~18.2ms. (210 bytes * 10 bits / 115200)
However, when I measure the time elapsed between 2 messages, I sometimes get a duration much inferior than the expected 18ms (it can go down to 11ms).
Is this a normal behavior for an asynchronous WriteFile + WaitForSingleObject?
What happens if I send another message just after 11ms, will it corrupt the previous message, or does it gets buffered?
I used std::chrono::high_resolution_clock::now() and std::chrono::duration<double, std::milli>(end - start).count() to get the duration of the frame, is it really accurate?
Since Windows is not a real-time OS and is a multi-process & multi-thread OS, time accuracy should not be guaranteed.
If the system is lightly loaded, most of it will work as intended, but not always.
Conversely, the completion of WriteFile() may be notified earlier than it actually is, depending on the hardware and device driver stack configuration.
For example, it may be considered that the process is completed at the time when the data is completely stored in the buffer of the device driver or when the last data is written to the FIFO buffer of the interface chip.
It is better to think that WriteFile() may be completed even if not all the data actually reaches the other party.
It is considered the same as writing file data to the hard disk. Completion of writing to a file on disk is done in the system buffer, and should be written to the actual media at a different time.
If the next serial_send() function is called before all the WriteFile data of the previous time has reached the other party due to bad conditions, there is a possibility that some of the previous transmission data will be discarded.
Because PurgeComm(*hPort, PURGE_TXCLEAR); is called at the beginning of the serial_send() function.
It's not as critical as specifying PURGE_TXABORT, but there is still the possibility of data being discarded with PURGE_TXCLEAR.
PurgeComm function
PURGE_TXABORT 0x0001 Terminates all outstanding overlapped write operations and returns immediately, even if the write operations have not been completed.
PURGE_TXCLEAR 0x0004 Clears the output buffer (if the device driver has one).
If a thread uses PurgeComm to flush an output buffer, the deleted characters are not transmitted. To empty the output buffer while ensuring that the contents are transmitted, call the FlushFileBuffers function (a synchronous operation).
The workaround is to simply not call PurgeComm().
If it is a serial port API, it may be possible to wait for the completion of transmission by specifying/detecting EV_TXEMPTY with SetCommMask()/WaitCommEvent(), but this will only be complicated.
SetCommMask function / WaitCommEvent function
EV_TXEMPTY 0x0004 The last character in the output buffer was sent.
Then your usage of WriteFile() + WaitForSingleObject() + GetOverlappedResult() will eventually work similar to calling WriteFile() synchronously.
Asynchronous operation is not always necessary, but it is better to consider in detail based on what kind of behavior your system requires.

How should I read the filename in FILE_NOTIFY_INFORMATION struct

I'm trying to monitor file changes but I am not really sure on how to read the filename in the FILE_NOTIFY_INFORMATION struct:
HANDLE dwChangeHandles[2];
DWORD dwWaitStatus;
wChangeHandles[0] = FindFirstChangeNotification(dirname.c_str(), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE) printerr(__FILE__,__LINE__,"FindFirstChangeNotification function failed.\n");
...
if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL)) //final validation
printerr(__FILE__,__LINE__,"Unexpected NULL from FindFirstChangeNotification.\n");
while (TRUE) {
std::cout << "Waiting for notification...\n";
dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles, FALSE, INFINITE);
if(dwWaitStatus==WAIT_OBJECT_0){
std::cout << "Something changed\n";
DWORD BytesReturned;
size_t bufLen = 1024;
FILE_NOTIFY_INFORMATION buffer[bufLen];
if (ReadDirectoryChangesW(dwChangeHandles[0], buffer, bufLen, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &BytesReturned, NULL, NULL)){
std::wcout << std::wstring(buffer->FileName)<< std::endl; //THERE IS NOTHING IN THE EXPECTED OUTPUT HERE
}
if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE ) printerr(__FILE__,__LINE__,"FindNextChangeNotification function failed.\n");
}
else if(dwWaitStatus==WAIT_TIMEOUT) printerr(__FILE__,__LINE__,"No changes in the timeout period.\n");
else printerr(__FILE__,__LINE__,"Unhandled dwWaitStatus.\n");
}
Is there something I am doing wrong
You have a number of problems that I can see immediately:
According to the docs for the ReadDirectoryChangesW function, the buffer needs to be DWORD-aligned. As you are using a buffer on the stack this isn't guaranteed - you should allocate one from the heap instead.
You don't seem to be using the function correctly. Normally you would call ReadDirectoryChangesW first, and then wait on the event. Not the other way around. When ReadDirectoryChangesW returns for an asynchronous call there is usually no data in the buffer at that point. You need to wait for notification that the request has been completed before using the buffer contents.
FindNextChangeNotification is only used with FindFirstChangeNotification, so this is completely wrong. When the ReadDirectoryChangesW completes you need to use the NextEntryOffset field in the FILE_NOTIFY_INFORMATION structure to loop through the returned events.
Edit: Since you've added more code to your question it's now obvious that you are mixing the two APIs. FindFirstChangeNotification and FindNextChangeNotification are one API, and ReadDirectoryChangesW is another. I believe you've been confused by this passage in the docs:
This function does not indicate the change that satisfied the wait
condition. To retrieve information about the specific change as part
of the notification, use the ReadDirectoryChangesW function.
I guess your confusion is understandable, but the two APIs can't be used together. If you're using FindFirstChangeNotification then all you get is a notification that something changed, and you have to re-read the directory to find out what it was. If you want specific notifications at the file level then you have to use ReadDirectoryChangesW to do the monitoring.

WaitCommEvent Hangs

I am using non overlapped WaitCommEvent to read the file data.
I would like to provide a piece of code as follows...
SetCommMask (io_ptr->comPortHandles->hComPort, EV_RXCHAR|EV_TXEMPTY);
WaitCommEvent (io_ptr->comPortHandles->hComPort, &dwMask, 0);
if (dwMask &= EV_RXCHAR) {
// Loop getting data.
// Need to loop because our buffer is only 1024 bytes
while (TRUE)
{
ClearCommError( io_ptr->comPortHandles->hComPort, &dwError, &comstat);
if (!comstat.cbInQue) continue;
else
{
if(comstat.cbInQue > 0)
ReceiveInterrupt(io_ptr, comstat);
}
// Loop around and check for more data
// In case additional byte has arrived while reading.
}
}
WaitCommEvent is blocking if the file handle was not open with overlapped flag.In you case it will wait until either a char received or last char has been sent.
MSDN about WaitCommEvent:
If hFile was not opened with FILE_FLAG_OVERLAPPED, WaitCommEvent does not return until one of the specified events or an error occurs.

How to check if WriteFile function is done

I want to check if the WriteFile function is done writing to UART so that i can call ReadFile on the same ComDev without causing an Exception.
It seems the WriteFile function can return before writing is done.
BOOL WriteCommBlock(HANDLE * pComDev, char *pBuffer , int BytesToWrite)
{
while(fComPortInUse){}
fComPortInUse = 1;
BOOL bWriteStat = 0;
DWORD BytesWritten = 0;
COMSTAT ComStat = {0};
OVERLAPPED osWrite = {0,0,0};
if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{
short Errorcode = GetLastError();
if( Errorcode != ERROR_IO_PENDING )
short breakpoint = 5; // Error
Sleep(1000); // complete write operation TBD
fComPortInUse = 0;
return (FALSE);
}
fComPortInUse = 0;
return (TRUE);
}
I used Sleep(1000) as an workaround, but how can i wait for an appropriate time?
You can create a Event, store it in your overlapped structure and wait for it to be signalled. Like this (untested):
BOOL WriteCommBlock(HANDLE * pComDev, char *pBuffer , int BytesToWrite)
{
while(fComPortInUse){}
fComPortInUse = 1;
BOOL bWriteStat = 0;
DWORD BytesWritten = 0;
COMSTAT ComStat = {0};
OVERLAPPED osWrite = {0,0,0};
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hEvent != NULL)
{
osWrite.hEvent = hEvent;
if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{
short Errorcode = GetLastError();
if( Errorcode != ERROR_IO_PENDING )
short breakpoint = 5; // Error
WaitForSingleObject(hEvent, INFINITE);
fComPortInUse = 0;
return (FALSE);
}
CloseHandle(hEvent);
}
fComPortInUse = 0;
return (TRUE);
}
Note that depending on what else you are trying to do simply calling WaitForSingleObject() might not be the best idea. And neither might an INFINITE timeout.
Your problem is the incorrect use of the overlapped I/O, regardless to the UART or whatever underlying device.
The easiest (though not necessarily the most optimal) way to fix your code is to use an event to handle the I/O completion.
// ...
OVERLAPPED osWrite = {0,0,0};
osWrite.hEvent = CreateEvent(FALSE, NULL, NULL, FALSE);
if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{
DWORD Errorcode = GetLastError();
// ensure it's ERROR_IO_PENDING
WaitForSingleObject(osWrite.hEvent, INFINITE);
}
CloseHandle(osWrite.hEvent);
Note however that the whole I/O is synchronous. It's handles by the OS in an asynchronous way, however your code doesn't go on until it's finished. If so, why do you use the overlapped I/O anyway?
One should use it to enable simultaneous processing of several I/Os (and other tasks) within the same thread. To do this correctly - you should allocate the OVERLAPPED structure on heap and use one of the available completion mechanisms: event, APC, completion port or etc. Your program flow logic should also be changed.
Since you didn't say that you need asynchronous I/O, you should try synchronous. It's easier. I think if you just pass a null pointer for the OVERLAPPED arg you get synchronous, blocking, I/O. Please see the example code I wrote in the "Windows C" section of this document:
http://www.pololu.com/docs/0J40/
Your Sleep(1000); is of no use, it will only execute after the writefile completes its operation.You have to wait till WriteFile is over.
if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{}
You must be knowing that anything inside conditionals will only execute if the result is true.
And here the result is sent to the program after completion(whether complete or with error) of WriteFile routine.
OK, I missed the overlapped I/O OVL parameter in the read/write code, so It's just as well I only replied yesterday as a comment else I would be hammered with downvotes:(
The classic way of handling overlapped I/O is to have an _OVL struct as a data member of the buffer class that is issued in the overlapped read/write call. This makes it easy to have read and write calls loaded in at the same time, (or indeed, multiple read/write calls with separate buffer instances).
For COM posrts, I usually use an APC completion routine whose address is passed in the readFileEx/writeFileEx APIs. This leaves the hEvent field of the _OVL free to use to hold the instance pointer of the buffer so it's easy to cast it back inside the completion routine, (this means that each buffer class instance contains an _OVL memebr that contains an hEvent field that points to the buffer class instance - sounds a but weird, but works fine).

COM port read - Thread remains alive after timeout occurs

I have a dll which includes a function called ReadPort that reads data from serial COM port, written in c/c++. This function is called within an extra thread from another WINAPI function using the _beginthreadex. When COM port has data to be read, the worker thread returns the data, ends normaly, the calling thread closes the worker's thread handle and the dll works fine.
However, if ReadPort is called without data pending on the COM port, when timeout occurs then WaitForSingleObject returns WAIT_TIMEOUT but the worker thread never ends. As a result, virtual memory grows at about 1 MB every time, physical memory grows some KBs and the application that calls the dll becomes unstable. I also tryied to use TerminateThread() but i got the same results.
I have to admit that although i have enough developing experience, i am not familiar with c/c++. I did a lot of research before posting but unfortunately i didn't manage to solve my problem.
Does anyone have a clue on how could i solve this problem? However, I really want to stick to this kind of solution. Also, i want to mention that i think i can't use any global variables to use some kind of extra events, because each dll's functions may be called many times for every COM port.
I post some parts of my code below:
The Worker Thread:
unsigned int __stdcall ReadPort(void* readstr){
DWORD dwError; int rres;DWORD dwCommModemStatus, dwBytesTransferred;
int ret;
char szBuff[64] = "";
ReadParams* params = (ReadParams*)readstr;
ret = SetCommMask(params->param2, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
if (ret == 0)
{
_endthreadex(0);
return -1;
}
ret = WaitCommEvent(params->param2, &dwCommModemStatus, 0);
if (ret == 0)
{
_endthreadex(0);
return -2;
}
ret = SetCommMask(params->param2, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD| EV_RING);
if (ret == 0)
{
_endthreadex(0);
return -3;
}
if (dwCommModemStatus & EV_RXCHAR||dwCommModemStatus & EV_RLSD)
{
rres = ReadFile(params->param2, szBuff, 64, &dwBytesTransferred,NULL);
if (rres == 0)
{
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
_endthreadex(0);
return -4;
}
_endthreadex(0);
return -5;
}
else
{
strcpy(params->param1,szBuff);
_endthreadex(0);
return 0;
}
}
else
{
_endthreadex(0);
return 0;
}
_endthreadex(0);
return 0;}
The Calling Thread:
int WINAPI StartReadThread(HANDLE porthandle, HWND windowhandle){
HANDLE hThread;
unsigned threadID;
ReadParams readstr;
DWORD ret, ret2;
readstr.param2 = porthandle;
hThread = (HANDLE)_beginthreadex( NULL, 0, ReadPort, &readstr, 0, &threadID );
ret = WaitForSingleObject(hThread, 500);
if (ret == WAIT_OBJECT_0)
{
CloseHandle(hThread);
if (readstr.param1 != NULL)
// Send message to GUI
return 0;
}
else if (ret == WAIT_TIMEOUT)
{
ret2 = CloseHandle(hThread);
return -1;
}
else
{
ret2 = CloseHandle(hThread);
if (ret2 == 0)
return -2;
}}
Thank you in advance,
Sna.
Don't use WaitCommEvent. You can call ReadFile even when there is no data waiting.
Use SetCommTimeouts to make ReadFile itself timeout, instead of building a timeout on the inter-thread communications.
Change the delay in the WaitForSingleObject call to 5000 or 10000 and I bet your problem frequency goes way down.
Edwin's answer is also valid. The spawned thread does not die because you closed the thread handle.
There is no guarantee that the ReadPort thread has even started by the time you are timing out. Windows takes a LONG time to start a thread.
Here are some suggestions:
You never check the return value of beginthreadex. How do you know the thread started?
Use whatever synchronization method with which you are comfortable to sync the ReadPort thread startup with StartReadThread. It could be as simple as an integer flag that ReadPort sets to 1 when its ready to work. Then the main thread can start its true waiting at that point. Otherwise you'll never know short of using a debugger what's happening between the 2 threads. Do not time out from the call to WaitForSingleObject in StartReadThread until your sync method indicates that ReadPort is working.
You should not use strcpy to copy the bytes received from the serial port with ReadFile. ReadFile tells you how many bytes it read. Use that value and memcpy to fill the buffer.
Look here and here for info on how to have ReadFile time out so your reads are not indefinite. Blocking forever on Windows is a recipe for disaster as it can cause zombie processes you cannot kill, among other problems.
You communicate no status to StartReadThread about what happened in the ReadPort thread. How do you know how many bytes ReadPort placed into szBuff? To get the theads exit code, use GetExitCodeThread. Documented here. Note that you cannot use GetExitCodeThread if you've closed the thread handle.
In your calling thread after a timeout you close the threadhandle. This will only stop you from using the handle. The worker thread however is still running. You should use a loop which waits again.