From: Martin Ling Date: Thu, 31 Oct 2013 17:31:39 +0000 (+0000) Subject: Rename rigol-ds1xx2 driver to rigol-ds. X-Git-Tag: libsigrok-0.3.0~527 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=3086efdd73885820da142ce8c36053bbc3cf0e5f;p=libsigrok.git Rename rigol-ds1xx2 driver to rigol-ds. --- diff --git a/README.devices b/README.devices index f28462a0..a99fc7e2 100644 --- a/README.devices +++ b/README.devices @@ -66,7 +66,7 @@ The following drivers/devices do not need any firmware upload: - mic-985xx - norma-dmm - openbench-logic-sniffer - - rigol-ds1xx2 + - rigol-ds - serial-dmm - teleinfo - tondaj-sl-814 @@ -118,7 +118,7 @@ The following drivers/devices do not require a serial port specification: - ikalogic-scanaplus - kecheng-kc-330b - lascar-el-usb - - rigol-ds1xx2 + - rigol-ds - saleae-logic16 - uni-t-dmm - uni-t-ut32x @@ -344,12 +344,12 @@ Example: $ sigrok-cli --driver ols:conn=/dev/ttyACM0 ... -Rigol DS1xx2 oscilloscopes --------------------------- +Rigol DS oscilloscopes +---------------------- -The 'rigol-ds1xx2' driver (for the Rigol DS1052E and some other, similar DSOs) -currently uses the Linux usbtmc kernel driver. This means it can currently -only be built and used on Linux (i.e., it's non-portable). +The 'rigol-ds' driver (for the Rigol DS series DSOs) currently uses the Linux +usbtmc kernel driver. This means it can currently only be built and used on +Linux (i.e., it's non-portable). The use of a kernel module also means it is dependent on the kernel version used, as well as on whether this specific module is available in the kernel. @@ -360,4 +360,3 @@ module as opposed to a libusb-based driver that works in user-space. We plan to change the driver to use the 'librevisa' user-space shared library (which uses libusb) soon, which will fix all these issues and make the driver portable at the same time. - diff --git a/configure.ac b/configure.ac index 29880ee5..c1c4aedc 100644 --- a/configure.ac +++ b/configure.ac @@ -189,10 +189,10 @@ AC_ARG_ENABLE(ols, AC_HELP_STRING([--enable-ols], [HW_OLS="$enableval"], [HW_OLS=$HW_ENABLED_DEFAULT]) -AC_ARG_ENABLE(rigol-ds1xx2, AC_HELP_STRING([--enable-rigol-ds1xx2], - [enable Rigol DS1xx2 support [default=yes]]), - [HW_RIGOL_DS1XX2="$enableval"], - [HW_RIGOL_DS1XX2=$HW_ENABLED_DEFAULT]) +AC_ARG_ENABLE(rigol-ds, AC_HELP_STRING([--enable-rigol-ds], + [enable Rigol DS support [default=yes]]), + [HW_RIGOL_DS="$enableval"], + [HW_RIGOL_DS=$HW_ENABLED_DEFAULT]) AC_ARG_ENABLE(saleae-logic16, AC_HELP_STRING([--enable-saleae-logic16], [enable Saleae Logic16 support [default=yes]]), @@ -334,18 +334,18 @@ PKG_CHECK_MODULES([check], [check >= 0.9.4], LIBS="$LIBS $check_LIBS"], [have_check="no"]) AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes") -# The Rigol DS1xx2 driver currently uses the Linux kernel usbtmc module +# The Rigol DS driver currently uses the Linux kernel usbtmc module # (though it is planned to rewrite the driver to be portable later). # Thus, it will be disabled for non-Linux builds for now. case "$host" in *linux*) # Do nothing. Whether the driver is enabled is determined by the # previous --enable-all-drivers/--disable-all-drivers and/or any - # --enable-rigol-ds1xx2/--disable-rigol-ds1xx2 options. + # --enable-rigol-ds/--disable-rigol-ds options. ;; *) # Disable the driver for builds that don't target Linux. - HW_RIGOL_DS1XX2="no" + HW_RIGOL_DS="no" ;; esac @@ -458,9 +458,9 @@ if test "x$HW_OLS" = "xyes"; then AC_DEFINE(HAVE_HW_OLS, 1, [OpenBench Logic Sniffer (OLS) support]) fi -AM_CONDITIONAL(HW_RIGOL_DS1XX2, test x$HW_RIGOL_DS1XX2 = xyes) -if test "x$HW_RIGOL_DS1XX2" = "xyes"; then - AC_DEFINE(HAVE_HW_RIGOL_DS1XX2, 1, [Rigol DS1xx2 support]) +AM_CONDITIONAL(HW_RIGOL_DS, test x$HW_RIGOL_DS = xyes) +if test "x$HW_RIGOL_DS" = "xyes"; then + AC_DEFINE(HAVE_HW_RIGOL_DS, 1, [Rigol DS support]) fi AM_CONDITIONAL(HW_SALEAE_LOGIC16, test x$HW_SALEAE_LOGIC16 = xyes) @@ -553,7 +553,7 @@ AC_CONFIG_FILES([Makefile version.h hardware/Makefile hardware/kecheng-kc-330b/Makefile hardware/lascar-el-usb/Makefile hardware/mic-985xx/Makefile - hardware/rigol-ds1xx2/Makefile + hardware/rigol-ds/Makefile hardware/saleae-logic16/Makefile hardware/teleinfo/Makefile hardware/tondaj-sl-814/Makefile @@ -625,7 +625,7 @@ echo " - link-mso19 (EXPERIMENTAL)....... $HW_LINK_MSO19" echo " - mic-985xx....................... $HW_MIC_985XX" echo " - norma-dmm....................... $HW_NORMA_DMM" echo " - openbench-logic-sniffer......... $HW_OLS" -echo " - rigol-ds1xx2.................... $HW_RIGOL_DS1XX2" +echo " - rigol-ds........................ $HW_RIGOL_DS" echo " - saleae-logic16.................. $HW_SALEAE_LOGIC16" echo " - serial-dmm...................... $HW_SERIAL_DMM" echo " - teleinfo........................ $HW_TELEINFO" diff --git a/contrib/gnuplot_rigol_ds1xx2.gpi b/contrib/gnuplot_rigol_ds1xx2.gpi index 6800158b..a598b9eb 100644 --- a/contrib/gnuplot_rigol_ds1xx2.gpi +++ b/contrib/gnuplot_rigol_ds1xx2.gpi @@ -30,7 +30,7 @@ set output "sigrok_gnuplot.png" # Rigol DS1xx2 output is currently always 600 samples in size. # This script currently also assumes only one channel is acquired like this: # -# $ sigrok-cli --driver rigol-ds1xx2 --frames 1 -p CH1 ... +# $ sigrok-cli --driver rigol-ds --frames 1 -p CH1 ... # plot [0:600] \ "sigrok_gnuplot.dat" using 1 with lines linewidth 2 title "CH1" diff --git a/hardware/Makefile.am b/hardware/Makefile.am index 27735af6..fec45790 100644 --- a/hardware/Makefile.am +++ b/hardware/Makefile.am @@ -41,7 +41,7 @@ SUBDIRS = \ mic-985xx \ norma-dmm \ openbench-logic-sniffer \ - rigol-ds1xx2 \ + rigol-ds \ saleae-logic16 \ serial-dmm \ teleinfo \ @@ -142,8 +142,8 @@ if HW_OLS libsigrokhardware_la_LIBADD += openbench-logic-sniffer/libsigrok_hw_ols.la endif -if HW_RIGOL_DS1XX2 -libsigrokhardware_la_LIBADD += rigol-ds1xx2/libsigrok_hw_rigol_ds1xx2.la +if HW_RIGOL_DS +libsigrokhardware_la_LIBADD += rigol-ds/libsigrok_hw_rigol_ds.la endif if HW_SALEAE_LOGIC16 diff --git a/hardware/rigol-ds/Makefile.am b/hardware/rigol-ds/Makefile.am new file mode 100644 index 00000000..fba4226d --- /dev/null +++ b/hardware/rigol-ds/Makefile.am @@ -0,0 +1,33 @@ +## +## This file is part of the libsigrok project. +## +## Copyright (C) 2012 Martin Ling +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see . +## + +if HW_RIGOL_DS + +# Local lib, this is NOT meant to be installed! +noinst_LTLIBRARIES = libsigrok_hw_rigol_ds.la + +libsigrok_hw_rigol_ds_la_SOURCES = \ + api.c \ + protocol.c \ + protocol.h + +libsigrok_hw_rigol_ds_la_CFLAGS = \ + -I$(top_srcdir) + +endif diff --git a/hardware/rigol-ds/api.c b/hardware/rigol-ds/api.c new file mode 100644 index 00000000..e0f4eaea --- /dev/null +++ b/hardware/rigol-ds/api.c @@ -0,0 +1,758 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2012 Martin Ling + * Copyright (C) 2013 Bert Vermeulen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include "libsigrok.h" +#include "libsigrok-internal.h" +#include "protocol.h" + +#define NUM_TIMEBASE 12 +#define NUM_VDIV 8 + +static const int32_t hwopts[] = { + SR_CONF_CONN, +}; + +static const int32_t hwcaps[] = { + SR_CONF_OSCILLOSCOPE, + SR_CONF_TIMEBASE, + SR_CONF_TRIGGER_SOURCE, + SR_CONF_TRIGGER_SLOPE, + SR_CONF_HORIZ_TRIGGERPOS, + SR_CONF_NUM_TIMEBASE, +}; + +static const int32_t analog_hwcaps[] = { + SR_CONF_NUM_VDIV, + SR_CONF_VDIV, + SR_CONF_COUPLING, +}; + +static const uint64_t timebases[][2] = { + /* nanoseconds */ + { 2, 1000000000 }, + { 5, 1000000000 }, + { 10, 1000000000 }, + { 20, 1000000000 }, + { 50, 1000000000 }, + { 100, 1000000000 }, + { 500, 1000000000 }, + /* microseconds */ + { 1, 1000000 }, + { 2, 1000000 }, + { 5, 1000000 }, + { 10, 1000000 }, + { 20, 1000000 }, + { 50, 1000000 }, + { 100, 1000000 }, + { 200, 1000000 }, + { 500, 1000000 }, + /* milliseconds */ + { 1, 1000 }, + { 2, 1000 }, + { 5, 1000 }, + { 10, 1000 }, + { 20, 1000 }, + { 50, 1000 }, + { 100, 1000 }, + { 200, 1000 }, + { 500, 1000 }, + /* seconds */ + { 1, 1 }, + { 2, 1 }, + { 5, 1 }, + { 10, 1 }, + { 20, 1 }, + { 50, 1 }, +}; + +static const uint64_t vdivs[][2] = { + /* millivolts */ + { 2, 1000 }, + { 5, 1000 }, + { 10, 1000 }, + { 20, 1000 }, + { 50, 1000 }, + { 100, 1000 }, + { 200, 1000 }, + { 500, 1000 }, + /* volts */ + { 1, 1 }, + { 2, 1 }, + { 5, 1 }, + { 10, 1 }, +}; + +static const char *trigger_sources[] = { + "CH1", + "CH2", + "EXT", + "AC Line", + "D0", + "D1", + "D2", + "D3", + "D4", + "D5", + "D6", + "D7", + "D8", + "D9", + "D10", + "D11", + "D12", + "D13", + "D14", + "D15", +}; + +static const char *coupling[] = { + "AC", + "DC", + "GND", +}; + +static const char *supported_models[] = { + "DS1052E", + "DS1102E", + "DS1152E", + "DS1052D", + "DS1102D", + "DS1152D", +}; + +SR_PRIV struct sr_dev_driver rigol_ds_driver_info; +static struct sr_dev_driver *di = &rigol_ds_driver_info; + +static void clear_helper(void *priv) +{ + struct dev_context *devc; + + devc = priv; + g_free(devc->coupling[0]); + g_free(devc->coupling[1]); + g_free(devc->trigger_source); + g_free(devc->trigger_slope); + g_slist_free(devc->analog_groups[0].probes); + g_slist_free(devc->analog_groups[1].probes); + g_slist_free(devc->digital_group.probes); +} + +static int dev_clear(void) +{ + return std_dev_clear(di, clear_helper); +} + +static int set_cfg(const struct sr_dev_inst *sdi, const char *format, ...) +{ + va_list args; + char buf[256]; + + va_start(args, format); + vsnprintf(buf, 255, format, args); + va_end(args); + if (rigol_ds_send(sdi, buf) != SR_OK) + return SR_ERR; + + /* When setting a bunch of parameters in a row, the DS1052E scrambles + * some of them unless there is at least 100ms delay in between. */ + sr_spew("delay %dms", 100); + g_usleep(100000); + + return SR_OK; +} + +static int init(struct sr_context *sr_ctx) +{ + return std_init(sr_ctx, di, LOG_PREFIX); +} + +static int probe_port(const char *port, GSList **devices) +{ + struct dev_context *devc; + struct sr_dev_inst *sdi; + struct sr_serial_dev_inst *serial; + struct sr_probe *probe; + unsigned int i; + int len, num_tokens; + gboolean matched, has_digital; + const char *manufacturer, *model, *version; + char buf[256]; + gchar **tokens, *channel_name; + + *devices = NULL; + if (!(serial = sr_serial_dev_inst_new(port, NULL))) + return SR_ERR_MALLOC; + + if (serial_open(serial, SERIAL_RDWR) != SR_OK) + return SR_ERR; + len = serial_write(serial, "*IDN?", 5); + len = serial_read(serial, buf, sizeof(buf)); + if (serial_close(serial) != SR_OK) + return SR_ERR; + + sr_serial_dev_inst_free(serial); + + if (len == 0) + return SR_ERR_NA; + + buf[len] = 0; + tokens = g_strsplit(buf, ",", 0); + sr_dbg("response: %s [%s]", port, buf); + + for (num_tokens = 0; tokens[num_tokens] != NULL; num_tokens++); + + if (num_tokens < 4) { + g_strfreev(tokens); + return SR_ERR_NA; + } + + manufacturer = tokens[0]; + model = tokens[1]; + version = tokens[3]; + + if (strcmp(manufacturer, "Rigol Technologies")) { + g_strfreev(tokens); + return SR_ERR_NA; + } + + matched = has_digital = FALSE; + for (i = 0; i < ARRAY_SIZE(supported_models); i++) { + if (!strcmp(model, supported_models[i])) { + matched = TRUE; + has_digital = g_str_has_suffix(model, "D"); + break; + } + } + + if (!matched || !(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, + manufacturer, model, version))) { + g_strfreev(tokens); + return SR_ERR_NA; + } + + g_strfreev(tokens); + + if (!(sdi->conn = sr_serial_dev_inst_new(port, NULL))) + return SR_ERR_MALLOC; + sdi->driver = di; + sdi->inst_type = SR_INST_SERIAL; + + if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) + return SR_ERR_MALLOC; + devc->limit_frames = 0; + devc->has_digital = has_digital; + + for (i = 0; i < 2; i++) { + channel_name = (i == 0 ? "CH1" : "CH2"); + if (!(probe = sr_probe_new(i, SR_PROBE_ANALOG, TRUE, channel_name))) + return SR_ERR_MALLOC; + sdi->probes = g_slist_append(sdi->probes, probe); + devc->analog_groups[i].name = channel_name; + devc->analog_groups[i].probes = g_slist_append(NULL, probe); + sdi->probe_groups = g_slist_append(sdi->probe_groups, + &devc->analog_groups[i]); + } + + if (devc->has_digital) { + for (i = 0; i < 16; i++) { + if (!(channel_name = g_strdup_printf("D%d", i))) + return SR_ERR_MALLOC; + probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, channel_name); + g_free(channel_name); + if (!probe) + return SR_ERR_MALLOC; + sdi->probes = g_slist_append(sdi->probes, probe); + devc->digital_group.probes = g_slist_append( + devc->digital_group.probes, probe); + devc->digital_group.name = "LA"; + sdi->probe_groups = g_slist_append(sdi->probe_groups, + &devc->digital_group); + } + } + sdi->priv = devc; + + *devices = g_slist_append(NULL, sdi); + + return SR_OK; +} + +static GSList *scan(GSList *options) +{ + struct drv_context *drvc; + struct sr_config *src; + GSList *l, *devices; + GDir *dir; + int ret; + const gchar *dev_name; + gchar *port = NULL; + + drvc = di->priv; + + for (l = options; l; l = l->next) { + src = l->data; + if (src->key == SR_CONF_CONN) { + port = (char *)g_variant_get_string(src->data, NULL); + break; + } + } + + devices = NULL; + if (port) { + if (probe_port(port, &devices) == SR_ERR_MALLOC) + return NULL; + } else { + if (!(dir = g_dir_open("/sys/class/usbmisc/", 0, NULL))) + if (!(dir = g_dir_open("/sys/class/usb/", 0, NULL))) + return NULL; + while ((dev_name = g_dir_read_name(dir))) { + if (strncmp(dev_name, "usbtmc", 6)) + continue; + port = g_strconcat("/dev/", dev_name, NULL); + ret = probe_port(port, &devices); + g_free(port); + if (ret == SR_ERR_MALLOC) { + g_dir_close(dir); + return NULL; + } + } + g_dir_close(dir); + } + + /* Tack a copy of the newly found devices onto the driver list. */ + l = g_slist_copy(devices); + drvc->instances = g_slist_concat(drvc->instances, l); + + return devices; +} + +static GSList *dev_list(void) +{ + return ((struct drv_context *)(di->priv))->instances; +} + +static int dev_open(struct sr_dev_inst *sdi) +{ + + if (serial_open(sdi->conn, SERIAL_RDWR) != SR_OK) + return SR_ERR; + + if (rigol_ds_get_dev_cfg(sdi) != SR_OK) + return SR_ERR; + + sdi->status = SR_ST_ACTIVE; + + return SR_OK; +} + +static int dev_close(struct sr_dev_inst *sdi) +{ + struct sr_serial_dev_inst *serial; + + serial = sdi->conn; + if (serial && serial->fd != -1) { + serial_close(serial); + sdi->status = SR_ST_INACTIVE; + } + + return SR_OK; +} + +static int cleanup(void) +{ + return dev_clear(); +} + +static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_probe_group *probe_group) +{ + struct dev_context *devc; + unsigned int i; + + if (!sdi || !(devc = sdi->priv)) + return SR_ERR_ARG; + + /* If a probe group is specified, it must be a valid one. */ + if (probe_group) { + if (probe_group != &devc->analog_groups[0] + && probe_group != &devc->analog_groups[1]) { + sr_err("Invalid probe group specified."); + return SR_ERR; + } + } + + switch (id) { + case SR_CONF_NUM_TIMEBASE: + *data = g_variant_new_int32(NUM_TIMEBASE); + break; + case SR_CONF_NUM_VDIV: + if (!probe_group) { + sr_err("No probe group specified."); + return SR_ERR_PROBE_GROUP; + } + for (i = 0; i < 2; i++) { + if (probe_group == &devc->analog_groups[i]) { + *data = g_variant_new_int32(NUM_VDIV); + return SR_OK; + } + } + return SR_ERR_NA; + default: + return SR_ERR_NA; + } + + return SR_OK; +} + +static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, + const struct sr_probe_group *probe_group) +{ + struct dev_context *devc; + uint64_t tmp_u64, p, q; + double t_dbl; + unsigned int i, j; + int ret; + const char *tmp_str; + + if (!(devc = sdi->priv)) + return SR_ERR_ARG; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + + /* If a probe group is specified, it must be a valid one. */ + if (probe_group) { + if (probe_group != &devc->analog_groups[0] + && probe_group != &devc->analog_groups[1]) { + sr_err("Invalid probe group specified."); + return SR_ERR; + } + } + + ret = SR_OK; + switch (id) { + case SR_CONF_LIMIT_FRAMES: + devc->limit_frames = g_variant_get_uint64(data); + break; + case SR_CONF_TRIGGER_SLOPE: + tmp_u64 = g_variant_get_uint64(data); + if (tmp_u64 != 0 && tmp_u64 != 1) + return SR_ERR; + g_free(devc->trigger_slope); + devc->trigger_slope = g_strdup(tmp_u64 ? "POS" : "NEG"); + ret = set_cfg(sdi, ":TRIG:EDGE:SLOP %s", devc->trigger_slope); + break; + case SR_CONF_HORIZ_TRIGGERPOS: + t_dbl = g_variant_get_double(data); + if (t_dbl < 0.0 || t_dbl > 1.0) + return SR_ERR; + devc->horiz_triggerpos = t_dbl; + /* We have the trigger offset as a percentage of the frame, but + * need to express this in seconds. */ + t_dbl = -(devc->horiz_triggerpos - 0.5) * devc->timebase * NUM_TIMEBASE; + ret = set_cfg(sdi, ":TIM:OFFS %.6f", t_dbl); + break; + case SR_CONF_TIMEBASE: + g_variant_get(data, "(tt)", &p, &q); + for (i = 0; i < ARRAY_SIZE(timebases); i++) { + if (timebases[i][0] == p && timebases[i][1] == q) { + devc->timebase = (float)p / q; + ret = set_cfg(sdi, ":TIM:SCAL %.9f", devc->timebase); + break; + } + } + if (i == ARRAY_SIZE(timebases)) + ret = SR_ERR_ARG; + break; + case SR_CONF_TRIGGER_SOURCE: + tmp_str = g_variant_get_string(data, NULL); + for (i = 0; i < ARRAY_SIZE(trigger_sources); i++) { + if (!strcmp(trigger_sources[i], tmp_str)) { + g_free(devc->trigger_source); + devc->trigger_source = g_strdup(trigger_sources[i]); + if (!strcmp(devc->trigger_source, "AC Line")) + tmp_str = "ACL"; + else if (!strcmp(devc->trigger_source, "CH1")) + tmp_str = "CHAN1"; + else if (!strcmp(devc->trigger_source, "CH2")) + tmp_str = "CHAN2"; + else + tmp_str = (char *)devc->trigger_source; + ret = set_cfg(sdi, ":TRIG:EDGE:SOUR %s", tmp_str); + break; + } + } + if (i == ARRAY_SIZE(trigger_sources)) + ret = SR_ERR_ARG; + break; + case SR_CONF_VDIV: + if (!probe_group) { + sr_err("No probe group specified."); + return SR_ERR_PROBE_GROUP; + } + g_variant_get(data, "(tt)", &p, &q); + for (i = 0; i < 2; i++) { + if (probe_group == &devc->analog_groups[i]) { + for (j = 0; j < ARRAY_SIZE(vdivs); j++) { + if (vdivs[j][0] != p || vdivs[j][1] != q) + continue; + devc->vdiv[i] = (float)p / q; + return set_cfg(sdi, ":CHAN%d:SCAL %.3f", i + 1, + devc->vdiv[i]); + } + return SR_ERR_ARG; + } + } + return SR_ERR_NA; + case SR_CONF_COUPLING: + if (!probe_group) { + sr_err("No probe group specified."); + return SR_ERR_PROBE_GROUP; + } + tmp_str = g_variant_get_string(data, NULL); + for (i = 0; i < 2; i++) { + if (probe_group == &devc->analog_groups[i]) { + for (j = 0; j < ARRAY_SIZE(coupling); j++) { + if (!strcmp(tmp_str, coupling[j])) { + g_free(devc->coupling[i]); + devc->coupling[i] = g_strdup(coupling[j]); + return set_cfg(sdi, ":CHAN%d:COUP %s", i + 1, + devc->coupling[i]); + } + } + return SR_ERR_ARG; + } + } + return SR_ERR_NA; + default: + ret = SR_ERR_NA; + break; + } + + return ret; +} + +static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_probe_group *probe_group) +{ + GVariant *tuple, *rational[2]; + GVariantBuilder gvb; + unsigned int i; + struct dev_context *devc; + + if (key == SR_CONF_SCAN_OPTIONS) { + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, + hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); + return SR_OK; + } else if (key == SR_CONF_DEVICE_OPTIONS && probe_group == NULL) { + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, + hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); + return SR_OK; + } + + /* Every other option requires a valid device instance. */ + if (!sdi || !(devc = sdi->priv)) + return SR_ERR_ARG; + + /* If a probe group is specified, it must be a valid one. */ + if (probe_group) { + if (probe_group != &devc->analog_groups[0] + && probe_group != &devc->analog_groups[1]) { + sr_err("Invalid probe group specified."); + return SR_ERR; + } + } + + switch (key) { + break; + case SR_CONF_DEVICE_OPTIONS: + if (!probe_group) { + sr_err("No probe group specified."); + return SR_ERR_PROBE_GROUP; + } + if (probe_group == &devc->digital_group) { + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, + NULL, 0, sizeof(int32_t)); + return SR_OK; + } else { + for (i = 0; i < 2; i++) { + if (probe_group == &devc->analog_groups[i]) { + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, + analog_hwcaps, ARRAY_SIZE(analog_hwcaps), sizeof(int32_t)); + return SR_OK; + } + } + return SR_ERR_NA; + } + break; + case SR_CONF_COUPLING: + if (!probe_group) { + sr_err("No probe group specified."); + return SR_ERR_PROBE_GROUP; + } + *data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling)); + break; + case SR_CONF_VDIV: + if (!probe_group) { + sr_err("No probe group specified."); + return SR_ERR_PROBE_GROUP; + } + g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); + for (i = 0; i < ARRAY_SIZE(vdivs); i++) { + rational[0] = g_variant_new_uint64(vdivs[i][0]); + rational[1] = g_variant_new_uint64(vdivs[i][1]); + tuple = g_variant_new_tuple(rational, 2); + g_variant_builder_add_value(&gvb, tuple); + } + *data = g_variant_builder_end(&gvb); + break; + case SR_CONF_TIMEBASE: + g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); + for (i = 0; i < ARRAY_SIZE(timebases); i++) { + rational[0] = g_variant_new_uint64(timebases[i][0]); + rational[1] = g_variant_new_uint64(timebases[i][1]); + tuple = g_variant_new_tuple(rational, 2); + g_variant_builder_add_value(&gvb, tuple); + } + *data = g_variant_builder_end(&gvb); + break; + case SR_CONF_TRIGGER_SOURCE: + *data = g_variant_new_strv(trigger_sources, + devc->has_digital ? ARRAY_SIZE(trigger_sources) : 4); + break; + default: + return SR_ERR_NA; + } + + return SR_OK; +} + +static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) +{ + struct sr_serial_dev_inst *serial; + struct dev_context *devc; + struct sr_probe *probe; + GSList *l; + char cmd[256]; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + + serial = sdi->conn; + devc = sdi->priv; + + for (l = sdi->probes; l; l = l->next) { + probe = l->data; + sr_dbg("handling probe %s", probe->name); + if (probe->type == SR_PROBE_ANALOG) { + if (probe->enabled) + devc->enabled_analog_probes = g_slist_append( + devc->enabled_analog_probes, probe); + if (probe->enabled != devc->analog_channels[probe->index]) { + /* Enabled channel is currently disabled, or vice versa. */ + sprintf(cmd, ":CHAN%d:DISP %s", probe->index + 1, + probe->enabled ? "ON" : "OFF"); + if (rigol_ds_send(sdi, cmd) != SR_OK) + return SR_ERR; + } + } else if (probe->type == SR_PROBE_LOGIC) { + if (probe->enabled) + devc->enabled_digital_probes = g_slist_append( + devc->enabled_digital_probes, probe); + if (probe->enabled != devc->digital_channels[probe->index]) { + /* Enabled channel is currently disabled, or vice versa. */ + sprintf(cmd, ":DIG%d:TURN %s", probe->index, + probe->enabled ? "ON" : "OFF"); + if (rigol_ds_send(sdi, cmd) != SR_OK) + return SR_ERR; + } + } + } + if (!devc->enabled_analog_probes && !devc->enabled_digital_probes) + return SR_ERR; + + sr_source_add(serial->fd, G_IO_IN, 50, rigol_ds_receive, (void *)sdi); + + /* Send header packet to the session bus. */ + std_session_send_df_header(cb_data, LOG_PREFIX); + + /* Fetch the first frame. */ + if (devc->enabled_analog_probes) { + devc->channel_frame = devc->enabled_analog_probes->data; + if (rigol_ds_send(sdi, ":WAV:DATA? CHAN%d", + devc->channel_frame->index + 1) != SR_OK) + return SR_ERR; + } else { + devc->channel_frame = devc->enabled_digital_probes->data; + if (rigol_ds_send(sdi, ":WAV:DATA? DIG") != SR_OK) + return SR_ERR; + } + + devc->num_frame_bytes = 0; + + return SR_OK; +} + +static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) +{ + struct dev_context *devc; + struct sr_serial_dev_inst *serial; + + (void)cb_data; + + devc = sdi->priv; + + if (sdi->status != SR_ST_ACTIVE) { + sr_err("Device inactive, can't stop acquisition."); + return SR_ERR; + } + + g_slist_free(devc->enabled_analog_probes); + g_slist_free(devc->enabled_digital_probes); + devc->enabled_analog_probes = NULL; + devc->enabled_digital_probes = NULL; + serial = sdi->conn; + sr_source_remove(serial->fd); + + return SR_OK; +} + +SR_PRIV struct sr_dev_driver rigol_ds_driver_info = { + .name = "rigol-ds", + .longname = "Rigol DS", + .api_version = 1, + .init = init, + .cleanup = cleanup, + .scan = scan, + .dev_list = dev_list, + .dev_clear = dev_clear, + .config_get = config_get, + .config_set = config_set, + .config_list = config_list, + .dev_open = dev_open, + .dev_close = dev_close, + .dev_acquisition_start = dev_acquisition_start, + .dev_acquisition_stop = dev_acquisition_stop, + .priv = NULL, +}; diff --git a/hardware/rigol-ds/protocol.c b/hardware/rigol-ds/protocol.c new file mode 100644 index 00000000..19e660d4 --- /dev/null +++ b/hardware/rigol-ds/protocol.c @@ -0,0 +1,292 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2012 Martin Ling + * Copyright (C) 2013 Bert Vermeulen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include "libsigrok.h" +#include "libsigrok-internal.h" +#include "protocol.h" + +SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data) +{ + struct sr_dev_inst *sdi; + struct sr_serial_dev_inst *serial; + struct dev_context *devc; + struct sr_datafeed_packet packet; + struct sr_datafeed_analog analog; + struct sr_datafeed_logic logic; + unsigned char buf[DIGITAL_WAVEFORM_SIZE]; + double vdiv, offset; + float data[ANALOG_WAVEFORM_SIZE]; + int len, i, waveform_size; + struct sr_probe *probe; + + (void)fd; + + if (!(sdi = cb_data)) + return TRUE; + + if (!(devc = sdi->priv)) + return TRUE; + + serial = sdi->conn; + + if (revents == G_IO_IN) { + probe = devc->channel_frame; + waveform_size = probe->type == SR_PROBE_ANALOG ? + ANALOG_WAVEFORM_SIZE : DIGITAL_WAVEFORM_SIZE; + len = serial_read(serial, buf, waveform_size - devc->num_frame_bytes); + sr_dbg("Received %d bytes.", len); + if (len == -1) + return TRUE; + + if (devc->num_frame_bytes == 0) { + /* Start of a new frame. */ + packet.type = SR_DF_FRAME_BEGIN; + sr_session_send(sdi, &packet); + } + + if (probe->type == SR_PROBE_ANALOG) { + for (i = 0; i < len; i++) { + vdiv = devc->vdiv[probe->index]; + offset = devc->vert_offset[probe->index]; + data[i] = vdiv / 25.6 * (128 - buf[i]) - offset; + } + analog.probes = g_slist_append(NULL, probe); + analog.num_samples = len; + analog.data = data; + analog.mq = SR_MQ_VOLTAGE; + analog.unit = SR_UNIT_VOLT; + analog.mqflags = 0; + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + sr_session_send(cb_data, &packet); + g_slist_free(analog.probes); + + if (len != ANALOG_WAVEFORM_SIZE) + /* Don't have the whole frame yet. */ + return TRUE; + } else { + logic.length = len - 10; + logic.unitsize = 2; + logic.data = buf + 10; + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + sr_session_send(cb_data, &packet); + + if (len != DIGITAL_WAVEFORM_SIZE) + /* Don't have the whole frame yet. */ + return TRUE; + } + + /* End of the frame. */ + packet.type = SR_DF_FRAME_END; + sr_session_send(sdi, &packet); + devc->num_frame_bytes = 0; + + if (devc->enabled_analog_probes + && devc->channel_frame == devc->enabled_analog_probes->data + && devc->enabled_analog_probes->next != NULL) { + /* We got the frame for the first analog channel, but + * there's a second analog channel. */ + devc->channel_frame = devc->enabled_analog_probes->next->data; + rigol_ds_send(sdi, ":WAV:DATA? CHAN%c", + devc->channel_frame->name[2]); + } else { + /* Done with both analog channels in this frame. */ + if (devc->enabled_digital_probes + && devc->channel_frame != devc->enabled_digital_probes->data) { + /* Now we need to get the digital data. */ + devc->channel_frame = devc->enabled_digital_probes->data; + rigol_ds_send(sdi, ":WAV:DATA? DIG"); + } else if (++devc->num_frames == devc->limit_frames) { + /* End of last frame. */ + packet.type = SR_DF_END; + sr_session_send(sdi, &packet); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + } else { + /* Get the next frame, starting with the first analog channel. */ + if (devc->enabled_analog_probes) { + devc->channel_frame = devc->enabled_analog_probes->data; + rigol_ds_send(sdi, ":WAV:DATA? CHAN%c", + devc->channel_frame->name[2]); + } else { + devc->channel_frame = devc->enabled_digital_probes->data; + rigol_ds_send(sdi, ":WAV:DATA? DIG"); + } + } + } + } + + return TRUE; +} + +SR_PRIV int rigol_ds_send(const struct sr_dev_inst *sdi, const char *format, ...) +{ + va_list args; + char buf[256]; + int len, out, ret; + + va_start(args, format); + len = vsnprintf(buf, 255, format, args); + va_end(args); + strcat(buf, "\n"); + len++; + out = serial_write(sdi->conn, buf, len); + buf[len - 1] = '\0'; + if (out != len) { + sr_dbg("Only sent %d/%d bytes of '%s'.", out, len, buf); + ret = SR_ERR; + } else { + sr_spew("Sent '%s'.", buf); + ret = SR_OK; + } + + return ret; +} + +static int get_cfg(const struct sr_dev_inst *sdi, char *cmd, char *reply) +{ + int len; + + if (rigol_ds_send(sdi, cmd) != SR_OK) + return SR_ERR; + + if ((len = serial_read(sdi->conn, reply, 255)) < 0) + return SR_ERR; + reply[len] = '\0'; + sr_spew("Received '%s'.", reply); + + return SR_OK; +} + +static int get_cfg_float(const struct sr_dev_inst *sdi, char *cmd, float *f) +{ + char buf[256], *e; + + if (get_cfg(sdi, cmd, buf) != SR_OK) + return SR_ERR; + *f = strtof(buf, &e); + if (e == buf || (fpclassify(*f) & (FP_ZERO | FP_NORMAL)) == 0) { + sr_dbg("failed to parse response to '%s': '%s'", cmd, buf); + return SR_ERR; + } + + return SR_OK; +} + +static int get_cfg_string(const struct sr_dev_inst *sdi, char *cmd, char **buf) +{ + + if (!(*buf = g_try_malloc0(256))) + return SR_ERR_MALLOC; + + if (get_cfg(sdi, cmd, *buf) != SR_OK) + return SR_ERR; + + return SR_OK; +} + +SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + char *t_s, *cmd; + int i, res; + + devc = sdi->priv; + + /* Analog channel state. */ + if (get_cfg_string(sdi, ":CHAN1:DISP?", &t_s) != SR_OK) + return SR_ERR; + devc->analog_channels[0] = !strcmp(t_s, "ON") ? TRUE : FALSE; + g_free(t_s); + if (get_cfg_string(sdi, ":CHAN2:DISP?", &t_s) != SR_OK) + return SR_ERR; + devc->analog_channels[1] = !strcmp(t_s, "ON") ? TRUE : FALSE; + g_free(t_s); + sr_dbg("Current analog channel state CH1 %s CH2 %s", + devc->analog_channels[0] ? "on" : "off", + devc->analog_channels[1] ? "on" : "off"); + + /* Digital channel state. */ + if (devc->has_digital) { + sr_dbg("Current digital channel state:"); + for (i = 0; i < 16; i++) { + cmd = g_strdup_printf(":DIG%d:TURN?", i); + res = get_cfg_string(sdi, cmd, &t_s); + g_free(cmd); + if (res != SR_OK) + return SR_ERR; + devc->digital_channels[i] = !strcmp(t_s, "ON") ? TRUE : FALSE; + g_free(t_s); + sr_dbg("D%d: %s", i, devc->digital_channels[i] ? "on" : "off"); + } + } + + /* Timebase. */ + if (get_cfg_float(sdi, ":TIM:SCAL?", &devc->timebase) != SR_OK) + return SR_ERR; + sr_dbg("Current timebase %f", devc->timebase); + + /* Vertical gain. */ + if (get_cfg_float(sdi, ":CHAN1:SCAL?", &devc->vdiv[0]) != SR_OK) + return SR_ERR; + if (get_cfg_float(sdi, ":CHAN2:SCAL?", &devc->vdiv[1]) != SR_OK) + return SR_ERR; + sr_dbg("Current vertical gain CH1 %f CH2 %f", devc->vdiv[0], devc->vdiv[1]); + + /* Vertical offset. */ + if (get_cfg_float(sdi, ":CHAN1:OFFS?", &devc->vert_offset[0]) != SR_OK) + return SR_ERR; + if (get_cfg_float(sdi, ":CHAN2:OFFS?", &devc->vert_offset[1]) != SR_OK) + return SR_ERR; + sr_dbg("Current vertical offset CH1 %f CH2 %f", devc->vert_offset[0], + devc->vert_offset[1]); + + /* Coupling. */ + if (get_cfg_string(sdi, ":CHAN1:COUP?", &devc->coupling[0]) != SR_OK) + return SR_ERR; + if (get_cfg_string(sdi, ":CHAN2:COUP?", &devc->coupling[1]) != SR_OK) + return SR_ERR; + sr_dbg("Current coupling CH1 %s CH2 %s", devc->coupling[0], + devc->coupling[1]); + + /* Trigger source. */ + if (get_cfg_string(sdi, ":TRIG:EDGE:SOUR?", &devc->trigger_source) != SR_OK) + return SR_ERR; + sr_dbg("Current trigger source %s", devc->trigger_source); + + /* Horizontal trigger position. */ + if (get_cfg_float(sdi, ":TIM:OFFS?", &devc->horiz_triggerpos) != SR_OK) + return SR_ERR; + sr_dbg("Current horizontal trigger position %f", devc->horiz_triggerpos); + + /* Trigger slope. */ + if (get_cfg_string(sdi, ":TRIG:EDGE:SLOP?", &devc->trigger_slope) != SR_OK) + return SR_ERR; + sr_dbg("Current trigger slope %s", devc->trigger_slope); + + return SR_OK; +} diff --git a/hardware/rigol-ds/protocol.h b/hardware/rigol-ds/protocol.h new file mode 100644 index 00000000..cce22b28 --- /dev/null +++ b/hardware/rigol-ds/protocol.h @@ -0,0 +1,76 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2012 Martin Ling + * Copyright (C) 2013 Bert Vermeulen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H +#define LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H + +#include +#include "libsigrok.h" +#include "libsigrok-internal.h" + +/* Message logging helpers with subsystem-specific prefix string. */ +#define LOG_PREFIX "rigol-ds: " +#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args) +#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args) +#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args) +#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args) +#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) +#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) + +#define ANALOG_WAVEFORM_SIZE 600 +#define DIGITAL_WAVEFORM_SIZE 1210 + +/** Private, per-device-instance driver context. */ +struct dev_context { + /* Device features */ + gboolean has_digital; + + /* Probe groups */ + struct sr_probe_group analog_groups[2]; + struct sr_probe_group digital_group; + + /* Acquisition settings */ + GSList *enabled_analog_probes; + GSList *enabled_digital_probes; + uint64_t limit_frames; + void *cb_data; + + /* Device settings */ + gboolean analog_channels[2]; + gboolean digital_channels[16]; + float timebase; + float vdiv[2]; + float vert_offset[2]; + char *trigger_source; + float horiz_triggerpos; + char *trigger_slope; + char *coupling[2]; + + /* Operational state */ + uint64_t num_frames; + uint64_t num_frame_bytes; + struct sr_probe *channel_frame; +}; + +SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data); +SR_PRIV int rigol_ds_send(const struct sr_dev_inst *sdi, const char *format, ...); +SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi); + +#endif diff --git a/hardware/rigol-ds1xx2/Makefile.am b/hardware/rigol-ds1xx2/Makefile.am deleted file mode 100644 index a538df0e..00000000 --- a/hardware/rigol-ds1xx2/Makefile.am +++ /dev/null @@ -1,33 +0,0 @@ -## -## This file is part of the libsigrok project. -## -## Copyright (C) 2012 Martin Ling -## -## This program is free software: you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation, either version 3 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program. If not, see . -## - -if HW_RIGOL_DS1XX2 - -# Local lib, this is NOT meant to be installed! -noinst_LTLIBRARIES = libsigrok_hw_rigol_ds1xx2.la - -libsigrok_hw_rigol_ds1xx2_la_SOURCES = \ - api.c \ - protocol.c \ - protocol.h - -libsigrok_hw_rigol_ds1xx2_la_CFLAGS = \ - -I$(top_srcdir) - -endif diff --git a/hardware/rigol-ds1xx2/api.c b/hardware/rigol-ds1xx2/api.c deleted file mode 100644 index d6f055e6..00000000 --- a/hardware/rigol-ds1xx2/api.c +++ /dev/null @@ -1,758 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2012 Martin Ling - * Copyright (C) 2013 Bert Vermeulen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include "libsigrok.h" -#include "libsigrok-internal.h" -#include "protocol.h" - -#define NUM_TIMEBASE 12 -#define NUM_VDIV 8 - -static const int32_t hwopts[] = { - SR_CONF_CONN, -}; - -static const int32_t hwcaps[] = { - SR_CONF_OSCILLOSCOPE, - SR_CONF_TIMEBASE, - SR_CONF_TRIGGER_SOURCE, - SR_CONF_TRIGGER_SLOPE, - SR_CONF_HORIZ_TRIGGERPOS, - SR_CONF_NUM_TIMEBASE, -}; - -static const int32_t analog_hwcaps[] = { - SR_CONF_NUM_VDIV, - SR_CONF_VDIV, - SR_CONF_COUPLING, -}; - -static const uint64_t timebases[][2] = { - /* nanoseconds */ - { 2, 1000000000 }, - { 5, 1000000000 }, - { 10, 1000000000 }, - { 20, 1000000000 }, - { 50, 1000000000 }, - { 100, 1000000000 }, - { 500, 1000000000 }, - /* microseconds */ - { 1, 1000000 }, - { 2, 1000000 }, - { 5, 1000000 }, - { 10, 1000000 }, - { 20, 1000000 }, - { 50, 1000000 }, - { 100, 1000000 }, - { 200, 1000000 }, - { 500, 1000000 }, - /* milliseconds */ - { 1, 1000 }, - { 2, 1000 }, - { 5, 1000 }, - { 10, 1000 }, - { 20, 1000 }, - { 50, 1000 }, - { 100, 1000 }, - { 200, 1000 }, - { 500, 1000 }, - /* seconds */ - { 1, 1 }, - { 2, 1 }, - { 5, 1 }, - { 10, 1 }, - { 20, 1 }, - { 50, 1 }, -}; - -static const uint64_t vdivs[][2] = { - /* millivolts */ - { 2, 1000 }, - { 5, 1000 }, - { 10, 1000 }, - { 20, 1000 }, - { 50, 1000 }, - { 100, 1000 }, - { 200, 1000 }, - { 500, 1000 }, - /* volts */ - { 1, 1 }, - { 2, 1 }, - { 5, 1 }, - { 10, 1 }, -}; - -static const char *trigger_sources[] = { - "CH1", - "CH2", - "EXT", - "AC Line", - "D0", - "D1", - "D2", - "D3", - "D4", - "D5", - "D6", - "D7", - "D8", - "D9", - "D10", - "D11", - "D12", - "D13", - "D14", - "D15", -}; - -static const char *coupling[] = { - "AC", - "DC", - "GND", -}; - -static const char *supported_models[] = { - "DS1052E", - "DS1102E", - "DS1152E", - "DS1052D", - "DS1102D", - "DS1152D", -}; - -SR_PRIV struct sr_dev_driver rigol_ds1xx2_driver_info; -static struct sr_dev_driver *di = &rigol_ds1xx2_driver_info; - -static void clear_helper(void *priv) -{ - struct dev_context *devc; - - devc = priv; - g_free(devc->coupling[0]); - g_free(devc->coupling[1]); - g_free(devc->trigger_source); - g_free(devc->trigger_slope); - g_slist_free(devc->analog_groups[0].probes); - g_slist_free(devc->analog_groups[1].probes); - g_slist_free(devc->digital_group.probes); -} - -static int dev_clear(void) -{ - return std_dev_clear(di, clear_helper); -} - -static int set_cfg(const struct sr_dev_inst *sdi, const char *format, ...) -{ - va_list args; - char buf[256]; - - va_start(args, format); - vsnprintf(buf, 255, format, args); - va_end(args); - if (rigol_ds1xx2_send(sdi, buf) != SR_OK) - return SR_ERR; - - /* When setting a bunch of parameters in a row, the DS1052E scrambles - * some of them unless there is at least 100ms delay in between. */ - sr_spew("delay %dms", 100); - g_usleep(100000); - - return SR_OK; -} - -static int init(struct sr_context *sr_ctx) -{ - return std_init(sr_ctx, di, LOG_PREFIX); -} - -static int probe_port(const char *port, GSList **devices) -{ - struct dev_context *devc; - struct sr_dev_inst *sdi; - struct sr_serial_dev_inst *serial; - struct sr_probe *probe; - unsigned int i; - int len, num_tokens; - gboolean matched, has_digital; - const char *manufacturer, *model, *version; - char buf[256]; - gchar **tokens, *channel_name; - - *devices = NULL; - if (!(serial = sr_serial_dev_inst_new(port, NULL))) - return SR_ERR_MALLOC; - - if (serial_open(serial, SERIAL_RDWR) != SR_OK) - return SR_ERR; - len = serial_write(serial, "*IDN?", 5); - len = serial_read(serial, buf, sizeof(buf)); - if (serial_close(serial) != SR_OK) - return SR_ERR; - - sr_serial_dev_inst_free(serial); - - if (len == 0) - return SR_ERR_NA; - - buf[len] = 0; - tokens = g_strsplit(buf, ",", 0); - sr_dbg("response: %s [%s]", port, buf); - - for (num_tokens = 0; tokens[num_tokens] != NULL; num_tokens++); - - if (num_tokens < 4) { - g_strfreev(tokens); - return SR_ERR_NA; - } - - manufacturer = tokens[0]; - model = tokens[1]; - version = tokens[3]; - - if (strcmp(manufacturer, "Rigol Technologies")) { - g_strfreev(tokens); - return SR_ERR_NA; - } - - matched = has_digital = FALSE; - for (i = 0; i < ARRAY_SIZE(supported_models); i++) { - if (!strcmp(model, supported_models[i])) { - matched = TRUE; - has_digital = g_str_has_suffix(model, "D"); - break; - } - } - - if (!matched || !(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, - manufacturer, model, version))) { - g_strfreev(tokens); - return SR_ERR_NA; - } - - g_strfreev(tokens); - - if (!(sdi->conn = sr_serial_dev_inst_new(port, NULL))) - return SR_ERR_MALLOC; - sdi->driver = di; - sdi->inst_type = SR_INST_SERIAL; - - if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) - return SR_ERR_MALLOC; - devc->limit_frames = 0; - devc->has_digital = has_digital; - - for (i = 0; i < 2; i++) { - channel_name = (i == 0 ? "CH1" : "CH2"); - if (!(probe = sr_probe_new(i, SR_PROBE_ANALOG, TRUE, channel_name))) - return SR_ERR_MALLOC; - sdi->probes = g_slist_append(sdi->probes, probe); - devc->analog_groups[i].name = channel_name; - devc->analog_groups[i].probes = g_slist_append(NULL, probe); - sdi->probe_groups = g_slist_append(sdi->probe_groups, - &devc->analog_groups[i]); - } - - if (devc->has_digital) { - for (i = 0; i < 16; i++) { - if (!(channel_name = g_strdup_printf("D%d", i))) - return SR_ERR_MALLOC; - probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, channel_name); - g_free(channel_name); - if (!probe) - return SR_ERR_MALLOC; - sdi->probes = g_slist_append(sdi->probes, probe); - devc->digital_group.probes = g_slist_append( - devc->digital_group.probes, probe); - devc->digital_group.name = "LA"; - sdi->probe_groups = g_slist_append(sdi->probe_groups, - &devc->digital_group); - } - } - sdi->priv = devc; - - *devices = g_slist_append(NULL, sdi); - - return SR_OK; -} - -static GSList *scan(GSList *options) -{ - struct drv_context *drvc; - struct sr_config *src; - GSList *l, *devices; - GDir *dir; - int ret; - const gchar *dev_name; - gchar *port = NULL; - - drvc = di->priv; - - for (l = options; l; l = l->next) { - src = l->data; - if (src->key == SR_CONF_CONN) { - port = (char *)g_variant_get_string(src->data, NULL); - break; - } - } - - devices = NULL; - if (port) { - if (probe_port(port, &devices) == SR_ERR_MALLOC) - return NULL; - } else { - if (!(dir = g_dir_open("/sys/class/usbmisc/", 0, NULL))) - if (!(dir = g_dir_open("/sys/class/usb/", 0, NULL))) - return NULL; - while ((dev_name = g_dir_read_name(dir))) { - if (strncmp(dev_name, "usbtmc", 6)) - continue; - port = g_strconcat("/dev/", dev_name, NULL); - ret = probe_port(port, &devices); - g_free(port); - if (ret == SR_ERR_MALLOC) { - g_dir_close(dir); - return NULL; - } - } - g_dir_close(dir); - } - - /* Tack a copy of the newly found devices onto the driver list. */ - l = g_slist_copy(devices); - drvc->instances = g_slist_concat(drvc->instances, l); - - return devices; -} - -static GSList *dev_list(void) -{ - return ((struct drv_context *)(di->priv))->instances; -} - -static int dev_open(struct sr_dev_inst *sdi) -{ - - if (serial_open(sdi->conn, SERIAL_RDWR) != SR_OK) - return SR_ERR; - - if (rigol_ds1xx2_get_dev_cfg(sdi) != SR_OK) - return SR_ERR; - - sdi->status = SR_ST_ACTIVE; - - return SR_OK; -} - -static int dev_close(struct sr_dev_inst *sdi) -{ - struct sr_serial_dev_inst *serial; - - serial = sdi->conn; - if (serial && serial->fd != -1) { - serial_close(serial); - sdi->status = SR_ST_INACTIVE; - } - - return SR_OK; -} - -static int cleanup(void) -{ - return dev_clear(); -} - -static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, - const struct sr_probe_group *probe_group) -{ - struct dev_context *devc; - unsigned int i; - - if (!sdi || !(devc = sdi->priv)) - return SR_ERR_ARG; - - /* If a probe group is specified, it must be a valid one. */ - if (probe_group) { - if (probe_group != &devc->analog_groups[0] - && probe_group != &devc->analog_groups[1]) { - sr_err("Invalid probe group specified."); - return SR_ERR; - } - } - - switch (id) { - case SR_CONF_NUM_TIMEBASE: - *data = g_variant_new_int32(NUM_TIMEBASE); - break; - case SR_CONF_NUM_VDIV: - if (!probe_group) { - sr_err("No probe group specified."); - return SR_ERR_PROBE_GROUP; - } - for (i = 0; i < 2; i++) { - if (probe_group == &devc->analog_groups[i]) { - *data = g_variant_new_int32(NUM_VDIV); - return SR_OK; - } - } - return SR_ERR_NA; - default: - return SR_ERR_NA; - } - - return SR_OK; -} - -static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi, - const struct sr_probe_group *probe_group) -{ - struct dev_context *devc; - uint64_t tmp_u64, p, q; - double t_dbl; - unsigned int i, j; - int ret; - const char *tmp_str; - - if (!(devc = sdi->priv)) - return SR_ERR_ARG; - - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - - /* If a probe group is specified, it must be a valid one. */ - if (probe_group) { - if (probe_group != &devc->analog_groups[0] - && probe_group != &devc->analog_groups[1]) { - sr_err("Invalid probe group specified."); - return SR_ERR; - } - } - - ret = SR_OK; - switch (id) { - case SR_CONF_LIMIT_FRAMES: - devc->limit_frames = g_variant_get_uint64(data); - break; - case SR_CONF_TRIGGER_SLOPE: - tmp_u64 = g_variant_get_uint64(data); - if (tmp_u64 != 0 && tmp_u64 != 1) - return SR_ERR; - g_free(devc->trigger_slope); - devc->trigger_slope = g_strdup(tmp_u64 ? "POS" : "NEG"); - ret = set_cfg(sdi, ":TRIG:EDGE:SLOP %s", devc->trigger_slope); - break; - case SR_CONF_HORIZ_TRIGGERPOS: - t_dbl = g_variant_get_double(data); - if (t_dbl < 0.0 || t_dbl > 1.0) - return SR_ERR; - devc->horiz_triggerpos = t_dbl; - /* We have the trigger offset as a percentage of the frame, but - * need to express this in seconds. */ - t_dbl = -(devc->horiz_triggerpos - 0.5) * devc->timebase * NUM_TIMEBASE; - ret = set_cfg(sdi, ":TIM:OFFS %.6f", t_dbl); - break; - case SR_CONF_TIMEBASE: - g_variant_get(data, "(tt)", &p, &q); - for (i = 0; i < ARRAY_SIZE(timebases); i++) { - if (timebases[i][0] == p && timebases[i][1] == q) { - devc->timebase = (float)p / q; - ret = set_cfg(sdi, ":TIM:SCAL %.9f", devc->timebase); - break; - } - } - if (i == ARRAY_SIZE(timebases)) - ret = SR_ERR_ARG; - break; - case SR_CONF_TRIGGER_SOURCE: - tmp_str = g_variant_get_string(data, NULL); - for (i = 0; i < ARRAY_SIZE(trigger_sources); i++) { - if (!strcmp(trigger_sources[i], tmp_str)) { - g_free(devc->trigger_source); - devc->trigger_source = g_strdup(trigger_sources[i]); - if (!strcmp(devc->trigger_source, "AC Line")) - tmp_str = "ACL"; - else if (!strcmp(devc->trigger_source, "CH1")) - tmp_str = "CHAN1"; - else if (!strcmp(devc->trigger_source, "CH2")) - tmp_str = "CHAN2"; - else - tmp_str = (char *)devc->trigger_source; - ret = set_cfg(sdi, ":TRIG:EDGE:SOUR %s", tmp_str); - break; - } - } - if (i == ARRAY_SIZE(trigger_sources)) - ret = SR_ERR_ARG; - break; - case SR_CONF_VDIV: - if (!probe_group) { - sr_err("No probe group specified."); - return SR_ERR_PROBE_GROUP; - } - g_variant_get(data, "(tt)", &p, &q); - for (i = 0; i < 2; i++) { - if (probe_group == &devc->analog_groups[i]) { - for (j = 0; j < ARRAY_SIZE(vdivs); j++) { - if (vdivs[j][0] != p || vdivs[j][1] != q) - continue; - devc->vdiv[i] = (float)p / q; - return set_cfg(sdi, ":CHAN%d:SCAL %.3f", i + 1, - devc->vdiv[i]); - } - return SR_ERR_ARG; - } - } - return SR_ERR_NA; - case SR_CONF_COUPLING: - if (!probe_group) { - sr_err("No probe group specified."); - return SR_ERR_PROBE_GROUP; - } - tmp_str = g_variant_get_string(data, NULL); - for (i = 0; i < 2; i++) { - if (probe_group == &devc->analog_groups[i]) { - for (j = 0; j < ARRAY_SIZE(coupling); j++) { - if (!strcmp(tmp_str, coupling[j])) { - g_free(devc->coupling[i]); - devc->coupling[i] = g_strdup(coupling[j]); - return set_cfg(sdi, ":CHAN%d:COUP %s", i + 1, - devc->coupling[i]); - } - } - return SR_ERR_ARG; - } - } - return SR_ERR_NA; - default: - ret = SR_ERR_NA; - break; - } - - return ret; -} - -static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, - const struct sr_probe_group *probe_group) -{ - GVariant *tuple, *rational[2]; - GVariantBuilder gvb; - unsigned int i; - struct dev_context *devc; - - if (key == SR_CONF_SCAN_OPTIONS) { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, - hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t)); - return SR_OK; - } else if (key == SR_CONF_DEVICE_OPTIONS && probe_group == NULL) { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, - hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); - return SR_OK; - } - - /* Every other option requires a valid device instance. */ - if (!sdi || !(devc = sdi->priv)) - return SR_ERR_ARG; - - /* If a probe group is specified, it must be a valid one. */ - if (probe_group) { - if (probe_group != &devc->analog_groups[0] - && probe_group != &devc->analog_groups[1]) { - sr_err("Invalid probe group specified."); - return SR_ERR; - } - } - - switch (key) { - break; - case SR_CONF_DEVICE_OPTIONS: - if (!probe_group) { - sr_err("No probe group specified."); - return SR_ERR_PROBE_GROUP; - } - if (probe_group == &devc->digital_group) { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, - NULL, 0, sizeof(int32_t)); - return SR_OK; - } else { - for (i = 0; i < 2; i++) { - if (probe_group == &devc->analog_groups[i]) { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, - analog_hwcaps, ARRAY_SIZE(analog_hwcaps), sizeof(int32_t)); - return SR_OK; - } - } - return SR_ERR_NA; - } - break; - case SR_CONF_COUPLING: - if (!probe_group) { - sr_err("No probe group specified."); - return SR_ERR_PROBE_GROUP; - } - *data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling)); - break; - case SR_CONF_VDIV: - if (!probe_group) { - sr_err("No probe group specified."); - return SR_ERR_PROBE_GROUP; - } - g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); - for (i = 0; i < ARRAY_SIZE(vdivs); i++) { - rational[0] = g_variant_new_uint64(vdivs[i][0]); - rational[1] = g_variant_new_uint64(vdivs[i][1]); - tuple = g_variant_new_tuple(rational, 2); - g_variant_builder_add_value(&gvb, tuple); - } - *data = g_variant_builder_end(&gvb); - break; - case SR_CONF_TIMEBASE: - g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY); - for (i = 0; i < ARRAY_SIZE(timebases); i++) { - rational[0] = g_variant_new_uint64(timebases[i][0]); - rational[1] = g_variant_new_uint64(timebases[i][1]); - tuple = g_variant_new_tuple(rational, 2); - g_variant_builder_add_value(&gvb, tuple); - } - *data = g_variant_builder_end(&gvb); - break; - case SR_CONF_TRIGGER_SOURCE: - *data = g_variant_new_strv(trigger_sources, - devc->has_digital ? ARRAY_SIZE(trigger_sources) : 4); - break; - default: - return SR_ERR_NA; - } - - return SR_OK; -} - -static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) -{ - struct sr_serial_dev_inst *serial; - struct dev_context *devc; - struct sr_probe *probe; - GSList *l; - char cmd[256]; - - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - - serial = sdi->conn; - devc = sdi->priv; - - for (l = sdi->probes; l; l = l->next) { - probe = l->data; - sr_dbg("handling probe %s", probe->name); - if (probe->type == SR_PROBE_ANALOG) { - if (probe->enabled) - devc->enabled_analog_probes = g_slist_append( - devc->enabled_analog_probes, probe); - if (probe->enabled != devc->analog_channels[probe->index]) { - /* Enabled channel is currently disabled, or vice versa. */ - sprintf(cmd, ":CHAN%d:DISP %s", probe->index + 1, - probe->enabled ? "ON" : "OFF"); - if (rigol_ds1xx2_send(sdi, cmd) != SR_OK) - return SR_ERR; - } - } else if (probe->type == SR_PROBE_LOGIC) { - if (probe->enabled) - devc->enabled_digital_probes = g_slist_append( - devc->enabled_digital_probes, probe); - if (probe->enabled != devc->digital_channels[probe->index]) { - /* Enabled channel is currently disabled, or vice versa. */ - sprintf(cmd, ":DIG%d:TURN %s", probe->index, - probe->enabled ? "ON" : "OFF"); - if (rigol_ds1xx2_send(sdi, cmd) != SR_OK) - return SR_ERR; - } - } - } - if (!devc->enabled_analog_probes && !devc->enabled_digital_probes) - return SR_ERR; - - sr_source_add(serial->fd, G_IO_IN, 50, rigol_ds1xx2_receive, (void *)sdi); - - /* Send header packet to the session bus. */ - std_session_send_df_header(cb_data, LOG_PREFIX); - - /* Fetch the first frame. */ - if (devc->enabled_analog_probes) { - devc->channel_frame = devc->enabled_analog_probes->data; - if (rigol_ds1xx2_send(sdi, ":WAV:DATA? CHAN%d", - devc->channel_frame->index + 1) != SR_OK) - return SR_ERR; - } else { - devc->channel_frame = devc->enabled_digital_probes->data; - if (rigol_ds1xx2_send(sdi, ":WAV:DATA? DIG") != SR_OK) - return SR_ERR; - } - - devc->num_frame_bytes = 0; - - return SR_OK; -} - -static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) -{ - struct dev_context *devc; - struct sr_serial_dev_inst *serial; - - (void)cb_data; - - devc = sdi->priv; - - if (sdi->status != SR_ST_ACTIVE) { - sr_err("Device inactive, can't stop acquisition."); - return SR_ERR; - } - - g_slist_free(devc->enabled_analog_probes); - g_slist_free(devc->enabled_digital_probes); - devc->enabled_analog_probes = NULL; - devc->enabled_digital_probes = NULL; - serial = sdi->conn; - sr_source_remove(serial->fd); - - return SR_OK; -} - -SR_PRIV struct sr_dev_driver rigol_ds1xx2_driver_info = { - .name = "rigol-ds1xx2", - .longname = "Rigol DS1xx2", - .api_version = 1, - .init = init, - .cleanup = cleanup, - .scan = scan, - .dev_list = dev_list, - .dev_clear = dev_clear, - .config_get = config_get, - .config_set = config_set, - .config_list = config_list, - .dev_open = dev_open, - .dev_close = dev_close, - .dev_acquisition_start = dev_acquisition_start, - .dev_acquisition_stop = dev_acquisition_stop, - .priv = NULL, -}; diff --git a/hardware/rigol-ds1xx2/protocol.c b/hardware/rigol-ds1xx2/protocol.c deleted file mode 100644 index 0efff693..00000000 --- a/hardware/rigol-ds1xx2/protocol.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2012 Martin Ling - * Copyright (C) 2013 Bert Vermeulen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include "libsigrok.h" -#include "libsigrok-internal.h" -#include "protocol.h" - -SR_PRIV int rigol_ds1xx2_receive(int fd, int revents, void *cb_data) -{ - struct sr_dev_inst *sdi; - struct sr_serial_dev_inst *serial; - struct dev_context *devc; - struct sr_datafeed_packet packet; - struct sr_datafeed_analog analog; - struct sr_datafeed_logic logic; - unsigned char buf[DIGITAL_WAVEFORM_SIZE]; - double vdiv, offset; - float data[ANALOG_WAVEFORM_SIZE]; - int len, i, waveform_size; - struct sr_probe *probe; - - (void)fd; - - if (!(sdi = cb_data)) - return TRUE; - - if (!(devc = sdi->priv)) - return TRUE; - - serial = sdi->conn; - - if (revents == G_IO_IN) { - probe = devc->channel_frame; - waveform_size = probe->type == SR_PROBE_ANALOG ? - ANALOG_WAVEFORM_SIZE : DIGITAL_WAVEFORM_SIZE; - len = serial_read(serial, buf, waveform_size - devc->num_frame_bytes); - sr_dbg("Received %d bytes.", len); - if (len == -1) - return TRUE; - - if (devc->num_frame_bytes == 0) { - /* Start of a new frame. */ - packet.type = SR_DF_FRAME_BEGIN; - sr_session_send(sdi, &packet); - } - - if (probe->type == SR_PROBE_ANALOG) { - for (i = 0; i < len; i++) { - vdiv = devc->vdiv[probe->index]; - offset = devc->vert_offset[probe->index]; - data[i] = vdiv / 25.6 * (128 - buf[i]) - offset; - } - analog.probes = g_slist_append(NULL, probe); - analog.num_samples = len; - analog.data = data; - analog.mq = SR_MQ_VOLTAGE; - analog.unit = SR_UNIT_VOLT; - analog.mqflags = 0; - packet.type = SR_DF_ANALOG; - packet.payload = &analog; - sr_session_send(cb_data, &packet); - g_slist_free(analog.probes); - - if (len != ANALOG_WAVEFORM_SIZE) - /* Don't have the whole frame yet. */ - return TRUE; - } else { - logic.length = len - 10; - logic.unitsize = 2; - logic.data = buf + 10; - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - sr_session_send(cb_data, &packet); - - if (len != DIGITAL_WAVEFORM_SIZE) - /* Don't have the whole frame yet. */ - return TRUE; - } - - /* End of the frame. */ - packet.type = SR_DF_FRAME_END; - sr_session_send(sdi, &packet); - devc->num_frame_bytes = 0; - - if (devc->enabled_analog_probes - && devc->channel_frame == devc->enabled_analog_probes->data - && devc->enabled_analog_probes->next != NULL) { - /* We got the frame for the first analog channel, but - * there's a second analog channel. */ - devc->channel_frame = devc->enabled_analog_probes->next->data; - rigol_ds1xx2_send(sdi, ":WAV:DATA? CHAN%c", - devc->channel_frame->name[2]); - } else { - /* Done with both analog channels in this frame. */ - if (devc->enabled_digital_probes - && devc->channel_frame != devc->enabled_digital_probes->data) { - /* Now we need to get the digital data. */ - devc->channel_frame = devc->enabled_digital_probes->data; - rigol_ds1xx2_send(sdi, ":WAV:DATA? DIG"); - } else if (++devc->num_frames == devc->limit_frames) { - /* End of last frame. */ - packet.type = SR_DF_END; - sr_session_send(sdi, &packet); - sdi->driver->dev_acquisition_stop(sdi, cb_data); - } else { - /* Get the next frame, starting with the first analog channel. */ - if (devc->enabled_analog_probes) { - devc->channel_frame = devc->enabled_analog_probes->data; - rigol_ds1xx2_send(sdi, ":WAV:DATA? CHAN%c", - devc->channel_frame->name[2]); - } else { - devc->channel_frame = devc->enabled_digital_probes->data; - rigol_ds1xx2_send(sdi, ":WAV:DATA? DIG"); - } - } - } - } - - return TRUE; -} - -SR_PRIV int rigol_ds1xx2_send(const struct sr_dev_inst *sdi, const char *format, ...) -{ - va_list args; - char buf[256]; - int len, out, ret; - - va_start(args, format); - len = vsnprintf(buf, 255, format, args); - va_end(args); - strcat(buf, "\n"); - len++; - out = serial_write(sdi->conn, buf, len); - buf[len - 1] = '\0'; - if (out != len) { - sr_dbg("Only sent %d/%d bytes of '%s'.", out, len, buf); - ret = SR_ERR; - } else { - sr_spew("Sent '%s'.", buf); - ret = SR_OK; - } - - return ret; -} - -static int get_cfg(const struct sr_dev_inst *sdi, char *cmd, char *reply) -{ - int len; - - if (rigol_ds1xx2_send(sdi, cmd) != SR_OK) - return SR_ERR; - - if ((len = serial_read(sdi->conn, reply, 255)) < 0) - return SR_ERR; - reply[len] = '\0'; - sr_spew("Received '%s'.", reply); - - return SR_OK; -} - -static int get_cfg_float(const struct sr_dev_inst *sdi, char *cmd, float *f) -{ - char buf[256], *e; - - if (get_cfg(sdi, cmd, buf) != SR_OK) - return SR_ERR; - *f = strtof(buf, &e); - if (e == buf || (fpclassify(*f) & (FP_ZERO | FP_NORMAL)) == 0) { - sr_dbg("failed to parse response to '%s': '%s'", cmd, buf); - return SR_ERR; - } - - return SR_OK; -} - -static int get_cfg_string(const struct sr_dev_inst *sdi, char *cmd, char **buf) -{ - - if (!(*buf = g_try_malloc0(256))) - return SR_ERR_MALLOC; - - if (get_cfg(sdi, cmd, *buf) != SR_OK) - return SR_ERR; - - return SR_OK; -} - -SR_PRIV int rigol_ds1xx2_get_dev_cfg(const struct sr_dev_inst *sdi) -{ - struct dev_context *devc; - char *t_s, *cmd; - int i, res; - - devc = sdi->priv; - - /* Analog channel state. */ - if (get_cfg_string(sdi, ":CHAN1:DISP?", &t_s) != SR_OK) - return SR_ERR; - devc->analog_channels[0] = !strcmp(t_s, "ON") ? TRUE : FALSE; - g_free(t_s); - if (get_cfg_string(sdi, ":CHAN2:DISP?", &t_s) != SR_OK) - return SR_ERR; - devc->analog_channels[1] = !strcmp(t_s, "ON") ? TRUE : FALSE; - g_free(t_s); - sr_dbg("Current analog channel state CH1 %s CH2 %s", - devc->analog_channels[0] ? "on" : "off", - devc->analog_channels[1] ? "on" : "off"); - - /* Digital channel state. */ - if (devc->has_digital) { - sr_dbg("Current digital channel state:"); - for (i = 0; i < 16; i++) { - cmd = g_strdup_printf(":DIG%d:TURN?", i); - res = get_cfg_string(sdi, cmd, &t_s); - g_free(cmd); - if (res != SR_OK) - return SR_ERR; - devc->digital_channels[i] = !strcmp(t_s, "ON") ? TRUE : FALSE; - g_free(t_s); - sr_dbg("D%d: %s", i, devc->digital_channels[i] ? "on" : "off"); - } - } - - /* Timebase. */ - if (get_cfg_float(sdi, ":TIM:SCAL?", &devc->timebase) != SR_OK) - return SR_ERR; - sr_dbg("Current timebase %f", devc->timebase); - - /* Vertical gain. */ - if (get_cfg_float(sdi, ":CHAN1:SCAL?", &devc->vdiv[0]) != SR_OK) - return SR_ERR; - if (get_cfg_float(sdi, ":CHAN2:SCAL?", &devc->vdiv[1]) != SR_OK) - return SR_ERR; - sr_dbg("Current vertical gain CH1 %f CH2 %f", devc->vdiv[0], devc->vdiv[1]); - - /* Vertical offset. */ - if (get_cfg_float(sdi, ":CHAN1:OFFS?", &devc->vert_offset[0]) != SR_OK) - return SR_ERR; - if (get_cfg_float(sdi, ":CHAN2:OFFS?", &devc->vert_offset[1]) != SR_OK) - return SR_ERR; - sr_dbg("Current vertical offset CH1 %f CH2 %f", devc->vert_offset[0], - devc->vert_offset[1]); - - /* Coupling. */ - if (get_cfg_string(sdi, ":CHAN1:COUP?", &devc->coupling[0]) != SR_OK) - return SR_ERR; - if (get_cfg_string(sdi, ":CHAN2:COUP?", &devc->coupling[1]) != SR_OK) - return SR_ERR; - sr_dbg("Current coupling CH1 %s CH2 %s", devc->coupling[0], - devc->coupling[1]); - - /* Trigger source. */ - if (get_cfg_string(sdi, ":TRIG:EDGE:SOUR?", &devc->trigger_source) != SR_OK) - return SR_ERR; - sr_dbg("Current trigger source %s", devc->trigger_source); - - /* Horizontal trigger position. */ - if (get_cfg_float(sdi, ":TIM:OFFS?", &devc->horiz_triggerpos) != SR_OK) - return SR_ERR; - sr_dbg("Current horizontal trigger position %f", devc->horiz_triggerpos); - - /* Trigger slope. */ - if (get_cfg_string(sdi, ":TRIG:EDGE:SLOP?", &devc->trigger_slope) != SR_OK) - return SR_ERR; - sr_dbg("Current trigger slope %s", devc->trigger_slope); - - return SR_OK; -} diff --git a/hardware/rigol-ds1xx2/protocol.h b/hardware/rigol-ds1xx2/protocol.h deleted file mode 100644 index ff345fd2..00000000 --- a/hardware/rigol-ds1xx2/protocol.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of the libsigrok project. - * - * Copyright (C) 2012 Martin Ling - * Copyright (C) 2013 Bert Vermeulen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef LIBSIGROK_HARDWARE_RIGOL_DS1XX2_PROTOCOL_H -#define LIBSIGROK_HARDWARE_RIGOL_DS1XX2_PROTOCOL_H - -#include -#include "libsigrok.h" -#include "libsigrok-internal.h" - -/* Message logging helpers with subsystem-specific prefix string. */ -#define LOG_PREFIX "rigol-ds1xx2: " -#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args) -#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args) -#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args) -#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args) -#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) -#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) - -#define ANALOG_WAVEFORM_SIZE 600 -#define DIGITAL_WAVEFORM_SIZE 1210 - -/** Private, per-device-instance driver context. */ -struct dev_context { - /* Device features */ - gboolean has_digital; - - /* Probe groups */ - struct sr_probe_group analog_groups[2]; - struct sr_probe_group digital_group; - - /* Acquisition settings */ - GSList *enabled_analog_probes; - GSList *enabled_digital_probes; - uint64_t limit_frames; - void *cb_data; - - /* Device settings */ - gboolean analog_channels[2]; - gboolean digital_channels[16]; - float timebase; - float vdiv[2]; - float vert_offset[2]; - char *trigger_source; - float horiz_triggerpos; - char *trigger_slope; - char *coupling[2]; - - /* Operational state */ - uint64_t num_frames; - uint64_t num_frame_bytes; - struct sr_probe *channel_frame; -}; - -SR_PRIV int rigol_ds1xx2_receive(int fd, int revents, void *cb_data); -SR_PRIV int rigol_ds1xx2_send(const struct sr_dev_inst *sdi, const char *format, ...); -SR_PRIV int rigol_ds1xx2_get_dev_cfg(const struct sr_dev_inst *sdi); - -#endif diff --git a/hwdriver.c b/hwdriver.c index 5897b63e..804838c8 100644 --- a/hwdriver.c +++ b/hwdriver.c @@ -148,8 +148,8 @@ extern SR_PRIV struct sr_dev_driver norma_dmm_driver_info; #ifdef HAVE_HW_OLS extern SR_PRIV struct sr_dev_driver ols_driver_info; #endif -#ifdef HAVE_HW_RIGOL_DS1XX2 -extern SR_PRIV struct sr_dev_driver rigol_ds1xx2_driver_info; +#ifdef HAVE_HW_RIGOL_DS +extern SR_PRIV struct sr_dev_driver rigol_ds_driver_info; #endif #ifdef HAVE_HW_SALEAE_LOGIC16 extern SR_PRIV struct sr_dev_driver saleae_logic16_driver_info; @@ -274,8 +274,8 @@ static struct sr_dev_driver *drivers_list[] = { #ifdef HAVE_HW_OLS &ols_driver_info, #endif -#ifdef HAVE_HW_RIGOL_DS1XX2 - &rigol_ds1xx2_driver_info, +#ifdef HAVE_HW_RIGOL_DS + &rigol_ds_driver_info, #endif #ifdef HAVE_HW_SALEAE_LOGIC16 &saleae_logic16_driver_info,