X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fscpi%2Fscpi_tcp.c;h=c85cf3eb93b0387ba3ecff420da9eb7af5052edc;hb=HEAD;hp=cf01c905cf65f8bfa4745275bbe820e15bbb0edc;hpb=7237e91262251a138cf150f9fcfe7b05d0e5904b;p=libsigrok.git diff --git a/src/scpi/scpi_tcp.c b/src/scpi/scpi_tcp.c index cf01c905..c85cf3eb 100644 --- a/src/scpi/scpi_tcp.c +++ b/src/scpi/scpi_tcp.c @@ -17,37 +17,26 @@ * along with this program. If not, see . */ -#ifdef _WIN32 -#define _WIN32_WINNT 0x0501 -#include -#include -#endif -#include -#include -#include -#ifndef _WIN32 -#include -#include -#include -#include -#endif +#include "config.h" + #include +#include #include +#include + #include "libsigrok-internal.h" #include "scpi.h" #define LOG_PREFIX "scpi_tcp" -#define LENGTH_BYTES 4 +#define LENGTH_BYTES sizeof(uint32_t) struct scpi_tcp { - char *address; - char *port; - int socket; - char length_buf[LENGTH_BYTES]; - int length_bytes_read; - int response_length; - int response_bytes_read; + struct sr_tcp_dev_inst *tcp_dev; + uint8_t length_buf[LENGTH_BYTES]; + size_t length_bytes_read; + size_t response_length; + size_t response_bytes_read; }; static int scpi_tcp_dev_inst_new(void *priv, struct drv_context *drvc, @@ -64,53 +53,38 @@ static int scpi_tcp_dev_inst_new(void *priv, struct drv_context *drvc, return SR_ERR; } - tcp->address = g_strdup(params[1]); - tcp->port = g_strdup(params[2]); - tcp->socket = -1; + tcp->tcp_dev = sr_tcp_dev_inst_new(params[1], params[2]); + if (!tcp->tcp_dev) + return SR_ERR; return SR_OK; } -static int scpi_tcp_open(void *priv) +static int scpi_tcp_open(struct sr_scpi_dev_inst *scpi) { - struct scpi_tcp *tcp = priv; - struct addrinfo hints; - struct addrinfo *results, *res; - int err; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - err = getaddrinfo(tcp->address, tcp->port, &hints, &results); + struct scpi_tcp *tcp = scpi->priv; + int ret; - if (err) { - sr_err("Address lookup failed: %s:%d: %s", tcp->address, tcp->port, - gai_strerror(err)); - return SR_ERR; - } + ret = sr_tcp_connect(tcp->tcp_dev); + if (ret != SR_OK) + return ret; - for (res = results; res; res = res->ai_next) { - if ((tcp->socket = socket(res->ai_family, res->ai_socktype, - res->ai_protocol)) < 0) - continue; - if (connect(tcp->socket, res->ai_addr, res->ai_addrlen) != 0) { - close(tcp->socket); - tcp->socket = -1; - continue; - } - break; - } + return SR_OK; +} - freeaddrinfo(results); +static int scpi_tcp_connection_id(struct sr_scpi_dev_inst *scpi, + char **connection_id) +{ + struct scpi_tcp *tcp = scpi->priv; + char conn_text[128]; + int ret; - if (tcp->socket < 0) { - sr_err("Failed to connect to %s:%s: %s", tcp->address, tcp->port, - g_strerror(errno)); - return SR_ERR; - } + ret = sr_tcp_get_port_path(tcp->tcp_dev, scpi->prefix, '/', + conn_text, sizeof(conn_text)); + if (ret != SR_OK) + return ret; + *connection_id = g_strdup(conn_text); return SR_OK; } @@ -119,36 +93,36 @@ static int scpi_tcp_source_add(struct sr_session *session, void *priv, { struct scpi_tcp *tcp = priv; - return sr_session_source_add(session, tcp->socket, events, timeout, - cb, cb_data); + return sr_tcp_source_add(session, tcp->tcp_dev, + events, timeout, cb, cb_data); } static int scpi_tcp_source_remove(struct sr_session *session, void *priv) { struct scpi_tcp *tcp = priv; - return sr_session_source_remove(session, tcp->socket); + return sr_tcp_source_remove(session, tcp->tcp_dev); } +/* Transmit text, usually a command. tcp-raw and tcp-rigol modes. */ static int scpi_tcp_send(void *priv, const char *command) { struct scpi_tcp *tcp = priv; - int len, out; - char *terminated_command; - - terminated_command = g_strdup_printf("%s\r\n", command); - len = strlen(terminated_command); - out = send(tcp->socket, terminated_command, len, 0); - g_free(terminated_command); - - if (out < 0) { + const uint8_t *wrptr; + size_t wrlen, written; + int ret; + + wrptr = (const uint8_t *)command; + wrlen = strlen(command); + ret = sr_tcp_write_bytes(tcp->tcp_dev, wrptr, wrlen); + if (ret < 0) { sr_err("Send error: %s", g_strerror(errno)); return SR_ERR; } - - if (out < len) { - sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.", out, - len, command); + written = (size_t)ret; + if (written < wrlen) { + sr_dbg("Only sent %zu/%zu bytes of SCPI command: '%s'.", + written, wrlen, command); } sr_spew("Successfully sent SCPI command: '%s'.", command); @@ -156,6 +130,7 @@ static int scpi_tcp_send(void *priv, const char *command) return SR_OK; } +/* Start reception across multiple read calls. tcp-raw and tcp-rigol modes. */ static int scpi_tcp_read_begin(void *priv) { struct scpi_tcp *tcp = priv; @@ -166,75 +141,126 @@ static int scpi_tcp_read_begin(void *priv) return SR_OK; } +/* Receive response data. tcp-raw mode. */ static int scpi_tcp_raw_read_data(void *priv, char *buf, int maxlen) { struct scpi_tcp *tcp = priv; - int len; - - len = recv(tcp->socket, buf, maxlen, 0); - - if (len < 0) { + uint8_t *rdptr; + size_t rdlen, rcvd; + int ret; + + /* Get another chunk of receive data. */ + rdptr = (uint8_t *)buf; + rdlen = maxlen; + ret = sr_tcp_read_bytes(tcp->tcp_dev, rdptr, rdlen, FALSE); + if (ret < 0) { sr_err("Receive error: %s", g_strerror(errno)); return SR_ERR; } - + rcvd = (size_t)ret; + + /* + * Raw data mode (in contrast to Rigol mode). Prepare to answer + * the "completed" condition while the payload's length is not + * known. Pretend that the length buffer had been received. + * Assume that short reads correspond to the end of a response, + * while full reads of the caller specified size suggest that + * more data can follow. + */ tcp->length_bytes_read = LENGTH_BYTES; - tcp->response_length = len < maxlen ? len : maxlen + 1; - tcp->response_bytes_read = len; + tcp->response_length = rcvd < rdlen ? rcvd : rdlen + 1; + tcp->response_bytes_read = rcvd; - return len; + return rcvd; } -static int scpi_tcp_rigol_read_data(void *priv, char *buf, int maxlen) +/* Transmit data of given length. tcp-raw mode. */ +static int scpi_tcp_raw_write_data(void *priv, char *buf, int len) { struct scpi_tcp *tcp = priv; - int len; + const uint8_t *wrptr; + size_t wrlen, sent; + int ret; + + wrptr = (const uint8_t *)buf; + wrlen = len; + ret = sr_tcp_write_bytes(tcp->tcp_dev, wrptr, wrlen); + if (ret < 0) { + sr_err("Send error: %s.", g_strerror(errno)); + return SR_ERR; + } + sent = (size_t)ret; + + return sent; +} - if (tcp->length_bytes_read < LENGTH_BYTES) { - len = recv(tcp->socket, tcp->length_buf + tcp->length_bytes_read, - LENGTH_BYTES - tcp->length_bytes_read, 0); - if (len < 0) { +/* Receive response data. tcp-rigol mode. */ +static int scpi_tcp_rigol_read_data(void *priv, char *buf, int maxlen) +{ + struct scpi_tcp *tcp = priv; + uint8_t *rdptr; + size_t rdlen, rcvd; + int ret; + + /* + * Rigol mode, chunks are prefixed by a length spec. + * Get more length bytes when we haven't read them before. + * Return "zero length read" if length has yet to get received. + * Otherwise get chunk length from length bytes buffer. + */ + if (tcp->length_bytes_read < sizeof(tcp->length_buf)) { + rdptr = &tcp->length_buf[tcp->length_bytes_read]; + rdlen = sizeof(tcp->length_buf) - tcp->length_bytes_read; + ret = sr_tcp_read_bytes(tcp->tcp_dev, rdptr, rdlen, FALSE); + if (ret < 0) { sr_err("Receive error: %s", g_strerror(errno)); return SR_ERR; } - - tcp->length_bytes_read += len; - - if (tcp->length_bytes_read < LENGTH_BYTES) + rcvd = (size_t)ret; + tcp->length_bytes_read += rcvd; + if (tcp->length_bytes_read < sizeof(tcp->length_buf)) return 0; - else - tcp->response_length = RL32(tcp->length_buf); + tcp->response_length = read_u32le(tcp->length_buf); } + /* Received more chunk data than announced size? Fatal. */ if (tcp->response_bytes_read >= tcp->response_length) return SR_ERR; - len = recv(tcp->socket, buf, maxlen, 0); - - if (len < 0) { + /* Read another chunk of the receive data. */ + rdptr = (uint8_t *)buf; + rdlen = maxlen; + ret = sr_tcp_read_bytes(tcp->tcp_dev, rdptr, rdlen, FALSE); + if (ret < 0) { sr_err("Receive error: %s", g_strerror(errno)); return SR_ERR; } + rcvd = (size_t)ret; + tcp->response_bytes_read += rcvd; - tcp->response_bytes_read += len; - - return len; + return rcvd; } +/* Check reception completion. tcp-raw and tcp-rigol modes. */ static int scpi_tcp_read_complete(void *priv) { struct scpi_tcp *tcp = priv; + gboolean have_length, have_response; + + have_length = tcp->length_bytes_read == LENGTH_BYTES; + have_response = tcp->response_bytes_read >= tcp->response_length; - return (tcp->length_bytes_read == LENGTH_BYTES && - tcp->response_bytes_read >= tcp->response_length); + return have_length && have_response; } -static int scpi_tcp_close(void *priv) +static int scpi_tcp_close(struct sr_scpi_dev_inst *scpi) { - struct scpi_tcp *tcp = priv; + struct scpi_tcp *tcp = scpi->priv; + int ret; - if (close(tcp->socket) < 0) - return SR_ERR; + ret = sr_tcp_disconnect(tcp->tcp_dev); + if (ret != SR_OK) + return ret; return SR_OK; } @@ -243,21 +269,23 @@ static void scpi_tcp_free(void *priv) { struct scpi_tcp *tcp = priv; - g_free(tcp->address); - g_free(tcp->port); + sr_tcp_dev_inst_free(tcp->tcp_dev); } SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_raw_dev = { .name = "RAW TCP", .prefix = "tcp-raw", + .transport = SCPI_TRANSPORT_RAW_TCP, .priv_size = sizeof(struct scpi_tcp), .dev_inst_new = scpi_tcp_dev_inst_new, .open = scpi_tcp_open, + .connection_id = scpi_tcp_connection_id, .source_add = scpi_tcp_source_add, .source_remove = scpi_tcp_source_remove, .send = scpi_tcp_send, .read_begin = scpi_tcp_read_begin, .read_data = scpi_tcp_raw_read_data, + .write_data = scpi_tcp_raw_write_data, .read_complete = scpi_tcp_read_complete, .close = scpi_tcp_close, .free = scpi_tcp_free, @@ -266,9 +294,11 @@ SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_raw_dev = { SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_rigol_dev = { .name = "RIGOL TCP", .prefix = "tcp-rigol", + .transport = SCPI_TRANSPORT_RIGOL_TCP, .priv_size = sizeof(struct scpi_tcp), .dev_inst_new = scpi_tcp_dev_inst_new, .open = scpi_tcp_open, + .connection_id = scpi_tcp_connection_id, .source_add = scpi_tcp_source_add, .source_remove = scpi_tcp_source_remove, .send = scpi_tcp_send,