The following are some notes I made when reading "communications programming for Windows 95", so most of the topics are the same as chapter 3 in this book. some structure and API announcements are copied from VC 5.0 on-line help.
These things mainly talk about how to communicate with the serial port on the Win32 platform. it may be helpful for those who understand the serial port communication, but it is unclear whether there are programer available APIs on the Win32 platform (like me? : P) I just want to sort it out. More clearly, I may need to flip through on-line help or books. if you want to try a program under Win32 that controls modem (such as dialing and communication), but you do not know about serial port, then you should look for another book that talks about these things.
1. Enable a serial port
Enable the serial port device by using creatfile ().
Handle createfile ( Lptstr lpfilename, // pointer to name of the file DWORD dwdesiredaccess, // access (read-write) Mode DWORD dw1_mode, // share mode Lpsecurity_attributes lpsecurityattributes, // pointer to security attributes DWORD dwcreationdistribution, // how to create DWORD dwflagsandattributes, // file attributes Handle htemplatefile // handle to file with attributes to copy ); |
Use createfile () API.
Lpfilename is "COM1" or "com2"
Dwdersiredaccess is generally generic_read | generic_write
Dww.mode "must" be 0, that is, it cannot be shared, but different threads in the same process can be shared once enabled.
Lpsecurityattributes is generally null
Dwcreateiondistributon here "must" be open_existing
Dwflagsandattributes defines the enabled attributes. If it is set to file_flag_overlapped, asynchronous I/O can be used.
Htemplatefile "must" be null
Return archive handle
Set the size of the serial port transfer and receipt Buffer
After the serial port is enabled, you can call setupcomm () to configure the Transfer Buffer and the receive buffer. if setupcomm () is not called, Win95 configures the preset buffer.
Bool setupcomm ( Handle hfile, // handle of communications device DWORD dwinqueue, // size of input buffer DWORD dwoutqueue // size of output buffer ); |
2. Disable serial port File
Use the General closehandle.
Bool closehandle ( Handle hobject // handle to object to close ) |
3. Obtain the seial port information
In Win32, the information used for communication is expressed in the comatrix drop structure. (Of course, it is not just the serial port.) getcomatrix roperties () can be used to obtain the information:
Bool getcomatrix roperties ( Handle hfile, // handle of communications device Lpcomatrix drop // address of communications properties Structure ); |
Comatrix Drop looks like this:
Typedef struct _ comatrix drop {// cmmp Word wpacketlength; // packet size, in bytes Word wpacketversion; // packet version DWORD dwservicemask; // services implemented DWORD dwreserved1; // Reserved DWORD dwmaxtxqueue; // Max TX bufsize, in bytes DWORD dwmaxrxqueue; // Max RX bufsize, in bytes DWORD dwmaxbaud; // Max baud rate, in BPS DWORD dwprovsubtype; // specific provider type DWORD dwprovcapabilities; // capabilities supported DWORD dwsettableparams; // changable Parameters DWORD dwsettablebaud; // allowable baud rates Word wsettabledata; // allowable byte sizes Word wsettablestopparity; // stop bits/parity allowed DWORD dwcurrenttxqueue; // TX buffer size, in bytes DWORD dwcurrentrxqueue; // RX buffer size, in bytes DWORD dwprovspec1; // provider-specific data DWORD dwprovspec2; // provider-specific data Wchar wcprovchar [1]; // provider-specific data } Comatrix drop; |
In this case, you need to configure the space by programmer. the interesting problem is that the system requires additional space after this structure. however, the programmer does not know how much the system will need. A simple practice is to configure a large block of space that will definitely be sufficient. another clever way is to execute getcomatrix roperties () twice. For the first time, only the space of sizeof (comatrix drop) is configured, because some actions have not yet been executed, therefore, the system will not try to fill in the following information, so there will be no problems. then execute getcomatrix roperties () for the first time. Obtain the result and retrieve the wpacketlength in the structure. The member represents the actual size, and then reconfigure a new one based on the size. in this way, there will be no waste of space.
As for the meaning of the above-mentioned members of the comatrix drop structure, the on-line help should be fully written.
4. Set and obtain the communication status
You can get some status by using comatrix drop, but when you want to change the current settings, you need two APIs:
Bool getcommstate ( Handle hfile, // handle of communications device Lpdcb // address of device-Control Block Structure ); Bool setcommstate ( Handle hfile, // handle of communications device Lpdcb // address of device-Control Block Structure ); |
You can use getcommstate () to get the current serial port status, or use setcommstate () to set the serial port status.
Please read help for the DCB structure.
In addition, the most common programmer control settings are baud rate, parity method, data bits, and stop bit. buildcommdcb.
Bool buildcommdcb ( Lptstr lpdef, // pointer to device-control string Lpdcb // pointer to device-Control Block ); |
Lpdef is long like this: "baud = 2400 parity = n data = 8 stop = 1"
5. Communication Setting Dialog Box
The Win32 API provides an API to enable the communication Setting Dialog Box: commconfigdialog (). When you call this API, a baud rate, data bits, and parity can be set .. and other information dialog box, programmer can use it to allow users to set some information and get results.
Bool commconfigdialog ( Lptstr lpszname, // pointer to device name string Hwnd, // handle to window Lpcommconfig lpcc // pointer to comm. Configuration Structure ); |
Among them, the lpcc is used to store the results of the set value.
Typedef struct _ comm_config { DWORD dwsize; Word wversion; Word wreserved; DCB; DWORD dwprovidersubtype; DWORD dwprovideroffset; DWORD dwprovidersize; Wchar wcproviderdata [1]; } Commconfig, * lpcommconfig; |
Before we call commconfigdialog (), dwsize should be set to sizeof (commconfig). The value of wversion does not seem important here (I don't know, the on-line help of vc5 can be set to 1, and the example of the book in my hand is set to 0x100). After the commconfigdialog () is called, the baudrate, bytesize, stopbits and parity are user settings.
6. Timeout Mechanism
Because it does not maintain an absolutely stable rate during transmission. because of the transmission quality, programer will need a timeout mechanism to help them with some control. in the timeout mechanism of Win32 communication, the nature of timeout is divided into two types. Let's take a look at the structure of commtimeouts:
Typedef struct _ commtimeouts {// ctmo DWORD readintervaltimeout; DWORD readtotaltimeoutmultiplier; DWORD readtotaltimeoutconstant; DWORD writetotaltimeoutmultiplier; DWORD writetotaltimeoutconstant; } Commtimeouts, * lpcommtimeouts; |
Programmer can use getcommtimeouts () and setcommtimeouts () to read or set the current timeout value.
Bool getcommtimeouts ( Handle hfile, // handle of communications device Lpcommtimeouts // address of Comm. time-outs Structure ); Bool setcommtimeouts ( Handle hfile, // handle of communications device Lpcommtimeouts // address of communications time-out Structure ); |
The first kind of timeout mechanism is called Interval timeout. It is literally easy to understand that this kind of timeout mechanism is to read the timeout of the interval between characters, interval timeout can be used only when characters are read. that is, in this structure of readintervaltimeout, the unit is MS, when read a character, beyond the value of readintervaltimeout, but has not read the next character, timeout occurs.
The second timeout mechanism is called total timeout. in this timeout mechanism, Win32 provides an elastic way to set total timeout. taking the read Total timeout as an example, a linear upper limit is formed using readtotaltimeoutmultiplier and readtotaltimeoutconstant. what does it mean? The actual total timeout should be a sub-statement like this:
Readtotaltimeout = readtotaltimeoutmultiplier * bytestoread + readtotaltimeoutconstant
Writetotaltimeout is calculated using the same formula. in this way, a fixed value can be used as the timeout value, or a line can be used as the value of timeout. The number of bytes to be read or written changes.
If you do not want to use timeout, set all data members in commtimeouts to 0.
If you set readintervaltimeout to maxdword and set both readtotaltimeoutmultiplier and readtotaltimeoutconstant to 0, the read action will be immediately returned if no data exists in the receive queue, but will not stop reading.
Here is an API similar to buildcommdcb () called buildcommdcbandtimeouts ():
Bool buildcommdcbandtimeouts ( Lptstr lpdef, // pointer to the device-control string Lpdcb, // pointer to the device-Control Block Lpcommtimeouts // pointer to comm. Time-out Structure ); |
Lpdef is a control string. It can be a string in the format of lpdef in buildcommdcb (), but the "to = xxx" setting is added. if "to = on", this API sets the Read and Write timeout values based on the value in lpcommtimeouts. if "to = off", no timeout is set for this device. if it is a value other than "on" and "off", the lpcommtimeouts setting will be ignored.
By the way, after setting the timeout value, check whether the pcf_inttimeouts and pcf_totaltimeouts flags in dwprovcapabilities in comatrix drop are set to check whether interval timeout and total timeout are supported.
7. Read data
Reading data from the serial port is the same as reading a normal file. It is achieved through readfile.
Bool readfile ( Handle hfile, // handle of file to read Lpvoid lpbuffer, // address of buffer that records es data DWORD nnumberofbytestoread, // number of bytes to read Lpdword lpnumberofbytesread, // address of number of bytes read Lpoverlapped // address of structure for Data ); |
Note that nnumberofbytestoread sets the maximum number of reads at a time. It is very likely that the read value (check lpnumberofbytesread) is smaller than this value. this API will usually return when an error or timeout occurs.
Purgecomm () can be used to terminate the reading or writing operations currently in progress, or flush the data waiting for reading or writing in the I/O buffer.
Bool purgecomm ( Handle hfile, // handle of communications Resource DWORD dwflags // action to perform ); |
Dwflags has four types of flags:
Purge_txabort: ends the currently ongoing (background) write action.
Purge_rxabort: The (background) read currently in progress
Purge_txclear: Buffer written by flush
Purge_txclear: Buffer read by flush
The use of flushfilebuffers () ensures that all data is sent, and this API will return.
Another interesting API is clearcommerror (). It is literally used to clear errors, but in fact it can also get some information about the current communication device.
Bool clearcommerror ( Handle hfile, // handle to communications device Lpdword lperrors, // pointer to variable to receive error codes Lpcomstat lpstat // pointer to buffer for communications Status ); |
After calling this API, some information about the communication device will be stored in lpstat. The COMSTAT structure is as follows:
Typedef struct _ COMSTAT {// CST DWORD fctshold: 1; // TX waiting for CTs Signal DWORD fdsrhold: 1; // TX waiting for DSR Signal DWORD frlsdhold: 1; // TX waiting for RlSD Signal DWORD fxoffhold: 1; // TX waiting, xoff char rec 'd DWORD fxoffsent: 1; // TX waiting, xoff char sent DWORD feof: 1; // EOF character sent DWORD ftxim: 1; // character waiting for TX DWORD freserved: 25; // Reserved DWORD cbinque; // bytes in input buffer DWORD cboutque; // bytes in output buffer } COMSTAT, * lpcomstat |
With fctshold, fdsrhold, frlsdhold, fxoffhold, and fxoffsent, you can know what causes communication to be blocked. (related to handshaking and Flow Control) cbinque and cboutque can show how many bytes are being read or written to the queue.
8. Write Data
Like reading data, programmer can use writefile () to write data to serial port.
Bool writefile ( Handle hfile, // handle to file to write Lpvoid lpbuffer, // pointer to data to write to file DWORD nnumberofbytestowrite, // number of bytes to write Lpdword lpnumberofbyteswritten, // pointer to number of bytes written Lpoverlapped // pointer to structure needed for overlapped I/O ); |
There are three interesting APIs for writing data to communication devices: setcommbreak (), clearcommbreak, and transmitcommchar ().
Bool setcommbreak ( Handle hfile // handle of communications device ); Bool clearcommbreak ( Handle hfile // handle to communications device ); Bool transmitcommchar ( Handle hfile, // handle of communications device Char cchar // character to transmit ); |
Setcommbreak () is used to pause the current transmission job, which will stop the data in the buffer from being sent. At this time, program can do some miscellaneous, and then use clearcommbreak () reply to the transmission job.
Transmitcommchar () is used to transmit one character of data immediately before all buffer data is sent out, even if there is data in the buffer. in other words, this character has the highest priority to be sent out.
9. event-driven I/O
In Win32, I/O of communication devices can be achieved through event-driven methods. it mainly uses an API called waitcommevent. after the API is called, it will be blocked until the specified event occurs. let's take a look at how to set events, and then look back at waitcommevent ().
The programer can use getcommmask () and setcommmask () to obtain or set the communication events currently set.
Bool getcommmask ( Handle hfile, // handle of communications device Lpdword lpevtmask // address of variable to get event mask ); Bool setcommmask ( Handle hfile, // handle of communications device DWORD dwevtmask // mask that identifies enabled events ); |
Configurable events include ev_break, ev_cts, ev_dsr, ev_err, ev_ring, ev_rlsd, ev_rxchar, ev_rxflag, and ev_txempty. (For more information about the meaning, see help.) Of course, you can combine them into combined events.
After setting the event to be processed, you can use waitcommevent ()
Bool waitcommevent ( Handle hfile, // handle of communications device Lpdword lpevtmask, // address of variable for event that occurred Lpoverlapped, // address of overlapped Structure ); |
Waitcommevent () will block until the specified communication event occurs. therefore, when waitcommevent () returns, you can obtain the event from lpevtmask and decide how to handle it.
For example, you can use setcommmask () to set the event to ev_rxchar. When waitcommevent () is called, it will not return until there are characters available for reading. After it returns, you can check whether ev_rxchar is set in lpevtmask. If yes, you can use readfile () to read it. in this way, we can avoid the inefficiency caused by polling in some situations.
10. handle errors
The clearncommerror () mentioned above can be used to obtain the cause of the current error. (See Help)
11. hardware control commands
Win32 provides the escapecommfunction () that allows the programer to control several hardware signals.
Bool escapecommfunction ( Handle hfile, // handle to communications device DWORD dwfunc // extended function to perform ); |
Dwfunc can be:
Clrdtr: Disable DTr
Clrrts: Get the RTS off
Setdtr: enables DTR on
Setrts: Let the RTS on
Setxoff: "simulation" receives xoff characters
Setxon: "simulation" receives the Xon character
Setbreak: The same as setcommbreak ().
Clrbreak: The same as clearcommbreak ().