From: Martin Ling Date: Sun, 29 Dec 2013 01:36:49 +0000 (+0100) Subject: Revise SCPI read API to allow backend-independent data handling. X-Git-Tag: libsigrok-0.3.0~379 X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=commitdiff_plain;h=05c644ea081f5973fcbb2429318b808b931edfe3 Revise SCPI read API to allow backend-independent data handling. --- diff --git a/hardware/common/scpi.c b/hardware/common/scpi.c index a29f31b7..7329b294 100644 --- a/hardware/common/scpi.c +++ b/hardware/common/scpi.c @@ -165,20 +165,15 @@ SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi, } /** - * Receive an SCPI reply and store the reply in scpi_response. + * Begin receiving an SCPI reply. * * @param scpi Previously initialised SCPI device structure. - * @param scpi_response Pointer where to store the SCPI response. * - * @return SR_OK upon fetching a full SCPI response, SR_ERR upon fetching an - * incomplete or no response. The allocated response must be freed by - * the caller in the case of a full response as well in the case of - * an incomplete. + * @return SR_OK on success, SR_ERR on failure. */ -SR_PRIV int sr_scpi_receive(struct sr_scpi_dev_inst *scpi, - char **scpi_response) +SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi) { - return scpi->receive(scpi->priv, scpi_response); + return scpi->read_begin(scpi->priv); } /** @@ -190,10 +185,22 @@ SR_PRIV int sr_scpi_receive(struct sr_scpi_dev_inst *scpi, * * @return Number of bytes read, or SR_ERR upon failure. */ -SR_PRIV int sr_scpi_read(struct sr_scpi_dev_inst *scpi, +SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen) { - return scpi->read(scpi->priv, buf, maxlen); + return scpi->read_data(scpi->priv, buf, maxlen); +} + +/** + * Check whether a complete SCPI response has been received. + * + * @param scpi Previously initialised SCPI device structure. + * + * @return 1 if complete, 0 otherwise. + */ +SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi) +{ + return scpi->read_complete(scpi->priv); } /** @@ -228,19 +235,39 @@ SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi) * @param command The SCPI command to send to the device (can be NULL). * @param scpi_response Pointer where to store the SCPI response. * - * @return SR_OK upon fetching a full SCPI response, SR_ERR upon fetching an - * incomplete or no response. The allocated response must be freed by - * the caller in the case of a full response as well in the case of - * an incomplete. + * @return SR_OK on success, SR_ERR on failure. */ SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi, const char *command, char **scpi_response) { + char buf[256]; + int len; + GString *response; + if (command) if (sr_scpi_send(scpi, command) != SR_OK) return SR_ERR; - return sr_scpi_receive(scpi, scpi_response); + if (sr_scpi_read_begin(scpi) != SR_OK) + return SR_ERR; + + response = g_string_new(""); + + *scpi_response = NULL; + + while (!sr_scpi_read_complete(scpi)) { + len = sr_scpi_read_data(scpi, buf, sizeof(buf)); + if (len < 0) { + g_string_free(response, TRUE); + return SR_ERR; + } + g_string_append_len(response, buf, len); + } + + *scpi_response = response->str; + g_string_free(response, FALSE); + + return SR_OK; } /** diff --git a/hardware/common/scpi_serial.c b/hardware/common/scpi_serial.c index dc099634..0ee58947 100644 --- a/hardware/common/scpi_serial.c +++ b/hardware/common/scpi_serial.c @@ -29,9 +29,15 @@ #define SCPI_READ_RETRIES 100 #define SCPI_READ_RETRY_TIMEOUT 10000 +struct scpi_serial { + struct sr_serial_dev_inst *serial; + char last_character; +}; + SR_PRIV int scpi_serial_open(void *priv) { - struct sr_serial_dev_inst *serial = priv; + struct scpi_serial *sscpi = priv; + struct sr_serial_dev_inst *serial = sscpi->serial; if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return SR_ERR; @@ -45,14 +51,16 @@ SR_PRIV int scpi_serial_open(void *priv) SR_PRIV int scpi_serial_source_add(void *priv, int events, int timeout, sr_receive_data_callback_t cb, void *cb_data) { - struct sr_serial_dev_inst *serial = priv; + struct scpi_serial *sscpi = priv; + struct sr_serial_dev_inst *serial = sscpi->serial; return serial_source_add(serial, events, timeout, cb, cb_data); } SR_PRIV int scpi_serial_source_remove(void *priv) { - struct sr_serial_dev_inst *serial = priv; + struct scpi_serial *sscpi = priv; + struct sr_serial_dev_inst *serial = sscpi->serial; return serial_source_remove(serial); } @@ -61,7 +69,8 @@ SR_PRIV int scpi_serial_send(void *priv, const char *command) { int len, result, written; gchar *terminated_command; - struct sr_serial_dev_inst *serial = priv; + struct scpi_serial *sscpi = priv; + struct sr_serial_dev_inst *serial = sscpi->serial; terminated_command = g_strconcat(command, "\n", NULL); len = strlen(terminated_command); @@ -89,7 +98,8 @@ SR_PRIV int scpi_serial_receive(void *priv, char **scpi_response) char buf[256]; unsigned int i; GString *response; - struct sr_serial_dev_inst *serial = priv; + struct scpi_serial *sscpi = priv; + struct sr_serial_dev_inst *serial = sscpi->serial; response = g_string_sized_new(1024); @@ -136,43 +146,84 @@ SR_PRIV int scpi_serial_receive(void *priv, char **scpi_response) return ret; } -/* Some stubs to keep the compiler from whining. */ -static int scpi_serial_read(void *priv, char *buf, int maxlen) +SR_PRIV int scpi_serial_read_begin(void *priv) +{ + struct scpi_serial *sscpi = priv; + + sscpi->last_character = '\0'; + + return SR_OK; +} + +SR_PRIV int scpi_serial_read_data(void *priv, char *buf, int maxlen) { - return serial_read(priv, buf, maxlen); + struct scpi_serial *sscpi = priv; + int ret; + + ret = serial_read(sscpi->serial, buf, maxlen); + + if (ret < 0) + return ret; + + if (ret > 0) { + sscpi->last_character = buf[ret - 1]; + if (sscpi->last_character == '\n') + ret--; + } + + return ret; } + +SR_PRIV int scpi_serial_read_complete(void *priv) +{ + struct scpi_serial *sscpi = priv; + + return (sscpi->last_character == '\n'); +} + static int scpi_serial_close(void *priv) { - return serial_close(priv); + struct scpi_serial *sscpi = priv; + struct sr_serial_dev_inst *serial = sscpi->serial; + + return serial_close(serial); } + static void scpi_serial_free(void *priv) { - return sr_serial_dev_inst_free(priv); + struct scpi_serial *sscpi = priv; + struct sr_serial_dev_inst *serial = sscpi->serial; + + sr_serial_dev_inst_free(serial); + g_free(sscpi); } SR_PRIV struct sr_scpi_dev_inst *scpi_serial_dev_inst_new(const char *port, const char *serialcomm) { struct sr_scpi_dev_inst *scpi; + struct scpi_serial *sscpi; struct sr_serial_dev_inst *serial; - scpi = g_try_malloc(sizeof(struct sr_scpi_dev_inst)); - if (!(serial = sr_serial_dev_inst_new(port, serialcomm))) - { - g_free(scpi); return NULL; - } + + sscpi = g_malloc(sizeof(struct scpi_serial)); + + sscpi->serial = serial; + + scpi = g_malloc(sizeof(struct sr_scpi_dev_inst)); scpi->open = scpi_serial_open; scpi->source_add = scpi_serial_source_add; scpi->source_remove = scpi_serial_source_remove; scpi->send = scpi_serial_send; - scpi->receive = scpi_serial_receive; - scpi->read = scpi_serial_read; + scpi->read_begin = scpi_serial_read_begin; + scpi->read_data = scpi_serial_read_data; + scpi->read_complete = scpi_serial_read_complete; scpi->close = scpi_serial_close; scpi->free = scpi_serial_free; - scpi->priv = serial; + scpi->priv = sscpi; return scpi; } diff --git a/hardware/common/scpi_tcp.c b/hardware/common/scpi_tcp.c index af2db140..44557937 100644 --- a/hardware/common/scpi_tcp.c +++ b/hardware/common/scpi_tcp.c @@ -39,10 +39,16 @@ #define LOG_PREFIX "scpi_tcp" +#define LENGTH_BYTES 4 + 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; }; SR_PRIV int scpi_tcp_open(void *priv) @@ -129,40 +135,40 @@ SR_PRIV int scpi_tcp_send(void *priv, const char *command) return SR_OK; } -SR_PRIV int scpi_tcp_receive(void *priv, char **scpi_response) +SR_PRIV int scpi_tcp_read_begin(void *priv) { struct scpi_tcp *tcp = priv; - GString *response; - char buf[256]; - int len; - response = g_string_sized_new(1024); - - len = recv(tcp->socket, buf, sizeof(buf), 0); - - if (len < 0) { - sr_err("Receive error: %s", strerror(errno)); - g_string_free(response, TRUE); - return SR_ERR; - } - - response = g_string_append_len(response, buf + 4, len - 4); - - *scpi_response = response->str; - - sr_dbg("SCPI response received (length %d): '%.50s'", - response->len, response->str); - - g_string_free(response, FALSE); + tcp->response_bytes_read = 0; + tcp->length_bytes_read = 0; return SR_OK; } -SR_PRIV int scpi_tcp_read(void *priv, char *buf, int maxlen) +SR_PRIV int scpi_tcp_read_data(void *priv, char *buf, int maxlen) { struct scpi_tcp *tcp = priv; int len; + 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) { + sr_err("Receive error: %s", strerror(errno)); + return SR_ERR; + } + + tcp->length_bytes_read += len; + + if (tcp->length_bytes_read < LENGTH_BYTES) + return 0; + else + tcp->response_length = RL32(tcp->length_buf); + } + + if (tcp->response_bytes_read >= tcp->response_length) + return SR_ERR; + len = recv(tcp->socket, buf, maxlen, 0); if (len < 0) { @@ -170,9 +176,19 @@ SR_PRIV int scpi_tcp_read(void *priv, char *buf, int maxlen) return SR_ERR; } + tcp->response_bytes_read += len; + return len; } +SR_PRIV int scpi_tcp_read_complete(void *priv) +{ + struct scpi_tcp *tcp = priv; + + return (tcp->length_bytes_read == LENGTH_BYTES && + tcp->response_bytes_read >= tcp->response_length); +} + SR_PRIV int scpi_tcp_close(void *priv) { struct scpi_tcp *tcp = priv; @@ -209,8 +225,9 @@ SR_PRIV struct sr_scpi_dev_inst *scpi_tcp_dev_inst_new(const char *address, scpi->source_add = scpi_tcp_source_add; scpi->source_remove = scpi_tcp_source_remove; scpi->send = scpi_tcp_send; - scpi->receive = scpi_tcp_receive; - scpi->read = scpi_tcp_read; + scpi->read_begin = scpi_tcp_read_begin; + scpi->read_data = scpi_tcp_read_data; + scpi->read_complete = scpi_tcp_read_complete; scpi->close = scpi_tcp_close; scpi->free = scpi_tcp_free; scpi->priv = tcp; diff --git a/hardware/common/scpi_usbtmc.c b/hardware/common/scpi_usbtmc.c index 298e3ab5..5aa0dbbd 100644 --- a/hardware/common/scpi_usbtmc.c +++ b/hardware/common/scpi_usbtmc.c @@ -28,9 +28,19 @@ #define LOG_PREFIX "scpi_usbtmc" +#define MAX_READ_LENGTH 2048 + +struct usbtmc_scpi { + struct sr_usbtmc_dev_inst *usbtmc; + char response_buffer[MAX_READ_LENGTH]; + int response_length; + int response_bytes_read; +}; + SR_PRIV int scpi_usbtmc_open(void *priv) { - struct sr_usbtmc_dev_inst *usbtmc = priv; + struct usbtmc_scpi *uscpi = priv; + struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc; if ((usbtmc->fd = open(usbtmc->device, O_RDWR)) < 0) return SR_ERR; @@ -41,21 +51,24 @@ SR_PRIV int scpi_usbtmc_open(void *priv) SR_PRIV int scpi_usbtmc_source_add(void *priv, int events, int timeout, sr_receive_data_callback_t cb, void *cb_data) { - struct sr_usbtmc_dev_inst *usbtmc = priv; + struct usbtmc_scpi *uscpi = priv; + struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc; return sr_source_add(usbtmc->fd, events, timeout, cb, cb_data); } SR_PRIV int scpi_usbtmc_source_remove(void *priv) { - struct sr_usbtmc_dev_inst *usbtmc = priv; + struct usbtmc_scpi *uscpi = priv; + struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc; return sr_source_remove(usbtmc->fd); } SR_PRIV int scpi_usbtmc_send(void *priv, const char *command) { - struct sr_usbtmc_dev_inst *usbtmc = priv; + struct usbtmc_scpi *uscpi = priv; + struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc; int len, out; len = strlen(command); @@ -76,53 +89,56 @@ SR_PRIV int scpi_usbtmc_send(void *priv, const char *command) return SR_OK; } -SR_PRIV int scpi_usbtmc_receive(void *priv, char **scpi_response) +SR_PRIV int scpi_usbtmc_read_begin(void *priv) { - struct sr_usbtmc_dev_inst *usbtmc = priv; - GString *response; - char buf[256]; + struct usbtmc_scpi *uscpi = priv; + struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc; int len; - response = g_string_sized_new(1024); - - len = read(usbtmc->fd, buf, sizeof(buf)); + len = read(usbtmc->fd, uscpi->response_buffer, MAX_READ_LENGTH); if (len < 0) { sr_err("Read error: %s", strerror(errno)); - g_string_free(response, TRUE); return SR_ERR; } - response = g_string_append_len(response, buf, len); - - *scpi_response = response->str; - - sr_dbg("SCPI response received (length %d): '%.50s'", - response->len, response->str); - - g_string_free(response, FALSE); + uscpi->response_length = len; + uscpi->response_bytes_read = 0; return SR_OK; } -SR_PRIV int scpi_usbtmc_read(void *priv, char *buf, int maxlen) +SR_PRIV int scpi_usbtmc_read_data(void *priv, char *buf, int maxlen) { - struct sr_usbtmc_dev_inst *usbtmc = priv; - int len; - - len = read(usbtmc->fd, buf, maxlen); + struct usbtmc_scpi *uscpi = priv; + int read_length; - if (len < 0) { - sr_err("Read error: %s", strerror(errno)); + if (uscpi->response_bytes_read >= uscpi->response_length) return SR_ERR; - } - return len; + read_length = uscpi->response_length - uscpi->response_bytes_read; + + if (read_length > maxlen) + read_length = maxlen; + + memcpy(buf, uscpi->response_buffer + uscpi->response_bytes_read, read_length); + + uscpi->response_bytes_read += read_length; + + return read_length; +} + +SR_PRIV int scpi_usbtmc_read_complete(void *priv) +{ + struct usbtmc_scpi *uscpi = priv; + + return (uscpi->response_bytes_read >= uscpi->response_length); } SR_PRIV int scpi_usbtmc_close(void *priv) { - struct sr_usbtmc_dev_inst *usbtmc = priv; + struct usbtmc_scpi *uscpi = priv; + struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc; if (close(usbtmc->fd) < 0) return SR_ERR; @@ -132,31 +148,38 @@ SR_PRIV int scpi_usbtmc_close(void *priv) static void scpi_usbtmc_free(void *priv) { - return sr_usbtmc_dev_inst_free(priv); + struct usbtmc_scpi *uscpi = priv; + struct sr_usbtmc_dev_inst *usbtmc = uscpi->usbtmc; + + g_free(uscpi); + sr_usbtmc_dev_inst_free(usbtmc); } SR_PRIV struct sr_scpi_dev_inst *scpi_usbtmc_dev_inst_new(const char *device) { struct sr_scpi_dev_inst *scpi; + struct usbtmc_scpi *uscpi; struct sr_usbtmc_dev_inst *usbtmc; - scpi = g_try_malloc(sizeof(struct sr_scpi_dev_inst)); - if (!(usbtmc = sr_usbtmc_dev_inst_new(device))) - { - g_free(scpi); return NULL; - } + + uscpi = g_malloc(sizeof(struct usbtmc_scpi)); + + uscpi->usbtmc = usbtmc; + + scpi = g_malloc(sizeof(struct sr_scpi_dev_inst)); scpi->open = scpi_usbtmc_open; scpi->source_add = scpi_usbtmc_source_add; scpi->source_remove = scpi_usbtmc_source_remove; scpi->send = scpi_usbtmc_send; - scpi->receive = scpi_usbtmc_receive; - scpi->read = scpi_usbtmc_read; + scpi->read_begin = scpi_usbtmc_read_begin; + scpi->read_data = scpi_usbtmc_read_data; + scpi->read_complete = scpi_usbtmc_read_complete; scpi->close = scpi_usbtmc_close; scpi->free = scpi_usbtmc_free; - scpi->priv = usbtmc; + scpi->priv = uscpi; return scpi; } diff --git a/hardware/rigol-ds/protocol.c b/hardware/rigol-ds/protocol.c index 4dec85b4..fc938e9d 100644 --- a/hardware/rigol-ds/protocol.c +++ b/hardware/rigol-ds/protocol.c @@ -368,7 +368,7 @@ static int rigol_ds_read_header(struct sr_scpi_dev_inst *scpi) int len, tmp; /* Read the hashsign and length digit. */ - tmp = sr_scpi_read(scpi, start, 2); + tmp = sr_scpi_read_data(scpi, start, 2); start[2] = '\0'; if (tmp != 2) { @@ -383,7 +383,7 @@ static int rigol_ds_read_header(struct sr_scpi_dev_inst *scpi) len = atoi(start + 1); /* Read the data length. */ - tmp = sr_scpi_read(scpi, length, len); + tmp = sr_scpi_read_data(scpi, length, len); length[len] = '\0'; if (tmp != len) { @@ -458,6 +458,8 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) probe = devc->channel_entry->data; if (devc->num_block_bytes == 0) { + if (sr_scpi_read_begin(scpi) != SR_OK) + return TRUE; if (devc->model->protocol == PROTOCOL_IEEE488_2) { sr_dbg("New block header expected"); if (sr_scpi_send(sdi->conn, ":WAV:DATA?") != SR_OK) @@ -474,7 +476,7 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) if (devc->data_source == DATA_SOURCE_LIVE && (unsigned)len < devc->num_frame_samples) { sr_dbg("Discarding short data block"); - sr_scpi_read(scpi, (char *)devc->buffer, len + 1); + sr_scpi_read_data(scpi, (char *)devc->buffer, len + 1); return TRUE; } devc->num_block_bytes = len; @@ -489,7 +491,7 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) } len = devc->num_block_bytes - devc->num_block_read; - len = sr_scpi_read(scpi, (char *)devc->buffer, + len = sr_scpi_read_data(scpi, (char *)devc->buffer, len < ACQ_BUFFER_SIZE ? len : ACQ_BUFFER_SIZE); sr_dbg("Received %d bytes.", len); @@ -538,7 +540,7 @@ SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) if (devc->model->protocol == PROTOCOL_IEEE488_2) { /* Discard the terminating linefeed and prepare for possible next block */ - sr_scpi_read(scpi, (char *)devc->buffer, 1); + sr_scpi_read_data(scpi, (char *)devc->buffer, 1); devc->num_block_bytes = 0; if (devc->data_source != DATA_SOURCE_LIVE) rigol_ds_set_wait_event(devc, WAIT_BLOCK); @@ -613,10 +615,7 @@ static int get_cfg(const struct sr_dev_inst *sdi, char *cmd, char *reply, size_t struct sr_scpi_dev_inst *scpi = sdi->conn; char *response; - if (sr_scpi_send(scpi, cmd) != SR_OK) - return SR_ERR; - - if (sr_scpi_receive(scpi, &response) != SR_OK) + if (sr_scpi_get_string(scpi, cmd, &response) != SR_OK) return SR_ERR; g_strlcpy(reply, response, maxlen); diff --git a/libsigrok-internal.h b/libsigrok-internal.h index 61978c29..646164cf 100644 --- a/libsigrok-internal.h +++ b/libsigrok-internal.h @@ -371,8 +371,9 @@ struct sr_scpi_dev_inst { int timeout, sr_receive_data_callback_t cb, void *cb_data); int (*source_remove)(void *priv); int (*send)(void *priv, const char *command); - int (*receive)(void *priv, char **scpi_response); - int (*read)(void *priv, char *buf, int maxlen); + int (*read_begin)(void *priv); + int (*read_data)(void *priv, char *buf, int maxlen); + int (*read_complete)(void *priv); int (*close)(void *priv); void (*free)(void *priv); void *priv; @@ -386,9 +387,9 @@ SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi, const char *format, ...); SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi, const char *format, va_list args); -SR_PRIV int sr_scpi_receive(struct sr_scpi_dev_inst *scpi, - char **scpi_response); -SR_PRIV int sr_scpi_read(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen); +SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi); +SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen); +SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi); SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi); SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi);