modem.c 4.2 KB

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