Saturday, July 26, 2008

LibGW32C for Windows

Version

0.4
Description

This is an implementation of a small part of GLibC, just enough to compile most Unix programs on MS Windows. It contains functions for passwords, process id's groups, and strings. Most are interfaces to the MS-Windows Win32 API. Some are just dummy functions that do nothing.

The following functions are provided:

* a64l
* __access
* access
* __addmntent
* addmntent
* __addmntentstr
* alarm
* alphasort
* alphasort64
* argp_err_exit_status
* __argp_error
* argp_error
* __argp_failure
* argp_failure
* __argp_fmtstream_ensure
* __argp_fmtstream_free
* __argp_fmtstream_point
* __argp_fmtstream_printf
* __argp_fmtstream_putc
* __argp_fmtstream_puts
* __argp_fmtstream_set_lmargin
* __argp_fmtstream_set_rmargin
* __argp_fmtstream_set_wmargin
* __argp_fmtstream_update
* __argp_fmtstream_write
* __argp_help
* argp_help
* __argp_input
* _argp_input
* __argp_make_fmtstream
* __argp_parse
* argp_parse
* argp_program_bug_address
* argp_program_version
* argp_program_version_hook
* __argp_state_help
* argp_state_help
* _argp_unlock_xxx
* __argp_usage
* argp_usage
* __argz_add
* argz_add
* __argz_add_sep
* argz_add_sep
* __argz_append
* argz_append
* __argz_count
* argz_count
* __argz_create
* argz_create
* __argz_create_sep
* argz_create_sep
* argz_delete
* __argz_extract
* argz_extract
* __argz_insert
* argz_insert
* __argz_next
* argz_next
* __argz_replace
* argz_replace
* __argz_stringify
* argz_stringify
* attr2mode
* BackupLink
* basename
* bcopy
* __brk
* brk
* bsearch
* __bzero
* bzero
* __canonicalize_file_name
* canonicalize_file_name
* catclose
* catgets
* catopen
* cfgetispeed
* cfgetospeed
* cfmakeraw
* cfsetispeed
* cfsetospeed
* cfsetspeed
* __chdir
* chdir
* chflags
* __chown
* chown
* chroot
* clock
* clock_getcpuclockid
* clock_getres
* clock_gettime
* clock_nanosleep
* clock_settime
* __closedir
* closedir
* CreateLink
* crypt
* __crypt_r
* crypt_r
* __curbrk
* cuserid
* __cxstat64
* debugprint
* DecodeError
* devrootdir
* dirfd
* dirname
* dladdr
* dlclose
* dlerror
* dlopen
* dlsym
* __dlvsym
* dlvsym
* drand48
* __drand48_iterate
* drand48_r
* ecvt
* ecvt_r
* encrypt
* __encrypt_r
* encrypt_r
* endfsent
* endgrent
* endhostent
* __endmntent
* endmntent
* endpwent
* endusershell
* envz_add
* envz_entry
* envz_get
* envz_merge
* envz_remove
* envz_strip
* erand48
* __erand48_r
* erand48_r
* err
* __error
* error
* __error_at_line
* error_at_line
* error_message_count
* error_one_per_line
* error_print_progname
* errx
* __euidaccess
* euidaccess
* __fchdir
* fchdir
* fchflags
* __fchmod
* fchmod
* __fchown
* fchown
* __fcntl
* fcntl
* fcrypt
* fcvt
* fcvt_r
* fdatasync
* fesetround
* __ffs
* ffs
* ffsl
* fgetxattr
* file_exists
* FileInformationToStat64
* flistxattr
* __flockfile
* flockfile
* __fork
* fork
* __fpathconf
* fpathconf
* fremovexattr
* frootdir
* fseeko
* fseeko64
* __fsetlocking
* fsetxattr
* __fstat
* fstat
* fstat64
* __fstatfs
* fstatfs
* __fstatfs64
* fstatfs64
* __fstatvfs
* fstatvfs
* __fstatvfs64
* fstatvfs64
* ftello
* ftello64
* __ftruncate
* ftruncate
* __ftruncate64
* ftruncate64
* __ftrylockfile
* ftrylockfile
* fts_children
* fts_close
* fts_open
* fts_read
* fts_set
* ftw
* ftw64
* __funlockfile
* funlockfile
* __futimes
* futimes
* __fxstat
* _fxstat
* __fxstat64
* gcvt
* __gen_tempname
* __get_avphys_pages
* get_avphys_pages
* __get_clockfreq
* get_current_dir_name
* __get_errno
* __get_nprocs
* get_nprocs
* __get_nprocs_conf
* get_nprocs_conf
* __get_phys_pages
* get_phys_pages
* __getclktck
* getcpuspeed
* __getcwd
* getdomainname
* __getdtablesize
* getdtablesize
* __getegid
* getegid
* __geteuid
* geteuid
* getexecdir
* getexecparent
* getexecpath
* GetFileAttributeData
* GetFileInformationByName
* getfsent
* getfsfile
* getfsspec
* __getgid
* getgid
* getgranularity
* getgrent
* getgrent_r
* getgrgid
* getgrnam
* __getgroups
* getgroups
* gethostent
* gethostid
* __getline
* getline
* getloadavg
* getlogin
* getlongpath
* GetMachInfo
* getmntent
* __getmntent_r
* getmntent_r
* __getntptimeofday
* getntptimeofday
* getopt
* __getopt_initialized
* _getopt_internal
* getopt_long
* getopt_long_only
* GetOsInfo
* __getpagesize
* getpagesize
* getpass
* __getpgid
* getpgid
* getpgrp
* __getppid
* getppid
* getpriority
* getprogname
* getpwent
* getpwnam
* getpwuid
* __getrlimit
* getrlimit
* __getrlimit64
* getrlimit64
* getrootdirs
* getshortpath
* getsid
* GetStat64ByHandle
* GetStat64ByName
* __gettimeofday
* gettimeofday
* __getuid
* getuid
* getuname
* getusershell
* GetVendorID
* GetVolumeSerialNumber
* getwd
* getxattr
* GetXStat64ByName
* __group_member
* group_member
* gtty
* handle2mode
* hashval
* __hasmntopt
* hasmntopt
* hcreate
* hcreate_r
* __hdestroy
* hdestroy
* hdestroy_r
* hsearch
* hsearch_r
* __hutimes
* __init_des
* __init_des_r
* __init_misc
* __initstate
* initstate
* __initstate_r
* initstate_r
* insque
* _IO_flockfile
* _IO_ftrylockfile
* _IO_funlockfile
* __ioctl
* ioctl
* issymlink
* IsWin31
* IsWin9x
* IsWinCE
* IsWinNT
* _itoa_lower_digits
* _itoa_upper_digits
* jrand48
* __jrand48_r
* jrand48_r
* __kill
* kill
* l64a
* lchmod
* __lchown
* lchown
* lcong48
* __lcong48_r
* lcong48_r
* lfind
* lgetxattr
* __libc_drand48_data
* __libc_enable_secure
* __libc_init
* __libc_init_first
* __libc_init_secure
* _libc_intl_domainname
* __libc_multiple_libcs
* __libc_nanosleep
* __libc_readv
* __libc_tcdrain
* __libc_tsd_LOCALE_data
* __libc_wait
* __libc_waitid
* __libc_waitpid
* __link
* link
* listxattr
* llistxattr
* lock
* lock64
* lrand48
* lrand48_r
* lremovexattr
* lsearch
* lsetxattr
* __lstat
* lstat
* lstat64
* __lutimes
* lutimes
* __lxstat
* _lxstat
* __lxstat64
* madvise
* __md5_buffer
* __md5_crypt
* __md5_crypt_r
* __md5_finish_ctx
* __md5_init_ctx
* __md5_process_block
* __md5_process_bytes
* __md5_read_ctx
* __md5_stream
* memfrob
* __mempcpy
* mempcpy
* __memrchr
* memrchr
* __mkdir
* mkdir
* mkdtemp
* mkfifo
* __mknod
* mknod
* mkstemp64
* mkstemps
* mktemp
* mlock
* mlockall
* __mmap
* mmap
* __mmap64
* mmap64
* mode2osflags
* __mpn_lshift
* __mpn_rshift
* __mprotect
* mprotect
* mrand48
* mrand48_r
* mremap
* msync
* mtrace
* munlock
* munlockall
* __munmap
* munmap
* muntrace
* __nanosleep
* nanosleep
* nftw
* nftw64
* nice
* _nl_C_codeset
* _nl_C_LC_ADDRESS
* _nl_C_LC_COLLATE
* _nl_C_LC_CTYPE
* _nl_C_LC_CTYPE_class
* _nl_C_LC_CTYPE_class32
* _nl_C_LC_CTYPE_class_alnum
* _nl_C_LC_CTYPE_class_alpha
* _nl_C_LC_CTYPE_class_blank
* _nl_C_LC_CTYPE_class_cntrl
* _nl_C_LC_CTYPE_class_digit
* _nl_C_LC_CTYPE_class_graph
* _nl_C_LC_CTYPE_class_lower
* _nl_C_LC_CTYPE_class_print
* _nl_C_LC_CTYPE_class_punct
* _nl_C_LC_CTYPE_class_space
* _nl_C_LC_CTYPE_class_upper
* _nl_C_LC_CTYPE_class_xdigit
* _nl_C_LC_CTYPE_map_tolower
* _nl_C_LC_CTYPE_map_toupper
* _nl_C_LC_CTYPE_tolower
* _nl_C_LC_CTYPE_toupper
* _nl_C_LC_CTYPE_width
* _nl_C_LC_IDENTIFICATION
* _nl_C_LC_MEASUREMENT
* _nl_C_LC_MESSAGES
* _nl_C_LC_MONETARY
* _nl_C_LC_NAME
* _nl_C_LC_NUMERIC
* _nl_C_LC_PAPER
* _nl_C_LC_TELEPHONE
* _nl_C_LC_TIME
* _nl_C_name
* _nl_global_locale
* nl_langinfo
* _nl_POSIX_name
* nrand48
* __nrand48_r
* nrand48_r
* __open_catalog
* __opendir
* opendir
* optarg
* opterr
* optind
* __option_is_end
* _option_is_end
* __option_is_short
* _option_is_short
* optopt
* osflags2mode
* path2mode
* __path_search
* __pathconf
* pathconf
* __pipe
* pipe
* posix2winfullpath
* posix2winpath
* posix_madvise
* posix_mremap
* PrintWinErr
* __progname
* __progname_full
* program_invocation_name
* program_invocation_short_name
* program_name
* __pthread_clock_gettime
* __pthread_clock_settime
* qecvt
* qecvt_r
* qfcvt
* qfcvt_r
* qgcvt
* qsort
* _quicksort
* rand
* rand_r
* __random
* random
* __random_r
* random_r
* __rawmemchr
* rawmemchr
* __readdir
* readdir
* __readdir64
* readdir64
* __readdir64_r
* readdir64_r
* __readdir_r
* readdir_r
* readlink
* __readv
* readv
* __realpath
* realpath
* remove
* removexattr
* remque
* rename
* ResolveLink
* __rewinddir
* rewinddir
* __rmdir
* rmdir
* rootdir
* __rstatfsx64
* __sbrk
* sbrk
* scandir
* scandir64
* __secure_getenv
* seed48
* __seed48_r
* seed48_r
* __seekdir
* seekdir
* __select
* select
* setdomainname
* setegid
* setenv
* setfsent
* setgid
* setgrent
* sethostent
* sethostid
* sethostname
* setkey
* __setkey_r
* setkey_r
* setlogin
* __setmntent
* setmntent
* __setntptimeofday
* setntptimeofday
* __setpgid
* setpgid
* setpgrp
* setpriority
* setpwent
* __setregid
* setregid
* __setreuid
* setreuid
* __setrlimit
* setrlimit
* __setrlimit64
* setrlimit64
* __setstate
* setstate
* __setstate_r
* setstate_r
* __settimeofday
* settimeofday
* setuid
* setusershell
* setxattr
* __sigaction
* sigaction
* __sigaddset
* sigaddset
* sigfillset
* __sigprocmask
* sigprocmask
* __sleep
* sleep
* _splitpath
* srand
* srand48
* __srand48_r
* srand48_r
* __srandom
* srandom
* __srandom_r
* srandom_r
* __stat
* stat
* __stat64
* stat64
* stat64_to_32
* __statfs
* statfs
* __statfs64
* statfs64
* __statfsbsd
* statfsbsd
* __statfsx64
* statfsx64
* __statvfs
* statvfs
* __statvfs64
* statvfs64
* __stpcpy
* stpcpy
* __stpncpy
* stpncpy
* __strchrnul
* strchrnul
* __strerror_r
* strerror_r
* strfry
* strlcat
* strlcpy
* strmode
* __strncasecmp
* strncasecmp
* __strndup
* strndup
* __strnlen
* strnlen
* strptime
* __strsep
* strsep
* __strsep_g
* strsignal
* __strtok_r
* strtok_r
* __strverscmp
* strverscmp
* symlink
* sync
* _sys_errlist_internal
* _sys_nerr_internal
* _sys_siglist
* sys_siglist
* _sys_siglist_internal
* syscall
* __sysconf
* sysconf
* sysinfo
* tcdrain
* tcflow
* tcflush
* __tcgetattr
* tcgetattr
* tcgetpgrp
* tcgetsid
* tcsendbreak
* tcsetattr
* tcsetpgrp
* __tdelete
* tdelete
* __tdestroy
* tdestroy
* __telldir
* telldir
* tempnam
* __tfind
* tfind
* __times
* times
* tm_year_base
* tmpfile
* tmpfile64
* tmpnam
* tmpnam_r
* __truncate
* truncate
* __truncate64
* truncate64
* __tsearch
* tsearch
* ttyname
* __twalk
* twalk
* __tzname_cur_max
* __tzname_max
* _ufc_dofinalperm_r
* _ufc_doit_r
* _ufc_foobar
* _ufc_mk_keytab_r
* _ufc_output_conversion_r
* _ufc_setup_salt_r
* __ulimit
* ulimit
* __uname
* uname
* unix2winpath
* __unlink
* unlink
* unsetenv
* usleep
* ustat
* utime
* __utimes
* utimes
* verr
* verrx
* versionsort
* versionsort64
* vlimit
* vsn2drive
* vwarn
* vwarnx
* __w32_gethostbyaddr
* w32_gethostbyaddr
* __w32_gethostbyname
* w32_gethostbyname
* __w32_gethostname
* w32_gethostname
* w32_same_file
* __wait
* wait
* __wait3
* wait3
* __wait4
* wait4
* __waitid
* waitid
* __waitpid
* waitpid
* warn
* warnx
* werrno
* win2posixfullpath
* win2posixpath
* win2unixpath
* win32_longpath
* WinErr
* winmajor
* winminor
* winos
* winplatform
* _wordcopy_bwd_aligned
* _wordcopy_bwd_dest_aligned
* _wordcopy_fwd_aligned
* _wordcopy_fwd_dest_aligned
* ws_cleanup
* ws_init
* WSAErr
* __xmknod
* _xmknod
* __xpg_basename
* __xstat
* _xstat
* __xstat64

