Updated 2016-01-15 09:07:27 by Kroc

serial port

See Also  edit

chan configure (fconfigure)
the standard command for configuring serial port channels
nearly everything but the socket information is related to serial ports
for closing a serial port channel
for readable/writable callbacks
the standard command to open serial ports. port names are platform-dependent. all relevant serial-port options to fconfigure are described on th man page for open
Parallel port
serial ports on Windows
Serial Port Central
Jan Axelson's site about serial links and networks, including RS-232, RS-485, COM ports, and USB virtual COM ports, and his book, "Serial Port Complete"
Simple TCP/IP to serial port gateway

Documentation  edit

serial port ,Wikipedia
RS-232 ,Wikipedia

Examples  edit

apache tcl cgi script with serial port access
Bwise, a serial port tcl script and a Xilinx demo board
A simple serial terminal
How to build a simple serial terminal in a text widget
How to read the serial port, and display in hexadezimal
List computations in a FPGA, driven by Tcl
More Serial Port Samples
How to read the serial port, and display in hexadezimal
Serial Port Logic Analyzer Screen Capture

Tools  edit

a serial line monitor
Serial Player
a Windows utility for recording and playing back data from the serial communications port of the computer
Portmon for Windows
a proprietary but freely available program that displays all serial and parallel port activity on a system
Serial line sniffer
open-source license
provides serial line features

Description  edit

On Linux, opening a special device with the proper major/minor numbers always succeeds independent of there being any hardware attached or not. The first error usually happens when doing chan configure -mode ... with -mode not a valid option for ...

On NetBSD, when a terminal file is opened, it normally causes the process to wait until a connection is established. For most hardware, the presence of a connection is indicated by the assertion of the hardware CARRIER DETECT (DCD) line. This is a problem since most hardware and/or cables in common use ignores this line. Using the NONBLOCK flag with open is not enough to get things right, because the DCD is also used to detect the eof condition, causing the channel to assert eof after the first read or gets. There's patch at feature request 603 which adds a new flag to chan configure, -ignoredcd (only on unix machines with conforming termios interface) which controls whether the underlying device driver ignores the DCD line or not. Without this patch, the (non-portable) way to use a serial port lacking the DCD line is:
set device /dev/tty00
set fd [open $device {RDWR NONBLOCK}]
exec stty -f $device clocal

Serial lines have many characteristics known to Tcl. fconfigure is their usual interface. Typical options include -ttycontrol, -ttystatus, -timeout, and more.

Basic Example  edit

D. J. Hagberg mailto:[email protected]:

