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