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