• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libiio - Library for interfacing industrial I/O (IIO) devices
3  *
4  * Copyright (C) 2014 Analog Devices, Inc.
5  * Author: Paul Cercueil <paul.cercueil@analog.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * */
18 
19 #include <errno.h>
20 #include <getopt.h>
21 #include <iio.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26 
27 #define MY_NAME "iio_readdev"
28 
29 #define SAMPLES_PER_READ 256
30 #define DEFAULT_FREQ_HZ  100
31 
32 static const struct option options[] = {
33 	  {"help", no_argument, 0, 'h'},
34 	  {"network", required_argument, 0, 'n'},
35 	  {"uri", required_argument, 0, 'u'},
36 	  {"trigger", required_argument, 0, 't'},
37 	  {"buffer-size", required_argument, 0, 'b'},
38 	  {"samples", required_argument, 0, 's' },
39 	  {"timeout", required_argument, 0, 'T'},
40 	  {"auto", no_argument, 0, 'a'},
41 	  {0, 0, 0, 0},
42 };
43 
44 static const char *options_descriptions[] = {
45 	"Show this help and quit.",
46 	"Use the network backend with the provided hostname.",
47 	"Use the context with the provided URI.",
48 	"Use the specified trigger.",
49 	"Size of the capture buffer. Default is 256.",
50 	"Number of samples to capture, 0 = infinite. Default is 0.",
51 	"Buffer timeout in milliseconds. 0 = no timeout",
52 	"Scan for available contexts and if only one is available use it.",
53 };
54 
usage(void)55 static void usage(void)
56 {
57 	unsigned int i;
58 
59 	printf("Usage:\n\t" MY_NAME " [-n <hostname>] [-t <trigger>] "
60 			"[-T <timeout-ms>] [-b <buffer-size>] [-s <samples>] "
61 			"<iio_device> [<channel> ...]\n\nOptions:\n");
62 	for (i = 0; options[i].name; i++)
63 		printf("\t-%c, --%s\n\t\t\t%s\n",
64 					options[i].val, options[i].name,
65 					options_descriptions[i]);
66 }
67 
68 static struct iio_context *ctx;
69 static struct iio_buffer *buffer;
70 static const char *trigger_name = NULL;
71 static size_t num_samples;
72 
73 static volatile sig_atomic_t app_running = true;
74 static int exit_code = EXIT_SUCCESS;
75 
quit_all(int sig)76 static void quit_all(int sig)
77 {
78 	exit_code = sig;
79 	app_running = false;
80 	if (buffer)
81 		iio_buffer_cancel(buffer);
82 }
83 
84 #ifdef _WIN32
85 
86 #include <windows.h>
87 
sig_handler_fn(DWORD dwCtrlType)88 BOOL WINAPI sig_handler_fn(DWORD dwCtrlType)
89 {
90 	/* Runs in its own thread */
91 
92 	switch (dwCtrlType) {
93 	case CTRL_C_EVENT:
94 	case CTRL_CLOSE_EVENT:
95 		quit_all(SIGTERM);
96 		return TRUE;
97 	default:
98 		return FALSE;
99 	}
100 }
101 
setup_sig_handler(void)102 static void setup_sig_handler(void)
103 {
104 	SetConsoleCtrlHandler(sig_handler_fn, TRUE);
105 }
106 
107 #elif NO_THREADS
108 
sig_handler(int sig)109 static void sig_handler(int sig)
110 {
111 	/*
112 	 * If the main function is stuck waiting for data it will not abort. If the
113 	 * user presses Ctrl+C a second time we abort without cleaning up.
114 	 */
115 	if (!app_running)
116 		exit(sig);
117 	app_running = false;
118 }
119 
set_handler(int sig)120 static void set_handler(int sig)
121 {
122 	struct sigaction action;
123 
124 	sigaction(sig, NULL, &action);
125 	action.sa_handler = sig_handler;
126 	sigaction(sig, &action, NULL);
127 }
128 
setup_sig_handler(void)129 static void setup_sig_handler(void)
130 {
131 	set_handler(SIGHUP);
132 	set_handler(SIGPIPE);
133 	set_handler(SIGINT);
134 	set_handler(SIGSEGV);
135 	set_handler(SIGTERM);
136 }
137 
138 #else
139 
140 #include <pthread.h>
141 
sig_handler_thd(void * data)142 static void * sig_handler_thd(void *data)
143 {
144 	sigset_t *mask = data;
145 	int ret, sig;
146 
147 	/* Blocks until one of the termination signals is received */
148 	do {
149 		ret = sigwait(mask, &sig);
150 	} while (ret == EINTR);
151 
152 	quit_all(ret);
153 
154 	return NULL;
155 }
156 
setup_sig_handler(void)157 static void setup_sig_handler(void)
158 {
159 	sigset_t mask, oldmask;
160 	pthread_t thd;
161 	int ret;
162 
163 	/*
164 	 * Async signals are difficult to handle and the IIO API is not signal
165 	 * safe. Use a seperate thread and handle the signals synchronous so we
166 	 * can call iio_buffer_cancel().
167 	 */
168 
169 	sigemptyset(&mask);
170 	sigaddset(&mask, SIGHUP);
171 	sigaddset(&mask, SIGPIPE);
172 	sigaddset(&mask, SIGINT);
173 	sigaddset(&mask, SIGSEGV);
174 	sigaddset(&mask, SIGTERM);
175 
176 	pthread_sigmask(SIG_BLOCK, &mask, &oldmask);
177 
178 	ret = pthread_create(&thd, NULL, sig_handler_thd, &mask);
179 	if (ret) {
180 		fprintf(stderr, "Failed to create signal handler thread: %d\n", ret);
181 		pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
182 	}
183 }
184 
185 #endif
186 
print_sample(const struct iio_channel * chn,void * buf,size_t len,void * d)187 static ssize_t print_sample(const struct iio_channel *chn,
188 		void *buf, size_t len, void *d)
189 {
190 	fwrite(buf, 1, len, stdout);
191 	if (num_samples != 0) {
192 		num_samples--;
193 		if (num_samples == 0) {
194 			quit_all(EXIT_SUCCESS);
195 			return -1;
196 		}
197 	}
198 	return (ssize_t) len;
199 }
200 
scan(void)201 static struct iio_context *scan(void)
202 {
203 	struct iio_scan_context *scan_ctx;
204 	struct iio_context_info **info;
205 	struct iio_context *ctx = NULL;
206 	unsigned int i;
207 	ssize_t ret;
208 
209 	scan_ctx = iio_create_scan_context(NULL, 0);
210 	if (!scan_ctx) {
211 		fprintf(stderr, "Unable to create scan context\n");
212 		return NULL;
213 	}
214 
215 	ret = iio_scan_context_get_info_list(scan_ctx, &info);
216 	if (ret < 0) {
217 		char err_str[1024];
218 		iio_strerror(-ret, err_str, sizeof(err_str));
219 		fprintf(stderr, "Scanning for IIO contexts failed: %s\n", err_str);
220 		goto err_free_ctx;
221 	}
222 
223 	if (ret == 0) {
224 		printf("No IIO context found.\n");
225 		goto err_free_info_list;
226 	}
227 
228 	if (ret == 1) {
229 		ctx = iio_create_context_from_uri(iio_context_info_get_uri(info[0]));
230 	} else {
231 		fprintf(stderr, "Multiple contexts found. Please select one using --uri:\n");
232 
233 		for (i = 0; i < (size_t) ret; i++) {
234 			fprintf(stderr, "\t%d: %s [%s]\n", i,
235 				iio_context_info_get_description(info[i]),
236 				iio_context_info_get_uri(info[i]));
237 		}
238 	}
239 
240 err_free_info_list:
241 	iio_context_info_list_free(info);
242 err_free_ctx:
243 	iio_scan_context_destroy(scan_ctx);
244 
245 	return ctx;
246 }
247 
main(int argc,char ** argv)248 int main(int argc, char **argv)
249 {
250 	unsigned int i, nb_channels;
251 	unsigned int buffer_size = SAMPLES_PER_READ;
252 	const char *arg_uri = NULL;
253 	const char *arg_ip = NULL;
254 	int c, option_index = 0;
255 	struct iio_device *dev;
256 	size_t sample_size;
257 	int timeout = -1;
258 	bool scan_for_context = false;
259 
260 	while ((c = getopt_long(argc, argv, "+hn:u:t:b:s:T:a",
261 					options, &option_index)) != -1) {
262 		switch (c) {
263 		case 'h':
264 			usage();
265 			return EXIT_SUCCESS;
266 		case 'n':
267 			arg_ip = optarg;
268 			break;
269 		case 'u':
270 			arg_uri = optarg;
271 			break;
272 		case 'a':
273 			scan_for_context = true;
274 			break;
275 		case 't':
276 			trigger_name = optarg;
277 			break;
278 		case 'b':
279 			buffer_size = atoi(optarg);
280 			break;
281 		case 's':
282 			num_samples = atoi(optarg);
283 			break;
284 		case 'T':
285 			timeout = atoi(optarg);
286 			break;
287 		case '?':
288 			return EXIT_FAILURE;
289 		}
290 	}
291 
292 	if (argc == optind) {
293 		fprintf(stderr, "Incorrect number of arguments.\n\n");
294 		usage();
295 		return EXIT_FAILURE;
296 	}
297 
298 	setup_sig_handler();
299 
300 	if (scan_for_context)
301 		ctx = scan();
302 	else if (arg_uri)
303 		ctx = iio_create_context_from_uri(arg_uri);
304 	else if (arg_ip)
305 		ctx = iio_create_network_context(arg_ip);
306 	else
307 		ctx = iio_create_default_context();
308 
309 	if (!ctx) {
310 		fprintf(stderr, "Unable to create IIO context\n");
311 		return EXIT_FAILURE;
312 	}
313 
314 	if (timeout >= 0)
315 		iio_context_set_timeout(ctx, timeout);
316 
317 	dev = iio_context_find_device(ctx, argv[optind]);
318 	if (!dev) {
319 		fprintf(stderr, "Device %s not found\n", argv[optind]);
320 		iio_context_destroy(ctx);
321 		return EXIT_FAILURE;
322 	}
323 
324 	if (trigger_name) {
325 		struct iio_device *trigger = iio_context_find_device(
326 				ctx, trigger_name);
327 		if (!trigger) {
328 			fprintf(stderr, "Trigger %s not found\n", trigger_name);
329 			iio_context_destroy(ctx);
330 			return EXIT_FAILURE;
331 		}
332 
333 		if (!iio_device_is_trigger(trigger)) {
334 			fprintf(stderr, "Specified device is not a trigger\n");
335 			iio_context_destroy(ctx);
336 			return EXIT_FAILURE;
337 		}
338 
339 		/*
340 		 * Fixed rate for now. Try new ABI first,
341 		 * fail gracefully to remain compatible.
342 		 */
343 		if (iio_device_attr_write_longlong(trigger,
344 				"sampling_frequency", DEFAULT_FREQ_HZ) < 0)
345 			iio_device_attr_write_longlong(trigger,
346 				"frequency", DEFAULT_FREQ_HZ);
347 
348 		iio_device_set_trigger(dev, trigger);
349 	}
350 
351 	nb_channels = iio_device_get_channels_count(dev);
352 
353 	if (argc == optind + 1) {
354 		/* Enable all channels */
355 		for (i = 0; i < nb_channels; i++)
356 			iio_channel_enable(iio_device_get_channel(dev, i));
357 	} else {
358 		for (i = 0; i < nb_channels; i++) {
359 			unsigned int j;
360 			struct iio_channel *ch = iio_device_get_channel(dev, i);
361 			for (j = optind + 1; j < (unsigned int) argc; j++) {
362 				const char *n = iio_channel_get_name(ch);
363 				if (!strcmp(argv[j], iio_channel_get_id(ch)) ||
364 						(n && !strcmp(n, argv[j])))
365 					iio_channel_enable(ch);
366 			}
367 		}
368 	}
369 
370 	sample_size = iio_device_get_sample_size(dev);
371 
372 	buffer = iio_device_create_buffer(dev, buffer_size, false);
373 	if (!buffer) {
374 		char buf[256];
375 		iio_strerror(errno, buf, sizeof(buf));
376 		fprintf(stderr, "Unable to allocate buffer: %s\n", buf);
377 		iio_context_destroy(ctx);
378 		return EXIT_FAILURE;
379 	}
380 
381 	while (app_running) {
382 		int ret = iio_buffer_refill(buffer);
383 		if (ret < 0) {
384 			if (app_running) {
385 				char buf[256];
386 				iio_strerror(-ret, buf, sizeof(buf));
387 				fprintf(stderr, "Unable to refill buffer: %s\n", buf);
388 			}
389 			break;
390 		}
391 
392 		/* If there are only the samples we requested, we don't need to
393 		 * demux */
394 		if (iio_buffer_step(buffer) == sample_size) {
395 			void *start = iio_buffer_start(buffer);
396 			size_t read_len, len = (intptr_t) iio_buffer_end(buffer)
397 				- (intptr_t) start;
398 
399 			if (num_samples && len > num_samples * sample_size)
400 				len = num_samples * sample_size;
401 
402 			for (read_len = len; len; ) {
403 				size_t nb = fwrite(start, 1, len, stdout);
404 				if (!nb)
405 					goto err_destroy_buffer;
406 
407 				len -= nb;
408 				start = (void *)((intptr_t) start + nb);
409 			}
410 
411 			if (num_samples) {
412 				num_samples -= read_len / sample_size;
413 				if (!num_samples)
414 					quit_all(EXIT_SUCCESS);
415 			}
416 		} else {
417 			iio_buffer_foreach_sample(buffer, print_sample, NULL);
418 		}
419 	}
420 
421 err_destroy_buffer:
422 	iio_buffer_destroy(buffer);
423 	iio_context_destroy(ctx);
424 	return exit_code;
425 }
426