Configuring the Serial Port

This chapter discusses how to configure a serial port from C.

Previous Chapter - Accessing Serial Ports from C
Next Chapter - Programming for MODEMs

Changing the Port Configuration

Most systems support the POSIX terminal (serial) interface for changing parameters such as baud rate, character size, and so on. The first thing you need to do is include the file <termios.h>; this defines the terminal control structure as well as the POSIX control functions.

The two most important POSIX functions are tcgetattr and tcsetattr. These get and set terminal attributes, respectively; you provide a pointer to a termios structure that contains all of the serial options available.

POSIX Termios Structure

POSIX Control Modes

The c_cflag member controls the baud rate, number of data bits, parity, stop bits, and hardware flow control. There are constants for all of the supported configurations.

POSIX Control Mode Constants

The c_cflag member contains two options that should always be enabled: CLOCAL and CREAD. These will ensure that your program does not become the 'owner' of the port subject to sporatic job control and hangup signals, and also that the serial interface driver will read incoming data bytes.

Setting the Baud Rate

The cfsetospeed and cfsetispeed functions are provided to set the baud rate in the termios structure. Typically you'd use the following code to set the baud rate:

  struct termios options;

 /*
  * Get the current options for the port...
  */

  tcgetattr(fd, &options);

 /*
  * Set the baud rates to 19200...
  */

  cfsetispeed(&options, B19200);
  cfsetospeed(&options, B19200);

 /*
  * Enable the receiver and set local mode...
  */

  options.c_cflags |= (CLOCAL | CREAD);

 /*
  * Set the new options for the port...
  */

  tcsetattr(fd, TCSANOW, &options);

The tcgetattr function fills the termios structure you provide with the current serial port configuration. After we set the baud rates and enable local mode and serial data receipt, we select the new configuration using tcsetattr. The TCSANOW constant specifies that all changes should occur immediately without waiting for output data to finish sending or input data to finish receiving. There are other constants to wait for input and output to finish or to flush the input and output buffers.

POSIX tcsetattr Constants

Setting the Character Size

Unlike the baud rate, there is no convienience function to set the character size. Instead you must do a little bitmasking to set things up. The character size is specified in bits:

  options.c_cflags &= ~CSIZE; /* Mask the character size bits */
  options.c_cflags |= CS8;    /* Select 8 data bits */

Setting Parity Checking

Like the character size you must manually set the parity enable and parity type bits. UNIX serial drivers support even, odd, and no parity bit generation. Mark and space parity can be simulated with clever coding.

Setting Hardware Flow Control

Some versions of UNIX support hardware flow control using the CTS (Clear To Send) and RTS (Request To Send) signal lines. If the CNEW_RTSCTS constant is defined on your system then hardware flow control is probably supported. Do the following to enable hardware flow control:

  options.c_cflags |= CNEW_RTSCTS;

Similarly, to disable hardware flow control:

  options.c_cflags &= ~CNEW_RTSCTS;

POSIX Local Modes

The local modes member c_lflag controls how input characters are managed by the serial driver. In general you will configure the c_lflag member for canonical or raw input.

POSIX Local Mode Constants

What Is Canonical Input?

Canonical input is line-oriented. Input characters are put into a buffer which can be edited interactively by the user until a CR (carriage return) or LF (line feed) character is received.

When selecting this mode you normally select the ICANON, ECHO, and ECHOE options:

  options.c_lflags |= (ICANON | ECHO | ECHOE);

What Is Raw Input?

Raw input is unprocessed. Input characters are passed through exactly as they are received, when they are received. Generally you'll deselect the ICANON, ECHO, and ISIG options when using raw input:

  options.c_lflags &= ~(ICANON | ECHO | ISIG);

A Note About Input Echo

Never enable input echo (ECHO) when sending commands to a MODEM or other computer that is echoing characters you send to it as you will generate a feedback loop between the two serial interfaces!

POSIX Input Modes

The input modes member c_iflag controls any input processing that is done to each character received on the port. Like the c_cflag field, the final value stored in c_iflag is the bitwise OR of the desired options.

POSIX Input Mode Constants

Setting Input Parity Options

You should enable input parity checking when you have enabled parity in the c_cflags member. The revelant constants for input parity checking are INPCK, IGNPAR, PARMRK, and ISTRIP. Generally you will select INPCK and ISTRIP:

  options.c_iflags |= (INPCK | ISTRIP);

The INPCK option enables checking of parity data, while ISTRIP strips the parity bit off the data before it gets to your program.

IGNPAR is a somewhat dangerous option that tells the serial driver to ignore parity errors and pass the incoming data through as if no errors had occurred. This can be useful for testing the quality of a communications link, but in general is not used for practical reasons.

PARMRK causes parity errors to be 'marked' in the input stream using special characters. If IGNPAR is enabled, a NUL character (0) is sent to your program before every character with a parity error. Otherwise, a DEL (255) and NUL character is sent along with the bad character.

Setting Software Flow Control

Software flow control is enabled using the IXON, IXOFF, and IXANY constants:

  options.c_iflags |= (IXON | IXOFF | IXANY)

The XON (start data) and XOFF (stop data) characters are defined in the c_cc array described below.

POSIX Output Modes

The c_oflags member contains output filtering options. Like the input modes, you can select processed or raw data output.

POSIX Output Mode Constants

Processed Output

Processed output is selected by setting the OPOST option in the c_oflags member:

  options.c_oflags |= OPOST;

Of all the different options, you will only probably use the ONLCR option which maps newlines into CR-LF pairs. The rest of the output options are primarily historic, dating back to the time when line printers and terminals could not keep up with the serial data stream!

Raw Output

Raw output is selected by resetting the OPOST option in the c_oflags member:

  options.c_oflags &= ~OPOST;

When the OPOST option is disabled, all other option bits in c_oflags are ignored.

POSIX Control Characters

The c_cc character array contains control character definitions as well as timeout parameters. Constants are defined for every element of this array.

POSIX Control Character Constants

Setting Software Flow Control Characters

The VSTART and VSTOP elements of the c_cc array contain the characters used for software flow control. Normally they should be set to DC1 (17) and DC3 (19), representing the defacto standard XON and XOFF characters.

Setting Read Timeouts

UNIX serial interface drivers provide the ability to specify character and packet timeouts. Timeouts are ignored in canonical input mode. Two elements of the c_cc array are used for timeouts: VMIN and VTIME.

VMIN specifies the minimum number of characters to read. If it is set to 0, then the VTIME value specifies the time to wait for every character read.

If VMIN is non-zero, VTIME specifies the time to wait for the first character read. If a character is read within the time given, any read will block (wait) until all VMIN characters are read. That is, once the first character is read, the serial interface driver expects to receive an entire packet of characters (VMIN bytes total). If no character is read within the time allowed, then the call to read returns 0.

VTIME specifies the amount of time to wait for incoming characters in tenths of seconds. If VTIME is set to 0 (the default), calls to read will block (wait) indefinitely unless the NDELAY option is set on the port with open or fcntl.