]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/gwinstek-gpd/api.c
gwinstek-gpd: Retry device identification on failure
[libsigrok.git] / src / hardware / gwinstek-gpd / api.c
index 79688afb6595f7efacfde7df6c8e1c868cea96fd..6e745ee48c41cd1fb4fa36a6d10ef54c2769e8f8 100644 (file)
@@ -21,6 +21,8 @@
 #include <string.h>
 #include "protocol.h"
 
+#define IDN_RETRIES 3 /* at least 2 */
+
 static const uint32_t scanopts[] = {
        SR_CONF_CONN,
        SR_CONF_SERIALCOMM,
@@ -60,6 +62,16 @@ static const struct gpd_model models[] = {
                        { { 0, 30, 0.001 }, { 0, 3, 0.001 } },
                },
        },
+       { GPD_3303S, "GPD-3303S",
+               CHANMODE_INDEPENDENT,
+               2,
+               {
+                       /* Channel 1 */
+                       { { 0, 32, 0.001 }, { 0, 3.2, 0.001 } },
+                       /* Channel 2 */
+                       { { 0, 32, 0.001 }, { 0, 3.2, 0.001 } },
+               },
+       },
 };
 
 static GSList *scan(struct sr_dev_driver *di, GSList *options)
@@ -72,7 +84,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
        GSList *l;
        struct sr_serial_dev_inst *serial;
        struct sr_dev_inst *sdi;
-       char reply[50];
+       char reply[100];
        unsigned int i;
        struct dev_context *devc;
        char channel[10];
@@ -102,18 +114,37 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
                return NULL;
        if (!serialcomm)
                serialcomm = "115200/8n1";
-       sr_info("Probing serial port %s.", conn);
+       sr_info("Probing serial port %s @ %s", conn, serialcomm);
        serial = sr_serial_dev_inst_new(conn, serialcomm);
        if (serial_open(serial, SERIAL_RDWR) != SR_OK)
                return NULL;
 
-       serial_flush(serial);
-       gpd_send_cmd(serial, "*IDN?\n");
-       if (gpd_receive_reply(serial, reply, sizeof(reply)) != SR_OK) {
-               sr_err("Device did not reply.");
+       /*
+        * Problem: we need to clear the GPD receive buffer before we
+        * can expect it to process commands correctly.
+        *
+        * Do not just send a newline, since that may cause it to
+        * execute a currently buffered command.
+        *
+        * Solution: Send identification request a few times.
+        * The first should corrupt any previous buffered command if present
+        * and respond with "Invalid Character." or respond directly with
+        * an identification string starting with "GW INSTEK"
+        */
+       for (i = 0; i<IDN_RETRIES; ++i) {
+               /* Request the GPD to identify itself */
+               gpd_send_cmd(serial, "*IDN?\n");
+               if (gpd_receive_reply(serial, reply, sizeof(reply)) == SR_OK) {
+                       if (0 == strncmp(reply, "GW INSTEK", 9 )) {
+                               break;
+                       }
+               }
+       }
+       if (i == IDN_RETRIES) {
+               sr_err("Device did not reply to identification request.");
+               serial_flush(serial);
                goto error;
        }
-       serial_flush(serial);
 
        /*
         * Returned identification string is for example:
@@ -170,8 +201,16 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
        if (sscanf(reply, "%1u%1u%1u%1u%1u%1u%1u%1u", &cc_cv_ch1,
                        &cc_cv_ch2, &track1, &track2, &beep,
                        &devc->output_enabled, &baud1, &baud2) != 8) {
-               sr_err("Invalid reply to STATUS: '%s'.", reply);
-               goto error;
+               /* old firmware (< 2.00?) responds with different format */
+               if (sscanf(reply, "%1u %1u %1u %1u %1u X %1u X", &cc_cv_ch1,
+                          &cc_cv_ch2, &track1, &track2, &beep,
+                          &devc->output_enabled) != 6) {
+                       sr_err("Invalid reply to STATUS: '%s'.", reply);
+                       goto error;
+               }
+               /* ignore remaining two lines of status message */
+               gpd_receive_reply(serial, reply, sizeof(reply));
+               gpd_receive_reply(serial, reply, sizeof(reply));
        }
 
        for (i = 0; i < model->num_channels; ++i) {
@@ -220,7 +259,7 @@ error:
 static int config_get(uint32_t key, GVariant **data,
        const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
 {
-       int ret, channel;
+       int channel;
        const struct dev_context *devc;
        const struct sr_channel *ch;
 
@@ -231,6 +270,9 @@ static int config_get(uint32_t key, GVariant **data,
 
        if (!cg) {
                switch (key) {
+               case SR_CONF_LIMIT_SAMPLES:
+               case SR_CONF_LIMIT_MSEC:
+                       return sr_sw_limits_config_get(&devc->limits, key, data);
                case SR_CONF_CHANNEL_CONFIG:
                        *data = g_variant_new_string(
                                channel_modes[devc->channel_mode]);
@@ -244,7 +286,6 @@ static int config_get(uint32_t key, GVariant **data,
        } else {
                ch = cg->channels->data;
                channel = ch->index;
-               ret = SR_OK;
                switch (key) {
                case SR_CONF_VOLTAGE:
                        *data = g_variant_new_double(
@@ -267,7 +308,7 @@ static int config_get(uint32_t key, GVariant **data,
                }
        }
 
-       return ret;
+       return SR_OK;
 }
 
 static int config_set(uint32_t key, GVariant *data,
@@ -384,7 +425,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
        return SR_OK;
 }
 
-SR_PRIV const struct sr_dev_driver gwinstek_gpd_driver_info = {
+static struct sr_dev_driver gwinstek_gpd_driver_info = {
        .name = "gwinstek-gpd",
        .longname = "GW Instek GPD",
        .api_version = 1,