]> sigrok.org Git - libsigrok.git/commitdiff
scpi: Rephrase length logic in data block reception, comment/group code
authorGerhard Sittig <redacted>
Fri, 30 Dec 2016 12:27:29 +0000 (13:27 +0100)
committerUwe Hermann <redacted>
Sat, 7 Jan 2017 14:51:47 +0000 (15:51 +0100)
Slightly rephrase the SCPI code which parses the responses that carry
(binary) data blocks. Be explicit about NUL termination when parsing the
leading length spec in the response, obsoleting the array initializer.
Add lots of comments and group source code lines to better reflect
what's happening from the protocol's perspective.

Fix the returned error code in the path which reads responses of
excessive length in chunks. The previous implementation detected errors
but always returned code 0 (success).

src/scpi/scpi.c

index efa839de748972052898156ecd1d4f087be3d3b6..f743f64d6b75d5f072cc2e8af8e8195e5b881113 100644 (file)
@@ -743,55 +743,74 @@ SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi,
 {
        int ret;
        GString* response;
-
-       char buf[10] = { 0 };
+       char buf[10];
        long llen;
        long datalen;
 
+       /*
+        * 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);
        *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;
        }
 
+       /*
+        * SCPI protocol data blocks are preceeded with a length spec.
+        * The length spec consists of a '#' marker, one digit which
+        * specifies the character count of the length spec, and the
+        * respective number of characters which specify the data block's
+        * length. Raw data bytes follow (thus one must no longer assume
+        * that the received input stream would be an ASCIIZ string).
+        *
+        * Get the data block length, and strip off the length spec from
+        * the input buffer, leaving just the data bytes.
+        */
        if (response->str[0] != '#') {
                g_string_free(response, TRUE);
                return SR_ERR_DATA;
        }
-
        buf[0] = response->str[1];
+       buf[1] = '\0';
        ret = sr_atol(buf, &llen);
        if ((ret != SR_OK) || (llen == 0)) {
                g_string_free(response, TRUE);
                return ret;
        }
-
        memcpy(buf, &response->str[2], llen);
+       buf[llen] = '\0';
        ret = sr_atol(buf, &datalen);
        if ((ret != SR_OK) || (datalen == 0)) {
                g_string_free(response, TRUE);
                return ret;
        }
-
-       // strip header
        g_string_erase(response, 0, 2 + llen);
 
+       /*
+        * If the initially assumed length does not cover the data block
+        * length, then re-allocate the buffer size to the now known
+        * length, and keep reading more chunks of response data.
+        */
        if (response->len < (unsigned long)(datalen)) {
                int oldlen = response->len;
                g_string_set_size(response, datalen);
                g_string_set_size(response, oldlen);
        }
-
        while (response->len < (unsigned long)(datalen)) {
-               if (sr_scpi_get_data(scpi, NULL, &response) != SR_OK) {
+               ret = sr_scpi_get_data(scpi, NULL, &response);
+               if (ret != SR_OK) {
                        g_string_free(response, TRUE);
                        return ret;
                }
        }
 
+       /* Convert received data to byte array. */
        *scpi_response = g_byte_array_new_take(
                (guint8*)g_string_free(response, FALSE), datalen);