From: Stefan BrĂ¼ns Date: Fri, 13 Jan 2017 22:10:41 +0000 (+0100) Subject: scpi: Do not block when reading header of definite length blocks X-Git-Tag: libsigrok-0.5.0~133 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=d64be25be4b315bceb7f6d87b1c414a3c94c31c5;p=libsigrok.git scpi: Do not block when reading header of definite length blocks When using SCPI over serial (over USB), we want the header without waiting for the terminating newline, as otherwise the transfer may time out. sr_scpi_get_data() will block until the message is complete. --- diff --git a/src/scpi.h b/src/scpi.h index 1c2c20d7..ddfd9450 100644 --- a/src/scpi.h +++ b/src/scpi.h @@ -120,6 +120,8 @@ 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); +SR_PRIV int sr_scpi_read_response(struct sr_scpi_dev_inst *scpi, + GString *response, gint64 abs_timeout_us); SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi, const char *command, char **scpi_response); SR_PRIV int sr_scpi_get_bool(struct sr_scpi_dev_inst *scpi, diff --git a/src/scpi/scpi.c b/src/scpi/scpi.c index f6865c37..a3a16ebd 100644 --- a/src/scpi/scpi.c +++ b/src/scpi/scpi.c @@ -412,14 +412,49 @@ SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi, return SR_OK; } +/** + * Do a non-blocking read of up to the allocated length, and + * check if a timeout has occured. + * + * @param scpi Previously initialised SCPI device structure. + * @param response Buffer to which the response is appended. + * @param abs_timeout_us Absolute timeout in microseconds + * + * @return read length on success, SR_ERR* on failure. + */ +SR_PRIV int sr_scpi_read_response(struct sr_scpi_dev_inst *scpi, + GString *response, gint64 abs_timeout_us) +{ + int len, space; + + space = response->allocated_len - response->len; + len = sr_scpi_read_data(scpi, &response->str[response->len], space); + + if (len < 0) { + sr_err("Incompletely read SCPI response."); + return SR_ERR; + } + + if (len > 0) { + g_string_set_size(response, response->len + len); + return len; + } + + if (g_get_monotonic_time() > abs_timeout_us) { + sr_err("Timed out waiting for SCPI response."); + return SR_ERR_TIMEOUT; + } + + return 0; +} + SR_PRIV int sr_scpi_get_data(struct sr_scpi_dev_inst *scpi, const char *command, GString **scpi_response) { - int len; + int ret; GString *response; - gint64 laststart, now; - unsigned int offset; int space; + gint64 timeout; /* Optionally send caller provided command. */ if (command) { @@ -432,37 +467,26 @@ SR_PRIV int sr_scpi_get_data(struct sr_scpi_dev_inst *scpi, return SR_ERR; /* Keep reading until completion or until timeout. */ - laststart = g_get_monotonic_time(); + timeout = g_get_monotonic_time() + scpi->read_timeout_us; response = *scpi_response; - offset = response->len; while (!sr_scpi_read_complete(scpi)) { /* Resize the buffer when free space drops below a threshold. */ space = response->allocated_len - response->len; if (space < 128) { - g_string_set_size(response, response->len + 1024); - g_string_set_size(response, offset); - space = response->allocated_len - response->len; - } - /* Read another chunk of the response. */ - len = sr_scpi_read_data(scpi, &response->str[offset], space); - if (len < 0) { - sr_err("Incompletely read SCPI response."); - return SR_ERR; + int oldlen = response->len; + g_string_set_size(response, oldlen + 1024); + g_string_set_size(response, oldlen); } - now = g_get_monotonic_time(); + /* Read another chunk of the response. */ + ret = sr_scpi_read_response(scpi, response, timeout); - if (len > 0) { - laststart = now; - offset += len; - g_string_set_size(response, offset); - } else if ((now - laststart) >= scpi->read_timeout_us) { - /* Quit reading after a period of time without receiving data. */ - sr_err("Timed out waiting for SCPI response."); - return SR_ERR_TIMEOUT; - } + if (ret < 0) + return ret; + if (ret > 0) + timeout = g_get_monotonic_time() + scpi->read_timeout_us; } return SR_OK; @@ -753,19 +777,32 @@ SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi, char buf[10]; long llen; long datalen; + gint64 timeout; + + if (command) + if (sr_scpi_send(scpi, command) != SR_OK) + return SR_ERR; + + if (sr_scpi_read_begin(scpi) != SR_OK) + return SR_ERR; /* * Assume an initial maximum length, optionally gets adjusted below. * Prepare a NULL return value for when error paths will be taken. */ response = g_string_sized_new(1024); + + timeout = g_get_monotonic_time() + scpi->read_timeout_us; + *scpi_response = NULL; /* Get (the first chunk of) the response. */ - ret = sr_scpi_get_data(scpi, command, &response); - if (ret != SR_OK) { - g_string_free(response, TRUE); - return ret; + while (response->len < 2) { + ret = sr_scpi_read_response(scpi, response, timeout); + if (ret < 0) { + g_string_free(response, TRUE); + return ret; + } } /* @@ -790,6 +827,15 @@ SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi, g_string_free(response, TRUE); return ret; } + + while (response->len < (unsigned long)(2 + llen)) { + ret = sr_scpi_read_response(scpi, response, timeout); + if (ret < 0) { + g_string_free(response, TRUE); + return ret; + } + } + memcpy(buf, &response->str[2], llen); buf[llen] = '\0'; ret = sr_atol(buf, &datalen); @@ -809,19 +855,22 @@ SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi, g_string_set_size(response, datalen); g_string_set_size(response, oldlen); } + while (response->len < (unsigned long)(datalen)) { - ret = sr_scpi_get_data(scpi, NULL, &response); - if (ret != SR_OK) { + ret = sr_scpi_read_response(scpi, response, timeout); + if (ret < 0) { g_string_free(response, TRUE); return ret; } + if (ret > 0) + timeout = g_get_monotonic_time() + scpi->read_timeout_us; } /* Convert received data to byte array. */ *scpi_response = g_byte_array_new_take( (guint8*)g_string_free(response, FALSE), datalen); - return ret; + return SR_OK; } /**