]> sigrok.org Git - libsigrok.git/blob - src/hardware/rigol-dg/api.c
rigol-dg: reduce redundancy in malloc() calls
[libsigrok.git] / src / hardware / rigol-dg / api.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2020 Timo Kokkonen <tjko@iki.fi>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <string.h>
22 #include "scpi.h"
23 #include "protocol.h"
24
25 static struct sr_dev_driver rigol_dg_driver_info;
26
27 static const uint32_t scanopts[] = {
28         SR_CONF_CONN,
29 };
30
31 static const uint32_t drvopts[] = {
32         SR_CONF_SIGNAL_GENERATOR,
33 };
34
35 static const uint32_t dg1000z_devopts[] = {
36         SR_CONF_CONTINUOUS,
37         SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
38         SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
39 };
40
41 static const uint32_t dg1000z_devopts_cg[] = {
42         SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
43         SR_CONF_PATTERN_MODE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
44         SR_CONF_OUTPUT_FREQUENCY | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
45         SR_CONF_AMPLITUDE | SR_CONF_GET | SR_CONF_SET,
46         SR_CONF_OFFSET | SR_CONF_GET | SR_CONF_SET,
47         SR_CONF_PHASE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
48         SR_CONF_DUTY_CYCLE | SR_CONF_GET | SR_CONF_SET,
49 };
50
51 static const double phase_min_max_step[] = { 0.0, 360.0, 0.001 };
52
53 #define WAVEFORM_DEFAULT WFO_FREQUENCY | WFO_AMPLITUDE | WFO_OFFSET | WFO_PHASE
54
55 static const struct waveform_spec dg1022z_waveforms[] = {
56         { "SIN",   WF_SINE,     1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT },
57         { "SQU",   WF_SQUARE,   1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
58         { "RAMP",  WF_RAMP,     1.0E-6, 0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
59         { "PULSE", WF_PULSE,    1.0E-6, 1.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
60         { "USER",  WF_ARB,      1.0E-6, 1.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
61         { "NOISE", WF_NOISE,    2.5E+7, 2.5E+7, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
62         { "DC",    WF_DC,       0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
63 };
64
65 static const struct channel_spec dg1022z_channels[] = {
66         { "CH1",  ARRAY_AND_SIZE(dg1022z_waveforms) },
67         { "CH2",  ARRAY_AND_SIZE(dg1022z_waveforms) },
68 };
69
70 static const struct waveform_spec dg1032z_waveforms[] = {
71         { "SIN",   WF_SINE,     1.0E-6, 3.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
72         { "SQU",   WF_SQUARE,   1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
73         { "RAMP",  WF_RAMP,     1.0E-6, 0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
74         { "PULSE", WF_PULSE,    1.0E-6, 1.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
75         { "USER",  WF_ARB,      1.0E-6, 1.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
76         { "NOISE", WF_NOISE,    3.0E+7, 3.0E+7, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
77         { "DC",    WF_DC,       0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
78 };
79
80 static const struct channel_spec dg1032z_channels[] = {
81         { "CH1",  ARRAY_AND_SIZE(dg1032z_waveforms) },
82         { "CH2",  ARRAY_AND_SIZE(dg1032z_waveforms) },
83 };
84
85 static const struct waveform_spec dg1062z_waveforms[] = {
86         { "SIN",   WF_SINE,     1.0E-6, 6.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
87         { "SQU",   WF_SQUARE,   1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
88         { "RAMP",  WF_RAMP,     1.0E-6, 1.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
89         { "PULSE", WF_PULSE,    1.0E-6, 2.5E+7, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
90         { "USER",  WF_ARB,      1.0E-6, 2.0E+7, 1.0E-6, WAVEFORM_DEFAULT },
91         { "NOISE", WF_NOISE,    6.0E+7, 6.0E+7, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
92         { "DC",    WF_DC,       0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
93 };
94
95 static const struct channel_spec dg1062z_channels[] = {
96         { "CH1",  ARRAY_AND_SIZE(dg1062z_waveforms) },
97         { "CH2",  ARRAY_AND_SIZE(dg1062z_waveforms) },
98 };
99
100 static const struct scpi_command cmdset_dg1000z[] = {
101         { PSG_CMD_SETUP_LOCAL, "SYST:KLOC:STATE OFF", },
102 /*      { PSG_CMD_SELECT_CHANNEL, "SYST:CHAN:CUR CH%s", }, */
103         { PSG_CMD_GET_CHANNEL, "SYST:CHAN:CUR?", },
104         { PSG_CMD_GET_ENABLED, "OUTP%s:STATE?", },
105         { PSG_CMD_SET_ENABLE, "OUTP%s:STATE ON", },
106         { PSG_CMD_SET_DISABLE, "OUTP%s:STATE OFF", },
107         { PSG_CMD_GET_SOURCE, "SOUR%s:APPL?", },
108         { PSG_CMD_SET_SOURCE, "SOUR%s:APPL:%s", },
109         { PSG_CMD_GET_FREQUENCY, "SOUR%s:FREQ?", },
110         { PSG_CMD_SET_FREQUENCY, "SOUR%s:FREQ %f", },
111         { PSG_CMD_GET_AMPLITUDE, "SOUR%s:VOLT?", },
112         { PSG_CMD_SET_AMPLITUDE, "SOUR%s:VOLT %f", },
113         { PSG_CMD_GET_OFFSET, "SOUR%s:VOLT:OFFS?", },
114         { PSG_CMD_SET_OFFSET, "SOUR%s:VOLT:OFFS %f", },
115         { PSG_CMD_GET_PHASE, "SOUR%s:PHAS?", },
116         { PSG_CMD_SET_PHASE, "SOUR%s:PHAS %f", },
117         { PSG_CMD_GET_DCYCL_PULSE, "SOUR%s:FUNC:PULS:DCYC?", },
118         { PSG_CMD_SET_DCYCL_PULSE, "SOUR%s:FUNC:PULS:DCYC %f", },
119         { PSG_CMD_GET_DCYCL_SQUARE, "SOUR%s:FUNC:SQU:DCYC?", },
120         { PSG_CMD_SET_DCYCL_SQUARE, "SOUR%s:FUNC:SQU:DCYC %f", },
121         { PSG_CMD_COUNTER_GET_ENABLED, "COUN:STAT?", },
122         { PSG_CMD_COUNTER_SET_ENABLE, "COUN:STAT ON", },
123         { PSG_CMD_COUNTER_SET_DISABLE, "COUN:STAT OFF", },
124         { PSG_CMD_COUNTER_MEASURE, "COUN:MEAS?", },
125         ALL_ZERO
126 };
127
128 static const struct device_spec device_models[] = {
129         { "Rigol Technologies", "DG1022Z",
130                 ARRAY_AND_SIZE(dg1000z_devopts),
131                 ARRAY_AND_SIZE(dg1000z_devopts_cg),
132                 ARRAY_AND_SIZE(dg1022z_channels),
133                 cmdset_dg1000z,
134         },
135         { "Rigol Technologies", "DG1032Z",
136                 ARRAY_AND_SIZE(dg1000z_devopts),
137                 ARRAY_AND_SIZE(dg1000z_devopts_cg),
138                 ARRAY_AND_SIZE(dg1032z_channels),
139                 cmdset_dg1000z,
140         },
141         { "Rigol Technologies", "DG1062Z",
142                 ARRAY_AND_SIZE(dg1000z_devopts),
143                 ARRAY_AND_SIZE(dg1000z_devopts_cg),
144                 ARRAY_AND_SIZE(dg1062z_channels),
145                 cmdset_dg1000z,
146         },
147 };
148
149 static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
150 {
151         struct sr_dev_inst *sdi;
152         struct dev_context *devc;
153         struct sr_scpi_hw_info *hw_info;
154         const struct device_spec *device;
155         const struct scpi_command *cmdset;
156         struct sr_channel *ch;
157         struct sr_channel_group *cg;
158         const char *command;
159         unsigned int i, ch_idx;
160         char tmp[16];
161
162         sdi = NULL;
163         devc = NULL;
164         hw_info = NULL;
165
166         if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK)
167                 goto error;
168
169         device = NULL;
170         for (i = 0; i < ARRAY_SIZE(device_models); i++) {
171                 if (g_ascii_strcasecmp(hw_info->manufacturer,
172                                 device_models[i].vendor) != 0)
173                         continue;
174                 if (g_ascii_strcasecmp(hw_info->model,
175                                 device_models[i].model) != 0)
176                         continue;
177                 device = &device_models[i];
178                 cmdset = device_models[i].cmdset;
179                 break;
180         }
181         if (!device)
182                 goto error;
183
184         sdi = g_malloc0(sizeof(*sdi));
185         sdi->vendor = g_strdup(hw_info->manufacturer);
186         sdi->model = g_strdup(hw_info->model);
187         sdi->version = g_strdup(hw_info->firmware_version);
188         sdi->serial_num = g_strdup(hw_info->serial_number);
189         sdi->conn = scpi;
190         sdi->driver = &rigol_dg_driver_info;
191         sdi->inst_type = SR_INST_SCPI;
192
193         devc = g_malloc0(sizeof(*devc));
194         devc->cmdset = cmdset;
195         devc->device = device;
196         devc->ch_status = g_malloc0((device->num_channels + 1) *
197                         sizeof(devc->ch_status[0]));
198         sr_sw_limits_init(&devc->limits);
199         sdi->priv = devc;
200
201         /* Create channel group and channel for each device channel. */
202         ch_idx = 0;
203         for (i = 0; i < device->num_channels; i++) {
204                 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE,
205                                 device->channels[i].name);
206                 cg = g_malloc0(sizeof(*cg));
207                 snprintf(tmp, sizeof(tmp), "%u", i + 1);
208                 cg->name = g_strdup(tmp);
209                 cg->channels = g_slist_append(cg->channels, ch);
210
211                 sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
212         }
213
214         /* Create channels for the frequency counter output. */
215         ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "FREQ1");
216         ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "PERIOD1");
217         ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "DUTY1");
218         ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "WIDTH1");
219
220         /* Put device back to "local" mode, in case only a scan was done... */
221         command = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_SETUP_LOCAL);
222         if (command && *command) {
223                 sr_scpi_get_opc(scpi);
224                 sr_scpi_send(scpi, command);
225         }
226
227         sr_scpi_hw_info_free(hw_info);
228
229         return sdi;
230
231 error:
232         sr_scpi_hw_info_free(hw_info);
233         g_free(devc);
234         sr_dev_inst_free(sdi);
235
236         return NULL;
237 }
238
239 static GSList *scan(struct sr_dev_driver *di, GSList *options)
240 {
241         return sr_scpi_scan(di->context, options, probe_device);
242 }
243
244 static int dev_open(struct sr_dev_inst *sdi)
245 {
246         return sr_scpi_open(sdi->conn);
247 }
248
249 static int dev_close(struct sr_dev_inst *sdi)
250 {
251         struct dev_context *devc;
252         struct sr_scpi_dev_inst *scpi;
253         const char *command;
254
255         devc = sdi->priv;
256         scpi = sdi->conn;
257         if (!scpi)
258                 return SR_ERR_BUG;
259
260         /* Put unit back to "local" mode. */
261         command = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_SETUP_LOCAL);
262         if (command && *command) {
263                 sr_scpi_get_opc(scpi);
264                 sr_scpi_send(scpi, command);
265         }
266
267         return sr_scpi_close(sdi->conn);
268 }
269
270 static int config_get(uint32_t key, GVariant **data,
271         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
272 {
273         struct dev_context *devc;
274         struct sr_scpi_dev_inst *scpi;
275         struct sr_channel *ch;
276         struct channel_status *ch_status;
277         const struct sr_key_info *kinfo;
278         uint32_t cmd;
279         int ret;
280
281         if (!sdi || !data)
282                 return SR_ERR_ARG;
283
284         devc = sdi->priv;
285         scpi = sdi->conn;
286         ret = SR_OK;
287         kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
288
289         if (!cg) {
290                 switch (key) {
291                 case SR_CONF_LIMIT_SAMPLES:
292                 case SR_CONF_LIMIT_MSEC:
293                         ret = sr_sw_limits_config_get(&devc->limits, key, data);
294                         break;
295                 default:
296                         sr_dbg("%s: Unsupported key: %d (%s)", __func__,
297                                 (int)key, (kinfo ? kinfo->name : "unknown"));
298                         ret = SR_ERR_NA;
299                         break;
300                 }
301         } else {
302                 ch = cg->channels->data;
303                 ch_status = &devc->ch_status[ch->index];
304
305                 switch (key) {
306                 case SR_CONF_ENABLED:
307                         sr_scpi_get_opc(scpi);
308                         ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
309                                 PSG_CMD_SELECT_CHANNEL, cg->name, data,
310                                 G_VARIANT_TYPE_BOOLEAN, PSG_CMD_GET_ENABLED,
311                                 cg->name);
312                         break;
313                 case SR_CONF_PATTERN_MODE:
314                         if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK) {
315                                 *data = g_variant_new_string(
316                                          rigol_dg_waveform_to_string(
317                                                  ch_status->wf));
318                         }
319                         break;
320                 case SR_CONF_OUTPUT_FREQUENCY:
321                         if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
322                                 *data = g_variant_new_double(ch_status->freq);
323                         break;
324                 case SR_CONF_AMPLITUDE:
325                         if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
326                                 *data = g_variant_new_double(ch_status->ampl);
327                         break;
328                 case SR_CONF_OFFSET:
329                         if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
330                                 *data = g_variant_new_double(ch_status->offset);
331                         break;
332                 case SR_CONF_PHASE:
333                         if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
334                                 *data = g_variant_new_double(ch_status->phase);
335                         break;
336                 case SR_CONF_DUTY_CYCLE:
337                         if (ch_status->wf == WF_SQUARE) {
338                                 cmd = PSG_CMD_GET_DCYCL_SQUARE;
339                         } else if (ch_status->wf == WF_PULSE) {
340                                 cmd = PSG_CMD_GET_DCYCL_PULSE;
341                         } else {
342                                 ret = SR_ERR_NA;
343                                 break;
344                         }
345                         sr_scpi_get_opc(scpi);
346                         ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
347                                 PSG_CMD_SELECT_CHANNEL, cg->name, data,
348                                 G_VARIANT_TYPE_DOUBLE, cmd, cg->name);
349                         break;
350                 default:
351                         sr_dbg("%s: Unsupported (cg) key: %d (%s)", __func__,
352                                 (int)key, (kinfo ? kinfo->name : "unknown"));
353                         ret = SR_ERR_NA;
354                         break;
355                 }
356         }
357
358         return ret;
359 }
360
361 static int config_set(uint32_t key, GVariant *data,
362         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
363 {
364         struct dev_context *devc;
365         struct sr_scpi_dev_inst *scpi;
366         struct sr_channel *ch;
367         const struct channel_spec *ch_spec;
368         struct channel_status *ch_status;
369         const struct sr_key_info *kinfo;
370         int ret;
371         uint32_t cmd;
372         const char *mode, *mode_name, *new_mode;
373         unsigned int i;
374
375         if (!data || !sdi)
376                 return SR_ERR_ARG;
377
378         devc = sdi->priv;
379         scpi = sdi->conn;
380         kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
381
382         ret = SR_OK;
383
384         if (!cg) {
385                 switch (key) {
386                 case SR_CONF_LIMIT_MSEC:
387                 case SR_CONF_LIMIT_SAMPLES:
388                         ret = sr_sw_limits_config_set(&devc->limits, key, data);
389                         break;
390                 default:
391                         sr_dbg("%s: Unsupported key: %d (%s)", __func__,
392                                 (int)key, (kinfo ? kinfo->name : "unknown"));
393                         ret = SR_ERR_NA;
394                         break;
395                 }
396         } else {
397                 ch = cg->channels->data;
398                 ch_spec = &devc->device->channels[ch->index];
399                 ch_status = &devc->ch_status[ch->index];
400
401                 if ((ret = rigol_dg_get_channel_state(sdi, cg)) != SR_OK)
402                         return ret;
403                 sr_scpi_get_opc(scpi);
404
405                 switch (key) {
406                 case SR_CONF_ENABLED:
407                         if (g_variant_get_boolean(data))
408                                 cmd = PSG_CMD_SET_ENABLE;
409                         else
410                                 cmd = PSG_CMD_SET_DISABLE;
411                         ret = sr_scpi_cmd(sdi, devc->cmdset,
412                                 PSG_CMD_SELECT_CHANNEL, cg->name, cmd, cg->name);
413                         break;
414                 case SR_CONF_PATTERN_MODE:
415                         ret = SR_ERR_NA;
416                         new_mode = NULL;
417                         mode = g_variant_get_string(data, NULL);
418                         for (i = 0; i < ch_spec->num_waveforms; i++) {
419                                 mode_name = rigol_dg_waveform_to_string(
420                                                 ch_spec->waveforms[i].waveform);
421                                 if (g_ascii_strncasecmp(mode, mode_name,
422                                                 strlen(mode_name)) == 0)
423                                         new_mode = ch_spec->waveforms[i].name;
424                         }
425                         if (new_mode)
426                                 ret = sr_scpi_cmd(sdi, devc->cmdset,
427                                         PSG_CMD_SELECT_CHANNEL, cg->name,
428                                         PSG_CMD_SET_SOURCE, cg->name, new_mode);
429                         break;
430                 case SR_CONF_OUTPUT_FREQUENCY:
431                         ret = SR_ERR_NA;
432                         if (!(ch_status->wf_spec->opts & WFO_FREQUENCY))
433                                 break;
434                         ret = sr_scpi_cmd(sdi, devc->cmdset,
435                                 PSG_CMD_SELECT_CHANNEL, cg->name,
436                                 PSG_CMD_SET_FREQUENCY, cg->name,
437                                 g_variant_get_double(data));
438                         break;
439                 case SR_CONF_AMPLITUDE:
440                         ret = SR_ERR_NA;
441                         if (!(ch_status->wf_spec->opts & WFO_AMPLITUDE))
442                                 break;
443                         ret = sr_scpi_cmd(sdi, devc->cmdset,
444                                 PSG_CMD_SELECT_CHANNEL, cg->name,
445                                 PSG_CMD_SET_AMPLITUDE, cg->name,
446                                 g_variant_get_double(data));
447                         break;
448                 case SR_CONF_OFFSET:
449                         ret = SR_ERR_NA;
450                         if (!(ch_status->wf_spec->opts & WFO_OFFSET))
451                                 break;
452                         ret = sr_scpi_cmd(sdi, devc->cmdset,
453                                 PSG_CMD_SELECT_CHANNEL, cg->name,
454                                 PSG_CMD_SET_OFFSET, cg->name,
455                                 g_variant_get_double(data));
456                         break;
457                 case SR_CONF_PHASE:
458                         ret = SR_ERR_NA;
459                         if (!(ch_status->wf_spec->opts & WFO_PHASE))
460                                 break;
461                         ret = sr_scpi_cmd(sdi, devc->cmdset,
462                                 PSG_CMD_SELECT_CHANNEL, cg->name,
463                                 PSG_CMD_SET_PHASE, cg->name,
464                                 g_variant_get_double(data));
465                         break;
466                 case SR_CONF_DUTY_CYCLE:
467                         ret = SR_ERR_NA;
468                         if (!(ch_status->wf_spec->opts & WFO_DUTY_CYCLE))
469                                 break;
470                         if (ch_status->wf == WF_SQUARE)
471                                 cmd = PSG_CMD_SET_DCYCL_SQUARE;
472                         else if (ch_status->wf == WF_PULSE)
473                                 cmd = PSG_CMD_SET_DCYCL_PULSE;
474                         else
475                                 break;
476                         ret = sr_scpi_cmd(sdi, devc->cmdset,
477                                 PSG_CMD_SELECT_CHANNEL, cg->name,
478                                 cmd, cg->name, g_variant_get_double(data));
479                         break;
480                 default:
481                         sr_dbg("%s: Unsupported key: %d (%s)", __func__,
482                                 (int)key, (kinfo ? kinfo->name : "unknown"));
483                         ret = SR_ERR_NA;
484                         break;
485                 }
486         }
487
488         return ret;
489 }
490
491 static int config_list(uint32_t key, GVariant **data,
492         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
493 {
494         struct dev_context *devc;
495         struct sr_channel *ch;
496         const struct channel_spec *ch_spec;
497         const struct waveform_spec *wf_spec;
498         struct channel_status *ch_status;
499         GVariantBuilder *b;
500         unsigned int i;
501         double fspec[3];
502
503         devc = NULL;
504         if (sdi)
505                 devc = sdi->priv;
506
507         if (!cg) {
508                 switch (key) {
509                 case SR_CONF_SCAN_OPTIONS:
510                 case SR_CONF_DEVICE_OPTIONS:
511                         return std_opts_config_list(key, data, sdi, cg,
512                                 ARRAY_AND_SIZE(scanopts),
513                                 ARRAY_AND_SIZE(drvopts),
514                                 (devc && devc->device) ? devc->device->devopts : NULL,
515                                 (devc && devc->device) ? devc->device->num_devopts : 0);
516                 default:
517                         return SR_ERR_NA;
518                 }
519         } else {
520                 if (!devc || !devc->device)
521                         return SR_ERR_ARG;
522                 ch = cg->channels->data;
523                 ch_spec = &devc->device->channels[ch->index];
524                 ch_status = &devc->ch_status[ch->index];
525
526                 switch(key) {
527                 case SR_CONF_DEVICE_OPTIONS:
528                         *data = std_gvar_array_u32(devc->device->devopts_cg,
529                                         devc->device->num_devopts_cg);
530                         break;
531                 case SR_CONF_PATTERN_MODE:
532                         b = g_variant_builder_new(G_VARIANT_TYPE("as"));
533                         for (i = 0; i < ch_spec->num_waveforms; i++) {
534                                 g_variant_builder_add(b, "s",
535                                         rigol_dg_waveform_to_string(
536                                                 ch_spec->waveforms[i].waveform));
537                         }
538                         *data = g_variant_new("as", b);
539                         g_variant_builder_unref(b);
540                         break;
541                 case SR_CONF_OUTPUT_FREQUENCY:
542                         /*
543                          * Frequency range depends on the currently active
544                          * wave form.
545                          */
546                         if (rigol_dg_get_channel_state(sdi, cg) != SR_OK)
547                                 return SR_ERR_NA;
548                         wf_spec = rigol_dg_get_waveform_spec(ch_spec,
549                                         ch_status->wf);
550                         if (!wf_spec)
551                                 return SR_ERR_BUG;
552                         fspec[0] = wf_spec->freq_min;
553                         fspec[1] = wf_spec->freq_max;
554                         fspec[2] = wf_spec->freq_step;
555                         *data = std_gvar_min_max_step_array(fspec);
556                         break;
557                 case SR_CONF_PHASE:
558                         *data = std_gvar_min_max_step_array(phase_min_max_step);
559                         break;
560                 default:
561                         return SR_ERR_NA;
562                 }
563         }
564
565         return SR_OK;
566 }
567
568 static int dev_acquisition_start(const struct sr_dev_inst *sdi)
569 {
570         struct dev_context *devc;
571         struct sr_scpi_dev_inst *scpi;
572         const char *cmd;
573         char *response;
574         int ret;
575
576         if (!sdi)
577                 return SR_ERR_ARG;
578
579         devc = sdi->priv;
580         scpi = sdi->conn;
581         response = NULL;
582         ret = SR_OK;
583
584         if (!scpi)
585                 return SR_ERR_BUG;
586
587         cmd = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_COUNTER_GET_ENABLED);
588         if (cmd && *cmd) {
589                 /* Check if counter is currently enabled. */
590                 ret = sr_scpi_get_string(scpi, cmd, &response);
591                 if (ret != SR_OK)
592                         return SR_ERR_NA;
593                 if (g_ascii_strncasecmp(response, "RUN", strlen("RUN")) == 0)
594                         devc->counter_enabled = TRUE;
595                 else
596                         devc->counter_enabled = FALSE;
597
598                 if (!devc->counter_enabled) {
599                         /* Enable counter if it was not already running. */
600                         cmd = sr_scpi_cmd_get(devc->cmdset,
601                                         PSG_CMD_COUNTER_SET_ENABLE);
602                         if (!cmd)
603                                 return SR_ERR_BUG;
604                         sr_scpi_get_opc(scpi);
605                         ret = sr_scpi_send(scpi, cmd);
606                 }
607         }
608
609         if (ret == SR_OK) {
610                 sr_sw_limits_acquisition_start(&devc->limits);
611                 ret = std_session_send_df_header(sdi);
612                 if (ret == SR_OK) {
613                         ret = sr_scpi_source_add(sdi->session, scpi,
614                                 G_IO_IN, 100, rigol_dg_receive_data,
615                                 (void *)sdi);
616                 }
617         }
618
619         g_free(response);
620
621         return ret;
622 }
623
624 static int dev_acquisition_stop(struct sr_dev_inst *sdi)
625 {
626         struct dev_context *devc;
627         struct sr_scpi_dev_inst *scpi;
628         const char *cmd;
629         int ret;
630
631         if (!sdi)
632                 return SR_ERR_ARG;
633
634         devc = sdi->priv;
635         scpi = sdi->conn;
636         ret = SR_OK;
637
638         cmd = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_COUNTER_SET_DISABLE);
639         if (cmd && *cmd && !devc->counter_enabled) {
640                 /*
641                  * If counter was not running when acquisiton started,
642                  * turn it off now...
643                  */
644                 sr_scpi_get_opc(scpi);
645                 ret = sr_scpi_send(scpi, cmd);
646         }
647
648         sr_scpi_source_remove(sdi->session, scpi);
649         std_session_send_df_end(sdi);
650
651         return ret;
652 }
653
654 static struct sr_dev_driver rigol_dg_driver_info = {
655         .name = "rigol-dg",
656         .longname = "Rigol DG Series",
657         .api_version = 1,
658         .init = std_init,
659         .cleanup = std_cleanup,
660         .scan = scan,
661         .dev_list = std_dev_list,
662         .dev_clear = std_dev_clear,
663         .config_get = config_get,
664         .config_set = config_set,
665         .config_list = config_list,
666         .dev_open = dev_open,
667         .dev_close = dev_close,
668         .dev_acquisition_start = dev_acquisition_start,
669         .dev_acquisition_stop = dev_acquisition_stop,
670         .context = NULL,
671 };
672 SR_REGISTER_DEV_DRIVER(rigol_dg_driver_info);