ref: 2c6cc121339ade33ac5aa4b46356df1cd5469fbe
dir: /sys/src/cmd/fax/modem.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); }