/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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 },}; voidusage(void){ punt("usage: hayes [-p] telno [device]");} voidmain(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);} intsend(int fd, char *x){ return write(fd, x, strlen(x));} voidgodial(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 */intreadmsg(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 */intgetspeed(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 */voidsetspeed(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);} voidpunt(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");}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#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");
}