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