Thread: [Dev-C++] Serial input(com port)
Open Source C & C++ IDE for Windows
Brought to you by:
claplace
|
From: <Ala...@cs...> - 2002-02-20 13:14:40
|
How do I get data from the serial port into my program? I have looked at
every book I can find and no mention is made of receiving serial input from a
com port. I want to hook up a Global Positioning System to my the computer to
calculate course and speed.
Thanks
|
|
From: Ioannis V. <no...@ya...> - 2002-02-20 20:21:47
|
You will use system extensions. E.g. in case of Windows and Dev-C++ you can use win32 api. Ioannis * Ioannis Vranos * Programming pages: http://www.noicys.d2g.com * Alternative URL: http://run.to/noicys > -----Original Message----- > From: dev...@li... > [mailto:dev...@li...] On Behalf > Of Ala...@cs... > Sent: Wednesday, February 20, 2002 3:14 PM > To: dev...@li... > Subject: [Dev-C++] Serial input(com port) > > > How do I get data from the serial port into my program? I > have looked at > every book I can find and no mention is made of receiving > serial input from a > com port. I want to hook up a Global Positioning System to my > the computer to > calculate course and speed. > Thanks > > _______________________________________________ > Dev-cpp-users mailing list > Dev...@li... > https://lists.sourceforge.net/lists/listinfo/dev-cpp-users > |
|
From: Yeoh H. <ye...@ya...> - 2002-02-21 01:03:58
|
Hi,
Here's an MSDN article that might be of some help.
<begin MSDN extract>
Serial Communications in Win32
Allen Denver
Microsoft Windows Developer Support
December 11, 1995
Allen seldom eats breakfast, but if he had to pick a favorite, Win32 serial
communications would be the top choice.
Click to open or copy the files in the MTTTY sample application for this
technical article.
Abstract
Serial communications in Microsoft® Win32® is significantly different from
serial communications in 16-bit Microsoft Windows®. Those familiar with
16-bit serial communications functions will have to relearn many parts of
the system to program serial communications properly. This article will help
to accomplish this. Those unfamiliar with serial communications will find
this article a helpful foundation for development efforts.
This article assumes the reader is familiar with the fundamentals of
multiple threading and synchronization in Win32. In addition, a basic
familiarity of the Win32 heap functions is useful to fully comprehend the
memory management methods used by the sample, MTTTY, included with this
article. For more information regarding these functions, consult the Win32
Software Development Kit (SDK) documentation, the Microsoft Win32 SDK
Knowledge Base, or the Microsoft Developer Network Library. Application
programming interfaces (APIs) that control user interface features of
windows and dialog boxes, though not discussed here, are useful to know in
order to fully comprehend the sample provided with this article. Readers
unfamiliar with general Windows programming practices should learn some of
the fundamentals of general Windows programming before taking on serial
communications. In other words, get your feet wet before diving in head
first.
Introduction
The focus of this article is on application programming interfaces (APIs)
and methods that are compatible with Microsoft® Windows NT® and Windows 95;
therefore, APIs supported on both platforms are the only ones discussed.
Windows 95 supports the Win32® Telephony API (TAPI) and Windows NT 3.x does
not; therefore, this discussion will not include TAPI. TAPI does deserve
mention, however, in that it very nicely implements modem interfacing and
call controlling. A production application that works with modems and makes
telephone calls should implement these features using the TAPI interface.
This will allow seamless integration with the other TAPI-enabled
applications that a user may have. Furthermore, this article does not
discuss some of the configuration functions in Win32, such as
GetCommProperties.
The article is broken into the following sections: Opening a port, reading
and writing (nonoverlapped and overlapped), serial status (events and
errors), and serial settings (DCB, flow control, and communications
time-outs).
The sample included with this article, MTTTY: Multithreaded TTY, implements
many of the features discussed here. It uses three threads in its
implementation: a user interface thread that does memory management, a
writer thread that controls all writing, and a reader/status thread that
reads data and handles status changes on the port. The sample employs a few
different data heaps for memory management. It also makes extensive use of
synchronization methods to facilitate communication between threads.
Opening a Port
The CreateFile function opens a communications port. There are two ways to
call CreateFile to open the communications port: overlapped and
nonoverlapped. The following is the proper way to open a communications
resource for overlapped operation:
HANDLE hComm;
hComm = CreateFile( gszPort,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
if (hComm == INVALID_HANDLE_VALUE)
// error opening port; abort
Removal of the FILE_FLAG_OVERLAPPED flag from the call to CreateFile
specifies nonoverlapped operation. The next section discusses overlapped and
nonoverlapped operations.
The Win32 Software Development Kit (SDK) Programmer's Reference (Overviews,
Window Management, System Services) states that when opening a
communications port, the call to CreateFile has the following requirements:
fdwShareMode must be zero. Communications ports cannot be shared in the same
manner that files are shared. Applications using TAPI can use the TAPI
functions to facilitate sharing resources between applications. For Win32
applications not using TAPI, handle inheritance or duplication is necessary
to share the communications port. Handle duplication is beyond the scope of
this article; please refer to the Win32 SDK documentation for more
information.
fdwCreate must specify the OPEN_EXISTING flag.
hTemplateFile parameter must be NULL.
One thing to note about port names is that traditionally they have been
COM1, COM2, COM3, or COM4. The Win32 API does not provide any mechanism for
determining what ports exist on a system. Windows NT and Windows 95 keep
track of installed ports differently from one another, so any one method
would not be portable across all Win32 platforms. Some systems even have
more ports than the traditional maximum of four. Hardware vendors and
serial-device-driver writers are free to name the ports anything they like.
For this reason, it is best that users have the ability to specify the port
name they want to use. If a port does not exist, an error will occur
(ERROR_FILE_NOT_FOUND) after attempting to open the port, and the user
should be notified that the port isn't available.
Reading and Writing
Reading from and writing to communications ports in Win32 is very similar to
file input/output (I/O) in Win32. In fact, the functions that accomplish
file I/O are the same functions used for serial I/O. I/O in Win32 can be
done either of two ways: overlapped or nonoverlapped. The Win32 SDK
documentation uses the terms asynchronous and synchronous to connote these
types of I/O operations. This article, however, uses the terms overlapped
and nonoverlapped.
Nonoverlapped I/O is familiar to most developers because this is the
traditional form of I/O, where an operation is requested and is assumed to
be complete when the function returns. In the case of overlapped I/O, the
system may return to the caller immediately even when an operation is not
finished and will signal the caller when the operation completes. The
program may use the time between the I/O request and its completion to
perform some "background" work.
Reading and writing in Win32 is significantly different from reading and
writing serial communications ports in 16-bit Windows. 16-bit Windows only
has the ReadComm and WriteComm functions. Win32 reading and writing can
involve many more functions and choices. These issues are discussed below.
Nonoverlapped I/O
Nonoverlapped I/O is very straightforward, though it has limitations. An
operation takes place while the calling thread is blocked. Once the
operation is complete, the function returns and the thread can continue its
work. This type of I/O is useful for multithreaded applications because
while one thread is blocked on an I/O operation, other threads can still
perform work. 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.
One of the many factors to consider when choosing between nonoverlapped and
overlapped operations is portability. Overlapped operation is not a good
choice because most operating systems do not support it. Most operating
systems support some form of multithreading, however, so multithreaded
nonoverlapped I/O may be the best choice for portability reasons.
Overlapped I/O
Overlapped I/O is not as straightforward as nonoverlapped I/O, but allows
more flexibility and efficiency. A port open for overlapped operations
allows multiple threads to do I/O operations at the same time and perform
other work while the operations are pending. Furthermore, the behavior of
overlapped operations allows a single thread to issue many different
requests and do work in the background while the operations are pending.
In both single-threaded and multithreaded applications, some synchronization
must take place between issuing requests and processing the results. One
thread will have to be blocked until the result of an operation is
available. The advantage is that overlapped I/O allows a thread to do some
work between the time of the request and its completion. If no work can be
done, then the only case for overlapped I/O is that it allows for better
user responsiveness.
Overlapped I/O is the type of operation that the MTTTY sample uses. It
creates a thread that is responsible for reading the port's data and reading
the port's status. It also performs periodic background work. The program
creates another thread exclusively for writing data out the port.
Note Applications sometimes abuse multithreading systems by creating too
many threads. Although using multiple threads can resolve many difficult
problems, creating excessive threads is not the most efficient use of them
in an application. Threads are less a strain on the system than processes
but still require system resources such as CPU time and memory. An
application that creates excessive threads may adversely affect the
performance of the entire system. A better use of threads is to create a
different request queue for each type of job and to have a worker thread
issue an I/O request for each entry in the request queue. This method is
used by the MTTTY sample provided with this article.
An overlapped I/O operation has two parts: the creation of the operation and
the detection of its completion. Creating the operation entails setting up
an OVERLAPPED structure, creating a manual-reset event for synchronization,
and calling the appropriate function (ReadFile or WriteFile). The I/O
operation may or may not be completed immediately. It is an error for an
application to assume that a request for an overlapped operation always
yields an overlapped operation. If an operation is completed immediately, an
application needs to be ready to continue processing normally. The second
part of an overlapped operation is to detect its completion. Detecting
completion of the operation involves waiting for the event handle, checking
the overlapped result, and then handling the data. The reason that there is
more work involved with an overlapped operation is that there are more
points of failure. If a nonoverlapped operation fails, the function just
returns an error-return result. If an overlapped operation fails, it can
fail in the creation of the operation or while the operation is pending. You
may also have a time-out of the operation or a time-out waiting for the
signal that the operation is complete.
Reading
The ReadFile function issues a read operation. ReadFileEx also issues a read
operation, but since it is not available on Windows 95, it is not discussed
in this article. Here is a code snippet that details how to issue a read
request. Notice that the function calls a function to process the data if
the ReadFile returns TRUE. This is the same function called if the operation
becomes overlapped. Note the fWaitingOnRead flag that is defined by the
code; it indicates whether or not a read operation is overlapped. It is used
to prevent the creation of a new read operation if one is outstanding.
DWORD dwRead;
BOOL fWaitingOnRead = FALSE;
OVERLAPPED osReader = {0};
// Create the overlapped event. Must be closed before exiting
// to avoid a handle leak.
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL)
// Error creating overlapped event; abort.
if (!fWaitingOnRead) {
// Issue read operation.
if (!ReadFile(hComm, lpBuf, READ_BUF_SIZE, &dwRead, &osReader)) {
if (GetLastError() != ERROR_IO_PENDING) // read not delayed?
// Error in communications; report it.
else
fWaitingOnRead = TRUE;
}
else
// read completed immediately
HandleASuccessfulRead(lpBuf, dwRead);
}
}
The second part of the overlapped operation is the detection of its
completion. The event handle in the OVERLAPPED structure is passed to the
WaitForSingleObject function, which will wait until the object is signaled.
Once the event is signaled, the operation is complete. This does not mean
that it was completed successfully, just that it was completed. The
GetOverlappedResult function reports the result of the operation. If an
error occurred, GetOverlappedResult returns FALSE and GetLastError returns
the error code. If the operation was completed successfully,
GetOverlappedResult will return TRUE.
Note GetOverlappedResult can detect completion of the operation, as well
as return the operation's failure status. GetOverlappedResult returns FALSE
and GetLastError returns ERROR_IO_INCOMPLETE when the operation is not
completed. In addition, GetOverlappedResult can be made to block until the
operation completes. This effectively turns the overlapped operation into a
nonoverlapped operation and is accomplished by passing TRUE as the bWait
parameter.
Here is a code snippet that shows one way to detect the completion of an
overlapped read operation. Note that the code calls the same function to
process the data that was called when the operation completed immediately.
Also note the use of the fWaitingOnRead flag. Here it controls entry into
the detection code, since it should be called only when an operation is
outstanding.
#define READ_TIMEOUT 500 // milliseconds
DWORD dwRes;
if (fWaitingOnRead) {
dwRes = WaitForSingleObject(osReader.hEvent, READ_TIMEOUT);
switch(dwRes)
{
// Read completed.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hComm, &osReader, &dwRead, FALSE))
// Error in communications; report it.
else
// Read completed successfully.
HandleASuccessfulRead(lpBuf, dwRead);
// Reset flag so that another opertion can be issued.
fWaitingOnRead = FALSE;
break;
case WAIT_TIMEOUT:
// Operation isn't complete yet. fWaitingOnRead flag isn't
// changed since I'll loop back around, and I don't want
// to issue another read until the first one finishes.
//
// This is a good time to do some background work.
break;
default:
// Error in the WaitForSingleObject; abort.
// This indicates a problem with the OVERLAPPED structure's
// event handle.
break;
}
}
Writing
Transmitting data out the communications port is very similar to reading in
that it uses a lot of the same APIs. The code snippet below demonstrates how
to issue and wait for a write operation to be completed.
BOOL WriteABuffer(char * lpBuf, DWORD dwToWrite)
{
OVERLAPPED osWrite = {0};
DWORD dwWritten;
DWORD dwRes;
BOOL fRes;
// 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
return FALSE;
// Issue write.
if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) {
if (GetLastError() != ERROR_IO_PENDING)
// WriteFile failed, but isn't delayed. Report error and abort.
fRes = FALSE;
}
else
// Write is pending.
dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
switch(dwRes)
{
// OVERLAPPED structure's event has been signaled.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hComm, &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;
CloseHandle(osWrite.hEvent);
return fRes;
}
Notice that the code above uses the WaitForSingleObject function with a
time-out value of INFINITE. This causes the WaitForSingleObject function to
wait forever until the operation is completed; this may make the thread or
program appear to be "hung" when, in fact, the write operation is simply
taking a long time to complete or flow control has blocked the transmission.
Status checking, discussed later, can detect this condition, but doesn't
cause the WaitForSingleObject to return. Three things can alleviate this
condition:
Place the code in a separate thread. This allows other threads to execute
any functions they desire while our writer thread waits for the write to be
completed. This is what the MTTTY sample does.
Use COMMTIMEOUTS to cause the write to be completed after a time-out period
has passed. This is discussed more fully in the "Communications Time-outs"
section later in this article. This is also what the MTTTY sample allows.
Change the WaitForSingleObject call to include a real time-out value. This
causes more problems because if the program issues another operation while
an older operation is still pending, new OVERLAPPED structures and
overlapped events need to be allocated. This type of recordkeeping is
difficult, particularly when compared to using a "job queue" design for the
operations. The "job queue" method is used in the MTTTY sample.
Note: The time-out values in synchronization functions are not
communications time-outs. Synchronization time-outs cause
WaitForSingleObject or WaitForMultipleObjects to return WAIT_TIMEOUT. This
is not the same as a read or write operation timing out. Communications
time-outs are described later in this article.
Because the WaitForSingleObject function in the above code snippet uses an
INFINITE time-out, it is equivalent to using GetOverlappedResult with TRUE
for the fWait parameter. Here is equivalent code in a much simplified form:
BOOL WriteABuffer(char * lpBuf, DWORD dwToWrite)
{
OVERLAPPED osWrite = {0};
DWORD dwWritten;
BOOL fRes;
// Create this writes OVERLAPPED structure hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
// Error creating overlapped event handle.
return FALSE;
// Issue write.
if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) {
if (GetLastError() != ERROR_IO_PENDING)
// WriteFile failed, but it isn't delayed. Report error and abort.
fRes = FALSE;
}
else {
// Write is pending.
if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, TRUE))
fRes = FALSE;
else
// Write operation completed successfully.
fRes = TRUE;
}
}
else
// WriteFile completed immediately.
fRes = TRUE;
CloseHandle(osWrite.hEvent);
return fRes;
}
GetOverlappedResult is not always the best way to wait for an overlapped
operation to be completed. For example, if an application needs to wait on
another event handle, the first code snippet serves as a better model than
the second. The call to WaitForSingleObject is easy to change to
WaitForMultipleObjects to include the additional handles on which to wait.
This is what the MTTTY sample application does.
A common mistake in overlapped I/O is to reuse an OVERLAPPED structure
before the previous overlapped operation is completed. If a new overlapped
operation is issued before a previous operation is completed, a new
OVERLAPPED structure must be allocated for it. A new manual-reset event for
the hEvent member of the OVERLAPPED structure must also be created. Once an
overlapped operation is complete, the OVERLAPPED structure and its event are
free for reuse.
The only member of the OVERLAPPED structure that needs modifying for serial
communications is the hEvent member. The other members of the OVERLAPPED
structure should be initialized to zero and left alone. Modifying the other
members of the OVERLAPPED structure is not necessary for serial
communications devices. The documentation for ReadFile and WriteFile state
that the Offset and OffsetHigh members of the OVERLAPPED structure must be
updated by the application, or else results are unpredictable. This
guideline should be applied to OVERLAPPED structures used for other types of
resources, such as files.
Serial Status
There are two methods to retrieve the status of a communications port. The
first is to set an event mask that causes notification of the application
when the desired events occur. The SetCommMask function sets this event
mask, and the WaitCommEvent function waits for the desired events to occur.
These functions are similar to the 16-bit functions SetCommEventMask and
EnableCommNotification, except that the Win32 functions do not post
WM_COMMNOTIFY messages. In fact, the WM_COMMNOTIFY message is not even part
of the Win32 API. The second method for retrieving the status of the
communications port is to periodically call a few different status
functions. Polling is, of course, neither efficient nor recommended.
Communications Events
Communications events can occur at any time in the course of using a
communications port. The two steps involved in receiving notification of
communications events are as follows:
SetCommMask sets the desired events that cause a notification.
WaitCommEvent issues a status check. The status check can be an overlapped
or nonoverlapped operation, just as the read and write operations can be.
Note: The word event in this context refers to communications events only.
It does not refer to an event object used for synchronization.
Here is an example of the SetCommMask function:
DWORD dwStoredFlags;
dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |\
EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY ;
if (!SetCommMask(hComm, dwStoredFlags))
// error setting communications mask
A description of each type of event is in Table 1.
Table 1. Communications Event Flags
Event Flag Description
EV_BREAK A break was detected on input.
EV_CTS The CTS (clear-to-send) signal changed state. To get the actual state
of the CTS line, GetCommModemStatus should be called.
EV_DSR The DSR (data-set-ready) signal changed state. To get the actual
state of the DSR line, GetCommModemStatus should be called.
EV_ERR A line-status error occurred. Line-status errors are CE_FRAME,
CE_OVERRUN, and CE_RXPARITY. To find the cause of the error, ClearCommError
should be called.
EV_RING A ring indicator was detected.
EV_RLSD The RLSD (receive-line-signal-detect) signal changed state. To get
the actual state of the RLSD line, GetCommModemStatus should be called. Note
that this is commonly referred to as the CD (carrier detect) line.
EV_RXCHAR A new character was received and placed in the input buffer. See
the "Caveat" section below for a discussion of this flag.
EV_RXFLAG The event character was received and placed in the input buffer.
The event character is specified in the EvtChar member of the DCB structure
discussed later. The "Caveat" section below also applies to this flag.
EV_TXEMPTY The last character in the output buffer was sent to the serial
port device. If a hardware buffer is used, this flag only indicates that all
data has been sent to the hardware. There is no way to detect when the
hardware buffer is empty without talking directly to the hardware with a
device driver.
After specifying the event mask, the WaitCommEvent function detects the
occurrence of the events. If the port is open for nonoverlapped operation,
then the WaitCommEvent function does not contain an OVERLAPPED structure.
The function blocks the calling thread until the occurrence of one of the
events. If an event never occurs, the thread may block indefinitely.
Here is a code snippet that shows how to wait for an EV_RING event when the
port is open for nonoverlapped operation:
DWORD dwCommEvent;
if (!SetCommMask(hComm, EV_RING))
// Error setting communications mask
return FALSE;
if (!WaitCommEvent(hComm, &dwCommEvent, NULL))
// An error occurred waiting for the event.
return FALSE;
else
// Event has occurred.
return TRUE;
Note The Microsoft Win32 SDK Knowledge Base documents a problem with
Windows 95 and the EV_RING flag. The above code never returns in Windows 95
because the EV_RING event is not detected by the system; Windows NT properly
reports the EV_RING event. Please see the Win32 SDK Knowledge Base for more
information on this bug.
As noted, the code above can be blocked forever if an event never occurs. A
better solution would be to open the port for overlapped operation and wait
for a status event in the following manner:
#define STATUS_CHECK_TIMEOUT 500 // Milliseconds
DWORD dwRes;
DWORD dwCommEvent;
DWORD dwStoredFlags;
BOOL fWaitingOnStat = FALSE;
OVERLAPPED osStatus = {0};
dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |\
EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY ;
if (!SetCommMask(comHandle, dwStoredFlags))
// error setting communications mask; abort
return 0;
osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osStatus.hEvent == NULL)
// error creating event; abort
return 0;
for ( ; ; ) {
// Issue a status event check if one hasn't been issued already.
if (!fWaitingOnStat) {
if (!WaitCommEvent(hComm, &dwCommEvent, &osStatus)) {
if (GetLastError() == ERROR_IO_PENDING)
bWaitingOnStatusHandle = TRUE;
else
// error in WaitCommEvent; abort
break;
}
else
// WaitCommEvent returned immediately.
// Deal with status event as appropriate.
ReportStatusEvent(dwCommEvent);
}
// Check on overlapped operation.
if (fWaitingOnStat) {
// Wait a little while for an event to occur.
dwRes = WaitForSingleObject(osStatus.hEvent, STATUS_CHECK_TIMEOUT);
switch(dwRes)
{
// Event occurred.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hComm, &osStatus, &dwOvRes,
FALSE))
// An error occurred in the overlapped operation;
// call GetLastError to find out what it was
// and abort if it is fatal.
else
// Status event is stored in the event flag
// specified in the original WaitCommEvent call.
// Deal with the status event as appropriate.
ReportStatusEvent(dwCommEvent);
// Set fWaitingOnStat flag to indicate that a new
// WaitCommEvent is to be issued.
fWaitingOnStat = FALSE;
break;
case WAIT_TIMEOUT:
// Operation isn't complete yet. fWaitingOnStatusHandle
flag
// isn't changed since I'll loop back around and I don't
want
// to issue another WaitCommEvent until the first one
finishes.
//
// This is a good time to do some background work.
DoBackgroundWork();
break;
default:
// Error in the WaitForSingleObject; abort
// This indicates a problem with the OVERLAPPED structure's
// event handle.
CloseHandle(osStatus.hEvent);
return 0;
}
}
}
CloseHandle(osStatus.hEvent);
The code above very closely resembles the code for overlapped reading. In
fact, the MTTTY sample implements its reading and status checking in the
same thread using WaitForMultipleObjects to wait for either the read event
or the status event to become signaled.
There are two interesting side effects of SetCommMask and WaitCommEvent.
First, if the communications port is open for nonoverlapped operation,
WaitCommEvent will be blocked until an event occurs. If another thread calls
SetCommMask to set a new event mask, that thread will be blocked on the call
to SetCommMask. The reason is that the original call to WaitCommEvent in the
first thread is still executing. The call to SetCommMask blocks the thread
until the WaitCommEvent function returns in the first thread. This side
effect is universal for ports open for nonoverlapped I/O. If a thread is
blocked on any communications function and another thread calls a
communications function, the second thread is blocked until the
communications function returns in the first thread. The second interesting
note about these functions is their use on a port open for overlapped
operation. If SetCommMask sets a new event mask, any pending WaitCommEvent
will complete successfully, and the event mask produced by the operation is
NULL.
Caveat
Using the EV_RXCHAR flag will notify the thread that a byte arrived at the
port. This event, used in combination with the ReadFile function, enables a
program to read data only after it is in the receive buffer, as opposed to
issuing a read that waits for the data to arrive. This is particularly
useful when a port is open for nonoverlapped operation because the program
does not need to poll for incoming data; the program is notified of the
incoming data by the occurrence of the EV_RXCHAR event. Initial attempts to
code this solution often produce the following pseudocode, including one
oversight covered later in this section:
DWORD dwCommEvent;
DWORD dwRead;
char chRead;
if (!SetCommMask(hComm, EV_RXCHAR))
// Error setting com...
[truncated message content] |