]> sigrok.org Git - libsigrok.git/blame - src/hardware/rigol-dg/api.c
rigol-dg: Add Rigol DG800 and DG900 series support.
[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
305static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
068db0fb 306{
02feeb30
TK
307 struct sr_dev_inst *sdi;
308 struct dev_context *devc;
309 struct sr_scpi_hw_info *hw_info;
310 const struct device_spec *device;
311 const struct scpi_command *cmdset;
312 struct sr_channel *ch;
313 struct sr_channel_group *cg;
314 const char *command;
315 unsigned int i, ch_idx;
316 char tmp[16];
317
318 sdi = NULL;
319 devc = NULL;
320 hw_info = NULL;
321
322 if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK)
323 goto error;
324
325 device = NULL;
326 for (i = 0; i < ARRAY_SIZE(device_models); i++) {
327 if (g_ascii_strcasecmp(hw_info->manufacturer,
328 device_models[i].vendor) != 0)
329 continue;
330 if (g_ascii_strcasecmp(hw_info->model,
331 device_models[i].model) != 0)
332 continue;
333 device = &device_models[i];
334 cmdset = device_models[i].cmdset;
335 break;
336 }
337 if (!device)
338 goto error;
339
5a030347 340 sdi = g_malloc0(sizeof(*sdi));
02feeb30
TK
341 sdi->vendor = g_strdup(hw_info->manufacturer);
342 sdi->model = g_strdup(hw_info->model);
343 sdi->version = g_strdup(hw_info->firmware_version);
344 sdi->serial_num = g_strdup(hw_info->serial_number);
345 sdi->conn = scpi;
346 sdi->driver = &rigol_dg_driver_info;
347 sdi->inst_type = SR_INST_SCPI;
348
5a030347 349 devc = g_malloc0(sizeof(*devc));
02feeb30
TK
350 devc->cmdset = cmdset;
351 devc->device = device;
5a030347
GS
352 devc->ch_status = g_malloc0((device->num_channels + 1) *
353 sizeof(devc->ch_status[0]));
02feeb30
TK
354 sr_sw_limits_init(&devc->limits);
355 sdi->priv = devc;
356
357 /* Create channel group and channel for each device channel. */
358 ch_idx = 0;
359 for (i = 0; i < device->num_channels; i++) {
360 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE,
361 device->channels[i].name);
5a030347 362 cg = g_malloc0(sizeof(*cg));
02feeb30
TK
363 snprintf(tmp, sizeof(tmp), "%u", i + 1);
364 cg->name = g_strdup(tmp);
365 cg->channels = g_slist_append(cg->channels, ch);
366
367 sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
368 }
068db0fb 369
02feeb30
TK
370 /* Create channels for the frequency counter output. */
371 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "FREQ1");
372 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "PERIOD1");
373 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "DUTY1");
374 ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE, "WIDTH1");
375
376 /* Put device back to "local" mode, in case only a scan was done... */
377 command = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_SETUP_LOCAL);
378 if (command && *command) {
379 sr_scpi_get_opc(scpi);
380 sr_scpi_send(scpi, command);
381 }
382
383 sr_scpi_hw_info_free(hw_info);
068db0fb 384
02feeb30 385 return sdi;
068db0fb 386
02feeb30
TK
387error:
388 sr_scpi_hw_info_free(hw_info);
389 g_free(devc);
390 sr_dev_inst_free(sdi);
068db0fb 391
02feeb30 392 return NULL;
068db0fb
TK
393}
394
02feeb30 395static GSList *scan(struct sr_dev_driver *di, GSList *options)
068db0fb 396{
02feeb30
TK
397 return sr_scpi_scan(di->context, options, probe_device);
398}
068db0fb 399
02feeb30
TK
400static int dev_open(struct sr_dev_inst *sdi)
401{
402 return sr_scpi_open(sdi->conn);
068db0fb
TK
403}
404
405static int dev_close(struct sr_dev_inst *sdi)
406{
02feeb30
TK
407 struct dev_context *devc;
408 struct sr_scpi_dev_inst *scpi;
409 const char *command;
410
411 devc = sdi->priv;
412 scpi = sdi->conn;
413 if (!scpi)
414 return SR_ERR_BUG;
415
416 /* Put unit back to "local" mode. */
417 command = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_SETUP_LOCAL);
418 if (command && *command) {
419 sr_scpi_get_opc(scpi);
420 sr_scpi_send(scpi, command);
421 }
068db0fb 422
02feeb30 423 return sr_scpi_close(sdi->conn);
068db0fb
TK
424}
425
426static int config_get(uint32_t key, GVariant **data,
427 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
428{
02feeb30
TK
429 struct dev_context *devc;
430 struct sr_scpi_dev_inst *scpi;
431 struct sr_channel *ch;
432 struct channel_status *ch_status;
433 const struct sr_key_info *kinfo;
434 uint32_t cmd;
068db0fb
TK
435 int ret;
436
02feeb30
TK
437 if (!sdi || !data)
438 return SR_ERR_ARG;
068db0fb 439
02feeb30
TK
440 devc = sdi->priv;
441 scpi = sdi->conn;
068db0fb 442 ret = SR_OK;
02feeb30
TK
443 kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
444
445 if (!cg) {
446 switch (key) {
447 case SR_CONF_LIMIT_SAMPLES:
448 case SR_CONF_LIMIT_MSEC:
449 ret = sr_sw_limits_config_get(&devc->limits, key, data);
450 break;
451 default:
452 sr_dbg("%s: Unsupported key: %d (%s)", __func__,
453 (int)key, (kinfo ? kinfo->name : "unknown"));
454 ret = SR_ERR_NA;
455 break;
456 }
457 } else {
458 ch = cg->channels->data;
459 ch_status = &devc->ch_status[ch->index];
460
461 switch (key) {
462 case SR_CONF_ENABLED:
463 sr_scpi_get_opc(scpi);
464 ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
465 PSG_CMD_SELECT_CHANNEL, cg->name, data,
466 G_VARIANT_TYPE_BOOLEAN, PSG_CMD_GET_ENABLED,
467 cg->name);
468 break;
469 case SR_CONF_PATTERN_MODE:
470 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK) {
471 *data = g_variant_new_string(
472 rigol_dg_waveform_to_string(
473 ch_status->wf));
474 }
475 break;
476 case SR_CONF_OUTPUT_FREQUENCY:
477 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
478 *data = g_variant_new_double(ch_status->freq);
479 break;
480 case SR_CONF_AMPLITUDE:
481 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
482 *data = g_variant_new_double(ch_status->ampl);
483 break;
484 case SR_CONF_OFFSET:
485 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
486 *data = g_variant_new_double(ch_status->offset);
487 break;
488 case SR_CONF_PHASE:
489 if ((ret = rigol_dg_get_channel_state(sdi, cg)) == SR_OK)
490 *data = g_variant_new_double(ch_status->phase);
491 break;
492 case SR_CONF_DUTY_CYCLE:
493 if (ch_status->wf == WF_SQUARE) {
494 cmd = PSG_CMD_GET_DCYCL_SQUARE;
495 } else if (ch_status->wf == WF_PULSE) {
496 cmd = PSG_CMD_GET_DCYCL_PULSE;
497 } else {
498 ret = SR_ERR_NA;
499 break;
500 }
501 sr_scpi_get_opc(scpi);
502 ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
503 PSG_CMD_SELECT_CHANNEL, cg->name, data,
504 G_VARIANT_TYPE_DOUBLE, cmd, cg->name);
505 break;
506 default:
507 sr_dbg("%s: Unsupported (cg) key: %d (%s)", __func__,
508 (int)key, (kinfo ? kinfo->name : "unknown"));
509 ret = SR_ERR_NA;
510 break;
511 }
068db0fb
TK
512 }
513
514 return ret;
515}
516
517static int config_set(uint32_t key, GVariant *data,
518 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
519{
02feeb30
TK
520 struct dev_context *devc;
521 struct sr_scpi_dev_inst *scpi;
522 struct sr_channel *ch;
523 const struct channel_spec *ch_spec;
524 struct channel_status *ch_status;
525 const struct sr_key_info *kinfo;
068db0fb 526 int ret;
02feeb30
TK
527 uint32_t cmd;
528 const char *mode, *mode_name, *new_mode;
529 unsigned int i;
068db0fb 530
02feeb30
TK
531 if (!data || !sdi)
532 return SR_ERR_ARG;
533
534 devc = sdi->priv;
535 scpi = sdi->conn;
536 kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
068db0fb
TK
537
538 ret = SR_OK;
02feeb30
TK
539
540 if (!cg) {
541 switch (key) {
542 case SR_CONF_LIMIT_MSEC:
543 case SR_CONF_LIMIT_SAMPLES:
544 ret = sr_sw_limits_config_set(&devc->limits, key, data);
545 break;
546 default:
547 sr_dbg("%s: Unsupported key: %d (%s)", __func__,
548 (int)key, (kinfo ? kinfo->name : "unknown"));
549 ret = SR_ERR_NA;
550 break;
551 }
552 } else {
553 ch = cg->channels->data;
554 ch_spec = &devc->device->channels[ch->index];
555 ch_status = &devc->ch_status[ch->index];
556
557 if ((ret = rigol_dg_get_channel_state(sdi, cg)) != SR_OK)
558 return ret;
559 sr_scpi_get_opc(scpi);
560
561 switch (key) {
562 case SR_CONF_ENABLED:
563 if (g_variant_get_boolean(data))
564 cmd = PSG_CMD_SET_ENABLE;
565 else
566 cmd = PSG_CMD_SET_DISABLE;
567 ret = sr_scpi_cmd(sdi, devc->cmdset,
568 PSG_CMD_SELECT_CHANNEL, cg->name, cmd, cg->name);
569 break;
570 case SR_CONF_PATTERN_MODE:
571 ret = SR_ERR_NA;
572 new_mode = NULL;
573 mode = g_variant_get_string(data, NULL);
574 for (i = 0; i < ch_spec->num_waveforms; i++) {
575 mode_name = rigol_dg_waveform_to_string(
576 ch_spec->waveforms[i].waveform);
577 if (g_ascii_strncasecmp(mode, mode_name,
578 strlen(mode_name)) == 0)
579 new_mode = ch_spec->waveforms[i].name;
580 }
581 if (new_mode)
582 ret = sr_scpi_cmd(sdi, devc->cmdset,
583 PSG_CMD_SELECT_CHANNEL, cg->name,
584 PSG_CMD_SET_SOURCE, cg->name, new_mode);
585 break;
586 case SR_CONF_OUTPUT_FREQUENCY:
587 ret = SR_ERR_NA;
588 if (!(ch_status->wf_spec->opts & WFO_FREQUENCY))
589 break;
590 ret = sr_scpi_cmd(sdi, devc->cmdset,
591 PSG_CMD_SELECT_CHANNEL, cg->name,
592 PSG_CMD_SET_FREQUENCY, cg->name,
593 g_variant_get_double(data));
594 break;
595 case SR_CONF_AMPLITUDE:
596 ret = SR_ERR_NA;
597 if (!(ch_status->wf_spec->opts & WFO_AMPLITUDE))
598 break;
599 ret = sr_scpi_cmd(sdi, devc->cmdset,
600 PSG_CMD_SELECT_CHANNEL, cg->name,
601 PSG_CMD_SET_AMPLITUDE, cg->name,
602 g_variant_get_double(data));
603 break;
604 case SR_CONF_OFFSET:
605 ret = SR_ERR_NA;
606 if (!(ch_status->wf_spec->opts & WFO_OFFSET))
607 break;
608 ret = sr_scpi_cmd(sdi, devc->cmdset,
609 PSG_CMD_SELECT_CHANNEL, cg->name,
610 PSG_CMD_SET_OFFSET, cg->name,
611 g_variant_get_double(data));
612 break;
613 case SR_CONF_PHASE:
614 ret = SR_ERR_NA;
615 if (!(ch_status->wf_spec->opts & WFO_PHASE))
616 break;
617 ret = sr_scpi_cmd(sdi, devc->cmdset,
618 PSG_CMD_SELECT_CHANNEL, cg->name,
619 PSG_CMD_SET_PHASE, cg->name,
620 g_variant_get_double(data));
621 break;
622 case SR_CONF_DUTY_CYCLE:
623 ret = SR_ERR_NA;
624 if (!(ch_status->wf_spec->opts & WFO_DUTY_CYCLE))
625 break;
626 if (ch_status->wf == WF_SQUARE)
627 cmd = PSG_CMD_SET_DCYCL_SQUARE;
628 else if (ch_status->wf == WF_PULSE)
629 cmd = PSG_CMD_SET_DCYCL_PULSE;
630 else
631 break;
632 ret = sr_scpi_cmd(sdi, devc->cmdset,
633 PSG_CMD_SELECT_CHANNEL, cg->name,
634 cmd, cg->name, g_variant_get_double(data));
635 break;
636 default:
637 sr_dbg("%s: Unsupported key: %d (%s)", __func__,
638 (int)key, (kinfo ? kinfo->name : "unknown"));
639 ret = SR_ERR_NA;
640 break;
641 }
068db0fb
TK
642 }
643
644 return ret;
645}
646
647static int config_list(uint32_t key, GVariant **data,
648 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
649{
02feeb30
TK
650 struct dev_context *devc;
651 struct sr_channel *ch;
652 const struct channel_spec *ch_spec;
653 const struct waveform_spec *wf_spec;
654 struct channel_status *ch_status;
655 GVariantBuilder *b;
656 unsigned int i;
657 double fspec[3];
658
659 devc = NULL;
660 if (sdi)
661 devc = sdi->priv;
662
663 if (!cg) {
664 switch (key) {
665 case SR_CONF_SCAN_OPTIONS:
666 case SR_CONF_DEVICE_OPTIONS:
667 return std_opts_config_list(key, data, sdi, cg,
668 ARRAY_AND_SIZE(scanopts),
669 ARRAY_AND_SIZE(drvopts),
670 (devc && devc->device) ? devc->device->devopts : NULL,
671 (devc && devc->device) ? devc->device->num_devopts : 0);
672 default:
673 return SR_ERR_NA;
674 }
675 } else {
676 if (!devc || !devc->device)
677 return SR_ERR_ARG;
678 ch = cg->channels->data;
679 ch_spec = &devc->device->channels[ch->index];
680 ch_status = &devc->ch_status[ch->index];
681
682 switch(key) {
683 case SR_CONF_DEVICE_OPTIONS:
684 *data = std_gvar_array_u32(devc->device->devopts_cg,
685 devc->device->num_devopts_cg);
686 break;
687 case SR_CONF_PATTERN_MODE:
688 b = g_variant_builder_new(G_VARIANT_TYPE("as"));
689 for (i = 0; i < ch_spec->num_waveforms; i++) {
690 g_variant_builder_add(b, "s",
691 rigol_dg_waveform_to_string(
692 ch_spec->waveforms[i].waveform));
693 }
694 *data = g_variant_new("as", b);
695 g_variant_builder_unref(b);
696 break;
697 case SR_CONF_OUTPUT_FREQUENCY:
698 /*
699 * Frequency range depends on the currently active
700 * wave form.
701 */
702 if (rigol_dg_get_channel_state(sdi, cg) != SR_OK)
703 return SR_ERR_NA;
704 wf_spec = rigol_dg_get_waveform_spec(ch_spec,
705 ch_status->wf);
706 if (!wf_spec)
707 return SR_ERR_BUG;
708 fspec[0] = wf_spec->freq_min;
709 fspec[1] = wf_spec->freq_max;
710 fspec[2] = wf_spec->freq_step;
711 *data = std_gvar_min_max_step_array(fspec);
712 break;
713 case SR_CONF_PHASE:
714 *data = std_gvar_min_max_step_array(phase_min_max_step);
715 break;
716 default:
717 return SR_ERR_NA;
718 }
719 }
720
721 return SR_OK;
722}
723
724static int dev_acquisition_start(const struct sr_dev_inst *sdi)
725{
726 struct dev_context *devc;
727 struct sr_scpi_dev_inst *scpi;
728 const char *cmd;
729 char *response;
068db0fb
TK
730 int ret;
731
02feeb30
TK
732 if (!sdi)
733 return SR_ERR_ARG;
068db0fb 734
02feeb30
TK
735 devc = sdi->priv;
736 scpi = sdi->conn;
737 response = NULL;
068db0fb 738 ret = SR_OK;
02feeb30
TK
739
740 if (!scpi)
741 return SR_ERR_BUG;
742
743 cmd = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_COUNTER_GET_ENABLED);
744 if (cmd && *cmd) {
745 /* Check if counter is currently enabled. */
746 ret = sr_scpi_get_string(scpi, cmd, &response);
747 if (ret != SR_OK)
748 return SR_ERR_NA;
749 if (g_ascii_strncasecmp(response, "RUN", strlen("RUN")) == 0)
750 devc->counter_enabled = TRUE;
751 else
752 devc->counter_enabled = FALSE;
753
754 if (!devc->counter_enabled) {
755 /* Enable counter if it was not already running. */
756 cmd = sr_scpi_cmd_get(devc->cmdset,
757 PSG_CMD_COUNTER_SET_ENABLE);
758 if (!cmd)
759 return SR_ERR_BUG;
760 sr_scpi_get_opc(scpi);
761 ret = sr_scpi_send(scpi, cmd);
762 }
763 }
764
765 if (ret == SR_OK) {
766 sr_sw_limits_acquisition_start(&devc->limits);
767 ret = std_session_send_df_header(sdi);
768 if (ret == SR_OK) {
769 ret = sr_scpi_source_add(sdi->session, scpi,
770 G_IO_IN, 100, rigol_dg_receive_data,
771 (void *)sdi);
772 }
068db0fb
TK
773 }
774
02feeb30
TK
775 g_free(response);
776
068db0fb
TK
777 return ret;
778}
779
02feeb30 780static int dev_acquisition_stop(struct sr_dev_inst *sdi)
068db0fb 781{
02feeb30
TK
782 struct dev_context *devc;
783 struct sr_scpi_dev_inst *scpi;
784 const char *cmd;
785 int ret;
068db0fb 786
02feeb30
TK
787 if (!sdi)
788 return SR_ERR_ARG;
068db0fb 789
02feeb30
TK
790 devc = sdi->priv;
791 scpi = sdi->conn;
792 ret = SR_OK;
068db0fb 793
02feeb30
TK
794 cmd = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_COUNTER_SET_DISABLE);
795 if (cmd && *cmd && !devc->counter_enabled) {
796 /*
797 * If counter was not running when acquisiton started,
798 * turn it off now...
799 */
800 sr_scpi_get_opc(scpi);
801 ret = sr_scpi_send(scpi, cmd);
802 }
068db0fb 803
02feeb30
TK
804 sr_scpi_source_remove(sdi->session, scpi);
805 std_session_send_df_end(sdi);
068db0fb 806
02feeb30 807 return ret;
068db0fb
TK
808}
809
810static struct sr_dev_driver rigol_dg_driver_info = {
811 .name = "rigol-dg",
02feeb30 812 .longname = "Rigol DG Series",
068db0fb
TK
813 .api_version = 1,
814 .init = std_init,
815 .cleanup = std_cleanup,
816 .scan = scan,
817 .dev_list = std_dev_list,
818 .dev_clear = std_dev_clear,
819 .config_get = config_get,
820 .config_set = config_set,
821 .config_list = config_list,
822 .dev_open = dev_open,
823 .dev_close = dev_close,
824 .dev_acquisition_start = dev_acquisition_start,
825 .dev_acquisition_stop = dev_acquisition_stop,
826 .context = NULL,
827};
828SR_REGISTER_DEV_DRIVER(rigol_dg_driver_info);