xref: /csrg-svn/usr.bin/tip/aculib/t3000.c (revision 62317)
159674Shibler /*
2*62317Sbostic  * Copyright (c) 1992, 1993
3*62317Sbostic  *	The Regents of the University of California.  All rights reserved.
459674Shibler  *
559674Shibler  * %sccs.include.redist.c%
659674Shibler  */
759674Shibler 
859674Shibler #ifndef lint
9*62317Sbostic static char sccsid[] = "@(#)t3000.c	8.1 (Berkeley) 06/06/93";
1059674Shibler #endif /* not lint */
1159674Shibler 
1259674Shibler /*
1359674Shibler  * Routines for calling up on a Telebit T3000 modem.
1459674Shibler  * Derived from Courier driver.
1559674Shibler  */
1659674Shibler #include "tip.h"
1759674Shibler #include <stdio.h>
1859674Shibler 
1959674Shibler #define	MAXRETRY	5
2059674Shibler 
2159674Shibler static	void sigALRM();
2259674Shibler static	int timeout = 0;
2359674Shibler static	int connected = 0;
2459674Shibler static	jmp_buf timeoutbuf, intbuf;
2559674Shibler static	int t3000_sync();
2659674Shibler 
t3000_dialer(num,acu)2759674Shibler t3000_dialer(num, acu)
2859674Shibler 	register char *num;
2959674Shibler 	char *acu;
3059674Shibler {
3159674Shibler 	register char *cp;
3259674Shibler #ifdef ACULOG
3359674Shibler 	char line[80];
3459674Shibler #endif
3559674Shibler 	static int t3000_connect(), t3000_swallow();
3659674Shibler 
3759674Shibler 	if (boolean(value(VERBOSE)))
3859674Shibler 		printf("Using \"%s\"\n", acu);
3959674Shibler 
4059674Shibler 	ioctl(FD, TIOCHPCL, 0);
4159674Shibler 	/*
4259674Shibler 	 * Get in synch.
4359674Shibler 	 */
4459674Shibler 	if (!t3000_sync()) {
4559674Shibler badsynch:
4659674Shibler 		printf("can't synchronize with t3000\n");
4759674Shibler #ifdef ACULOG
4859674Shibler 		logent(value(HOST), num, "t3000", "can't synch up");
4959674Shibler #endif
5059674Shibler 		return (0);
5159674Shibler 	}
5259674Shibler 	t3000_write(FD, "AT E0\r", 6);	/* turn off echoing */
5359674Shibler 	sleep(1);
5459674Shibler #ifdef DEBUG
5559674Shibler 	if (boolean(value(VERBOSE)))
5659674Shibler 		t3000_verbose_read();
5759674Shibler #endif
5859674Shibler 	ioctl(FD, TIOCFLUSH, 0);	/* flush any clutter */
5959674Shibler 	t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18);
6059674Shibler 	if (!t3000_swallow("\r\nOK\r\n"))
6159674Shibler 		goto badsynch;
6259674Shibler 	fflush(stdout);
6359674Shibler 	t3000_write(FD, "AT D", 4);
6459674Shibler 	for (cp = num; *cp; cp++)
6559674Shibler 		if (*cp == '=')
6659674Shibler 			*cp = ',';
6759674Shibler 	t3000_write(FD, num, strlen(num));
6859674Shibler 	t3000_write(FD, "\r", 1);
6959674Shibler 	connected = t3000_connect();
7059674Shibler #ifdef ACULOG
7159674Shibler 	if (timeout) {
7259674Shibler 		sprintf(line, "%d second dial timeout",
7359674Shibler 			number(value(DIALTIMEOUT)));
7459674Shibler 		logent(value(HOST), num, "t3000", line);
7559674Shibler 	}
7659674Shibler #endif
7759674Shibler 	if (timeout)
7859674Shibler 		t3000_disconnect();
7959674Shibler 	return (connected);
8059674Shibler }
8159674Shibler 
t3000_disconnect()8259674Shibler t3000_disconnect()
8359674Shibler {
8459674Shibler 	 /* first hang up the modem*/
8559674Shibler 	ioctl(FD, TIOCCDTR, 0);
8659674Shibler 	sleep(1);
8759674Shibler 	ioctl(FD, TIOCSDTR, 0);
8859674Shibler 	t3000_sync();				/* reset */
8959674Shibler 	close(FD);
9059674Shibler }
9159674Shibler 
t3000_abort()9259674Shibler t3000_abort()
9359674Shibler {
9459674Shibler 	t3000_write(FD, "\r", 1);	/* send anything to abort the call */
9559674Shibler 	t3000_disconnect();
9659674Shibler }
9759674Shibler 
9859674Shibler static void
sigALRM()9959674Shibler sigALRM()
10059674Shibler {
10159674Shibler 	printf("\07timeout waiting for reply\n");
10259674Shibler 	timeout = 1;
10359674Shibler 	longjmp(timeoutbuf, 1);
10459674Shibler }
10559674Shibler 
10659674Shibler static int
t3000_swallow(match)10759674Shibler t3000_swallow(match)
10859674Shibler   register char *match;
10959674Shibler   {
11059674Shibler 	sig_t f;
11159674Shibler 	char c;
11259674Shibler 
11359674Shibler 	f = signal(SIGALRM, sigALRM);
11459674Shibler 	timeout = 0;
11559674Shibler 	do {
11659674Shibler 		if (*match =='\0') {
11759674Shibler 			signal(SIGALRM, f);
11859674Shibler 			return (1);
11959674Shibler 		}
12059674Shibler 		if (setjmp(timeoutbuf)) {
12159674Shibler 			signal(SIGALRM, f);
12259674Shibler 			return (0);
12359674Shibler 		}
12459674Shibler 		alarm(number(value(DIALTIMEOUT)));
12559674Shibler 		read(FD, &c, 1);
12659674Shibler 		alarm(0);
12759674Shibler 		c &= 0177;
12859674Shibler #ifdef DEBUG
12959674Shibler 		if (boolean(value(VERBOSE)))
13059674Shibler 			putchar(c);
13159674Shibler #endif
13259674Shibler 	} while (c == *match++);
13359674Shibler #ifdef DEBUG
13459674Shibler 	if (boolean(value(VERBOSE)))
13559674Shibler 		fflush(stdout);
13659674Shibler #endif
13759674Shibler 	signal(SIGALRM, SIG_DFL);
13859674Shibler 	return (0);
13959674Shibler }
14059674Shibler 
14159674Shibler #ifndef B19200		/* XXX */
14259674Shibler #define	B19200	EXTA
14359674Shibler #define	B38400	EXTB
14459674Shibler #endif
14559674Shibler 
14659674Shibler struct tbaud_msg {
14759674Shibler 	char *msg;
14859674Shibler 	int baud;
14959674Shibler 	int baud2;
15059674Shibler } tbaud_msg[] = {
15159674Shibler 	"",		B300,	0,
15259674Shibler 	" 1200",	B1200,	0,
15359674Shibler 	" 2400",	B2400,	0,
15459674Shibler 	" 4800",	B4800,	0,
15559674Shibler 	" 9600",	B9600,	0,
15659674Shibler 	" 14400",	B19200,	B9600,
15759674Shibler 	" 19200",	B19200,	B9600,
15859674Shibler 	" 38400",	B38400,	B9600,
15959674Shibler 	" 57600",	B38400,	B9600,
16059674Shibler 	" 7512",	B9600,	0,
16159674Shibler 	" 1275",	B2400,	0,
16259674Shibler 	" 7200",	B9600,	0,
16359674Shibler 	" 12000",	B19200,	B9600,
16459674Shibler 	0,		0,	0,
16559674Shibler };
16659674Shibler 
16759674Shibler static int
t3000_connect()16859674Shibler t3000_connect()
16959674Shibler {
17059674Shibler 	char c;
17159674Shibler 	int nc, nl, n;
17259674Shibler 	struct sgttyb sb;
17359674Shibler 	char dialer_buf[64];
17459674Shibler 	struct tbaud_msg *bm;
17559674Shibler 	sig_t f;
17659674Shibler 
17759674Shibler 	if (t3000_swallow("\r\n") == 0)
17859674Shibler 		return (0);
17959674Shibler 	f = signal(SIGALRM, sigALRM);
18059674Shibler again:
18159674Shibler 	nc = 0; nl = sizeof(dialer_buf)-1;
18259674Shibler 	bzero(dialer_buf, sizeof(dialer_buf));
18359674Shibler 	timeout = 0;
18459674Shibler 	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
18559674Shibler 		if (setjmp(timeoutbuf))
18659674Shibler 			break;
18759674Shibler 		alarm(number(value(DIALTIMEOUT)));
18859674Shibler 		n = read(FD, &c, 1);
18959674Shibler 		alarm(0);
19059674Shibler 		if (n <= 0)
19159674Shibler 			break;
19259674Shibler 		c &= 0x7f;
19359674Shibler 		if (c == '\r') {
19459674Shibler 			if (t3000_swallow("\n") == 0)
19559674Shibler 				break;
19659674Shibler 			if (!dialer_buf[0])
19759674Shibler 				goto again;
19859674Shibler 			if (strcmp(dialer_buf, "RINGING") == 0 &&
19959674Shibler 			    boolean(value(VERBOSE))) {
20059674Shibler #ifdef DEBUG
20159674Shibler 				printf("%s\r\n", dialer_buf);
20259674Shibler #endif
20359674Shibler 				goto again;
20459674Shibler 			}
20559674Shibler 			if (strncmp(dialer_buf, "CONNECT",
20659674Shibler 				    sizeof("CONNECT")-1) != 0)
20759674Shibler 				break;
20859674Shibler 			for (bm = tbaud_msg ; bm->msg ; bm++)
20959674Shibler 				if (strcmp(bm->msg,
21059674Shibler 				    dialer_buf+sizeof("CONNECT")-1) == 0) {
21159674Shibler 					if (ioctl(FD, TIOCGETP, &sb) < 0) {
21259674Shibler 						perror("TIOCGETP");
21359674Shibler 						goto error;
21459674Shibler 					}
21559674Shibler 					sb.sg_ispeed = sb.sg_ospeed = bm->baud;
21659674Shibler 					if (ioctl(FD, TIOCSETP, &sb) < 0) {
21759674Shibler 						if (bm->baud2) {
21859674Shibler 							sb.sg_ispeed =
21959674Shibler 							sb.sg_ospeed =
22059674Shibler 								bm->baud2;
22159674Shibler 							if (ioctl(FD,
22259674Shibler 								  TIOCSETP,
22359674Shibler 								  &sb) >= 0)
22459674Shibler 								goto isok;
22559674Shibler 						}
22659674Shibler 						perror("TIOCSETP");
22759674Shibler 						goto error;
22859674Shibler 					}
22959674Shibler isok:
23059674Shibler 					signal(SIGALRM, f);
23159674Shibler #ifdef DEBUG
23259674Shibler 					if (boolean(value(VERBOSE)))
23359674Shibler 						printf("%s\r\n", dialer_buf);
23459674Shibler #endif
23559674Shibler 					return (1);
23659674Shibler 				}
23759674Shibler 			break;
23859674Shibler 		}
23959674Shibler 		dialer_buf[nc] = c;
24059674Shibler #ifdef notdef
24159674Shibler 		if (boolean(value(VERBOSE)))
24259674Shibler 			putchar(c);
24359674Shibler #endif
24459674Shibler 	}
24559674Shibler error1:
24659674Shibler 	printf("%s\r\n", dialer_buf);
24759674Shibler error:
24859674Shibler 	signal(SIGALRM, f);
24959674Shibler 	return (0);
25059674Shibler }
25159674Shibler 
25259674Shibler /*
25359674Shibler  * This convoluted piece of code attempts to get
25459674Shibler  * the t3000 in sync.
25559674Shibler  */
25659674Shibler static int
t3000_sync()25759674Shibler t3000_sync()
25859674Shibler {
25959674Shibler 	int already = 0;
26059674Shibler 	int len;
26159674Shibler 	char buf[40];
26259674Shibler 
26359674Shibler 	while (already++ < MAXRETRY) {
26459674Shibler 		ioctl(FD, TIOCFLUSH, 0);	/* flush any clutter */
26559674Shibler 		t3000_write(FD, "\rAT Z\r", 6);	/* reset modem */
26659674Shibler 		bzero(buf, sizeof(buf));
26759674Shibler 		sleep(2);
26859674Shibler 		ioctl(FD, FIONREAD, &len);
26959674Shibler #if 1
27059674Shibler if (len == 0) len = 1;
27159674Shibler #endif
27259674Shibler 		if (len) {
27359674Shibler 			len = read(FD, buf, sizeof(buf));
27459674Shibler #ifdef DEBUG
27559674Shibler 			buf[len] = '\0';
27659674Shibler 			printf("t3000_sync: (\"%s\")\n\r", buf);
27759674Shibler #endif
27859674Shibler 			if (index(buf, '0') ||
27959674Shibler 		   	   (index(buf, 'O') && index(buf, 'K')))
28059674Shibler 				return(1);
28159674Shibler 		}
28259674Shibler 		/*
28359674Shibler 		 * If not strapped for DTR control,
28459674Shibler 		 * try to get command mode.
28559674Shibler 		 */
28659674Shibler 		sleep(1);
28759674Shibler 		t3000_write(FD, "+++", 3);
28859674Shibler 		sleep(1);
28959674Shibler 		/*
29059674Shibler 		 * Toggle DTR to force anyone off that might have left
29159674Shibler 		 * the modem connected.
29259674Shibler 		 */
29359674Shibler 		ioctl(FD, TIOCCDTR, 0);
29459674Shibler 		sleep(1);
29559674Shibler 		ioctl(FD, TIOCSDTR, 0);
29659674Shibler 	}
29759674Shibler 	t3000_write(FD, "\rAT Z\r", 6);
29859674Shibler 	return (0);
29959674Shibler }
30059674Shibler 
t3000_write(fd,cp,n)30159674Shibler t3000_write(fd, cp, n)
30259674Shibler int fd;
30359674Shibler char *cp;
30459674Shibler int n;
30559674Shibler {
30659674Shibler 	struct sgttyb sb;
30759674Shibler 
30859674Shibler #ifdef notdef
30959674Shibler 	if (boolean(value(VERBOSE)))
31059674Shibler 		write(1, cp, n);
31159674Shibler #endif
31259674Shibler 	ioctl(fd, TIOCGETP, &sb);
31359674Shibler 	ioctl(fd, TIOCSETP, &sb);
31459674Shibler 	t3000_nap();
31559674Shibler 	for ( ; n-- ; cp++) {
31659674Shibler 		write(fd, cp, 1);
31759674Shibler 		ioctl(fd, TIOCGETP, &sb);
31859674Shibler 		ioctl(fd, TIOCSETP, &sb);
31959674Shibler 		t3000_nap();
32059674Shibler 	}
32159674Shibler }
32259674Shibler 
32359674Shibler #ifdef DEBUG
t3000_verbose_read()32459674Shibler t3000_verbose_read()
32559674Shibler {
32659674Shibler 	int n = 0;
32759674Shibler 	char buf[BUFSIZ];
32859674Shibler 
32959674Shibler 	if (ioctl(FD, FIONREAD, &n) < 0)
33059674Shibler 		return;
33159674Shibler 	if (n <= 0)
33259674Shibler 		return;
33359674Shibler 	if (read(FD, buf, n) != n)
33459674Shibler 		return;
33559674Shibler 	write(1, buf, n);
33659674Shibler }
33759674Shibler #endif
33859674Shibler 
33959674Shibler /*
34059674Shibler  * Code stolen from /usr/src/lib/libc/gen/sleep.c
34159674Shibler  */
34259674Shibler #define mask(s) (1<<((s)-1))
34359674Shibler #define setvec(vec, a) \
34459674Shibler         vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
34559674Shibler 
34659674Shibler static napms = 50; /* Give the t3000 50 milliseconds between characters */
34759674Shibler 
34859674Shibler static int ringring;
34959674Shibler 
t3000_nap()35059674Shibler t3000_nap()
35159674Shibler {
35259674Shibler 
35359674Shibler         static void t3000_napx();
35459674Shibler 	int omask;
35559674Shibler         struct itimerval itv, oitv;
35659674Shibler         register struct itimerval *itp = &itv;
35759674Shibler         struct sigvec vec, ovec;
35859674Shibler 
35959674Shibler         timerclear(&itp->it_interval);
36059674Shibler         timerclear(&itp->it_value);
36159674Shibler         if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
36259674Shibler                 return;
36359674Shibler         setvec(ovec, SIG_DFL);
36459674Shibler         omask = sigblock(mask(SIGALRM));
36559674Shibler         itp->it_value.tv_sec = napms/1000;
36659674Shibler 	itp->it_value.tv_usec = ((napms%1000)*1000);
36759674Shibler         setvec(vec, t3000_napx);
36859674Shibler         ringring = 0;
36959674Shibler         (void) sigvec(SIGALRM, &vec, &ovec);
37059674Shibler         (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
37159674Shibler         while (!ringring)
37259674Shibler                 sigpause(omask &~ mask(SIGALRM));
37359674Shibler         (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
37459674Shibler         (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
37559674Shibler 	(void) sigsetmask(omask);
37659674Shibler }
37759674Shibler 
37859674Shibler static void
t3000_napx()37959674Shibler t3000_napx()
38059674Shibler {
38159674Shibler         ringring = 1;
38259674Shibler }
383