diff --git a/Makefile.am b/Makefile.am
index 9bab81dd3..326a5d4de 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -214,6 +214,14 @@ src_libdrivers_tail_la_SOURCES = src/driver_list_stop.c
src_libdrivers_la_SOURCES = src/drivers.c
+if HW_ADALM2000
+src_libdrivers_la_SOURCES += \
+ src/hardware/adalm2000/libm2k.h \
+ src/hardware/adalm2000/libm2k.cpp \
+ src/hardware/adalm2000/protocol.h \
+ src/hardware/adalm2000/protocol.c \
+ src/hardware/adalm2000/api.c
+endif
if HW_AGILENT_DMM
src_libdrivers_la_SOURCES += \
src/hardware/agilent-dmm/protocol.h \
diff --git a/configure.ac b/configure.ac
index ba2d45133..92e02eb06 100644
--- a/configure.ac
+++ b/configure.ac
@@ -99,6 +99,9 @@ SR_EXTRA_CXX_LIBS=
SR_ARG_OPT_PKG([libserialport], [LIBSERIALPORT], ,
[libserialport >= 0.1.1])
+SR_ARG_OPT_PKG([libm2k], [LIBM2K], ,
+ [libm2k])
+
SR_ARG_OPT_PKG([libftdi], [LIBFTDI], , [libftdi1 >= 1.0])
# pkg-config file names: MinGW/MacOSX: hidapi; Linux: hidapi-hidraw/-libusb
@@ -140,6 +143,14 @@ AS_IF([test "x$sr_have_libieee1284" = xyes],
SR_ARG_OPT_PKG([libgio], [LIBGIO], , [gio-2.0 >= 2.24.0])
+AC_LANG_PUSH([C++])
+PKG_CHECK_MODULES(LIBM2K, [libm2k] )
+AC_DEFINE([HAVE_LIBM2K], [1], [Have libm2k dep.])
+#SR_APPEND([SR_PKGLIBS], ['libm2k'])
+SR_APPEND([sr_deps_avail], [libm2k])
+AM_CONDITIONAL([NEED_LIBM2K], [test "x$sr_have_libm2k" = xyes])
+AC_LANG_POP([C++])
+
# See if any of the (potentially platform specific) libs are available
# which provide some means of Bluetooth communication.
AS_IF([test "x$sr_have_libbluez" = xyes],
@@ -257,6 +268,7 @@ m4_define([_SR_DRIVER], [
m4_define([SR_DRIVER],
[_SR_DRIVER([$1], [$2], m4_expand([AS_TR_CPP([HW_$2])]), [$3])])
+SR_DRIVER([ADALM2000], [adalm2000], [libm2k])
SR_DRIVER([Agilent DMM], [agilent-dmm], [serial_comm])
SR_DRIVER([Appa 55II], [appa-55ii], [serial_comm])
SR_DRIVER([Arachnid Labs Re:load Pro], [arachnid-labs-re-load-pro], [serial_comm])
@@ -569,6 +581,8 @@ AC_SUBST([SR_PKGLIBS])
# Retrieve the compile and link flags for all modules combined.
# Also, bail out at this point if any module dependency is not met.
+
+PKG_CHECK_MODULES([LIBSIGROK], [libm2k $SR_PKGLIBS])
PKG_CHECK_MODULES([LIBSIGROK], [glib-2.0 >= 2.32.0 $SR_PKGLIBS])
PKG_CHECK_MODULES([TESTS], [$SR_PKGLIBS_TESTS glib-2.0 $SR_PKGLIBS])
@@ -649,6 +663,7 @@ $sr_driver_summary
Enabled serial communication transports:
- serial comm ................... $sr_have_serial_comm
- libserialport ................. $sr_have_libserialport
+ - libm2k ........................ $sr_have_libm2k
- hidapi ........................ $sr_have_libhidapi
- bluetooth ..................... $sr_have_bluetooth
- bluez ......................... $sr_have_libbluez
diff --git a/src/hardware/adalm2000/api.c b/src/hardware/adalm2000/api.c
new file mode 100644
index 000000000..ac9a80400
--- /dev/null
+++ b/src/hardware/adalm2000/api.c
@@ -0,0 +1,641 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2020 Analog Devices Inc.
+ *
+ * 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 "protocol.h"
+
+
+static const uint32_t scanopts[] = {
+ SR_CONF_CONN,
+};
+
+static const uint32_t drvopts[] = {
+ SR_CONF_LOGIC_ANALYZER,
+ SR_CONF_OSCILLOSCOPE,
+};
+
+static const uint32_t devopts[] = {
+ SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
+ SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
+ SR_CONF_AVERAGING | SR_CONF_GET | SR_CONF_SET,
+ SR_CONF_AVG_SAMPLES | SR_CONF_GET | SR_CONF_SET,
+ SR_CONF_TRIGGER_MATCH | SR_CONF_LIST,
+ SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET,
+};
+
+static const uint32_t devopts_cg_analog_group[] = {
+ SR_CONF_TRIGGER_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+};
+
+static const uint32_t devopts_cg_analog_channel[] = {
+ SR_CONF_TRIGGER_SLOPE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
+ SR_CONF_HIGH_RESOLUTION | SR_CONF_GET | SR_CONF_SET,
+ SR_CONF_TRIGGER_LEVEL | SR_CONF_GET | SR_CONF_SET,
+};
+
+static const uint32_t devopts_cg[] = {
+};
+
+static const int32_t trigger_matches[] = {
+ SR_TRIGGER_ZERO,
+ SR_TRIGGER_ONE,
+ SR_TRIGGER_RISING,
+ SR_TRIGGER_FALLING,
+ SR_TRIGGER_EDGE,
+};
+
+static const uint64_t samplerates[] = {
+ SR_KHZ(1),
+ SR_KHZ(10),
+ SR_KHZ(100),
+ SR_MHZ(1),
+ SR_MHZ(10),
+ SR_MHZ(100),
+};
+
+static const char *trigger_sources[] = {
+ "CHANNEL 1",
+ "CHANNEL 2",
+ "CHANNEL 1 OR CHANNEL 2",
+ "CHANNEL 1 AND CHANNEL 2",
+ "CHANNEL 1 XOR CHANNEL 2",
+ "NONE",
+};
+
+static const char *trigger_slopes[] = {
+ "RISING",
+ "FALLING",
+ "LOW",
+ "HIGH",
+};
+
+static struct sr_dev_driver adalm2000_driver_info;
+
+static GSList *scan(struct sr_dev_driver *di, GSList *options)
+{
+ struct dev_context *devc;
+ struct sr_dev_inst *sdi;
+ struct sr_channel *ch;
+
+ struct sr_channel_group *cg, *acg;
+ struct sr_config *src;
+ GSList *l, *devices;
+ struct CONTEXT_INFO **devlist;
+ unsigned int i, j, len;
+ char *conn;
+ char channel_name[16];
+ char ip[30];
+ gboolean ip_connection;
+
+ conn = NULL;
+ ip_connection = FALSE;
+
+ for (l = options; l; l = l->next) {
+ src = l->data;
+ switch (src->key) {
+ case SR_CONF_CONN:
+ conn = (char *) g_variant_get_string(src->data, NULL);
+ break;
+ }
+ }
+
+ if (conn) {
+ if (strstr(conn, "tcp")) {
+ strtok(conn, "/");
+ snprintf(ip, 30, "ip:%s", strtok(NULL, "/"));
+ ip_connection = TRUE;
+ }
+ }
+ devices = NULL;
+
+ len = sr_libm2k_context_get_all(&devlist);
+
+ for (i = 0; i < len; i++) {
+ struct CONTEXT_INFO *info = (struct CONTEXT_INFO *) devlist[i];
+
+ sdi = g_malloc0(sizeof(struct sr_dev_inst));
+ devc = g_malloc0(sizeof(struct dev_context));
+
+ sdi->status = SR_ST_INACTIVE;
+ sdi->vendor = g_strdup(info->manufacturer);
+ sdi->model = g_strdup(info->product);
+ sdi->serial_num = g_strdup(info->serial);
+ sdi->connection_id = g_strdup(info->uri);
+ if (ip_connection) {
+ sdi->conn = g_strdup(ip);
+ } else {
+ sdi->conn = g_strdup(info->uri);
+ }
+
+ cg = g_malloc0(sizeof(struct sr_channel_group));
+ cg->name = g_strdup("Logic");
+
+ for (j = 0; j < DEFAULT_NUM_LOGIC_CHANNELS; j++) {
+ snprintf(channel_name, 16, "DIO%d", j);
+ ch = sr_channel_new(sdi, j, SR_CHANNEL_LOGIC, TRUE,
+ channel_name);
+ cg->channels = g_slist_append(cg->channels, ch);
+ }
+ sdi->channel_groups = g_slist_append(NULL, cg);
+
+ acg = g_malloc0(sizeof(struct sr_channel_group));
+ acg->name = g_strdup("Analog");
+ sdi->channel_groups = g_slist_append(sdi->channel_groups, acg);
+
+ for (j = 0; j < DEFAULT_NUM_ANALOG_CHANNELS; j++) {
+ snprintf(channel_name, 16, "A%d", j);
+
+ cg = g_malloc0(sizeof(struct sr_channel_group));
+ cg->name = g_strdup(channel_name);
+
+ ch = sr_channel_new(sdi, j,
+ SR_CHANNEL_ANALOG, TRUE,
+ channel_name);
+
+ acg->channels = g_slist_append(acg->channels, ch);
+
+ cg->channels = g_slist_append(cg->channels, ch);
+ sdi->channel_groups = g_slist_append(
+ sdi->channel_groups, cg);
+
+ }
+ devc->m2k = NULL;
+ devc->logic_unitsize = 2;
+ devc->buffersize = 1 << 16;
+ sr_analog_init(&devc->packet, &devc->encoding, &devc->meaning,
+ &devc->spec, 6);
+
+ devc->meaning.mq = SR_MQ_VOLTAGE;
+ devc->meaning.unit = SR_UNIT_VOLT;
+ devc->meaning.mqflags = 0;
+
+ sdi->priv = devc;
+ sdi->inst_type = SR_INST_USB;
+
+ devices = g_slist_append(devices, sdi);
+ }
+ return std_scan_complete(di, devices);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+
+ devc = sdi->priv;
+ devc->m2k = sr_libm2k_context_open(sdi->conn);
+ if (!devc->m2k) {
+ sr_err("Failed to open device");
+ return SR_ERR;
+ }
+ sr_libm2k_context_adc_calibrate(devc->m2k);
+ devc->avg_samples = sr_libm2k_analog_oversampling_ratio_get(devc->m2k);
+
+ return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ int ret;
+
+ devc = sdi->priv;
+
+ sr_info("Closing device on ...");
+ ret = sr_libm2k_context_close(&(devc->m2k));
+ if (ret) {
+ sr_err("Failed to close device");
+ return SR_ERR;
+ }
+ return SR_OK;
+}
+
+static int config_get(uint32_t key, GVariant **data,
+ const struct sr_dev_inst *sdi,
+ const struct sr_channel_group *cg)
+{
+ unsigned int idx, capture_ratio, samplerate;
+ int delay;
+ gboolean analog_enabled, digital_enabled;
+ struct sr_channel *ch;
+ struct dev_context *devc;
+ if (!sdi) {
+ return SR_ERR_ARG;
+ }
+
+ devc = sdi->priv;
+
+ if (!cg) {
+ switch (key) {
+ case SR_CONF_SAMPLERATE:
+ digital_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_LOGIC) > 0)
+ ? TRUE : FALSE;
+ samplerate = sr_libm2k_analog_samplerate_get(devc->m2k);
+ if (digital_enabled) {
+ sr_libm2k_digital_samplerate_set(devc->m2k, samplerate);
+ }
+ *data = g_variant_new_uint64(samplerate);
+ break;
+ case SR_CONF_LIMIT_SAMPLES:
+ *data = g_variant_new_uint64(devc->limit_samples);
+ break;
+ case SR_CONF_LIMIT_MSEC:
+ *data = g_variant_new_uint64(devc->limit_msec);
+ break;
+ case SR_CONF_AVERAGING:
+ *data = g_variant_new_boolean(devc->avg);
+ break;
+ case SR_CONF_AVG_SAMPLES:
+ *data = g_variant_new_uint64(devc->avg_samples);
+ break;
+ case SR_CONF_CAPTURE_RATIO:
+ analog_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_ANALOG) > 0)
+ ? TRUE : FALSE;
+ digital_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_LOGIC) > 0)
+ ? TRUE : FALSE;
+
+ if (analog_enabled) {
+ delay = sr_libm2k_analog_trigger_delay_get(devc->m2k);
+ } else {
+ delay = sr_libm2k_digital_trigger_delay_get(devc->m2k);
+ }
+ if (delay > 0) {
+ delay = 0;
+ capture_ratio = 0;
+ } else {
+ capture_ratio = delay * 100 / MAX_NEG_DELAY;
+ }
+
+ if (analog_enabled) {
+ sr_libm2k_analog_trigger_delay_set(devc->m2k, 0);
+ }
+ if (digital_enabled) {
+ sr_libm2k_digital_trigger_delay_set(devc->m2k, delay);
+ }
+ *data = g_variant_new_uint64(capture_ratio);
+ break;
+ default:
+ return SR_ERR_NA;
+ }
+ } else {
+ ch = cg->channels->data;
+ idx = ch->index;
+ switch (key) {
+ case SR_CONF_TRIGGER_SOURCE:
+ if (sr_libm2k_analog_trigger_mode_get(devc->m2k, 0) == ALWAYS &&
+ sr_libm2k_analog_trigger_mode_get(devc->m2k, 1) == ALWAYS) {
+ *data = g_variant_new_string(trigger_sources[5]);
+ } else {
+ *data = g_variant_new_string(
+ trigger_sources[sr_libm2k_analog_trigger_source_get(devc->m2k)]);
+ }
+ break;
+ case SR_CONF_TRIGGER_SLOPE:
+ if (ch->type != SR_CHANNEL_ANALOG) {
+ return SR_ERR_ARG;
+ }
+ *data = g_variant_new_string(
+ trigger_slopes[sr_libm2k_analog_trigger_condition_get(devc->m2k, idx)]);
+ break;
+ case SR_CONF_TRIGGER_LEVEL:
+ *data = g_variant_new_double(sr_libm2k_analog_trigger_level_get(devc->m2k, idx));
+ break;
+ case SR_CONF_HIGH_RESOLUTION:
+ if (ch->type != SR_CHANNEL_ANALOG) {
+ return SR_ERR_ARG;
+ }
+ if (sr_libm2k_analog_range_get(devc->m2k, idx) == PLUS_MINUS_2_5V) {
+ *data = g_variant_new_boolean(TRUE);
+ } else {
+ *data = g_variant_new_boolean(FALSE);
+ }
+ break;
+ default:
+ return SR_ERR_NA;
+ }
+ }
+
+ return SR_OK;
+}
+
+static int config_set(uint32_t key, GVariant *data,
+ const struct sr_dev_inst *sdi,
+ const struct sr_channel_group *cg)
+{
+ int ch_idx, idx, delay;
+ char *trigger_source, *trigger_slope;
+ gboolean analog_enabled, digital_enabled, high_resolution;
+ struct sr_channel *ch;
+ struct dev_context *devc;
+
+ if (!sdi) {
+ return SR_ERR_ARG;
+ }
+
+ devc = sdi->priv;
+
+ if (!cg) {
+ switch (key) {
+ case SR_CONF_SAMPLERATE:
+ analog_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_ANALOG) > 0)
+ ? TRUE : FALSE;
+ digital_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_LOGIC) > 0)
+ ? TRUE : FALSE;
+ if (analog_enabled) {
+ sr_libm2k_analog_samplerate_set(devc->m2k, g_variant_get_uint64(data));
+ }
+ if (digital_enabled) {
+ sr_libm2k_digital_samplerate_set(devc->m2k, g_variant_get_uint64(data));
+ }
+ break;
+ case SR_CONF_LIMIT_SAMPLES:
+ devc->limit_samples = g_variant_get_uint64(data);
+ devc->limit_msec = 0;
+ break;
+ case SR_CONF_LIMIT_MSEC:
+ devc->limit_msec = g_variant_get_uint64(data);
+ devc->limit_samples = 0;
+ break;
+ case SR_CONF_CAPTURE_RATIO:
+ analog_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_ANALOG) > 0)
+ ? TRUE : FALSE;
+ digital_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_LOGIC) > 0)
+ ? TRUE : FALSE;
+ delay = MAX_NEG_DELAY *
+ (int) g_variant_get_uint64(data) / 100;
+ if (analog_enabled) {
+ sr_libm2k_analog_trigger_delay_set(devc->m2k, delay);
+ }
+ if (digital_enabled) {
+ sr_libm2k_digital_trigger_delay_set(devc->m2k, delay);
+ }
+ break;
+ case SR_CONF_AVERAGING:
+ devc->avg = g_variant_get_boolean(data);
+ break;
+ case SR_CONF_AVG_SAMPLES:
+ devc->avg_samples = g_variant_get_uint64(data);
+ break;
+ default:
+ return SR_ERR_NA;
+ }
+ } else {
+ ch = cg->channels->data;
+ ch_idx = ch->index;
+
+ switch (key) {
+ case SR_CONF_TRIGGER_SOURCE:
+ if (ch->type != SR_CHANNEL_ANALOG) {
+ return SR_ERR_ARG;
+ }
+ if ((idx = std_str_idx(data, ARRAY_AND_SIZE(trigger_sources))) < 0) {
+ return SR_ERR_ARG;
+ }
+ trigger_source = g_strdup(trigger_sources[idx]);
+ if (!strcmp(trigger_source, trigger_sources[0])) {
+ sr_libm2k_analog_trigger_source_set(devc->m2k, CH_1);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 0, ANALOG);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 1, ALWAYS);
+ } else if (!strcmp(trigger_source, trigger_sources[1])) {
+ sr_libm2k_analog_trigger_source_set(devc->m2k, CH_2);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 0, ALWAYS);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 1, ANALOG);
+ } else if (!strcmp(trigger_source, trigger_sources[2])) {
+ sr_libm2k_analog_trigger_source_set(devc->m2k, CH_1_OR_CH_2);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 0, ANALOG);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 1, ANALOG);
+ } else if (!strcmp(trigger_source, trigger_sources[3])) {
+ sr_libm2k_analog_trigger_source_set(devc->m2k, CH_1_AND_CH_2);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 0, ANALOG);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 1, ANALOG);
+ } else if (!strcmp(trigger_source, trigger_sources[4])) {
+ sr_libm2k_analog_trigger_source_set(devc->m2k, CH_1_XOR_CH_2);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 0, ANALOG);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 1, ANALOG);
+ } else {
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 0, ALWAYS);
+ sr_libm2k_analog_trigger_mode_set(devc->m2k, 1, ALWAYS);
+ }
+ g_free(trigger_source);
+ break;
+ case SR_CONF_TRIGGER_SLOPE:
+ if (ch->type != SR_CHANNEL_ANALOG) {
+ return SR_ERR_ARG;
+ }
+ if ((idx = std_str_idx(data, ARRAY_AND_SIZE(trigger_slopes))) < 0) {
+ return SR_ERR_ARG;
+ }
+ trigger_slope = g_strdup(trigger_slopes[idx]);
+ if (strcmp(trigger_slope, trigger_slopes[0]) == 0) {
+ sr_libm2k_analog_trigger_condition_set(devc->m2k, ch_idx, RISING);
+ } else if (strcmp(trigger_slope, trigger_slopes[1]) == 0) {
+ sr_libm2k_analog_trigger_condition_set(devc->m2k, ch_idx, FALLING);
+ } else if (strcmp(trigger_slope, trigger_slopes[2]) == 0) {
+ sr_libm2k_analog_trigger_condition_set(devc->m2k, ch_idx, LOW);
+ } else if (strcmp(trigger_slope, trigger_slopes[3]) == 0) {
+ sr_libm2k_analog_trigger_condition_set(devc->m2k, ch_idx, HIGH);
+ }
+ g_free(trigger_slope);
+ break;
+ case SR_CONF_TRIGGER_LEVEL:
+ analog_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_ANALOG) > 0)
+ ? TRUE : FALSE;
+ if (analog_enabled) {
+ sr_libm2k_analog_trigger_level_set(devc->m2k, ch_idx,
+ g_variant_get_double(data));
+ }
+ break;
+ case SR_CONF_HIGH_RESOLUTION:
+ if (ch->type != SR_CHANNEL_ANALOG) {
+ return SR_ERR_ARG;
+ }
+ high_resolution = g_variant_get_boolean(data);
+ if (high_resolution) {
+ sr_libm2k_analog_range_set(devc->m2k, ch_idx, PLUS_MINUS_2_5V);
+ } else {
+ sr_libm2k_analog_range_set(devc->m2k, ch_idx, PLUS_MINUS_25V);
+ }
+ break;
+ default:
+ return SR_ERR_NA;
+ }
+ }
+ return SR_OK;
+}
+
+static int config_list(uint32_t key, GVariant **data,
+ const struct sr_dev_inst *sdi,
+ const struct sr_channel_group *cg)
+{
+ struct sr_channel *ch;
+
+ if (!cg) {
+ switch (key) {
+ case SR_CONF_SCAN_OPTIONS:
+ case SR_CONF_DEVICE_OPTIONS:
+ return STD_CONFIG_LIST(key, data, sdi, cg,
+ scanopts, drvopts,
+ devopts);
+
+ case SR_CONF_SAMPLERATE:
+ *data = std_gvar_samplerates(
+ ARRAY_AND_SIZE(samplerates));
+ break;
+ case SR_CONF_TRIGGER_MATCH:
+ *data = std_gvar_array_i32(
+ ARRAY_AND_SIZE(trigger_matches));
+ break;
+
+ default:
+ return SR_ERR_NA;
+ }
+ } else {
+ ch = cg->channels->data;
+
+ switch (key) {
+ case SR_CONF_DEVICE_OPTIONS:
+ if (ch->type == SR_CHANNEL_ANALOG) {
+ if (strcmp(cg->name, "Analog") == 0) {
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_analog_group));
+ } else {
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_analog_channel));
+ }
+ } else {
+ *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
+ }
+ break;
+ case SR_CONF_TRIGGER_SOURCE:
+ *data = g_variant_new_strv(ARRAY_AND_SIZE(trigger_sources));
+ break;
+ case SR_CONF_TRIGGER_SLOPE:
+ *data = g_variant_new_strv(ARRAY_AND_SIZE(trigger_slopes));
+ break;
+ default:
+ return SR_ERR_NA;
+ }
+ }
+ return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ GSList *l;
+ gboolean analog_enabled, digital_enabled;
+ struct sr_channel *ch;
+
+ devc = sdi->priv;
+ devc->sent_samples = 0;
+ analog_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_ANALOG) > 0) ? TRUE : FALSE;
+ digital_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_LOGIC) > 0) ? TRUE : FALSE;
+
+ for (l = sdi->channels; l; l = l->next) {
+ ch = l->data;
+ if (ch->type == SR_CHANNEL_ANALOG) {
+ sr_libm2k_analog_channel_enable(devc->m2k, ch->index, 1);
+ }
+ }
+
+ if (adalm2000_convert_trigger(sdi) != SR_OK) {
+ sr_err("Failed to configure triggers.");
+ return SR_ERR;
+ }
+
+ if (analog_enabled) {
+ if (devc->avg) {
+ sr_libm2k_analog_oversampling_ratio_set(devc->m2k, devc->avg_samples);
+ }
+ sr_libm2k_analog_kernel_buffers_count_set(devc->m2k, 64);
+ sr_libm2k_analog_streaming_flag_set(devc->m2k, 0);
+ }
+ if (digital_enabled) {
+ sr_libm2k_digital_kernel_buffers_count_set(devc->m2k, 64);
+ sr_libm2k_digital_streaming_flag_set(devc->m2k, 0);
+ }
+
+ if (sr_libm2k_has_mixed_signal(devc->m2k)) {
+ sr_libm2k_mixed_signal_acquisition_start(devc->m2k, devc->buffersize);
+ } else {
+ if (analog_enabled) {
+ sr_libm2k_analog_acquisition_start(devc->m2k, devc->buffersize);
+ }
+ if (digital_enabled) {
+ sr_libm2k_digital_acquisition_start(devc->m2k, devc->buffersize);
+ }
+ }
+
+ std_session_send_df_header(sdi);
+ sr_session_source_add(sdi->session, -1, G_IO_IN, 0, adalm2000_receive_data,
+ (struct sr_dev_inst *) sdi);
+
+ devc->start_time = g_get_monotonic_time();
+ devc->spent_us = 0;
+
+ return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ gboolean analog_enabled, digital_enabled;
+
+ devc = sdi->priv;
+
+ sr_libm2k_analog_acquisition_cancel(devc->m2k);
+ sr_libm2k_digital_acquisition_cancel(devc->m2k);
+
+ analog_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_ANALOG) > 0) ? TRUE : FALSE;
+ digital_enabled = (adalm2000_nb_enabled_channels(sdi, SR_CHANNEL_LOGIC) > 0) ? TRUE : FALSE;
+
+ if (sr_libm2k_has_mixed_signal(devc->m2k)) {
+ sr_libm2k_mixed_signal_acquisition_stop(devc->m2k);
+ } else {
+ if (digital_enabled) {
+ sr_libm2k_digital_acquisition_stop(devc->m2k);
+ }
+ if (analog_enabled) {
+ sr_libm2k_analog_acquisition_stop(devc->m2k);
+ }
+ }
+
+ sr_session_source_remove(sdi->session, -1);
+ std_session_send_df_end(sdi);
+
+ return SR_OK;
+}
+
+static struct sr_dev_driver adalm2000_driver_info = {
+ .name = "adalm2000",
+ .longname = "ADALM2000",
+ .api_version = 1,
+ .init = std_init,
+ .cleanup = std_cleanup,
+ .scan = scan,
+ .dev_list = std_dev_list,
+ .dev_clear = std_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,
+ .context = NULL,
+};
+SR_REGISTER_DEV_DRIVER(adalm2000_driver_info);
diff --git a/src/hardware/adalm2000/libm2k.cpp b/src/hardware/adalm2000/libm2k.cpp
new file mode 100644
index 000000000..224e0dbaf
--- /dev/null
+++ b/src/hardware/adalm2000/libm2k.cpp
@@ -0,0 +1,372 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2020 Analog Devices Inc.
+ *
+ * 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 "libm2k.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern "C" {
+
+libm2k::digital::M2kDigital *getDigital(struct M2k *m2k)
+{
+ libm2k::context::M2k *ctx = (libm2k::context::M2k *) m2k;
+ return ctx->getDigital();
+}
+
+libm2k::analog::M2kAnalogIn *getAnalogIn(struct M2k *m2k)
+{
+ libm2k::context::M2k *ctx = (libm2k::context::M2k *) m2k;
+ return ctx->getAnalogIn();
+}
+
+libm2k::M2kHardwareTrigger *getTrigger(struct M2k *m2k)
+{
+ libm2k::context::M2k *ctx = (libm2k::context::M2k *) m2k;
+ return ctx->getDigital()->getTrigger();
+}
+
+/* Context */
+M2k *sr_libm2k_context_open(const char *uri)
+{
+ libm2k::context::M2k *ctx;
+ if (strlen(uri) == 0) {
+ ctx = libm2k::context::m2kOpen();
+ } else {
+ ctx = libm2k::context::m2kOpen(uri);
+ }
+ return (M2k *) ctx;
+}
+
+int sr_libm2k_context_close(struct M2k **m2k)
+{
+ if (*m2k == nullptr) {
+ return 0;
+ }
+ auto ctx = (libm2k::context::M2k *) *m2k;
+
+ libm2k::context::contextClose(ctx, false);
+ *m2k = nullptr;
+ return 0;
+}
+
+void sr_libm2k_context_adc_calibrate(struct M2k *m2k)
+{
+ libm2k::context::M2k *ctx = (libm2k::context::M2k *) m2k;
+ ctx->calibrateADC();
+}
+
+int sr_libm2k_context_get_all(struct CONTEXT_INFO ***info)
+{
+ auto ctxs = libm2k::context::getContextsInfo();
+
+ struct CONTEXT_INFO **ctxs_info = (struct CONTEXT_INFO **) malloc(
+ ctxs.size() * sizeof(struct CONTEXT_INFO *));
+ for (unsigned int i = 0; i < ctxs.size(); ++i) {
+ ctxs_info[i] = (struct CONTEXT_INFO *) malloc(sizeof(struct CONTEXT_INFO));
+ ctxs_info[i]->id_vendor = ctxs[i]->id_vendor.c_str();
+ ctxs_info[i]->id_product = ctxs[i]->id_product.c_str();
+ ctxs_info[i]->manufacturer = ctxs[i]->manufacturer.c_str();
+ ctxs_info[i]->product = ctxs[i]->product.c_str();
+ ctxs_info[i]->serial = ctxs[i]->serial.c_str();
+ ctxs_info[i]->uri = ctxs[i]->uri.c_str();
+ }
+ *info = ctxs_info;
+ return ctxs.size();
+}
+
+int sr_libm2k_has_mixed_signal(struct M2k *m2k)
+{
+ libm2k::context::M2k *ctx = (libm2k::context::M2k *) m2k;
+ return ctx->hasMixedSignal();
+}
+
+void sr_libm2k_mixed_signal_acquisition_start(struct M2k *m2k, unsigned int nb_samples)
+{
+ libm2k::context::M2k *ctx = (libm2k::context::M2k *) m2k;
+ ctx->startMixedSignalAcquisition(nb_samples);
+}
+
+void sr_libm2k_mixed_signal_acquisition_stop(struct M2k *m2k)
+{
+ libm2k::context::M2k *ctx = (libm2k::context::M2k *) m2k;
+ ctx->stopMixedSignalAcquisition();
+}
+
+/* Analog */
+void sr_libm2k_analog_channel_enable(struct M2k *m2k, unsigned int chnIdx, int enable)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ analogIn->enableChannel(chnIdx, static_cast(enable));
+}
+
+double sr_libm2k_analog_samplerate_get(struct M2k *m2k)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ return analogIn->getSampleRate();
+}
+
+double sr_libm2k_analog_samplerate_set(struct M2k *m2k, double samplerate)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ return analogIn->setSampleRate(samplerate);
+}
+
+int sr_libm2k_analog_oversampling_ratio_get(struct M2k *m2k)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ return analogIn->getOversamplingRatio();
+}
+
+void sr_libm2k_analog_oversampling_ratio_set(struct M2k *m2k, int oversampling)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ analogIn->setOversamplingRatio(oversampling);
+}
+
+enum M2K_RANGE sr_libm2k_analog_range_get(struct M2k *m2k, unsigned int channel)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ return static_cast(analogIn->getRange(
+ static_cast(channel)));
+}
+
+void sr_libm2k_analog_range_set(struct M2k *m2k, unsigned int channel, enum M2K_RANGE range)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ analogIn->setRange(static_cast(channel),
+ static_cast(range));
+}
+
+void sr_libm2k_analog_acquisition_start(struct M2k *m2k, unsigned int buffer_size)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ analogIn->startAcquisition(buffer_size);
+}
+
+float **sr_libm2k_analog_samples_get(struct M2k *m2k, uint64_t nb_samples)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+
+ const double *data = analogIn->getSamplesInterleaved(nb_samples);
+ float **samples = new float *[2];
+ samples[0] = new float[nb_samples];
+ samples[1] = new float[nb_samples];
+ for (unsigned int i = 0, j = 0; i < nb_samples; i++, j += 2) {
+ samples[0][i] = (float) data[j];
+ samples[1][i] = (float) data[j + 1];
+ }
+ return samples;
+}
+
+void sr_libm2k_analog_acquisition_cancel(struct M2k *m2k)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ analogIn->cancelAcquisition();
+}
+
+void sr_libm2k_analog_acquisition_stop(struct M2k *m2k)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ analogIn->stopAcquisition();
+}
+
+void sr_libm2k_analog_kernel_buffers_count_set(struct M2k *m2k, unsigned int count)
+{
+ libm2k::analog::M2kAnalogIn *analogIn = getAnalogIn(m2k);
+ analogIn->setKernelBuffersCount(count);
+}
+
+/* Analog trigger */
+enum ANALOG_TRIGGER_SOURCE sr_libm2k_analog_trigger_source_get(struct M2k *m2k)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ return static_cast(trigger->getAnalogSource());
+}
+
+void sr_libm2k_analog_trigger_source_set(struct M2k *m2k, enum ANALOG_TRIGGER_SOURCE source)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setAnalogSource(static_cast(source));
+}
+
+enum ANALOG_TRIGGER_MODE sr_libm2k_analog_trigger_mode_get(struct M2k *m2k, unsigned int chnIdx)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ return static_cast(trigger->getAnalogMode(chnIdx));
+}
+
+void sr_libm2k_analog_trigger_mode_set(struct M2k *m2k, unsigned int chnIdx,
+ enum ANALOG_TRIGGER_MODE mode)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setAnalogMode(chnIdx, static_cast(mode));
+}
+
+enum ANALOG_TRIGGER_CONDITION sr_libm2k_analog_trigger_condition_get(struct M2k *m2k, unsigned int chnIdx)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ return static_cast(trigger->getAnalogCondition(chnIdx));
+}
+
+void sr_libm2k_analog_trigger_condition_set(struct M2k *m2k, unsigned int chnIdx,
+ enum ANALOG_TRIGGER_CONDITION condition)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setAnalogCondition(chnIdx, static_cast(condition));
+}
+
+float sr_libm2k_analog_trigger_level_get(struct M2k *m2k, unsigned int chnIdx)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ return static_cast(trigger->getAnalogLevel(chnIdx));
+}
+
+void sr_libm2k_analog_trigger_level_set(struct M2k *m2k, unsigned int chnIdx, float level)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setAnalogLevel(chnIdx, static_cast(level));
+}
+
+int sr_libm2k_analog_trigger_delay_get(struct M2k *m2k)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ return trigger->getAnalogDelay();
+}
+
+void sr_libm2k_analog_trigger_delay_set(struct M2k *m2k, int delay)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setAnalogDelay(delay);
+}
+
+void sr_libm2k_analog_streaming_flag_set(struct M2k *m2k, int flag)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setAnalogStreamingFlag(static_cast(flag));
+}
+
+/* Digital */
+double sr_libm2k_digital_samplerate_get(struct M2k *m2k)
+{
+ libm2k::digital::M2kDigital *digital = getDigital(m2k);
+ return digital->getSampleRateIn();
+}
+
+double sr_libm2k_digital_samplerate_set(struct M2k *m2k, double samplerate)
+{
+ libm2k::digital::M2kDigital *digital = getDigital(m2k);
+ return digital->setSampleRateIn(samplerate);
+}
+
+void sr_libm2k_digital_acquisition_start(struct M2k *m2k, unsigned int buffer_size)
+{
+ libm2k::digital::M2kDigital *digital = getDigital(m2k);
+ digital->startAcquisition(buffer_size);
+}
+
+uint32_t *sr_libm2k_digital_samples_get(struct M2k *m2k, uint64_t nb_samples)
+{
+ libm2k::digital::M2kDigital *digital = getDigital(m2k);
+ return (uint32_t *) digital->getSamplesP(nb_samples);
+}
+
+void sr_libm2k_digital_acquisition_cancel(struct M2k *m2k)
+{
+ libm2k::digital::M2kDigital *digital = getDigital(m2k);
+ digital->cancelAcquisition();
+}
+
+void sr_libm2k_digital_acquisition_stop(struct M2k *m2k)
+{
+ libm2k::digital::M2kDigital *digital = getDigital(m2k);
+ digital->stopAcquisition();
+}
+
+void sr_libm2k_digital_kernel_buffers_count_set(struct M2k *m2k, unsigned int count)
+{
+ libm2k::digital::M2kDigital *digital = getDigital(m2k);
+ digital->setKernelBuffersCountIn(count);
+}
+
+/* Digital trigger */
+void sr_libm2k_digital_trigger_source_set(struct M2k *m2k, enum DIGITAL_TRIGGER_SOURCE source)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setDigitalSource(static_cast(source));
+}
+
+enum M2K_TRIGGER_CONDITION_DIGITAL sr_libm2k_digital_trigger_condition_get(struct M2k *m2k, unsigned int chnIdx)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ return static_cast(trigger->getDigitalCondition(chnIdx));
+}
+
+void sr_libm2k_digital_trigger_condition_set(struct M2k *m2k, unsigned int chnIdx, uint32_t cond)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ libm2k::M2K_TRIGGER_CONDITION_DIGITAL condition;
+ switch (cond) {
+ case SR_TRIGGER_ZERO:
+ condition = libm2k::LOW_LEVEL_DIGITAL;
+ break;
+ case SR_TRIGGER_ONE:
+ condition = libm2k::HIGH_LEVEL_DIGITAL;
+ break;
+ case SR_TRIGGER_RISING:
+ condition = libm2k::RISING_EDGE_DIGITAL;
+ break;
+ case SR_TRIGGER_FALLING:
+ condition = libm2k::FALLING_EDGE_DIGITAL;
+ break;
+ case SR_TRIGGER_EDGE:
+ condition = libm2k::ANY_EDGE_DIGITAL;
+ break;
+ case SR_NO_TRIGGER:
+ condition = libm2k::NO_TRIGGER_DIGITAL;
+ break;
+ default:
+ condition = libm2k::NO_TRIGGER_DIGITAL;
+ }
+ trigger->setDigitalCondition(chnIdx, condition);
+}
+
+int sr_libm2k_digital_trigger_delay_get(struct M2k *m2k)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ return trigger->getDigitalDelay();
+}
+
+void sr_libm2k_digital_trigger_delay_set(struct M2k *m2k, int delay)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setDigitalDelay(delay);
+}
+
+void sr_libm2k_digital_streaming_flag_set(struct M2k *m2k, int flag)
+{
+ libm2k::M2kHardwareTrigger *trigger = getTrigger(m2k);
+ trigger->setDigitalStreamingFlag(flag);
+}
+
+}
diff --git a/src/hardware/adalm2000/libm2k.h b/src/hardware/adalm2000/libm2k.h
new file mode 100644
index 000000000..a340f76f4
--- /dev/null
+++ b/src/hardware/adalm2000/libm2k.h
@@ -0,0 +1,182 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2020 Analog Devices Inc.
+ *
+ * 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_ADALM2000_LIBM2K_H
+#define LIBSIGROK_HARDWARE_ADALM2000_LIBM2K_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SR_NO_TRIGGER -1
+
+enum DIGITAL_TRIGGER_SOURCE {
+ SRC_TRIGGER_IN = 0,
+ SRC_ANALOG_IN = 1,
+ SRC_NONE = 2,
+};
+
+enum M2K_TRIGGER_CONDITION_DIGITAL {
+ RISING_EDGE_DIGITAL = 0,
+ FALLING_EDGE_DIGITAL = 1,
+ LOW_LEVEL_DIGITAL = 2,
+ HIGH_LEVEL_DIGITAL = 3,
+ ANY_EDGE_DIGITAL = 4,
+ NO_TRIGGER_DIGITAL = 5
+};
+
+enum M2K_RANGE {
+ PLUS_MINUS_25V = 0,
+ PLUS_MINUS_2_5V = 1,
+};
+
+enum ANALOG_TRIGGER_SOURCE {
+ CH_1 = 0,
+ CH_2 = 1,
+ CH_1_OR_CH_2 = 2,
+ CH_1_AND_CH_2 = 3,
+ CH_1_XOR_CH_2 = 4,
+ SRC_DIGITAL_IN = 5,
+};
+
+enum ANALOG_TRIGGER_MODE {
+ ALWAYS = 0,
+ ANALOG = 1,
+};
+
+enum ANALOG_TRIGGER_CONDITION {
+ RISING = 0,
+ FALLING = 1,
+ LOW = 2,
+ HIGH = 3,
+};
+
+struct CONTEXT_INFO {
+ const char *id_vendor;
+ const char *id_product;
+ const char *manufacturer;
+ const char *product;
+ const char *serial;
+ const char *uri;
+};
+
+/* Context */
+struct M2k *sr_libm2k_context_open(const char *uri);
+
+int sr_libm2k_context_close(struct M2k **m2k);
+
+void sr_libm2k_context_adc_calibrate(struct M2k *m2k);
+
+int sr_libm2k_context_get_all(struct CONTEXT_INFO ***info);
+
+int sr_libm2k_has_mixed_signal(struct M2k *m2k);
+
+void sr_libm2k_mixed_signal_acquisition_start(struct M2k *m2k, unsigned int nb_samples);
+
+void sr_libm2k_mixed_signal_acquisition_stop(struct M2k *m2k);
+
+
+/* Analog */
+void sr_libm2k_analog_channel_enable(struct M2k *m2k, unsigned int chnIdx, int enable);
+
+double sr_libm2k_analog_samplerate_get(struct M2k *m2k);
+
+double sr_libm2k_analog_samplerate_set(struct M2k *m2k, double samplerate);
+
+int sr_libm2k_analog_oversampling_ratio_get(struct M2k *m2k);
+
+void sr_libm2k_analog_oversampling_ratio_set(struct M2k *m2k, int oversampling);
+
+enum M2K_RANGE sr_libm2k_analog_range_get(struct M2k *m2k, unsigned int channel);
+
+void sr_libm2k_analog_range_set(struct M2k *m2k, unsigned int channel, enum M2K_RANGE range);
+
+void sr_libm2k_analog_acquisition_start(struct M2k *m2k, unsigned int buffer_size);
+
+float **sr_libm2k_analog_samples_get(struct M2k *m2k, uint64_t nb_samples);
+
+void sr_libm2k_analog_acquisition_cancel(struct M2k *m2k);
+
+void sr_libm2k_analog_acquisition_stop(struct M2k *m2k);
+
+void sr_libm2k_analog_kernel_buffers_count_set(struct M2k *m2k, unsigned int count);
+
+
+/* Analog trigger */
+enum ANALOG_TRIGGER_SOURCE sr_libm2k_analog_trigger_source_get(struct M2k *m2k);
+
+void sr_libm2k_analog_trigger_source_set(struct M2k *m2k, enum ANALOG_TRIGGER_SOURCE source);
+
+enum ANALOG_TRIGGER_MODE sr_libm2k_analog_trigger_mode_get(struct M2k *m2k, unsigned int chnIdx);
+
+void sr_libm2k_analog_trigger_mode_set(struct M2k *m2k, unsigned int chnIdx,
+ enum ANALOG_TRIGGER_MODE mode);
+
+enum ANALOG_TRIGGER_CONDITION sr_libm2k_analog_trigger_condition_get(struct M2k *m2k, unsigned int chnIdx);
+
+void sr_libm2k_analog_trigger_condition_set(struct M2k *m2k, unsigned int chnIdx,
+ enum ANALOG_TRIGGER_CONDITION condition);
+
+float sr_libm2k_analog_trigger_level_get(struct M2k *m2k, unsigned int chnIdx);
+
+void sr_libm2k_analog_trigger_level_set(struct M2k *m2k, unsigned int chnIdx, float level);
+
+int sr_libm2k_analog_trigger_delay_get(struct M2k *m2k);
+
+void sr_libm2k_analog_trigger_delay_set(struct M2k *m2k, int delay);
+
+void sr_libm2k_analog_streaming_flag_set(struct M2k *m2k, int flag);
+
+
+/* Digital */
+double sr_libm2k_digital_samplerate_get(struct M2k *m2k);
+
+double sr_libm2k_digital_samplerate_set(struct M2k *m2k, double samplerate);
+
+void sr_libm2k_digital_acquisition_start(struct M2k *m2k, unsigned int buffer_size);
+
+uint32_t *sr_libm2k_digital_samples_get(struct M2k *m2k, uint64_t nb_samples);
+
+void sr_libm2k_digital_acquisition_cancel(struct M2k *m2k);
+
+void sr_libm2k_digital_acquisition_stop(struct M2k *m2k);
+
+void sr_libm2k_digital_kernel_buffers_count_set(struct M2k *m2k, unsigned int count);
+
+
+/* Digital trigger*/
+void sr_libm2k_digital_trigger_source_set(struct M2k *m2k, enum DIGITAL_TRIGGER_SOURCE source);
+
+enum M2K_TRIGGER_CONDITION_DIGITAL sr_libm2k_digital_trigger_condition_get(struct M2k *m2k, unsigned int chnIdx);
+
+void sr_libm2k_digital_trigger_condition_set(struct M2k *m2k, unsigned int chnIdx, uint32_t cond);
+
+int sr_libm2k_digital_trigger_delay_get(struct M2k *m2k);
+
+void sr_libm2k_digital_trigger_delay_set(struct M2k *m2k, int delay);
+
+void sr_libm2k_digital_streaming_flag_set(struct M2k *m2k, int flag);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif //LIBSIGROK_HARDWARE_ADALM2000_LIBM2K_H
diff --git a/src/hardware/adalm2000/protocol.c b/src/hardware/adalm2000/protocol.c
new file mode 100644
index 000000000..6c159503b
--- /dev/null
+++ b/src/hardware/adalm2000/protocol.c
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2020 Analog Devices Inc.
+ *
+ * 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 "protocol.h"
+
+SR_PRIV int adalm2000_nb_enabled_channels(const struct sr_dev_inst *sdi, int type)
+{
+ struct sr_channel *ch;
+ int nb_channels;
+ GSList *l;
+
+ nb_channels = 0;
+
+ for (l = sdi->channels; l; l = l->next) {
+ ch = l->data;
+ if (ch->type == type) {
+ if (ch->enabled) {
+ nb_channels++;
+ }
+ }
+ }
+ return nb_channels;
+}
+
+SR_PRIV int adalm2000_convert_trigger(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ struct sr_trigger *trigger;
+ struct sr_trigger_stage *stage;
+ struct sr_trigger_match *match;
+ struct sr_channel *ch;
+ const GSList *l, *m;
+
+ devc = sdi->priv;
+
+ for (l = sdi->channels; l; l = l->next) {
+ ch = l->data;
+ if (ch->type == SR_CHANNEL_LOGIC) {
+ if (ch->enabled) {
+ sr_libm2k_digital_trigger_condition_set(devc->m2k, ch->index,
+ SR_NO_TRIGGER);
+ }
+ }
+ }
+
+ if (!(trigger = sr_session_trigger_get(sdi->session))) {
+ return SR_OK;
+ }
+
+ sr_libm2k_digital_streaming_flag_set(devc->m2k, 0);
+ for (l = trigger->stages; l; l = l->next) {
+ stage = l->data;
+ for (m = stage->matches; m; m = m->next) {
+ match = m->data;
+ if (!match->channel->enabled) {
+ /* Ignore disabled channels with a trigger. */
+ continue;
+ }
+ sr_libm2k_digital_trigger_condition_set(devc->m2k, match->channel->index,
+ match->match);
+ }
+ }
+
+ return SR_OK;
+}
+
+static void send_analog_packet(struct sr_dev_inst *sdi, float *data, int index, uint64_t sending_now)
+{
+ struct dev_context *devc;
+ struct sr_channel *ch;
+ struct sr_datafeed_packet packet;
+
+ if (!(devc = sdi->priv)) {
+ return;
+ }
+
+ ch = g_slist_nth_data(sdi->channels, DEFAULT_NUM_LOGIC_CHANNELS + index);
+ devc->meaning.channels = g_slist_append(NULL, ch);
+
+ devc->packet.data = data;
+ devc->packet.num_samples = sending_now;
+
+ packet.payload = &devc->packet;
+ packet.type = SR_DF_ANALOG;
+
+ sr_session_send(sdi, &packet);
+}
+
+SR_PRIV int adalm2000_receive_data(int fd, int revents, void *cb_data)
+{
+ struct sr_dev_inst *sdi;
+ struct dev_context *devc;
+ struct sr_channel *ch;
+ struct sr_datafeed_packet packet;
+ struct sr_datafeed_logic logic;
+ uint64_t samples_todo, logic_done, analog_done, sending_now, analog_sent;
+ int64_t elapsed_us, limit_us, todo_us;
+ uint32_t *logic_data;
+ float **analog_data;
+ GSList *l;
+
+ (void) fd;
+ (void) revents;
+
+ if (!(sdi = cb_data)) {
+ return TRUE;
+ }
+
+ if (!(devc = sdi->priv)) {
+ return TRUE;
+ }
+
+ elapsed_us = g_get_monotonic_time() - devc->start_time;
+ limit_us = 1000 * devc->limit_msec;
+
+ if (limit_us > 0 && limit_us < elapsed_us) {
+ todo_us = MAX(0, limit_us - devc->spent_us);
+ } else {
+ todo_us = MAX(0, elapsed_us - devc->spent_us);
+ }
+
+ samples_todo = (todo_us * sr_libm2k_digital_samplerate_get(devc->m2k) + G_USEC_PER_SEC - 1)
+ / G_USEC_PER_SEC;
+
+ if (devc->limit_samples > 0) {
+ if (devc->limit_samples < devc->sent_samples) {
+ samples_todo = 0;
+ } else if (devc->limit_samples - devc->sent_samples < samples_todo) {
+ samples_todo = devc->limit_samples - devc->sent_samples;
+ }
+ }
+
+ if (samples_todo == 0) {
+ return G_SOURCE_CONTINUE;
+ }
+
+ todo_us = samples_todo * G_USEC_PER_SEC / sr_libm2k_digital_samplerate_get(devc->m2k);
+
+ logic_done = 0;
+ analog_done = 0;
+
+ while (logic_done < samples_todo || analog_done < samples_todo) {
+ if (analog_done < samples_todo) {
+ analog_sent = MIN(samples_todo - analog_done, devc->buffersize);
+
+ analog_data = sr_libm2k_analog_samples_get(devc->m2k, devc->buffersize);
+ for (l = sdi->channels; l; l = l->next) {
+ ch = l->data;
+ if (ch->type == SR_CHANNEL_ANALOG) {
+ if (ch->enabled) {
+ send_analog_packet(sdi, analog_data[ch->index],
+ ch->index, analog_sent);
+ }
+ }
+ }
+ analog_done += analog_sent;
+ }
+ if (logic_done < samples_todo) {
+ logic_data = sr_libm2k_digital_samples_get(devc->m2k, devc->buffersize);
+
+ packet.type = SR_DF_LOGIC;
+ packet.payload = &logic;
+ logic.unitsize = devc->logic_unitsize;
+
+ sending_now = MIN(samples_todo - logic_done, devc->buffersize);
+
+ logic.length = sending_now * devc->logic_unitsize;
+ logic.data = logic_data;
+ sr_session_send(sdi, &packet);
+ logic_done += sending_now;
+ }
+
+ }
+
+ devc->sent_samples += logic_done;
+ devc->spent_us += todo_us;
+ if ((devc->limit_samples > 0 && devc->sent_samples >= devc->limit_samples)
+ || (limit_us > 0 && devc->spent_us >= limit_us)) {
+ sr_dev_acquisition_stop(sdi);
+ }
+
+ return G_SOURCE_CONTINUE;
+}
diff --git a/src/hardware/adalm2000/protocol.h b/src/hardware/adalm2000/protocol.h
new file mode 100644
index 000000000..b5a6745ee
--- /dev/null
+++ b/src/hardware/adalm2000/protocol.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2020 Analog Devices Inc.
+ *
+ * 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_ADALM2000_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_ADALM2000_PROTOCOL_H
+
+#include
+#include
+#include
+#include "libsigrok-internal.h"
+#include "libm2k.h"
+
+#define LOG_PREFIX "adalm2000"
+
+#define DEFAULT_NUM_LOGIC_CHANNELS 16
+#define DEFAULT_NUM_ANALOG_CHANNELS 2
+#define MAX_NEG_DELAY -8192
+
+struct dev_context {
+ struct M2k *m2k;
+
+ uint64_t start_time;
+ int64_t spent_us;
+ uint64_t limit_msec;
+ uint64_t limit_frames;
+ uint64_t limit_samples;
+ uint64_t sent_samples;
+ uint64_t buffersize;
+ uint32_t logic_unitsize;
+ gboolean avg;
+ uint64_t avg_samples;
+
+ struct sr_datafeed_analog packet;
+ struct sr_analog_encoding encoding;
+ struct sr_analog_meaning meaning;
+ struct sr_analog_spec spec;
+};
+
+SR_PRIV int adalm2000_nb_enabled_channels(const struct sr_dev_inst *sdi, int type);
+
+SR_PRIV int adalm2000_convert_trigger(const struct sr_dev_inst *sdi);
+
+SR_PRIV int adalm2000_receive_data(int fd, int revents, void *cb_data);
+
+#endif