]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/rigol-ds1xx2/api.c
drivers: return SR_ERR_NA on unsupported config key
[libsigrok.git] / hardware / rigol-ds1xx2 / api.c
... / ...
CommitLineData
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
5 * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <fcntl.h>
22#include <unistd.h>
23#include <stdlib.h>
24#include <string.h>
25#include <glib.h>
26#include "libsigrok.h"
27#include "libsigrok-internal.h"
28#include "protocol.h"
29
30#define NUM_TIMEBASE 12
31#define NUM_VDIV 8
32
33static const int32_t hwcaps[] = {
34 SR_CONF_OSCILLOSCOPE,
35 SR_CONF_TIMEBASE,
36 SR_CONF_TRIGGER_SOURCE,
37 SR_CONF_TRIGGER_SLOPE,
38 SR_CONF_HORIZ_TRIGGERPOS,
39 SR_CONF_VDIV,
40 SR_CONF_COUPLING,
41 SR_CONF_NUM_TIMEBASE,
42 SR_CONF_NUM_VDIV,
43};
44
45static const uint64_t timebases[][2] = {
46 /* nanoseconds */
47 { 2, 1000000000 },
48 { 5, 1000000000 },
49 { 10, 1000000000 },
50 { 20, 1000000000 },
51 { 50, 1000000000 },
52 { 100, 1000000000 },
53 { 500, 1000000000 },
54 /* microseconds */
55 { 1, 1000000 },
56 { 2, 1000000 },
57 { 5, 1000000 },
58 { 10, 1000000 },
59 { 20, 1000000 },
60 { 50, 1000000 },
61 { 100, 1000000 },
62 { 200, 1000000 },
63 { 500, 1000000 },
64 /* milliseconds */
65 { 1, 1000 },
66 { 2, 1000 },
67 { 5, 1000 },
68 { 10, 1000 },
69 { 20, 1000 },
70 { 50, 1000 },
71 { 100, 1000 },
72 { 200, 1000 },
73 { 500, 1000 },
74 /* seconds */
75 { 1, 1 },
76 { 2, 1 },
77 { 5, 1 },
78 { 10, 1 },
79 { 20, 1 },
80 { 50, 1 },
81};
82
83static const uint64_t vdivs[][2] = {
84 /* millivolts */
85 { 2, 1000 },
86 { 5, 1000 },
87 { 10, 1000 },
88 { 20, 1000 },
89 { 50, 1000 },
90 { 100, 1000 },
91 { 200, 1000 },
92 { 500, 1000 },
93 /* volts */
94 { 1, 1 },
95 { 2, 1 },
96 { 5, 1 },
97 { 10, 1 },
98};
99
100static const char *trigger_sources[] = {
101 "CH1",
102 "CH2",
103 "EXT",
104 "AC Line",
105 "D0",
106 "D1",
107 "D2",
108 "D3",
109 "D4",
110 "D5",
111 "D6",
112 "D7",
113 "D8",
114 "D9",
115 "D10",
116 "D11",
117 "D12",
118 "D13",
119 "D14",
120 "D15",
121};
122
123static const char *coupling[] = {
124 "AC",
125 "DC",
126 "GND",
127};
128
129static const char *supported_models[] = {
130 "DS1052E",
131 "DS1102E",
132 "DS1052D",
133 "DS1102D",
134};
135
136SR_PRIV struct sr_dev_driver rigol_ds1xx2_driver_info;
137static struct sr_dev_driver *di = &rigol_ds1xx2_driver_info;
138
139/* Properly close and free all devices. */
140static int clear_instances(void)
141{
142 struct sr_dev_inst *sdi;
143 struct drv_context *drvc;
144 struct dev_context *devc;
145 GSList *l;
146
147 if (!(drvc = di->priv))
148 return SR_OK;
149
150 for (l = drvc->instances; l; l = l->next) {
151 if (!(sdi = l->data))
152 continue;
153 if (!(devc = sdi->priv))
154 continue;
155
156 g_free(devc->device);
157 g_free(devc->coupling[0]);
158 g_free(devc->coupling[1]);
159 g_free(devc->trigger_source);
160 g_free(devc->trigger_slope);
161 close(devc->fd);
162
163 sr_dev_inst_free(sdi);
164 }
165
166 g_slist_free(drvc->instances);
167 drvc->instances = NULL;
168
169 return SR_OK;
170}
171
172static int set_cfg(const struct sr_dev_inst *sdi, const char *format, ...)
173{
174 struct dev_context *devc;
175 va_list args;
176 char buf[256];
177
178 devc = sdi->priv;
179
180 va_start(args, format);
181 vsnprintf(buf, 255, format, args);
182 va_end(args);
183 if (rigol_ds1xx2_send(devc, buf) != SR_OK)
184 return SR_ERR;
185
186 /* When setting a bunch of parameters in a row, the DS1052E scrambles
187 * some of them unless there is at least 100ms delay in between. */
188 sr_spew("delay %dms", 100);
189 g_usleep(100);
190
191 return SR_OK;
192}
193
194static int hw_init(struct sr_context *sr_ctx)
195{
196 return std_hw_init(sr_ctx, di, DRIVER_LOG_DOMAIN);
197}
198
199static GSList *hw_scan(GSList *options)
200{
201 struct drv_context *drvc;
202 struct sr_dev_inst *sdi;
203 struct dev_context *devc;
204 struct sr_probe *probe;
205 GSList *devices;
206 GDir *dir;
207 const gchar *dev_name;
208 const gchar *dev_dir = "/dev/";
209 const gchar *prefix = "usbtmc";
210 gchar *device;
211 const gchar *idn_query = "*IDN?";
212 unsigned int i;
213 int len, num_tokens, fd;
214 const gchar *delimiter = ",";
215 gchar **tokens;
216 const char *manufacturer, *model, *version;
217 gboolean matched = FALSE;
218 gboolean has_digital = FALSE;
219 char buf[256];
220 gchar *channel_name;
221
222 (void)options;
223
224 drvc = di->priv;
225 drvc->instances = NULL;
226
227 devices = NULL;
228
229 dir = g_dir_open("/sys/class/usb/", 0, NULL);
230
231 if (dir == NULL)
232 return NULL;
233
234 while ((dev_name = g_dir_read_name(dir)) != NULL) {
235 if (strncmp(dev_name, prefix, strlen(prefix)))
236 continue;
237
238 device = g_strconcat(dev_dir, dev_name, NULL);
239
240 fd = open(device, O_RDWR);
241 len = write(fd, idn_query, strlen(idn_query));
242 len = read(fd, buf, sizeof(buf));
243 close(fd);
244 if (len == 0) {
245 g_free(device);
246 return NULL;
247 }
248
249 buf[len] = 0;
250 tokens = g_strsplit(buf, delimiter, 0);
251 close(fd);
252 sr_dbg("response: %s %d [%s]", device, len, buf);
253
254 for (num_tokens = 0; tokens[num_tokens] != NULL; num_tokens++);
255
256 if (num_tokens < 4) {
257 g_strfreev(tokens);
258 g_free(device);
259 return NULL;
260 }
261
262 manufacturer = tokens[0];
263 model = tokens[1];
264 version = tokens[3];
265
266 if (strcmp(manufacturer, "Rigol Technologies")) {
267 g_strfreev(tokens);
268 g_free(device);
269 return NULL;
270 }
271
272 for (i = 0; i < ARRAY_SIZE(supported_models); i++) {
273 if (!strcmp(model, supported_models[i])) {
274 matched = 1;
275 has_digital = g_str_has_suffix(model, "D");
276 break;
277 }
278 }
279
280 if (!matched || !(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE,
281 manufacturer, model, version))) {
282 g_strfreev(tokens);
283 g_free(device);
284 return NULL;
285 }
286
287 g_strfreev(tokens);
288
289 if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
290 sr_err("Device context malloc failed.");
291 g_free(device);
292 return NULL;
293 }
294 devc->limit_frames = 0;
295 devc->device = device;
296 devc->has_digital = has_digital;
297 sdi->priv = devc;
298 sdi->driver = di;
299
300 for (i = 0; i < 2; i++) {
301 if (!(probe = sr_probe_new(i, SR_PROBE_ANALOG, TRUE,
302 i == 0 ? "CH1" : "CH2")))
303 return NULL;
304 sdi->probes = g_slist_append(sdi->probes, probe);
305 }
306
307 if (devc->has_digital) {
308 for (i = 0; i < 16; i++) {
309 if (!(channel_name = g_strdup_printf("D%d", i)))
310 return NULL;
311 probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, channel_name);
312 g_free(channel_name);
313 if (!probe)
314 return NULL;
315 sdi->probes = g_slist_append(sdi->probes, probe);
316 }
317 }
318
319 drvc->instances = g_slist_append(drvc->instances, sdi);
320 devices = g_slist_append(devices, sdi);
321 }
322
323 g_dir_close(dir);
324
325 return devices;
326}
327
328static GSList *hw_dev_list(void)
329{
330 return ((struct drv_context *)(di->priv))->instances;
331}
332
333static int hw_dev_open(struct sr_dev_inst *sdi)
334{
335 struct dev_context *devc;
336 int fd;
337
338 devc = sdi->priv;
339
340 if ((fd = open(devc->device, O_RDWR)) == -1)
341 return SR_ERR;
342 devc->fd = fd;
343
344 if (rigol_ds1xx2_get_dev_cfg(sdi) != SR_OK)
345 /* TODO: force configuration? */
346 return SR_ERR;
347
348 return SR_OK;
349}
350
351static int hw_dev_close(struct sr_dev_inst *sdi)
352{
353 struct dev_context *devc;
354
355 devc = sdi->priv;
356
357 close(devc->fd);
358
359 return SR_OK;
360}
361
362static int hw_cleanup(void)
363{
364 clear_instances();
365
366 return SR_OK;
367}
368
369static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi)
370{
371
372 (void)sdi;
373
374 switch (id) {
375 case SR_CONF_NUM_TIMEBASE:
376 *data = g_variant_new_int32(NUM_TIMEBASE);
377 break;
378 case SR_CONF_NUM_VDIV:
379 *data = g_variant_new_int32(NUM_VDIV);
380 break;
381 default:
382 return SR_ERR_NA;
383 }
384
385 return SR_OK;
386}
387
388static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi)
389{
390 struct dev_context *devc;
391 uint64_t tmp_u64, p, q;
392 double t_dbl;
393 unsigned int i;
394 int ret;
395 const char *tmp_str;
396
397 devc = sdi->priv;
398
399 if (sdi->status != SR_ST_ACTIVE) {
400 sr_err("Device inactive, can't set config options.");
401 return SR_ERR;
402 }
403
404 ret = SR_OK;
405 switch (id) {
406 case SR_CONF_LIMIT_FRAMES:
407 devc->limit_frames = g_variant_get_uint64(data);
408 break;
409 case SR_CONF_TRIGGER_SLOPE:
410 tmp_u64 = g_variant_get_uint64(data);
411 if (tmp_u64 != 0 && tmp_u64 != 1)
412 return SR_ERR;
413 g_free(devc->trigger_slope);
414 devc->trigger_slope = g_strdup(tmp_u64 ? "POS" : "NEG");
415 ret = set_cfg(sdi, ":TRIG:EDGE:SLOP %s", devc->trigger_slope);
416 break;
417 case SR_CONF_HORIZ_TRIGGERPOS:
418 t_dbl = g_variant_get_double(data);
419 if (t_dbl < 0.0 || t_dbl > 1.0)
420 return SR_ERR;
421 devc->horiz_triggerpos = t_dbl;
422 /* We have the trigger offset as a percentage of the frame, but
423 * need to express this in seconds. */
424 t_dbl = -(devc->horiz_triggerpos - 0.5) * devc->timebase * NUM_TIMEBASE;
425 ret = set_cfg(sdi, ":TIM:OFFS %.6f", t_dbl);
426 break;
427 case SR_CONF_TIMEBASE:
428 g_variant_get(data, "(tt)", &p, &q);
429 for (i = 0; i < ARRAY_SIZE(timebases); i++) {
430 if (timebases[i][0] == p && timebases[i][1] == q) {
431 devc->timebase = (float)p / q;
432 ret = set_cfg(sdi, ":TIM:SCAL %.9f", devc->timebase);
433 break;
434 }
435 }
436 if (i == ARRAY_SIZE(timebases))
437 ret = SR_ERR_ARG;
438 break;
439 case SR_CONF_TRIGGER_SOURCE:
440 tmp_str = g_variant_get_string(data, NULL);
441 for (i = 0; i < ARRAY_SIZE(trigger_sources); i++) {
442 if (!strcmp(trigger_sources[i], tmp_str)) {
443 g_free(devc->trigger_source);
444 devc->trigger_source = g_strdup(trigger_sources[i]);
445 if (!strcmp(devc->trigger_source, "AC Line"))
446 tmp_str = "ACL";
447 else if (!strcmp(devc->trigger_source, "CH1"))
448 tmp_str = "CHAN1";
449 else if (!strcmp(devc->trigger_source, "CH2"))
450 tmp_str = "CHAN2";
451 else
452 tmp_str = (char *)devc->trigger_source;
453 ret = set_cfg(sdi, ":TRIG:EDGE:SOUR %s", tmp_str);
454 break;
455 }
456 }
457 if (i == ARRAY_SIZE(trigger_sources))
458 ret = SR_ERR_ARG;
459 break;
460 case SR_CONF_VDIV:
461 g_variant_get(data, "(tt)", &p, &q);
462 for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
463 if (vdivs[i][0] != p || vdivs[i][1] != q)
464 continue;
465 devc->vdiv[0] = devc->vdiv[1] = (float)p / q;
466 set_cfg(sdi, ":CHAN1:SCAL %.3f", devc->vdiv[0]);
467 ret = set_cfg(sdi, ":CHAN2:SCAL %.3f", devc->vdiv[1]);
468 break;
469 }
470 if (i == ARRAY_SIZE(vdivs))
471 ret = SR_ERR_ARG;
472 break;
473 case SR_CONF_COUPLING:
474 /* TODO: Not supporting coupling per channel yet. */
475 tmp_str = g_variant_get_string(data, NULL);
476 for (i = 0; i < ARRAY_SIZE(coupling); i++) {
477 if (!strcmp(tmp_str, coupling[i])) {
478 g_free(devc->coupling[0]);
479 g_free(devc->coupling[1]);
480 devc->coupling[0] = g_strdup(coupling[i]);
481 devc->coupling[1] = g_strdup(coupling[i]);
482 set_cfg(sdi, ":CHAN1:COUP %s", devc->coupling[0]);
483 ret = set_cfg(sdi, ":CHAN2:COUP %s", devc->coupling[1]);
484 break;
485 }
486 }
487 if (i == ARRAY_SIZE(coupling))
488 ret = SR_ERR_ARG;
489 break;
490 default:
491 ret = SR_ERR_NA;
492 break;
493 }
494
495 return ret;
496}
497
498static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi)
499{
500 GVariant *tuple, *rational[2];
501 GVariantBuilder gvb;
502 unsigned int i;
503 struct dev_context *devc;
504
505 switch (key) {
506 case SR_CONF_DEVICE_OPTIONS:
507 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
508 hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
509 break;
510 case SR_CONF_COUPLING:
511 *data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling));
512 break;
513 case SR_CONF_VDIV:
514 g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
515 for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
516 rational[0] = g_variant_new_uint64(vdivs[i][0]);
517 rational[1] = g_variant_new_uint64(vdivs[i][1]);
518 tuple = g_variant_new_tuple(rational, 2);
519 g_variant_builder_add_value(&gvb, tuple);
520 }
521 *data = g_variant_builder_end(&gvb);
522 break;
523 case SR_CONF_TIMEBASE:
524 g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
525 for (i = 0; i < ARRAY_SIZE(timebases); i++) {
526 rational[0] = g_variant_new_uint64(timebases[i][0]);
527 rational[1] = g_variant_new_uint64(timebases[i][1]);
528 tuple = g_variant_new_tuple(rational, 2);
529 g_variant_builder_add_value(&gvb, tuple);
530 }
531 *data = g_variant_builder_end(&gvb);
532 break;
533 case SR_CONF_TRIGGER_SOURCE:
534 if (!sdi || !sdi->priv)
535 /* Can't know this until we have the exact model. */
536 return SR_ERR_ARG;
537 devc = sdi->priv;
538 *data = g_variant_new_strv(trigger_sources,
539 devc->has_digital ? ARRAY_SIZE(trigger_sources) : 4);
540 break;
541 default:
542 return SR_ERR_NA;
543 }
544
545 return SR_OK;
546}
547
548static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
549{
550 struct dev_context *devc;
551 struct sr_probe *probe;
552 GSList *l;
553 char cmd[256];
554
555 (void)cb_data;
556
557 devc = sdi->priv;
558
559 for (l = sdi->probes; l; l = l->next) {
560 probe = l->data;
561 sr_dbg("handling probe %s", probe->name);
562 if (probe->type == SR_PROBE_ANALOG) {
563 if (probe->enabled)
564 devc->enabled_analog_probes = g_slist_append(
565 devc->enabled_analog_probes, probe);
566 if (probe->enabled != devc->analog_channels[probe->index]) {
567 /* Enabled channel is currently disabled, or vice versa. */
568 sprintf(cmd, ":CHAN%d:DISP %s", probe->index + 1,
569 probe->enabled ? "ON" : "OFF");
570 if (rigol_ds1xx2_send(devc, cmd) != SR_OK)
571 return SR_ERR;
572 }
573 } else if (probe->type == SR_PROBE_LOGIC) {
574 if (probe->enabled)
575 devc->enabled_digital_probes = g_slist_append(
576 devc->enabled_digital_probes, probe);
577 if (probe->enabled != devc->digital_channels[probe->index]) {
578 /* Enabled channel is currently disabled, or vice versa. */
579 sprintf(cmd, ":DIG%d:TURN %s", probe->index,
580 probe->enabled ? "ON" : "OFF");
581 if (rigol_ds1xx2_send(devc, cmd) != SR_OK)
582 return SR_ERR;
583 }
584 }
585 }
586 if (!devc->enabled_analog_probes && !devc->enabled_digital_probes)
587 return SR_ERR;
588
589 sr_source_add(devc->fd, G_IO_IN, 50, rigol_ds1xx2_receive, (void *)sdi);
590
591 /* Send header packet to the session bus. */
592 std_session_send_df_header(cb_data, DRIVER_LOG_DOMAIN);
593
594 /* Fetch the first frame. */
595 if (devc->enabled_analog_probes) {
596 devc->channel_frame = devc->enabled_analog_probes->data;
597 if (rigol_ds1xx2_send(devc, ":WAV:DATA? CHAN%d",
598 devc->channel_frame->index + 1) != SR_OK)
599 return SR_ERR;
600 } else {
601 devc->channel_frame = devc->enabled_digital_probes->data;
602 if (rigol_ds1xx2_send(devc, ":WAV:DATA? DIG") != SR_OK)
603 return SR_ERR;
604 }
605
606 devc->num_frame_bytes = 0;
607
608 return SR_OK;
609}
610
611static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
612{
613 struct dev_context *devc;
614
615 (void)cb_data;
616
617 devc = sdi->priv;
618
619 if (sdi->status != SR_ST_ACTIVE) {
620 sr_err("Device inactive, can't stop acquisition.");
621 return SR_ERR;
622 }
623
624 g_slist_free(devc->enabled_analog_probes);
625 g_slist_free(devc->enabled_digital_probes);
626 devc->enabled_analog_probes = NULL;
627 devc->enabled_digital_probes = NULL;
628 sr_source_remove(devc->fd);
629
630 return SR_OK;
631}
632
633SR_PRIV struct sr_dev_driver rigol_ds1xx2_driver_info = {
634 .name = "rigol-ds1xx2",
635 .longname = "Rigol DS1xx2",
636 .api_version = 1,
637 .init = hw_init,
638 .cleanup = hw_cleanup,
639 .scan = hw_scan,
640 .dev_list = hw_dev_list,
641 .dev_clear = clear_instances,
642 .config_get = config_get,
643 .config_set = config_set,
644 .config_list = config_list,
645 .dev_open = hw_dev_open,
646 .dev_close = hw_dev_close,
647 .dev_acquisition_start = dev_acquisition_start,
648 .dev_acquisition_stop = dev_acquisition_stop,
649 .priv = NULL,
650};