The documentation of most of these functions is in the Glibc-documentation, in the Linux manpages and in the FreeBsd manpages.
Homepage

http://www.gnu.org/software/libc/libc.html

Sources:
Download


Description Download Size Last change Md5sum

• Developer files Zip 643174 10 January 2004 55b41650239b13d2b0d79c100d160665
• Sources Zip 2226097 10 January 2004 f8c7c821033c9ed141c347edf3c30477
• Original source

You can also download the files from the GnuWin32 files page. New releases of the port of this package can be monitored.

Wednesday, July 23, 2008

SSH Connection Protocol

Status of This memo

This document is an Internet-Draft and is in full conformance
with all provisions of Section 10 of RFC2026.

Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF), its areas, and its working groups. Note that
other groups may also distribute working documents as
Internet-Drafts.

Internet-Drafts are draft documents valid for a maximum of six
months and may be updated, replaced, or obsoleted by other
documents at any time. It is inappropriate to use Internet-
Drafts as reference material or to cite them other than as
"work in progress."

The list of current Internet-Drafts can be accessed at
http://www.ietf.org/ietf/1id-abstracts.txt

The list of Internet-Draft Shadow Directories can be accessed at
http://www.ietf.org/shadow.html.

Abstract

SSH is a protocol for secure remote login and other secure network ser-
vices over an insecure network. This document describes the SSH Connec-
tion Protocol. It provides interactive login sessions, remote execution
of commands, forwarded TCP/IP connections, and forwarded X11 connec-
tions. All of these channels are multiplexed into a single encrypted
tunnel. The SSH Connection Protocol has been designed to run on top of
the SSH transport layer and user authentication protocols.














T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 1]

INTERNET-DRAFT 21 Nov, 2000

Table of Contents

1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2. Global Requests . . . . . . . . . . . . . . . . . . . . . . . . 2
3. Channel Mechanism . . . . . . . . . . . . . . . . . . . . . . . 3
3.1. Opening a Channel . . . . . . . . . . . . . . . . . . . . . 3
3.2. Data Transfer . . . . . . . . . . . . . . . . . . . . . . . 4
3.3. Closing a Channel . . . . . . . . . . . . . . . . . . . . . 5
3.4. Channel-Specific Requests . . . . . . . . . . . . . . . . . 5
4. Interactive Sessions . . . . . . . . . . . . . . . . . . . . . . 6
4.1. Opening a Session . . . . . . . . . . . . . . . . . . . . . 6
4.2. Requesting a Pseudo-Terminal . . . . . . . . . . . . . . . . 6
4.3. X11 Forwarding . . . . . . . . . . . . . . . . . . . . . . . 7
4.3.1. Requesting X11 Forwarding . . . . . . . . . . . . . . . 7
4.3.2. X11 Channels . . . . . . . . . . . . . . . . . . . . . . 8
4.4. Environment Variable Passing . . . . . . . . . . . . . . . . 8
4.5. Starting a Shell or a Command . . . . . . . . . . . . . . . 8
4.6. Session Data Transfer . . . . . . . . . . . . . . . . . . . 9
4.7. Window Dimension Change Message . . . . . . . . . . . . . . 9
4.8. Local Flow Control . . . . . . . . . . . . . . . . . . . . . 9
4.9. Signals . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.10. Returning Exit Status . . . . . . . . . . . . . . . . . . . 10
5. TCP/IP Port Forwarding . . . . . . . . . . . . . . . . . . . . . 11
5.1. Requesting Port Forwarding . . . . . . . . . . . . . . . . . 11
5.2. TCP/IP Forwarding Channels . . . . . . . . . . . . . . . . . 12
6. Encoding of Terminal Modes . . . . . . . . . . . . . . . . . . . 13
7. Summary of Message Numbers . . . . . . . . . . . . . . . . . . . 15
8. Security Considerations . . . . . . . . . . . . . . . . . . . . 15
9. Trademark Issues . . . . . . . . . . . . . . . . . . . . . . . . 16
10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 16
11. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 16



1. Introduction

The SSH Connection Protocol has been designed to run on top of the SSH
transport layer and user authentication protocols. It provides
interactive login sessions, remote execution of commands, forwarded
TCP/IP connections, and forwarded X11 connections. The service name for
this protocol (after user authentication) is "ssh-connection".

This document should be read only after reading the SSH architecture
document [SSH-ARCH]. This document freely uses terminology and notation
from the architecture document without reference or further explanation.

2. Global Requests

There are several kinds of requests that affect the state of the remote
end "globally", independent of any channels. An example is a request to
start TCP/IP forwarding for a specific port. All such requests use the
following format.



T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 2]

INTERNET-DRAFT 21 Nov, 2000

byte SSH_MSG_GLOBAL_REQUEST
string request name (restricted to US-ASCII)
boolean want reply
... request-specific data follows

The recipient will respond to this message with SSH_MSG_REQUEST_SUCCESS,
SSH_MSG_REQUEST_FAILURE, or some request-specific continuation messages
if `want reply' is TRUE.

byte SSH_MSG_REQUEST_SUCCESS

If the recipient does not recognize or support the request, it simply
responds with SSH_MSG_REQUEST_FAILURE.

byte SSH_MSG_REQUEST_FAILURE

3. Channel Mechanism

All terminal sessions, forwarded connections, etc. are channels. Either
side may open a channel. Multiple channels are multiplexed into a
single connection.

Channels are identified by numbers at each end. The number referring to
a channel may be different on each side. Requests to open a channel
contain the sender's channel number. Any other channel-related messages
contain the recipient's channel number for the channel.

Channels are flow-controlled. No data may be sent to a channel until a
message is received to indicate that window space is available.

3.1. Opening a Channel

When either side wishes to open a new channel, it allocates a local
number for the channel. It then sends the following message to the
other side, and includes the local channel number and initial window
size in the message.

byte SSH_MSG_CHANNEL_OPEN
string channel type (restricted to US-ASCII)
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
... channel type specific data follows

The channel type is a name as described in the SSH architecture
document, with similar extension mechanisms. `sender channel' is a local
identifier for the channel used by the sender of this message. `initial
window size' specifies how many bytes of channel data can be sent to the
sender of this message without adjusting the window. `Maximum packet
size' specifies the maximum size of an individual data packet that can
be sent to the sender (for example, one might want to use smaller
packets for interactive connections to get better interactive response
on slow links).


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 3]

INTERNET-DRAFT 21 Nov, 2000

The remote side then decides whether it can open the channel, and
responds with either
byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION
uint32 recipient channel
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
... channel type specific data follows

where `recipient channel' is the channel number given in the original
open request, and `sender channel' is the channel number allocated by
the other side, or

byte SSH_MSG_CHANNEL_OPEN_FAILURE
uint32 recipient channel
uint32 reason code
string additional textual information (ISO-10646 UTF-8
[RFC-2044])
string language tag (as defined in [RFC-1766])

If the recipient of the SSH_MSG_CHANNEL_OPEN message does not support
the specified channel type, it simply responds with
SSH_MSG_CHANNEL_OPEN_FAILURE. The client MAY show the additional
information to the user. If this is done, the client software should
take the precautions discussed in [SSH-ARCH].

The following reason codes are defined:

#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
#define SSH_OPEN_CONNECT_FAILED 2
#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
#define SSH_OPEN_RESOURCE_SHORTAGE 4

3.2. Data Transfer

The window size specifies how many bytes the other party can send before
it must wait for the window to be adjusted. Both parties use the
following message to adjust the window.

byte SSH_MSG_CHANNEL_WINDOW_ADJUST
uint32 recipient channel
uint32 bytes to add

After receiving this message, the recipient MAY send the given number of
bytes more than it was previously allowed to send; the window size is
incremented.

Data transfer is done with messages of the following type.

byte SSH_MSG_CHANNEL_DATA
uint32 recipient channel
string data



T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 4]

INTERNET-DRAFT 21 Nov, 2000

The maximum amount of data allowed is the current window size. The
window size is decremented by the amount of data sent. Both parties MAY
ignore all extra data sent after the allowed window is empty.

Additionally, some channels can transfer several types of data. An
example of this is stderr data from interactive sessions. Such data can
be passed with SSH_MSG_CHANNEL_EXTENDED_DATA messages, where a separate
integer specifies the type of the data. The available types and their
interpretation depend on the type of the channel.

byte SSH_MSG_CHANNEL_EXTENDED_DATA
uint32 recipient_channel
uint32 data_type_code
string data

Data sent with these messages consumes the same window as ordinary data.

Currently, only the following type is defined.

#define SSH_EXTENDED_DATA_STDERR 1

3.3. Closing a Channel

When a party will no longer send more data to a channel, it SHOULD send
SSH_MSG_CHANNEL_EOF.

byte SSH_MSG_CHANNEL_EOF
uint32 recipient_channel

No explicit response is sent to this message; however, the application
may send EOF to whatever is at the other end of the channel. Note that
the channel remains open after this message, and more data may still be
sent in the other direction. This message does not consume window space
and can be sent even if no window space is available.

When either party wishes to terminate the channel, it sends
SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST send
back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this message for
the channel. The channel is considered closed for a party when it has
both sent and received SSH_MSG_CHANNEL_CLOSE, and the party may then
reuse the channel number. A party MAY send SSH_MSG_CHANNEL_CLOSE
without having sent or received SSH_MSG_CHANNEL_EOF.
byte SSH_MSG_CHANNEL_CLOSE
uint32 recipient_channel

This message does not consume window space and can be sent even if no
window space is available.

It is recommended that any data sent before this message is delivered to
the actual destination, if possible.

3.4. Channel-Specific Requests



T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 5]

INTERNET-DRAFT 21 Nov, 2000

Many channel types have extensions that are specific to that particular
channel type. An example is requesting a pty (pseudo terminal) for an
interactive session.

All channel-specific requests use the following format.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string request type (restricted to US-ASCII)
boolean want reply
... type-specific data

If want reply is FALSE, no response will be sent to the request.
Otherwise, the recipient responds with either SSH_MSG_CHANNEL_SUCCESS or
SSH_MSG_CHANNEL_FAILURE, or request-specific continuation messages. If
the request is not recognized or is not supported for the channel,
SSH_MSG_CHANNEL_FAILURE is returned.

This message does not consume window space and can be sent even if no
window space is available. Request types are local to each channel type.

The client is allowed to send further messages without waiting for the
response to the request.

byte SSH_MSG_CHANNEL_SUCCESS
uint32 recipient_channel

byte SSH_MSG_CHANNEL_FAILURE
uint32 recipient_channel

These messages do not consume window space and can be sent even if no
window space is available.
4. Interactive Sessions

A session is a remote execution of a program. The program may be a
shell, an application, a system command, or some built-in subsystem. It
may or may not have a tty, and may or may not involve X11 forwarding.
Multiple sessions can be active simultaneously.

4.1. Opening a Session

A session is started by sending the following message.

byte SSH_MSG_CHANNEL_OPEN
string "session"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size

Client implementations SHOULD reject any session channel open requests
to make it more difficult for a corrupt server to attack the client.




T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 6]

INTERNET-DRAFT 21 Nov, 2000

4.2. Requesting a Pseudo-Terminal

A pseudo-terminal can be allocated for the session by sending the
following message.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient_channel
string "pty-req"
boolean want_reply
string TERM environment variable value (e.g., vt100)
uint32 terminal width, characters (e.g., 80)
uint32 terminal height, rows (e.g., 24)
uint32 terminal width, pixels (e.g., 480)
uint32 terminal height, pixels (e.g., 640)
string encoded terminal modes

The encoding of terminal modes is described in Section ``Encoding of
Terminal Modes''. Zero dimension parameters MUST be ignored. The
character/row dimensions override the pixel dimensions (when nonzero).
Pixel dimensions refer to the drawable area of the window.

The dimension parameters are only informational.

The client SHOULD ignore pty requests.

4.3. X11 Forwarding

4.3.1. Requesting X11 Forwarding

X11 forwarding may be requested for a session by sending

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "x11-req"
boolean want reply
boolean single connection
string x11 authentication protocol
string x11 authentication cookie
uint32 x11 screen number

It is recommended that the authentication cookie that is sent be a fake,
random cookie, and that the cookie is checked and replaced by the real
cookie when a connection request is received.

X11 connection forwarding should stop when the session channel is
closed; however, already opened forwardings should not be automatically
closed when the session channel is closed.

If `single connection' is TRUE, only a single connection should be
forwarded. No more connections will be forwarded after the first, or
after the session channel has been closed.

`X11 authentication protocol is the name of the X11 authentication


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 7]

INTERNET-DRAFT 21 Nov, 2000

method used, i.e. "MIT-MAGIC-COOKIE-1".

X Protocol is documented in [Scheifler].

4.3.2. X11 Channels

X11 channels are opened with a channel open request. The resulting
channels are independent of the session, and closing the session channel
does not close the forwarded X11 channels.

byte SSH_MSG_CHANNEL_OPEN
string "x11"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
string originator address (e.g. "192.168.7.38")
uint32 originator port

The recipient should respond with SSH_MSG_CHANNEL_OPEN_CONFIRMATION or
SSH_MSG_CHANNEL_OPEN_FAILURE.

Implementations MUST reject any X11 channel open requests if they have
not requested X11 forwarding.

