함수포인터
공부를 해보자/프로그래밍 2008. 6. 18. 14:49타이거 월드 분수대
내 삶의 이야기/사진과 함께 2008. 6. 16. 23:02'내 삶의 이야기 > 사진과 함께' 카테고리의 다른 글
생일선물 (0) | 2006.01.17 |
---|---|
사공이를 떠나보내다. (3) | 2005.03.15 |
아인스 월드 커플연간회원... (0) | 2005.02.20 |
티켓 모음 (2) | 2005.01.17 |
일피와 이피 (2) | 2005.01.08 |
하온이의 하루하루
내 삶의 이야기/육아 2008. 6. 16. 22:54'내 삶의 이야기 > 육아' 카테고리의 다른 글
좋은 부모가 되기 위한 책읽기 (0) | 2008.04.07 |
---|---|
아기의 체온과 열날때 대처법 (0) | 2008.03.04 |
훈육에 관련된 글 (0) | 2008.01.30 |
무서운 땅콩 (1) | 2007.12.24 |
하온이 입원 5일째 (0) | 2007.11.16 |
읽고 있는 책 (읽어야 할 책)
내 삶의 이야기/책 2008. 6. 16. 10:08바바라 민토 지음, 이진원 옮김 / 더난출판사
경영, 과학에게 길을 묻다
유정식 지음 / 위즈덤하우스
겅호!
켄 블랜차드,셀든 보울즈 지음, 조천제 외 옮김 / 21세기북스(북이십일)
딜리셔스 샌드위치
유병률 지음 / 웅진윙스
'내 삶의 이야기 > 책' 카테고리의 다른 글
글쓰기 책 고르는 중 (0) | 2008.03.30 |
---|---|
재무설계? 재테크? (0) | 2006.12.25 |
트랙백 놀이 (0) | 2004.10.07 |
MPEG4도서 (0) | 2004.09.22 |
요즘 읽고 있는 책... (0) | 2004.09.13 |
파일/문자열 찾기
공부를 해보자/프로그래밍 2008. 6. 11. 17:10. => 현재 위치
-name *.h => 확장자가 h인 파일
-exec => 찾은 파일로 다음에 나오는 명령을 수행
{} => 찾은 파일 명
; => 명령의 끝
Serial Communications in Win32
카테고리 없음 2008. 6. 10. 13:33다른자료:http://155.230.25.119/teleadam/program/rs232c.asp
- Microsoft Windows and the Plug and Play Framework Architecture
- OnNow Power Management Architecture for Applications
- PCMCIA Card Support in Windows 95
- Plug and Play for Microsoft Windows 2000
- Plug and Play SCSI: Designing to the New Standard
- Serial Communications in Win32
- Win32 Application Support for Plug and Play
FilesandI/0TechnicalArticles
Allen Denver
Microsoft Windows Developer Support
December 11, 1995
Applies to:
Microsoft® Win32®
Microsoft Windows®
Summary:Learn how serial communications in Microsoft Win32 is significantlydifferent from serial communications in 16-bit Microsoft Windows. Thisarticle assumes a familiarity with the fundamentals of multiplethreading and synchronization in Win32. In addition, a basicunderstanding of the Win32 heap functions is useful to fullycomprehend the memory management methods used by the Multithreaded TTY(MTTTY) sample included with this article. (35 printed pages)
Download the MTTTY sample (4918.exe) for this technical article.
Contents
Overview
Introduction
Opening a Port
Reading and Writing
Serial Status
Serial Settings
Conclusion
Bibliography
Overview
Serialcommunications in Microsoft® Win32® is significantly different fromserial communications in 16-bit Microsoft Windows®. Those familiar with16-bit serial communications functions will have to relearn many partsof the system to program serial communications properly. This articlewill help to accomplish this. Those unfamiliar with serialcommunications will find this article a helpful foundation fordevelopment efforts.
This article assumes you are familiar withthe fundamentals of multiple threading and synchronization in Win32. Inaddition, 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.
Formore information regarding these functions, consult the Platform SDKdocumentation, the Microsoft Win32 SDK Knowledge Base, or the MicrosoftDeveloper 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 fullycomprehend the sample provided with this article. Readers unfamiliarwith general Windows programming practices should learn some of thefundamentals of general Windows programming before taking on serialcommunications. In other words, get your feet wet before diving in headfirst. (36 printed pages)
Introduction
Thefocus of this article is on application programming interfaces (APIs)and methods that are compatible with Microsoft Windows NT andWindows 95; therefore, APIs supported on both platforms are the onlyones discussed. Windows 95 supports the Win32 Telephony API (TAPI) andWindows NT 3.x does not; therefore, this discussion will notinclude TAPI. TAPI does deserve mention, however, in that it verynicely implements modem interfacing and call controlling. A productionapplication that works with modems and makes telephone calls shouldimplement these features using the TAPI interface. This will allowseamless integration with the other TAPI-enabled applications that auser may have. Furthermore, this article does not discuss some of theconfiguration functions in Win32, such as GetCommProperties.
Thesample included with this article, MTTTY: Multithreaded TTY (4918.exe),implements many of the features discussed here. It uses three threadsin its implementation: a user interface thread that does memorymanagement, a writer thread that controls all writing, and areader/status thread that reads data and handles status changes on theport. The sample employs a few different data heaps for memorymanagement. It also makes extensive use of synchronization methods tofacilitate communication between threads.
Opening a Port
The CreateFile function opens a communications port. There are two ways to call CreateFileto open the communications port: overlapped and nonoverlapped. Thefollowing is the proper way to open a communications resource foroverlapped 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 Platform SDK documentation 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 areshared. Applications using TAPI can use the TAPI functions tofacilitate sharing resources between applications. For Win32applications not using TAPI, handle inheritance or duplication isnecessary to share the communications port. Handle duplication isbeyond the scope of this article; please refer to the Platform SDKdocumentation for more information.
- fdwCreate must specify the OPEN_EXISTING flag.
- hTemplateFile parameter must be NULL.
Onething to note about port names is that traditionally they have beenCOM1, COM2, COM3, or COM4. The Win32 API does not provide any mechanismfor determining what ports exist on a system. Windows NT and Windows 95keep track of installed ports differently from one another, so any onemethod would not be portable across all Win32 platforms. Some systemseven have more ports than the traditional maximum of four. Hardwarevendors and serial-device-driver writers are free to name the portsanything they like. For this reason, it is best that users have theability to specify the port name they want to use. If a port does notexist, an error will occur (ERROR_FILE_NOT_FOUND) after attempting toopen the port, and the user should be notified that the port isn'tavailable.
Reading and Writing
Readingfrom and writing to communications ports in Win32 is very similar tofile input/output (I/O) in Win32. In fact, the functions thataccomplish file I/O are the same functions used for serial I/O. I/O inWin32 can be done either of two ways: overlapped or nonoverlapped. ThePlatform 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/Ois familiar to most developers because this is the traditional form ofI/O, where an operation is requested and is assumed to be complete whenthe function returns. In the case of overlapped I/O, the systemmay return to the caller immediately even when an operation is notfinished and will signal the caller when the operation completes. Theprogram may use the time between the I/O request and its completion toperform some "background" work.
Reading and writing in Win32 issignificantly different from reading and writing serial communicationsports 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
NonoverlappedI/O is very straightforward, though it has limitations. An operationtakes place while the calling thread is blocked. Once the operation iscomplete, the function returns and the thread can continue its work.This type of I/O is useful for multithreaded applications because whileone thread is blocked on an I/O operation, other threads can stillperform work. It is the responsibility of the application to serializeaccess to the port correctly. If one thread is blocked waiting for itsI/O operation to complete, all other threads that subsequently call acommunications API will be blocked until the original operationcompletes. For instance, if one thread were waiting for a ReadFile function to return, any other thread that issued a WriteFile function would be blocked.
Oneof the many factors to consider when choosing between nonoverlapped andoverlapped operations is portability. Overlapped operation is not agood choice because most operating systems do not support it. Mostoperating systems support some form of multithreading, however, somultithreaded nonoverlapped I/O may be the best choice for portabilityreasons.
Overlapped I/O
Overlapped I/O isnot as straightforward as nonoverlapped I/O, but allows moreflexibility and efficiency. A port open for overlapped operationsallows multiple threads to do I/O operations at the same timeand perform other work while the operations are pending. Furthermore,the behavior of overlapped operations allows a single thread to issuemany different requests and do work in the background while theoperations are pending.
In both single-threaded andmultithreaded applications, some synchronization must take placebetween issuing requests and processing the results. One thread willhave to be blocked until the result of an operation is available. Theadvantage is that overlapped I/O allows a thread to do some workbetween 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.
OverlappedI/O is the type of operation that the MTTTY sample uses. It creates athread that is responsible for reading the port's data and reading theport's status. It also performs periodic background work. The programcreates another thread exclusively for writing data out the port.
NoteApplicationssometimes 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 anapplication. Threads are less a strain on the system than processes butstill require system resources such as CPU time and memory. Anapplication that creates excessive threads may adversely affect theperformance of the entire system. A better use of threads is to createa different request queue for each type of job and to have a workerthread issue an I/O request for each entry in the request queue. Thismethod is used by the MTTTY sample provided with this article.
Anoverlapped I/O operation has two parts: the creation of the operationand the detection of its completion. Creating the operation entailssetting 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 anerror for an application to assume that a request for an overlappedoperation always yields an overlapped operation. If an operation iscompleted immediately, an application needs to be ready to continueprocessing normally. The second part of an overlapped operation is todetect its completion. Detecting completion of the operation involveswaiting for the event handle, checking the overlapped result, and thenhandling the data. The reason that there is more work involved with anoverlapped operation is that there are more points of failure. If anonoverlapped operation fails, the function just returns anerror-return result. If an overlapped operation fails, it can fail inthe creation of the operation or while the operation is pending. Youmay also have a time-out of the operation or a time-out waiting for thesignal that the operation is complete.
Reading
The ReadFile function issues a read operation. ReadFileExalso issues a read operation, but since it is not available on Windows95, it is not discussed in this article. Here is a code snippet thatdetails how to issue a read request. Notice that the function calls afunction to process the data if the ReadFile returns TRUE. Thisis the same function called if the operation becomes overlapped. Notethe fWaitingOnRead flag that is defined by the code; it indicateswhether or not a read operation is overlapped. It is used to preventthe 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 WaitForSingleObjectfunction, which will wait until the object is signaled. Once the eventis signaled, the operation is complete. This does not mean that it wascompleted 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.
NoteGetOverlappedResult 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, GetOverlappedResultcan be made to block until the operation completes. This effectivelyturns the overlapped operation into a nonoverlapped operation and isaccomplished by passing TRUE as the bWait parameter.
Hereis a code snippet that shows one way to detect the completion of anoverlapped read operation. Note that the code calls the same functionto process the data that was called when the operation completedimmediately. Also note the use of the fWaitingOnRead flag. Here itcontrols entry into the detection code, since it should be called onlywhen 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 thecommunications port is very similar to reading in that it uses a lot ofthe same APIs. The code snippet below demonstrates how to issue andwait 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 WaitForSingleObjectfunction to wait forever until the operation is completed; this maymake the thread or program appear to be "hung" when, in fact, the writeoperation is simply taking a long time to complete or flow control hasblocked the transmission. Status checking, discussed later, can detectthis condition, but doesn't cause the WaitForSingleObject to return. Three things can alleviate this condition:
- Place the code in a separate thread. Thisallows other threads to execute any functions they desire while ourwriter thread waits for the write to be completed. This is what theMTTTY sample does.
- Use COMMTIMEOUTS to cause the write to becompleted after a time-out period has passed. This is discussed morefully in the "Communications Time-outs" section later in this article.This is also what the MTTTY sample allows.
- Change the WaitForSingleObjectcall to include a real time-out value. This causes more problemsbecause if the program issues another operation while an olderoperation is still pending, new OVERLAPPED structures andoverlapped events need to be allocated. This type of recordkeeping isdifficult, particularly when compared to using a "job queue" design forthe 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 WaitForMultipleObjectsto return WAIT_TIMEOUT. This is not the same as a read or writeoperation timing out. Communications time-outs are described later inthis 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 wayto wait for an overlapped operation to be completed. For example, if anapplication needs to wait on another event handle, the first codesnippet 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 OVERLAPPEDstructure before the previous overlapped operation is completed. If anew overlapped operation is issued before a previous operation iscompleted, 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
Thereare two methods to retrieve the status of a communications port. Thefirst is to set an event mask that causes notification of theapplication 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. Infact, the WM_COMMNOTIFY message is not even part of the Win32 API. Thesecond method for retrieving the status of the communications port isto periodically call a few different status functions. Polling is, ofcourse, neither efficient nor recommended.
Communications Events
Communicationsevents can occur at any time in the course of using a communicationsport. The two steps involved in receiving notification ofcommunications events are as follows:
- SetCommMask sets the desired events that cause a notification.
- WaitCommEventissues a status check. The status check can be an overlapped ornonoverlapped 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 | Thelast character in the output buffer was sent to the serial port device.If a hardware buffer is used, this flag only indicates that all datahas been sent to the hardware. There is no way to detect when thehardware buffer is empty without talking directly to the hardware witha 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 OVERLAPPEDstructure. The function blocks the calling thread until the occurrenceof one of the events. If an event never occurs, the thread may blockindefinitely.
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;
NoteTheMicrosoft Win32 SDK Knowledge Base documents a problem with Windows 95and the EV_RING flag. The above code never returns in Windows 95because the EV_RING event is not detected by the system; Windows NTproperly reports the EV_RING event. Please see the Win32 SDK KnowledgeBase for more information on this bug.
As noted, thecode above can be blocked forever if an event never occurs. A bettersolution would be to open the port for overlapped operation and waitfor 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 foroverlapped reading. In fact, the MTTTY sample implements its readingand 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 WaitCommEventfunction returns in the first thread. This side effect is universal forports open for nonoverlapped I/O. If a thread is blocked on anycommunications function and another thread calls a communicationsfunction, the second thread is blocked until the communicationsfunction returns in the first thread. The second interesting note aboutthese 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 waitsfor the data to arrive. This is particularly useful when a port is openfor nonoverlapped operation because the program does not need to pollfor incoming data; the program is notified of the incoming data by theoccurrence of the EV_RXCHAR event. Initial attempts to code thissolution often produce the following pseudocode, including oneoversight covered later in this section:
DWORD dwCommEvent;
DWORD dwRead;
char chRead;
if (!SetCommMask(hComm, EV_RXCHAR))
// Error setting communications event mask.
for ( ; ; ) {
if (WaitCommEvent(hComm, &dwCommEvent, NULL)) {
if (ReadFile(hComm, &chRead, 1, &dwRead, NULL))
// A byte has been read; process it.
else
// An error occurred in the ReadFile call.
break;
}
else
// Error in WaitCommEvent.
break;
}
The above code waits for an EV_RXCHAR event to occur. When this happens, the code calls ReadFileto read the one byte received. The loop starts again, and the codewaits for another EV_RXCHAR event. This code works fine when one or twobytes arrive in quick succession. The byte reception causes theEV_RXCHAR event to occur. The code reads the byte. If no other bytearrives before the code calls WaitCommEvent again, then all is fine; the next byte to arrive will cause the WaitCommEventfunction to indicate the occurrence of the EV_RXCHAR event. If anothersingle byte arrives before the code has a chance to reach the WaitCommEventfunction, then all is fine, too. The first byte is read as before; thearrival of the second byte causes the EV_RXCHAR flag to be setinternally. When the code returns to the WaitCommEvent function, it indicates the occurrence of the EV_RXCHAR event and the second byte is read from the port in the ReadFile call.
Theproblem with the above code occurs when three or more bytes arrive inquick succession. The first byte causes the EV_RXCHAR event to occur.The second byte causes the EV_RXCHAR flag to be set internally. Thenext time the code calls WaitCommEvent, it indicates theEV_RXCHAR event. Now, a third byte arrives at the communications port.This third byte causes the system to attempt to set the EV_RXCHAR flaginternally. Because this has already occurred when the second bytearrived, the arrival of the third byte goes unnoticed. The codeeventually will read the first byte without a problem. After this, thecode will call WaitCommEvent, and it indicates the occurrenceof the EV_RXCHAR event (from the arrival of the second byte). Thesecond byte is read, and the code returns to the WaitCommEventfunction. The third byte waits in the system's internal receive buffer.The code and the system are now out of sync. When a fourth byte finallyarrives, the EV_RXCHAR event occurs, and the code reads a single byte.It reads the third byte. This will continue indefinitely.
Thesolution to this problem seems as easy as increasing the number ofbytes requested in the read operation. Instead of requesting a singlebyte, the code could request two, ten, or some other number of bytes.The problem with this idea is that it still fails when two or moreextra bytes above the size of the read request arrive at the port inquick succession. So, if two bytes are read, then four bytes arrivingin quick succession would cause the problem. Ten bytes requested wouldstill fail if twelve bytes arrived in quick succession.
The realsolution to this problem is to read from the port until no bytes areremaining. The following pseudocode solves the problem by reading in aloop until zero characters are read. Another possible method would beto call ClearCommError to determine the number of bytes in thebuffer and read them all in one read operation. This method requiresmore sophisticated buffer management, but it reduces the number ofreads when a lot of data arrives at once.
DWORD dwCommEvent;
DWORD dwRead;
char chRead;
if (!SetCommMask(hComm, EV_RXCHAR))
// Error setting communications event mask
for ( ; ; ) {
if (WaitCommEvent(hComm, &dwCommEvent, NULL)) {
do {
if (ReadFile(hComm, &chRead, 1, &dwRead, NULL))
// A byte has been read; process it.
else
// An error occurred in the ReadFile call.
break;
} while (dwRead);
}
else
// Error in WaitCommEvent
break;
}
The above code does not work correctly without settingthe proper time-outs. Communications time-outs, discussed later, affectthe behavior of the ReadFile operation in order to cause it toreturn without waiting for bytes to arrive. Discussion of this topicoccurs later in the "Communications Time-outs" section of this article.
Theabove caveat regarding EV_RXCHAR also applies to EV_RXFLAG. If flagcharacters arrive in quick succession, EV_RXFLAG events may not occurfor all of them. Once again, the best solution is to read all bytesuntil none remain.
The above caveat also applies to other eventsnot related to character reception. If other events occur in quicksuccession some of the notifications will be lost. For instance, if theCTS line voltage starts high, then goes low, high, and low again, anEV_CTS event occurs. There is no guarantee of how many EV_CTS eventswill actually be detected with WaitCommEvent if the changes in the CTS line happen quickly. For this reason, WaitCommEventcannot be used to keep track of the state of the line. Line status iscovered in the "Modem Status" section later in this article.
Error Handling and Communications Status
One of the communications event flags specified in the call to SetCommMaskis possibly EV_ERR. The occurrence of the EV_ERR event indicates thatan error condition exists in the communications port. Other errors canoccur in the port that do not cause the EV_ERR event to occur. Ineither case, errors associated with the communications port cause allI/O operations to be suspended until removal of the error condition. ClearCommError is the function to call to detect errors and clear the error condition.
ClearCommErroralso provides communications status indicating why transmission hasstopped; it also indicates the number of bytes waiting in the transmitand receive buffers. The reason why transmission may stop is because oferrors or to flow control. The discussion of flow control occurs laterin this article.
Here is some code that demonstrates how to call ClearCommError:
COMSTAT comStat;
DWORD dwErrors;
BOOL fOOP, fOVERRUN, fPTO, fRXOVER, fRXPARITY, fTXFULL;
BOOL fBREAK, fDNS, fFRAME, fIOE, fMODE;
// Get and clear current errors on the port.
if (!ClearCommError(hComm, &dwErrors, &comStat))
// Report error in ClearCommError.
return;
// Get error flags.
fDNS = dwErrors & CE_DNS;
fIOE = dwErrors & CE_IOE;
fOOP = dwErrors & CE_OOP;
fPTO = dwErrors & CE_PTO;
fMODE = dwErrors & CE_MODE;
fBREAK = dwErrors & CE_BREAK;
fFRAME = dwErrors & CE_FRAME;
fRXOVER = dwErrors & CE_RXOVER;
fTXFULL = dwErrors & CE_TXFULL;
fOVERRUN = dwErrors & CE_OVERRUN;
fRXPARITY = dwErrors & CE_RXPARITY;
// COMSTAT structure contains information regarding
// communications status.
if (comStat.fCtsHold)
// Tx waiting for CTS signal
if (comStat.fDsrHold)
// Tx waiting for DSR signal
if (comStat.fRlsdHold)
// Tx waiting for RLSD signal
if (comStat.fXoffHold)
// Tx waiting, XOFF char rec'd
if (comStat.fXoffSent)
// Tx waiting, XOFF char sent
if (comStat.fEof)
// EOF character received
if (comStat.fTxim)
// Character waiting for Tx; char queued with TransmitCommChar
if (comStat.cbInQue)
// comStat.cbInQue bytes have been received, but not read
if (comStat.cbOutQue)
// comStat.cbOutQue bytes are awaiting transfer
Modem Status (a.k.a. Line Status)
The call to SetCommMaskmay include the flags EV_CTS, EV_DSR, EV_RING, and EV_RLSD. These flagsindicate changes in the voltage on the lines of the serial port. Thereis no indication of the actual status of these lines, just that achange occurred. The GetCommModemStatus function retrieves theactual state of these status lines by returning a bit mask indicating a0 for low or no voltage and 1 for high voltage for each of the lines.
Please note that the term RLSD (Receive Line Signal Detect) is commonly referred to as the CD (Carrier Detect) line.
NoteThe EV_RING flag does not work in Windows 95 as mentioned earlier. The GetCommModemStatus function, however, does detect the state of the RING line.
Changes in these lines may also cause a flow-control event. The ClearCommError function reports whether transmission is suspended because of flow control. If necessary, a thread may call ClearCommErrorto detect whether the event is the cause of a flow-control action. Flowcontrol is covered in the "Flow Control" section later in this article.
Here is some code that demonstrates how to call GetCommModemStatus:
DWORD dwModemStatus;
BOOL fCTS, fDSR, fRING, fRLSD;
if (!GetCommModemStatus(hComm, &dwModemStatus))
// Error in GetCommModemStatus;
return;
fCTS = MS_CTS_ON & dwModemStatus;
fDSR = MS_DSR_ON & dwModemStatus;
fRING = MS_RING_ON & dwModemStatus;
fRLSD = MS_RLSD_ON & dwModemStatus;
// Do something with the flags.
Extended Functions
The driverwill automatically change the state of control lines as necessary.Generally speaking, changing status lines is under the control of adriver. If a device uses communications port control lines in a mannerdifferent from RS-232 standards, the standard serial communicationsdriver will not work to control the device. If the standard serialcommunications driver will not control the device, a custom devicedriver is necessary.
There are occasions when standard control lines areunder the control of the application instead of the serialcommunications driver. For instance, an application may wish toimplement its own flow control. The application would be responsiblefor changing the status of the RTS and DTR lines. EscapeCommFunction directs a communications driver to perform such extended operations. EscapeCommFunctioncan make the driver perform some other function, such as setting orclearing a BREAK condition. For more information on this function,consult the Platform SDK documentation, the Microsoft Win32 SDKKnowledge Base, or the Microsoft Developer Network (MSDN) Library.
Serial Settings
DCB Settings
Themost crucial aspect of programming serial communications applicationsis the settings in the Device-Control Block (DCB) structure. The mostcommon errors in serial communications programming occur ininitializing the DCB structure improperly. When the serialcommunications functions do not behave as expected, a close examinationof the DCB structure usually reveals the problem.
There are three ways to initialize a DCB structure. The first method is to use the function GetCommState. This function returns the current DCB in use for the communications port. The following code shows how to use the GetCommState function:
DCB dcb = {0};
if (!GetCommState(hComm, &dcb))
// Error getting current DCB settings
else
// DCB is ready for use.
The second method to initialize a DCB is to use a function called BuildCommDCB.This function fills in the baud, parity type, number of stop bits, andnumber of data bits members of the DCB. The function also sets theflow-control members to default values. Consult the documentation ofthe BuildCommDCB function for details on which default valuesit uses for flow-control members. Other members of the DCB areunaffected by this function. It is the program's duty to make sure theother members of the DCB do not cause errors. The simplest thing to doin this regard is to initialize the DCB structure with zeros and thenset the size member to the size, in bytes, of the structure. If thezero initialization of the DCB structure does not occur, then there maybe nonzero values in the reserved members; this produces an error whentrying to use the DCB later. The following function shows how toproperly use this method:
DCB dcb;
FillMemory(&dcb, sizeof(dcb), 0);
dcb.DCBlength = sizeof(dcb);
if (!BuildCommDCB("9600,n,8,1", &dcb)) {
// Couldn't build the DCB. Usually a problem
// with the communications specification string.
return FALSE;
}
else
// DCB is ready for use.
The third method to initialize a DCB structure is to doit manually. The program allocates the DCB structure and sets eachmember with any value desired. This method does not deal well withchanges to the DCB in future implementations of Win32 and is notrecommended.
An application usually needs to set some of the DCBmembers differently than the defaults or may need to modify settings inthe middle of execution. Once proper initialization of the DCB occurs,modification of individual members is possible. The changes to the DCBstructure do not have any effect on the behavior of the port untilexecution of the SetCommState function. Here is a section ofcode that retrieves the current DCB, changes the baud, and thenattempts to set the configuration:
DCB dcb;
FillMemory(&dcb, sizeof(dcb), 0);
if (!GetCommState(hComm, &dcb)) // get current DCB
// Error in GetCommState
return FALSE;
// Update DCB rate.
dcb.BaudRate = CBR_9600 ;
// Set new state.
if (!SetCommState(hComm, &dcb))
// Error in SetCommState. Possibly a problem with the communications
// port handle or a problem with the DCB structure itself.
Here is an explanation of each of the members of the DCB and how they affect other parts of the serial communications functions.
NoteMostof this information is from the Platform SDK documentation. Becausedocumentation is the official word in what the members actually are andwhat they mean, this table may not be completely accurate if changesoccur in the operating system.
Table 2. The DCB Structure Members
Member | Description | |||||||||||||||||||||||||||||||||||||||||
DCBlength | Size, in bytes, of the structure. Should be set before calling SetCommState to update the settings. | |||||||||||||||||||||||||||||||||||||||||
BaudRate | Specifies the baud at which the communications device operates. This member can be an actual baud value, or a baud index. | |||||||||||||||||||||||||||||||||||||||||
fBinary | Specifieswhether binary mode is enabled. The Win32 API does not supportnonbinary mode transfers, so this member should be TRUE. Trying to useFALSE will not work. | |||||||||||||||||||||||||||||||||||||||||
fParity | Specifieswhether parity checking is enabled. If this member is TRUE, paritychecking is performed and parity errors are reported. This should notbe confused with the Parity member, which controls the type of parity used in communications. | |||||||||||||||||||||||||||||||||||||||||
fOutxCtsFlow | Specifieswhether the CTS (clear-to-send) signal is monitored for output flowcontrol. If this member is TRUE and CTS is low, output is suspendeduntil CTS is high again. The CTS signal is under control of the DCE(usually a modem), the DTE (usually the PC) simply monitors the statusof this signal, the DTE does not change it. | |||||||||||||||||||||||||||||||||||||||||
fOutxDsrFlow | Specifieswhether the DSR (data-set-ready) signal is monitored for output flowcontrol. If this member is TRUE and DSR is low, output is suspendeduntil DSR is high again. Once again, this signal is under the controlof the DCE; the DTE only monitors this signal. | |||||||||||||||||||||||||||||||||||||||||
fDtrControl | Specifies the DTR (data-terminal-ready) input flow control. This member can be one of the following values: | |||||||||||||||||||||||||||||||||||||||||
Value | Meaning | |||||||||||||||||||||||||||||||||||||||||
DTR_CONTROL_DISABLE | Lowers the DTR line when the device is opened. The application can adjust the state of the line with EscapeCommFunction. | |||||||||||||||||||||||||||||||||||||||||
DTR_CONTROL_ENABLE | Raises the DTR line when the device is opened. The application can adjust the state of the line with EscapeCommFunction. | |||||||||||||||||||||||||||||||||||||||||
DTR_CONTROL_HANDSHAKE | Enables DTR flow-control handshaking. If this value is used, it is an error for the application to adjust the line with EscapeCommFunction. | |||||||||||||||||||||||||||||||||||||||||
fDsrSensitivity | Specifieswhether the communications driver is sensitive to the state of the DSRsignal. If this member is TRUE, the driver ignores any bytes received,unless the DSR modem input line is high. | |||||||||||||||||||||||||||||||||||||||||
fTXContinueOnXoff | Specifieswhether transmission stops when the input buffer is full and the driverhas transmitted the XOFF character. If this member is TRUE,transmission continues after the XOFF character has been sent. If thismember is FALSE, transmission does not continue until the input bufferis within XonLim bytes of being empty and the driver has transmittedthe XON character. | |||||||||||||||||||||||||||||||||||||||||
fOutX | Specifieswhether XON/XOFF flow control is used during transmission. If thismember is TRUE, transmission stops when the XOFF character is receivedand starts again when the XON character is received. | |||||||||||||||||||||||||||||||||||||||||
fInX | Specifieswhether XON/XOFF flow control is used during reception. If this memberis TRUE, the XOFF character is sent when the input buffer comes withinXoffLim bytes of being full, and the XON character is sent when theinput buffer comes within XonLim bytes of being empty. | |||||||||||||||||||||||||||||||||||||||||
fErrorChar | Specifies whether bytes received with parity errors are replaced with the character specified by the ErrorChar member. If this member is TRUE and the fParity member is TRUE, replacement occurs. | |||||||||||||||||||||||||||||||||||||||||
fNull | Specifies whether null bytes are discarded. If this member is TRUE, null bytes are discarded when received. | |||||||||||||||||||||||||||||||||||||||||
fRtsControl | Specifiesthe RTS (request-to-send) input flow control. If this value is zero,the default is RTS_CONTROL_HANDSHAKE. This member can be one of thefollowing values: | |||||||||||||||||||||||||||||||||||||||||
Value | Meaning | |||||||||||||||||||||||||||||||||||||||||
RTS_CONTROL_DISABLE | Lowers the RTS line when the device is opened. The application can use EscapeCommFunction to change the state of the line. | |||||||||||||||||||||||||||||||||||||||||
RTS_CONTROL_ENABLE | Raises the RTS line when the device is opened. The application can use EscapeCommFunction to change the state of the line. | |||||||||||||||||||||||||||||||||||||||||
RTS_CONTROL_HANDSHAKE | EnablesRTS flow-control handshaking. The driver raises the RTS line, enablingthe DCE to send, when the input buffer has enough room to receive data.The driver lowers the RTS line, preventing the DCE to send, when theinput buffer does not have enough room to receive data. If this valueis used, it is an error for the application to adjust the line with EscapeCommFunction. | |||||||||||||||||||||||||||||||||||||||||
DynDNS공부를 해보자/프로그래밍 2008. 6. 9. 16:38dns-host-servers_sd_a_copy.pdf
https://www.dyndns.com/ 업데이트 구문(https://www.dyndns.com/developers/specs/syntax.html) http://username:password@members.dyndns.org/nic/update?hostname=yourhostname&myip=ipaddress&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG '공부를 해보자 > 프로그래밍' 카테고리의 다른 글
전자사전 조사중내 삶의 이야기/잡다한 이야기 2008. 5. 2. 08:32아이리버 딕플 D30
누리안 X20 '내 삶의 이야기 > 잡다한 이야기' 카테고리의 다른 글
좋은 부모가 되기 위한 책읽기내 삶의 이야기/육아 2008. 4. 7. 22:59(관련글 - 혜민아빠 책과 사진 사랑)
작년엔 그래도 틈틈히 책을 많이 읽었는데 올해는 잘 안된다. 읽고 생각하고 정리하고 하는게 엄두가 잘 안난다. 없는 시간을 내서 하지 않으면 못하는 거겠지? 아무튼 정리해 놓고 시간나는데로 찾아봐야겠다. 1. 부모의 역할이 뭔지, 어떻게 해야 할지 답을 제시 해주는 책은? 부모 역할 훈련 토마스 고든 지음, 이훈구 옮김 / 양철북 2. 제대로된 부모가 될 수 있도록 도와 주는책 아이에게 행복을 주는 비결 1 스티브 비덜프 지음, 전순영 옮김 / 북하우스 3. 아이에게 돈관리 방법을 어떻게 해야 할지 알려 주는 책 공짜 용돈은 없다 졸린 고드프리 지음, 홍은주 옮김 / 이콘 4. 아이가 책을 친구 삼을 수 있도록 책을 골라 주려면 어떻게 해야 하나? 내 아이를 위한 일생의 독서 계획 저우예후이 지음, 최경숙 옮김 / 바다출판사 5. 똑똑한 여자아이로 키우고 싶다면 어떤 책을 선택 해야 하는가? 딸은 세상의 중심으로 키워라 마츠나가 노부후미 지음, 이수경 옮김 / 21세기북스(북이십일) 6. 멀어져버린 딸과의 관계를 회복시키기 위한 해결책을 제시하는 책은? 딸에게 사랑 받는 아버지들의 48가지 매력 다고 아키라 지음, 채숙향 옮김 / 지식여행 '내 삶의 이야기 > 육아' 카테고리의 다른 글
OCW공부를 해보자/프로그래밍 2008. 4. 7. 09:02몇년전에 처음봤을때는 엄두가 나지 않아서 "좋쿠나~~~"라고만 생각하고 있었던 곳인데 다시 가보니 코스도 방대해지고 좋아진 것 같다. 물론 지금도 영어의 압박으로 엄두가 나진 않지만... 볼만한 코스가 있는지 찾아보는 것부터 시작해 봐야겠다. ^^ '공부를 해보자 > 프로그래밍' 카테고리의 다른 글
|