X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=hardware%2Fcommon%2Fserial.c;h=af80356a3cc72a714627a272e0a420c1a22e28d0;hb=7faa3e8821735e063e17fcad326c68aae14fe907;hp=53712e82fd4110580ceb1fe1e08a1a99f8cfbed8;hpb=a9bce5a56199e44d4e2ec42d7aab7f57f386d55a;p=libsigrok.git diff --git a/hardware/common/serial.c b/hardware/common/serial.c index 53712e82..af80356a 100644 --- a/hardware/common/serial.c +++ b/hardware/common/serial.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "libsigrok.h" #include "libsigrok-internal.h" @@ -51,6 +51,7 @@ SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags) { int ret; char *error; + int sp_flags = 0; if (!serial) { sr_dbg("Invalid serial port."); @@ -59,22 +60,30 @@ SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags) sr_spew("Opening serial port '%s' (flags %d).", serial->port, flags); - ret = sp_open(&serial->data, serial->port, flags); - - switch (ret) - { - case SP_ERR_ARG: - sr_err("Attempt to open serial port with invalid parameters."); - return SR_ERR_ARG; - case SP_ERR_FAIL: - error = sp_last_error_message(); - sr_err("Error opening port: %s.", error); - sp_free_error_message(error); - return SR_ERR; + sp_get_port_by_name(serial->port, &serial->data); + + if (flags & SERIAL_RDWR) + sp_flags = (SP_MODE_READ | SP_MODE_WRITE); + else if (flags & SERIAL_RDONLY) + sp_flags = SP_MODE_READ; + + serial->nonblocking = (flags & SERIAL_NONBLOCK) ? 1 : 0; + + ret = sp_open(serial->data, sp_flags); + + switch (ret) { + case SP_ERR_ARG: + sr_err("Attempt to open serial port with invalid parameters."); + return SR_ERR_ARG; + case SP_ERR_FAIL: + error = sp_last_error_message(); + sr_err("Error opening port: %s.", error); + sp_free_error_message(error); + return SR_ERR; } #ifndef _WIN32 - serial->fd = serial->data.fd; + sp_get_port_handle(serial->data, &serial->fd); #endif if (serial->serialcomm) @@ -107,25 +116,24 @@ SR_PRIV int serial_close(struct sr_serial_dev_inst *serial) } sr_spew("Closing serial port %s (fd %d).", serial->port, serial->fd); - ret = SR_OK; - - ret = sp_close(&serial->data); - - switch (ret) - { - case SP_ERR_ARG: - sr_err("Attempt to close an invalid serial port."); - return SR_ERR_ARG; - case SP_ERR_FAIL: - error = sp_last_error_message(); - sr_err("Error closing port: %s.", error); - sp_free_error_message(error); - return SR_ERR; + + ret = sp_close(serial->data); + sp_free_port(serial->data); + + switch (ret) { + case SP_ERR_ARG: + sr_err("Attempt to close an invalid serial port."); + return SR_ERR_ARG; + case SP_ERR_FAIL: + error = sp_last_error_message(); + sr_err("Error closing port: %s.", error); + sp_free_error_message(error); + return SR_ERR; } serial->fd = -1; - return ret; + return SR_OK; } /** @@ -153,21 +161,20 @@ SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial) sr_spew("Flushing serial port %s (fd %d).", serial->port, serial->fd); - ret = sp_flush(&serial->data); - - switch (ret) - { - case SP_ERR_ARG: - sr_err("Attempt to flush an invalid serial port."); - return SR_ERR_ARG; - case SP_ERR_FAIL: - error = sp_last_error_message(); - sr_err("Error flushing port: %s.", error); - sp_free_error_message(error); - return SR_ERR; + ret = sp_flush(serial->data, SP_BUF_BOTH); + + switch (ret) { + case SP_ERR_ARG: + sr_err("Attempt to flush an invalid serial port."); + return SR_ERR_ARG; + case SP_ERR_FAIL: + error = sp_last_error_message(); + sr_err("Error flushing port: %s.", error); + sp_free_error_message(error); + return SR_ERR; } - return ret; + return SR_OK; } /** @@ -177,7 +184,7 @@ SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial) * @param buf Buffer containing the bytes to write. * @param count Number of bytes to write. * - * @return The number of bytes written, or -1 upon failure. + * @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) @@ -187,27 +194,29 @@ SR_PRIV int serial_write(struct sr_serial_dev_inst *serial, if (!serial) { sr_dbg("Invalid serial port."); - return -1; + return SR_ERR; } if (serial->fd == -1) { sr_dbg("Cannot use unopened serial port %s (fd %d).", serial->port, serial->fd); - return -1; + return SR_ERR; } - ret = sp_write(&serial->data, buf, count); - - switch (ret) - { - case SP_ERR_ARG: - sr_err("Attempted serial port write with invalid arguments."); - return SR_ERR_ARG; - case SP_ERR_FAIL: - error = sp_last_error_message(); - sr_err("Write error: %s.", error); - sp_free_error_message(error); - return SR_ERR; + if (serial->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: + sr_err("Attempted serial port write with invalid arguments."); + return SR_ERR_ARG; + case SP_ERR_FAIL: + error = sp_last_error_message(); + sr_err("Write error: %s.", error); + sp_free_error_message(error); + return SR_ERR; } sr_spew("Wrote %d/%d bytes (fd %d).", ret, count, serial->fd); @@ -222,7 +231,7 @@ SR_PRIV int serial_write(struct sr_serial_dev_inst *serial, * @param buf Buffer where to store the bytes that are read. * @param count The number of bytes to read. * - * @return The number of bytes read, or -1 upon failure. + * @return The number of bytes read, or a negative error code upon failure. */ SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf, size_t count) @@ -232,30 +241,33 @@ SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf, if (!serial) { sr_dbg("Invalid serial port."); - return -1; + return SR_ERR; } if (serial->fd == -1) { sr_dbg("Cannot use unopened serial port %s (fd %d).", serial->port, serial->fd); - return -1; + return SR_ERR; } - ret = sp_read(&serial->data, buf, count); - - switch (ret) - { - case SP_ERR_ARG: - sr_err("Attempted serial port read with invalid arguments."); - return SR_ERR_ARG; - case SP_ERR_FAIL: - error = sp_last_error_message(); - sr_err("Read error: %s.", error); - sp_free_error_message(error); - return SR_ERR; + if (serial->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; + case SP_ERR_FAIL: + error = sp_last_error_message(); + sr_err("Read error: %s.", error); + sp_free_error_message(error); + return SR_ERR; } - sr_spew("Read %d/%d bytes (fd %d).", ret, count, serial->fd); + if (ret > 0) + sr_spew("Read %d/%d bytes (fd %d).", ret, count, serial->fd); return ret; } @@ -279,6 +291,7 @@ SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate, { int ret; char *error; + struct sp_port_config *config; if (!serial) { sr_dbg("Invalid serial port."); @@ -294,19 +307,41 @@ SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate, sr_spew("Setting serial parameters on port %s (fd %d).", serial->port, serial->fd); - ret = sp_set_params(&serial->data, baudrate, bits, parity, stopbits, - flowcontrol, rts, dtr); - - switch (ret) - { - case SP_ERR_ARG: - sr_err("Invalid arguments for setting serial port parameters."); - return SR_ERR_ARG; - case SP_ERR_FAIL: - error = sp_last_error_message(); - sr_err("Error setting serial port parameters: %s.", error); - sp_free_error_message(error); - return SR_ERR; + sp_new_config(&config); + sp_set_config_baudrate(config, baudrate); + sp_set_config_bits(config, bits); + switch (parity) { + case 0: + sp_set_config_parity(config, SP_PARITY_NONE); + break; + case 1: + sp_set_config_parity(config, SP_PARITY_EVEN); + break; + case 2: + sp_set_config_parity(config, SP_PARITY_ODD); + break; + default: + return SR_ERR_ARG; + } + 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); + sp_free_config(config); + + switch (ret) { + case SP_ERR_ARG: + sr_err("Invalid arguments for setting serial port parameters."); + return SR_ERR_ARG; + case SP_ERR_FAIL: + error = sp_last_error_message(); + sr_err("Error setting serial port parameters: %s.", error); + sp_free_error_message(error); + return SR_ERR; } return SR_OK; @@ -322,7 +357,7 @@ SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate, * * @return SR_OK upon success, SR_ERR upon failure. */ -#define SERIAL_COMM_SPEC "^(\\d+)/([78])([neo])([12])(.*)$" +#define SERIAL_COMM_SPEC "^(\\d+)/([5678])([neo])([12])(.*)$" SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial, const char *paramstr) { @@ -561,3 +596,56 @@ SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial, return SR_ERR; } + +/** + * Extract the serial device and options from the options linked list. + * + * @param options List of options passed from the command line. + * @param serial_device Pointer where to store the exctracted serial device. + * @param serial_options Pointer where to store the optional extracted serial + * options. + * + * @return SR_OK if a serial_device is found, SR_ERR if no device is found. The + * returned string should not be freed by the caller. + */ +SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_device, + const char **serial_options) +{ + GSList *l; + struct sr_config *src; + + *serial_device = NULL; + + for (l = options; l; l = l->next) { + src = l->data; + switch (src->key) { + case SR_CONF_CONN: + *serial_device = g_variant_get_string(src->data, NULL); + sr_dbg("Parsed serial device: %s", *serial_device); + break; + + case SR_CONF_SERIALCOMM: + *serial_options = g_variant_get_string(src->data, NULL); + sr_dbg("Parsed serial options: %s", *serial_options); + break; + } + } + + if (!*serial_device) { + sr_dbg("No serial device specified"); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int serial_source_add(struct sr_serial_dev_inst *serial, int events, + int timeout, sr_receive_data_callback_t cb, void *cb_data) +{ + return sr_source_add(serial->fd, events, timeout, cb, cb_data); +} + +SR_PRIV int serial_source_remove(struct sr_serial_dev_inst *serial) +{ + return sr_source_remove(serial->fd); +}