4.4. Environment Variable Passing

Environment variables may be passed to the shell/command to be started
later. Typically, each machine will have a preconfigured set of
variables that it will allow. Since uncontrolled setting of environment
variables can be very dangerous, it is recommended that implementations
allow setting only variables whose names have been explicitly configured
to be allowed.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "env"
boolean want reply
string variable name
string variable value

4.5. Starting a Shell or a Command

Once the session has been set up, a program is started at the remote
end. The program can be a shell, an application program or a subsystem
with a host-independent name. Only one of these requests can succeed
per channel.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "shell"
boolean want reply

This message will request the user's default shell (typically defined in


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 8]

INTERNET-DRAFT 21 Nov, 2000

/etc/passwd in UNIX systems) to be started at the other end.
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exec"
boolean want reply
string command

This message will request the server to start the execution of the given
command. The command string may contain a path. Normal precautions MUST
be taken to prevent the execution of unauthorized commands.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "subsystem"
boolean want reply
string subsystem name

This last form executes a predefined subsystem. It expected that these
will include a general file transfer mechanism, and possibly other
features. Implementations may also allow configuring more such
mechanisms.

The server SHOULD not halt the execution of the protocol stack when
starting a shell or a program. All input and output from these SHOULD be
redirected to the channel or to the encrypted tunnel.

It is RECOMMENDED to request and check the reply for these messages. The
client SHOULD ignore these messages.

4.6. Session Data Transfer

Data transfer for a session is done using SSH_MSG_CHANNEL_DATA and
SSH_MSG_CHANNEL_EXTENDED_DATA packets and the window mechanism. The
extended data type SSH_EXTENDED_DATA_STDERR has been defined for stderr
data.

4.7. Window Dimension Change Message

When the window (terminal) size changes on the client side, it MAY send
a message to the other side to inform it of the new dimensions.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient_channel
string "window-change"
boolean FALSE
uint32 terminal width, columns
uint32 terminal height, rows
uint32 terminal width, pixels
uint32 terminal height, pixels

No response SHOULD be sent to this message.




T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 9]

INTERNET-DRAFT 21 Nov, 2000

4.8. Local Flow Control

On many systems, it is possible to determine if a pseudo-terminal is
using control-S/control-Q flow control. When flow control is allowed,
it is often desirable to do the flow control at the client end to speed
up responses to user requests. This is facilitated by the following
notification. Initially, the server is responsible for flow control.
(Here, again, client means the side originating the session, and server
means the other side.)

The message below is used by the server to inform the client when it can
or cannot perform flow control (control-S/control-Q processing). If
`client can do' is TRUE, the client is allowed to do flow control using
control-S and control-Q. The client MAY ignore this message.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "xon-xoff"
boolean FALSE
boolean client can do

No response is sent to this message.

4.9. Signals

A signal can be delivered to the remote process/service using the
following message. Some systems may not implement signals, in which
case they SHOULD ignore this message.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "signal"
boolean FALSE
string signal name without the "SIG" prefix.

Signal names will be encoded as discussed in the "exit-signal"
SSH_MSG_CHANNEL_REQUEST.

4.10. Returning Exit Status

When the command running at the other end terminates, the following
message can be sent to return the exit status of the command. Returning
the status is RECOMMENDED. No acknowledgment is sent for this message.
The channel needs to be closed with SSH_MSG_CHANNEL_CLOSE after this
message.

The client MAY ignore these messages.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient_channel
string "exit-status"
boolean FALSE
uint32 exit_status


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 10]

INTERNET-DRAFT 21 Nov, 2000

The remote command may also terminate violently due to a signal. Such a
condition can be indicated by the following message. A zero exit_status
usually means that the command terminated successfully.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exit-signal"
boolean FALSE
string signal name without the "SIG" prefix.
boolean core dumped
string error message (ISO-10646 UTF-8 [RFC-2044])
string language tag (as defined in [RFC-1766])

The signal name is one of the following (these are from [POSIX]):

ABRT
ALRM
FPE
HUP
ILL
INT
KILL
PIPE
QUIT
SEGV
TERM
USR1
USR2

Additional signal names MAY be sent in the format "sig-name@xyz", where
`sig-name' and `xyz' may be anything a particular implementor wants
(except the `@' sign). However, it is suggested that if a `configure'
script is used, the non-standard signal names it finds be encoded as
"SIG@xyz.config.guess", where `SIG' is the signal name without the "SIG"
prefix, and `xyz' be the host type, as determined by `config.guess'.

The `error message' contains an additional explanation of the error
message. The message may consist of multiple lines. The client software
MAY display this message to the user. If this is done, the client
software should take the precautions discussed in [SSH-ARCH].

5. TCP/IP Port Forwarding

5.1. Requesting Port Forwarding

A party need not explicitly request forwardings from its own end to the
other direction. However, if it wishes that connections to a port on
the other side be forwarded to the local side, it must explicitly
request this.

byte SSH_MSG_GLOBAL_REQUEST
string "tcpip-forward"
boolean want reply


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 11]

INTERNET-DRAFT 21 Nov, 2000

string address to bind (e.g. "0.0.0.0")
uint32 port number to bind

`Address to bind' and `port number to bind' specify the IP address and
port to which the socket to be listened is bound. The address should be
"0.0.0.0" if connections are allowed from anywhere. (Note that the
client can still filter connections based on information passed in the
open request.)

Implementations should only allow forwarding privileged ports if the
user has been authenticated as a privileged user.

Client implementations SHOULD reject these messages; they are normally
only sent by the client.

A port forwarding can be cancelled with the following message. Note
that channel open requests may be received until a reply to this message
is received.

byte SSH_MSG_GLOBAL_REQUEST
string "cancel-tcpip-forward"
boolean want reply
string address_to_bind (e.g. "127.0.0.1")
uint32 port number to bind

Client implementations SHOULD reject these messages; they are normally
only sent by the client.

5.2. TCP/IP Forwarding Channels

When a connection comes to a port for which remote forwarding has been
requested, a channel is opened to forward the port to the other side.

byte SSH_MSG_CHANNEL_OPEN
string "forwarded-tcpip"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
string address that was connected
uint32 port that was connected
string originator IP address
uint32 originator port

Implementations MUST reject these messages unless they have previously
requested a remote TCP/IP port forwarding with the given port number.

When a connection comes to a locally forwarded TCP/IP port, the
following packet is sent to the other side. Note that these messages
MAY be sent also for ports for which no forwarding has been explicitly
requested. The receiving side must decide whether to allow the
forwarding.

byte SSH_MSG_CHANNEL_OPEN


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 12]

INTERNET-DRAFT 21 Nov, 2000

string "direct-tcpip"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
string host to connect
uint32 port to connect
string originator IP address
uint32 originator port

`Host to connect' and `port to connect' specify the TCP/IP host and port
where the recipient should connect the channel. `Host to connect' may
be either a domain name or a numeric IP address.

`Originator IP address' is the numeric IP address of the machine where
the connection request comes from, and `originator port' is the port on
the originator host from where the connection came from.

Forwarded TCP/IP channels are independent of any sessions, and closing a
session channel does not in any way imply that forwarded connections
should be closed.

Client implementations SHOULD reject direct TCP/IP open requests for
security reasons.

6. Encoding of Terminal Modes

Terminal modes (as passed in a pty request) are encoded into a byte
stream. It is intended that the coding be portable across different
environments.

The tty mode description is a stream of bytes. The stream consists of
opcode-argument pairs. It is terminated by opcode TTY_OP_END (0).
Opcodes 1 to 159 have a single uint32 argument. Opcodes 160 to 255 are
not yet defined, and cause parsing to stop (they should only be used
after any other data).

The client SHOULD put in the stream any modes it knows about, and the
server MAY ignore any modes it does not know about. This allows some
degree of machine-independence, at least between systems that use a
POSIX-like tty interface. The protocol can support other systems as
well, but the client may need to fill reasonable values for a number of
parameters so the server pty gets set to a reasonable mode (the server
leaves all unspecified mode bits in their default values, and only some
combinations make sense).

The following opcodes have been defined. The naming of opcodes mostly
follows the POSIX terminal mode flags.

0 TTY_OP_END Indicates end of options.
1 VINTR Interrupt character; 255 if none. Similarly for the
other characters. Not all of these characters are
supported on all systems.
2 VQUIT The quit character (sends SIGQUIT signal on POSIX


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 13]

INTERNET-DRAFT 21 Nov, 2000

systems).
3 VERASE Erase the character to left of the cursor.
4 VKILL Kill the current input line.
5 VEOF End-of-file character (sends EOF from the terminal).
6 VEOL End-of-line character in addition to carriage return
and/or linefeed.
7 VEOL2 Additional end-of-line character.
8 VSTART Continues paused output (normally control-Q).
9 VSTOP Pauses output (normally control-S).
10 VSUSP Suspends the current program.
11 VDSUSP Another suspend character.
12 VREPRINT Reprints the current input line.
13 VWERASE Erases a word left of cursor.
14 VLNEXT Enter the next character typed literally, even if it
is a special character
15 VFLUSH Character to flush output.
16 VSWTCH Switch to a different shell layer.
17 VSTATUS Prints system status line (load, command, pid etc).
18 VDISCARD Toggles the flushing of terminal output.
30 IGNPAR The ignore parity flag. The parameter SHOULD be 0 if
this flag is FALSE set, and 1 if it is TRUE.
31 PARMRK Mark parity and framing errors.
32 INPCK Enable checking of parity errors.
33 ISTRIP Strip 8th bit off characters.
34 INLCR Map NL into CR on input.
35 IGNCR Ignore CR on input.
36 ICRNL Map CR to NL on input.
37 IUCLC Translate uppercase characters to lowercase.
38 IXON Enable output flow control.
39 IXANY Any char will restart after stop.
40 IXOFF Enable input flow control.
41 IMAXBEL Ring bell on input queue full.
50 ISIG Enable signals INTR, QUIT, [D]SUSP.
51 ICANON Canonicalize input lines.
52 XCASE Enable input and output of uppercase characters by
preceding their lowercase equivalents with `\'.
53 ECHO Enable echoing.
54 ECHOE Visually erase chars.
55 ECHOK Kill character discards current line.
56 ECHONL Echo NL even if ECHO is off.
57 NOFLSH Don't flush after interrupt.
58 TOSTOP Stop background jobs from output.
59 IEXTEN Enable extensions.
60 ECHOCTL Echo control characters as ^(Char).
61 ECHOKE Visual erase for line kill.
62 PENDIN Retype pending input.
70 OPOST Enable output processing.
71 OLCUC Convert lowercase to uppercase.
72 ONLCR Map NL to CR-NL.
73 OCRNL Translate carriage return to newline (output).
74 ONOCR Translate newline to carriage return-newline
(output).
75 ONLRET Newline performs a carriage return (output).


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 14]

INTERNET-DRAFT 21 Nov, 2000

90 CS7 7 bit mode.
91 CS8 8 bit mode.
92 PARENB Parity enable.
93 PARODD Odd parity, else even.

128 TTY_OP_ISPEED Specifies the input baud rate in bits per second.
129 TTY_OP_OSPEED Specifies the output baud rate in bits per second.

7. Summary of Message Numbers

#define SSH_MSG_GLOBAL_REQUEST 80
#define SSH_MSG_REQUEST_SUCCESS 81
#define SSH_MSG_REQUEST_FAILURE 82
#define SSH_MSG_CHANNEL_OPEN 90
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91
#define SSH_MSG_CHANNEL_OPEN_FAILURE 92
#define SSH_MSG_CHANNEL_WINDOW_ADJUST 93
#define SSH_MSG_CHANNEL_DATA 94
#define SSH_MSG_CHANNEL_EXTENDED_DATA 95
#define SSH_MSG_CHANNEL_EOF 96
#define SSH_MSG_CHANNEL_CLOSE 97
#define SSH_MSG_CHANNEL_REQUEST 98
#define SSH_MSG_CHANNEL_SUCCESS 99
#define SSH_MSG_CHANNEL_FAILURE 100

8. Security Considerations

This protocol is assumed to run on top of a secure, authenticated
transport. User authentication and protection against network-level
attacks are assumed to be provided by the underlying protocols.

This protocol can, however, be used to execute commands on remote
machines. The protocol also permits the server to run commands on the
client. Implementations may wish to disallow this to prevent an
attacker from coming from the server machine to the client machine.

X11 forwarding provides major security improvements over normal cookie-
based X11 forwarding. The cookie never needs to be transmitted in the
clear, and traffic is encrypted and integrity-protected. No useful
authentication data will remain on the server machine after the
connection has been closed. On the other hand, in some situations a
forwarded X11 connection might be used to get access to the local X
server across security perimeters.

Port forwardings can potentially allow an intruder to cross security
perimeters such as firewalls. They do not offer anything fundamentally
new that a user could not do otherwise; however, they make opening
tunnels very easy. Implementations should allow policy control over
what can be forwarded. Administrators should be able to deny
forwardings where appropriate.

Since this protocol normally runs inside an encrypted tunnel, firewalls
will not be able to examine the traffic.


T. Ylonen, T. Kivinen, M. Saarinen, T. Rinne and S. Lehtinen [page 15]

INTERNET-DRAFT 21 Nov, 2000

It is RECOMMENDED that implementations disable all the potentially
dangerous features (e.g. agent forwarding, X11 forwarding, and TCP/IP
forwarding) if the host key has changed.

9. Trademark Issues

SSH is a registered trademark and Secure Shell is a trademark of SSH
Communications Security Corp. SSH Communications Security Corp permits
the use of these trademarks as the name of this standard and protocol,
and permits their use to describe that a product conforms to this
standard, provided that the following acknowledgement is included where
the trademarks are used: ``SSH is a registered trademark and Secure
Shell is a trademark of SSH Communications Security Corp
(www.ssh.com)''. These trademarks may not be used as part of a product
name or in otherwise confusing manner without prior written permission
of SSH Communications Security Corp

port setting from linux journel

