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