X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=hardware%2Fcommon%2Fserial.c;h=9a9a0d94fd3b3058e84ba74202db681de8397885;hp=7cc81c64213e95b67f5949dc6998b5abdf1a4721;hb=43cd4637285833706f8a404ca027bcf0ee75b9ae;hpb=3182932d360303df459abce20dbe093ce9c453e8 diff --git a/hardware/common/serial.c b/hardware/common/serial.c index 7cc81c64..9a9a0d94 100644 --- a/hardware/common/serial.c +++ b/hardware/common/serial.c @@ -22,30 +22,25 @@ #include #include #include +#include #include #include "libsigrok.h" #include "libsigrok-internal.h" -/* Message logging helpers with subsystem-specific prefix string. */ -#define LOG_PREFIX "serial: " -#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args) -#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args) -#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args) -#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args) -#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) -#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) +#define LOG_PREFIX "serial" /** * Open the specified serial port. * * @param serial Previously initialized serial port structure. - * @param flags Flags to use when opening the serial port. Possible flags + * @param[in] flags Flags to use when opening the serial port. Possible flags * include SERIAL_RDWR, SERIAL_RDONLY, SERIAL_NONBLOCK. * * If the serial structure contains a serialcomm string, it will be * passed to serial_set_paramstr() after the port is opened. * - * @return SR_OK on success, SR_ERR on failure. + * @retval SR_OK Success. + * @retval SR_ERR Failure. */ SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags) { @@ -66,8 +61,8 @@ SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags) sp_flags = (SP_MODE_READ | SP_MODE_WRITE); else if (flags & SERIAL_RDONLY) sp_flags = SP_MODE_READ; - if (flags & SERIAL_NONBLOCK) - sp_flags |= SP_MODE_NONBLOCK; + + serial->nonblocking = (flags & SERIAL_NONBLOCK) ? 1 : 0; ret = sp_open(serial->data, sp_flags); @@ -77,15 +72,12 @@ SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags) return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); - sr_err("Error opening port: %s.", error); + sr_err("Error opening port (%d): %s.", + sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } -#ifndef _WIN32 - sp_get_port_handle(serial->data, &serial->fd); -#endif - if (serial->serialcomm) return serial_set_paramstr(serial, serial->serialcomm); else @@ -97,7 +89,8 @@ SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags) * * @param serial Previously initialized serial port structure. * - * @return SR_OK on success, SR_ERR on failure. + * @retval SR_OK Success. + * @retval SR_ERR Failure. */ SR_PRIV int serial_close(struct sr_serial_dev_inst *serial) { @@ -109,16 +102,14 @@ SR_PRIV int serial_close(struct sr_serial_dev_inst *serial) return SR_ERR; } - if (serial->fd == -1) { - sr_dbg("Cannot close unopened serial port %s (fd %d).", - serial->port, serial->fd); + if (!serial->data) { + sr_dbg("Cannot close unopened serial port %s.", serial->port); return SR_ERR; } - sr_spew("Closing serial port %s (fd %d).", serial->port, serial->fd); + sr_spew("Closing serial port %s.", serial->port); ret = sp_close(serial->data); - sp_free_port(serial->data); switch (ret) { case SP_ERR_ARG: @@ -126,12 +117,14 @@ SR_PRIV int serial_close(struct sr_serial_dev_inst *serial) return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); - sr_err("Error closing port: %s.", error); + sr_err("Error closing port (%d): %s.", + sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } - serial->fd = -1; + sp_free_port(serial->data); + serial->data = NULL; return SR_OK; } @@ -141,7 +134,8 @@ SR_PRIV int serial_close(struct sr_serial_dev_inst *serial) * * @param serial Previously initialized serial port structure. * - * @return SR_OK on success, SR_ERR on failure. + * @retval SR_OK Success. + * @retval SR_ERR Failure. */ SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial) { @@ -153,13 +147,12 @@ SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial) return SR_ERR; } - if (serial->fd == -1) { - sr_dbg("Cannot flush unopened serial port %s (fd %d).", - serial->port, serial->fd); + if (!serial->data) { + sr_dbg("Cannot flush unopened serial port %s.", serial->port); return SR_ERR; } - sr_spew("Flushing serial port %s (fd %d).", serial->port, serial->fd); + sr_spew("Flushing serial port %s.", serial->port); ret = sp_flush(serial->data, SP_BUF_BOTH); @@ -169,7 +162,8 @@ SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial) return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); - sr_err("Error flushing port: %s.", error); + sr_err("Error flushing port (%d): %s.", + sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } @@ -177,17 +171,8 @@ SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial) return SR_OK; } -/** - * Write a number of bytes to the specified serial port. - * - * @param serial Previously initialized serial port structure. - * @param buf Buffer containing the bytes to write. - * @param count Number of bytes to write. - * - * @return The number of bytes written, or a negative error code upon failure. - */ -SR_PRIV int serial_write(struct sr_serial_dev_inst *serial, - const void *buf, size_t count) +static int _serial_write(struct sr_serial_dev_inst *serial, + const void *buf, size_t count, int nonblocking) { ssize_t ret; char *error; @@ -197,13 +182,15 @@ SR_PRIV int serial_write(struct sr_serial_dev_inst *serial, return SR_ERR; } - if (serial->fd == -1) { - sr_dbg("Cannot use unopened serial port %s (fd %d).", - serial->port, serial->fd); + if (!serial->data) { + sr_dbg("Cannot use unopened serial port %s.", serial->port); return SR_ERR; } - ret = sp_write(serial->data, buf, count); + if (nonblocking) + ret = sp_nonblocking_write(serial->data, buf, count); + else + ret = sp_blocking_write(serial->data, buf, count, 0); switch (ret) { case SP_ERR_ARG: @@ -211,74 +198,144 @@ SR_PRIV int serial_write(struct sr_serial_dev_inst *serial, return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); - sr_err("Write error: %s.", error); + sr_err("Write error (%d): %s.", sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } - sr_spew("Wrote %d/%d bytes (fd %d).", ret, count, serial->fd); + sr_spew("Wrote %d/%d bytes.", ret, count); return ret; } /** - * Read a number of bytes from the specified serial port. + * Write a number of bytes to the specified serial port. * * @param serial Previously initialized serial port structure. - * @param buf Buffer where to store the bytes that are read. - * @param count The number of bytes to read. + * @param[in] buf Buffer containing the bytes to write. + * @param[in] count Number of bytes to write. * - * @return The number of bytes read, or a negative error code upon failure. + * @retval SR_ERR_ARG Invalid argument. + * @retval SR_ERR Other error. + * @retval other The number of bytes written. */ -SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf, - size_t count) +SR_PRIV int serial_write(struct sr_serial_dev_inst *serial, + const void *buf, size_t count) +{ + return _serial_write(serial, buf, count, serial->nonblocking); +} + +/** + * Write a number of bytes to the specified serial port, blocking until finished. + * @copydetails serial_write() + */ +SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial, + const void *buf, size_t count) +{ + return _serial_write(serial, buf, count, 0); +} + +/** + * Write a number of bytes to the specified serial port, return immediately. + * @copydetails serial_write() +*/ +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); +} + +static int _serial_read(struct sr_serial_dev_inst *serial, void *buf, + size_t count, int nonblocking) { ssize_t ret; - //char *error; + char *error; if (!serial) { sr_dbg("Invalid serial port."); return SR_ERR; } - if (serial->fd == -1) { - sr_dbg("Cannot use unopened serial port %s (fd %d).", - serial->port, serial->fd); + if (!serial->data) { + sr_dbg("Cannot use unopened serial port %s.", serial->port); return SR_ERR; } - ret = sp_read(serial->data, buf, count); + if (nonblocking) + ret = sp_nonblocking_read(serial->data, buf, count); + else + ret = sp_blocking_read(serial->data, buf, count, 0); switch (ret) { case SP_ERR_ARG: sr_err("Attempted serial port read with invalid arguments."); return SR_ERR_ARG; - // Temporarily disabled, will come back later. - // case SP_ERR_FAIL: - // error = sp_last_error_message(); - // sr_err("Read error: %s.", error); - // sp_free_error_message(error); - // return SR_ERR; + case SP_ERR_FAIL: + error = sp_last_error_message(); + sr_err("Read error (%d): %s.", sp_last_error_code(), error); + sp_free_error_message(error); + return SR_ERR; } - if (ret >= 0) - sr_spew("Read %d/%d bytes (fd %d).", ret, count, serial->fd); + if (ret > 0) + sr_spew("Read %d/%d bytes.", ret, count); return ret; } +/** + * Read a number of bytes from the specified serial port. + * + * @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. + * + * @retval SR_ERR_ARG Invalid argument. + * @retval SR_ERR Other error. + * @retval other The number of bytes read. + */ +SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf, + size_t count) +{ + return _serial_read(serial, buf, count, serial->nonblocking); +} + +/** + * Read a number of bytes from the specified serial port, block until finished. + * @copydetails serial_read() + */ +SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf, + size_t count) +{ + return _serial_read(serial, buf, count, 0); +} + +/** + * Try to read up to @a count bytes from the specified serial port, return + * immediately with what's available. + * @copydetails serial_read() + */ +SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf, + size_t count) +{ + return _serial_read(serial, buf, count, 1); +} + /** * Set serial parameters for the specified serial port. * * @param serial Previously initialized serial port structure. - * @param baudrate The baudrate to set. - * @param bits The number of data bits to use. - * @param parity The parity setting to use (0 = none, 1 = even, 2 = odd). - * @param stopbits The number of stop bits to use (1 or 2). - * @param flowcontrol The flow control settings to use (0 = none, 1 = RTS/CTS, - * 2 = XON/XOFF). + * @param[in] baudrate The baudrate to set. + * @param[in] bits The number of data bits to use (5, 6, 7 or 8). + * @param[in] parity The parity setting to use (0 = none, 1 = even, 2 = odd). + * @param[in] stopbits The number of stop bits to use (1 or 2). + * @param[in] flowcontrol The flow control settings to use (0 = none, + * 1 = RTS/CTS, 2 = XON/XOFF). + * @param[in] rts Status of RTS line (0 or 1; required by some interfaces). + * @param[in] dtr Status of DTR line (0 or 1; required by some interfaces). * - * @return SR_OK upon success, SR_ERR upon failure. + * @retval SR_OK Success. + * @retval SR_ERR Failure. */ SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate, int bits, int parity, int stopbits, @@ -286,45 +343,45 @@ SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate, { int ret; char *error; - struct sp_port_config config; + struct sp_port_config *config; if (!serial) { sr_dbg("Invalid serial port."); return SR_ERR; } - if (serial->fd == -1) { - sr_dbg("Cannot configure unopened serial port %s (fd %d).", - serial->port, serial->fd); + if (!serial->data) { + sr_dbg("Cannot configure unopened serial port %s.", serial->port); return SR_ERR; } - sr_spew("Setting serial parameters on port %s (fd %d).", serial->port, - serial->fd); + sr_spew("Setting serial parameters on port %s.", serial->port); - config.baudrate = baudrate; - config.bits = bits; + sp_new_config(&config); + sp_set_config_baudrate(config, baudrate); + sp_set_config_bits(config, bits); switch (parity) { case 0: - config.parity = SP_PARITY_NONE; + sp_set_config_parity(config, SP_PARITY_NONE); break; case 1: - config.parity = SP_PARITY_EVEN; + sp_set_config_parity(config, SP_PARITY_EVEN); break; case 2: - config.parity = SP_PARITY_ODD; + sp_set_config_parity(config, SP_PARITY_ODD); break; default: return SR_ERR_ARG; } - config.stopbits = stopbits; - config.rts = flowcontrol == 1 ? SP_RTS_FLOW_CONTROL : rts; - config.cts = flowcontrol == 1 ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE; - config.dtr = dtr; - config.dsr = SP_DSR_IGNORE; - config.xon_xoff = flowcontrol == 2 ? SP_XONXOFF_INOUT : SP_XONXOFF_DISABLED; + sp_set_config_stopbits(config, stopbits); + sp_set_config_rts(config, flowcontrol == 1 ? SP_RTS_FLOW_CONTROL : rts); + sp_set_config_cts(config, flowcontrol == 1 ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE); + sp_set_config_dtr(config, dtr); + sp_set_config_dsr(config, SP_DSR_IGNORE); + sp_set_config_xon_xoff(config, flowcontrol == 2 ? SP_XONXOFF_INOUT : SP_XONXOFF_DISABLED); - ret = sp_set_config(serial->data, &config); + ret = sp_set_config(serial->data, config); + sp_free_config(config); switch (ret) { case SP_ERR_ARG: @@ -332,7 +389,8 @@ SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate, return SR_ERR_ARG; case SP_ERR_FAIL: error = sp_last_error_message(); - sr_err("Error setting serial port parameters: %s.", error); + sr_err("Error setting serial port parameters (%d): %s.", + sp_last_error_code(), error); sp_free_error_message(error); return SR_ERR; } @@ -341,19 +399,30 @@ SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate, } /** - * Set serial parameters for the specified serial port. + * Set serial parameters for the specified serial port from parameter string. * * @param serial Previously initialized serial port structure. - * @param paramstr A serial communication parameters string, in the form - * of /, for example "9600/8n1" or - * "600/7o2" or "460800/8n1/flow=2" where flow is 0 for none, 1 for rts/cts and 2 for xon/xoff. - * - * @return SR_OK upon success, SR_ERR upon failure. + * @param[in] paramstr A serial communication parameters string of the form + * "/{/