The Pro-Lite Tru-Color II PL-M2014R is an affordable multi-color LED scrolling message board that is capable of being controlled by a standard RS-232 serial port. The sign is obtainable from Pro-Lite directly (http://www.pro-lite.com/), but can also be purchased at various discount warehouses for approximately $150. The serial cable and Windows software are sold separately.

This article is not just a review; it can serve as a primer for Pro-Lite's PL-M2014R with ROM release 5.24Q and 32K of memory with Trivia mode, basically your standard sign. Until now, not much developer information has been available to the public, meaning signs were usually configured with the included infrared remote control to display static messages. For very little money, it is possible to build your own serial cable and control the sign using Linux to display more than static text.

The business and personal applications for a highly visible sign are almost limitless: reporting days until software delivery, announcing traffic congestion, providing the weather, showing the date and time, sending public messages, reporting system load, announcing new mail, showing who's logged in, warning when disk space gets low, login information, announcing unexpected server outages as a watchdog, etc.

Communicating with the sign is almost as simple as beaming text out the serial port; however, a bit of text manipulation is necessary in order to get the sign to respond and do advanced tasks. Linux handles the serial port communication, so sending information to the sign appears as trivial as writing to a file.

Luckily, the majority of the work can be accomplished by simple scripts. All you need is a basic understanding of the shell, AWK, PERL or Python, and you can be running in almost no time. The first hurdle is to build a cable and configure Linux to talk out the serial port.

Cable Construction

Figure 1. Female DB9 Adapter

The first step is wiring an RJ12 to female DB9 adapter. It requires no tools, and an adapter kit can be purchased at most computer supply stores for about $2 US. The only other thing you need is a length of RJ12 cable with male adapters at each end. This means a standard telephone cord will do nicely. Your cable will most likely have the standard colors black, red, green and yellow, in that order.

Cables come in two flavors: straight-thru and reversed. You'll need to take the RJ12 cable and put it end to end (like a loop) to find out which kind of adapter you need to build.

Figure 2. RJ12 Adapter Diagram

One of two things will be noticeable: either the wires will match black to black, red to red and so on, or they will reverse their order showing black to yellow, red to green and so on.

If the cable is a straight-through, where the colors match, wire your RJ12 to a DB9 adapter using Pin 2 as green, Pin 3 as red and Pin 5 as yellow. If the cable is reversed, then where the colors reverse sequence, wire your RJ12 to a DB9 adapter using Pin 2 as red, Pin 3 as green and Pin 5 as black.

Figure 3. RJ12 to DB9 Wiring

Shove the unused adapter wires into the casing and snap the adapter shut. Take care not to let the exposed ends touch anything metal inside the adapter casing. You may want to clip the unused wires. Put an extension cable on your serial port and connect the adapter wires directly to the extension cable in order to test the wiring configuration before pushing the pins into the connector.

When all is said and done, one end of the RJ12 goes into the side of the LED sign, the other into the adapter you just made, and the adapter plugs into the computer.

Configuring Linux to Talk to the Sign

My sign is plugged into COM1, also known as /dev/ttyS0. I've elected to use a symbolic link to the sign, in the event I ever decide to change to another serial port in the future. To make the link, as root type:

ln -s /dev/ttyS0 /dev/prolite

I tend to shy away from doing development as root. Putting security issues aside for the moment, we can make the device world-writable by typing:

chmod a+rw /dev/prolite

The sign communicates using No Parity, 8 Bits, 1 Stop Bit; no handshaking of any kind (hardware or software) is used. Early versions of the sign work only at 300 baud, but they can be upgraded to 9600 baud. All signs I've encountered had the 9600 capability right out of the box. The bottom line is that all signs are capable of communication, and even at 300 baud you can outrun the sign. The only drawback is that the sign's baud rate has to be set by the remote control, according to the setup in the manual. This needs to be done only once.

In theory, the sign requires a 15ms delay between each character sent to the sign. I've found that Linux's device driver seems to work just fine without having to do anything special in the software.

stty speed 9600 cs8 -parenb -cstopb cread \

-clocal -crtscts -ignpar -echo nl1 cr3 < \
/dev/prolite

Naturally, you can substitute any baud rate the sign will handle for the 9600. This command will work when you aren't root because it is world-writable.

The most important piece of information for communicating with the sign is that each command sent to the sign must end with a carriage return/newline pair. This is ctrl-M ctrl-J on the keyboard or 0x0C 0x0A in hexadecimal. C programmers will recognize it as \r\n. If you want Linux to handle the end-of-line sequence for you, type the command:

stty opost -ocrnl onlcr < /dev/prolite

When you send a newline, Linux will send both carriage return/newline automatically. Text can now be listed or redirected to /dev/prolite from the shell. If you want to send the carriage returns yourself, type:

stty -opost -ocrnl -onlcr < /dev/prolite

Where the options are defined as:
  • opost: postprocess the output stream.

  • -opost: do not postprocess the output stream.

  • -ocrnl: do not convert carriage returns into newlines.

  • -onlcr: do not translate each newline into a carriage return/newline pair.

  • onlcr: translate each newline into a carriage return/newline pair.

The stty command allows for a shorthand representation of all the termios structures that define the device characteristics. For 9600,N,8,1 with automatic carriage returns, type on one line:
stty 0:705:bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:

12:f:17:16:0:0:73 < /dev/prolite
For 9600,N,8,1 with no automatic carriage returns, use the line:
stty 0:700:bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:

12:f:17:16:0:0:73 < /dev/prolite
Command Syntax

Only a minimal understanding is needed in order to operate the sign. Mastery requires becoming familiar with the protocol and doing a little experimenting.

Multiple signs can be connected to a computer over the same serial port by using a simple telephone-line-splitting Y-connector. Each sign has an assignable logical address that allows you to send messages to particular signs. A logical address is represented in hexadecimal as a number between 01 and FF. Addresses may be shared enabling grouping; in this way, a message to ID01 goes to all signs with ID01.

Communication with the sign is always done with readable ASCII characters; thus, an arbitrary ID of 2F would be designated with the digit “2” and the capital letter “F”.

ID00 is reserved to mean “broadcast to all signs”. By default, a sign is preconfigured as ID01; this can be changed with the remote control. If you are addressing a single sign connected straight to the computer, it will respond with its ID number after each successful command. Messages sent to ID00 do not return a response, and neither does an individual sign when the line is shared via the Y-connector.

All messages to the sign, except for those setting the date and time, are sent in the following format followed by the carriage return/line feed: xx>command, xx is 00 to FF. Any command longer than 1,023 bytes will be ignored by the sign.

To set the date and time, no ID is needed. The format is <TYYMMDDwhhmmss> where YY is the year, MM the month, DD the day, w the weekday (0=Sun, 1=Mon,...6=Sat), hh the hour, mm the minute and ss the seconds. This can be accomplished with the shell very easily. Set the date/time of all signs with the command:

ate "+" te "+" > /dev/prolite> /dev/prolite

The leading + sign tells the date command to build a string via substitution; see your man pages for details.

To signal a sign to start listening to responses, send it an empty command with the format xx>; e.g., type:

echo "" > /dev/prolite

Pages

The most fundamental concept of the sign is the idea of a page. A page consists of a message the sign is to display either now or some time in the future. Pages may contain text, numerics, symbols, font attribute tags, color tags, graphic tags and effect tags. There are 26 pages named, appropriately enough, A to Z. Case does matter when identifying a page.

Any given page can hold approximately 1,012 bytes of information. I say approximately because special tags (see sidebar) consume more than one byte, which means less space. Also, using some trickery by omitting the page directive completely and defaulting to page A squeezes out an additional two bytes, which means more space.

The command to set a page is x>, where x is the page name. Any text after this sequence is considered text for the sign. To set the message “Linux Rules” on page A, type the following command:

echo "Linux Rules" > /dev/prolite

It is important to leave extra space at the end so the end of the message is separated from the front of the message as it scrolls.

To delete a page, use x>, where x is the page name. For example, to delete page B, type:

echo "" > /dev/prolite

Displaying Pages

The sign is constantly displaying a page. If the default page A is scrolling by, then when its content is changed it will immediately start displaying the new message. Otherwise, we must tell the sign which page to run using the x> command, where x is the page to display. Normally, the sign can run only one page at a time.

Once a page has been defined, it can be run. For example, to repeatedly display our message, type:

echo "" > /dev/prolite

Running an undefined page will result in displaying the sign's demo.

Two points of interest for script writers:

  1. It is possible to update the contents of a page not being displayed, then switch to that page at a later time.

  2. It is possible to update the currently displayed message. The only problem is the display will be interrupted mid-message.

Sadly, you cannot ask the sign what the contents of a page are, what page it is currently displaying, or when it has started or ended a display sequence. Thus, techniques like double-buffering don't work for continuous messages.

I have received one terse message from Pro-Lite that alluded to a future version of the sign which is designed to address such needs explicitly for computer users.

Timers

In order to display one or more messages at a time, the sign includes ten timers named A to J. Each timer specifies a time and a series of 1 to 32 pages to sequence through. You may repeat pages in a sequence. The time a sequence is displayed consists of a weekday, an hour and a minute, any of which may be wildcarded (*) to match “all”.

When the first timer is defined, the sign is put into “timer” mode and will display that timer's messages immediately. Should two or more timers be defined, the sign seems to wait one minute, then checks each timer to see if one triggered based on the current time. If so, at the end of the displaying message, the new timer's sequence goes into effect. If no rule matches, no change is made.

Note the sign checks the rules for the immediate time. It will not go back to try to find a previous timer. So if you set a timer for 4:15PM and it is now 4:17PM, you've missed the moment when the sign would change.

Should two or more timers both be valid for the current time, the sign unpredictably selects one for display. This means you cannot set one timer to display at 4:15 and another timer to display at 15 minutes past any hour. Both rules would be triggered at 4:15 and it is a toss-up as to which message will be displayed.

The timer command is defined as x>dhhmmABC..., where x is the timer, d is 0 (Sunday) to 6 (Saturday) for the day, hh is a two-digit hour and mm is the minute. “ABC...” is a list of 1 to 32 pages to display in the order specified. Note that Page-A and Timer-A are two different, unrelated entities. A timer set for “*****” will be triggered immediately.

The following sequence will display a series of messages at 8:00AM, noon, 1:00PM and 5:00PM:

$ cat > /dev/prolite


Good morning.
Have a nice lunch.
Get back to work.
Have a safe drive home.
*0800A
*1200B
*1300C
*1700D
ctrl-D

In order to display a whole sequences of pages, just list more page letters. For instance, it is useful to make a scheme where you assign page letters to different message content. For example, page A could be hourly announcements, page R the runtime status of your machine, page M the message of the day, page T the time and so on. To display several pages right now (including repeats):

$ cat > /dev/prolite


*****TAMARA
ctrl-D
Two interesting tidbits of information:
  • For some reason, the specific time of Sunday at midnight (00000 as a timer value) does not seem to work consistently. I suspect it confuses this value with unset timers.

  • If a run-page command () is issued, the sign is taken out of “timer” mode and displays the requested page. If you then issue the command , the sign will go back into “timer” mode, displaying the last sequence of messages.

To delete a timer, use x>, where x is the timer letter or * for all timers. For example, to delete timer D type:
echo "" > /dev/prolite

Graphics

There are 26 graphic blocks that can be redefined and are commonly used for graphics. Graphics are inserted into the text via the tag x>, where x is a letter from A to Z. For example, this command will display a mug and a wine glass:

echo " Party Tonight "

>\
/dev/prolite

Altering the graphics requires the x> command followed by a string of 126 characters made up of R (for red), Y (for yellow), G (for green) and B (for black or unlit). A sequence of seven rows of eighteen LEDs is specified back to back on a single command line. (See Figure 4.)

Figure 4. A Graphics Block Specification

I know at least one user who loads a font into a sequence of graphic blocks, and in this way is able to display more characters than the sign technically allows by default—very clever.

To delete a graphic block, restoring it to the default, use x>, where x is a letter A to Z; * is a wildcard indicating all are to be deleted.

Trivia

One additional feature of the sign is to display in sequence a trivia question, your message, the answer to the question and your message again. It works its way though a canned list of questions and then starts over. The sign can be loaded with your own list, which does not have to be trivia. The list can be up to 16KB long, leaving 16KB for the pages. If no list is loaded (i.e., you deleted the trivia), the full 32KB of the sign is available for page content. To make your own list, do the following:

$ cat > /dev/prolite



What operating system isn't a pig?
Linux.
What operating system is free?
Linux.

Control-D

To delete the trivia, just omit the lines between and . If no messages are loaded, trivia mode is turned off. If they are, trivia is turned on.

Other Useful Commands and Tricks

To reset the sign, removing all timers and pages, use like this:

echo "" > /dev/prolite

Technically, there is no way to bring the sign to a halt. However, you can take advantage of a quirk in the software to do the same thing. If you use the tag in a message to control the speed of the sign, but don't supply a message, the old text isn't cleared and the sign stops scrolling until it gets a new message.

Function Tags

Additional tags are shown in “Function Tabs”. European tags are available for characters shown in Figure 5.

Figure 5. European Characters Available

Uses for the Sign

It doesn't take much to make the sign useful. For example, scripts that send commands to the sign can be executed every few minutes by editing your crontab file (crontab -e) to include:

*/5 * * * * /usr/local/bin/sign 1> /dev/null \

2> /dev/null

Every five minutes, the system will call /usr/local/bin/sign. In this script, we can place any number of tasks. To show our uptime, add these lines:

#!/bin/bash

stty 0:705:bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:12\
:f:17:16:0:0:73 < /dev/prolite
echo "'uptime' " > /dev/prolite
echo "*****U" > /dev/prolite
If root wants to see the last line of the log file scroll by, this command will suffice:
tail -f -n 1 /var/log/messages |

awk '{ print "" $0 " "; }' >
/dev/prolite &
This job sits in the background, getting lines from the end of the log as they come in, prefixes a to it and sends it to the sign. The process then goes to sleep until another log entry is made. The only reason to run as root is to get access to the messages file.

The sign can also act as a watchdog for our system by setting up a timer to go off several minutes later. Ideally, the sign will get updated before the timer goes off and the timer will again be set for some time in the future. In the event the sign is not updated, the timer trips and an alternate alert message is displayed.

!/bin/bash

stty 0:705:bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:12\
:f:17:16:0:0:73 < /dev/prolite
echo "Server Up" > /dev/prolite
echo "" > /dev/prolite
echo "00001U" > /dev/prolite
echo "Server Down" > \
/dev/prolite
date "+*%H%MD" -date "7 min" > \
/dev/prolite

To do this relies on some tricks. First, you cannot use a generic timer (*****) for running standard messages because it conflicts with our watchdog timer. Secondly, we cannot use timer 00000 because it confuses the sign. Thus, we have to use one minute after midnight on Sunday (00001) in order to display our messages. When no timers are defined, the first timer defined shows our page.

Deleting timer B keeps us using timer A, which shows normal text. The sign ignores requests to delete timers and pages that don't exist. Once page A is defined and displaying, we define page B in the background and set up a time, again using the clever date command to output it seven minutes from now. Since our cron job is set to run this script every five minutes, the timer should never go off unless something is wrong.

If Linux suffers a power failure, the cron daemon is killed, or the sign becomes disconnected, it will display a warning message. The tag indicates the message should instantly appear instead of scrolling, where indicates the text should appear from the center—this will get your attention quickly.





I have a led board which has 2 lines and 120x16 leds. The protocol described on this page is simular to the protocol used in my led board only it has some kind of security code in it.

For example:
This wil return a ACK, and the led board will show the message:
test62

This wil return a NACK, and the led board does not change:
test80

So there is a code right after the text... Another example:
Leon ter Linden1B = ACK
Leon ter Linden43 = NACK

Does anyone know how to calculate the code that comes after the text?

xor checksum

On October 16th, 2006 Are (not verified) says:

Here is the code to calculate the checksum.
The checksum is an xor of all the characters sent, without the first ID tag and without the end E tag.


static unsigned char
checksum(const char *str, unsigned char init)
{
unsigned char i = init;

while (*str != '\0') {
i ^= *str;
str++;
}

return (i);
}

int
main(int argc, char *argv[])
{
unsigned char csum = 0x0;

if (argc != 2)
exit(-1);
else
msg = argv[1];

csum = checksum(msg, csum);
printf("%02X\n",csum);
return (csum);

Thursday, July 10, 2008

Serial Communications in Win32

Serial Communications in Win32

 

Allen Denver
Microsoft Windows Developer Support

December 11, 1995

Allen seldom eats breakfast, but if he had to pick a favorite, Win32 serial communications would be the top choice.

Click to open or copy the files in the MTTTY sample application for this technical article.

 
Abstract

Serial communications in Microsoft?Win32?is significantly different from serial communications in 16-bit Microsoft Windows? Those familiar with 16-bit serial communications functions will have to relearn many parts of the system to program serial communications properly. This article will help to accomplish this. Those unfamiliar with serial communications will find this article a helpful foundation for development efforts.

This article assumes the reader is familiar with the fundamentals of multiple threading and synchronization in Win32. In addition, a basic familiarity of the Win32 heap functions is useful to fully comprehend the memory management methods used by the sample, MTTTY, included with this article. For more information regarding these functions, consult the Platform SDK documentation, the Microsoft Win32 SDK Knowledge Base, or the Microsoft Developer Network Library. Application programming interfaces (APIs) that control user interface features of windows and dialog boxes, though not discussed here, are useful to know in order to fully comprehend the sample provided with this article. Readers unfamiliar with general Windows programming practices should learn some of the fundamentals of general Windows programming before taking on serial communications. In other words, get your feet wet before diving in head first.
Introduction

The focus of this article is on application programming interfaces (APIs) and methods that are compatible with Microsoft?Windows NT?and Windows 95; therefore, APIs supported on both platforms are the only ones discussed. Windows 95 supports the Win32?Telephony API (TAPI) and Windows NT 3.x does not; therefore, this discussion will not include TAPI. TAPI does deserve mention, however, in that it very nicely implements modem interfacing and call controlling. A production application that works with modems and makes telephone calls should implement these features using the TAPI interface. This will allow seamless integration with the other TAPI-enabled applications that a user may have. Furthermore, this article does not discuss some of the configuration functions in Win32, such as GetCommProperties.

The article is broken into the following sections: Opening a port, reading and writing (nonoverlapped and overlapped), serial status (events and errors), and serial settings (DCB, flow control, and communications time-outs).

The sample included with this article, MTTTY: Multithreaded TTY, implements many of the features discussed here. It uses three threads in its implementation: a user interface thread that does memory management, a writer thread that controls all writing, and a reader/status thread that reads data and handles status changes on the port. The sample employs a few different data heaps for memory management. It also makes extensive use of synchronization methods to facilitate communication between threads.
Opening a Port

The CreateFile function opens a communications port. There are two ways to call CreateFile to open the communications port: overlapped and nonoverlapped. The following is the proper way to open a communications resource for overlapped operation:

HANDLE hComm;

hComm = CreateFile( gszPort,

GENERIC_READ | GENERIC_WRITE,

0,

0,

OPEN_EXISTING,

FILE_FLAG_OVERLAPPED,

0);

if (hComm == INVALID_HANDLE_VALUE)

// error opening port; abort

Removal of the FILE_FLAG_OVERLAPPED flag from the call to CreateFile specifies nonoverlapped operation. The next section discusses overlapped and nonoverlapped operations.

The Platform SDK documentation states that when opening a communications port, the call to CreateFile has the following requirements:

* fdwShareMode must be zero. Communications ports cannot be shared in the same manner that files are shared. Applications using TAPI can use the TAPI functions to facilitate sharing resources between applications. For Win32 applications not using TAPI, handle inheritance or duplication is necessary to share the communications port. Handle duplication is beyond the scope of this article; please refer to the Platform SDK documentation for more information.
* fdwCreate must specify the OPEN_EXISTING flag.
* hTemplateFile parameter must be NULL.

One thing to note about port names is that traditionally they have been COM1, COM2, COM3, or COM4. The Win32 API does not provide any mechanism for determining what ports exist on a system. Windows NT and Windows 95 keep track of installed ports differently from one another, so any one method would not be portable across all Win32 platforms. Some systems even have more ports than the traditional maximum of four. Hardware vendors and serial-device-driver writers are free to name the ports anything they like. For this reason, it is best that users have the ability to specify the port name they want to use. If a port does not exist, an error will occur (ERROR_FILE_NOT_FOUND) after attempting to open the port, and the user should be notified that the port isn’t available.
Reading and Writing

Reading from and writing to communications ports in Win32 is very similar to file input/output (I/O) in Win32. In fact, the functions that accomplish file I/O are the same functions used for serial I/O. I/O in Win32 can be done either of two ways: overlapped or nonoverlapped. The Platform SDK documentation uses the terms asynchronous and synchronous to connote these types of I/O operations. This article, however, uses the terms overlapped and nonoverlapped.

Nonoverlapped I/O is familiar to most developers because this is the traditional form of I/O, where an operation is requested and is assumed to be complete when the function returns. In the case of overlapped I/O, the system may return to the caller immediately even when an operation is not finished and will signal the caller when the operation completes. The program may use the time between the I/O request and its completion to perform some “background?work.

Reading and writing in Win32 is significantly different from reading and writing serial communications ports in 16-bit Windows. 16-bit Windows only has the ReadComm and WriteComm functions. Win32 reading and writing can involve many more functions and choices. These issues are discussed below.
Nonoverlapped I/O

Nonoverlapped I/O is very straightforward, though it has limitations. An operation takes place while the calling thread is blocked. Once the operation is complete, the function returns and the thread can continue its work. This type of I/O is useful for multithreaded applications because while one thread is blocked on an I/O operation, other threads can still perform work. It is the responsibility of the application to serialize access to the port correctly. If one thread is blocked waiting for its I/O operation to complete, all other threads that subsequently call a communications API will be blocked until the original operation completes. For instance, if one thread were waiting for a ReadFile function to return, any other thread that issued a WriteFile function would be blocked.

One of the many factors to consider when choosing between nonoverlapped and overlapped operations is portability. Overlapped operation is not a good choice because most operating systems do not support it. Most operating systems support some form of multithreading, however, so multithreaded nonoverlapped I/O may be the best choice for portability reasons.
Overlapped I/O

Overlapped I/O is not as straightforward as nonoverlapped I/O, but allows more flexibility and efficiency. A port open for overlapped operations allows multiple threads to do I/O operations at the same time and perform other work while the operations are pending. Furthermore, the behavior of overlapped operations allows a single thread to issue many different requests and do work in the background while the operations are pending.

In both single-threaded and multithreaded applications, some synchronization must take place between issuing requests and processing the results. One thread will have to be blocked until the result of an operation is available. The advantage is that overlapped I/O allows a thread to do some work between the time of the request and its completion. If no work can be done, then the only case for overlapped I/O is that it allows for better user responsiveness.

Overlapped I/O is the type of operation that the MTTTY sample uses. It creates a thread that is responsible for reading the port’s data and reading the port’s status. It also performs periodic background work. The program creates another thread exclusively for writing data out the port.

Note Applications sometimes abuse multithreading systems by creating too many threads. Although using multiple threads can resolve many difficult problems, creating excessive threads is not the most efficient use of them in an application. Threads are less a strain on the system than processes but still require system resources such as CPU time and memory. An application that creates excessive threads may adversely affect the performance of the entire system. A better use of threads is to create a different request queue for each type of job and to have a worker thread issue an I/O request for each entry in the request queue. This method is used by the MTTTY sample provided with this article.

An overlapped I/O operation has two parts: the creation of the operation and the detection of its completion. Creating the operation entails setting up an OVERLAPPED structure, creating a manual-reset event for synchronization, and calling the appropriate function (ReadFile or WriteFile). The I/O operation may or may not be completed immediately. It is an error for an application to assume that a request for an overlapped operation always yields an overlapped operation. If an operation is completed immediately, an application needs to be ready to continue processing normally. The second part of an overlapped operation is to detect its completion. Detecting completion of the operation involves waiting for the event handle, checking the overlapped result, and then handling the data. The reason that there is more work involved with an overlapped operation is that there are more points of failure. If a nonoverlapped operation fails, the function just returns an error-return result. If an overlapped operation fails, it can fail in the creation of the operation or while the operation is pending. You may also have a time-out of the operation or a time-out waiting for the signal that the operation is complete.
Reading

The ReadFile function issues a read operation. ReadFileEx also issues a read operation, but since it is not available on Windows 95, it is not discussed in this article. Here is a code snippet that details how to issue a read request. Notice that the function calls a function to process the data if the ReadFile returns TRUE. This is the same function called if the operation becomes overlapped. Note the fWaitingOnRead flag that is defined by the code; it indicates whether or not a read operation is overlapped. It is used to prevent the creation of a new read operation if one is outstanding.

DWORD dwRead;

BOOL fWaitingOnRead = FALSE;

OVERLAPPED osReader = {0};



// Create the overlapped event. Must be closed before exiting

// to avoid a handle leak.

osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);



if (osReader.hEvent == NULL)

// Error creating overlapped event; abort.



if (!fWaitingOnRead) {

// Issue read operation.

if (!ReadFile(hComm, lpBuf, READ_BUF_SIZE, &dwRead, &osReader)) {

if (GetLastError() != ERROR_IO_PENDING) // read not delayed?

// Error in communications; report it.

else

fWaitingOnRead = TRUE;

}

else {

// read completed immediately

HandleASuccessfulRead(lpBuf, dwRead);

}

}

The second part of the overlapped operation is the detection of its completion. The event handle in the OVERLAPPED structure is passed to the WaitForSingleObject function, which will wait until the object is signaled. Once the event is signaled, the operation is complete. This does not mean that it was completed successfully, just that it was completed. The GetOverlappedResult function reports the result of the operation. If an error occurred, GetOverlappedResult returns FALSE and GetLastError returns the error code. If the operation was completed successfully, GetOverlappedResult will return TRUE.

Note GetOverlappedResult can detect completion of the operation, as well as return the operation’s failure status. GetOverlappedResult returns FALSE and GetLastError returns ERROR_IO_INCOMPLETE when the operation is not completed. In addition, GetOverlappedResult can be made to block until the operation completes. This effectively turns the overlapped operation into a nonoverlapped operation and is accomplished by passing TRUE as the bWait parameter.

Here is a code snippet that shows one way to detect the completion of an overlapped read operation. Note that the code calls the same function to process the data that was called when the operation completed immediately. Also note the use of the fWaitingOnRead flag. Here it controls entry into the detection code, since it should be called only when an operation is outstanding.

#define READ_TIMEOUT 500 // milliseconds



DWORD dwRes;



if (fWaitingOnRead) {

dwRes = WaitForSingleObject(osReader.hEvent, READ_TIMEOUT);

switch(dwRes)

{

// Read completed.

case WAIT_OBJECT_0:

if (!GetOverlappedResult(hComm, &osReader, &dwRead, FALSE))

// Error in communications; report it.

else

// Read completed successfully.

HandleASuccessfulRead(lpBuf, dwRead);



// Reset flag so that another opertion can be issued.

fWaitingOnRead = FALSE;

break;



case WAIT_TIMEOUT:

// Operation isn't complete yet. fWaitingOnRead flag isn't

// changed since I'll loop back around, and I don't want

// to issue another read until the first one finishes.

//

// This is a good time to do some background work.

break;



default:

// Error in the WaitForSingleObject; abort.

// This indicates a problem with the OVERLAPPED structure's

// event handle.

break;

}

}

Writing

Transmitting data out the communications port is very similar to reading in that it uses a lot of the same APIs. The code snippet below demonstrates how to issue and wait for a write operation to be completed.

BOOL WriteABuffer(char * lpBuf, DWORD dwToWrite)

{

OVERLAPPED osWrite = {0};

DWORD dwWritten;

DWORD dwRes;

BOOL fRes;



// Create this write operation's OVERLAPPED structure's hEvent.

osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (osWrite.hEvent == NULL)

// error creating overlapped event handle

return FALSE;



// Issue write.

if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) {

if (GetLastError() != ERROR_IO_PENDING) {

// WriteFile failed, but isn't delayed. Report error and abort.

fRes = FALSE;

}

else

// Write is pending.

dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);

switch(dwRes)

{

// OVERLAPPED structure's event has been signaled.

case WAIT_OBJECT_0:

if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, FALSE))

