123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <unistd.h>
- #include <termios.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/time.h>
- #include <sys/select.h>
- #include <serial.h>
- #include <sprog.h>
- int serial_setbaud_termios(struct termios *t, int baud);
- int serial_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
- int ringbuf_append(struct ring_buf *buf, const char *data, unsigned int len);
- int ringbuf_getline(struct ring_buf *buf, char *data, unsigned int len);
- int ringbuf_getdata(struct ring_buf *buf, char *data, unsigned int len);
- void ringbuf_move(struct ring_buf *buf, unsigned int bytes);
- void ringbuf_reset(struct ring_buf *buf);
- /* supported baud codes to use with cfsetispeed, cfsetospeed - keep sorted! */
- const struct baud_code baud_codes[] = {
- {50, B50},
- {75, B75},
- {110, B110},
- {134, B134},
- {150, B150},
- {200, B200},
- {300, B300},
- {600, B600},
- {1200, B1200},
- {1800, B1800},
- {2400, B2400},
- {4800, B4800},
- {9600, B9600},
- {19200, B19200},
- {38400, B38400},
- {57600, B57600},
- {115200, B115200},
- {230400, B230400},
- {-1, 0}
- };
- int serial_open(struct serial_device *port, const char *path, int baud) {
- struct termios attr;
- int fd;
- fd = open(path, O_RDWR);
- if(fd<0) {
- sprog_error("Unable to open serial port %s: %s\n", path, strerror(errno));
- exit(1);
- }
-
- tcgetattr(fd, &attr);
- /* 8 data bits, 1 stop bit, no parity */
- attr.c_iflag = IGNBRK;
- attr.c_oflag &= ~(OPOST | OLCUC | ONOCR | ONLRET | ONLCR);
- attr.c_cflag = CS8 | CREAD | CLOCAL;
- attr.c_lflag = ICANON;
- serial_setbaud_termios(&attr, baud);
- tcsetattr(fd, TCSANOW, &attr);
- port->fd = fd;
- return fd;
- }
- void serial_close(struct serial_device *port) {
- close(port->fd);
- }
- int serial_setbaud(struct serial_device *port, int baud) {
- struct termios attr;
- tcgetattr(port->fd, &attr);
- baud = serial_setbaud_termios(&attr, baud);
- tcsetattr(port->fd, TCSANOW, &attr);
- return baud;
- }
- int serial_setbaud_termios(struct termios *t, int baud) {
- int i;
- int baudcode;
-
- /* find the corresponding baud code */
-
- for(i=0; baud_codes[i].baud>0; i++) {
- if(baud_codes[i].baud == baud)
- break;
- if(baud_codes[i].baud > baud) {
- if(i>0) i--;
- break;
- }
- }
-
- /* if the selected baud rate is greater than any of available rates, set the highest one */
- if(baud_codes[i].baud<=0) i--;
-
- if(baud_codes[i].baud != baud)
- sprog_error("Unsupported baud rate %d, using the nearest value %d\n", baud, baud_codes[i].baud);
-
- baudcode = baud_codes[i].code;
- cfsetispeed(t, baudcode);
- cfsetospeed(t, baudcode);
- return baud_codes[i].baud;
- }
- void serial_setline(struct serial_device *port, int line, int state) {
- int bits;
- int mask;
- if(line==SERIAL_DTR)
- mask = TIOCM_DTR;
- else
- mask = TIOCM_RTS;
-
- ioctl(port->fd, TIOCMGET, &bits);
- if(state)
- bits |= mask;
- else
- bits &= ~mask;
- ioctl(port->fd, TIOCMSET, &bits);
- }
- void serial_write(struct serial_device *port, const char *text) {
- int i;
- int b;
- int bytes;
- bytes = strlen(text);
- i = 0;
-
- while(bytes-i>0) {
- b = write(port->fd, &text[i], bytes-i);
- if(b<0) {
- sprog_error("Error while writing to the serial port: %s\n", strerror(errno));
- break;
- }
- i += b;
- }
- }
- int serial_read(struct serial_device *port, char *buf, int len, int timeout) {
- int bytes;
- fd_set readset;
- struct timeval tval;
- FD_ZERO(&readset);
- FD_SET(port->fd, &readset);
-
- tval.tv_sec = timeout/1000;
- tval.tv_usec = (timeout % 1000) * 1000;
-
- bytes = 0;
- while((serial_select(port->fd+1, &readset, NULL, NULL, &tval)>0) && (len-bytes)>0) {
- if(FD_ISSET(port->fd, &readset))
- bytes += read(port->fd, &buf[bytes], len-bytes);
- }
- return bytes;
- }
- int serial_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) {
- int res;
-
- /* Linux automatically subtracts the time elapsed on awaiting
- * for an event when calling select(), The following code unifices
- * the behaviour under different implementations of UNIX.
- */
- #ifndef __linux__
- struct timeval start_time
- struct timeval cur_time;
- long int remaining;
-
- gettimeofday(&start_time, NULL);
- res = pselect(nfds, readfds, writefds, exceptfds, timeout, NULL)
- gettimeofday(&cur_time, NULL);
- remaining = (timeout->tv_sec - (cur_time.tv_sec - start_time.tv_sec))*1000000 + timeout->tv_usec - (cur_time.tv_usec - start_time.tv_usec);
- if(remaining<0) remaining = 0;
-
- timeout.tv_sec = remaining/1000000;
- timeout.tv_usec = remmaining%1000000;
- #else
- res = select(nfds, readfds, writefds, exceptfds, timeout);
- #endif
-
- return res;
- }
- void serial_communicate(struct serial_device *port, int infd, int outfd) {
- char buf[4096];
- int n;
- int bytes;
- int nfds;
- fd_set read_set;
- fd_set write_set;
- fd_set except_set;
-
- ringbuf_reset(&port->in_buf);
- ringbuf_reset(&port->out_buf);
-
- FD_ZERO(&read_set);
- FD_ZERO(&write_set);
- FD_ZERO(&except_set);
- FD_SET(port->fd, &read_set);
- FD_SET(infd, &read_set);;
- FD_SET(port->fd, &except_set);
- FD_SET(infd, &except_set);
- FD_SET(outfd, &except_set);
-
- nfds = port->fd;
- if(infd>nfds)
- nfds = infd;
- if(outfd>nfds)
- nfds = outfd;
- nfds++;
-
- while(select(nfds, &read_set, &write_set, &except_set, NULL)>0) {
- if(FD_ISSET(outfd, &write_set)) {
- n = ringbuf_getdata(&port->in_buf, buf, sizeof(buf));
- n = write(outfd, buf, n);
- ringbuf_move(&port->in_buf, n);
- }
-
- if(FD_ISSET(port->fd, &write_set)) {
- n = ringbuf_getdata(&port->out_buf, buf, sizeof(buf));
- n = write(port->fd, buf, n);
- ringbuf_move(&port->out_buf, n);
- }
-
- FD_ZERO(&read_set);
- FD_ZERO(&write_set);
- FD_ZERO(&except_set);
- FD_SET(port->fd, &read_set);
- FD_SET(infd, &read_set);
- FD_SET(port->fd, &except_set);
- FD_SET(infd, &except_set);
- FD_SET(outfd, &except_set);
-
- if(FD_ISSET(infd, &read_set)) {
- bytes = sizeof(port->out_buf.data) - port->out_buf.size;
- if(bytes>0) {
- n = read(infd, buf, bytes);
- ringbuf_append(&port->out_buf, buf, n);
- } else
- FD_CLR(infd, &read_set);
- FD_SET(port->fd, &write_set);
- }
-
- if(FD_ISSET(port->fd, &read_set)) {
- bytes = sizeof(port->in_buf.data) - port->out_buf.size;
- if(bytes>0) {
- n = read(infd, buf, bytes);
- ringbuf_append(&port->out_buf, buf, n);
- } else
- FD_CLR(port->fd, &read_set);
- FD_SET(outfd, &write_set);
- }
-
- }
- }
- int ringbuf_append(struct ring_buf *buf, const char *data, unsigned int len) {
- unsigned int p;
- unsigned int i;
-
- if((buf->size + len)>sizeof(buf->data))
- return 1;
-
- p = buf->start + buf->size;
-
- for(i=0; i<len; i++) {
- if(p>=sizeof(buf->data))
- p -= sizeof(buf->data);
- buf->data[p] = data[i];
- }
- buf->size += len;
- return 0;
- }
- int ringbuf_getline(struct ring_buf *buf, char *data, unsigned int len) {
- unsigned int datap;
- unsigned int p;
- unsigned int i;
- datap = strlen(data);
-
- p = buf->start;
- for(i=0; i<buf->size; i++) {
- if(p>=sizeof(buf->data))
- p -= sizeof(buf->data);
- if(buf->data[p]=='\r' || buf->data[p]=='\n') break;
- }
-
- if((len-datap-1)<i) return -1;
- len = ringbuf_getdata(buf, &data[datap], i);
- data[datap+len] = 0;
-
- if(i<buf->size)
- i++;
- if(buf->data[p]=='\r') {
- if((i+1)<buf->size) {
- p++;
- if(p>=sizeof(buf->data))
- p -= sizeof(buf->data);
- if(buf->data[p]=='\n')
- i++;
- }
- }
- ringbuf_move(buf, i);
- if(buf->data[p]!='\n')
- return 0;
-
- return datap+len;
- }
- int ringbuf_getdata(struct ring_buf *buf, char *data, unsigned int len) {
- unsigned int p;
- unsigned int i;
-
- if(len>buf->size) len = buf->size;
- p = buf->start;
- for(i=0; i<len; i++) {
- if(p>=sizeof(buf->data))
- p -= sizeof(buf->data);
- data[i] = buf->data[p];
- }
- return len;
- }
- void ringbuf_move(struct ring_buf *buf, unsigned int bytes) {
- unsigned int p;
-
- if(buf->size<bytes) {
- buf->start = 0;
- buf->size = 0;
- } else {
- p = buf->start + bytes;
- if(p>=sizeof(buf->data))
- p -= sizeof(buf->data);
- buf->start = p;
- }
- }
- void ringbuf_reset(struct ring_buf *buf) {
- buf->start = 0;
- buf->size = 0;
- }
|