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