• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * iio_adi_dac_overflow_test
3  *
4  * Copyright (C) 2015 Analog Devices, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * */
17 
18 #include <errno.h>
19 #include <getopt.h>
20 #include <iio.h>
21 #include <math.h>
22 #include <pthread.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 struct xflow_pthread_data {
29 	struct iio_context *ctx;
30 	const char *device_name;
31 };
32 
33 static const struct option options[] = {
34 	  {"help", no_argument, 0, 'h'},
35 	  {"network", required_argument, 0, 'n'},
36 	  {"uri", required_argument, 0, 'u'},
37 	  {"buffer-size", required_argument, 0, 's'},
38 	  {"auto", no_argument, 0, 'a'},
39 	  {0, 0, 0, 0},
40 };
41 
42 static const char *options_descriptions[] = {
43 	"Show this help and quit.",
44 	"Use the network backend with the provided hostname.",
45 	"Use the context with the provided URI.",
46 	"Size of the buffer in sample sets. Default is 1Msample",
47 	"Scan for available contexts and if only one is available use it.",
48 };
49 
usage(char * argv[])50 static void usage(char *argv[])
51 {
52 	unsigned int i;
53 
54 	printf("Usage:\n\t%s [-n <hostname>] [-u <uri>] [ -a ][-s <size>] <iio_device>\n\nOptions:\n", argv[0]);
55 	for (i = 0; options[i].name; i++)
56 		printf("\t-%c, --%s\n\t\t\t%s\n",
57 					options[i].val, options[i].name,
58 					options_descriptions[i]);
59 }
60 
61 static bool app_running = true;
62 static bool device_is_tx;
63 
quit_all(int sig)64 static void quit_all(int sig)
65 {
66 	app_running = false;
67 }
68 
set_handler(int signal_nb,void (* handler)(int))69 static void set_handler(int signal_nb, void (*handler)(int))
70 {
71 #ifdef _WIN32
72 	signal(signal_nb, handler);
73 #else
74 	struct sigaction sig;
75 	sigaction(signal_nb, NULL, &sig);
76 	sig.sa_handler = handler;
77 	sigaction(signal_nb, &sig, NULL);
78 #endif
79 }
80 
get_device(const struct iio_context * ctx,const char * id)81 static struct iio_device *get_device(const struct iio_context *ctx,
82 		const char *id)
83 {
84 
85 	unsigned int i, nb_devices = iio_context_get_devices_count(ctx);
86 	struct iio_device *device;
87 
88 	for (i = 0; i < nb_devices; i++) {
89 		const char *name;
90 		device = iio_context_get_device(ctx, i);
91 		name = iio_device_get_name(device);
92 		if (name && !strcmp(name, id))
93 			break;
94 		if (!strcmp(id, iio_device_get_id(device)))
95 			break;
96 	}
97 
98 	if (i < nb_devices)
99 		return device;
100 
101 	fprintf(stderr, "Device %s not found\n", id);
102 	return NULL;
103 }
104 
105 
monitor_thread_fn(void * data)106 static void *monitor_thread_fn(void *data)
107 {
108 	struct xflow_pthread_data *xflow_pthread_data = data;
109 	struct iio_context *ctx;
110 	struct iio_device *dev;
111 	uint32_t val;
112 	int ret;
113 
114 	ctx = xflow_pthread_data->ctx;
115 
116 	dev = get_device(ctx, xflow_pthread_data->device_name);
117 	if (!dev) {
118 		fprintf(stderr, "Unable to find IIO device\n");
119 		return (void *)-1;
120 	}
121 
122 	/* Give the main thread a moment to start the DMA */
123 	sleep(1);
124 
125 	/* Clear all status bits */
126 	iio_device_reg_write(dev, 0x80000088, 0x6);
127 
128 	while (app_running) {
129 		ret = iio_device_reg_read(dev, 0x80000088, &val);
130 		if (ret) {
131 			fprintf(stderr, "Failed to read status register: %s\n",
132 					strerror(-ret));
133 			continue;
134 		}
135 
136 		if (device_is_tx) {
137 			if (val & 1)
138 				fprintf(stderr, "Underflow detected\n");
139 		} else {
140 			if (val & 4)
141 				fprintf(stderr, "Overflow detected\n");
142 		}
143 
144 		/* Clear bits */
145 		if (val)
146 			iio_device_reg_write(dev, 0x80000088, val);
147 		sleep(1);
148 	}
149 
150 	return (void *)0;
151 }
152 
scan(void)153 static struct iio_context *scan(void)
154 {
155 	struct iio_scan_context *scan_ctx;
156 	struct iio_context_info **info;
157 	struct iio_context *ctx = NULL;
158 	unsigned int i;
159 	ssize_t ret;
160 
161 	scan_ctx = iio_create_scan_context(NULL, 0);
162 	if (!scan_ctx) {
163 		fprintf(stderr, "Unable to create scan context\n");
164 		return NULL;
165 	}
166 
167 	ret = iio_scan_context_get_info_list(scan_ctx, &info);
168 	if (ret < 0) {
169 		char err_str[1024];
170 		iio_strerror(-ret, err_str, sizeof(err_str));
171 		fprintf(stderr, "Scanning for IIO contexts failed: %s\n", err_str);
172 		goto err_free_ctx;
173 	}
174 
175 	if (ret == 0) {
176 		printf("No IIO context found.\n");
177 		goto err_free_info_list;
178 	}
179 
180 	if (ret == 1) {
181 		ctx = iio_create_context_from_uri(iio_context_info_get_uri(info[0]));
182 	} else {
183 		fprintf(stderr, "Multiple contexts found. Please select one using --uri:\n");
184 
185 		for (i = 0; i < (size_t) ret; i++) {
186 			fprintf(stderr, "\t%d: %s [%s]\n", i,
187 				iio_context_info_get_description(info[i]),
188 				iio_context_info_get_uri(info[i]));
189 		}
190 	}
191 
192 	err_free_info_list:
193 	iio_context_info_list_free(info);
194 	err_free_ctx:
195 	iio_scan_context_destroy(scan_ctx);
196 
197 	return ctx;
198 }
199 
main(int argc,char ** argv)200 int main(int argc, char **argv)
201 {
202 	unsigned int buffer_size = 1024 * 1024;
203 	int c, option_index = 0;
204 	const char *arg_uri = NULL;
205 	const char *arg_ip = NULL;
206 	unsigned int n_tx = 0, n_rx = 0;
207 	static struct iio_context *ctx;
208 	static struct xflow_pthread_data xflow_pthread_data;
209 	bool scan_for_context = false;
210 	unsigned int i, nb_channels;
211 	struct iio_buffer *buffer;
212 	pthread_t monitor_thread;
213 	const char *device_name;
214 	struct iio_device *dev;
215 	char unit;
216 	int ret;
217 
218 	while ((c = getopt_long(argc, argv, "+hn:u:s:a",
219 					options, &option_index)) != -1) {
220 		switch (c) {
221 		case 'h':
222 			usage(argv);
223 			return EXIT_SUCCESS;
224 		case 's':
225 			ret = sscanf(optarg, "%u%c", &buffer_size, &unit);
226 			if (ret == 0)
227 				return EXIT_FAILURE;
228 			if (ret == 2) {
229 				if (unit == 'k')
230 					buffer_size *= 1024;
231 				else if (unit == 'M')
232 					buffer_size *= 1024 * 1024;
233 			}
234 			break;
235 		case 'n':
236 			arg_ip = optarg;
237 			break;
238 		case 'u':
239 			arg_uri = optarg;
240 			break;
241 		case 'a':
242 			scan_for_context = true;
243 			break;
244 		case '?':
245 			return EXIT_FAILURE;
246 		}
247 	}
248 
249 	if (optind + 1 != argc) {
250 		fprintf(stderr, "Incorrect number of arguments.\n\n");
251 		usage(argv);
252 		return EXIT_FAILURE;
253 	}
254 
255 #ifndef _WIN32
256 	set_handler(SIGHUP, &quit_all);
257 #endif
258 	set_handler(SIGINT, &quit_all);
259 	set_handler(SIGSEGV, &quit_all);
260 	set_handler(SIGTERM, &quit_all);
261 
262 
263 	if (scan_for_context)
264 		ctx = scan();
265 	else if (arg_uri)
266 		ctx = iio_create_context_from_uri(arg_uri);
267 	else if (arg_ip)
268 		ctx = iio_create_network_context(arg_ip);
269 	else
270 		ctx = iio_create_default_context();
271 
272 	if (!ctx) {
273 		fprintf(stderr, "Unable to create IIO context\n");
274 		return EXIT_FAILURE;
275 	}
276 
277 	device_name = argv[optind];
278 
279 	dev = get_device(ctx, device_name);
280 	if (!dev) {
281 		iio_context_destroy(ctx);
282 		return EXIT_FAILURE;
283 	}
284 
285 	nb_channels = iio_device_get_channels_count(dev);
286 	for (i = 0; i < nb_channels; i++) {
287 		struct iio_channel *ch = iio_device_get_channel(dev, i);
288 		if (!iio_channel_is_scan_element(ch))
289 			continue;
290 		iio_channel_enable(ch);
291 		if (iio_channel_is_output(ch))
292 			n_tx++;
293 		else
294 			n_rx++;
295 	}
296 
297 	if (n_tx >= n_rx)
298 		device_is_tx = true;
299 	else
300 		device_is_tx = false;
301 
302 	printf("Monitoring %s for underflows/overflows\n",
303 		iio_device_get_name(dev));
304 
305 	buffer = iio_device_create_buffer(dev, buffer_size, false);
306 	if (!buffer) {
307 		fprintf(stderr, "Unable to allocate buffer\n");
308 		iio_context_destroy(ctx);
309 		return EXIT_FAILURE;
310 	}
311 
312 	xflow_pthread_data.ctx = ctx;
313 	xflow_pthread_data.device_name = device_name;
314 
315 	ret = pthread_create(&monitor_thread, NULL, monitor_thread_fn,
316 			     (void *)&xflow_pthread_data);
317 	if (ret) {
318 		fprintf(stderr, "Failed to create monitor thread: %s\n",
319 				strerror(-ret));
320 	}
321 
322 	while (app_running) {
323 		if (device_is_tx) {
324 			ret = iio_buffer_push(buffer);
325 			if (ret < 0) {
326 				fprintf(stderr, "Unable to push buffer: %s\n",
327 						strerror(-ret));
328 				app_running = false;
329 				break;
330 			}
331 		} else {
332 			ret = iio_buffer_refill(buffer);
333 			if (ret < 0) {
334 				fprintf(stderr, "Unable to refill buffer: %s\n",
335 						strerror(-ret));
336 				app_running = false;
337 				break;
338 			}
339 		}
340 	}
341 
342 	pthread_join(monitor_thread, NULL);
343 
344 	iio_buffer_destroy(buffer);
345 	iio_context_destroy(ctx);
346 
347 	return 0;
348 }
349