Program did not write the article for a long time, and recently to compile a serial communication terminal program busy for nearly a month, was found in the Win32 API has a lot of communication problems, and many other serial communications in the article did not Turning to the issue, talk about where to concentrate. This is not a comprehensive how to write a serial communication program, but rather to discuss some practical problems.
1 Select the means of communication - synchronous or asynchronous
As in the "Serial communications in Microsoft Win32" and other articles mentioned, synchronization (NonOverLapped) approach is a relatively simple way to write code to be significantly less than the length of the asynchronous (OverLapped) way, I began to write synchronization the whole routine, to work in normal Windows98, Windows2000, but later tested and found to receive normal, but the one to send data, the program will stop there, because synchronization mode should be is if there is a communication Api in operation, another One will block until the completion of an operation, so when reading the data when the thread stay in WaitCommEvent, WriteFile stopped there. I tested my hands all the examples of serial communication program, found that all the procedures for using the synchronization mode Windows 2000 does not work correctly under all of this I could not find a solution, was found on the site in Iczelion article referred to under NT and 9x serial communication processing is different, simply do not expect to under NT or Windows 2000 while using synchronous mode send and receive data and I have to use asynchronous mode to the communication routines to re-write it again.
Therefore, the recommendations on this issue is: If the program is only intended to work in Win9x, the sake of simplicity, you can write programs using synchronous mode, if the program intends to work in the NT, you can then use the asynchronous mode must be written.
2 Win32 Communications API Bug one --- CommConfigDialog
CommConfigDialog is built into the system serial port settings dialog box pops up the API, we are set in the Device Manager dialog box is the serial port parameters, use the API without first opening the port, it is not for an already open port, but only the contents of the DCB is completed to the dialog box, press the OK when the results after the deposit back to the input DCB data structure, as when set to the serial port on the results, that is, you had to do.
CommCinfigDialog defined as follows:
BOOL CommConfigDialog (
LPTSTR lpszName, / / pointer to device name string
HWND hWnd, / / handle to window
LPCOMMCONFIG lpCC / / pointer to comm. Configuration structure
);
However, the use of found, the dialog box can sometimes, sometimes not get out, the final summing up the experience of the problem structure in COMMCONFIG dwSize field, COMMCONFIG defined as follows:
typedef struct _COMM_CONFIG (
DWORD dwSize;
WORD wVersion;
WORD wReserved;
DCB dcb;
DWORD dwProviderSubType;
DWORD dwProviderOffset;
DWORD dwProviderSize;
WCHAR wcProviderData [1];
) COMMCONFIG, * LPCOMMCONFIG;
In the parameters, wVersion to fill 100h, dwProviderSubType to fill one, but can not fill sizeof COMMCONFIG dwSize, I found that if a certain ratio should be set dwSize to sizeof COMMCONFIG dialog box out, so I used the code defines a large enough buffer for the address structure:
_CommConfigDialog Proc
local @ stCC [256]: BYTE
pushad
invoke RtlZeroMemory, addr @ stCC, sizeof @ stCC
mov (COMMCONFIG ptr @ stCC). dwSize, 256
mov (COMMCONFIG ptr @ stCC). wVersion, 100h
mov (COMMCONFIG ptr @ stCC). dwProviderSubType, 1
invoke CommConfigDialog, addr [esi]. szPortName, [esi]. hWnd, addr @ stCC
popad
ret
_CommConfigDialog Endp
3 Win32 Communications API Bug bis --- BuildCommDCB
BuildCommDCB function is to a string such as com1: 9600, n, 8,1 such a conversion to the specific data to fill in DCB, but in use there, I found that I use it to transform like com1: 9600, e, 7,1 with a parity bit like a string, it does not always give me this e conversion in the past, set up the serial port of a look into 9600, n, 7,1, and return the above-mentioned CommConfigDialog The results used to set the serial port is correct, by comparison, found that the problem lies in DCB.fbits.fParity this bit, only this bit set to 1, parity bit is valid, but BuildCommDCB precisely missed this bit, If you want to use all BuildCommDCB, do not forget to add the DCB.fbits.fParity settings back, I used the code is:
_BuildCommDCB Proc _lpszPara, _lpstDCB
pushad
mov esi, _lpstDCB
assume esi: ptr DCB
invoke RtlZeroMemory, esi, sizeof DCB
invoke BuildCommDCB, _lpszPara, esi
;************************************************* *******************
; Under the parity bit added to set DCB in DCB.fbits.fParity field
;************************************************* *******************
mov dword ptr [esi]. fbits, 0010b
cld
@ @:
lodsb
or al, al
jz @ F
cmp al ,''=''
jz _BCD_Check
cmp al ,'',''
jnz @ B
_BCD_Check:
lodsb
or al, al
jz @ F
or al, 20h
cmp al,''n''
jnz @ B
;************************************************* *******************
; Scan = n or, n parity bit is canceled
;************************************************* *******************
mov esi, _lpstDCB
and dword ptr [esi]. fbits, not 0010b
@ @:
popad
ret
_BuildCommDCB Endp
4 Win32 programming in general process of communication
Because the synchronization method is relatively simple, here is about the way the process of induction, many of the other article mentioned Windows communication API has more than 20, they are:
BuildCommDCB
BuildCommDCBAndTimeouts
ClearCommBreak
ClearCommError
CommConfigDialog
EscapeCommFunction
GetCommConfig
GetCommMask
GetCommModemStatus
GetCommProperties
GetCommState
GetCommTimeouts
GetDefaultCommConfig
PurgeComm
SetCommBreak
SetCommConfig
SetCommMask
SetCommState
SetCommTimeouts
SetDefaultCommConfig
SetupComm
TransmitCommChar
WaitCommEvent
I just see the API, when do not know how to use them, but not all of these API are to be used, for example, you want to detect the current serial port settings can only SetCommState without GetCommProperties and GetCommConfig, although they return to The information may be more. Similarly, if you want to use some default values, such as buffer size and timeout time, etc., then SetupComm and BuildCommDCBAndTimeouts, SetCommTimeouts can not, TransmitCommChar is immediately sent into the priority sequence used to send a character, usually rarely used, the following must be used about the API and use these steps:
Establishment of Event - with CreateEvent
invoke CreateEvent, NULL, TRUE, FALSE, NULL
Asynchronous serial mode operation OVERLAPPED structure must be defined, which hEvent must establish their own, you have to define two OVERLAPPED structure, one for reading one for writing, of course, must also create two Event, put them in OVERLAPPED.hEvent
Open the serial port - use CreateFile
invoke CreateFile, addr szPortName, GENERIC_READ or GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL
Note that with asynchronous mode must be specified FILE_FLAG_OVERLAPPED, and papers must be OPEN_EXISTING, read and write must be GENERIC_READ or GENERIC_WRITE
Set serial port parameters - with SetCommState
invoke SetCommState, hCom, addr dcbx
hCom is in front of the handle to open a successful return, dcbx is the data structure DCB, which includes the specific parameters of communication, as the establishment of this parameter, you can fill out their own, you can also use the previously mentioned BuildCommDCB or CommConfigDialog fill
The establishment of the thread reading data
Here, you can start reading data, and generally we are in the main thread to write data, because writing is something we can control, and reading the data when we do not know when it will come, so I want to set up a new thread Yonglai Reading data, in this thread, we cycle to read serial port using ReadFile, while the state line with WaitCommEvent detection.
To test communication status, as CTS signals, RingIn and so on - with SetCommMask, WaitCommEvent, ClearCommError, GetCommModemStatus
invoke SetCommMask, hCom, EV_BREAK or EV_CTS or EV_DSR or EV_ERR or EV_RING or EV_RLSD or EV_RXCHAR or EV_RXFLAG or EV_TXEMPTY
SetCommMask designated WaitCommEvent to wait for the event name, please check the manual for the specific parameters
invoke WaitCommEvent, hCom, addr dwEvent, NULL
WaitCommEvent wait until one of the specified event occurs SetCommMask
invoke ClearCommError, hCom, addr dwError, addr stComStat
In WaitCommEvent later, use the clear events ClearCommError Flag, for the next round of WaitCommEvent, while the API can get more detailed event information
invoke GetCommModemStatus, hCom, addr dwModemStatus
Similarly, GetCommModemStatus is used to obtain serial line status, such as CTS, RING, etc., when WaitCommEvent return, only that the state has changed, such as CTS, etc., but specifically into the On or Off to also depend on the API obtain more detailed information
Reading data - use ReadFile
invoke ReadFile, hCom, addr szBuffer, sizeof szBuffer, addr dwBytesRead, addr stReadState
The last parameter is defined at the beginning of the OVERLAPPED structure's address, designated it the way that is asynchronous read mode, the API will return immediately, and the latter use
invoke GetOverlappedResult, hCom, addr stReadState, addr dwBytesRead, FALSE
Read the rest of the data
Close the port at the end - stop waiting and close ports WaitCommEvent CloseHandle
Normal procedures will remain in WaitCommEvent wait, when to terminate the thread when the process must withdraw from the WaitCommEvent in, this time to use
In accordance with the instructions on the Win32 manual, parameters NULL's SetCommMask make another thread in the WaitCommEvent immediately returned, and then the port is closed with CloseHandle
invoke CloseHandle, hCom
5 Win32 Communications API Bug bis --- SetCommMask and WaitCommEvent
Strictly speaking it should not be a Bug, but by accident, I found that sometimes I can not read the thread end, tracking found to be parked in the WaitCommEvent, this description sometimes invoke SetCommMask, hCom, NULL does not make WaitCommEvent exit I last used by: the SetCommMask a later invoke SetEvent, stReadState.hEvent, to read the OVERLAPPED structure Event Set for WaitCommEvent think that Event occurs, it will immediately return, perhaps this is not universal , but if your program is stopped at the WaitCommEvent place a try.
6 How to read the thread in the cycle of preparation
In accordance with the "Serial communications in Microsoft Win32" article in the routine, time cycle can be:
# Define READ_TIMEOUT 500 / / milliseconds
DWORD dwRes;
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);
)
)
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;
)
)
This is a procedure in 98 normal, but very unfortunate that under the Win2000, ReadFile always returns the correct time, not to return ERROR_IO_PENDING, make the following WaitForSingleObject cycle non-existent, The problem is, ReadFile returns the correct time is read every time 1 byte, the result program works very strange, even if many of the characters in the buffer, the program also can only read one character each time, to wait until the send operation character or do other changes to the state line to read the next character , I do not know this strange phenomenon is how it happened, anyway I solved the way is ReadFile Qian Zai add WaitCommEvent, Zhen Zheng Yi Hou Cai until EV_RXCHAR go ReadFile, Dao Finally, I Yong's Xunhuan is that, without an article in Suiran example is the case, but it also in windows9x and work well under windows2000:
. While dwFlag & IF_CONNECT
;************************************************* *******************
; Detection of other communication events
; If detected and defined lpProcessEvent call the lpProcessEvent
;************************************************* *******************
invoke WaitCommEvent, hCom, addr @ dwEvent, NULL; addr stReadState
push eax
invoke ClearCommError, hCom, addr @ dwError, addr @ stComStat
pop eax
. If eax == 0
invoke GetLastError
. If eax == ERROR_IO_PENDING
or dwFlag, IF_WAITING
. Endif
. Else
; Here is the line handling state
. Endif
;************************************************* *******************
; If you do not have to wait for asynchronous read process, the read port
;************************************************* *******************
. If! (DwFlag & IF_WAITING)
mov @ dwBytesRead, 0
invoke ReadFile, hCom, addr @ szBuffer, sizeof @ szBuffer, addr @ dwBytesRead, addr stReadState
. If eax == FALSE
or dwFlag, IF_WAITING
invoke GetLastError
. If eax! = ERROR_IO_PENDING
; Here is the error handling
. Endif
. Else
and dwFlag, not IF_WAITING
mov eax, @ dwBytesRead
. If eax! = 0
; Here is the received data processing
. Endif
. Endif
. Endif
;************************************************* *******************
; If the asynchronous read port, then wait
;************************************************* *******************
. If dwFlag & IF_WAITING
invoke WaitForSingleObject, stReadState.hEvent, 200
. If eax == WAIT_OBJECT_0
and dwFlag, not IF_WAITING
invoke GetOverlappedResult, hCom, addr stReadState, addr @ dwBytesRead, FALSE
. If eax! = 0
mov eax, @ dwBytesRead
. If eax! = 0
; Here is the received data processing
. Endif
. Else
; Here is the error handling
invoke ClearCommError, hCom, addr @ dwError, addr @ stComStat
. Endif
. Else
; Here is the error handling
. Endif
. Endif
. Endw
7 flow control problems
In flow control mode for the "no" and "software controlled" circumstances, basically no problem, but the "hardware control" under, win32 manual control method described in RTS_CONTROL_HANDSHAKE meaning is:
Enables RTS handshaking. The driver raises the RTS line when the "type-ahead" (input) buffer is less than one-half full and lowers the RTS line when the buffer is more than three-quarters full. If handshaking is enabled, it is an error for the application to adjust the line by using the EscapeCommFunction function.
That is, when the buffer is full when the fast OFF RTS will automatically send notice to the other suspended, when the buffer is empty again came out, RTS will be automatically ON, but I found that when RTS OFF after changing the buffer even if you have empty , RTS will not automatically ON, causing the other party do not stop there, sent in, so if the hardware flow control to use it, even with the best detection in the receiving buffer size after the judge, after the concrete is used to return ClearCommError The COMSTAT.cbInQue, when the buffer is already empty out when to use invoke EscapeCommFunction, hCom, SETRTS re-RTS is set to ON.
These are the serial communication programming I found the real problem, if there are discrepancies and where practical, or other questions, welcome to the forum of programming.
Recommended links:
Basic Or VB Or VB DotNet ReportDell CEO or forced to replace him within a six potential successors to the electionUsing warm and intimate small music prompted the fish that you're familiar with the music fishJinshan Jinshan Nu Pi Typing Through Repeated Fake "Li Gui," Poisonous Pit UsersMy Favorite PrinterIntroduction to Fibre Channel based: FCIP and iSCSI comparisonRegistry combat Collection - "Operation" Change Collectionavi to mp4 converter free downloadBrowser Tools for youOrient Securities Executive Assistant Shu Wang: grab the share of off-site transactionsMy Favorite Management And DistributionAlternative workplace quit: to a rival company to do an undercover intelligence probemov to mpeg converter freeM2TS to movRealplayer H.264Navigator V6.0 grand publicCustomer is not his wife is a lover of God is