fRes = FALSE;

else

// Write operation completed successfully.

fRes = TRUE;

break;



default:

// An error has occurred in WaitForSingleObject.

// This usually indicates a problem with the

// OVERLAPPED structure's event handle.

fRes = FALSE;

break;

}

}

}

else

// WriteFile completed immediately.

fRes = TRUE;



CloseHandle(osWrite.hEvent);

return fRes;

}

Notice that the code above uses the WaitForSingleObject function with a time-out value of INFINITE. This causes the WaitForSingleObject function to wait forever until the operation is completed; this may make the thread or program appear to be “hung?when, in fact, the write operation is simply taking a long time to complete or flow control has blocked the transmission. Status checking, discussed later, can detect this condition, but doesn’t cause the WaitForSingleObject to return. Three things can alleviate this condition:

* Place the code in a separate thread. This allows other threads to execute any functions they desire while our writer thread waits for the write to be completed. This is what the MTTTY sample does.
* Use COMMTIMEOUTS to cause the write to be completed after a time-out period has passed. This is discussed more fully in the “Communications Time-outs?section later in this article. This is also what the MTTTY sample allows.
* Change the WaitForSingleObject call to include a real time-out value. This causes more problems because if the program issues another operation while an older operation is still pending, new OVERLAPPED structures and overlapped events need to be allocated. This type of recordkeeping is difficult, particularly when compared to using a “job queue?design for the operations. The “job queue?method is used in the MTTTY sample.

