1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "modem.h"
6
7 typedef struct {
8 char *terse;
9 char *verbose;
10 int result;
11 int (*f)(Modem*);
12 } ResultCode;
13
14 static ResultCode results[] = {
15 { "0", "OK", Rok, 0, },
16 { "1", "CONNECT", Rconnect, 0, },
17 { "2", "RING", Rring, 0, },
18 { "3", "NO CARRIER", Rfailure, 0, },
19 { "4", "ERROR", Rrerror, 0, },
20 { "5", "CONNECT 1200", Rconnect, 0, },
21 { "6", "NO DIALTONE", Rfailure, 0, },
22 { "7", "BUSY", Rfailure, 0, },
23 { "8", "NO ANSWER", Rfailure, 0, },
24 { "9", "CONNECT 2400", Rconnect, 0, }, /* MT1432BA */
25 { "10", "CONNECT 2400", Rconnect, 0, }, /* Hayes */
26 { "11", "CONNECT 4800", Rconnect, 0, },
27 { "12", "CONNECT 9600", Rconnect, 0, },
28 { "13", "CONNECT 14400",Rconnect, 0, },
29 { "23", "CONNECT 1275", Rconnect, 0, }, /* MT1432BA */
30
31 { "-1", "+FCON", Rcontinue, fcon, },
32 { "-1", "+FTSI", Rcontinue, ftsi, },
33 { "-1", "+FDCS", Rcontinue, fdcs, },
34 { "-1", "+FCFR", Rcontinue, fcfr, },
35 { "-1", "+FPTS", Rcontinue, fpts, },
36 { "-1", "+FET", Rcontinue, fet, },
37 { "-1", "+FHNG", Rcontinue, fhng, },
38
39 { 0 },
40 };
41
42 void
initmodem(Modem * m,int fd,int cfd,char * type,char * id)43 initmodem(Modem *m, int fd, int cfd, char *type, char *id)
44 {
45 m->fd = fd;
46 m->cfd = cfd;
47 if(id == 0)
48 id = "Plan 9";
49 m->id = id;
50 m->t = type;
51 }
52
53 int
rawmchar(Modem * m,char * p)54 rawmchar(Modem *m, char *p)
55 {
56 Dir *d;
57 int n;
58
59 if(m->icount == 0)
60 m->iptr = m->ibuf;
61
62 if(m->icount){
63 *p = *m->iptr++;
64 m->icount--;
65 return Eok;
66 }
67
68 m->iptr = m->ibuf;
69
70 if((d = dirfstat(m->fd)) == nil){
71 verbose("rawmchar: dirfstat: %r");
72 return seterror(m, Esys);
73 }
74 n = d->length;
75 free(d);
76 if(n == 0)
77 return Enoresponse;
78
79 if(n > sizeof(m->ibuf)-1)
80 n = sizeof(m->ibuf)-1;
81 if((m->icount = read(m->fd, m->ibuf, n)) <= 0){
82 verbose("rawmchar: read: %r");
83 m->icount = 0;
84 return seterror(m, Esys);
85 }
86 *p = *m->iptr++;
87 m->icount--;
88
89 return Eok;
90 }
91
92 int
getmchar(Modem * m,char * buf,long timeout)93 getmchar(Modem *m, char *buf, long timeout)
94 {
95 int r, t;
96
97 timeout += time(0);
98 while((t = time(0)) <= timeout){
99 switch(r = rawmchar(m, buf)){
100
101 case Eok:
102 return Eok;
103
104 case Enoresponse:
105 sleep(100);
106 continue;
107
108 default:
109 return r;
110 }
111 }
112 verbose("getmchar: time %ud, timeout %ud", t, timeout);
113
114 return seterror(m, Enoresponse);
115 }
116
117 int
putmchar(Modem * m,char * p)118 putmchar(Modem *m, char *p)
119 {
120 if(write(m->fd, p, 1) < 0)
121 return seterror(m, Esys);
122 return Eok;
123 }
124
125 /*
126 * lines terminate with cr-lf
127 */
128 static int
getmline(Modem * m,char * buf,int len,long timeout)129 getmline(Modem *m, char *buf, int len, long timeout)
130 {
131 int r, t;
132 char *e = buf+len-1;
133 char last = 0;
134
135 timeout += time(0);
136 while((t = time(0)) <= timeout){
137 switch(r = rawmchar(m, buf)){
138
139 case Eok:
140 /* ignore ^s ^q which are used for flow */
141 if(*buf == '\021' || *buf == '\023')
142 continue;
143 if(*buf == '\n'){
144 /* ignore nl if its not with a cr */
145 if(last == '\r'){
146 *buf = 0;
147 return Eok;
148 }
149 continue;
150 }
151 last = *buf;
152 if(*buf == '\r')
153 continue;
154 buf++;
155 if(buf == e){
156 *buf = 0;
157 return Eok;
158 }
159 continue;
160
161 case Enoresponse:
162 sleep(100);
163 continue;
164
165 default:
166 return r;
167 }
168 }
169 verbose("getmline: time %ud, timeout %ud", t, timeout);
170
171 return seterror(m, Enoresponse);
172 }
173
174 int
command(Modem * m,char * s)175 command(Modem *m, char *s)
176 {
177 verbose("m->: %s", s);
178 if(fprint(m->fd, "%s\r", s) < 0)
179 return seterror(m, Esys);
180 return Eok;
181 }
182
183 /*
184 * Read till we see a message or we time out.
185 * BUG: line lengths not checked;
186 * newlines
187 */
188 int
response(Modem * m,int timeout)189 response(Modem *m, int timeout)
190 {
191 int r;
192 ResultCode *rp;
193
194 while(getmline(m, m->response, sizeof(m->response), timeout) == Eok){
195 if(m->response[0] == 0)
196 continue;
197 verbose("<-m: %s", m->response);
198 for(rp = results; rp->terse; rp++){
199 if(strncmp(rp->verbose, m->response, strlen(rp->verbose)))
200 continue;
201 r = rp->result;
202 if(rp->f && (r = (*rp->f)(m)) == Rcontinue)
203 break;
204 return r;
205 }
206 }
207
208 m->response[0] = 0;
209 return Rnoise;
210 }
211
212 void
xonoff(Modem * m,int i)213 xonoff(Modem *m, int i)
214 {
215 char buf[8];
216
217 sprint(buf, "x%d", i);
218 i = strlen(buf);
219 write(m->cfd, buf, i);
220 }
221