serial.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <unistd.h>
  5. #include <termios.h>
  6. #include <fcntl.h>
  7. #include <sys/ioctl.h>
  8. #include <sys/time.h>
  9. #include <sys/select.h>
  10. #include <serial.h>
  11. #include <sprog.h>
  12. int serial_setbaud_termios(struct termios *t, int baud);
  13. int serial_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  14. int ringbuf_append(struct ring_buf *buf, const char *data, unsigned int len);
  15. int ringbuf_getline(struct ring_buf *buf, char *data, unsigned int len);
  16. int ringbuf_getdata(struct ring_buf *buf, char *data, unsigned int len);
  17. void ringbuf_move(struct ring_buf *buf, unsigned int bytes);
  18. void ringbuf_reset(struct ring_buf *buf);
  19. /* supported baud codes to use with cfsetispeed, cfsetospeed - keep sorted! */
  20. const struct baud_code baud_codes[] = {
  21. {50, B50},
  22. {75, B75},
  23. {110, B110},
  24. {134, B134},
  25. {150, B150},
  26. {200, B200},
  27. {300, B300},
  28. {600, B600},
  29. {1200, B1200},
  30. {1800, B1800},
  31. {2400, B2400},
  32. {4800, B4800},
  33. {9600, B9600},
  34. {19200, B19200},
  35. {38400, B38400},
  36. {57600, B57600},
  37. {115200, B115200},
  38. {230400, B230400},
  39. {-1, 0}
  40. };
  41. int serial_open(struct serial_device *port, const char *path, int baud) {
  42. struct termios attr;
  43. int fd;
  44. fd = open(path, O_RDWR);
  45. if(fd<0) {
  46. sprog_error("Unable to open serial port %s: %s\n", path, strerror(errno));
  47. exit(1);
  48. }
  49. tcgetattr(fd, &attr);
  50. /* 8 data bits, 1 stop bit, no parity */
  51. attr.c_iflag = IGNBRK;
  52. attr.c_oflag &= ~(OPOST | OLCUC | ONOCR | ONLRET | ONLCR);
  53. attr.c_cflag = CS8 | CREAD | CLOCAL;
  54. attr.c_lflag = ICANON;
  55. serial_setbaud_termios(&attr, baud);
  56. tcsetattr(fd, TCSANOW, &attr);
  57. port->fd = fd;
  58. return fd;
  59. }
  60. void serial_close(struct serial_device *port) {
  61. close(port->fd);
  62. }
  63. int serial_setbaud(struct serial_device *port, int baud) {
  64. struct termios attr;
  65. tcgetattr(port->fd, &attr);
  66. baud = serial_setbaud_termios(&attr, baud);
  67. tcsetattr(port->fd, TCSANOW, &attr);
  68. return baud;
  69. }
  70. int serial_setbaud_termios(struct termios *t, int baud) {
  71. int i;
  72. int baudcode;
  73. /* find the corresponding baud code */
  74. for(i=0; baud_codes[i].baud>0; i++) {
  75. if(baud_codes[i].baud == baud)
  76. break;
  77. if(baud_codes[i].baud > baud) {
  78. if(i>0) i--;
  79. break;
  80. }
  81. }
  82. /* if the selected baud rate is greater than any of available rates, set the highest one */
  83. if(baud_codes[i].baud<=0) i--;
  84. if(baud_codes[i].baud != baud)
  85. sprog_error("Unsupported baud rate %d, using the nearest value %d\n", baud, baud_codes[i].baud);
  86. baudcode = baud_codes[i].code;
  87. cfsetispeed(t, baudcode);
  88. cfsetospeed(t, baudcode);
  89. return baud_codes[i].baud;
  90. }
  91. void serial_setline(struct serial_device *port, int line, int state) {
  92. int bits;
  93. int mask;
  94. if(line==SERIAL_DTR)
  95. mask = TIOCM_DTR;
  96. else
  97. mask = TIOCM_RTS;
  98. ioctl(port->fd, TIOCMGET, &bits);
  99. if(state)
  100. bits |= mask;
  101. else
  102. bits &= ~mask;
  103. ioctl(port->fd, TIOCMSET, &bits);
  104. }
  105. void serial_write(struct serial_device *port, const char *text) {
  106. int i;
  107. int b;
  108. int bytes;
  109. bytes = strlen(text);
  110. i = 0;
  111. while(bytes-i>0) {
  112. b = write(port->fd, &text[i], bytes-i);
  113. if(b<0) {
  114. sprog_error("Error while writing to the serial port: %s\n", strerror(errno));
  115. break;
  116. }
  117. i += b;
  118. }
  119. }
  120. int serial_read(struct serial_device *port, char *buf, int len, int timeout) {
  121. int bytes;
  122. fd_set readset;
  123. struct timeval tval;
  124. FD_ZERO(&readset);
  125. FD_SET(port->fd, &readset);
  126. tval.tv_sec = timeout/1000;
  127. tval.tv_usec = (timeout % 1000) * 1000;
  128. bytes = 0;
  129. while((serial_select(port->fd+1, &readset, NULL, NULL, &tval)>0) && (len-bytes)>0) {
  130. if(FD_ISSET(port->fd, &readset))
  131. bytes += read(port->fd, &buf[bytes], len-bytes);
  132. }
  133. return bytes;
  134. }
  135. int serial_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
  136. int res;
  137. /* Linux automatically subtracts the time elapsed on awaiting
  138. * for an event when calling select(), The following code unifices
  139. * the behaviour under different implementations of UNIX.
  140. */
  141. #ifndef __linux__
  142. struct timeval start_time
  143. struct timeval cur_time;
  144. long int remaining;
  145. gettimeofday(&start_time, NULL);
  146. res = pselect(nfds, readfds, writefds, exceptfds, timeout, NULL)
  147. gettimeofday(&cur_time, NULL);
  148. remaining = (timeout->tv_sec - (cur_time.tv_sec - start_time.tv_sec))*1000000 + timeout->tv_usec - (cur_time.tv_usec - start_time.tv_usec);
  149. if(remaining<0) remaining = 0;
  150. timeout.tv_sec = remaining/1000000;
  151. timeout.tv_usec = remmaining%1000000;
  152. #else
  153. res = select(nfds, readfds, writefds, exceptfds, timeout);
  154. #endif
  155. return res;
  156. }
  157. void serial_communicate(struct serial_device *port, int infd, int outfd) {
  158. char buf[4096];
  159. int n;
  160. int bytes;
  161. int nfds;
  162. fd_set read_set;
  163. fd_set write_set;
  164. fd_set except_set;
  165. ringbuf_reset(&port->in_buf);
  166. ringbuf_reset(&port->out_buf);
  167. FD_ZERO(&read_set);
  168. FD_ZERO(&write_set);
  169. FD_ZERO(&except_set);
  170. FD_SET(port->fd, &read_set);
  171. FD_SET(infd, &read_set);;
  172. FD_SET(port->fd, &except_set);
  173. FD_SET(infd, &except_set);
  174. FD_SET(outfd, &except_set);
  175. nfds = port->fd;
  176. if(infd>nfds)
  177. nfds = infd;
  178. if(outfd>nfds)
  179. nfds = outfd;
  180. nfds++;
  181. while(select(nfds, &read_set, &write_set, &except_set, NULL)>0) {
  182. if(FD_ISSET(outfd, &write_set)) {
  183. n = ringbuf_getdata(&port->in_buf, buf, sizeof(buf));
  184. n = write(outfd, buf, n);
  185. ringbuf_move(&port->in_buf, n);
  186. }
  187. if(FD_ISSET(port->fd, &write_set)) {
  188. n = ringbuf_getdata(&port->out_buf, buf, sizeof(buf));
  189. n = write(port->fd, buf, n);
  190. ringbuf_move(&port->out_buf, n);
  191. }
  192. FD_ZERO(&read_set);
  193. FD_ZERO(&write_set);
  194. FD_ZERO(&except_set);
  195. FD_SET(port->fd, &read_set);
  196. FD_SET(infd, &read_set);
  197. FD_SET(port->fd, &except_set);
  198. FD_SET(infd, &except_set);
  199. FD_SET(outfd, &except_set);
  200. if(FD_ISSET(infd, &read_set)) {
  201. bytes = sizeof(port->out_buf.data) - port->out_buf.size;
  202. if(bytes>0) {
  203. n = read(infd, buf, bytes);
  204. ringbuf_append(&port->out_buf, buf, n);
  205. } else
  206. FD_CLR(infd, &read_set);
  207. FD_SET(port->fd, &write_set);
  208. }
  209. if(FD_ISSET(port->fd, &read_set)) {
  210. bytes = sizeof(port->in_buf.data) - port->out_buf.size;
  211. if(bytes>0) {
  212. n = read(infd, buf, bytes);
  213. ringbuf_append(&port->out_buf, buf, n);
  214. } else
  215. FD_CLR(port->fd, &read_set);
  216. FD_SET(outfd, &write_set);
  217. }
  218. }
  219. }
  220. int ringbuf_append(struct ring_buf *buf, const char *data, unsigned int len) {
  221. unsigned int p;
  222. unsigned int i;
  223. if((buf->size + len)>sizeof(buf->data))
  224. return 1;
  225. p = buf->start + buf->size;
  226. for(i=0; i<len; i++) {
  227. if(p>=sizeof(buf->data))
  228. p -= sizeof(buf->data);
  229. buf->data[p] = data[i];
  230. }
  231. buf->size += len;
  232. return 0;
  233. }
  234. int ringbuf_getline(struct ring_buf *buf, char *data, unsigned int len) {
  235. unsigned int datap;
  236. unsigned int p;
  237. unsigned int i;
  238. datap = strlen(data);
  239. p = buf->start;
  240. for(i=0; i<buf->size; i++) {
  241. if(p>=sizeof(buf->data))
  242. p -= sizeof(buf->data);
  243. if(buf->data[p]=='\r' || buf->data[p]=='\n') break;
  244. }
  245. if((len-datap-1)<i) return -1;
  246. len = ringbuf_getdata(buf, &data[datap], i);
  247. data[datap+len] = 0;
  248. if(i<buf->size)
  249. i++;
  250. if(buf->data[p]=='\r') {
  251. if((i+1)<buf->size) {
  252. p++;
  253. if(p>=sizeof(buf->data))
  254. p -= sizeof(buf->data);
  255. if(buf->data[p]=='\n')
  256. i++;
  257. }
  258. }
  259. ringbuf_move(buf, i);
  260. if(buf->data[p]!='\n')
  261. return 0;
  262. return datap+len;
  263. }
  264. int ringbuf_getdata(struct ring_buf *buf, char *data, unsigned int len) {
  265. unsigned int p;
  266. unsigned int i;
  267. if(len>buf->size) len = buf->size;
  268. p = buf->start;
  269. for(i=0; i<len; i++) {
  270. if(p>=sizeof(buf->data))
  271. p -= sizeof(buf->data);
  272. data[i] = buf->data[p];
  273. }
  274. return len;
  275. }
  276. void ringbuf_move(struct ring_buf *buf, unsigned int bytes) {
  277. unsigned int p;
  278. if(buf->size<bytes) {
  279. buf->start = 0;
  280. buf->size = 0;
  281. } else {
  282. p = buf->start + bytes;
  283. if(p>=sizeof(buf->data))
  284. p -= sizeof(buf->data);
  285. buf->start = p;
  286. }
  287. }
  288. void ringbuf_reset(struct ring_buf *buf) {
  289. buf->start = 0;
  290. buf->size = 0;
  291. }