]> sigrok.org Git - libsigrok.git/commitdiff
scpi: Add support for arbitray/definite length block data retrieval
authorStefan Brüns <redacted>
Sun, 1 May 2016 03:20:39 +0000 (05:20 +0200)
committerUwe Hermann <redacted>
Mon, 16 May 2016 21:35:10 +0000 (23:35 +0200)
Binary block data is specified in IEEE 488.2. First character is '#',
followed by a single ascii digit denoting the the number of digits needed
for the length specification. Length is given in bytes.

This allows drivers to replace retrieval of comma separated ASCII values
with binary formats. See bug #791.

src/scpi.h
src/scpi/scpi.c

index c70bd930fd5b2e42d284be08973516790b68ad2c..cfef40a0c6382a9b1933cb3f20752ea8fc16cf7b 100644 (file)
@@ -128,6 +128,10 @@ SR_PRIV int sr_scpi_get_floatv(struct sr_scpi_dev_inst *scpi,
                        const char *command, GArray **scpi_response);
 SR_PRIV int sr_scpi_get_uint8v(struct sr_scpi_dev_inst *scpi,
                        const char *command, GArray **scpi_response);
+SR_PRIV int sr_scpi_get_data(struct sr_scpi_dev_inst *scpi,
+                       const char *command, GString **scpi_response);
+SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi,
+                       const char *command, GByteArray **scpi_response);
 SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi,
                        struct sr_scpi_hw_info **scpi_response);
 SR_PRIV void sr_scpi_hw_info_free(struct sr_scpi_hw_info *hw_info);
index 9f5dba43ae493a5b4558b1970186c07ddd69b417..e54427ff0b3445c107a0e46ee24cb1cb2fb4ac97 100644 (file)
@@ -387,11 +387,40 @@ SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi)
 SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
                               const char *command, char **scpi_response)
 {
-       char buf[256];
+       GString *response;
+       response = g_string_sized_new(1024);
+
+       if (sr_scpi_get_data(scpi, command, &response) != SR_OK) {
+               if (response)
+                       g_string_free(response, TRUE);
+               return SR_ERR;
+       }
+
+       /* Get rid of trailing linefeed if present */
+       if (response->len >= 1 && response->str[response->len - 1] == '\n')
+               g_string_truncate(response, response->len - 1);
+
+       /* Get rid of trailing carriage return if present */
+       if (response->len >= 1 && response->str[response->len - 1] == '\r')
+               g_string_truncate(response, response->len - 1);
+
+       sr_spew("Got response: '%.70s', length %" G_GSIZE_FORMAT ".",
+               response->str, response->len);
+
+       *scpi_response = g_string_free(response, FALSE);
+
+       return SR_OK;
+}
+
+SR_PRIV int sr_scpi_get_data(struct sr_scpi_dev_inst *scpi,
+                            const char *command, GString **scpi_response)
+{
        int len;
        GString *response;
        gint64 laststart;
        unsigned int elapsed_ms;
+       unsigned int offset = 0;
+       int space;
 
        if (command)
                if (sr_scpi_send(scpi, command) != SR_OK)
@@ -402,41 +431,32 @@ SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
 
        laststart = g_get_monotonic_time();
 
-       response = g_string_new("");
+       response = *scpi_response;
 
-       *scpi_response = NULL;
+       offset = response->len;
 
        while (!sr_scpi_read_complete(scpi)) {
-               len = sr_scpi_read_data(scpi, buf, sizeof(buf));
+               space = response->allocated_len - response->len;
+               if (space < 128) {
+                       g_string_set_size(response, response->len + 1024);
+                       space = response->allocated_len - response->len;
+               }
+               len = sr_scpi_read_data(scpi, &response->str[offset], space);
                if (len < 0) {
                        sr_err("Incompletely read SCPI response.");
-                       g_string_free(response, TRUE);
                        return SR_ERR;
                } else if (len > 0) {
                        laststart = g_get_monotonic_time();
                }
-               g_string_append_len(response, buf, len);
+               offset += len;
+               g_string_set_size(response, offset);
                elapsed_ms = (g_get_monotonic_time() - laststart) / 1000;
                if (elapsed_ms >= scpi->read_timeout_ms) {
                        sr_err("Timed out waiting for SCPI response.");
-                       g_string_free(response, TRUE);
                        return SR_ERR;
                }
        }
 
-       /* Get rid of trailing linefeed if present */
-       if (response->len >= 1 && response->str[response->len - 1] == '\n')
-               g_string_truncate(response, response->len - 1);
-
-       /* Get rid of trailing carriage return if present */
-       if (response->len >= 1 && response->str[response->len - 1] == '\r')
-               g_string_truncate(response, response->len - 1);
-
-       sr_spew("Got response: '%.70s', length %" G_GSIZE_FORMAT ".",
-               response->str, response->len);
-
-       *scpi_response = g_string_free(response, FALSE);
-
        return SR_OK;
 }
 
@@ -703,6 +723,79 @@ SR_PRIV int sr_scpi_get_uint8v(struct sr_scpi_dev_inst *scpi,
 
        return ret;
 }
+/**
+ * Send a SCPI command, read the reply, parse it as binary data with a
+ * "definite length block" header and store the as an result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK upon successfully parsing all values, SR_ERR* upon a parsing
+ *         error or upon no response. The allocated response must be freed by
+ *         the caller in the case of an SR_OK as well as in the case of
+ *         parsing error.
+ */
+SR_PRIV int sr_scpi_get_block(struct sr_scpi_dev_inst *scpi,
+                              const char *command, GByteArray **scpi_response)
+{
+       int ret;
+       GString* response;
+
+       char buf[10] = { 0 };
+       long llen;
+       long datalen;
+
+       response = g_string_sized_new(1024);
+       *scpi_response = NULL;
+
+       ret = sr_scpi_get_data(scpi, command, &response);
+       if (ret != SR_OK) {
+               g_string_free(response, TRUE);
+               return ret;
+       }
+
+       if (response->str[0] != '#') {
+               g_string_free(response, TRUE);
+               return SR_ERR_DATA;
+       }
+
+       buf[0] = response->str[1];
+       ret = sr_atol(buf, &llen);
+       if ((ret != SR_OK) || (llen == 0)) {
+               g_string_free(response, TRUE);
+               return ret;
+       }
+
+       memcpy(buf, &response->str[2], llen);
+       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 (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) {
+                       g_string_free(response, TRUE);
+                       return ret;
+               }
+       }
+
+       *scpi_response = g_byte_array_new_take(
+               (guint8*)g_string_free(response, FALSE), datalen);
+
+       return ret;
+}
+
 
 /**
  * Send the *IDN? SCPI command, receive the reply, parse it and store the