v13i058: Baud rate detection for 4.3BSD

Rich Salz rsalz at bbn.com
Tue Feb 23 10:09:18 AEST 1988


Submitted-by: Gregg Townsend <gmt at MEGARON.ARIZONA.EDU>
Posting-number: Volume 13, Issue 58
Archive-name: 4.3autobaud

This program does automatic baud rate detection under 4.3 BSD Unix.  That is,
you send it a carriage return and it figures out your baud rate.  It depends
on the hardware response to a speed mismatch, but the technique dates back at
least to TOPS-10 and probably much earlier.  I've seen it work on several
systems; we're running this code on Vaxes.

Note that only certain speeds work; generalizing it to handle all possible
speeds is decidedly nontrivial.  The set here (300, 1200, 2400, 9600) is
sufficient for us.

Autobaud was originally written to handle terminals coming in through a port
switch that intercepts BREAKs.  Now we run it on nearly all incoming lines as
a replacement for getty(8).

(We tried, not too hard, to get getty's baud detection code to work; the
 tangled code, comments referencing Micom, and omission of the feature from
 the published documentation were all discouraging.)

     Gregg Townsend / Computer Science Dept / Univ of Arizona / Tucson, AZ 85721
     +1 602 621 4325      gmt at Arizona.EDU       {allegra|noao|ihnp4}!arizona!gmt

---------------------------- cut here -----------------------------------
# To unbundle, sh this file
echo unbundling Makefile 1>&2
cat >Makefile <<'AlBeRtEiNsTeIn'
autobaud:	autobaud.c	; cc -O -s -o autobaud autobaud.c
AlBeRtEiNsTeIn
echo unbundling autobaud.8 1>&2
cat >autobaud.8 <<'AlBeRtEiNsTeIn'
.TH AUTOBAUD 8 "15 April 1987" "University of Arizona"
.SH NAME
autobaud \- terminal speed detection
.SH SYNOPSIS
\fB/etc/local/autobaud [ \-l ] [ \fIttyname\fB ]
.SH DESCRIPTION
.I Autobaud
is a simpler replacement for
.IR getty (8),
the crucial difference being that
.I autobaud
performs line speed detection as distinguished from cycling.
The speeds recognized are 300, 1200, 2400, and 9600 baud.
Autobaud expects the user to type a carriage return and will loop
until one is received.
.PP
If
.I ttyname
is given,
.I autobaud
samples
.RI /dev/ ttyname
instead of standard input.
The
.B \-l
option is normally set in /etc/ttys
and causes
.I autobaud
to exec
.IR login (1)
after determining the speed.
.PP
Autobaud sets these terminal parameters:  any parity, no tabs, echo,
erase ^H, kill ^U.
.SH FILES
.PP
/etc/ttys
.br
/dev/\fIttyname\fP
.SH "SEE ALSO"
init(8), getty(8), login(1)
.SH BUGS
.PP
BREAK and NUL have no effect, but typing any other character is
likely to cause
.I autobaud
to set the speed incorrectly.
.PP
Theory says that 600 baud should also work, but it doesn't.
AlBeRtEiNsTeIn
echo unbundling autobaud.c 1>&2
cat >autobaud.c <<'AlBeRtEiNsTeIn'
/*  autobaud.c - determine tty speed of standard input  (for 4.3 BSD Unix)
 *
 *  Autobaud reads standard input at 2400 baud.  Assuming a carriage return
 *  is typed, the bit pattern received is used to select and set the "true"
 *  speed.  This works for speeds of 300, 1200, 2400, and 9600 baud.  In theory
 *  600 should also work, but empirically a 00 character is read and it doesn't.
 *  Any other speed, or any character other than a carriage return, is likely
 *  to give a wrong result.
 *
 *  Autobaud is primarily intended as a replacement for getty(8), and as such
 *  it also sets a few terminal parameters such as the kill character to
 *  default values.  However, it can also be run from a shell for testing.
 *
 *  usage:  autobaud [-l] [ttyname]
 *
 *  -l		sets "login" mode and execs login after the speed is set
 *  ttyname	specifies a device to autobaud (/dev/ttyname) instead of stdin
 *
 *  Gregg Townsend
 *  University of Arizona
 *  April, 1987
 */

#define PGMNAME "autobaud"		/* program name (for diagnostics) */
#define LOGIN "/bin/login"		/* location of login program */
#define STRSIZ 100			/* string size for host and tty names */

#include <sgtty.h>
#include <signal.h>
#include <stdio.h>
#include <sys/file.h>
#include <sys/time.h>



