- mic-985xx
- norma-dmm
- openbench-logic-sniffer
- - rigol-ds1xx2
+ - rigol-ds
- serial-dmm
- teleinfo
- tondaj-sl-814
- ikalogic-scanaplus
- kecheng-kc-330b
- lascar-el-usb
- - rigol-ds1xx2
+ - rigol-ds
- saleae-logic16
- uni-t-dmm
- uni-t-ut32x
$ 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.
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.
-
[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]]),
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
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)
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
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"
# 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"
mic-985xx \
norma-dmm \
openbench-logic-sniffer \
- rigol-ds1xx2 \
+ rigol-ds \
saleae-logic16 \
serial-dmm \
teleinfo \
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
--- /dev/null
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2012 Martin Ling <martin-git@earth.li>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+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
--- /dev/null
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#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,
+};
--- /dev/null
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#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;
+}
--- /dev/null
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H
+
+#include <stdint.h>
+#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
+++ /dev/null
-##
-## This file is part of the libsigrok project.
-##
-## Copyright (C) 2012 Martin Ling <martin-git@earth.li>
-##
-## 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 <http://www.gnu.org/licenses/>.
-##
-
-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
+++ /dev/null
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#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,
-};
+++ /dev/null
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <math.h>
-#include <glib.h>
-#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;
-}
+++ /dev/null
-/*
- * This file is part of the libsigrok project.
- *
- * Copyright (C) 2012 Martin Ling <martin-git@earth.li>
- * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LIBSIGROK_HARDWARE_RIGOL_DS1XX2_PROTOCOL_H
-#define LIBSIGROK_HARDWARE_RIGOL_DS1XX2_PROTOCOL_H
-
-#include <stdint.h>
-#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
#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;
#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,