xref: /plan9/sys/src/cmd/con/hayes.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 
4 void setspeed(int, int);
5 int getspeed(char*, int);
6 void godial(int, int, char*);
7 int readmsg(int, int);
8 void punt(char*, ...);
9 
10 int pulsed;
11 int verbose;
12 char msgbuf[128];		/* last message read */
13 
14 enum
15 {
16 	Ok,
17 	Success,
18 	Failure,
19 	Noise,
20 };
21 
22 typedef struct Msg	Msg;
23 struct Msg
24 {
25 	char	*text;
26 	int	type;
27 };
28 
29 
30 Msg msgs[] =
31 {
32 	{ "OK",			Ok, },
33 	{ "NO CARRIER", 	Failure, },
34 	{ "ERROR",		Failure, },
35 	{ "NO DIALTONE",	Failure, },
36 	{ "BUSY",		Failure, },
37 	{ "NO ANSWER",		Failure, },
38 	{ "CONNECT",		Success, },
39 	{ 0,			0 },
40 };
41 
42 void
usage(void)43 usage(void)
44 {
45 	punt("usage: hayes [-p] telno [device]");
46 }
47 
48 void
main(int argc,char ** argv)49 main(int argc, char **argv)
50 {
51 	int data = -1;
52 	int ctl = -1;
53 	char *cname;
54 
55 	ARGBEGIN{
56 	case 'p':
57 		pulsed = 1;
58 		break;
59 	case 'v':
60 		verbose = 1;
61 		break;
62 	default:
63 		usage();
64 	}ARGEND
65 
66 	switch(argc){
67 	case 1:
68 		data = 1;
69 		break;
70 	case 2:
71 		data = open(argv[1], ORDWR);
72 		if(data < 0){
73 			fprint(2, "hayes: %r opening %s\n", argv[1]);
74 			exits("hayes");
75 		}
76 		cname = malloc(strlen(argv[1])+4);
77 		sprint(cname, "%sctl", argv[1]);
78 		ctl = open(cname, ORDWR);
79 		free(cname);
80 		break;
81 	default:
82 		usage();
83 	}
84 	godial(data, ctl, argv[0]);
85 	exits(0);
86 }
87 
88 int
send(int fd,char * x)89 send(int fd, char *x)
90 {
91 	return write(fd, x, strlen(x));
92 }
93 
94 void
godial(int data,int ctl,char * number)95 godial(int data, int ctl, char *number)
96 {
97 	char *dialstr;
98 	int m;
99 	int baud;
100 
101 	/* get the modem's attention */
102 	if(send(data, "\r+++\r") < 0)
103 		punt("failed write");
104 	readmsg(data, 2);
105 	sleep(1000);
106 
107 	/* initialize */
108 	if(send(data, "ATZ\r") < 0)
109 		punt("failed write");
110 	m = readmsg(data, 2);
111 	if(m < 0)
112 		punt("can't get modem's attention");
113 
114 	/*
115 	 *	Q0 = report result codes
116 	 * 	V1 = full word result codes
117 	 *	W1 = negotiation progress codes enabled
118 	 *	E1 = echo commands
119 	 *	M1 = speaker on until on-line
120 	 */
121 	if(send(data, "ATQ0V1E1M1\r") < 0)
122 		punt("failed write");
123 	m = readmsg(data, 2);
124 	if(m != Ok)
125 		punt("can't get modem's attention");
126 	if(send(data, "ATW1\r") < 0)
127 		punt("failed write");
128 	readmsg(data, 2);
129 	sleep(1000);
130 
131 	/* godial */
132 	dialstr = malloc(6+strlen(number));
133 	sprint(dialstr, "ATD%c%s\r", pulsed ? 'P' : 'T', number);
134 	if(send(data, dialstr) < 0) {
135 		free(dialstr);
136 		punt("failed write");
137 	}
138 	free(dialstr);
139 	m = readmsg(data, 60);
140 	if(m != Success)
141 		punt("dial failed: %s", msgbuf);
142 	baud = getspeed(msgbuf, 9600);
143 	setspeed(ctl, baud);
144 	fprint(2, "hayes: connected at %d baud\n", baud);
145 }
146 
147 /*
148  *  read until we see a message or we time out
149  */
150 int
readmsg(int f,int secs)151 readmsg(int f, int secs)
152 {
153 	ulong start;
154 	char *p;
155 	int len;
156 	Dir *d;
157 	Msg *pp;
158 
159 	p = msgbuf;
160 	len = sizeof(msgbuf) - 1;
161 	for(start = time(0); time(0) <= start+secs;){
162 		if((d = dirfstat(f)) == nil)
163 			punt("failed read");
164 		if(d->length == 0){
165 			free(d);
166 			sleep(100);
167 			continue;
168 		}
169 		free(d);
170 		if(read(f, p, 1) <= 0)
171 			punt("failed read");
172 		if(*p == '\n' || *p == '\r' || len == 0){
173 			*p = 0;
174 			if(verbose && p != msgbuf)
175 				fprint(2, "%s\n", msgbuf);
176 			for(pp = msgs; pp->text; pp++)
177 				if(strncmp(pp->text, msgbuf, strlen(pp->text))==0)
178 					return pp->type;
179 			start = time(0);
180 			p = msgbuf;
181 			len = sizeof(msgbuf) - 1;
182 			continue;
183 		}
184 		len--;
185 		p++;
186 	}
187 	strcpy(msgbuf, "No response from modem");
188 	return Noise;
189 }
190 
191 /*
192  *  get baud rate from a connect message
193  */
194 int
getspeed(char * msg,int speed)195 getspeed(char *msg, int speed)
196 {
197 	char *p;
198 	int s;
199 
200 	p = msg + sizeof("CONNECT") - 1;
201 	while(*p == ' ' || *p == '\t')
202 		p++;
203 	s = atoi(p);
204 	if(s <= 0)
205 		return speed;
206 	else
207 		return s;
208 }
209 
210 /*
211  *  set speed and RTS/CTS modem flow control
212  */
213 void
setspeed(int ctl,int baud)214 setspeed(int ctl, int baud)
215 {
216 	char buf[32];
217 
218 	if(ctl < 0)
219 		return;
220 	sprint(buf, "b%d", baud);
221 	write(ctl, buf, strlen(buf));
222 	write(ctl, "m1", 2);
223 }
224 
225 
226 void
punt(char * fmt,...)227 punt(char *fmt, ...)
228 {
229 	char buf[256];
230 	va_list arg;
231 	int n;
232 
233 	strcpy(buf, "hayes: ");
234 	va_start(arg, fmt);
235 	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
236 	va_end(arg);
237 	buf[n] = '\n';
238 	write(2, buf, n+1);
239 	exits("hayes");
240 }
241