TIP:            35
Title:          Enhanced Support for Serial Communications
Version:        $Revision: 1.12 $
Author:         Rolf Schroedter <rolf.schroedter@dlr.de>
State:          Final
Type:           Project
Vote:           Done
Created:        06-Jun-2001
Post-History:   
Tcl-Version:    8.4

~ Abstract

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.

~ Rationale

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''.

~ Specification

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.

~ Timeouts

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

~ Copyright

This document has been placed in the public domain.
