hayes.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #include <u.h>
  2. #include <libc.h>
  3. void setspeed(int, int);
  4. int getspeed(char*, int);
  5. void godial(int, int, char*);
  6. int readmsg(int, int);
  7. void punt(char*, ...);
  8. int pulsed;
  9. int verbose;
  10. char msgbuf[128]; /* last message read */
  11. enum
  12. {
  13. Ok,
  14. Success,
  15. Failure,
  16. Noise,
  17. };
  18. typedef struct Msg Msg;
  19. struct Msg
  20. {
  21. char *text;
  22. int type;
  23. };
  24. Msg msgs[] =
  25. {
  26. { "OK", Ok, },
  27. { "NO CARRIER", Failure, },
  28. { "ERROR", Failure, },
  29. { "NO DIALTONE", Failure, },
  30. { "BUSY", Failure, },
  31. { "NO ANSWER", Failure, },
  32. { "CONNECT", Success, },
  33. { 0, 0 },
  34. };
  35. void
  36. usage(void)
  37. {
  38. punt("usage: hayes [-p] telno [device]");
  39. }
  40. void
  41. main(int argc, char **argv)
  42. {
  43. int data = -1;
  44. int ctl = -1;
  45. char *cname;
  46. ARGBEGIN{
  47. case 'p':
  48. pulsed = 1;
  49. break;
  50. case 'v':
  51. verbose = 1;
  52. break;
  53. default:
  54. usage();
  55. }ARGEND
  56. switch(argc){
  57. case 1:
  58. data = 1;
  59. break;
  60. case 2:
  61. data = open(argv[1], ORDWR);
  62. if(data < 0){
  63. fprint(2, "hayes: %r opening %s\n", argv[1]);
  64. exits("hayes");
  65. }
  66. cname = malloc(strlen(argv[1])+4);
  67. sprint(cname, "%sctl", argv[1]);
  68. ctl = open(cname, ORDWR);
  69. free(cname);
  70. break;
  71. default:
  72. usage();
  73. }
  74. godial(data, ctl, argv[0]);
  75. exits(0);
  76. }
  77. int
  78. send(int fd, char *x)
  79. {
  80. return write(fd, x, strlen(x));
  81. }
  82. void
  83. godial(int data, int ctl, char *number)
  84. {
  85. char *dialstr;
  86. int m;
  87. int baud;
  88. /* get the modem's attention */
  89. if(send(data, "\r+++\r") < 0)
  90. punt("failed write");
  91. readmsg(data, 2);
  92. sleep(1000);
  93. /* initialize */
  94. if(send(data, "ATZ\r") < 0)
  95. punt("failed write");
  96. m = readmsg(data, 2);
  97. if(m < 0)
  98. punt("can't get modem's attention");
  99. /*
  100. * Q0 = report result codes
  101. * V1 = full word result codes
  102. * W1 = negotiation progress codes enabled
  103. * E1 = echo commands
  104. * M1 = speaker on until on-line
  105. */
  106. if(send(data, "ATQ0V1E1M1\r") < 0)
  107. punt("failed write");
  108. m = readmsg(data, 2);
  109. if(m != Ok)
  110. punt("can't get modem's attention");
  111. if(send(data, "ATW1\r") < 0)
  112. punt("failed write");
  113. readmsg(data, 2);
  114. sleep(1000);
  115. /* godial */
  116. dialstr = malloc(6+strlen(number));
  117. sprint(dialstr, "ATD%c%s\r", pulsed ? 'P' : 'T', number);
  118. if(send(data, dialstr) < 0) {
  119. free(dialstr);
  120. punt("failed write");
  121. }
  122. free(dialstr);
  123. m = readmsg(data, 60);
  124. if(m != Success)
  125. punt("dial failed: %s", msgbuf);
  126. baud = getspeed(msgbuf, 9600);
  127. setspeed(ctl, baud);
  128. fprint(2, "hayes: connected at %d baud\n", baud);
  129. }
  130. /*
  131. * read until we see a message or we time out
  132. */
  133. int
  134. readmsg(int f, int secs)
  135. {
  136. ulong start;
  137. char *p;
  138. int len;
  139. Dir *d;
  140. Msg *pp;
  141. p = msgbuf;
  142. len = sizeof(msgbuf) - 1;
  143. for(start = time(0); time(0) <= start+secs;){
  144. if((d = dirfstat(f)) == nil)
  145. punt("failed read");
  146. if(d->length == 0){
  147. free(d);
  148. sleep(100);
  149. continue;
  150. }
  151. free(d);
  152. if(read(f, p, 1) <= 0)
  153. punt("failed read");
  154. if(*p == '\n' || *p == '\r' || len == 0){
  155. *p = 0;
  156. if(verbose && p != msgbuf)
  157. fprint(2, "%s\n", msgbuf);
  158. for(pp = msgs; pp->text; pp++)
  159. if(strncmp(pp->text, msgbuf, strlen(pp->text))==0)
  160. return pp->type;
  161. start = time(0);
  162. p = msgbuf;
  163. len = sizeof(msgbuf) - 1;
  164. continue;
  165. }
  166. len--;
  167. p++;
  168. }
  169. strcpy(msgbuf, "No response from modem");
  170. return Noise;
  171. }
  172. /*
  173. * get baud rate from a connect message
  174. */
  175. int
  176. getspeed(char *msg, int speed)
  177. {
  178. char *p;
  179. int s;
  180. p = msg + sizeof("CONNECT") - 1;
  181. while(*p == ' ' || *p == '\t')
  182. p++;
  183. s = atoi(p);
  184. if(s <= 0)
  185. return speed;
  186. else
  187. return s;
  188. }
  189. /*
  190. * set speed and RTS/CTS modem flow control
  191. */
  192. void
  193. setspeed(int ctl, int baud)
  194. {
  195. char buf[32];
  196. if(ctl < 0)
  197. return;
  198. sprint(buf, "b%d", baud);
  199. write(ctl, buf, strlen(buf));
  200. write(ctl, "m1", 2);
  201. }
  202. void
  203. punt(char *fmt, ...)
  204. {
  205. char buf[256];
  206. va_list arg;
  207. int n;
  208. strcpy(buf, "hayes: ");
  209. va_start(arg, fmt);
  210. n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
  211. va_end(arg);
  212. buf[n] = '\n';
  213. write(2, buf, n+1);
  214. exits("hayes");
  215. }