This chapter discusses how to configure a serial port from C.
Previous Chapter - Accessing Serial Ports from C
Next Chapter - Programming for MODEMs
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.
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.
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.
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.
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 */
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.
options.c_cflags &= ~PARENB options.c_cflags &= ~CSTOPB options.c_cflags &= ~CSIZE; options.c_cflags |= CS8;
options.c_cflags |= PARENB options.c_cflags &= ~PARODD options.c_cflags &= ~CSTOPB options.c_cflags &= ~CSIZE; options.c_cflags |= CS7;
options.c_cflags |= PARENB options.c_cflags |= PARODD options.c_cflags &= ~CSTOPB options.c_cflags &= ~CSIZE; options.c_cflags |= CS7;
options.c_cflags &= ~PARENB options.c_cflags |= CSTOPB options.c_cflags &= ~CSIZE; options.c_cflags |= CS7;
options.c_cflags &= ~PARENB options.c_cflags &= ~CSTOPB options.c_cflags &= ~CSIZE; options.c_cflags |= CS8;
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;
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.
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);
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);
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!
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.
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.
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.
The c_oflags member contains output filtering options. Like the input modes, you can select processed or raw data 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 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.
The c_cc character array contains control character definitions as well as timeout parameters. Constants are defined for every element of this array.
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.
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.