X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;ds=inline;f=src%2Fscpi%2Fscpi_tcp.c;h=c85cf3eb93b0387ba3ecff420da9eb7af5052edc;hb=204dd31fa1074a78fbe3bf04208776a4a3615a1c;hp=62974680aa93bdc99b321c5daeff5196af842134;hpb=04229f7bfc750f2b67e8dd54ac82ae6bb7eae1e4;p=libsigrok.git
diff --git a/src/scpi/scpi_tcp.c b/src/scpi/scpi_tcp.c
index 62974680..c85cf3eb 100644
--- a/src/scpi/scpi_tcp.c
+++ b/src/scpi/scpi_tcp.c
@@ -17,38 +17,26 @@
* along with this program. If not, see .
*/
-#include
-#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,
@@ -65,9 +53,9 @@ 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;
}
@@ -75,43 +63,28 @@ static int scpi_tcp_dev_inst_new(void *priv, struct drv_context *drvc,
static int scpi_tcp_open(struct sr_scpi_dev_inst *scpi)
{
struct scpi_tcp *tcp = scpi->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;
+ int ret;
- err = getaddrinfo(tcp->address, tcp->port, &hints, &results);
-
- if (err) {
- sr_err("Address lookup failed: %s:%s: %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;
}
@@ -120,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);
@@ -157,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;
@@ -167,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;
- return (tcp->length_bytes_read == LENGTH_BYTES &&
- tcp->response_bytes_read >= tcp->response_length);
+ have_length = tcp->length_bytes_read == LENGTH_BYTES;
+ have_response = tcp->response_bytes_read >= tcp->response_length;
+
+ return have_length && have_response;
}
static int scpi_tcp_close(struct sr_scpi_dev_inst *scpi)
{
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;
}
@@ -244,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,
@@ -267,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,