]> sigrok.org Git - libsigrok.git/blame - src/hardware/rigol-dg/api.c
rigol-ds: improve robustness in samplerate getting code path
[libsigrok.git] / src / hardware / rigol-dg / api.c
CommitLineData
068db0fb
TK
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>
02feeb30
TK
21#include <string.h>
22#include "scpi.h"
068db0fb
TK
23#include "protocol.h"
24
25static struct sr_dev_driver rigol_dg_driver_info;
26
02feeb30
TK
27static const uint32_t scanopts[] = {
28 SR_CONF_CONN,
29};
30
31static const uint32_t drvopts[] = {
32 SR_CONF_SIGNAL_GENERATOR,
33};
34
35static 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
41static 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
51static 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
9ce14905
TK
55static const struct waveform_spec dg810_waveforms[] = {
56 { "SIN", WF_SINE, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
57 { "SQU", WF_SQUARE, 1.0E-6, 5.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
58 { "RAMP", WF_RAMP, 1.0E-6, 0.2E+6, 1.0E-6, WAVEFORM_DEFAULT },
59 { "PULSE", WF_PULSE, 1.0E-6, 5.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
60 { "USER", WF_ARB, 1.0E-6, 5.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
61 { "NOISE", WF_NOISE, 100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
62 { "DC", WF_DC, 0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
63};
64
65static const struct channel_spec dg811_channels[] = {
66 { "CH1", ARRAY_AND_SIZE(dg810_waveforms) },
67};
68
69static const struct channel_spec dg812_channels[] = {
70 { "CH1", ARRAY_AND_SIZE(dg810_waveforms) },
71 { "CH2", ARRAY_AND_SIZE(dg810_waveforms) },
72};
73
74static const struct waveform_spec dg820_waveforms[] = {
75 { "SIN", WF_SINE, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
76 { "SQU", WF_SQUARE, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
77 { "RAMP", WF_RAMP, 1.0E-6, 0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
78 { "PULSE", WF_PULSE, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
79 { "USER", WF_ARB, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
80 { "NOISE", WF_NOISE, 100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
81 { "DC", WF_DC, 0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
82};
83
84static const struct channel_spec dg821_channels[] = {
85 { "CH1", ARRAY_AND_SIZE(dg820_waveforms) },
86};
87
88static const struct channel_spec dg822_channels[] = {
89 { "CH1", ARRAY_AND_SIZE(dg820_waveforms) },
90 { "CH2", ARRAY_AND_SIZE(dg820_waveforms) },
91};
92
93static const struct waveform_spec dg830_waveforms[] = {
94 { "SIN", WF_SINE, 1.0E-6, 35.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
95 { "SQU", WF_SQUARE, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
96 { "RAMP", WF_RAMP, 1.0E-6, 1.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
97 { "PULSE", WF_PULSE, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
98 { "USER", WF_ARB, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
99 { "NOISE", WF_NOISE, 100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
100 { "DC", WF_DC, 0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
101};
102
103static const struct channel_spec dg831_channels[] = {
104 { "CH1", ARRAY_AND_SIZE(dg830_waveforms) },
105};
106
107static const struct channel_spec dg832_channels[] = {
108 { "CH1", ARRAY_AND_SIZE(dg830_waveforms) },
109 { "CH2", ARRAY_AND_SIZE(dg830_waveforms) },
110};
111
112static const struct waveform_spec dg952_waveforms[] = {
113 { "SIN", WF_SINE, 1.0E-6, 50.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
114 { "SQU", WF_SQUARE, 1.0E-6, 15.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
115 { "RAMP", WF_RAMP, 1.0E-6, 1.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
116 { "PULSE", WF_PULSE, 1.0E-6, 15.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
117 { "USER", WF_ARB, 1.0E-6, 15.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
118 { "NOISE", WF_NOISE, 100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
119 { "DC", WF_DC, 0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
120};
121
122static const struct channel_spec dg952_channels[] = {
123 { "CH1", ARRAY_AND_SIZE(dg952_waveforms) },
124 { "CH2", ARRAY_AND_SIZE(dg952_waveforms) },
125};
126
127static const struct waveform_spec dg972_waveforms[] = {
128 { "SIN", WF_SINE, 1.0E-6, 70.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
129 { "SQU", WF_SQUARE, 1.0E-6, 20.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
130 { "RAMP", WF_RAMP, 1.0E-6, 1.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
131 { "PULSE", WF_PULSE, 1.0E-6, 20.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
132 { "USER", WF_ARB, 1.0E-6, 20.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
133 { "NOISE", WF_NOISE, 100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
134 { "DC", WF_DC, 0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
135};
136
137static const struct channel_spec dg972_channels[] = {
138 { "CH1", ARRAY_AND_SIZE(dg972_waveforms) },
139 { "CH2", ARRAY_AND_SIZE(dg972_waveforms) },
140};
141
142static const struct waveform_spec dg992_waveforms[] = {
143 { "SIN", WF_SINE, 1.0E-6, 100.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
144 { "SQU", WF_SQUARE, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
145 { "RAMP", WF_RAMP, 1.0E-6, 2.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
146 { "PULSE", WF_PULSE, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
147 { "USER", WF_ARB, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
148 { "NOISE", WF_NOISE, 100.0E+6, 100.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
149 { "DC", WF_DC, 0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
150};
151
152static const struct channel_spec dg992_channels[] = {
153 { "CH1", ARRAY_AND_SIZE(dg992_waveforms) },
154 { "CH2", ARRAY_AND_SIZE(dg992_waveforms) },
155};
156
02feeb30 157static const struct waveform_spec dg1022z_waveforms[] = {
9ce14905
TK
158 { "SIN", WF_SINE, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
159 { "SQU", WF_SQUARE, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
160 { "RAMP", WF_RAMP, 1.0E-6, 0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
161 { "PULSE", WF_PULSE, 1.0E-6, 15.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
162 { "USER", WF_ARB, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
163 { "NOISE", WF_NOISE, 25.0E+6, 25.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
164 { "DC", WF_DC, 0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
02feeb30
TK
165};
166
167static const struct channel_spec dg1022z_channels[] = {
168 { "CH1", ARRAY_AND_SIZE(dg1022z_waveforms) },
169 { "CH2", ARRAY_AND_SIZE(dg1022z_waveforms) },
170};
171
172static const struct waveform_spec dg1032z_waveforms[] = {
9ce14905
TK
173 { "SIN", WF_SINE, 1.0E-6, 30.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
174 { "SQU", WF_SQUARE, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
175 { "RAMP", WF_RAMP, 1.0E-6, 0.5E+6, 1.0E-6, WAVEFORM_DEFAULT },
176 { "PULSE", WF_PULSE, 1.0E-6, 15.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
177 { "USER", WF_ARB, 1.0E-6, 10.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
178 { "NOISE", WF_NOISE, 30.0E+6, 30.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
179 { "DC", WF_DC, 0.0E-0 , 0.0E+0, 0.0E-0, WFO_OFFSET },
02feeb30
TK
180};
181
182static const struct channel_spec dg1032z_channels[] = {
183 { "CH1", ARRAY_AND_SIZE(dg1032z_waveforms) },
184 { "CH2", ARRAY_AND_SIZE(dg1032z_waveforms) },
185};
186
187static const struct waveform_spec dg1062z_waveforms[] = {
9ce14905
TK
188 { "SIN", WF_SINE, 1.0E-6, 60.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
189 { "SQU", WF_SQUARE, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
190 { "RAMP", WF_RAMP, 1.0E-6, 1.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
191 { "PULSE", WF_PULSE, 1.0E-6, 25.0E+6, 1.0E-6, WAVEFORM_DEFAULT | WFO_DUTY_CYCLE },
192 { "USER", WF_ARB, 1.0E-6, 20.0E+6, 1.0E-6, WAVEFORM_DEFAULT },
193 { "NOISE", WF_NOISE, 60.0E+6, 60.0E+6, 0.0E-0, WFO_AMPLITUDE | WFO_OFFSET },
194 { "DC", WF_DC, 0.0E-0, 0.0E+0, 0.0E-0, WFO_OFFSET },
02feeb30
TK
195};
196
197static const struct channel_spec dg1062z_channels[] = {
198 { "CH1", ARRAY_AND_SIZE(dg1062z_waveforms) },
199 { "CH2", ARRAY_AND_SIZE(dg1062z_waveforms) },
200};
201
202static const struct scpi_command cmdset_dg1000z[] = {
203 { PSG_CMD_SETUP_LOCAL, "SYST:KLOC:STATE OFF", },
204/* { PSG_CMD_SELECT_CHANNEL, "SYST:CHAN:CUR CH%s", }, */
205 { PSG_CMD_GET_CHANNEL, "SYST:CHAN:CUR?", },
206 { PSG_CMD_GET_ENABLED, "OUTP%s:STATE?", },
207 { PSG_CMD_SET_ENABLE, "OUTP%s:STATE ON", },
208 { PSG_CMD_SET_DISABLE, "OUTP%s:STATE OFF", },
209 { PSG_CMD_GET_SOURCE, "SOUR%s:APPL?", },
210 { PSG_CMD_SET_SOURCE, "SOUR%s:APPL:%s", },
211 { PSG_CMD_GET_FREQUENCY, "SOUR%s:FREQ?", },
212 { PSG_CMD_SET_FREQUENCY, "SOUR%s:FREQ %f", },
213 { PSG_CMD_GET_AMPLITUDE, "SOUR%s:VOLT?", },
214 { PSG_CMD_SET_AMPLITUDE, "SOUR%s:VOLT %f", },
215 { PSG_CMD_GET_OFFSET, "SOUR%s:VOLT:OFFS?", },
216 { PSG_CMD_SET_OFFSET, "SOUR%s:VOLT:OFFS %f", },
217 { PSG_CMD_GET_PHASE, "SOUR%s:PHAS?", },
218 { PSG_CMD_SET_PHASE, "SOUR%s:PHAS %f", },
219 { PSG_CMD_GET_DCYCL_PULSE, "SOUR%s:FUNC:PULS:DCYC?", },
220 { PSG_CMD_SET_DCYCL_PULSE, "SOUR%s:FUNC:PULS:DCYC %f", },
221 { PSG_CMD_GET_DCYCL_SQUARE, "SOUR%s:FUNC:SQU:DCYC?", },
222 { PSG_CMD_SET_DCYCL_SQUARE, "SOUR%s:FUNC:SQU:DCYC %f", },
223 { PSG_CMD_COUNTER_GET_ENABLED, "COUN:STAT?", },
224 { PSG_CMD_COUNTER_SET_ENABLE, "COUN:STAT ON", },
225 { PSG_CMD_COUNTER_SET_DISABLE, "COUN:STAT OFF", },
226 { PSG_CMD_COUNTER_MEASURE, "COUN:MEAS?", },
227 ALL_ZERO
228};
229
230static const struct device_spec device_models[] = {
9ce14905
TK
231 { "Rigol Technologies", "DG811",
232 ARRAY_AND_SIZE(dg1000z_devopts),
233 ARRAY_AND_SIZE(dg1000z_devopts_cg),
234 ARRAY_AND_SIZE(dg811_channels),
235 cmdset_dg1000z,
236 },
237 { "Rigol Technologies", "DG812",
238 ARRAY_AND_SIZE(dg1000z_devopts),
239 ARRAY_AND_SIZE(dg1000z_devopts_cg),
240 ARRAY_AND_SIZE(dg812_channels),
241 cmdset_dg1000z,
242 },
243 { "Rigol Technologies", "DG821",
244 ARRAY_AND_SIZE(dg1000z_devopts),
245 ARRAY_AND_SIZE(dg1000z_devopts_cg),
246 ARRAY_AND_SIZE(dg821_channels),
247 cmdset_dg1000z,
248 },
249 { "Rigol Technologies", "DG822",
250 ARRAY_AND_SIZE(dg1000z_devopts),
251 ARRAY_AND_SIZE(dg1000z_devopts_cg),
252 ARRAY_AND_SIZE(dg822_channels),
253 cmdset_dg1000z,
254 },
255 { "Rigol Technologies", "DG831",
256 ARRAY_AND_SIZE(dg1000z_devopts),
257 ARRAY_AND_SIZE(dg1000z_devopts_cg),
258 ARRAY_AND_SIZE(dg831_channels),
259 cmdset_dg1000z,
260 },
261 { "Rigol Technologies", "DG832",
262 ARRAY_AND_SIZE(dg1000z_devopts),
263 ARRAY_AND_SIZE(dg1000z_devopts_cg),
264 ARRAY_AND_SIZE(dg832_channels),
265 cmdset_dg1000z,
266 },
267 { "Rigol Technologies", "DG952",
268 ARRAY_AND_SIZE(dg1000z_devopts),
269 ARRAY_AND_SIZE(dg1000z_devopts_cg),
270 ARRAY_AND_SIZE(dg952_channels),
271 cmdset_dg1000z,
272 },
273 { "Rigol Technologies", "DG972",
274 ARRAY_AND_SIZE(dg1000z_devopts),
275 ARRAY_AND_SIZE(dg1000z_devopts_cg),
276 ARRAY_AND_SIZE(dg972_channels),
277 cmdset_dg1000z,
278 },
279 { "Rigol Technologies", "DG992",
280 ARRAY_AND_SIZE(dg1000z_devopts),
281 ARRAY_AND_SIZE(dg1000z_devopts_cg),
282 ARRAY_AND_SIZE(dg992_channels),
283 cmdset_dg1000z,
284 },
02feeb30
TK
285 { "Rigol Technologies", "DG1022Z",
286 ARRAY_AND_SIZE(dg1000z_devopts),
287 ARRAY_AND_SIZE(dg1000z_devopts_cg),
288 ARRAY_AND_SIZE(dg1022z_channels),
289 cmdset_dg1000z,
290 },
291 { "Rigol Technologies", "DG1032Z",
292 ARRAY_AND_SIZE(dg1000z_devopts),
293 ARRAY_AND_SIZE(dg1000z_devopts_cg),
294 ARRAY_AND_SIZE(dg1032z_channels),
295 cmdset_dg1000z,
296 },
297 { "Rigol Technologies", "DG1062Z",
298 ARRAY_AND_SIZE(dg1000z_devopts),
299 ARRAY_AND_SIZE(dg1000z_devopts_cg),
300 ARRAY_AND_SIZE(dg1062z_channels),
301 cmdset_dg1000z,
302 },
303};
304
b1eb94bb
TK
305static void check_device_quirks(struct sr_dev_inst *sdi)
306{
307 struct dev_context *devc;
308 gboolean is_8xx, is_9xx;
309
310 devc = sdi->priv;
311
312 /*
313 * Check for counter issue in DG800/DG900 units...
314 *
315 * TODO: Add firmware version check if Rigol fixes this issue
316 * in future firmware versions.
317 */
318 is_8xx = g_ascii_strncasecmp(sdi->model, "DG8", strlen("DG8")) == 0;
319 is_9xx = g_ascii_strncasecmp(sdi->model, "DG9", strlen("DG9")) == 0;
320 if (is_8xx || is_9xx) {
321 devc->quirks |= RIGOL_DG_COUNTER_BUG;
322 devc->quirks |= RIGOL_DG_COUNTER_CH2_CONFLICT;
323 }
324}
325
02feeb30 326static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
068db0fb 327{
02feeb30
TK
328 struct sr_dev_inst *sdi;
329 struct dev_context *devc;
330 struct sr_scpi_hw_info *hw_info;
331 const struct device_spec *device;
332 const struct scpi_command *cmdset;
333 struct sr_channel *ch;
334 struct sr_channel_group *cg;
335 const char *command;
336 unsigned int i, ch_idx;
337 char tmp[16];
338
339 sdi = NULL;
340 devc = NULL;
341 hw_info = NULL;
342
343 if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK)
344 goto error;
345
346 device = NULL;
347 for (i = 0; i < ARRAY_SIZE(device_models); i++) {
348 if (g_ascii_strcasecmp(hw_info->manufacturer,
349 device_models[i].vendor) != 0)
350 continue;
351 if (g_ascii_strcasecmp(hw_info->model,
352 device_models[i].model) != 0)
353 continue;
354 device = &device_models[i];
355 cmdset = device_models[i].cmdset;
356 break;
357 }
358 if (!device)
359 goto error;
360
5a030347 361 sdi = g_malloc0(sizeof(*sdi));
02feeb30
TK
362 sdi->vendor = g_strdup(hw_info->manufacturer);
363 sdi->model = g_strdup(hw_info->model);
364 sdi->version = g_strdup(hw_info->firmware_version);
365 sdi->serial_num = g_strdup(hw_info->serial_number);
366 sdi->conn = scpi;
367 sdi->driver = &rigol_dg_driver_info;
368 sdi->inst_type = SR_INST_SCPI;
369
5a030347 370 devc = g_malloc0(sizeof(*devc));
02feeb30
TK
371 devc->cmdset = cmdset;
372 devc->device = device;
5a030347
GS
373 devc->ch_status = g_malloc0((device->num_channels + 1) *
374 sizeof(devc->ch_status[0]));
02feeb30
TK
375 sr_sw_limits_init(&devc->limits);
376 sdi->priv = devc;
377
378 /* Create channel group and channel for each device channel. */
379 ch_idx = 0;
380 for (i = 0; i < device->num_channels; i++) {
381 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE,
382 device->channels[i].name);
5a030347 383 cg = g_malloc0(sizeof(*cg));
02feeb30
TK
384 snprintf(tmp, sizeof(tmp), "%u", i + 1);
385 cg->name = g_strdup(tmp);
386 cg->channels = g_slist_append(cg->channels, ch);
387
388 sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
389 }
068db0fb 390
02feeb30
TK
391 /* Create channels for the frequency counter output. */
392 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "FREQ1");
393 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "PERIOD1");
394 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "DUTY1");
395 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "WIDTH1");
396
397 /* Put device back to "local" mode, in case only a scan was done... */
398 command = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_SETUP_LOCAL);
399 if (command && *command) {
400 sr_scpi_get_opc(scpi);
401 sr_scpi_send(scpi, command);
402 }
403
404 sr_scpi_hw_info_free(hw_info);
068db0fb 405
b1eb94bb
TK
406 /* Check for device/firmware specific issues. */
407 check_device_quirks(sdi);
408
02feeb30 409 return sdi;
068db0fb 410
02feeb30
TK
411error:
412 sr_scpi_hw_info_free(hw_info);
413 g_free(devc);
414 sr_dev_inst_free(sdi);
068db0fb 415
02feeb30 416 return NULL;
068db0fb
TK
417}
418
02feeb30 419static GSList *scan(struct sr_dev_driver *di, GSList *options)
068db0fb 420{
02feeb30
TK
421 return sr_scpi_scan(di->context, options, probe_device);
422}
068db0fb 423
02feeb30
TK
424static int dev_open(struct sr_dev_inst *sdi)
425{
426 return sr_scpi_open(sdi->conn);
068db0fb
TK
427}
428
429static int dev_close(struct sr_dev_inst *sdi)
430{
02feeb30
TK
431 struct dev_context *devc;
432 struct sr_scpi_dev_inst *scpi;
433 const char *command;
434
435 devc = sdi->priv;
436 scpi = sdi->conn;
437 if (!scpi)
438 return SR_ERR_BUG;
439
440 /* Put unit back to "local" mode. */
441 command = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_SETUP_LOCAL);
442 if (command && *command) {
443 sr_scpi_get_opc(scpi);
444 sr_scpi_send(scpi, command);
445 }
068db0fb 446
02feeb30 447 return sr_scpi_close(sdi->conn);
068db0fb
TK
448}
449
450static int config_get(uint32_t key, GVariant **data,
451 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
452{
02feeb30
TK
453 struct dev_context *devc;
454 struct sr_scpi_dev_inst *scpi;
455 struct sr_channel *ch;
456 struct channel_status *ch_status;
457 const struct sr_key_info *kinfo;
458 uint32_t cmd;
068db0fb
TK
459 int ret;
460
02feeb30
TK
461 if (!sdi || !data)
462 return SR_ERR_ARG;
068db0fb 463
02feeb30
TK
464 devc = sdi->priv;
465 scpi = sdi->conn;
068db0fb 466 ret = SR_OK;
02feeb30
TK
467 kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
468
469 if (!cg) {
470 switch (key) {
471 case SR_CONF_LIMIT_SAMPLES:
472 case SR_CONF_LIMIT_MSEC:
473 ret = sr_sw_limits_config_get(&devc->limits, key, data);
474 break;
475 default:
476 sr_dbg("%s: Unsupported key: %d (%s)", __func__,
477 (int)key, (kinfo ? kinfo->name : "unknown"));
478 ret = SR_ERR_NA;
479 break;
480 }
481 } else {
482 ch = cg->channels->data;
483 ch_status = &devc->ch_status[ch->index];
484
485 switch (key) {
486 case SR_CONF_ENABLED:
487 sr_scpi_get_opc(scpi);
488 ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
489 PSG_CMD_SELECT_CHANNEL, cg->name, data,
490 G_VARIANT_TYPE_BOOLEAN, PSG_CMD_GET_ENABLED,
491 cg->name);
492 break;
493 case SR_CONF_PATTERN_MODE:
494 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK) {
495 *data = g_variant_new_string(
496 rigol_dg_waveform_to_string(
497 ch_status->wf));
498 }
499 break;
500 case SR_CONF_OUTPUT_FREQUENCY:
501 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
502 *data = g_variant_new_double(ch_status->freq);
503 break;
504 case SR_CONF_AMPLITUDE:
505 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
506 *data = g_variant_new_double(ch_status->ampl);
507 break;
508 case SR_CONF_OFFSET:
509 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
510 *data = g_variant_new_double(ch_status->offset);
511 break;
512 case SR_CONF_PHASE:
513 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
514 *data = g_variant_new_double(ch_status->phase);
515 break;
516 case SR_CONF_DUTY_CYCLE:
d999f2b6
TK
517 if ((ret = rigol_dg_get_channel_state(sdi, cg)) != SR_OK)
518 break;
02feeb30
TK
519 if (ch_status->wf == WF_SQUARE) {
520 cmd = PSG_CMD_GET_DCYCL_SQUARE;
521 } else if (ch_status->wf == WF_PULSE) {
522 cmd = PSG_CMD_GET_DCYCL_PULSE;
523 } else {
524 ret = SR_ERR_NA;
525 break;
526 }
527 sr_scpi_get_opc(scpi);
528 ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
529 PSG_CMD_SELECT_CHANNEL, cg->name, data,
530 G_VARIANT_TYPE_DOUBLE, cmd, cg->name);
531 break;
532 default:
533 sr_dbg("%s: Unsupported (cg) key: %d (%s)", __func__,
534 (int)key, (kinfo ? kinfo->name : "unknown"));
535 ret = SR_ERR_NA;
536 break;
537 }
068db0fb
TK
538 }
539
540 return ret;
541}
542
543static int config_set(uint32_t key, GVariant *data,
544 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
545{
02feeb30
TK
546 struct dev_context *devc;
547 struct sr_scpi_dev_inst *scpi;
548 struct sr_channel *ch;
549 const struct channel_spec *ch_spec;
550 struct channel_status *ch_status;
551 const struct sr_key_info *kinfo;
068db0fb 552 int ret;
02feeb30
TK
553 uint32_t cmd;
554 const char *mode, *mode_name, *new_mode;
555 unsigned int i;
068db0fb 556
02feeb30
TK
557 if (!data || !sdi)
558 return SR_ERR_ARG;
559
560 devc = sdi->priv;
561 scpi = sdi->conn;
562 kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
068db0fb
TK
563
564 ret = SR_OK;
02feeb30
TK
565
566 if (!cg) {
567 switch (key) {
568 case SR_CONF_LIMIT_MSEC:
569 case SR_CONF_LIMIT_SAMPLES:
570 ret = sr_sw_limits_config_set(&devc->limits, key, data);
571 break;
572 default:
573 sr_dbg("%s: Unsupported key: %d (%s)", __func__,
574 (int)key, (kinfo ? kinfo->name : "unknown"));
575 ret = SR_ERR_NA;
576 break;
577 }
578 } else {
579 ch = cg->channels->data;
580 ch_spec = &devc->device->channels[ch->index];
581 ch_status = &devc->ch_status[ch->index];
582
583 if ((ret = rigol_dg_get_channel_state(sdi, cg)) != SR_OK)
584 return ret;
585 sr_scpi_get_opc(scpi);
586
587 switch (key) {
588 case SR_CONF_ENABLED:
589 if (g_variant_get_boolean(data))
590 cmd = PSG_CMD_SET_ENABLE;
591 else
592 cmd = PSG_CMD_SET_DISABLE;
593 ret = sr_scpi_cmd(sdi, devc->cmdset,
594 PSG_CMD_SELECT_CHANNEL, cg->name, cmd, cg->name);
595 break;
596 case SR_CONF_PATTERN_MODE:
597 ret = SR_ERR_NA;
598 new_mode = NULL;
599 mode = g_variant_get_string(data, NULL);
600 for (i = 0; i < ch_spec->num_waveforms; i++) {
601 mode_name = rigol_dg_waveform_to_string(
602 ch_spec->waveforms[i].waveform);
603 if (g_ascii_strncasecmp(mode, mode_name,
604 strlen(mode_name)) == 0)
605 new_mode = ch_spec->waveforms[i].name;
606 }
607 if (new_mode)
608 ret = sr_scpi_cmd(sdi, devc->cmdset,
609 PSG_CMD_SELECT_CHANNEL, cg->name,
610 PSG_CMD_SET_SOURCE, cg->name, new_mode);
611 break;
612 case SR_CONF_OUTPUT_FREQUENCY:
613 ret = SR_ERR_NA;
614 if (!(ch_status->wf_spec->opts & WFO_FREQUENCY))
615 break;
616 ret = sr_scpi_cmd(sdi, devc->cmdset,
617 PSG_CMD_SELECT_CHANNEL, cg->name,
618 PSG_CMD_SET_FREQUENCY, cg->name,
619 g_variant_get_double(data));
620 break;
621 case SR_CONF_AMPLITUDE:
622 ret = SR_ERR_NA;
623 if (!(ch_status->wf_spec->opts & WFO_AMPLITUDE))
624 break;
625 ret = sr_scpi_cmd(sdi, devc->cmdset,
626 PSG_CMD_SELECT_CHANNEL, cg->name,
627 PSG_CMD_SET_AMPLITUDE, cg->name,
628 g_variant_get_double(data));
629 break;
630 case SR_CONF_OFFSET:
631 ret = SR_ERR_NA;
632 if (!(ch_status->wf_spec->opts & WFO_OFFSET))
633 break;
634 ret = sr_scpi_cmd(sdi, devc->cmdset,
635 PSG_CMD_SELECT_CHANNEL, cg->name,
636 PSG_CMD_SET_OFFSET, cg->name,
637 g_variant_get_double(data));
638 break;
639 case SR_CONF_PHASE:
640 ret = SR_ERR_NA;
641 if (!(ch_status->wf_spec->opts & WFO_PHASE))
642 break;
643 ret = sr_scpi_cmd(sdi, devc->cmdset,
644 PSG_CMD_SELECT_CHANNEL, cg->name,
645 PSG_CMD_SET_PHASE, cg->name,
646 g_variant_get_double(data));
647 break;
648 case SR_CONF_DUTY_CYCLE:
649 ret = SR_ERR_NA;
650 if (!(ch_status->wf_spec->opts & WFO_DUTY_CYCLE))
651 break;
652 if (ch_status->wf == WF_SQUARE)
653 cmd = PSG_CMD_SET_DCYCL_SQUARE;
654 else if (ch_status->wf == WF_PULSE)
655 cmd = PSG_CMD_SET_DCYCL_PULSE;
656 else
657 break;
658 ret = sr_scpi_cmd(sdi, devc->cmdset,
659 PSG_CMD_SELECT_CHANNEL, cg->name,
660 cmd, cg->name, g_variant_get_double(data));
661 break;
662 default:
663 sr_dbg("%s: Unsupported key: %d (%s)", __func__,
664 (int)key, (kinfo ? kinfo->name : "unknown"));
665 ret = SR_ERR_NA;
666 break;
667 }
068db0fb
TK
668 }
669
670 return ret;
671}
672
673static int config_list(uint32_t key, GVariant **data,
674 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
675{
02feeb30
TK
676 struct dev_context *devc;
677 struct sr_channel *ch;
678 const struct channel_spec *ch_spec;
679 const struct waveform_spec *wf_spec;
680 struct channel_status *ch_status;
681 GVariantBuilder *b;
682 unsigned int i;
683 double fspec[3];
684
685 devc = NULL;
686 if (sdi)
687 devc = sdi->priv;
688
689 if (!cg) {
690 switch (key) {
691 case SR_CONF_SCAN_OPTIONS:
692 case SR_CONF_DEVICE_OPTIONS:
693 return std_opts_config_list(key, data, sdi, cg,
694 ARRAY_AND_SIZE(scanopts),
695 ARRAY_AND_SIZE(drvopts),
696 (devc && devc->device) ? devc->device->devopts : NULL,
697 (devc && devc->device) ? devc->device->num_devopts : 0);
698 default:
699 return SR_ERR_NA;
700 }
701 } else {
702 if (!devc || !devc->device)
703 return SR_ERR_ARG;
704 ch = cg->channels->data;
705 ch_spec = &devc->device->channels[ch->index];
706 ch_status = &devc->ch_status[ch->index];
707
708 switch(key) {
709 case SR_CONF_DEVICE_OPTIONS:
710 *data = std_gvar_array_u32(devc->device->devopts_cg,
711 devc->device->num_devopts_cg);
712 break;
713 case SR_CONF_PATTERN_MODE:
714 b = g_variant_builder_new(G_VARIANT_TYPE("as"));
715 for (i = 0; i < ch_spec->num_waveforms; i++) {
716 g_variant_builder_add(b, "s",
717 rigol_dg_waveform_to_string(
718 ch_spec->waveforms[i].waveform));
719 }
720 *data = g_variant_new("as", b);
721 g_variant_builder_unref(b);
722 break;
723 case SR_CONF_OUTPUT_FREQUENCY:
724 /*
725 * Frequency range depends on the currently active
726 * wave form.
727 */
728 if (rigol_dg_get_channel_state(sdi, cg) != SR_OK)
729 return SR_ERR_NA;
730 wf_spec = rigol_dg_get_waveform_spec(ch_spec,
731 ch_status->wf);
732 if (!wf_spec)
733 return SR_ERR_BUG;
734 fspec[0] = wf_spec->freq_min;
735 fspec[1] = wf_spec->freq_max;
736 fspec[2] = wf_spec->freq_step;
737 *data = std_gvar_min_max_step_array(fspec);
738 break;
739 case SR_CONF_PHASE:
740 *data = std_gvar_min_max_step_array(phase_min_max_step);
741 break;
742 default:
743 return SR_ERR_NA;
744 }
745 }
746
747 return SR_OK;
748}
749
750static int dev_acquisition_start(const struct sr_dev_inst *sdi)
751{
752 struct dev_context *devc;
753 struct sr_scpi_dev_inst *scpi;
754 const char *cmd;
755 char *response;
b1eb94bb
TK
756 GVariant *data;
757 gboolean need_quirk;
758 gboolean ch_active;
068db0fb
TK
759 int ret;
760
02feeb30
TK
761 if (!sdi)
762 return SR_ERR_ARG;
068db0fb 763
02feeb30
TK
764 devc = sdi->priv;
765 scpi = sdi->conn;
766 response = NULL;
b1eb94bb 767 data = NULL;
068db0fb 768 ret = SR_OK;
02feeb30
TK
769
770 if (!scpi)
771 return SR_ERR_BUG;
772
773 cmd = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_COUNTER_GET_ENABLED);
774 if (cmd && *cmd) {
775 /* Check if counter is currently enabled. */
776 ret = sr_scpi_get_string(scpi, cmd, &response);
777 if (ret != SR_OK)
778 return SR_ERR_NA;
779 if (g_ascii_strncasecmp(response, "RUN", strlen("RUN")) == 0)
780 devc->counter_enabled = TRUE;
781 else
782 devc->counter_enabled = FALSE;
ff85a7f0 783 g_free(response);
02feeb30
TK
784
785 if (!devc->counter_enabled) {
b1eb94bb
TK
786 /*
787 * Enable counter if it was not already running.
788 * Some devices cannot use channel 2 and the counter
789 * at the same time. Some cannot respond right after
790 * enabling the counter and need a delay.
791 */
792
793 need_quirk = devc->quirks & RIGOL_DG_COUNTER_CH2_CONFLICT;
794 need_quirk &= devc->device->num_channels > 1;
795 if (need_quirk) {
796 sr_scpi_get_opc(scpi);
797 ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
798 PSG_CMD_SELECT_CHANNEL, "2",
799 &data, G_VARIANT_TYPE_BOOLEAN,
800 PSG_CMD_GET_ENABLED, "2");
801 if (ret != SR_OK)
802 return SR_ERR_NA;
803 ch_active = g_variant_get_boolean(data);
804 g_variant_unref(data);
805 if (ch_active) {
806 sr_scpi_get_opc(scpi);
807 ret = sr_scpi_cmd(sdi, devc->cmdset,
808 PSG_CMD_SELECT_CHANNEL, "2",
809 PSG_CMD_SET_DISABLE, "2");
810 if (ret != SR_OK)
811 return SR_ERR_NA;
812 }
813 }
814
02feeb30
TK
815 cmd = sr_scpi_cmd_get(devc->cmdset,
816 PSG_CMD_COUNTER_SET_ENABLE);
817 if (!cmd)
818 return SR_ERR_BUG;
819 sr_scpi_get_opc(scpi);
820 ret = sr_scpi_send(scpi, cmd);
b1eb94bb
TK
821
822 need_quirk = devc->quirks & RIGOL_DG_COUNTER_BUG;
823 if (need_quirk)
824 g_usleep(RIGOL_DG_COUNTER_BUG_DELAY);
02feeb30
TK
825 }
826 }
827
828 if (ret == SR_OK) {
829 sr_sw_limits_acquisition_start(&devc->limits);
830 ret = std_session_send_df_header(sdi);
831 if (ret == SR_OK) {
832 ret = sr_scpi_source_add(sdi->session, scpi,
833 G_IO_IN, 100, rigol_dg_receive_data,
834 (void *)sdi);
835 }
068db0fb
TK
836 }
837
838 return ret;
839}
840
02feeb30 841static int dev_acquisition_stop(struct sr_dev_inst *sdi)
068db0fb 842{
02feeb30
TK
843 struct dev_context *devc;
844 struct sr_scpi_dev_inst *scpi;
845 const char *cmd;
846 int ret;
068db0fb 847
02feeb30
TK
848 if (!sdi)
849 return SR_ERR_ARG;
068db0fb 850
02feeb30
TK
851 devc = sdi->priv;
852 scpi = sdi->conn;
853 ret = SR_OK;
068db0fb 854
02feeb30
TK
855 cmd = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_COUNTER_SET_DISABLE);
856 if (cmd && *cmd && !devc->counter_enabled) {
857 /*
858 * If counter was not running when acquisiton started,
b1eb94bb
TK
859 * turn it off now. Some devices need a delay after
860 * disabling the counter.
02feeb30
TK
861 */
862 sr_scpi_get_opc(scpi);
863 ret = sr_scpi_send(scpi, cmd);
b1eb94bb
TK
864 if (devc->quirks & RIGOL_DG_COUNTER_BUG)
865 g_usleep(RIGOL_DG_COUNTER_BUG_DELAY);
02feeb30 866 }
068db0fb 867
02feeb30
TK
868 sr_scpi_source_remove(sdi->session, scpi);
869 std_session_send_df_end(sdi);
068db0fb 870
02feeb30 871 return ret;
068db0fb
TK
872}
873
874static struct sr_dev_driver rigol_dg_driver_info = {
875 .name = "rigol-dg",
02feeb30 876 .longname = "Rigol DG Series",
068db0fb
TK
877 .api_version = 1,
878 .init = std_init,
879 .cleanup = std_cleanup,
880 .scan = scan,
881 .dev_list = std_dev_list,
882 .dev_clear = std_dev_clear,
883 .config_get = config_get,
884 .config_set = config_set,
885 .config_list = config_list,
886 .dev_open = dev_open,
887 .dev_close = dev_close,
888 .dev_acquisition_start = dev_acquisition_start,
889 .dev_acquisition_stop = dev_acquisition_stop,
890 .context = NULL,
891};
892SR_REGISTER_DEV_DRIVER(rigol_dg_driver_info);