Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Non-blocking ReadFile on a serial port

6,515 views
Skip to first unread message

Diego Sebastián

unread,
Nov 20, 2003, 8:06:21 AM11/20/03
to
Hi all.

I'm trying to write a C++ wrapper class for serial communications under
win32. My first approach has been opening the port synchronously (no
FILE_FLAG_OVERLAPPED attribute), and create an RX polling thread, which uses
ReadFile. This thread is getting blocked upon the call to ReadFile, even
though there is incoming data, so I'm not sure if this is a blocking call or
if there is a different problem.

Must I use overlapped file access to do this? Anyone knows a good tutorial
on overlapped file access?

Thank you for your attention.

Diego

Larry Lindstrom

unread,
Nov 20, 2003, 10:11:29 AM11/20/03
to

Diego Sebastián wrote:

Hi Diego:

Jeff Richter's Advanced Windows Programming describes the
issues you need to understand.

I fought through this same problem a year ago. You might want
to look at Google's archives for this group to see some of the
great guidance I received.

Good luck.

Larry

Charlie Gibbs

unread,
Nov 20, 2003, 12:19:40 PM11/20/03
to
In article <dcd31b95.03112...@posting.google.com>
diego.s...@tecnocom.biz (Diego Sebastián) writes:

So far I've managed to avoid using overlapped file access -
it looks too complicated and nonportable to me. Here's a
snippet of code from a program of mine which opens a serial
port and issues nonblocking reads:

HANDLE serfd;
char *portname = "COM1";
int sermemsize = 8192;
COMMTIMEOUTS ct;

