xref: /original-bsd/usr.bin/tip/aculib/hayes.c (revision cfde0222)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)hayes.c	5.1 (Berkeley) 04/30/85";
9 #endif not lint
10 
11 /*
12  * Routines for calling up on a Hayes Modem
13  * (based on the old VenTel driver).
14  * The modem is expected to be strapped for "echo".
15  * Also, the switches enabling the DTR and CD lines
16  * must be set correctly.
17  * NOTICE:
18  * The easy way to hang up a modem is always simply to
19  * clear the DTR signal. However, if the +++ sequence
20  * (which switches the modem back to local mode) is sent
21  * before modem is hung up, removal of the DTR signal
22  * has no effect (except that it prevents the modem from
23  * recognizing commands).
24  * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984)
25  */
26 /*
27  * TODO:
28  * It is probably not a good idea to switch the modem
29  * state between 'verbose' and terse (status messages).
30  * This should be kicked out and we should use verbose
31  * mode only. This would make it consistent with normal
32  * interactive use thru the command 'tip dialer'.
33  */
34 #include "tip.h"
35 
36 #define	min(a,b)	((a < b) ? a : b)
37 
38 static	int sigALRM();
39 static	int timeout = 0;
40 static	jmp_buf timeoutbuf;
41 static 	char gobble();
42 #define DUMBUFLEN	40
43 static char dumbuf[DUMBUFLEN];
44 
45 #define	DIALING		1
46 #define IDLE		2
47 #define CONNECTED	3
48 #define	FAILED		4
49 static	int state = IDLE;
50 
51 hay_dialer(num, acu)
52 	register char *num;
53 	char *acu;
54 {
55 	register char *cp;
56 	register int connected = 0;
57 	char dummy;
58 #ifdef ACULOG
59 	char line[80];
60 #endif
61 	if (hay_sync() == 0)		/* make sure we can talk to the modem */
62 		return(0);
63 	if (boolean(value(VERBOSE)))
64 		printf("\ndialing...");
65 	fflush(stdout);
66 	ioctl(FD, TIOCHPCL, 0);
67 	ioctl(FD, TIOCFLUSH, 0);	/* get rid of garbage */
68 	write(FD, "ATv0\r", 5);	/* tell modem to use short status codes */
69 	gobble("\r");
70 	gobble("\r");
71 	write(FD, "ATTD", 4);	/* send dial command */
72 	write(FD, num, strlen(num));
73 	state = DIALING;
74 	write(FD, "\r", 1);
75 	connected = 0;
76 	if (gobble("\r")) {
77 		if ((dummy = gobble("01234")) != '1')
78 			error_rep(dummy);
79 		else
80 			connected = 1;
81 	}
82 	if (connected)
83 		state = CONNECTED;
84 	else {
85 		state = FAILED;
86 		return (connected);	/* lets get out of here.. */
87 	}
88 	ioctl(FD, TIOCFLUSH, 0);
89 #ifdef ACULOG
90 	if (timeout) {
91 		sprintf(line, "%d second dial timeout",
92 			number(value(DIALTIMEOUT)));
93 		logent(value(HOST), num, "hayes", line);
94 	}
95 #endif
96 	if (timeout)
97 		hay_disconnect();	/* insurance */
98 	return (connected);
99 }
100 
101 
102 hay_disconnect()
103 {
104 	char c;
105 	int len, rlen;
106 
107 	/* first hang up the modem*/
108 #ifdef DEBUG
109 	printf("\rdisconnecting modem....\n\r");
110 #endif
111 	ioctl(FD, TIOCCDTR, 0);
112 	sleep(1);
113 	ioctl(FD, TIOCSDTR, 0);
114 	goodbye();
115 }
116 
117 hay_abort()
118 {
119 
120 	char c;
121 
122 	write(FD, "\r", 1);	/* send anything to abort the call */
123 	hay_disconnect();
124 }
125 
126 static int
127 sigALRM()
128 {
129 
130 	printf("\07timeout waiting for reply\n\r");
131 	timeout = 1;
132 	longjmp(timeoutbuf, 1);
133 }
134 
135 static char
136 gobble(match)
137 	register char *match;
138 {
139 	char c;
140 	int (*f)();
141 	int i, status = 0;
142 
143 	signal(SIGALRM, sigALRM);
144 	timeout = 0;
145 #ifdef DEBUG
146 	printf("\ngobble: waiting for %s\n", match);
147 #endif
148 	do {
149 		if (setjmp(timeoutbuf)) {
150 			signal(SIGALRM, f);
151 			return (0);
152 		}
153 		alarm(number(value(DIALTIMEOUT)));
154 		read(FD, &c, 1);
155 		alarm(0);
156 		c &= 0177;
157 #ifdef DEBUG
158 		printf("%c 0x%x ", c, c);
159 #endif
160 		for (i = 0; i < strlen(match); i++)
161 			if (c == match[i])
162 				status = c;
163 	} while (status == 0);
164 	signal(SIGALRM, SIG_DFL);
165 #ifdef DEBUG
166 	printf("\n");
167 #endif
168 	return (status);
169 }
170 
171 error_rep(c)
172 	register char c;
173 {
174 	printf("\n\r");
175 	switch (c) {
176 
177 	case '0':
178 		printf("OK");
179 		break;
180 
181 	case '1':
182 		printf("CONNECT");
183 		break;
184 
185 	case '2':
186 		printf("RING");
187 		break;
188 
189 	case '3':
190 		printf("NO CARRIER");
191 		break;
192 
193 	case '4':
194 		printf("ERROR in input");
195 		break;
196 
197 	case '5':
198 		printf("CONNECT 1200");
199 		break;
200 
201 	default:
202 		printf("Unknown Modem error: %c (0x%x)", c, c);
203 	}
204 	printf("\n\r");
205 	return;
206 }
207 
208 /*
209  * set modem back to normal verbose status codes.
210  */
211 goodbye()
212 {
213 	int len, rlen;
214 	char c;
215 
216 	ioctl(FD, TIOCFLUSH, &len);	/* get rid of trash */
217 	if (hay_sync()) {
218 		sleep(1);
219 #ifndef DEBUG
220 		ioctl(FD, TIOCFLUSH, 0);
221 #endif
222 		write(FD, "ATH0\r", 5);		/* insurance */
223 #ifndef DEBUG
224 		c = gobble("03");
225 		if (c != '0' && c != '3') {
226 			printf("cannot hang up modem\n\r");
227 			printf("please use 'tip dialer' to make sure the line is hung up\n\r");
228 		}
229 #endif
230 		sleep(1);
231 		ioctl(FD, FIONREAD, &len);
232 #ifdef DEBUG
233 		printf("goodbye1: len=%d -- ", len);
234 		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
235 		dumbuf[rlen] = '\0';
236 		printf("read (%d): %s\r\n", rlen, dumbuf);
237 #endif
238 		write(FD, "ATv1\r", 5);
239 		sleep(1);
240 #ifdef DEBUG
241 		ioctl(FD, FIONREAD, &len);
242 		printf("goodbye2: len=%d -- ", len);
243 		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
244 		dumbuf[rlen] = '\0';
245 		printf("read (%d): %s\r\n", rlen, dumbuf);
246 #endif
247 	}
248 	ioctl(FD, TIOCFLUSH, 0);	/* clear the input buffer */
249 	ioctl(FD, TIOCCDTR, 0);		/* clear DTR (insurance) */
250 	close(FD);
251 }
252 
253 #define MAXRETRY	5
254 
255 hay_sync()
256 {
257 	int len, retry = 0;
258 
259 	while (retry++ <= MAXRETRY) {
260 		write(FD, "AT\r", 3);
261 		sleep(1);
262 		ioctl(FD, FIONREAD, &len);
263 		if (len) {
264 			len = read(FD, dumbuf, min(len, DUMBUFLEN));
265 			if (index(dumbuf, '0') ||
266 		   	(index(dumbuf, 'O') && index(dumbuf, 'K')))
267 				return(1);
268 #ifdef DEBUG
269 			dumbuf[len] = '\0';
270 			printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
271 #endif
272 		}
273 		ioctl(FD, TIOCCDTR, 0);
274 		ioctl(FD, TIOCSDTR, 0);
275 	}
276 	printf("Cannot synchronize with hayes...\n\r");
277 	return(0);
278 }
279