Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#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");
}