xref: /plan9/sys/src/cmd/con/hayes.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier 
47dd7cddfSDavid du Colombier void setspeed(int, int);
57dd7cddfSDavid du Colombier int getspeed(char*, int);
67dd7cddfSDavid du Colombier void godial(int, int, char*);
77dd7cddfSDavid du Colombier int readmsg(int, int);
87dd7cddfSDavid du Colombier void punt(char*, ...);
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier int pulsed;
117dd7cddfSDavid du Colombier int verbose;
127dd7cddfSDavid du Colombier char msgbuf[128];		/* last message read */
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier enum
157dd7cddfSDavid du Colombier {
167dd7cddfSDavid du Colombier 	Ok,
177dd7cddfSDavid du Colombier 	Success,
187dd7cddfSDavid du Colombier 	Failure,
197dd7cddfSDavid du Colombier 	Noise,
207dd7cddfSDavid du Colombier };
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier typedef struct Msg	Msg;
237dd7cddfSDavid du Colombier struct Msg
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier 	char	*text;
267dd7cddfSDavid du Colombier 	int	type;
277dd7cddfSDavid du Colombier };
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier Msg msgs[] =
317dd7cddfSDavid du Colombier {
327dd7cddfSDavid du Colombier 	{ "OK",			Ok, },
337dd7cddfSDavid du Colombier 	{ "NO CARRIER", 	Failure, },
347dd7cddfSDavid du Colombier 	{ "ERROR",		Failure, },
357dd7cddfSDavid du Colombier 	{ "NO DIALTONE",	Failure, },
367dd7cddfSDavid du Colombier 	{ "BUSY",		Failure, },
377dd7cddfSDavid du Colombier 	{ "NO ANSWER",		Failure, },
387dd7cddfSDavid du Colombier 	{ "CONNECT",		Success, },
397dd7cddfSDavid du Colombier 	{ 0,			0 },
407dd7cddfSDavid du Colombier };
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier void
usage(void)437dd7cddfSDavid du Colombier usage(void)
447dd7cddfSDavid du Colombier {
457dd7cddfSDavid du Colombier 	punt("usage: hayes [-p] telno [device]");
467dd7cddfSDavid du Colombier }
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier void
main(int argc,char ** argv)497dd7cddfSDavid du Colombier main(int argc, char **argv)
507dd7cddfSDavid du Colombier {
517dd7cddfSDavid du Colombier 	int data = -1;
527dd7cddfSDavid du Colombier 	int ctl = -1;
53*9a747e4fSDavid du Colombier 	char *cname;
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier 	ARGBEGIN{
567dd7cddfSDavid du Colombier 	case 'p':
577dd7cddfSDavid du Colombier 		pulsed = 1;
587dd7cddfSDavid du Colombier 		break;
597dd7cddfSDavid du Colombier 	case 'v':
607dd7cddfSDavid du Colombier 		verbose = 1;
617dd7cddfSDavid du Colombier 		break;
627dd7cddfSDavid du Colombier 	default:
637dd7cddfSDavid du Colombier 		usage();
647dd7cddfSDavid du Colombier 	}ARGEND
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier 	switch(argc){
677dd7cddfSDavid du Colombier 	case 1:
687dd7cddfSDavid du Colombier 		data = 1;
697dd7cddfSDavid du Colombier 		break;
707dd7cddfSDavid du Colombier 	case 2:
717dd7cddfSDavid du Colombier 		data = open(argv[1], ORDWR);
727dd7cddfSDavid du Colombier 		if(data < 0){
737dd7cddfSDavid du Colombier 			fprint(2, "hayes: %r opening %s\n", argv[1]);
747dd7cddfSDavid du Colombier 			exits("hayes");
757dd7cddfSDavid du Colombier 		}
76*9a747e4fSDavid du Colombier 		cname = malloc(strlen(argv[1])+4);
777dd7cddfSDavid du Colombier 		sprint(cname, "%sctl", argv[1]);
787dd7cddfSDavid du Colombier 		ctl = open(cname, ORDWR);
79*9a747e4fSDavid du Colombier 		free(cname);
807dd7cddfSDavid du Colombier 		break;
817dd7cddfSDavid du Colombier 	default:
827dd7cddfSDavid du Colombier 		usage();
837dd7cddfSDavid du Colombier 	}
847dd7cddfSDavid du Colombier 	godial(data, ctl, argv[0]);
857dd7cddfSDavid du Colombier 	exits(0);
867dd7cddfSDavid du Colombier }
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier int
send(int fd,char * x)897dd7cddfSDavid du Colombier send(int fd, char *x)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier 	return write(fd, x, strlen(x));
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier void
godial(int data,int ctl,char * number)957dd7cddfSDavid du Colombier godial(int data, int ctl, char *number)
967dd7cddfSDavid du Colombier {
97*9a747e4fSDavid du Colombier 	char *dialstr;
987dd7cddfSDavid du Colombier 	int m;
997dd7cddfSDavid du Colombier 	int baud;
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier 	/* get the modem's attention */
1027dd7cddfSDavid du Colombier 	if(send(data, "\r+++\r") < 0)
1037dd7cddfSDavid du Colombier 		punt("failed write");
1047dd7cddfSDavid du Colombier 	readmsg(data, 2);
1057dd7cddfSDavid du Colombier 	sleep(1000);
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier 	/* initialize */
1087dd7cddfSDavid du Colombier 	if(send(data, "ATZ\r") < 0)
1097dd7cddfSDavid du Colombier 		punt("failed write");
1107dd7cddfSDavid du Colombier 	m = readmsg(data, 2);
1117dd7cddfSDavid du Colombier 	if(m < 0)
1127dd7cddfSDavid du Colombier 		punt("can't get modem's attention");
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 	/*
1157dd7cddfSDavid du Colombier 	 *	Q0 = report result codes
1167dd7cddfSDavid du Colombier 	 * 	V1 = full word result codes
1177dd7cddfSDavid du Colombier 	 *	W1 = negotiation progress codes enabled
1187dd7cddfSDavid du Colombier 	 *	E1 = echo commands
1197dd7cddfSDavid du Colombier 	 *	M1 = speaker on until on-line
1207dd7cddfSDavid du Colombier 	 */
1217dd7cddfSDavid du Colombier 	if(send(data, "ATQ0V1E1M1\r") < 0)
1227dd7cddfSDavid du Colombier 		punt("failed write");
1237dd7cddfSDavid du Colombier 	m = readmsg(data, 2);
1247dd7cddfSDavid du Colombier 	if(m != Ok)
1257dd7cddfSDavid du Colombier 		punt("can't get modem's attention");
1267dd7cddfSDavid du Colombier 	if(send(data, "ATW1\r") < 0)
1277dd7cddfSDavid du Colombier 		punt("failed write");
1287dd7cddfSDavid du Colombier 	readmsg(data, 2);
1297dd7cddfSDavid du Colombier 	sleep(1000);
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 	/* godial */
132*9a747e4fSDavid du Colombier 	dialstr = malloc(6+strlen(number));
1337dd7cddfSDavid du Colombier 	sprint(dialstr, "ATD%c%s\r", pulsed ? 'P' : 'T', number);
134*9a747e4fSDavid du Colombier 	if(send(data, dialstr) < 0) {
135*9a747e4fSDavid du Colombier 		free(dialstr);
1367dd7cddfSDavid du Colombier 		punt("failed write");
137*9a747e4fSDavid du Colombier 	}
138*9a747e4fSDavid du Colombier 	free(dialstr);
1397dd7cddfSDavid du Colombier 	m = readmsg(data, 60);
1407dd7cddfSDavid du Colombier 	if(m != Success)
1417dd7cddfSDavid du Colombier 		punt("dial failed: %s", msgbuf);
1427dd7cddfSDavid du Colombier 	baud = getspeed(msgbuf, 9600);
1437dd7cddfSDavid du Colombier 	setspeed(ctl, baud);
1447dd7cddfSDavid du Colombier 	fprint(2, "hayes: connected at %d baud\n", baud);
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier /*
1487dd7cddfSDavid du Colombier  *  read until we see a message or we time out
1497dd7cddfSDavid du Colombier  */
1507dd7cddfSDavid du Colombier int
readmsg(int f,int secs)1517dd7cddfSDavid du Colombier readmsg(int f, int secs)
1527dd7cddfSDavid du Colombier {
1537dd7cddfSDavid du Colombier 	ulong start;
1547dd7cddfSDavid du Colombier 	char *p;
1557dd7cddfSDavid du Colombier 	int len;
156*9a747e4fSDavid du Colombier 	Dir *d;
1577dd7cddfSDavid du Colombier 	Msg *pp;
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 	p = msgbuf;
1607dd7cddfSDavid du Colombier 	len = sizeof(msgbuf) - 1;
1617dd7cddfSDavid du Colombier 	for(start = time(0); time(0) <= start+secs;){
162*9a747e4fSDavid du Colombier 		if((d = dirfstat(f)) == nil)
1637dd7cddfSDavid du Colombier 			punt("failed read");
164*9a747e4fSDavid du Colombier 		if(d->length == 0){
165*9a747e4fSDavid du Colombier 			free(d);
1667dd7cddfSDavid du Colombier 			sleep(100);
1677dd7cddfSDavid du Colombier 			continue;
1687dd7cddfSDavid du Colombier 		}
169*9a747e4fSDavid du Colombier 		free(d);
1707dd7cddfSDavid du Colombier 		if(read(f, p, 1) <= 0)
1717dd7cddfSDavid du Colombier 			punt("failed read");
1727dd7cddfSDavid du Colombier 		if(*p == '\n' || *p == '\r' || len == 0){
1737dd7cddfSDavid du Colombier 			*p = 0;
1747dd7cddfSDavid du Colombier 			if(verbose && p != msgbuf)
1757dd7cddfSDavid du Colombier 				fprint(2, "%s\n", msgbuf);
1767dd7cddfSDavid du Colombier 			for(pp = msgs; pp->text; pp++)
1777dd7cddfSDavid du Colombier 				if(strncmp(pp->text, msgbuf, strlen(pp->text))==0)
1787dd7cddfSDavid du Colombier 					return pp->type;
1797dd7cddfSDavid du Colombier 			start = time(0);
1807dd7cddfSDavid du Colombier 			p = msgbuf;
1817dd7cddfSDavid du Colombier 			len = sizeof(msgbuf) - 1;
1827dd7cddfSDavid du Colombier 			continue;
1837dd7cddfSDavid du Colombier 		}
1847dd7cddfSDavid du Colombier 		len--;
1857dd7cddfSDavid du Colombier 		p++;
1867dd7cddfSDavid du Colombier 	}
1877dd7cddfSDavid du Colombier 	strcpy(msgbuf, "No response from modem");
1887dd7cddfSDavid du Colombier 	return Noise;
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier /*
1927dd7cddfSDavid du Colombier  *  get baud rate from a connect message
1937dd7cddfSDavid du Colombier  */
1947dd7cddfSDavid du Colombier int
getspeed(char * msg,int speed)1957dd7cddfSDavid du Colombier getspeed(char *msg, int speed)
1967dd7cddfSDavid du Colombier {
1977dd7cddfSDavid du Colombier 	char *p;
1987dd7cddfSDavid du Colombier 	int s;
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 	p = msg + sizeof("CONNECT") - 1;
2017dd7cddfSDavid du Colombier 	while(*p == ' ' || *p == '\t')
2027dd7cddfSDavid du Colombier 		p++;
2037dd7cddfSDavid du Colombier 	s = atoi(p);
2047dd7cddfSDavid du Colombier 	if(s <= 0)
2057dd7cddfSDavid du Colombier 		return speed;
2067dd7cddfSDavid du Colombier 	else
2077dd7cddfSDavid du Colombier 		return s;
2087dd7cddfSDavid du Colombier }
2097dd7cddfSDavid du Colombier 
2107dd7cddfSDavid du Colombier /*
2117dd7cddfSDavid du Colombier  *  set speed and RTS/CTS modem flow control
2127dd7cddfSDavid du Colombier  */
2137dd7cddfSDavid du Colombier void
setspeed(int ctl,int baud)2147dd7cddfSDavid du Colombier setspeed(int ctl, int baud)
2157dd7cddfSDavid du Colombier {
2167dd7cddfSDavid du Colombier 	char buf[32];
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	if(ctl < 0)
2197dd7cddfSDavid du Colombier 		return;
2207dd7cddfSDavid du Colombier 	sprint(buf, "b%d", baud);
2217dd7cddfSDavid du Colombier 	write(ctl, buf, strlen(buf));
2227dd7cddfSDavid du Colombier 	write(ctl, "m1", 2);
2237dd7cddfSDavid du Colombier }
2247dd7cddfSDavid du Colombier 
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier void
punt(char * fmt,...)2277dd7cddfSDavid du Colombier punt(char *fmt, ...)
2287dd7cddfSDavid du Colombier {
2297dd7cddfSDavid du Colombier 	char buf[256];
2307dd7cddfSDavid du Colombier 	va_list arg;
2317dd7cddfSDavid du Colombier 	int n;
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier 	strcpy(buf, "hayes: ");
2347dd7cddfSDavid du Colombier 	va_start(arg, fmt);
235*9a747e4fSDavid du Colombier 	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
2367dd7cddfSDavid du Colombier 	va_end(arg);
2377dd7cddfSDavid du Colombier 	buf[n] = '\n';
2387dd7cddfSDavid du Colombier 	write(2, buf, n+1);
2397dd7cddfSDavid du Colombier 	exits("hayes");
2407dd7cddfSDavid du Colombier }
241