serial.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <stdarg.h>
  4. #include <errno.h>
  5. #include <unistd.h>
  6. #include <termios.h>
  7. #include <fcntl.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/time.h>
  10. #include <sys/select.h>
  11. #include <serial.h>
  12. #include <sprog.h>
  13. int serial_setbaud_termios(struct termios *t, int baud);
  14. int serial_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  15. /* supported baud codes to use with cfsetispeed, cfsetospeed - keep sorted! */
  16. const struct baud_code baud_codes[] = {
  17. {50, B50},
  18. {75, B75},
  19. {110, B110},
  20. {134, B134},
  21. {150, B150},
  22. {200, B200},
  23. {300, B300},
  24. {600, B600},
  25. {1200, B1200},
  26. {1800, B1800},
  27. {2400, B2400},
  28. {4800, B4800},
  29. {9600, B9600},
  30. {19200, B19200},
  31. {38400, B38400},
  32. {57600, B57600},
  33. {115200, B115200},
  34. {230400, B230400},
  35. {-1, 0}
  36. };
  37. int serial_open(struct serial_device *port, const char *path, int baud) {
  38. struct termios attr;
  39. int fd;
  40. fd = open(path, O_RDWR);
  41. if(fd<0) {
  42. sprog_error("Unable to open serial port %s: %s\n", path, strerror(errno));
  43. exit(1);
  44. }
  45. tcgetattr(fd, &attr);
  46. /* 8 data bits, 1 stop bit, no parity */
  47. attr.c_iflag = IGNBRK;
  48. attr.c_oflag &= ~(OPOST | OLCUC | ONOCR | ONLRET | ONLCR);
  49. attr.c_cflag = CS8 | CREAD | CLOCAL;
  50. attr.c_lflag = ICANON;
  51. serial_setbaud_termios(&attr, baud);
  52. tcsetattr(fd, TCSANOW, &attr);
  53. port->fd = fd;
  54. port->f = fdopen(fd, "r+");
  55. return fd;
  56. }
  57. void serial_close(struct serial_device *port) {
  58. close(port->fd);
  59. }
  60. int serial_setbaud(struct serial_device *port, int baud) {
  61. struct termios attr;
  62. tcgetattr(port->fd, &attr);
  63. baud = serial_setbaud_termios(&attr, baud);
  64. tcsetattr(port->fd, TCSANOW, &attr);
  65. return baud;
  66. }
  67. int serial_setbaud_termios(struct termios *t, int baud) {
  68. int i;
  69. int baudcode;
  70. /* find the corresponding baud code */
  71. for(i=0; baud_codes[i].baud>0; i++) {
  72. if(baud_codes[i].baud == baud)
  73. break;
  74. if(baud_codes[i].baud > baud) {
  75. if(i>0) i--;
  76. break;
  77. }
  78. }
  79. /* if the selected baud rate is greater than any of available rates, set the highest one */
  80. if(baud_codes[i].baud<=0) i--;
  81. if(baud_codes[i].baud != baud)
  82. sprog_error("Unsupported baud rate %d, using the nearest value %d\n", baud, baud_codes[i].baud);
  83. baudcode = baud_codes[i].code;
  84. cfsetispeed(t, baudcode);
  85. cfsetospeed(t, baudcode);
  86. return baud_codes[i].baud;
  87. }
  88. void serial_setline(struct serial_device *port, int line, int state) {
  89. int bits;
  90. int mask;
  91. if(line==SERIAL_DTR)
  92. mask = TIOCM_DTR;
  93. else
  94. mask = TIOCM_RTS;
  95. ioctl(port->fd, TIOCMGET, &bits);
  96. if(state)
  97. bits |= mask;
  98. else
  99. bits &= ~mask;
  100. ioctl(port->fd, TIOCMSET, &bits);
  101. }
  102. void serial_write(struct serial_device *port, const char *text) {
  103. int i;
  104. int b;
  105. int bytes;
  106. bytes = strlen(text);
  107. i = 0;
  108. // sprog_info("<-- %s\n", text);
  109. while(bytes-i>0) {
  110. b = write(port->fd, &text[i], bytes-i);
  111. if(b<0) {
  112. sprog_error("Error while writing to the serial port: %s\n", strerror(errno));
  113. break;
  114. }
  115. i += b;
  116. }
  117. }
  118. int serial_read(struct serial_device *port, char *buf, int len, int timeout) {
  119. int bytes;
  120. fd_set readset;
  121. struct timeval tval;
  122. FD_ZERO(&readset);
  123. FD_SET(port->fd, &readset);
  124. tval.tv_sec = timeout/1000;
  125. tval.tv_usec = (timeout % 1000) * 1000;
  126. bytes = 0;
  127. while((serial_select(port->fd+1, &readset, NULL, NULL, &tval)>0) && (len-bytes)>0) {
  128. if(FD_ISSET(port->fd, &readset))
  129. bytes += read(port->fd, &buf[bytes], len-bytes);
  130. }
  131. // buf[bytes]=0; sprog_info("--> %s\n", buf);
  132. return bytes;
  133. }
  134. int serial_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
  135. int res;
  136. /* Linux automatically subtracts the time elapsed on awaiting
  137. * for an event when calling select(), The following code unifices
  138. * the behaviour under different implementations of UNIX.
  139. */
  140. #ifndef __linux__
  141. struct timeval start_time
  142. struct timeval cur_time;
  143. long int remaining;
  144. gettimeofday(&start_time, NULL);
  145. res = pselect(nfds, readfds, writefds, exceptfds, timeout, NULL)
  146. gettimeofday(&cur_time, NULL);
  147. remaining = (timeout->tv_sec - (cur_time.tv_sec - start_time.tv_sec))*1000000 + timeout->tv_usec - (cur_time.tv_usec - start_time.tv_usec);
  148. if(remaining<0) remaining = 0;
  149. timeout.tv_sec = remaining/1000000;
  150. timeout.tv_usec = remmaining%1000000;
  151. #else
  152. res = select(nfds, readfds, writefds, exceptfds, timeout);
  153. #endif
  154. return res;
  155. }