X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=serialport.c;h=0276567a4008008064e871ac24e7e63d8dd5e9fa;hb=6c8716e9dabb5aece68eec87bbf4e322ff92e6a2;hp=e2cf48abd33df6785a6930c39b5f4742f7cce2fa;hpb=e3dcf9068e8b0e5d6b21a0203bfa963a8e0711d2;p=libserialport.git diff --git a/serialport.c b/serialport.c index e2cf48a..0276567 100644 --- a/serialport.c +++ b/serialport.c @@ -50,11 +50,21 @@ #include "libudev.h" #include "linux/serial.h" #include "linux_termios.h" + +/* TCGETX/TCSETX is not available everywhere. */ #if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX) #define USE_TERMIOX #endif #endif +/* TIOCINQ/TIOCOUTQ is not available everywhere. */ +#if !defined(TIOCINQ) && defined(FIONREAD) +#define TIOCINQ FIONREAD +#endif +#if !defined(TIOCOUTQ) && defined(FIONWRITE) +#define TIOCOUTQ FIONWRITE +#endif + #ifndef _WIN32 #include "linux_termios.h" #endif @@ -799,13 +809,23 @@ enum sp_return sp_drain(struct sp_port *port) /* Returns non-zero upon success, 0 upon failure. */ if (FlushFileBuffers(port->hdl) == 0) RETURN_FAIL("FlushFileBuffers() failed"); + RETURN_OK(); #else - /* Returns 0 upon success, -1 upon failure. */ - if (tcdrain(port->fd) < 0) - RETURN_FAIL("tcdrain() failed"); + int result; + while (1) { + result = tcdrain(port->fd); + if (result < 0) { + if (errno == EINTR) { + DEBUG("tcdrain() was interrupted"); + continue; + } else { + RETURN_FAIL("tcdrain() failed"); + } + } else { + RETURN_OK(); + } + } #endif - - RETURN_OK(); } enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout) @@ -870,7 +890,7 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c gettimeofday(&start, NULL); /* Define duration of timeout. */ delta.tv_sec = timeout / 1000; - delta.tv_usec = timeout % 1000; + delta.tv_usec = (timeout % 1000) * 1000; /* Calculate time at which we should give up. */ timeradd(&start, &delta, &end); } @@ -890,9 +910,14 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c timersub(&end, &now, &delta); } result = select(port->fd + 1, NULL, &fds, NULL, timeout ? &delta : NULL); - if (result < 0) - RETURN_FAIL("select() failed"); - if (result == 0) { + if (result < 0) { + if (errno == EINTR) { + DEBUG("select() call was interrupted, repeating"); + continue; + } else { + RETURN_FAIL("select() failed"); + } + } else if (result == 0) { DEBUG("write timed out"); RETURN_VALUE("%d", bytes_written); } @@ -1041,7 +1066,7 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u gettimeofday(&start, NULL); /* Define duration of timeout. */ delta.tv_sec = timeout / 1000; - delta.tv_usec = timeout % 1000; + delta.tv_usec = (timeout % 1000) * 1000; /* Calculate time at which we should give up. */ timeradd(&start, &delta, &end); } @@ -1060,9 +1085,14 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u timersub(&end, &now, &delta); } result = select(port->fd + 1, &fds, NULL, NULL, timeout ? &delta : NULL); - if (result < 0) - RETURN_FAIL("select() failed"); - if (result == 0) { + if (result < 0) { + if (errno == EINTR) { + DEBUG("select() call was interrupted, repeating"); + continue; + } else { + RETURN_FAIL("select() failed"); + } + } else if (result == 0) { DEBUG("read timed out"); RETURN_VALUE("%d", bytes_read); } @@ -1131,6 +1161,52 @@ enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count #endif } +enum sp_return sp_input_waiting(struct sp_port *port) +{ + TRACE("%p", port); + + CHECK_OPEN_PORT(); + + DEBUG("Checking input bytes waiting on port %s", port->name); + +#ifdef _WIN32 + DWORD errors; + COMSTAT comstat; + + if (ClearCommError(port->hdl, &errors, &comstat) == 0) + RETURN_FAIL("ClearComError() failed"); + RETURN_VALUE("%d", comstat.cbInQue); +#else + int bytes_waiting; + if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0) + RETURN_FAIL("TIOCINQ ioctl failed"); + RETURN_VALUE("%d", bytes_waiting); +#endif +} + +enum sp_return sp_output_waiting(struct sp_port *port) +{ + TRACE("%p", port); + + CHECK_OPEN_PORT(); + + DEBUG("Checking output bytes waiting on port %s", port->name); + +#ifdef _WIN32 + DWORD errors; + COMSTAT comstat; + + if (ClearCommError(port->hdl, &errors, &comstat) == 0) + RETURN_FAIL("ClearComError() failed"); + RETURN_VALUE("%d", comstat.cbOutQue); +#else + int bytes_waiting; + if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0) + RETURN_FAIL("TIOCOUTQ ioctl failed"); + RETURN_VALUE("%d", bytes_waiting); +#endif +} + #ifdef __linux__ static enum sp_return get_baudrate(int fd, int *baudrate) {