xref: /plan9/sys/src/cmd/fax/modem.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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