5

I am encoutering a issues with win32 programming doing a serial port communication using a event-driven approach. I have my communication handle created as:

hComm = CreateFile(lpszCommName, GENERIC_READ | GENERIC_WRITE, 0,
    NULL, OPEN_EXISTING, 0, NULL);

and i set my CommTimeouts as:

    commTimeout.ReadIntervalTimeout = MAXWORD;
    commTimeout.ReadTotalTimeoutConstant = 0;
    commTimeout.ReadTotalTimeoutMultiplier = 0;
    commTimeout.WriteTotalTimeoutConstant = 0;
    commTimeout.WriteTotalTimeoutMultiplier = 0;

I created a thread for ReadFile which looks like this:

SetCommMask(hComm, EV_RXCHAR);
while (isConnected)
{
    if (WaitCommEvent(hComm, &dwEvent, NULL)) //If i comment out this block my write file will work fine
    {
        ClearCommError(hComm, &dwError, &cs);
        if ((dwEvent & EV_RXCHAR) && cs.cbInQue)
        {
            if (!ReadFile(hComm, str, cs.cbInQue, &read_byte, NULL))
              /* Process error*/
            else if (read_byte)
                /* Print to screen */
        }
        else {
            /* Process error*/
        }
    }
}
PurgeComm(hComm, PURGE_RXCLEAR);

My Wrifile goes into WndProc which sends characters to the communication device when WM_CHAR is triggered:

    VOID Write_To_Serial(WPARAM wParam, HWND hwnd){
        DWORD write_byte;
        char    str[10];
        sprintf_s(str, "%c", (char)wParam);         //Convert wParam to a string
        WriteFile(hComm, str, strlen(str), &write_byte, NULL)//Program hangs here
    }   

My problem is everytime WriteFile() is called my application hangs and I have to force to close it. And if I comment out the WaitCommEvent() in my read thread it works fine, but I can't read then.Any pointers would be appreciated. thanks

  • I don't remember well, but I think you need a `FILE_FLAG_OVERLAPPED` in your implementation. If it could help you take a look at my old old old and old CBuilder Com Port Component [HERE](http://sourceforge.net/projects/tlpscomport/) – LPs Oct 06 '15 at 07:24
  • It makes no sense that it would block. Look for the non-trivial bug. Something is going to blow up badly when `str` is not properly zero-terminated, very easy mistake. And try another USB emulator, there's a lot of junk around. – Hans Passant Oct 06 '15 at 09:50
  • Can you post the actual code writing to the port? In the current code you're sending uninitialized stack garbage, and I hope that's not what you're actually doing. – theB Oct 06 '15 at 12:56
  • @HERE – LPs I am able to used the FILE_FLAG_OVERLAPPED in my previous project for asynchronous I/O. But I am attempting a synchrounous event-driven approach for this assignment – Some_Tasty_Donuts Oct 06 '15 at 16:01
  • @theB Sorry I've delete some code in my writing which it might look like the writefile is sending unitializaed stack garbage, I've added back on the full function. Anyhow, I'm sure there has to be something going on with WriteFile and WaitCommEvent that caused my program to hang. My speculation is that the buffer in the serial port is full while waiting for the comm event which prevents me from writing anything. (I tried calling ClearCommError() everytime before I call WriteFIle() but didn't resolve the issue) – Some_Tasty_Donuts Oct 06 '15 at 16:03
  • I don't think you're allowed to use a synchronous handle simultaneously from multiple threads. Perhaps try opening separate read and write handles? – Harry Johnston Oct 06 '15 at 22:26

1 Answers1

1

This is the expected behavior of Synchronous IO operations.

As per the following description in Serial Communications article in MSDN (https://msdn.microsoft.com/en-us/library/ff802693.aspx),

It is the responsibility of the application to serialize access to the port correctly. If one thread is blocked waiting for its I/O operation to complete, all other threads that subsequently call a communications API will be blocked until the original operation completes. For instance, if one thread were waiting for a ReadFile function to return, any other thread that issued a WriteFile function would be blocked.

WriteFile has to wait until WaitCommEvent function has completed its operation.

A small workaround would be to cancel the pending WaitCommEvent operation (for instance by using CancelIoEx API) when WriteFile needs to be invoked.

 VOID Write_To_Serial(WPARAM wParam, HWND hwnd){
        DWORD write_byte;
        char    str[10];
        sprintf_s(str, "%c", (char)wParam);         //Convert wParam to a string
        CancelIoEx(hComm, NULL);
        WriteFile(hComm, str, strlen(str), &write_byte, NULL);//Program hangs here
    }  

WaitCommEvent returns FALSE when canceled. Hence,the code following WaitCommEvent will not be executed.

However, in extreme case, there is a chance, where the thread invoking the ReadFile function, re invokes the WaitCommEvent function, before WndProc gets to WriteFile. If this occurs, it needs to be handled separately. Maybe a small delay when WaitCommEvent returns FALSE would do.