]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/rigol-dg/api.c
uni-t-ut181a: silence compiler warning, use of uninitialized variable
[libsigrok.git] / src / hardware / rigol-dg / api.c
index ddc0c72db56e296a61ff2bdb467cdd8cd5554c95..e8a3aadc8acd4ea2fd8edaa2824bb114abb42f31 100644 (file)
@@ -52,14 +52,116 @@ static const double phase_min_max_step[] = { 0.0, 360.0, 0.001 };
 
 #define WAVEFORM_DEFAULT WFO_FREQUENCY | WFO_AMPLITUDE | WFO_OFFSET | WFO_PHASE
 
+static const struct waveform_spec dg810_waveforms[] = {
+       { "SIN",   WF_SINE,     1.0E-6,  10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6,   5.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,   0.2E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6,   5.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6,   5.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,  100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0,   0.0E+0, 0.0E-0, WFO_OFFSET },
+};
+
+static const struct channel_spec dg811_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg810_waveforms) },
+};
+
+static const struct channel_spec dg812_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg810_waveforms) },
+       { "CH2",  ARRAY_AND_SIZE(dg810_waveforms) },
+};
+
+static const struct waveform_spec dg820_waveforms[] = {
+       { "SIN",   WF_SINE,     1.0E-6,  25.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6,  10.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,   0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6,  10.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6,  10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,  100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0,   0.0E+0, 0.0E-0, WFO_OFFSET },
+};
+
+static const struct channel_spec dg821_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg820_waveforms) },
+};
+
+static const struct channel_spec dg822_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg820_waveforms) },
+       { "CH2",  ARRAY_AND_SIZE(dg820_waveforms) },
+};
+
+static const struct waveform_spec dg830_waveforms[] = {
+       { "SIN",   WF_SINE,     1.0E-6,  35.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6,  10.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,   1.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6,  10.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6,  10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,  100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0,   0.0E+0, 0.0E-0, WFO_OFFSET },
+};
+
+static const struct channel_spec dg831_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg830_waveforms) },
+};
+
+static const struct channel_spec dg832_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg830_waveforms) },
+       { "CH2",  ARRAY_AND_SIZE(dg830_waveforms) },
+};
+
+static const struct waveform_spec dg952_waveforms[] = {
+       { "SIN",   WF_SINE,     1.0E-6,  50.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6,  15.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,   1.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6,  15.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6,  15.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,  100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0,   0.0E+0, 0.0E-0, WFO_OFFSET },
+};
+
+static const struct channel_spec dg952_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg952_waveforms) },
+       { "CH2",  ARRAY_AND_SIZE(dg952_waveforms) },
+};
+
+static const struct waveform_spec dg972_waveforms[] = {
+       { "SIN",   WF_SINE,     1.0E-6,  70.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6,  20.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,   1.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6,  20.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6,  20.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,  100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0,   0.0E+0, 0.0E-0, WFO_OFFSET },
+};
+
+static const struct channel_spec dg972_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg972_waveforms) },
+       { "CH2",  ARRAY_AND_SIZE(dg972_waveforms) },
+};
+
+static const struct waveform_spec dg992_waveforms[] = {
+       { "SIN",   WF_SINE,     1.0E-6, 100.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6,  25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,   2.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6,  25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6,  25.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,  100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0,   0.0E+0, 0.0E-0, WFO_OFFSET },
+};
+
+static const struct channel_spec dg992_channels[] = {
+       { "CH1",  ARRAY_AND_SIZE(dg992_waveforms) },
+       { "CH2",  ARRAY_AND_SIZE(dg992_waveforms) },
+};
+
 static const struct waveform_spec dg1022z_waveforms[] = {
-       { "SIN",   WF_SINE,     1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT },
-       { "SQU",   WF_SQUARE,   1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
-       { "RAMP",  WF_RAMP,     1.0E-6, 0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
-       { "PULSE", WF_PULSE,    1.0E-6, 1.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
-       { "USER",  WF_ARB,      1.0E-6, 1.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
-       { "NOISE", WF_NOISE,    2.5E+7, 2.5E+7, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
-       { "DC",    WF_DC,       0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
+       { "SIN",   WF_SINE,     1.0E-6,  25.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6,  25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,   0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6,  15.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6,  10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,   25.0E+6,  25.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0,   0.0E+0, 0.0E-0, WFO_OFFSET },
 };
 
 static const struct channel_spec dg1022z_channels[] = {
@@ -68,13 +170,13 @@ static const struct channel_spec dg1022z_channels[] = {
 };
 
 static const struct waveform_spec dg1032z_waveforms[] = {
-       { "SIN",   WF_SINE,     1.0E-6, 3.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
-       { "SQU",   WF_SQUARE,   1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
-       { "RAMP",  WF_RAMP,     1.0E-6, 0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
-       { "PULSE", WF_PULSE,    1.0E-6, 1.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
-       { "USER",  WF_ARB,      1.0E-6, 1.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
-       { "NOISE", WF_NOISE,    3.0E+7, 3.0E+7, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
-       { "DC",    WF_DC,       0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
+       { "SIN",   WF_SINE,     1.0E-6, 30.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,  0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6, 15.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,   30.0E+6, 30.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0 , 0.0E+0, 0.0E-0, WFO_OFFSET },
 };
 
 static const struct channel_spec dg1032z_channels[] = {
@@ -83,13 +185,13 @@ static const struct channel_spec dg1032z_channels[] = {
 };
 
 static const struct waveform_spec dg1062z_waveforms[] = {
-       { "SIN",   WF_SINE,     1.0E-6, 6.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
-       { "SQU",   WF_SQUARE,   1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
-       { "RAMP",  WF_RAMP,     1.0E-6, 1.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
-       { "PULSE", WF_PULSE,    1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
-       { "USER",  WF_ARB,      1.0E-6, 2.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
-       { "NOISE", WF_NOISE,    6.0E+7, 6.0E+7, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
-       { "DC",    WF_DC,       0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
+       { "SIN",   WF_SINE,     1.0E-6, 60.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "SQU",   WF_SQUARE,   1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "RAMP",  WF_RAMP,     1.0E-6,  1.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "PULSE", WF_PULSE,    1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
+       { "USER",  WF_ARB,      1.0E-6, 20.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
+       { "NOISE", WF_NOISE,   60.0E+6, 60.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
+       { "DC",    WF_DC,       0.0E-0,  0.0E+0, 0.0E-0, WFO_OFFSET },
 };
 
 static const struct channel_spec dg1062z_channels[] = {
@@ -126,6 +228,60 @@ static const struct scpi_command cmdset_dg1000z[] = {
 };
 
 static const struct device_spec device_models[] = {
+       { "Rigol Technologies", "DG811",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg811_channels),
+               cmdset_dg1000z,
+       },
+       { "Rigol Technologies", "DG812",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg812_channels),
+               cmdset_dg1000z,
+       },
+       { "Rigol Technologies", "DG821",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg821_channels),
+               cmdset_dg1000z,
+       },
+       { "Rigol Technologies", "DG822",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg822_channels),
+               cmdset_dg1000z,
+       },
+       { "Rigol Technologies", "DG831",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg831_channels),
+               cmdset_dg1000z,
+       },
+       { "Rigol Technologies", "DG832",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg832_channels),
+               cmdset_dg1000z,
+       },
+       { "Rigol Technologies", "DG952",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg952_channels),
+               cmdset_dg1000z,
+       },
+       { "Rigol Technologies", "DG972",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg972_channels),
+               cmdset_dg1000z,
+       },
+       { "Rigol Technologies", "DG992",
+               ARRAY_AND_SIZE(dg1000z_devopts),
+               ARRAY_AND_SIZE(dg1000z_devopts_cg),
+               ARRAY_AND_SIZE(dg992_channels),
+               cmdset_dg1000z,
+       },
        { "Rigol Technologies", "DG1022Z",
                ARRAY_AND_SIZE(dg1000z_devopts),
                ARRAY_AND_SIZE(dg1000z_devopts_cg),
@@ -146,6 +302,27 @@ static const struct device_spec device_models[] = {
        },
 };
 
+static void check_device_quirks(struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       gboolean is_8xx, is_9xx;
+
+       devc = sdi->priv;
+
+       /*
+        * Check for counter issue in DG800/DG900 units...
+        *
+        * TODO: Add firmware version check if Rigol fixes this issue
+        *       in future firmware versions.
+        */
+       is_8xx = g_ascii_strncasecmp(sdi->model, "DG8", strlen("DG8")) == 0;
+       is_9xx = g_ascii_strncasecmp(sdi->model, "DG9", strlen("DG9")) == 0;
+       if (is_8xx || is_9xx) {
+               devc->quirks |= RIGOL_DG_COUNTER_BUG;
+               devc->quirks |= RIGOL_DG_COUNTER_CH2_CONFLICT;
+       }
+}
+
 static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
 {
        struct sr_dev_inst *sdi;
@@ -226,6 +403,9 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
 
        sr_scpi_hw_info_free(hw_info);
 
+       /* Check for device/firmware specific issues. */
+       check_device_quirks(sdi);
+
        return sdi;
 
 error:
@@ -334,6 +514,8 @@ static int config_get(uint32_t key, GVariant **data,
                                *data = g_variant_new_double(ch_status->phase);
                        break;
                case SR_CONF_DUTY_CYCLE:
+                       if ((ret = rigol_dg_get_channel_state(sdi, cg)) != SR_OK)
+                               break;
                        if (ch_status->wf == WF_SQUARE) {
                                cmd = PSG_CMD_GET_DCYCL_SQUARE;
                        } else if (ch_status->wf == WF_PULSE) {
@@ -571,6 +753,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
        struct sr_scpi_dev_inst *scpi;
        const char *cmd;
        char *response;
+       GVariant *data;
+       gboolean need_quirk;
+       gboolean ch_active;
        int ret;
 
        if (!sdi)
@@ -579,6 +764,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
        devc = sdi->priv;
        scpi = sdi->conn;
        response = NULL;
+       data = NULL;
        ret = SR_OK;
 
        if (!scpi)
@@ -594,15 +780,48 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
                        devc->counter_enabled = TRUE;
                else
                        devc->counter_enabled = FALSE;
+               g_free(response);
 
                if (!devc->counter_enabled) {
-                       /* Enable counter if it was not already running. */
+                       /*
+                        * Enable counter if it was not already running.
+                        * Some devices cannot use channel 2 and the counter
+                        * at the same time. Some cannot respond right after
+                        * enabling the counter and need a delay.
+                        */
+
+                       need_quirk = devc->quirks & RIGOL_DG_COUNTER_CH2_CONFLICT;
+                       need_quirk &= devc->device->num_channels > 1;
+                       if (need_quirk) {
+                               sr_scpi_get_opc(scpi);
+                               ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
+                                       PSG_CMD_SELECT_CHANNEL, "2",
+                                       &data, G_VARIANT_TYPE_BOOLEAN,
+                                       PSG_CMD_GET_ENABLED, "2");
+                               if (ret != SR_OK)
+                                       return SR_ERR_NA;
+                               ch_active = g_variant_get_boolean(data);
+                               g_variant_unref(data);
+                               if (ch_active) {
+                                       sr_scpi_get_opc(scpi);
+                                       ret = sr_scpi_cmd(sdi, devc->cmdset,
+                                               PSG_CMD_SELECT_CHANNEL, "2",
+                                               PSG_CMD_SET_DISABLE, "2");
+                                       if (ret != SR_OK)
+                                               return SR_ERR_NA;
+                               }
+                       }
+
                        cmd = sr_scpi_cmd_get(devc->cmdset,
                                        PSG_CMD_COUNTER_SET_ENABLE);
                        if (!cmd)
                                return SR_ERR_BUG;
                        sr_scpi_get_opc(scpi);
                        ret = sr_scpi_send(scpi, cmd);
+
+                       need_quirk = devc->quirks & RIGOL_DG_COUNTER_BUG;
+                       if (need_quirk)
+                               g_usleep(RIGOL_DG_COUNTER_BUG_DELAY);
                }
        }
 
@@ -616,8 +835,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
                }
        }
 
-       g_free(response);
-
        return ret;
 }
 
@@ -639,10 +856,13 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi)
        if (cmd && *cmd && !devc->counter_enabled) {
                /*
                 * If counter was not running when acquisiton started,
-                * turn it off now...
+                * turn it off now. Some devices need a delay after
+                * disabling the counter.
                 */
                sr_scpi_get_opc(scpi);
                ret = sr_scpi_send(scpi, cmd);
+               if (devc->quirks & RIGOL_DG_COUNTER_BUG)
+                       g_usleep(RIGOL_DG_COUNTER_BUG_DELAY);
        }
 
        sr_scpi_source_remove(sdi->session, scpi);