Note: The time-out values in synchronization functions are not communications time-outs. Synchronization time-outs cause WaitForSingleObject or WaitForMultipleObjects to return WAIT_TIMEOUT. This is not the same as a read or write operation timing out. Communications time-outs are described later in this article.

Because the WaitForSingleObject function in the above code snippet uses an INFINITE time-out, it is equivalent to using GetOverlappedResult with TRUE for the fWait parameter. Here is equivalent code in a much simplified form:

BOOL WriteABuffer(char * lpBuf, DWORD dwToWrite)

{

OVERLAPPED osWrite = {0};

DWORD dwWritten;

BOOL fRes;



// Create this writes OVERLAPPED structure hEvent.

osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (osWrite.hEvent == NULL)

// Error creating overlapped event handle.

return FALSE;



// Issue write.

if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) {

if (GetLastError() != ERROR_IO_PENDING) {

// WriteFile failed, but it isn't delayed. Report error and abort.

fRes = FALSE;

}

else {

// Write is pending.

if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, TRUE))

fRes = FALSE;

else

// Write operation completed successfully.

fRes = TRUE;

}

}

else

// WriteFile completed immediately.

fRes = TRUE;



CloseHandle(osWrite.hEvent);

return fRes;

}

GetOverlappedResult is not always the best way to wait for an overlapped operation to be completed. For example, if an application needs to wait on another event handle, the first code snippet serves as a better model than the second. The call to WaitForSingleObject is easy to change to WaitForMultipleObjects to include the additional handles on which to wait. This is what the MTTTY sample application does.

A common mistake in overlapped I/O is to reuse an OVERLAPPED structure before the previous overlapped operation is completed. If a new overlapped operation is issued before a previous operation is completed, a new OVERLAPPED structure must be allocated for it. A new manual-reset event for the hEvent member of the OVERLAPPED structure must also be created. Once an overlapped operation is complete, the OVERLAPPED structure and its event are free for reuse.

The only member of the OVERLAPPED structure that needs modifying for serial communications is the hEvent member. The other members of the OVERLAPPED structure should be initialized to zero and left alone. Modifying the other members of the OVERLAPPED structure is not necessary for serial communications devices. The documentation for ReadFile and WriteFile state that the Offset and OffsetHigh members of the OVERLAPPED structure must be updated by the application, or else results are unpredictable. This guideline should be applied to OVERLAPPED structures used for other types of resources, such as files.
Serial Status

There are two methods to retrieve the status of a communications port. The first is to set an event mask that causes notification of the application when the desired events occur. The SetCommMask function sets this event mask, and the WaitCommEvent function waits for the desired events to occur. These functions are similar to the 16-bit functions SetCommEventMask and EnableCommNotification, except that the Win32 functions do not post WM_COMMNOTIFY messages. In fact, the WM_COMMNOTIFY message is not even part of the Win32 API. The second method for retrieving the status of the communications port is to periodically call a few different status functions. Polling is, of course, neither efficient nor recommended.
Communications Events

Communications events can occur at any time in the course of using a communications port. The two steps involved in receiving notification of communications events are as follows:

* SetCommMask sets the desired events that cause a notification.
* WaitCommEvent issues a status check. The status check can be an overlapped or nonoverlapped operation, just as the read and write operations can be.

Note: The word event in this context refers to communications events only. It does not refer to an event object used for synchronization.

Here is an example of the SetCommMask function:

DWORD dwStoredFlags;



dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |\

EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY ;

if (!SetCommMask(hComm, dwStoredFlags))

// error setting communications mask

A description of each type of event is in Table 1.

Table 1. Communications Event Flags

Event Flag


Description

EV_BREAK


A break was detected on input.

EV_CTS


The CTS (clear-to-send) signal changed state. To get the actual state of the CTS line, GetCommModemStatus should be called.

EV_DSR


The DSR (data-set-ready) signal changed state. To get the actual state of the DSR line, GetCommModemStatus should be called.

EV_ERR


A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY. To find the cause of the error, ClearCommError should be called.

EV_RING


A ring indicator was detected.

EV_RLSD


The RLSD (receive-line-signal-detect) signal changed state. To get the actual state of the RLSD line, GetCommModemStatus should be called. Note that this is commonly referred to as the CD (carrier detect) line.

EV_RXCHAR


A new character was received and placed in the input buffer. See the “Caveat?section below for a discussion of this flag.

EV_RXFLAG


The event character was received and placed in the input buffer. The event character is specified in the EvtChar member of the DCB structure discussed later. The “Caveat?section below also applies to this flag.

EV_TXEMPTY


The last character in the output buffer was sent to the serial port device. If a hardware buffer is used, this flag only indicates that all data has been sent to the hardware. There is no way to detect when the hardware buffer is empty without talking directly to the hardware with a device driver.



After specifying the event mask, the WaitCommEvent function detects the occurrence of the events. If the port is open for nonoverlapped operation, then the WaitCommEvent function does not contain an OVERLAPPED structure. The function blocks the calling thread until the occurrence of one of the events. If an event never occurs, the thread may block indefinitely.

Here is a code snippet that shows how to wait for an EV_RING event when the port is open for nonoverlapped operation:

DWORD dwCommEvent;



if (!SetCommMask(hComm, EV_RING))

// Error setting communications mask

return FALSE;



if (!WaitCommEvent(hComm, &dwCommEvent, NULL))

// An error occurred waiting for the event.

return FALSE;

else

// Event has occurred.

return TRUE;

Note The Microsoft Win32 SDK Knowledge Base documents a problem with Windows 95 and the EV_RING flag. The above code never returns in Windows 95 because the EV_RING event is not detected by the system; Windows NT properly reports the EV_RING event. Please see the Win32 SDK Knowledge Base for more information on this bug.

As noted, the code above can be blocked forever if an event never occurs. A better solution would be to open the port for overlapped operation and wait for a status event in the following manner:

#define STATUS_CHECK_TIMEOUT 500 // Milliseconds



DWORD dwRes;

DWORD dwCommEvent;

DWORD dwStoredFlags;

BOOL fWaitingOnStat = FALSE;

OVERLAPPED osStatus = {0};



dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |\

EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY ;

if (!SetCommMask(comHandle, dwStoredFlags))

// error setting communications mask; abort

return 0;



osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (osStatus.hEvent == NULL)

// error creating event; abort

return 0;



for ( ; ; ) {

// Issue a status event check if one hasn't been issued already.

if (!fWaitingOnStat) {

if (!WaitCommEvent(hComm, &dwCommEvent, &osStatus)) {

if (GetLastError() == ERROR_IO_PENDING)

bWaitingOnStatusHandle = TRUE;

else

// error in WaitCommEvent; abort

break;

}

else

// WaitCommEvent returned immediately.

// Deal with status event as appropriate.

ReportStatusEvent(dwCommEvent);

}



// Check on overlapped operation.

if (fWaitingOnStat) {

// Wait a little while for an event to occur.

dwRes = WaitForSingleObject(osStatus.hEvent, STATUS_CHECK_TIMEOUT);

switch(dwRes)

{

// Event occurred.

case WAIT_OBJECT_0:

if (!GetOverlappedResult(hComm, &osStatus, &dwOvRes, FALSE))

// An error occurred in the overlapped operation;

// call GetLastError to find out what it was

// and abort if it is fatal.

else

// Status event is stored in the event flag

// specified in the original WaitCommEvent call.

// Deal with the status event as appropriate.

ReportStatusEvent(dwCommEvent);



// Set fWaitingOnStat flag to indicate that a new

// WaitCommEvent is to be issued.

fWaitingOnStat = FALSE;

break;



case WAIT_TIMEOUT:

// Operation isn't complete yet. fWaitingOnStatusHandle flag

// isn't changed since I'll loop back around and I don't want

// to issue another WaitCommEvent until the first one finishes.

//

// This is a good time to do some background work.

DoBackgroundWork();

break;



default:

// Error in the WaitForSingleObject; abort

// This indicates a problem with the OVERLAPPED structure's

// event handle.

CloseHandle(osStatus.hEvent);

return 0;

}

}

}



CloseHandle(osStatus.hEvent);

The code above very closely resembles the code for overlapped reading. In fact, the MTTTY sample implements its reading and status checking in the same thread using WaitForMultipleObjects to wait for either the read event or the status event to become signaled.

There are two interesting side effects of SetCommMask and WaitCommEvent. First, if the communications port is open for nonoverlapped operation, WaitCommEvent will be blocked until an event occurs. If another thread calls SetCommMask to set a new event mask, that thread will be blocked on the call to SetCommMask. The reason is that the original call to WaitCommEvent in the first thread is still executing. The call to SetCommMask blocks the thread until the WaitCommEvent function returns in the first thread. This side effect is universal for ports open for nonoverlapped I/O. If a thread is blocked on any communications function and another thread calls a communications function, the second thread is blocked until the communications function returns in the first thread. The second interesting note about these functions is their use on a port open for overlapped operation. If SetCommMask sets a new event mask, any pending WaitCommEvent will complete successfully, and the event mask produced by the operation is NULL.
Caveat

Using the EV_RXCHAR flag will notify the thread that a byte arrived at the port. This event, used in combination with the ReadFile function, enables a program to read data only after it is in the receive buffer, as opposed to issuing a read that waits for the data to arrive. This is particularly useful when a port is open for nonoverlapped operation because the program does not need to poll for incoming data; the program is notified of the incoming data by the occurrence of the EV_RXCHAR event. Initial attempts to code this solution often produce the following pseudocode, including one oversight covered later in this section:

DWORD dwCommEvent;

DWORD dwRead;

char chRead;



if (!SetCommMask(hComm, EV_RXCHAR))

// Error setting communications event mask.



for ( ; ; ) {

if (WaitCommEvent(hComm, &dwCommEvent, NULL)) {

if (ReadFile(hComm, &chRead, 1, &dwRead, NULL))

// A byte has been read; process it.

else

// An error occurred in the ReadFile call.

break;

}

else

// Error in WaitCommEvent.

break;

}

The above code waits for an EV_RXCHAR event to occur. When this happens, the code calls ReadFile to read the one byte received. The loop starts again, and the code waits for another EV_RXCHAR event. This code works fine when one or two bytes arrive in quick succession. The byte reception causes the EV_RXCHAR event to occur. The code reads the byte. If no other byte arrives before the code calls WaitCommEvent again, then all is fine; the next byte to arrive will cause the WaitCommEvent function to indicate the occurrence of the EV_RXCHAR event. If another single byte arrives before the code has a chance to reach the WaitCommEvent function, then all is fine, too. The first byte is read as before; the arrival of the second byte causes the EV_RXCHAR flag to be set internally. When the code returns to the WaitCommEvent function, it indicates the occurrence of the EV_RXCHAR event and the second byte is read from the port in the ReadFile call.

The problem with the above code occurs when three or more bytes arrive in quick succession. The first byte causes the EV_RXCHAR event to occur. The second byte causes the EV_RXCHAR flag to be set internally. The next time the code calls WaitCommEvent, it indicates the EV_RXCHAR event. Now, a third byte arrives at the communications port. This third byte causes the system to attempt to set the EV_RXCHAR flag internally. Because this has already occurred when the second byte arrived, the arrival of the third byte goes unnoticed. The code eventually will read the first byte without a problem. After this, the code will call WaitCommEvent, and it indicates the occurrence of the EV_RXCHAR event (from the arrival of the second byte). The second byte is read, and the code returns to the WaitCommEvent function. The third byte waits in the system’s internal receive buffer. The code and the system are now out of sync. When a fourth byte finally arrives, the EV_RXCHAR event occurs, and the code reads a single byte. It reads the third byte. This will continue indefinitely.

The solution to this problem seems as easy as increasing the number of bytes requested in the read operation. Instead of requesting a single byte, the code could request two, ten, or some other number of bytes. The problem with this idea is that it still fails when two or more extra bytes above the size of the read request arrive at the port in quick succession. So, if two bytes are read, then four bytes arriving in quick succession would cause the problem. Ten bytes requested would still fail if twelve bytes arrived in quick succession.

The real solution to this problem is to read from the port until no bytes are remaining. The following pseudocode solves the problem by reading in a loop until zero characters are read. Another possible method would be to call ClearCommError to determine the number of bytes in the buffer and read them all in one read operation. This method requires more sophisticated buffer management, but it reduces the number of reads when a lot of data arrives at once.

DWORD dwCommEvent;

DWORD dwRead;

char chRead;



if (!SetCommMask(hComm, EV_RXCHAR))

// Error setting communications event mask



for ( ; ; ) {

if (WaitCommEvent(hComm, &dwCommEvent, NULL)) {

do {

if (ReadFile(hComm, &chRead, 1, &dwRead, NULL))

// A byte has been read; process it.

else

// An error occurred in the ReadFile call.

break;

} while (dwRead);

}

else

// Error in WaitCommEvent

break;

}

