summaryrefslogtreecommitdiff
path: root/tests/iio_adi_xflow_check.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/iio_adi_xflow_check.c')
-rw-r--r--tests/iio_adi_xflow_check.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/tests/iio_adi_xflow_check.c b/tests/iio_adi_xflow_check.c
new file mode 100644
index 0000000..a1d4be8
--- /dev/null
+++ b/tests/iio_adi_xflow_check.c
@@ -0,0 +1,348 @@
+/*
+ * iio_adi_dac_overflow_test
+ *
+ * Copyright (C) 2015 Analog Devices, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * */
+
+#include <errno.h>
+#include <getopt.h>
+#include <iio.h>
+#include <math.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+struct xflow_pthread_data {
+ struct iio_context *ctx;
+ const char *device_name;
+};
+
+static const struct option options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"network", required_argument, 0, 'n'},
+ {"uri", required_argument, 0, 'u'},
+ {"buffer-size", required_argument, 0, 's'},
+ {"auto", no_argument, 0, 'a'},
+ {0, 0, 0, 0},
+};
+
+static const char *options_descriptions[] = {
+ "Show this help and quit.",
+ "Use the network backend with the provided hostname.",
+ "Use the context with the provided URI.",
+ "Size of the buffer in sample sets. Default is 1Msample",
+ "Scan for available contexts and if only one is available use it.",
+};
+
+static void usage(char *argv[])
+{
+ unsigned int i;
+
+ printf("Usage:\n\t%s [-n <hostname>] [-u <uri>] [ -a ][-s <size>] <iio_device>\n\nOptions:\n", argv[0]);
+ for (i = 0; options[i].name; i++)
+ printf("\t-%c, --%s\n\t\t\t%s\n",
+ options[i].val, options[i].name,
+ options_descriptions[i]);
+}
+
+static bool app_running = true;
+static bool device_is_tx;
+
+static void quit_all(int sig)
+{
+ app_running = false;
+}
+
+static void set_handler(int signal_nb, void (*handler)(int))
+{
+#ifdef _WIN32
+ signal(signal_nb, handler);
+#else
+ struct sigaction sig;
+ sigaction(signal_nb, NULL, &sig);
+ sig.sa_handler = handler;
+ sigaction(signal_nb, &sig, NULL);
+#endif
+}
+
+static struct iio_device *get_device(const struct iio_context *ctx,
+ const char *id)
+{
+
+ unsigned int i, nb_devices = iio_context_get_devices_count(ctx);
+ struct iio_device *device;
+
+ for (i = 0; i < nb_devices; i++) {
+ const char *name;
+ device = iio_context_get_device(ctx, i);
+ name = iio_device_get_name(device);
+ if (name && !strcmp(name, id))
+ break;
+ if (!strcmp(id, iio_device_get_id(device)))
+ break;
+ }
+
+ if (i < nb_devices)
+ return device;
+
+ fprintf(stderr, "Device %s not found\n", id);
+ return NULL;
+}
+
+
+static void *monitor_thread_fn(void *data)
+{
+ struct xflow_pthread_data *xflow_pthread_data = data;
+ struct iio_context *ctx;
+ struct iio_device *dev;
+ uint32_t val;
+ int ret;
+
+ ctx = xflow_pthread_data->ctx;
+
+ dev = get_device(ctx, xflow_pthread_data->device_name);
+ if (!dev) {
+ fprintf(stderr, "Unable to find IIO device\n");
+ return (void *)-1;
+ }
+
+ /* Give the main thread a moment to start the DMA */
+ sleep(1);
+
+ /* Clear all status bits */
+ iio_device_reg_write(dev, 0x80000088, 0x6);
+
+ while (app_running) {
+ ret = iio_device_reg_read(dev, 0x80000088, &val);
+ if (ret) {
+ fprintf(stderr, "Failed to read status register: %s\n",
+ strerror(-ret));
+ continue;
+ }
+
+ if (device_is_tx) {
+ if (val & 1)
+ fprintf(stderr, "Underflow detected\n");
+ } else {
+ if (val & 4)
+ fprintf(stderr, "Overflow detected\n");
+ }
+
+ /* Clear bits */
+ if (val)
+ iio_device_reg_write(dev, 0x80000088, val);
+ sleep(1);
+ }
+
+ return (void *)0;
+}
+
+static struct iio_context *scan(void)
+{
+ struct iio_scan_context *scan_ctx;
+ struct iio_context_info **info;
+ struct iio_context *ctx = NULL;
+ unsigned int i;
+ ssize_t ret;
+
+ scan_ctx = iio_create_scan_context(NULL, 0);
+ if (!scan_ctx) {
+ fprintf(stderr, "Unable to create scan context\n");
+ return NULL;
+ }
+
+ ret = iio_scan_context_get_info_list(scan_ctx, &info);
+ if (ret < 0) {
+ char err_str[1024];
+ iio_strerror(-ret, err_str, sizeof(err_str));
+ fprintf(stderr, "Scanning for IIO contexts failed: %s\n", err_str);
+ goto err_free_ctx;
+ }
+
+ if (ret == 0) {
+ printf("No IIO context found.\n");
+ goto err_free_info_list;
+ }
+
+ if (ret == 1) {
+ ctx = iio_create_context_from_uri(iio_context_info_get_uri(info[0]));
+ } else {
+ fprintf(stderr, "Multiple contexts found. Please select one using --uri:\n");
+
+ for (i = 0; i < (size_t) ret; i++) {
+ fprintf(stderr, "\t%d: %s [%s]\n", i,
+ iio_context_info_get_description(info[i]),
+ iio_context_info_get_uri(info[i]));
+ }
+ }
+
+ err_free_info_list:
+ iio_context_info_list_free(info);
+ err_free_ctx:
+ iio_scan_context_destroy(scan_ctx);
+
+ return ctx;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned int buffer_size = 1024 * 1024;
+ int c, option_index = 0;
+ const char *arg_uri = NULL;
+ const char *arg_ip = NULL;
+ unsigned int n_tx = 0, n_rx = 0;
+ static struct iio_context *ctx;
+ static struct xflow_pthread_data xflow_pthread_data;
+ bool scan_for_context = false;
+ unsigned int i, nb_channels;
+ struct iio_buffer *buffer;
+ pthread_t monitor_thread;
+ const char *device_name;
+ struct iio_device *dev;
+ char unit;
+ int ret;
+
+ while ((c = getopt_long(argc, argv, "+hn:u:s:a",
+ options, &option_index)) != -1) {
+ switch (c) {
+ case 'h':
+ usage(argv);
+ return EXIT_SUCCESS;
+ case 's':
+ ret = sscanf(optarg, "%u%c", &buffer_size, &unit);
+ if (ret == 0)
+ return EXIT_FAILURE;
+ if (ret == 2) {
+ if (unit == 'k')
+ buffer_size *= 1024;
+ else if (unit == 'M')
+ buffer_size *= 1024 * 1024;
+ }
+ break;
+ case 'n':
+ arg_ip = optarg;
+ break;
+ case 'u':
+ arg_uri = optarg;
+ break;
+ case 'a':
+ scan_for_context = true;
+ break;
+ case '?':
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (optind + 1 != argc) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ usage(argv);
+ return EXIT_FAILURE;
+ }
+
+#ifndef _WIN32
+ set_handler(SIGHUP, &quit_all);
+#endif
+ set_handler(SIGINT, &quit_all);
+ set_handler(SIGSEGV, &quit_all);
+ set_handler(SIGTERM, &quit_all);
+
+
+ if (scan_for_context)
+ ctx = scan();
+ else if (arg_uri)
+ ctx = iio_create_context_from_uri(arg_uri);
+ else if (arg_ip)
+ ctx = iio_create_network_context(arg_ip);
+ else
+ ctx = iio_create_default_context();
+
+ if (!ctx) {
+ fprintf(stderr, "Unable to create IIO context\n");
+ return EXIT_FAILURE;
+ }
+
+ device_name = argv[optind];
+
+ dev = get_device(ctx, device_name);
+ if (!dev) {
+ iio_context_destroy(ctx);
+ return EXIT_FAILURE;
+ }
+
+ nb_channels = iio_device_get_channels_count(dev);
+ for (i = 0; i < nb_channels; i++) {
+ struct iio_channel *ch = iio_device_get_channel(dev, i);
+ if (!iio_channel_is_scan_element(ch))
+ continue;
+ iio_channel_enable(ch);
+ if (iio_channel_is_output(ch))
+ n_tx++;
+ else
+ n_rx++;
+ }
+
+ if (n_tx >= n_rx)
+ device_is_tx = true;
+ else
+ device_is_tx = false;
+
+ printf("Monitoring %s for underflows/overflows\n",
+ iio_device_get_name(dev));
+
+ buffer = iio_device_create_buffer(dev, buffer_size, false);
+ if (!buffer) {
+ fprintf(stderr, "Unable to allocate buffer\n");
+ iio_context_destroy(ctx);
+ return EXIT_FAILURE;
+ }
+
+ xflow_pthread_data.ctx = ctx;
+ xflow_pthread_data.device_name = device_name;
+
+ ret = pthread_create(&monitor_thread, NULL, monitor_thread_fn,
+ (void *)&xflow_pthread_data);
+ if (ret) {
+ fprintf(stderr, "Failed to create monitor thread: %s\n",
+ strerror(-ret));
+ }
+
+ while (app_running) {
+ if (device_is_tx) {
+ ret = iio_buffer_push(buffer);
+ if (ret < 0) {
+ fprintf(stderr, "Unable to push buffer: %s\n",
+ strerror(-ret));
+ app_running = false;
+ break;
+ }
+ } else {
+ ret = iio_buffer_refill(buffer);
+ if (ret < 0) {
+ fprintf(stderr, "Unable to refill buffer: %s\n",
+ strerror(-ret));
+ app_running = false;
+ break;
+ }
+ }
+ }
+
+ pthread_join(monitor_thread, NULL);
+
+ iio_buffer_destroy(buffer);
+ iio_context_destroy(ctx);
+
+ return 0;
+}