221 lines
3.8 KiB
C
221 lines
3.8 KiB
C
|
#include <u.h>
|
||
|
#include <libc.h>
|
||
|
#include <bio.h>
|
||
|
|
||
|
#include "modem.h"
|
||
|
|
||
|
typedef struct {
|
||
|
char *terse;
|
||
|
char *verbose;
|
||
|
int result;
|
||
|
int (*f)(Modem*);
|
||
|
} ResultCode;
|
||
|
|
||
|
static ResultCode results[] = {
|
||
|
{ "0", "OK", Rok, 0, },
|
||
|
{ "1", "CONNECT", Rconnect, 0, },
|
||
|
{ "2", "RING", Rring, 0, },
|
||
|
{ "3", "NO CARRIER", Rfailure, 0, },
|
||
|
{ "4", "ERROR", Rrerror, 0, },
|
||
|
{ "5", "CONNECT 1200", Rconnect, 0, },
|
||
|
{ "6", "NO DIALTONE", Rfailure, 0, },
|
||
|
{ "7", "BUSY", Rfailure, 0, },
|
||
|
{ "8", "NO ANSWER", Rfailure, 0, },
|
||
|
{ "9", "CONNECT 2400", Rconnect, 0, }, /* MT1432BA */
|
||
|
{ "10", "CONNECT 2400", Rconnect, 0, }, /* Hayes */
|
||
|
{ "11", "CONNECT 4800", Rconnect, 0, },
|
||
|
{ "12", "CONNECT 9600", Rconnect, 0, },
|
||
|
{ "13", "CONNECT 14400",Rconnect, 0, },
|
||
|
{ "23", "CONNECT 1275", Rconnect, 0, }, /* MT1432BA */
|
||
|
|
||
|
{ "-1", "+FCON", Rcontinue, fcon, },
|
||
|
{ "-1", "+FTSI", Rcontinue, ftsi, },
|
||
|
{ "-1", "+FDCS", Rcontinue, fdcs, },
|
||
|
{ "-1", "+FCFR", Rcontinue, fcfr, },
|
||
|
{ "-1", "+FPTS", Rcontinue, fpts, },
|
||
|
{ "-1", "+FET", Rcontinue, fet, },
|
||
|
{ "-1", "+FHNG", Rcontinue, fhng, },
|
||
|
|
||
|
{ 0 },
|
||
|
};
|
||
|
|
||
|
void
|
||
|
initmodem(Modem *m, int fd, int cfd, char *type, char *id)
|
||
|
{
|
||
|
m->fd = fd;
|
||
|
m->cfd = cfd;
|
||
|
if(id == 0)
|
||
|
id = "Plan 9";
|
||
|
m->id = id;
|
||
|
m->t = type;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
rawmchar(Modem *m, char *p)
|
||
|
{
|
||
|
Dir *d;
|
||
|
int n;
|
||
|
|
||
|
if(m->icount == 0)
|
||
|
m->iptr = m->ibuf;
|
||
|
|
||
|
if(m->icount){
|
||
|
*p = *m->iptr++;
|
||
|
m->icount--;
|
||
|
return Eok;
|
||
|
}
|
||
|
|
||
|
m->iptr = m->ibuf;
|
||
|
|
||
|
if((d = dirfstat(m->fd)) == nil){
|
||
|
verbose("rawmchar: dirfstat: %r");
|
||
|
return seterror(m, Esys);
|
||
|
}
|
||
|
n = d->length;
|
||
|
free(d);
|
||
|
if(n == 0)
|
||
|
return Enoresponse;
|
||
|
|
||
|
if(n > sizeof(m->ibuf)-1)
|
||
|
n = sizeof(m->ibuf)-1;
|
||
|
if((m->icount = read(m->fd, m->ibuf, n)) <= 0){
|
||
|
verbose("rawmchar: read: %r");
|
||
|
m->icount = 0;
|
||
|
return seterror(m, Esys);
|
||
|
}
|
||
|
*p = *m->iptr++;
|
||
|
m->icount--;
|
||
|
|
||
|
return Eok;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
getmchar(Modem *m, char *buf, long timeout)
|
||
|
{
|
||
|
int r, t;
|
||
|
|
||
|
timeout += time(0);
|
||
|
while((t = time(0)) <= timeout){
|
||
|
switch(r = rawmchar(m, buf)){
|
||
|
|
||
|
case Eok:
|
||
|
return Eok;
|
||
|
|
||
|
case Enoresponse:
|
||
|
sleep(100);
|
||
|
continue;
|
||
|
|
||
|
default:
|
||
|
return r;
|
||
|
}
|
||
|
}
|
||
|
verbose("getmchar: time %ud, timeout %ud", t, timeout);
|
||
|
|
||
|
return seterror(m, Enoresponse);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
putmchar(Modem *m, char *p)
|
||
|
{
|
||
|
if(write(m->fd, p, 1) < 0)
|
||
|
return seterror(m, Esys);
|
||
|
return Eok;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* lines terminate with cr-lf
|
||
|
*/
|
||
|
static int
|
||
|
getmline(Modem *m, char *buf, int len, long timeout)
|
||
|
{
|
||
|
int r, t;
|
||
|
char *e = buf+len-1;
|
||
|
char last = 0;
|
||
|
|
||
|
timeout += time(0);
|
||
|
while((t = time(0)) <= timeout){
|
||
|
switch(r = rawmchar(m, buf)){
|
||
|
|
||
|
case Eok:
|
||
|
/* ignore ^s ^q which are used for flow */
|
||
|
if(*buf == '\021' || *buf == '\023')
|
||
|
continue;
|
||
|
if(*buf == '\n'){
|
||
|
/* ignore nl if its not with a cr */
|
||
|
if(last == '\r'){
|
||
|
*buf = 0;
|
||
|
return Eok;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
last = *buf;
|
||
|
if(*buf == '\r')
|
||
|
continue;
|
||
|
buf++;
|
||
|
if(buf == e){
|
||
|
*buf = 0;
|
||
|
return Eok;
|
||
|
}
|
||
|
continue;
|
||
|
|
||
|
case Enoresponse:
|
||
|
sleep(100);
|
||
|
continue;
|
||
|
|
||
|
default:
|
||
|
return r;
|
||
|
}
|
||
|
}
|
||
|
verbose("getmline: time %ud, timeout %ud", t, timeout);
|
||
|
|
||
|
return seterror(m, Enoresponse);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
command(Modem *m, char *s)
|
||
|
{
|
||
|
verbose("m->: %s", s);
|
||
|
if(fprint(m->fd, "%s\r", s) < 0)
|
||
|
return seterror(m, Esys);
|
||
|
return Eok;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Read till we see a message or we time out.
|
||
|
* BUG: line lengths not checked;
|
||
|
* newlines
|
||
|
*/
|
||
|
int
|
||
|
response(Modem *m, int timeout)
|
||
|
{
|
||
|
int r;
|
||
|
ResultCode *rp;
|
||
|
|
||
|
while(getmline(m, m->response, sizeof(m->response), timeout) == Eok){
|
||
|
if(m->response[0] == 0)
|
||
|
continue;
|
||
|
verbose("<-m: %s", m->response);
|
||
|
for(rp = results; rp->terse; rp++){
|
||
|
if(strncmp(rp->verbose, m->response, strlen(rp->verbose)))
|
||
|
continue;
|
||
|
r = rp->result;
|
||
|
if(rp->f && (r = (*rp->f)(m)) == Rcontinue)
|
||
|
break;
|
||
|
return r;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m->response[0] = 0;
|
||
|
return Rnoise;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
xonoff(Modem *m, int i)
|
||
|
{
|
||
|
char buf[8];
|
||
|
|
||
|
sprint(buf, "x%d", i);
|
||
|
i = strlen(buf);
|
||
|
write(m->cfd, buf, i);
|
||
|
}
|