diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/con/hayes.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/con/hayes.c')
-rwxr-xr-x | sys/src/cmd/con/hayes.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/sys/src/cmd/con/hayes.c b/sys/src/cmd/con/hayes.c new file mode 100755 index 000000000..6ade8be86 --- /dev/null +++ b/sys/src/cmd/con/hayes.c @@ -0,0 +1,240 @@ +#include <u.h> +#include <libc.h> + +void setspeed(int, int); +int getspeed(char*, int); +void godial(int, int, char*); +int readmsg(int, int); +void punt(char*, ...); + +int pulsed; +int verbose; +char msgbuf[128]; /* last message read */ + +enum +{ + Ok, + Success, + Failure, + Noise, +}; + +typedef struct Msg Msg; +struct Msg +{ + char *text; + int type; +}; + + +Msg msgs[] = +{ + { "OK", Ok, }, + { "NO CARRIER", Failure, }, + { "ERROR", Failure, }, + { "NO DIALTONE", Failure, }, + { "BUSY", Failure, }, + { "NO ANSWER", Failure, }, + { "CONNECT", Success, }, + { 0, 0 }, +}; + +void +usage(void) +{ + punt("usage: hayes [-p] telno [device]"); +} + +void +main(int argc, char **argv) +{ + int data = -1; + int ctl = -1; + char *cname; + + ARGBEGIN{ + case 'p': + pulsed = 1; + break; + case 'v': + verbose = 1; + break; + default: + usage(); + }ARGEND + + switch(argc){ + case 1: + data = 1; + break; + case 2: + data = open(argv[1], ORDWR); + if(data < 0){ + fprint(2, "hayes: %r opening %s\n", argv[1]); + exits("hayes"); + } + cname = malloc(strlen(argv[1])+4); + sprint(cname, "%sctl", argv[1]); + ctl = open(cname, ORDWR); + free(cname); + break; + default: + usage(); + } + godial(data, ctl, argv[0]); + exits(0); +} + +int +send(int fd, char *x) +{ + return write(fd, x, strlen(x)); +} + +void +godial(int data, int ctl, char *number) +{ + char *dialstr; + int m; + int baud; + + /* get the modem's attention */ + if(send(data, "\r+++\r") < 0) + punt("failed write"); + readmsg(data, 2); + sleep(1000); + + /* initialize */ + if(send(data, "ATZ\r") < 0) + punt("failed write"); + m = readmsg(data, 2); + if(m < 0) + punt("can't get modem's attention"); + + /* + * Q0 = report result codes + * V1 = full word result codes + * W1 = negotiation progress codes enabled + * E1 = echo commands + * M1 = speaker on until on-line + */ + if(send(data, "ATQ0V1E1M1\r") < 0) + punt("failed write"); + m = readmsg(data, 2); + if(m != Ok) + punt("can't get modem's attention"); + if(send(data, "ATW1\r") < 0) + punt("failed write"); + readmsg(data, 2); + sleep(1000); + + /* godial */ + dialstr = malloc(6+strlen(number)); + sprint(dialstr, "ATD%c%s\r", pulsed ? 'P' : 'T', number); + if(send(data, dialstr) < 0) { + free(dialstr); + punt("failed write"); + } + free(dialstr); + m = readmsg(data, 60); + if(m != Success) + punt("dial failed: %s", msgbuf); + baud = getspeed(msgbuf, 9600); + setspeed(ctl, baud); + fprint(2, "hayes: connected at %d baud\n", baud); +} + +/* + * read until we see a message or we time out + */ +int +readmsg(int f, int secs) +{ + ulong start; + char *p; + int len; + Dir *d; + Msg *pp; + + p = msgbuf; + len = sizeof(msgbuf) - 1; + for(start = time(0); time(0) <= start+secs;){ + if((d = dirfstat(f)) == nil) + punt("failed read"); + if(d->length == 0){ + free(d); + sleep(100); + continue; + } + free(d); + if(read(f, p, 1) <= 0) + punt("failed read"); + if(*p == '\n' || *p == '\r' || len == 0){ + *p = 0; + if(verbose && p != msgbuf) + fprint(2, "%s\n", msgbuf); + for(pp = msgs; pp->text; pp++) + if(strncmp(pp->text, msgbuf, strlen(pp->text))==0) + return pp->type; + start = time(0); + p = msgbuf; + len = sizeof(msgbuf) - 1; + continue; + } + len--; + p++; + } + strcpy(msgbuf, "No response from modem"); + return Noise; +} + +/* + * get baud rate from a connect message + */ +int +getspeed(char *msg, int speed) +{ + char *p; + int s; + + p = msg + sizeof("CONNECT") - 1; + while(*p == ' ' || *p == '\t') + p++; + s = atoi(p); + if(s <= 0) + return speed; + else + return s; +} + +/* + * set speed and RTS/CTS modem flow control + */ +void +setspeed(int ctl, int baud) +{ + char buf[32]; + + if(ctl < 0) + return; + sprint(buf, "b%d", baud); + write(ctl, buf, strlen(buf)); + write(ctl, "m1", 2); +} + + +void +punt(char *fmt, ...) +{ + char buf[256]; + va_list arg; + int n; + + strcpy(buf, "hayes: "); + va_start(arg, fmt); + n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + buf[n] = '\n'; + write(2, buf, n+1); + exits("hayes"); +} |