Implementing Serial Communication in Win9X/2000

Introduction

Serial data transmission seems a bit difficult for those who are new to the world of serial communication and VC++. A long time ago, I searched codeguru.com to get some help on serial data transmission; I got some valuable information from this site. Since then, it has been my dream to develop a simple class to implement serial data transmission. After getting seven months of practical experience in the field of serial communication, I have developed a simple class to implement Serial transmission using WINAPI functions. Before going into the details of this class, it is essential to know the basics of serial data transmission.

In serial data transmission, the data is transmitted in serial format with LSB of the byte to be transmitted shifted out first among the data bits.The general format for serial transmission is Start Bit + Data Bits + Parity Bit (Optional) + Stop Bit.

The parity bit is optional. It is used for error checking in communication. You can enable or disable parity checking by software modifications. Also, you can specify which parity you want to use, either EVEN or ODD through software.

The various steps you need to perform to send and receive data through the serial port of a PC are listed below:

Open the communication port.

Configure the communication port, setting the baud rate, parity, number of data bits, and so forth.

Set timeouts for communication.

Write data to the port.

Read data from the port.

Close the port.

Opening the Serial Port

The CreateFile( ) WINAPI opens a communications port. There are two ways to call CreateFile( ) to open the communications port—overlapped and non-overlapped. You can open a Communication Port for OVERLAPPED IO operation and NON-OVERLAPPED IO operation. CSerialPort class is written for NON-OVERLAPPED IO Operation. For more details on OVERLAPPED and NON-OVERLAPPED IO, please refer to the MSDN documentation.

Configuring the Serial Port

The most critical phase in serial communication programming is configuring the port settings with the DCB structure. Erroneously initializing the DCB structure is a common problem. When a serial communications function does not produce the expected results, the DCB structure may be in error. A call to the CreateFile( ) function opens a serial port with default port settings. Usually, the application needs to change the defaults. You must set the baud rate for communication, parity functions, number of stop bits, and so on, in accordance with the requirements of the external device by calling the appropriate WINAPI functions.

Configuring Timeouts

An application must always set communication timeouts using the COMMTIMEOUTS structure each time it opens a communication port. If this structure is not configured, the port uses default timeouts supplied by the driver, or timeouts from a previous communications application. By assuming specific timeout settings when the settings are actually different, an application can have read/write operations that never complete or complete too often. You must configure the read and write timeouts for communication by calling the appropriate WINAPI functions.

Writing to a Serial Port

The WriteFile( ) WINAPI transfers data through the serial connection to another device. Before calling this function, an application must open and configure a serial port.

Reading from a Serial Port

An application calls the ReadFile( ) WINAPI to receive data from a device at the other end of a serial connection. ReadFile( ).

Closing a Serial Port

You must close the communications port after serial transmission to make this port available for other applications that use this resource. As long as you are working with a port (the port is in the open state), other threads or applications will not get access to this port until you close the handle to that port in a NON-OVERLAPPED IO operation. Call the CloseHandle( ) WINAPI to close a serial port. CloseHandle has one parameter, which is the handle returned by the CreateFile( ) WINAPI call that opened the port.

The CSerialPort Class

The CSerialPort Class uses six member functions to achieve the above-mentioned things. They are:

The OpenPort( ) member function opens a communication port for data transmission. The parameter to be passed to this function is a string containing the port name; for example, "com1" for COM1, "com2" for COM2, and so forth. If the function succeeds, the return value is true; otherwise, it is false.

The ConfigurePort( ) member function configures a communication port for data transmission. The parameters to be passed to this function are given below.

Parameter

Explanation

DWORD BaudRate

Represents the baud rate for communication supported by an external device. For example, you can give this parameter as 9600 or CBR_9600 for a baud rate of 9600. The available standard baud rates supported by the PC are CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400, CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400, CBR_56000, CBR_57600, CBR_115200, CBR_128000, and CBR_256000.

BYTE ByteSize

Represents the number of bits in the bytes transmitted and received. Standard values are 8 or 4.

DWORD fParity

Specifies whether parity checking is enabled. If this member is TRUE, parity checking is performed and errors are reported. If FALSE, no parity checking is performed.

BYTE Parity

Specifies the parity scheme to be used. This member can be one of the following values:

NOTE: The ConfigurePort( ) function is written on the assumption that the communication flow control is completely controlled on the basis of the protocol supported by the external device. It transmits and receives data without checking the CTS/RTS and Xon/Xoff hardware flow control. You can modify this to your requirements by changing the values of the members of DCB that are responsible for it, in the implementation of ConfigurePort( ) in SerialPort.cpp.

Here's another example.

ConfigurePort(CBR_9600, 8, true, EVENPARITY , ONESTOPBIT )

If the function succeeds, the return value is true; otherwise, it is false.

The SetCommunicationTimeouts( ) member function sets the write and read timeouts for data transmission. The parameters to be passed to this function are given below.

