TIP 35: Enhanced Support for Serial Communications

Author:         Rolf Schroedter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        06-Jun-2001
Tcl-Version:    8.4
Tcl-Ticket:     438509


Tcl's support for RS-232 is very rudimentary. Mainly it allows to setup the communication rate [fconfigure -mode] and to read and write data with the standard Tcl functions. Real serial communications are often more complex. Therefore it is proposed to add support for hardware and software flow control, polling RS-232 (modem) status lines, and watching the input and output queue. This is all to be implemented via additional [fconfigure] options.


There is an undamped interest in serial communications, because it's very easy to connect external hardware to a computer using the RS-232 ports.

However Tcl's support for serial communications is not complete. Real applications often need more than setting the baud rate and to read/write data bytes.

Especially if the external hardware is slow or the communication rate is high one needs support for flow-control (hard- and software). These features are provided by the operating system drivers, but Tcl's [fconfigure] doesn't support it.

On the the other hand there are cases that the external hardware makes static use of the RS-232 signals to signal external events via the modem status lines or even to be powered by the RS-232 control lines.

Additionally for non-blocking serial I/O it may be interesting for the Tcl application to know about the status of the input and output queues to read a fixed size block or to support communication timeouts.

At this opportunity it is proposed to move the documentation of the serial port fconfigure options form the open.n man-page to fconfigure.n.


It is proposed to have following set of [fconfigure] options for serial communications:

-mode baud,parity,data,stop: (Windows and Unix). Already implemented.

-handshake mode: (Windows and Unix). This option is used to setup automatic handshake control. Note that not all handshake modes maybe supported by your operating system. The mode parameter is case-independent.

If mode is none then any handshake is switched off. rtscts activates hardware handshake. For software handshake xonxoff the handshake characters can be redefined with [fconfigure -xchar]. An additional hardware handshake dtrdsr is available only for Windows. There is no default handshake configuration, the initial value depends on your operating system settings. The -handshake option cannot be queried, because the operating system settings may be ambiguous.

-xchar {xonChar xoffChar}: (Windows and Unix). This option is used to change the software handshake characters. Normally the operating system default should be DC1 (0x11 hex) and DC3 (0x13 hex) representing the ASCII standard XON and XOFF characters.
When queried -xchar returns a list of two characters representing the XON and XOFF characters respectively.

-timeout msec: (Windows and Unix. This option is used to set the timeout for blocking read operations. It specifies the maximum interval between the receiption of two bytes in milliseconds. For Unix systems the granularity is 100 milliseconds. The -timeout option does not affect write operations or nonblocking reads. This option cannot be queried.

-ttycontrol {signal boolean signal boolean ...}: (Windows and Unix). This option is used to setup the handshake output lines permanently or to send a BREAK over the serial line. The signal names are case-independent.

{RTS 1 DTR 0} sets the RTS output to high and the DTR output to low. For POSIX systems {BREAK 1} sends a break signal (zero-valued bits) for 0.25 to 0.5 seconds and {BREAK 0} does nothing. For Windows the break is enabled and disabled with {BREAK 1} and {BREAK 0} respectively. It's not a good idea to change the RTS (or DTR) signal with active hardware handshake rtscts (or dtrdsr). The result is unpredictable. The -ttycontrol option cannot be queried.

-ttystatus: (Windows and Unix). The -ttystatus option can only be queried. It returns the current modem status and handshake input signals. The result is a list of signal,value pairs with a fixed order, e.g. {CTS 1 DSR 0 RING 1 DCD 0}. The signal names are returned upper case.

-queue: (Windows and Unix). The -queue option can only be queried. It returns a list of two integers representing the current number of bytes in the input and output queue respectively.

-sysbuffer inSize:

-sysbuffer {inSize outSize}: (Windows only, Unix ?). This option is used to change the size of Windows system buffers for a serial channel. Especially at higher communication rates the default input buffer size of 4096 bytes can overrun for latent systems. The first form specifies the input buffer size, in the second form both input and output buffers are defined.

-pollinterval msec: (Windows only). Already implemented.

-lasterror: (Windows only, Unix?). Already implemented for Windows.

Implementation Details

For Unix (termios.h) systems the proposed changes are very straight forward, because Unix channels can be configured blocking or non-blocking. One only needs to add the serial [fconfigure] options calling the appropriate ioctl() functions to configure the serial port.

For Windows reading and writing files is generally blocking. Especially with activated handshake the serial communication can stop forever. Therefore the Windows implementation needs at least a writing thread preventing Tcl's main application to block. Additionally Windows provides a reach set of special APIs for serial communication which needs to be translated to [fconfigure] options.

There is one special point about Windows: For making multiple threads accessing a serial port, it needs to be opened with the OVERLAPPED flag set. Tcl detects a serial port only after opening it without the OVERLAPPED flag. Therefore this port has to be reopened, which requires a little change to tclWinChan.c and tclWinPort.h.

Macintosh systems - ?

Changed Files

tclUnixChan.c: Add [fconfigure] options.

tclWinPort.h: Declare a new function TclWinSerialReopen()

tclWinChan.h: Call TclWinSerialReopen() after detecting the serial port.

tclWinSerial.c: Partial rewrite of Tcl's serial driver. The current implementation only performs blocking output. Add [fconfigure] options.

fconfigure.n: Serial [fconfigure] options should be documented here.

open.n: Serial port filenames are documented here. Add a link to [fconfigure] for additional serial options.


It has also been proposed to add a [fconfigure -timeout] option specifying read and write timeouts. Together with a blocking read a timeout could be used to wait for an expected number of data bytes from the serial port. There are two arguments against timeouts:

  1. Adding timeout to blocking I/O at the driver level radically changes the behaviour of write operations. This adds a lot of oddity to serial communications.

  2. Timeouts can easily be implemented at Tcl level using non-blocking I/O together with Tcl's event loop. Additional support is given by [fconfigure -queue].

July 03, 2001: On the other hand timeout for read operations can easily be implemented in a cross-platform way by using the VMIN/VTIME settings for Unix and the COMTIMEOUTS for Windows. That's why the author finally agrees with the -timeout proposal.

Restore settings at close ?

It has also been proposed that Tcl should not restore the original serial ports settings at [close $chan]. IMO it doesn't hurt, because anyway an application should care about setting up the serial port properly before using. Without restoring a Tcl script could be used as a poor stty, considering however that Tcl does not provide a complete control over serial settings.

So the proposal is to remove the current save/restore mechanism from the Unix implementation for serial ports.

Source code patches

The patches have been uploaded to the sourceforge patch tracker: ID=438509 TIP#35 Patches: Serial Port Enhancements file=tip35patch.tgz


This document has been placed in the public domain.