modem.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "modem.h"
  5. typedef struct {
  6. char *terse;
  7. char *verbose;
  8. int result;
  9. int (*f)(Modem*);
  10. } ResultCode;
  11. static ResultCode results[] = {
  12. { "0", "OK", Rok, 0, },
  13. { "1", "CONNECT", Rconnect, 0, },
  14. { "2", "RING", Rring, 0, },
  15. { "3", "NO CARRIER", Rfailure, 0, },
  16. { "4", "ERROR", Rrerror, 0, },
  17. { "5", "CONNECT 1200", Rconnect, 0, },
  18. { "6", "NO DIALTONE", Rfailure, 0, },
  19. { "7", "BUSY", Rfailure, 0, },
  20. { "8", "NO ANSWER", Rfailure, 0, },
  21. { "9", "CONNECT 2400", Rconnect, 0, }, /* MT1432BA */
  22. { "10", "CONNECT 2400", Rconnect, 0, }, /* Hayes */
  23. { "11", "CONNECT 4800", Rconnect, 0, },
  24. { "12", "CONNECT 9600", Rconnect, 0, },
  25. { "13", "CONNECT 14400",Rconnect, 0, },
  26. { "23", "CONNECT 1275", Rconnect, 0, }, /* MT1432BA */
  27. { "-1", "+FCON", Rcontinue, fcon, },
  28. { "-1", "+FTSI", Rcontinue, ftsi, },
  29. { "-1", "+FDCS", Rcontinue, fdcs, },
  30. { "-1", "+FCFR", Rcontinue, fcfr, },
  31. { "-1", "+FPTS", Rcontinue, fpts, },
  32. { "-1", "+FET", Rcontinue, fet, },
  33. { "-1", "+FHNG", Rcontinue, fhng, },
  34. { 0 },
  35. };
  36. void
  37. initmodem(Modem *m, int fd, int cfd, char *type, char *id)
  38. {
  39. m->fd = fd;
  40. m->cfd = cfd;
  41. if(id == 0)
  42. id = "Plan 9";
  43. m->id = id;
  44. m->t = type;
  45. }
  46. int
  47. rawmchar(Modem *m, char *p)
  48. {
  49. Dir *d;
  50. int n;
  51. if(m->icount == 0)
  52. m->iptr = m->ibuf;
  53. if(m->icount){
  54. *p = *m->iptr++;
  55. m->icount--;
  56. return Eok;
  57. }
  58. m->iptr = m->ibuf;
  59. if((d = dirfstat(m->fd)) == nil){
  60. verbose("rawmchar: dirfstat: %r");
  61. return seterror(m, Esys);
  62. }
  63. n = d->length;
  64. free(d);
  65. if(n == 0)
  66. return Enoresponse;
  67. if(n > sizeof(m->ibuf)-1)
  68. n = sizeof(m->ibuf)-1;
  69. if((m->icount = read(m->fd, m->ibuf, n)) <= 0){
  70. verbose("rawmchar: read: %r");
  71. m->icount = 0;
  72. return seterror(m, Esys);
  73. }
  74. *p = *m->iptr++;
  75. m->icount--;
  76. return Eok;
  77. }
  78. int
  79. getmchar(Modem *m, char *buf, long timeout)
  80. {
  81. int r, t;
  82. timeout += time(0);
  83. while((t = time(0)) <= timeout){
  84. switch(r = rawmchar(m, buf)){
  85. case Eok:
  86. return Eok;
  87. case Enoresponse:
  88. sleep(100);
  89. continue;
  90. default:
  91. return r;
  92. }
  93. }
  94. verbose("getmchar: time %ud, timeout %ud", t, timeout);
  95. return seterror(m, Enoresponse);
  96. }
  97. int
  98. putmchar(Modem *m, char *p)
  99. {
  100. if(write(m->fd, p, 1) < 0)
  101. return seterror(m, Esys);
  102. return Eok;
  103. }
  104. /*
  105. * lines terminate with cr-lf
  106. */
  107. static int
  108. getmline(Modem *m, char *buf, int len, long timeout)
  109. {
  110. int r, t;
  111. char *e = buf+len-1;
  112. char last = 0;
  113. timeout += time(0);
  114. while((t = time(0)) <= timeout){
  115. switch(r = rawmchar(m, buf)){
  116. case Eok:
  117. /* ignore ^s ^q which are used for flow */
  118. if(*buf == '\021' || *buf == '\023')
  119. continue;
  120. if(*buf == '\n'){
  121. /* ignore nl if its not with a cr */
  122. if(last == '\r'){
  123. *buf = 0;
  124. return Eok;
  125. }
  126. continue;
  127. }
  128. last = *buf;
  129. if(*buf == '\r')
  130. continue;
  131. buf++;
  132. if(buf == e){
  133. *buf = 0;
  134. return Eok;
  135. }
  136. continue;
  137. case Enoresponse:
  138. sleep(100);
  139. continue;
  140. default:
  141. return r;
  142. }
  143. }
  144. verbose("getmline: time %ud, timeout %ud", t, timeout);
  145. return seterror(m, Enoresponse);
  146. }
  147. int
  148. command(Modem *m, char *s)
  149. {
  150. verbose("m->: %s", s);
  151. if(fprint(m->fd, "%s\r", s) < 0)
  152. return seterror(m, Esys);
  153. return Eok;
  154. }
  155. /*
  156. * Read till we see a message or we time out.
  157. * BUG: line lengths not checked;
  158. * newlines
  159. */
  160. int
  161. response(Modem *m, int timeout)
  162. {
  163. int r;
  164. ResultCode *rp;
  165. while(getmline(m, m->response, sizeof(m->response), timeout) == Eok){
  166. if(m->response[0] == 0)
  167. continue;
  168. verbose("<-m: %s", m->response);
  169. for(rp = results; rp->terse; rp++){
  170. if(strncmp(rp->verbose, m->response, strlen(rp->verbose)))
  171. continue;
  172. r = rp->result;
  173. if(rp->f && (r = (*rp->f)(m)) == Rcontinue)
  174. break;
  175. return r;
  176. }
  177. }
  178. m->response[0] = 0;
  179. return Rnoise;
  180. }
  181. void
  182. xonoff(Modem *m, int i)
  183. {
  184. char buf[8];
  185. sprint(buf, "x%d", i);
  186. i = strlen(buf);
  187. write(m->cfd, buf, i);
  188. }