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