serfd = CreateFile (portname, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (serfd == INVALID_HANDLE_VALUE) {

/* Couldn't open the port! */

}

SetupComm (serfd, sermemsize, sermemsize); /* Set buffer size. */
PurgeComm (serfd,
PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR);

memset ((void *) &ct, 0, sizeof (ct));
ct.ReadIntervalTimeout = MAXDWORD;
ct.ReadTotalTimeoutMultiplier = 0;
ct.ReadTotalTimeoutConstant = 0;
ct.WriteTotalTimeoutMultiplier = 20000L / baudrate;
ct.WriteTotalTimeoutConstant = 0;
SetCommTimeouts (serfd, &ct);

Look up SetCommTimeouts and the COMMTIMEOUTS structure in the
API reference. The description of the ReadIntervalTimeout
structure member contains the following paragraph:

A value of MAXDWORD, combined with zero values for both the
ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members,
specifies that the read operation is to return immediately with
the number of characters that have already been received, even
if no characters have been received.

--
/~\ cgi...@kltpzyxm.invalid (Charlie Gibbs)
\ / I'm really at ac.dekanfrus if you read it the right way.
X Top-posted messages will probably be ignored. See RFC1855.
/ \ HTML will DEFINITELY be ignored. Join the ASCII ribbon campaign!

Diego Sebasti?n

unread,
Nov 20, 2003, 1:06:51 PM11/20/03
to
Thanks, Larry. I will.

Diego

Diego Sebasti?n

unread,
Nov 20, 2003, 1:14:38 PM11/20/03
to
Hi there again.

Checking back through the code, I found out why ReadFile was blocking
even though data was coming. It turns out I had defined a 256-byte
buffer to read in blocks, so the call was blocked until I had received
256 bytes... anyway, reading on a 1-char-basis did the trick -almost.
My second problem was that I couldn't request the thread to exit while
it was blocked, so I actually needed (a) another byte coming into the
port, or (b) terminate the thread non-graciouslly, which wasn't that
good either since I had declared local-stack variables.

So, in conclussion. I'm moving into overlapping anyway, and so far my
approach has been to issue a "ReadFile" command followed by a
"WaitForSingleObject" call, waiting for the "OVERLAPPED.hEvent" object
to be signaled. That way, I can signal it from outside the thread.
Then I check if data has actually come in, using
"GetOverlappedResult", process it and loop back to "ReadFile". Is that
an optimal approach?

Thank you,

Diego

Scott McPhillips [MVP]

unread,
Nov 20, 2003, 8:42:48 PM11/20/03
to
Diego Sebasti?n wrote:

All of this was worked out long ago in an MSDN SDK sample application
named MTTTY, and described in a nice MSDN article by Allen Denver. If
you can't find them keep digging, perhaps in older MSDN disks.

As revealed only in that article, you MUST use overlapped I/O if you
want to support concurrent input and output.

The approach you describe is *part* of an optimal approach. But if
there is a UART error (framing, parity, etc.) the communication will
halt. The MTTTY sample manages that problem in the same loop that does
inputting.

--
Scott McPhillips [VC++ MVP]

Diego Sebasti?n

unread,
Nov 21, 2003, 3:42:29 AM11/21/03
to
Thanks Scott.

I'll dig into that sample, but in the meantime I'm using Charlie's
approach which seems to work fine and allows me to read the incoming
data in chunks instead of bytes, which is more appropiate for my
further data processing. But once again thank you for your help.

Diego

Off-topic PS: As you may have seen, I'm posting this from Google's
groups, since I have no access to a free news server, but Google
required me to post my real e-mail address, and I'm getting all sort
of unwanted stuff to my mailbox. It may be too late, but does anybody
know a free NNTP server (with posting rights) or how to hide my real
address from Google's groups? Thanks for all.

r_z_...@pen_fact.com

unread,
Nov 21, 2003, 2:21:42 PM11/21/03
to
Another voice supporting your switch to overlapped i/o:

I resisted using overlapped i/o for a few years. In my case, part of
the motivation was that it isn't supported for Windows CE, my primary
target. But as I refined my code further, I ran into miscellaneous
problems when running under NT. So I recently added support for
overlapped i/o, subject to compiler directives to hide it from Windows
CE.

The following comment from my code might be relevant:

// According to tty sample in July 2001 MSDN Library, SetCommMask
triggers WaitCommEvent.
// But Knowledge Base article Q105302 says that, for
non-overlapped i/o under NT & 2000,
// SetCommMask does _not_ return until WaitCommEvent is done. The
article further states
// that under NT & 2000, a port really can do only one thing at a
time. (article found
// (found via 13 Sep 2000 thread called "SetCommMask &
WaitCommEvent question" in
// microsoft.public.vc.mfc)


On 20 Nov 2003 05:06:21 -0800, diego.s...@tecnocom.biz
(=?ISO-8859-1?Q?Diego_Sebasti=E1n?=) wrote:

-----------------------------------------
To reply to me, remove the underscores (_) from my email address (and please indicate which newsgroup and message).

Robert E. Zaret
PenFact, Inc.
500 Harrison Ave., Suite 3R
Boston, MA 02118
www.penfact.com

Alex Blekhman

unread,
Nov 23, 2003, 4:48:41 AM11/23/03
to
"Diego Sebasti?n" <diego.s...@tecnocom.biz> wrote in message
news:dcd31b95.03112...@posting.google.com...

>
> Off-topic PS: As you may have seen, I'm posting this from Google's
> groups, since I have no access to a free news server, but Google
> required me to post my real e-mail address, and I'm getting all sort
> of unwanted stuff to my mailbox. It may be too late, but does anybody
> know a free NNTP server (with posting rights) or how to hide my real
> address from Google's groups? Thanks for all.

Here are two excellent sites:

http://freenews.maxbaud.net/
http://www.newzbot.com/

HTH
Alex


Diego Sebasti?n

unread,
Nov 24, 2003, 3:42:03 AM11/24/03
to
Hi, thank you all for your responses.

I implemented my class as Charlie Gibbs suggested and it did work
fine, until... I tested it under XP. In XP, as soon as I've received
one char, subsequent calls to WriteFile fail yielding the error 995
(ERROR_OPERATION_ABORTED). Both ReadFile and WriteFile are enclosed
within a critical section, to prevent concurrent access to the port
handle, and each thread has a separate buffer allocated by the main
class, which is not shared by the threads.

If any of you know what this error indicates, I'm open to any
suggestion. Until then, I'll to work my way into overlapping.

Thanks a lot.

Diego

PS: By the way, in deed it's too late to do anything about my email
address, I'll have to get another one and leave this one for all these
forums :-(

0 new messages