xref: /plan9/sys/src/cmd/fax/modem.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier 
5219b2ee8SDavid du Colombier #include "modem.h"
6219b2ee8SDavid du Colombier 
7219b2ee8SDavid du Colombier typedef struct {
8219b2ee8SDavid du Colombier 	char	*terse;
9219b2ee8SDavid du Colombier 	char	*verbose;
10219b2ee8SDavid du Colombier 	int	result;
11219b2ee8SDavid du Colombier 	int	(*f)(Modem*);
12219b2ee8SDavid du Colombier } ResultCode;
13219b2ee8SDavid du Colombier 
14219b2ee8SDavid du Colombier static ResultCode results[] = {
15219b2ee8SDavid du Colombier 	{ "0",	"OK",		Rok,		0, },
16219b2ee8SDavid du Colombier 	{ "1",	"CONNECT",	Rconnect,	0, },
17219b2ee8SDavid du Colombier 	{ "2",	"RING",		Rring,		0, },
18219b2ee8SDavid du Colombier 	{ "3",	"NO CARRIER", 	Rfailure,	0, },
19219b2ee8SDavid du Colombier 	{ "4",	"ERROR",	Rrerror,	0, },
20219b2ee8SDavid du Colombier 	{ "5",	"CONNECT 1200",	Rconnect,	0, },
21219b2ee8SDavid du Colombier 	{ "6",	"NO DIALTONE",	Rfailure,	0, },
22219b2ee8SDavid du Colombier 	{ "7",	"BUSY",		Rfailure,	0, },
23219b2ee8SDavid du Colombier 	{ "8",	"NO ANSWER",	Rfailure,	0, },
24219b2ee8SDavid du Colombier 	{ "9",	"CONNECT 2400",	Rconnect,	0, },		/* MT1432BA */
25219b2ee8SDavid du Colombier 	{ "10",	"CONNECT 2400",	Rconnect,	0, },		/* Hayes */
26219b2ee8SDavid du Colombier 	{ "11",	"CONNECT 4800",	Rconnect,	0, },
27219b2ee8SDavid du Colombier 	{ "12",	"CONNECT 9600",	Rconnect,	0, },
28219b2ee8SDavid du Colombier 	{ "13",	"CONNECT 14400",Rconnect,	0, },
29219b2ee8SDavid du Colombier 	{ "23",	"CONNECT 1275",	Rconnect,	0, },		/* MT1432BA */
30219b2ee8SDavid du Colombier 
31219b2ee8SDavid du Colombier 	{ "-1",	"+FCON",	Rcontinue,	fcon, },
32219b2ee8SDavid du Colombier 	{ "-1",	"+FTSI",	Rcontinue,	ftsi, },
33219b2ee8SDavid du Colombier 	{ "-1",	"+FDCS",	Rcontinue,	fdcs, },
34219b2ee8SDavid du Colombier 	{ "-1",	"+FCFR",	Rcontinue,	fcfr, },
35219b2ee8SDavid du Colombier 	{ "-1",	"+FPTS",	Rcontinue,	fpts, },
36219b2ee8SDavid du Colombier 	{ "-1",	"+FET",		Rcontinue,	fet, },
37219b2ee8SDavid du Colombier 	{ "-1",	"+FHNG",	Rcontinue,	fhng, },
38219b2ee8SDavid du Colombier 
39219b2ee8SDavid du Colombier 	{ 0 },
40219b2ee8SDavid du Colombier };
41219b2ee8SDavid du Colombier 
42219b2ee8SDavid du Colombier void
initmodem(Modem * m,int fd,int cfd,char * type,char * id)43219b2ee8SDavid du Colombier initmodem(Modem *m, int fd, int cfd, char *type, char *id)
44219b2ee8SDavid du Colombier {
45219b2ee8SDavid du Colombier 	m->fd = fd;
46219b2ee8SDavid du Colombier 	m->cfd = cfd;
47219b2ee8SDavid du Colombier 	if(id == 0)
48219b2ee8SDavid du Colombier 		id = "Plan 9";
49219b2ee8SDavid du Colombier 	m->id = id;
50219b2ee8SDavid du Colombier 	m->t = type;
51219b2ee8SDavid du Colombier }
52219b2ee8SDavid du Colombier 
53219b2ee8SDavid du Colombier int
rawmchar(Modem * m,char * p)54219b2ee8SDavid du Colombier rawmchar(Modem *m, char *p)
55219b2ee8SDavid du Colombier {
56*9a747e4fSDavid du Colombier 	Dir *d;
577dd7cddfSDavid du Colombier 	int n;
58219b2ee8SDavid du Colombier 
59219b2ee8SDavid du Colombier 	if(m->icount == 0)
60219b2ee8SDavid du Colombier 		m->iptr = m->ibuf;
61219b2ee8SDavid du Colombier 
62219b2ee8SDavid du Colombier 	if(m->icount){
63219b2ee8SDavid du Colombier 		*p = *m->iptr++;
64219b2ee8SDavid du Colombier 		m->icount--;
65219b2ee8SDavid du Colombier 		return Eok;
66219b2ee8SDavid du Colombier 	}
67219b2ee8SDavid du Colombier 
68219b2ee8SDavid du Colombier 	m->iptr = m->ibuf;
69219b2ee8SDavid du Colombier 
70*9a747e4fSDavid du Colombier 	if((d = dirfstat(m->fd)) == nil){
71219b2ee8SDavid du Colombier 		verbose("rawmchar: dirfstat: %r");
72219b2ee8SDavid du Colombier 		return seterror(m, Esys);
73219b2ee8SDavid du Colombier 	}
74*9a747e4fSDavid du Colombier 	n = d->length;
75*9a747e4fSDavid du Colombier 	free(d);
767dd7cddfSDavid du Colombier 	if(n == 0)
77219b2ee8SDavid du Colombier 		return Enoresponse;
78219b2ee8SDavid du Colombier 
797dd7cddfSDavid du Colombier 	if(n > sizeof(m->ibuf)-1)
807dd7cddfSDavid du Colombier 		n = sizeof(m->ibuf)-1;
817dd7cddfSDavid du Colombier 	if((m->icount = read(m->fd, m->ibuf, n)) <= 0){
82219b2ee8SDavid du Colombier 		verbose("rawmchar: read: %r");
83219b2ee8SDavid du Colombier 		m->icount = 0;
84219b2ee8SDavid du Colombier 		return seterror(m, Esys);
85219b2ee8SDavid du Colombier 	}
86219b2ee8SDavid du Colombier 	*p = *m->iptr++;
87219b2ee8SDavid du Colombier 	m->icount--;
88219b2ee8SDavid du Colombier 
89219b2ee8SDavid du Colombier 	return Eok;
90219b2ee8SDavid du Colombier }
91219b2ee8SDavid du Colombier 
92219b2ee8SDavid du Colombier int
getmchar(Modem * m,char * buf,long timeout)93219b2ee8SDavid du Colombier getmchar(Modem *m, char *buf, long timeout)
94219b2ee8SDavid du Colombier {
957dd7cddfSDavid du Colombier 	int r, t;
96219b2ee8SDavid du Colombier 
97219b2ee8SDavid du Colombier 	timeout += time(0);
987dd7cddfSDavid du Colombier 	while((t = time(0)) <= timeout){
99219b2ee8SDavid du Colombier 		switch(r = rawmchar(m, buf)){
100219b2ee8SDavid du Colombier 
101219b2ee8SDavid du Colombier 		case Eok:
102219b2ee8SDavid du Colombier 			return Eok;
103219b2ee8SDavid du Colombier 
104219b2ee8SDavid du Colombier 		case Enoresponse:
105219b2ee8SDavid du Colombier 			sleep(100);
106219b2ee8SDavid du Colombier 			continue;
107219b2ee8SDavid du Colombier 
108219b2ee8SDavid du Colombier 		default:
109219b2ee8SDavid du Colombier 			return r;
110219b2ee8SDavid du Colombier 		}
111219b2ee8SDavid du Colombier 	}
1127dd7cddfSDavid du Colombier 	verbose("getmchar: time %ud, timeout %ud", t, timeout);
113219b2ee8SDavid du Colombier 
114219b2ee8SDavid du Colombier 	return seterror(m, Enoresponse);
115219b2ee8SDavid du Colombier }
116219b2ee8SDavid du Colombier 
117219b2ee8SDavid du Colombier int
putmchar(Modem * m,char * p)118219b2ee8SDavid du Colombier putmchar(Modem *m, char *p)
119219b2ee8SDavid du Colombier {
120219b2ee8SDavid du Colombier 	if(write(m->fd, p, 1) < 0)
121219b2ee8SDavid du Colombier 		return seterror(m, Esys);
122219b2ee8SDavid du Colombier 	return Eok;
123219b2ee8SDavid du Colombier }
124219b2ee8SDavid du Colombier 
1257dd7cddfSDavid du Colombier /*
1267dd7cddfSDavid du Colombier  *  lines terminate with cr-lf
1277dd7cddfSDavid du Colombier  */
128219b2ee8SDavid du Colombier static int
getmline(Modem * m,char * buf,int len,long timeout)129219b2ee8SDavid du Colombier getmline(Modem *m, char *buf, int len, long timeout)
130219b2ee8SDavid du Colombier {
1317dd7cddfSDavid du Colombier 	int r, t;
132219b2ee8SDavid du Colombier 	char *e = buf+len-1;
1337dd7cddfSDavid du Colombier 	char last = 0;
134219b2ee8SDavid du Colombier 
135219b2ee8SDavid du Colombier 	timeout += time(0);
1367dd7cddfSDavid du Colombier 	while((t = time(0)) <= timeout){
137219b2ee8SDavid du Colombier 		switch(r = rawmchar(m, buf)){
138219b2ee8SDavid du Colombier 
139219b2ee8SDavid du Colombier 		case Eok:
1407dd7cddfSDavid du Colombier 			/* ignore ^s ^q which are used for flow */
1417dd7cddfSDavid du Colombier 			if(*buf == '\021' || *buf == '\023')
142219b2ee8SDavid du Colombier 				continue;
1437dd7cddfSDavid du Colombier 			if(*buf == '\n'){
1447dd7cddfSDavid du Colombier 				/* ignore nl if its not with a cr */
1457dd7cddfSDavid du Colombier 				if(last == '\r'){
146219b2ee8SDavid du Colombier 					*buf = 0;
147219b2ee8SDavid du Colombier 					return Eok;
148219b2ee8SDavid du Colombier 				}
1497dd7cddfSDavid du Colombier 				continue;
1507dd7cddfSDavid du Colombier 			}
1517dd7cddfSDavid du Colombier 			last = *buf;
1527dd7cddfSDavid du Colombier 			if(*buf == '\r')
1537dd7cddfSDavid du Colombier 				continue;
154219b2ee8SDavid du Colombier 			buf++;
155219b2ee8SDavid du Colombier 			if(buf == e){
156219b2ee8SDavid du Colombier 				*buf = 0;
157219b2ee8SDavid du Colombier 				return Eok;
158219b2ee8SDavid du Colombier 			}
159219b2ee8SDavid du Colombier 			continue;
160219b2ee8SDavid du Colombier 
161219b2ee8SDavid du Colombier 		case Enoresponse:
162219b2ee8SDavid du Colombier 			sleep(100);
163219b2ee8SDavid du Colombier 			continue;
164219b2ee8SDavid du Colombier 
165219b2ee8SDavid du Colombier 		default:
166219b2ee8SDavid du Colombier 			return r;
167219b2ee8SDavid du Colombier 		}
168219b2ee8SDavid du Colombier 	}
1697dd7cddfSDavid du Colombier 	verbose("getmline: time %ud, timeout %ud", t, timeout);
170219b2ee8SDavid du Colombier 
171219b2ee8SDavid du Colombier 	return seterror(m, Enoresponse);
172219b2ee8SDavid du Colombier }
173219b2ee8SDavid du Colombier 
174219b2ee8SDavid du Colombier int
command(Modem * m,char * s)175219b2ee8SDavid du Colombier command(Modem *m, char *s)
176219b2ee8SDavid du Colombier {
177219b2ee8SDavid du Colombier 	verbose("m->: %s", s);
178219b2ee8SDavid du Colombier 	if(fprint(m->fd, "%s\r", s) < 0)
179219b2ee8SDavid du Colombier 		return seterror(m, Esys);
180219b2ee8SDavid du Colombier 	return Eok;
181219b2ee8SDavid du Colombier }
182219b2ee8SDavid du Colombier 
183219b2ee8SDavid du Colombier /*
184219b2ee8SDavid du Colombier  * Read till we see a message or we time out.
185219b2ee8SDavid du Colombier  * BUG: line lengths not checked;
186219b2ee8SDavid du Colombier  *	newlines
187219b2ee8SDavid du Colombier  */
188219b2ee8SDavid du Colombier int
response(Modem * m,int timeout)189219b2ee8SDavid du Colombier response(Modem *m, int timeout)
190219b2ee8SDavid du Colombier {
191219b2ee8SDavid du Colombier 	int r;
192219b2ee8SDavid du Colombier 	ResultCode *rp;
193219b2ee8SDavid du Colombier 
194219b2ee8SDavid du Colombier 	while(getmline(m, m->response, sizeof(m->response), timeout) == Eok){
195219b2ee8SDavid du Colombier 		if(m->response[0] == 0)
196219b2ee8SDavid du Colombier 			continue;
197219b2ee8SDavid du Colombier 		verbose("<-m: %s", m->response);
198219b2ee8SDavid du Colombier 		for(rp = results; rp->terse; rp++){
199219b2ee8SDavid du Colombier 			if(strncmp(rp->verbose, m->response, strlen(rp->verbose)))
200219b2ee8SDavid du Colombier 				continue;
201219b2ee8SDavid du Colombier 			r = rp->result;
202219b2ee8SDavid du Colombier 			if(rp->f && (r = (*rp->f)(m)) == Rcontinue)
203219b2ee8SDavid du Colombier 				break;
204219b2ee8SDavid du Colombier 			return r;
205219b2ee8SDavid du Colombier 		}
206219b2ee8SDavid du Colombier 	}
207219b2ee8SDavid du Colombier 
208219b2ee8SDavid du Colombier 	m->response[0] = 0;
209219b2ee8SDavid du Colombier 	return Rnoise;
210219b2ee8SDavid du Colombier }
211219b2ee8SDavid du Colombier 
212219b2ee8SDavid du Colombier void
xonoff(Modem * m,int i)213219b2ee8SDavid du Colombier xonoff(Modem *m, int i)
214219b2ee8SDavid du Colombier {
215219b2ee8SDavid du Colombier 	char buf[8];
216219b2ee8SDavid du Colombier 
217219b2ee8SDavid du Colombier 	sprint(buf, "x%d", i);
218219b2ee8SDavid du Colombier 	i = strlen(buf);
219219b2ee8SDavid du Colombier 	write(m->cfd, buf, i);
220219b2ee8SDavid du Colombier }
221