X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fserial.c;h=192b18a7245a4caffa17eb3a23ab3801bd16c33e;hb=f3ba3c119c3918dfa9cbde74afe21bd4c5609b44;hp=4fe9b88fc0805e43b7716a4cdd1ace37501620a4;hpb=98edee7926b9827eec743bbfbfde9025089dc502;p=libsigrok.git diff --git a/src/serial.c b/src/serial.c index 4fe9b88f..192b18a7 100644 --- a/src/serial.c +++ b/src/serial.c @@ -4,6 +4,7 @@ * Copyright (C) 2010-2012 Bert Vermeulen * Copyright (C) 2010-2012 Uwe Hermann * Copyright (C) 2012 Alexandru Gagniuc + * Copyright (C) 2014 Uffe Jakobsen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -169,8 +170,46 @@ SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial) return SR_OK; } +/** + * Drain serial port buffers. + * + * @param serial Previously initialized serial port structure. + * + * @retval SR_OK Success. + * @retval SR_ERR Failure. + */ +SR_PRIV int serial_drain(struct sr_serial_dev_inst *serial) +{ + int ret; + char *error; + + if (!serial) { + sr_dbg("Invalid serial port."); + return SR_ERR; + } + + if (!serial->data) { + sr_dbg("Cannot drain unopened serial port %s.", serial->port); + return SR_ERR; + } + + sr_spew("Draining serial port %s.", serial->port); + + ret = sp_drain(serial->data); + + if (ret == SP_ERR_FAIL) { + error = sp_last_error_message(); + sr_err("Error draining port (%d): %s.", + sp_last_error_code(), error); + sp_free_error_message(error); + return SR_ERR; + } + + return SR_OK; +} + static int _serial_write(struct sr_serial_dev_inst *serial, - const void *buf, size_t count, int nonblocking) + const void *buf, size_t count, int nonblocking, unsigned int timeout_ms) { ssize_t ret; char *error; @@ -188,7 +227,7 @@ static int _serial_write(struct sr_serial_dev_inst *serial, if (nonblocking) ret = sp_nonblocking_write(serial->data, buf, count); else - ret = sp_blocking_write(serial->data, buf, count, 0); + ret = sp_blocking_write(serial->data, buf, count, timeout_ms); switch (ret) { case SP_ERR_ARG: @@ -212,15 +251,17 @@ static int _serial_write(struct sr_serial_dev_inst *serial, * @param serial Previously initialized serial port structure. * @param[in] buf Buffer containing the bytes to write. * @param[in] count Number of bytes to write. + * @param[in] timeout_ms Timeout in ms, or 0 for no timeout. * * @retval SR_ERR_ARG Invalid argument. * @retval SR_ERR Other error. - * @retval other The number of bytes written. + * @retval other The number of bytes written. If this is less than the number + * specified in the call, the timeout was reached. */ SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial, - const void *buf, size_t count) + const void *buf, size_t count, unsigned int timeout_ms) { - return _serial_write(serial, buf, count, 0); + return _serial_write(serial, buf, count, 0, timeout_ms); } /** @@ -237,11 +278,11 @@ SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial, SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial, const void *buf, size_t count) { - return _serial_write(serial, buf, count, 1); + return _serial_write(serial, buf, count, 1, 0); } static int _serial_read(struct sr_serial_dev_inst *serial, void *buf, - size_t count, int nonblocking) + size_t count, int nonblocking, unsigned int timeout_ms) { ssize_t ret; char *error; @@ -259,7 +300,7 @@ static int _serial_read(struct sr_serial_dev_inst *serial, void *buf, if (nonblocking) ret = sp_nonblocking_read(serial->data, buf, count); else - ret = sp_blocking_read(serial->data, buf, count, 0); + ret = sp_blocking_read(serial->data, buf, count, timeout_ms); switch (ret) { case SP_ERR_ARG: @@ -284,15 +325,17 @@ static int _serial_read(struct sr_serial_dev_inst *serial, void *buf, * @param serial Previously initialized serial port structure. * @param buf Buffer where to store the bytes that are read. * @param[in] count The number of bytes to read. + * @param[in] timeout_ms Timeout in ms, or 0 for no timeout. * * @retval SR_ERR_ARG Invalid argument. * @retval SR_ERR Other error. - * @retval other The number of bytes read. + * @retval other The number of bytes read. If this is less than the number + * requested, the timeout was reached. */ SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf, - size_t count) + size_t count, unsigned int timeout_ms) { - return _serial_read(serial, buf, count, 0); + return _serial_read(serial, buf, count, 0, timeout_ms); } /** @@ -310,7 +353,7 @@ SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf, SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf, size_t count) { - return _serial_read(serial, buf, count, 1); + return _serial_read(serial, buf, count, 1, 0); } /** @@ -794,3 +837,43 @@ SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id) sp_free_port_list(ports); return tty_devs; } + +SR_PRIV int serial_timeout(struct sr_serial_dev_inst *port, int num_bytes) +{ + struct sp_port_config *config; + int timeout_ms, bits, baud, tmp; + + /* Default to 1s. */ + timeout_ms = 1000; + + if (sp_new_config(&config) < 0) + return timeout_ms; + + bits = baud = 0; + do { + if (sp_get_config(port->data, config) < 0) + break; + + /* Start bit. */ + bits = 1; + if (sp_get_config_bits(config, &tmp) < 0) + break; + bits += tmp; + if (sp_get_config_stopbits(config, &tmp) < 0) + break; + bits += tmp; + if (sp_get_config_baudrate(config, &tmp) < 0) + break; + baud = tmp; + } while (FALSE); + + if (bits && baud) { + /* Throw in 10ms for misc OS overhead. */ + timeout_ms = 10; + timeout_ms += ((1000.0 / baud) * bits) * num_bytes; + } + + sp_free_config(config); + + return timeout_ms; +}