hameg-hmo: Avoid getting stuck upon SCPI timeouts.

Correctly set the length of the buffer used to hold the SCPI response
from the device containing the binary acquisition data.

If a timeout occurs, truncate the buffer and send the partial response
from the device instead of getting stuck on timeouts!

Thanks to Stefan Brüns for reviewing the first version of this patch
and spotting out a serious problem with it.

This fixes bug #1323.
This commit is contained in:
Guido Trentalancia 2018-11-16 18:42:16 +01:00 committed by Uwe Hermann
parent d779dcacb7
commit bb0665868e
1 changed files with 28 additions and 19 deletions

View File

@ -961,6 +961,7 @@ SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi,
{ {
int ret; int ret;
GString* response; GString* response;
gsize oldlen;
char buf[10]; char buf[10];
long llen; long llen;
long datalen; long datalen;
@ -990,14 +991,14 @@ SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi,
*scpi_response = NULL; *scpi_response = NULL;
/* Get (the first chunk of) the response. */ /* Get (the first chunk of) the response. */
while (response->len < 2) { do {
ret = scpi_read_response(scpi, response, timeout); ret = scpi_read_response(scpi, response, timeout);
if (ret < 0) { if (ret < 0) {
g_mutex_unlock(&scpi->scpi_mutex); g_mutex_unlock(&scpi->scpi_mutex);
g_string_free(response, TRUE); g_string_free(response, TRUE);
return ret; return ret;
} }
} } while (response->len < 2);
/* /*
* SCPI protocol data blocks are preceeded with a length spec. * SCPI protocol data blocks are preceeded with a length spec.
@ -1044,25 +1045,33 @@ SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi,
g_string_erase(response, 0, 2 + llen); g_string_erase(response, 0, 2 + llen);
/* /*
* If the initially assumed length does not cover the data block * Re-allocate the buffer size to the now known length
* length, then re-allocate the buffer size to the now known * and keep reading more chunks of response data.
* length, and keep reading more chunks of response data.
*/ */
if (response->len < (unsigned long)(datalen)) { oldlen = response->len;
int oldlen = response->len; g_string_set_size(response, datalen);
g_string_set_size(response, datalen); g_string_set_size(response, oldlen);
g_string_set_size(response, oldlen);
}
while (response->len < (unsigned long)(datalen)) { if (oldlen < (unsigned long)(datalen)) {
ret = scpi_read_response(scpi, response, timeout); do {
if (ret < 0) { oldlen = response->len;
g_mutex_unlock(&scpi->scpi_mutex); ret = scpi_read_response(scpi, response, timeout);
g_string_free(response, TRUE);
return ret; /* On timeout truncate the buffer and send the partial response
} * instead of getting stuck on timeouts...
if (ret > 0) */
timeout = g_get_monotonic_time() + scpi->read_timeout_us; if (ret == SR_ERR_TIMEOUT) {
datalen = oldlen;
break;
}
if (ret < 0) {
g_mutex_unlock(&scpi->scpi_mutex);
g_string_free(response, TRUE);
return ret;
}
if (ret > 0)
timeout = g_get_monotonic_time() + scpi->read_timeout_us;
} while (response->len < (unsigned long)(datalen));
} }
g_mutex_unlock(&scpi->scpi_mutex); g_mutex_unlock(&scpi->scpi_mutex);