The above code does not work correctly without setting the proper time-outs. Communications time-outs, discussed later, affect the behavior of the ReadFile operation in order to cause it to return without waiting for bytes to arrive. Discussion of this topic occurs later in the “Communications Time-outs?section of this article.

The above caveat regarding EV_RXCHAR also applies to EV_RXFLAG. If flag characters arrive in quick succession, EV_RXFLAG events may not occur for all of them. Once again, the best solution is to read all bytes until none remain.

The above caveat also applies to other events not related to character reception. If other events occur in quick succession some of the notifications will be lost. For instance, if the CTS line voltage starts high, then goes low, high, and low again, an EV_CTS event occurs. There is no guarantee of how many EV_CTS events will actually be detected with WaitCommEvent if the changes in the CTS line happen quickly. For this reason, WaitCommEvent cannot be used to keep track of the state of the line. Line status is covered in the “Modem Status?section later in this article.
Error Handling and Communications Status

One of the communications event flags specified in the call to SetCommMask is possibly EV_ERR. The occurrence of the EV_ERR event indicates that an error condition exists in the communications port. Other errors can occur in the port that do not cause the EV_ERR event to occur. In either case, errors associated with the communications port cause all I/O operations to be suspended until removal of the error condition. ClearCommError is the function to call to detect errors and clear the error condition.

ClearCommError also provides communications status indicating why transmission has stopped; it also indicates the number of bytes waiting in the transmit and receive buffers. The reason why transmission may stop is because of errors or to flow control. The discussion of flow control occurs later in this article.

Here is some code that demonstrates how to call ClearCommError:

COMSTAT comStat;

DWORD dwErrors;

BOOL fOOP, fOVERRUN, fPTO, fRXOVER, fRXPARITY, fTXFULL;

BOOL fBREAK, fDNS, fFRAME, fIOE, fMODE;



// Get and clear current errors on the port.

if (!ClearCommError(hComm, &dwErrors, &comStat))

// Report error in ClearCommError.

return;



// Get error flags.

fDNS = dwErrors & CE_DNS;

fIOE = dwErrors & CE_IOE;

fOOP = dwErrors & CE_OOP;

fPTO = dwErrors & CE_PTO;

fMODE = dwErrors & CE_MODE;

fBREAK = dwErrors & CE_BREAK;

fFRAME = dwErrors & CE_FRAME;

fRXOVER = dwErrors & CE_RXOVER;

fTXFULL = dwErrors & CE_TXFULL;

fOVERRUN = dwErrors & CE_OVERRUN;

fRXPARITY = dwErrors & CE_RXPARITY;



// COMSTAT structure contains information regarding

// communications status.

if (comStat.fCtsHold)

// Tx waiting for CTS signal



if (comStat.fDsrHold)

// Tx waiting for DSR signal



if (comStat.fRlsdHold)

// Tx waiting for RLSD signal



if (comStat.fXoffHold)

// Tx waiting, XOFF char rec'd



if (comStat.fXoffSent)

// Tx waiting, XOFF char sent



if (comStat.fEof)

// EOF character received



if (comStat.fTxim)

// Character waiting for Tx; char queued with TransmitCommChar



if (comStat.cbInQue)

// comStat.cbInQue bytes have been received, but not read



if (comStat.cbOutQue)

// comStat.cbOutQue bytes are awaiting transfer

Modem Status (a.k.a. Line Status)

The call to SetCommMask may include the flags EV_CTS, EV_DSR, EV_RING, and EV_RLSD. These flags indicate changes in the voltage on the lines of the serial port. There is no indication of the actual status of these lines, just that a change occurred. The GetCommModemStatus function retrieves the actual state of these status lines by returning a bit mask indicating a 0 for low or no voltage and 1 for high voltage for each of the lines.

Please note that the term RLSD (Receive Line Signal Detect) is commonly referred to as the CD (Carrier Detect) line.

Note The EV_RING flag does not work in Windows 95 as mentioned earlier. The GetCommModemStatus function, however, does detect the state of the RING line.

Changes in these lines may also cause a flow-control event. The ClearCommError function reports whether transmission is suspended because of flow control. If necessary, a thread may call ClearCommError to detect whether the event is the cause of a flow-control action. Flow control is covered in the “Flow Control?section later in this article.

Here is some code that demonstrates how to call GetCommModemStatus:

DWORD dwModemStatus;

BOOL fCTS, fDSR, fRING, fRLSD;



if (!GetCommModemStatus(hComm, &dwModemStatus))

// Error in GetCommModemStatus;

return;



fCTS = MS_CTS_ON & dwModemStatus;

fDSR = MS_DSR_ON & dwModemStatus;

fRING = MS_RING_ON & dwModemStatus;

fRLSD = MS_RLSD_ON & dwModemStatus;



// Do something with the flags.

Extended Functions

The driver will automatically change the state of control lines as necessary. Generally speaking, changing status lines is under the control of a driver. If a device uses communications port control lines in a manner different from RS-232 standards, the standard serial communications driver will not work to control the device. If the standard serial communications driver will not control the device, a custom device driver is necessary.

There are occasions when standard control lines are under the control of the application instead of the serial communications driver. For instance, an application may wish to implement its own flow control. The application would be responsible for changing the status of the RTS and DTR lines. EscapeCommFunction directs a communications driver to perform such extended operations. EscapeCommFunction can make the driver perform some other function, such as setting or clearing a BREAK condition. For more information on this function, consult the Platform SDK documentation, the Microsoft Win32 SDK Knowledge Base, or the Microsoft Developer Network (MSDN) Library.
Serial Settings
DCB Settings

The most crucial aspect of programming serial communications applications is the settings in the Device-Control Block (DCB) structure. The most common errors in serial communications programming occur in initializing the DCB structure improperly. When the serial communications functions do not behave as expected, a close examination of the DCB structure usually reveals the problem.

There are three ways to initialize a DCB structure. The first method is to use the function GetCommState. This function returns the current DCB in use for the communications port. The following code shows how to use the GetCommState function:

DCB dcb = {0};



if (!GetCommState(hComm, &dcb))

// Error getting current DCB settings

else

// DCB is ready for use.

The second method to initialize a DCB is to use a function called BuildCommDCB. This function fills in the baud, parity type, number of stop bits, and number of data bits members of the DCB. The function also sets the flow-control members to default values. Consult the documentation of the BuildCommDCB function for details on which default values it uses for flow-control members. Other members of the DCB are unaffected by this function. It is the program's duty to make sure the other members of the DCB do not cause errors. The simplest thing to do in this regard is to initialize the DCB structure with zeros and then set the size member to the size, in bytes, of the structure. If the zero initialization of the DCB structure does not occur, then there may be nonzero values in the reserved members; this produces an error when trying to use the DCB later. The following function shows how to properly use this method:

DCB dcb;



FillMemory(&dcb, sizeof(dcb), 0);

dcb.DCBlength = sizeof(dcb);

if (!BuildCommDCB("9600,n,8,1", &dcb)) {

// Couldn't build the DCB. Usually a problem

// with the communications specification string.

return FALSE;

}

else

// DCB is ready for use.

The third method to initialize a DCB structure is to do it manually. The program allocates the DCB structure and sets each member with any value desired. This method does not deal well with changes to the DCB in future implementations of Win32 and is not recommended.

An application usually needs to set some of the DCB members differently than the defaults or may need to modify settings in the middle of execution. Once proper initialization of the DCB occurs, modification of individual members is possible. The changes to the DCB structure do not have any effect on the behavior of the port until execution of the SetCommState function. Here is a section of code that retrieves the current DCB, changes the baud, and then attempts to set the configuration:

DCB dcb;



FillMemory(&dcb, sizeof(dcb), 0);

if (!GetCommState(hComm, &dcb)) // get current DCB

// Error in GetCommState

return FALSE;



// Update DCB rate.

dcb.BaudRate = CBR_9600 ;



// Set new state.

if (!SetCommState(hComm, &dcb))

// Error in SetCommState. Possibly a problem with the communications

// port handle or a problem with the DCB structure itself.

Here is an explanation of each of the members of the DCB and how they affect other parts of the serial communications functions.

Note Most of this information is from the Platform SDK documentation. Because documentation is the official word in what the members actually are and what they mean, this table may not be completely accurate if changes occur in the operating system.

Table 2. The DCB Structure Members

Member


Description

DCBlength


Size, in bytes, of the structure. Should be set before calling SetCommState to update the settings.

BaudRate


Specifies the baud at which the communications device operates. This member can be an actual baud value, or a baud index.

fBinary


Specifies whether binary mode is enabled. The Win32 API does not support nonbinary mode transfers, so this member should be TRUE. Trying to use FALSE will not work.

fParity


Specifies whether parity checking is enabled. If this member is TRUE, parity checking is performed and parity errors are reported. This should not be confused with the Parity member, which controls the type of parity used in communications.

fOutxCtsFlow


Specifies whether the CTS (clear-to-send) signal is monitored for output flow control. If this member is TRUE and CTS is low, output is suspended until CTS is high again. The CTS signal is under control of the DCE (usually a modem), the DTE (usually the PC) simply monitors the status of this signal, the DTE does not change it.

fOutxDsrFlow


Specifies whether the DSR (data-set-ready) signal is monitored for output flow control. If this member is TRUE and DSR is low, output is suspended until DSR is high again. Once again, this signal is under the control of the DCE; the DTE only monitors this signal.

fDtrControl


Specifies the DTR (data-terminal-ready) input flow control. This member can be one of the following values:




Value


Meaning

DTR_CONTROL_DISABLE


Lowers the DTR line when the device is opened. The application can adjust the state of the line with EscapeCommFunction.

DTR_CONTROL_ENABLE


Raises the DTR line when the device is opened. The application can adjust the state of the line with EscapeCommFunction.

DTR_CONTROL_HANDSHAKE


Enables DTR flow-control handshaking. If this value is used, it is an error for the application to adjust the line with EscapeCommFunction.

fDsrSensitivity


Specifies whether the communications driver is sensitive to the state of the DSR signal. If this member is TRUE, the driver ignores any bytes received, unless the DSR modem input line is high.

fTXContinueOnXoff


Specifies whether transmission stops when the input buffer is full and the driver has transmitted the XOFF character. If this member is TRUE, transmission continues after the XOFF character has been sent. If this member is FALSE, transmission does not continue until the input buffer is within XonLim bytes of being empty and the driver has transmitted the XON character.

fOutX


Specifies whether XON/XOFF flow control is used during transmission. If this member is TRUE, transmission stops when the XOFF character is received and starts again when the XON character is received.

fInX


Specifies whether XON/XOFF flow control is used during reception. If this member is TRUE, the XOFF character is sent when the input buffer comes within XoffLim bytes of being full, and the XON character is sent when the input buffer comes within XonLim bytes of being empty.

fErrorChar


Specifies whether bytes received with parity errors are replaced with the character specified by the ErrorChar member. If this member is TRUE and the fParity member is TRUE, replacement occurs.

fNull


Specifies whether null bytes are discarded. If this member is TRUE, null bytes are discarded when received.

fRtsControl


Specifies the RTS (request-to-send) input flow control. If this value is zero, the default is RTS_CONTROL_HANDSHAKE. This member can be one of the following values:




Value


Meaning

RTS_CONTROL_DISABLE


Lowers the RTS line when the device is opened. The application can use EscapeCommFunction to change the state of the line.

RTS_CONTROL_ENABLE


Raises the RTS line when the device is opened. The application can use EscapeCommFunction to change the state of the line.

RTS_CONTROL_HANDSHAKE


Enables RTS flow-control handshaking. The driver raises the RTS line, enabling the DCE to send, when the input buffer has enough room to receive data. The driver lowers the RTS line, preventing the DCE to send, when the input buffer does not have enough room to receive data. If this value is used, it is an error for the application to adjust the line with EscapeCommFunction.

RTS_CONTROL_TOGGLE


Specifies that the RTS line will be high if bytes are available for transmission. After all buffered bytes have been sent, the RTS line will be low. If this value is set, it would be an error for an application to adjust the line with EscapeCommFunction. This value is ignored in Windows 95; it causes the driver to act as if RTS_CONTROL_ENABLE were specified.

fAbortOnError


Specifies whether read and write operations are terminated if an error occurs. If this member is TRUE, the driver terminates all read and write operations with an error status (ERROR_IO_ABORTED) if an error occurs. The driver will not accept any further communications operations until the application has acknowledged the error by calling the ClearCommError function.

fDummy2


Reserved; do not use.

wReserved


Not used; must be set to zero.

XonLim


Specifies the minimum number of bytes allowed in the input buffer before the XON character is sent.

XoffLim


Specifies the maximum number of bytes allowed in the input buffer before the XOFF character is sent. The maximum number of bytes allowed is calculated by subtracting this value from the size, in bytes, of the input buffer.

Parity


Specifies the parity scheme to be used. This member can be one of the following values:




Value


Meaning

EVENPARITY


Even

MARKPARITY


Mark

NOPARITY


No parity

ODDPARITY


Odd

StopBits


Specifies the number of stop bits to be used. This member can be one of the following values:




Value


Meaning

ONESTOPBIT


1 stop bit

ONE5STOPBITS


1.5 stop bits

TWOSTOPBITS


2 stop bits

XonChar


Specifies the value of the XON character for both transmission and reception.

XoffChar


Specifies the value of the XOFF character for both transmission and reception.

ErrorChar


Specifies the value of the character used to replace bytes received with a parity error.

EofChar


Specifies the value of the character used to signal the end of data.

EvtChar


Specifies the value of the character used to cause the EV_RXFLAG event. This setting does not actually cause anything to happen without the use of EV_RXFLAG in the SetCommMask function and the use of WaitCommEvent.

wReserved1


Reserved; do not use.



Flow Control

Flow control in serial communications provides a mechanism for suspending communications while one of the devices is busy or for some reason cannot do any communication. There are traditionally two types of flow control: hardware and software.

