Question

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?

Was it helpful?

Solution

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/

OTHER TIPS

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.

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top