char *sp[] = {   "0",   "50",   "75",  "110",  "134",  "150",  "200",  "300",
	       "600", "1200", "1800", "2400", "4800", "9600", "EXTA", "EXTB"};

int login = 0;				/* set nonzero if to exec login */
char ttyname[STRSIZ] = "/dev/";		/* buffer for explicit tty name */
char hostname[STRSIZ];			/* buffer for hostname */



/*  main program  */

main(argc,argv)
int argc;
char **argv;
{
    struct sgttyb ttyb;
    unsigned char c;
    char s;
    int zero = 0;

    argv++;					/* skip program name */
    if (*argv && !strcmp(*argv,"-l"))
	login++, argv++;			/* if "-l", set login flag */
    if (*argv)  {				
	strcpy(ttyname+5,*argv++);		/* if tty given, build name */
	close(0);				/* close previous stdin */
	close(1);				/* close previous stdout */
	close(2);				/* close previous stderr */
	if (login)  {
	    nap(2000);				/* hold DTR down for 2 sec */
	    chown(ttyname,0,0);			/* make root the owner */
	    chmod(ttyname,0622);		/* and set the protections */
	}
	if (open(ttyname,O_RDWR) != 0)		/* open once for stdin */
	    abort(ttyname);
	dup(0);					/* dup for stdout */
	dup(0);					/* dup for stderr */
    }

    ttyb.sg_ispeed = ttyb.sg_ospeed = B2400;	/* sample line at 2400 baud */
    ttyb.sg_erase = ttyb.sg_kill = -1;		/* no editing characters */
    ttyb.sg_flags = EVENP + ODDP + RAW;		/* raw mode, no echo */
    if (ioctl(0,TIOCSETN,&ttyb) <0)		/* set tty parameters */
	abort("ioctl");
    s = 0;
    while (!s)  {
	nap(100);				/* wait .1 sec for line quiet */
	ioctl(0,TIOCFLUSH,&zero);		/* flush input & output */
	if (read(0,&c,1) != 1)			/* read a character */
	    exit(1);
	/* select baud rate based on pattern received */
	if (c >= 0xF0)
	    s = B9600;
	else switch (c)  {
	    case 0x80: s = B300;  break;
	    case 0x78: s = B600;  break;
	    case 0xE6: s = B1200; break;
	    case 0x0D: s = B2400; break;
	    case 0x8D: s = B2400; break;
	    default:   s = 0;     break;
	}
    }
    nap(100);					/* let slow input finish */
    ttyb.sg_ispeed = ttyb.sg_ospeed = s;	/* set speeds */
    ttyb.sg_erase =  '\b';			/* \b for char correction */
    ttyb.sg_kill = 'U' & 037;			/* ^U for line kill */
    ttyb.sg_flags = XTABS+EVENP+ODDP+CRMOD+ECHO;/* any parity, -TABS, CR, ECHO*/
    ioctl(0,TIOCSETN,&ttyb);			/* set parameters */
    ioctl(0,TIOCFLUSH,&zero);			/* flush I/O */
    ioctl(0,TIOCHPCL,0);			/* set hangup on last close */
    if (login)  {
	gethostname(hostname,STRSIZ);
	printf("\n%s %s\n",hostname,ttyname+5);	/* display banner */
	fflush(stdout);				/* flush it */
	execl(LOGIN,"login",NULL);		/* exec login */
	abort("can't exec login");
    } else {
	printf("%s baud\n",sp[s]);		/* from shell,just print speed*/
	exit(0);
    }
}



/*  abort(s) - abort, for reason given in string s, calling perror first
 *
 *  (It's not totally clear what we should do, but we'll do it here for
 *   uniformity.)
 */

abort(s)
char *s;
{
    fprintf(stderr,"%s: ",PGMNAME);	/* display program name */
    perror(s);				/* display detail, and error message */
    if (login)
	nap(5000);			/* prevent fast looping in login mode */
    exit(1);
}




/*  nap(n) - delay for n milliseconds.
 *  Assumes nobody else is using SIGALRM or ITIMER_REAL.
 */

static int nap_flag = -1;
static nap_done() { nap_flag = 0; }

nap(n)
int n;
{
    struct itimerval t;

    if (nap_flag < 0)
	signal(SIGALRM,nap_done);
    if (!(nap_flag = n))
	return;
    t.it_value.tv_sec = n / 1000;
    t.it_value.tv_usec = (n % 1000) * 1000;
    t.it_interval.tv_sec = t.it_interval.tv_usec = 0;
    setitimer(ITIMER_REAL,&t,(struct itimerval *)0);
    while (nap_flag)
	pause();
}
AlBeRtEiNsTeIn
exit 0

-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list