A common problem with serial communications is write operations that actually do not write the data to the device. Often, the problem lies in flow control being used when the program did not specify it. A close examination of the DCB structure reveals that one or more of the following members may be TRUE: fOutxCtsFlow, fOutxDsrFlow, or fOutX. Another mechanism to reveal that flow control is enabled is to call ClearCommError and examine the COMSTAT structure. It will reveal when transmission is suspended because of flow control.

Before discussing the types of flow control, a good understanding of some terms is in order. Serial communications takes place between two devices. Traditionally, there is a PC and a modem or printer. The PC is labeled the Data Terminal Equipment (DTE). The DTE is sometimes called the host. The modem, printer, or other peripheral equipment is identified as the Data Communications Equipment (DCE). The DCE is sometimes referred to as the device.
Hardware flow control

Hardware flow control uses voltage signals on control lines of the serial cable to control whether sending or receiving is enabled. The DTE and the DCE must agree on the types of flow control used for a communications session. Setting the DCB structure to enable flow control just configures the DTE. The DCE also needs configuration to make certain the DTE and DCE use the same type of flow control. There is no mechanism provided by Win32 to set the flow control of the DCE. DIP switches on the device, or commands sent to it typically establish its configuration. The following table describes the control lines, the direction of the flow control, and the line's effect on the DTE and DCE.

Table 3. Hardware Flow-control Lines

Line and Direction


Effect on DTE/DCE

CTS
(Clear To Send)
Output flow control


DCE sets the line high to indicate that it can receive data. DCE sets the line low to indicate that it cannot receive data.

If the fOutxCtsFlow member of the DCB is TRUE, then the DTE will not send data if this line is low. It will resume sending if the line is high.

If the fOutxCtsFlow member of the DCB is FALSE, then the state of the line does not affect transmission.

DSR
(Data Set Ready)
Output flow control


DCE sets the line high to indicate that it can receive data. DCE sets the line low to indicate that it cannot receive data.

If the fOutxDsrFlow member of the DCB is TRUE, then the DTE will not send data if this line is low. It will resume sending if the line is high.

If the fOutxDsrFlow member of the DCB is FALSE, then the state of the line does not affect transmission.

DSR
(Data Set Ready)
Input flow control


If the DSR line is low, then data that arrives at the port is ignored. If the DSR line is high, data that arrives at the port is received.

This behavior occurs if the fDsrSensitivity member of the DCB is set to TRUE. If it is FALSE, then the state of the line does not affect reception.

RTS
(Ready To Send)
Input flow control


The RTS line is controlled by the DTE.

If the fRtsControl member of the DCB is set to RTS_CONTROL_HANDSHAKE, the following flow control is used: If the input buffer has enough room to receive data (at least half the buffer is empty), the driver sets the RTS line high. If the input buffer has little room for incoming data (less than a quarter of the buffer is empty), the driver sets the RTS line low.

If the fRtsControl member of the DCB is set to RTS_CONTROL_TOGGLE, the driver sets the RTS line high when data is available for sending. The driver sets the line low when no data is available for sending. Windows 95 ignores this value and treats it the same as RTS_CONTROL_ENABLE.

If the fRtsControl member of the DCB is set to RTS_CONTROL_ENABLE or RTS_CONTROL_DISABLE, the application is free to change the state of the line as it needs. Note that in this case, the state of the line does not affect reception.

The DCE will suspend transmission when the line goes low. The DCE will resume transmission when the line goes high.

DTR
(Data Terminal Ready)
Input flow control


The DTR line is controlled by the DTE.

If the fDtrControl member of the DCB is set to DTR_CONTROL_HANDSHAKE, the following flow control is used: If the input buffer has enough room to receive data (at least half the buffer is empty), the driver sets the DTR line high. If the input buffer has little room for incoming data (less than a quarter of the buffer is empty), the driver sets the DTR line low.

If the fDtrControl member of the DCB is set to DTR_CONTROL_ENABLE or DTR_CONTROL_DISABLE, the application is free to change the state of the line as it needs. In this case, the state of the line does not affect reception.

The DCE will suspend transmission when the line goes low. The DCE will resume transmission when the line goes high.



The need for flow control is easy to recognize when the CE_RXOVER error occurs. This error indicates an overflow of the receive buffer and data loss. If data arrives at the port faster than it is read, CE_RXOVER can occur. Increasing the input buffer size may cause the error to occur less frequently, but it does not completely solve the problem. Input flow control is necessary to completely alleviate this problem. When the driver detects that the input buffer is nearly full, it will lower the input flow-control lines. This should cause the DCE to stop transmitting, which gives the DTE enough time to read the data from the input buffer. When the input buffer has more room available, the voltage on flow-control lines is set high, and the DCE resumes sending data.

A similar error is CE_OVERRUN. This error occurs when new data arrives before the communications hardware and serial communications driver completely receives old data. This can occur when the transmission speed is too high for the type of communications hardware or CPU. This can also occur when the operating system is not free to service the communications hardware. The only way to alleviate this problem is to apply some combination of decreasing the transmission speed, replacing the communications hardware, and increasing the CPU speed. Sometimes third-party hardware drivers that are not very efficient with CPU resources cause this error. Flow control cannot completely solve the problems that cause the CE_OVERRUN error, although it may help to reduce the frequency of the error.
Software flow control

Software flow control uses data in the communications stream to control the transmission and reception of data. Because software flow control uses two special characters, XOFF and XON, binary transfers cannot use software flow control; the XON or XOFF character may appear in the binary data and would interfere with data transfer. Software flow control befits text-based communications or data being transferred that does not contain the XON and XOFF characters.

In order to enable software flow control, the fOutX and fInX members of the DCB must be set to TRUE. The fOutX member controls output flow control. The fInX member controls input flow control.

One thing to note is that the DCB allows the program to dynamically assign the values the system recognizes as flow-control characters. The XoffChar member of the DCB dictates the XOFF character for both input and output flow control. The XonChar member of the DCB similarly dictates the XON character.

For input flow control, the XoffLim member of the DCB specifies the minimum amount of free space allowed in the input buffer before the XOFF character is sent. If the amount of free space in the input buffer drops below this amount, then the XOFF character is sent. For input flow control, the XonLim member of the DCB specifies the minimum number of bytes allowed in the input buffer before the XON character is sent. If the amount of data in the input buffer drops below this value, then the XON character is sent.

Table 4 lists the behavior of the DTE when using XOFF/XON flow control.

Table 4. Software flow-control behavior

Flow-control character


Behavior

XOFF received by DTE


DTE transmission is suspended until XON is received. DTE reception continues. The fOutX member of the DCB controls this behavior.

XON received by DTE


If DTE transmission is suspended because of a previous XOFF character being received, DTE transmission is resumed. The fOutX member of the DCB controls this behavior.

XOFF sent from DTE


XOFF is automatically sent by the DTE when the receive buffer approaches full. The actual limit is dictated by the XoffLim member of the DCB. The fInX member of the DCB controls this behavior. DTE transmission is controlled by the fTXContinueOnXoff member of the DCB as described below.

XON sent from the DTE


XON is automatically sent by the DTE when the receive buffer approaches empty. The actual limit is dictated by the XonLim member of the DCB. The fInX member of the DCB controls this behavior.



If software flow control is enabled for input control, then the fTXContinueOnXoff member of the DCB takes effect. The fTXContinueOnXoff member controls whether transmission is suspended after the XOFF character is automatically sent by the system. If fTXContinueOnXoff is TRUE, then transmission continues after the XOFF is sent when the receive buffer is full. If fTXContinueOnXoff is FALSE, then transmission is suspended until the system automatically sends the XON character. DCE devices using software flow control will suspend their sending after the XOFF character is received. Some equipment will resume sending when the XON character is sent by the DTE. On the other hand, some DCE devices will resume sending after any character arrives. The fTXContinueOnXoff member should be set to FALSE when communicating with a DCE device that resumes sending after any character arrives. If the DTE continued transmission after it automatically sent the XOFF, the resumption of transmission would cause the DCE to continue sending, defeating the XOFF.

There is no mechanism available in the Win32 API to cause the DTE to behave the same way as these devices. The DCB structure contains no members for specifying suspended transmission to resume when any character is received. The XON character is the only character that causes transmission to resume.

One other interesting note about software flow control is that reception of XON and XOFF characters causes pending read operations to complete with zero bytes read. The XON and XOFF characters cannot be read by the application, since they are not placed in the input buffer.

A lot of programs on the market, including the Terminal program that comes with Windows, give the user three choices for flow control: Hardware, Software, or None. The Windows operating system itself does not limit an application in this way. The settings of the DCB allow for Software and Hardware flow control simultaneously. In fact, it is possible to separately configure each member of the DCB that affects flow control, which allows for several different flow-control configurations. The limits placed on flow-control choices are there for ease-of-use reasons to reduce confusion for end users. The limits placed on flow-control choices may also be because devices used for communications may not support all types of flow control.
Communications Time-outs

Another major topic affecting the behavior of read and write operations is time-outs. Time-outs affect read and write operations in the following way. If an operation takes longer than the computed time-out period, the operation is completed. There is no error code that is returned by ReadFile, WriteFile, GetOverlappedResult, or WaitForSingleObject. All indicators used to monitor the operation indicate that it completed successfully. The only way to tell that the operation timed out is that the number of bytes actually transferred are fewer than the number of bytes requested. So, if ReadFile returns TRUE, but fewer bytes were read than were requested, the operation timed out. If an overlapped write operation times out, the overlapped event handle is signaled and WaitForSingleObject returns WAIT_OBJECT_O. GetOverlappedResult returns TRUE, but dwBytesTransferred contains the number of bytes that were transferred before the time-out. The following code demonstrates how to handle this in an overlapped write operation:

BOOL WriteABuffer(char * lpBuf, DWORD dwToWrite)

{

OVERLAPPED osWrite = {0};

DWORD dwWritten;

DWORD dwRes;

BOOL fRes;



// Create this write operation's OVERLAPPED structure hEvent.

osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (osWrite.hEvent == NULL)

// Error creating overlapped event handle.

return FALSE;



// Issue write

if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) {

if (GetLastError() != ERROR_IO_PENDING) {

// WriteFile failed, but it isn't delayed. Report error.

fRes = FALSE;

}

else

// Write is pending.

dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);

switch(dwRes)

{

// Overlapped event has been signaled.

case WAIT_OBJECT_0:

if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, FALSE))

fRes = FALSE;

else {

if (dwWritten != dwToWrite) {

// The write operation timed out. I now need to

// decide if I want to abort or retry. If I retry,

// I need to send only the bytes that weren't sent.

// If I want to abort, I would just set fRes to

// FALSE and return.

fRes = FALSE;

}

else

// Write operation completed successfully.

fRes = TRUE;

}

break;



default:

// An error has occurred in WaitForSingleObject. This usually

// indicates a problem with the overlapped event handle.

fRes = FALSE;

break;

}

}

}

else {

// WriteFile completed immediately.



if (dwWritten != dwToWrite) {

// The write operation timed out. I now need to

// decide if I want to abort or retry. If I retry,

// I need to send only the bytes that weren't sent.

// If I want to abort, then I would just set fRes to

// FALSE and return.

fRes = FALSE;

}

else

fRes = TRUE;

}



CloseHandle(osWrite.hEvent);

return fRes;

}

The SetCommTimeouts function specifies the communications time-outs for a port. To retrieve the current time-outs for a port, a program calls the GetCommTimeouts function. An applications should retrieve the communications time-outs before modifying them. This allows the application to set time-outs back to their original settings when it finishes with the port. Following is an example of setting new time-outs using SetCommTimeouts:

COMMTIMEOUTS timeouts;



timeouts.ReadIntervalTimeout = 20;

timeouts.ReadTotalTimeoutMultiplier = 10;

timeouts.ReadTotalTimeoutConstant = 100;

timeouts.WriteTotalTimeoutMultiplier = 10;

timeouts.WriteTotalTimeoutConstant = 100;



if (!SetCommTimeouts(hComm, &timeouts))

// Error setting time-outs.

Note Once again, communications time-outs are not the same as time-out values supplied in synchronization functions. WaitForSingleObject, for instance, uses a time-out value to wait for an object to become signaled; this is not the same as a communications time-out.

Setting the members of the COMMTIMEOUTS structure to all zeros causes no time-outs to occur. Nonoverlapped operations will block until all the requested bytes are transferred. The ReadFile function is blocked until all the requested characters arrive at the port. The WriteFile function is blocked until all requested characters are sent out. On the other hand, an overlapped operation will not finish until all the characters are transferred or the operation is aborted. The following conditions occur until the operation is completed:

* WaitForSingleObject always returns WAIT_TIMEOUT if a synchronization time-out is supplied. WaitForSingleObject will block forever if an INFINITE synchronization time-out is used.
* GetOverlappedResult always returns FALSE and GetLastError returns ERROR_IO_INCOMPLETE if called directly after the call to GetOverlappedResult.

Setting the members of the COMMTIMEOUTS structure in the following manner causes read operations to complete immediately without waiting for any new data to arrive:

COMMTIMEOUTS timeouts;



timeouts.ReadIntervalTimeout = MAXDWORD;

timeouts.ReadTotalTimeoutMultiplier = 0;

timeouts.ReadTotalTimeoutConstant = 0;

timeouts.WriteTotalTimeoutMultiplier = 0;

timeouts.WriteTotalTimeoutConstant = 0;



if (!SetCommTimeouts(hComm, &timeouts))

// Error setting time-outs.

These settings are necessary when used with an event-based read described in the “Caveat?section earlier. In order for ReadFile to return 0 bytes read, the ReadIntervalTimeout member of the COMMTIMEOUTS structure is set to MAXDWORD, and the ReadTimeoutMultiplier and ReadTimeoutConstant are both set to zero.

An application must always specifically set communications time-outs when it uses a communications port. The behavior of read and write operations is affected by communications time-outs. When a port is initially open, it uses default time-outs supplied by the driver or time-outs left over from a previous communications application. If an application assumes that time-outs are set a certain way, while the time-outs are actually different, then read and write operations may never complete or may complete too often.
Conclusion

This article serves as a discussion of some of the common pitfalls and questions that arise when developing a serial communications application. The Multithreaded TTY sample that comes with this article is designed using many of the techniques discussed here. Download it and try it out. Learning how it works will provide a thorough understanding of the Win32 serial communications functions.