/* * 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>#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 },}; voidinitmodem(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;} intrawmchar(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;} intgetmchar(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);} intputmchar(Modem *m, char *p){ if(write(m->fd, p, 1) < 0) return seterror(m, Esys); return Eok;} /* * lines terminate with cr-lf */static intgetmline(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);} intcommand(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 */intresponse(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;} voidxonoff(Modem *m, int i){ char buf[8]; sprint(buf, "x%d", i); i = strlen(buf); write(m->cfd, buf, i);}
/*
* 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>
#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);
}