Parameter

Explanation

DWORD ReadIntervalTimeout

Specifies the maximum time, in milliseconds, allowed to elapse between the arrival of two characters on the communications line. During a ReadFile( ) operation, the time period begins when the first character is received. If the interval between the arrival of any two characters exceeds this amount, the ReadFile operation is completed and any buffered data is returned. A value of zero indicates that interval timeouts are not used. A value of MAXDWORD, combined with zero values for both the ReadTotalTimeout Constant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the characters that have already been received, even if no characters have been received.

ReadTotalTimeoutConstant

Specifies the constant, in milliseconds, used to calculate the total timeout period for read operations. For each read operation, this value is added to the product of the ReadTotal Timeout Multiplier member and the requested number of bytes. A value of zero for both the ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant members indicates that total timeouts are not used for read operations.

ReadTotalTimeoutMultiplier

Specifies the multiplier, in milliseconds, used to calculate the total timeout period for read operations. For each read operation, this value is multiplied by the requested number of bytes to be read.

WriteTotalTimeoutConstant

Specifies the constant, in milliseconds, used to calculate the total timeout period for write operations. For each write operation, this value is added to the product of the WriteTotal TimeoutMultiplier member and the number of bytes to be written.

WriteTotalTimeoutMultiplier

Specifies the multiplier, in milliseconds, used to calculate the total timeout period for write operations. For each write operation, this value is multiplied by the number of bytes to be written.

A value of zero for both the WriteTotalTimeoutMultiplier and WriteTotalTimeoutConstant members indicates that total timeouts are not used for write operations.

For example, if your device transmits a block of characters with a maximum timeout value of 500 ms between characters, you can set the timeout function as:

SetCommunicationTimeouts(0,500,0,0,0) ;

If the function succeeds, the return value is true; otherwise, it is false.

The WriteByte( ) member function writes the data byte to the communication port. The parameter to be passed to this function is the byte to be transmitted. You can call this function repeatedly in a loop with your data to be written placed in an array. Each time you send characters, increment the index of the array and call WriteByte( ) until all data bytes are transmitted.

If the function succeeds, the return value is true; otherwise, it is false.

The ReadByte( ) member function reads data bytes from the communication port. The parameter to be passed to this function is the address of the variable in which received data byte is to be stored. You can call this function repeatedly in a loop with your received data moved to an array. Each time you receive characters, increment the index of the array and call ReadByte( ) until all data bytes are received.

If you know the exact number of response bytes from the external device, you can call the ReadByte( ) function in a loop until all characters are received or a timeout occurs. Sometimes you may not be able to predict the number of response bytes from the external device. In that case, call the ReadByte file repeatedly until you get a timeout and if the character received previously is a character representing end of transmission in your protocol format, the communication process is successfully completed. For example, for a device following 3964, the end of transmission is the ETX character. So use the ReadByte( ) function properly in accordance with the protocol your external device supports.

If ReadByte( ) succeeds, the return value is true and the received byte will be stored in the location pointed by the address of ReadByte( )'s parameter. If a timeout occurs, the return value will be false.

void CSerialPort::ClosePort()
{
CloseHandle(hComm);
return;
}

The ClosePort( ) member function closes a communication port that is already in an open state.

How to Use the CSerialPort Class

Do the following steps to use the CSerialPort class:

Copy the "SerialPort .h" and "SerialPort .cpp" files and paste them in your Project directory.

NOTE: This code has been tested with an RS-232 connector, whose TXD pin and RXD pin were shorted, connected to "com1" (for example, for case1: where the number of databytes to be read is predefined) or constant (in this case, 1) and with a Smart Card Reader with a baud rate of 9600 supporting the 3964 protocol for communication (as in case2: where the number of databytes to be read from the external device is unknown and the end of data transmission is detected by a timeout with the last character received being the End-of-transmission character in that protocol (the "ETX" character for the 3964 protocol) in Win98/2000 and it is found to be working properly).

Some of the explanation given in this article are taken from MSDN library.

Top White Papers and Webcasts

Live Event Date: March 19, 2015 @ 1:00 p.m. ET / 10:00 a.m. PT
The 2015 Enterprise Mobile Application Survey asked 250 mobility professionals what their biggest mobile challenges are, how many employees they are equipping with mobile apps, and their methods for driving value with mobility.
Join Dan Woods, Editor and CTO of CITO Research, and Alan Murray, SVP of Products at Apperian, as they break down the results of this survey and discuss how enterprises are using mobile application management and private …

This report outlines the future look of Forrester's solution for security and risk (S&R) executives working on building an identity and access management strategy for the extended enterprise. We designed this report to help you understand and navigate the major business and IT trends affecting identity and access management (IAM) during the next five years. IAM in 2012 has become a tool not just for security but also for business agility. Competitive challenges push businesses into the cloud and encourage …