diff --git a/docs/serial.md b/docs/serial.md index ba5b394..1b5bc0b 100644 --- a/docs/serial.md +++ b/docs/serial.md @@ -96,6 +96,8 @@ Read up to `len` number of bytes from the serial port into the `buf` buffer with For a non-blocking or timeout-bound read, `serial_read()` may return less than the requested number of bytes. +For a blocking read with the VMIN setting configured, `serial_read()` will block until at least VMIN bytes are read. For a blocking read with both VMIN and VTIME settings configured, `serial_read()` will block until at least VMIN bytes are read or the VTIME interbyte timeout expires after the last byte read. In either case, `serial_read()` may return less than the requested number of bytes. + `serial` should be a valid pointer to a Serial handle opened with `serial_open()` or `serial_open_advanced()`. `timeout_ms` can be positive for a blocking read with a timeout in milliseconds, zero for a non-blocking read, or negative for a blocking read. Returns the number of bytes read on success, 0 on timeout, or a negative [Serial error code](#return-value) on failure. diff --git a/src/serial.c b/src/serial.c index d4b0f90..0e317f6 100644 --- a/src/serial.c +++ b/src/serial.c @@ -25,6 +25,7 @@ struct serial_handle { int fd; + bool use_termios_timeout; struct { int c_errno; @@ -234,6 +235,8 @@ int serial_open_advanced(serial_t *serial, const char *path, uint32_t baudrate, return _serial_error(serial, SERIAL_ERROR_CONFIGURE, errsv, "Setting serial port attributes"); } + serial->use_termios_timeout = false; + return 0; } @@ -261,6 +264,10 @@ int serial_read(serial_t *serial, uint8_t *buf, size_t len, int timeout_ms) { if ((ret = read(serial->fd, buf + bytes_read, len - bytes_read)) < 0) return _serial_error(serial, SERIAL_ERROR_IO, errno, "Reading serial port"); + /* If we're using VMIN or VMIN+VTIME semantics for end of read, return now */ + if (serial->use_termios_timeout) + return ret; + /* Empty read */ if (ret == 0 && len != 0) return _serial_error(serial, SERIAL_ERROR_IO, 0, "Reading serial port: unexpected empty read"); @@ -576,6 +583,8 @@ int serial_set_vmin(serial_t *serial, unsigned int vmin) { if (tcsetattr(serial->fd, TCSANOW, &termios_settings) < 0) return _serial_error(serial, SERIAL_ERROR_CONFIGURE, errno, "Setting serial port attributes"); + serial->use_termios_timeout = vmin > 0; + return 0; }