summaryrefslogtreecommitdiff
path: root/sys/src/cmd/con/hayes.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/con/hayes.c240
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");
+}