Here is a simple example... The [send_exp] stuff is pretty generic and should work for any channel that supports non- blocking I/O.
# simple serial port example to send AT to modem and 
# wait for OK response in a fixed amount of time.  At the
# bottom is a simple loop to do this 20x to check serial
# handler reliability...
# Works well on Tcl 8.0 and up on Unix (Solaris/NT), poorly on 
# the tclsh included with Tcl 8.1.1 on NT, but pretty well on 
# the wish included with same.
# NOTE may need to set comPort appropriately for your
# platform.  Must have a modem configured to respond
# with "OK" to "AT" commands.
switch $tcl_platform(os) {
    {Linux}            {set comPort /dev/modem}
    {SunOS}            {set comPort /dev/cua/a}
    {Windows NT}       {set comPort COM2:}
    default            {error "Must configure comPort"}
set waitSecs 2
set nTries   20

# A cheap version of expect.
# Set up a event-driven I/O reader on the channel, output the
# string, and wait some number of seconds for the result.
# @param fh
#        a channel opened in non-blocking mode for I/O
#        with buffering turned off.
# @param outstr
#        a string to send to the output channel -- note: end-
#        of-line characters must be included in this string,
#        if desired.
# @param regexp
#        regular expression to match in the incoming data.
# @param seconds
#        number of seconds to wait for above match
# @throws error
#        if eof is detected on the channel while waiting
# @returns int
#        1 if a match is found, 0 otherwise.
proc send_expect {fh outstr regexp seconds} {
    global send_exp

    # make sure global vars are initialized properly
    set send_exp($fh.matched)        0
    if {![info exists send_exp($fh.buffer)]} {
        set send_exp($fh.buffer) {}

    # set up our Read handler before outputting the string.
    if {![info exists send_exp($fh.setReader)]} {
        fileevent $fh readable [list private_send_exp_reader \
                        $fh $regexp]
        set send_exp($fh.setReader) 1

    # output the string to send
    puts -nonewline $fh $outstr
    flush $fh

    # set up a timer so that we wait a limited amt of seconds
    set afterId [after [expr {$seconds*1000}] \
                [list set send_exp($fh.matched) 0]]
    vwait send_exp($fh.matched)
    set matched $send_exp($fh.matched)
    unset send_exp($fh.matched)
    catch [list after cancel $afterId]

    # If we got an eof, then throw an error
    if {$matched < 0} {
                error "Channel EOF while waiting for data"
                return 0
    return $matched

# PRIVATE channel read event handler for send_expect.  Should
# not be called by user.
proc private_send_exp_reader {fh regexp} { 
    global send_exp
    if {[eof $fh]} {
        close $fh
        set send_exp($fh.matched) -1
    append send_exp($fh.buffer) [read $fh]
    if {[regexp $regexp $send_exp($fh.buffer)]} {
        set send_exp($fh.matched) 1

# Return the current contents of the send_expect buffer
# @param fh
#        channel identifier that was used with send_expect
# @returns string
#        the current contents of the buffer for the channel
proc send_exp_getbuf {fh} {
    global send_exp
    return $send_exp($fh.buffer)

# Reset the send_expect buffer, returning its contents
# @param fh
#        channel identifier that was used with send_expect
# @returns string
#        the current contents of the buffer for the channel
proc send_exp_resetbuf {fh} {
    global send_exp 

    set buf $send_exp($fh.buffer)
    set send_exp($fh.buffer) {}
    return $buf

# Close out a send_expect session, closing I/O event handler
# @param fh
#        channel identifier that was used with send_expect
# @returns
#        the channel identifier passed as the fh parameter
proc send_exp_end {fh} {
    global send_exp

    fileevent $fh readable {}
    foreach v [array names send_exp $fh.*] {
        catch [list unset send_exp($v)]
    return $fh

set fh [open $comPort RDWR]
fconfigure $fh -blocking 0 -buffering none \
        -mode 9600,n,8,1 -translation binary -eofchar {}

# Loop nTries times, sending AT to modem and expecting OK.
set nMatches 0
for {set i 0} {$i < $nTries} {incr i} {
    if {[send_expect $fh "AT\r" "OK" $waitSecs]} {
        incr nMatches
        regsub -all "\r" [send_exp_getbuf $fh] {\r} buf
        regsub -all "\n" $buf {\n} buf
        puts "GOT MATCH: <$buf>"
    } else {
        puts "NO MATCH IN $waitSecs SECONDS"
    send_exp_resetbuf $fh
send_exp_end $fh
close $fh
puts "Matched $nMatches/$nTries\
        ([expr 100.0*$nMatches/$nTries]%)"

RJM: Via the serial communication resources, one can also communicate via USB. However, this will surely work with one specific USB peripheral chip, namely from FTDI.

Resource: http://www.ftdichip.com/FTDrivers.htm

They provide a royalty-free USB driver. With Tcl apps the virtual com port driver can be used.

Advantages over RS-232:

  • USB protocol handles transmission errors, so protocol free communication is possible
  • high speed

I myself created a project with Tcl and USB: http://www.msp430web.de/msp430-usb.htm (note that downloadable software resources here may need an update).

[Jogusto] 2014-01-12: Forgive me for saying so, but IMO RJM does not have correct information regarding "Advantages over RS-232". The FTDI chip does not do anything for you except create a COM port that your system can use to send serial data via RS-232. So, I think RJM is confused between what USB is, and what the FTDI chip does. USB will not help you communicate over serial if your serial is connecting to a noisy modem channel. Furthermore, the FTDI chip implements the same set of common serial port baud rates available on other hardware implementations (eg 16450/16550 UARTS). The USB speeds have nothing to do with this.

The FTDI chip works very well to add a hardware serial port to a system, if you want to use a USB hardware interface to do it, as opposed to plugging in a PCIe card or something similar. Otherwise, there is really no difference between one kind of serial port, or the other, provided you have the correct driver to present a COM/tty device to your OS. That is one thing to be aware of. Many times, especially on older Windows systems (XP and previous) the USB support wasn't all that great, and in such cases, it is especially important to install the best driver for your system. Some devices simply do not support XP very well, because XP is so old, the USB compatibility with the new device drivers just isn't there. I have upgraded systems running XP to Win 7, and have solved numerous USB compatibility issues, including those with running Serial port bridges over USB. I have also had the experience of having interactions between USB devices with downrev drivers causing problems, where upgrading the driver for, say, a webcam, immediately cleared up issues with the serial port. So, for best results, ensure all your USB devices have up-to-date drivers for the best results. Those of you still on Windows XP can expect to have problems in certain situations/configurations, which you will not be able to solve without upgrading your OS.

MS 2005-01-09: If you want to use the ftdi-chip with a Linux system you can also use the RS-232-emulation of the Linux driver. The USB chip can then be accessed as if it were an RS-232 chip. You can look at http://www.enertex.de/linux/ftdi for some basic code examples.

Twylite: Note that on Windows you can use the device aliases "COM1" .. "COM9" (the trailing colon is not necessary), but to access higher numbered COM ports (quite common when using USB-to-serial converters or Bluetooth dongles) you must use the Win32 device name e.g. {\\.\COM14} .

HaO 2015-05-29: We are currently (Tcl/Tk8.6.4) suffering from a bug ed5be77734 that in wish (not tclsh), serial port names are not accepted with following ":".

[George] - 2015-11-24 11:52:35

Helpful code! I'm a complete beginner and I wanted to try to alter this to send messages over an RS422 loopback and read out the reply. I had some issues, but learned that for anyone trying to do something similar, sending longer messages over serial ports, I had to add:

puts -nonewline $fh $outstr after 200 flush $fh

This "after 200" command fixed the issues of only part of the message being sent. I suspect this may not be a far reaching issue but on the off chance anyone has a similar problem! :)