• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libiio - Dummy IIO streaming example
3  *
4  * This example libiio program is meant to exercise the features of IIO present
5  * in the sample dummy IIO device. For buffered access it relies on the hrtimer
6  * trigger but could be modified to use the sysfs trigger. No hardware should
7  * be required to run this program.
8  *
9  * Copyright (c) 2016, DAQRI. All rights reserved.
10  * Author: Lucas Magasweran <lucas.magasweran@daqri.com>
11  *
12  * Based on AD9361 example:
13  * Copyright (C) 2014 IABG mbH
14  * Author: Michael Feilen <feilen_at_iabg.de>
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * How to setup the sample IIO dummy device and hrtimer trigger:
27  *
28  * 1. Check if `configfs` is already mounted
29  *
30  * $ mount | grep 'config'
31  * configfs on /sys/kernel/config type configfs (rw,relatime)
32  *
33  * 1.b. Mount `configfs` if it is not already mounted
34  *  $ sudo mount -t configfs none /sys/kernel/config
35  *
36  * 2. Load modules one by one
37  *
38  * $ sudo modprobe industrialio
39  * $ sudo modprobe industrialio-configfs
40  * $ sudo modprobe industrialio-sw-device
41  * $ sudo modprobe industrialio-sw-trigger
42  * $ sudo modprobe iio-trig-hrtimer
43  * $ sudo modprobe iio_dummy
44  *
45  * 3. Create trigger and dummy device under `/sys/kernel/config`
46  *
47  * $ sudo mkdir /sys/kernel/config/iio/triggers/hrtimer/instance1
48  * $ sudo mkdir /sys/kernel/config/iio/devices/dummy/my_dummy_device
49  *
50  * 4. Run `iio_info` to see that all worked properly
51  *
52  * $ iio_info
53  * Library version: 0.14 (git tag: c9909f2)
54  * Compiled with backends: local xml ip
55  * IIO context created with local backend.
56  * Backend version: 0.14 (git tag: c9909f2)
57  * Backend description string: Linux ...
58  * IIO context has 1 attributes:
59  *         local,kernel: 4.13.0-39-generic
60  * IIO context has 2 devices:
61  *         iio:device0: my_dummy_device
62  *                 10 channels found:
63  *                         activity_walking:  (input)
64  *                         1 channel-specific attributes found:
65  *                                 attr  0: input value: 4
66  * ...
67  *
68  **/
69 
70 #include <stdbool.h>
71 #include <stdint.h>
72 #include <stdio.h>
73 #include <string.h>
74 #include <assert.h>
75 #include <signal.h>
76 #include <stdio.h>
77 #include <errno.h>
78 #include <getopt.h>
79 
80 #ifdef __APPLE__
81 #include <iio/iio.h>
82 #else
83 #include <iio.h>
84 #endif
85 
86 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
87 
88 static char *name        = "iio_dummy_part_no";
89 static char *trigger_str = "instance1";
90 static int buffer_length = 1;
91 static int count         = -1;
92 
93 // libiio supports multiple methods for reading data from a buffer
94 enum {
95 	BUFFER_POINTER,
96 	SAMPLE_CALLBACK,
97 	CHANNEL_READ_RAW,
98 	CHANNEL_READ,
99 	MAX_READ_METHOD,
100 };
101 static int buffer_read_method = BUFFER_POINTER;
102 
103 // Streaming devices
104 static struct iio_device *dev;
105 
106 /* IIO structs required for streaming */
107 static struct iio_context *ctx;
108 static struct iio_buffer  *rxbuf;
109 static struct iio_channel **channels;
110 static int channel_count;
111 
112 static bool stop;
113 static bool has_repeat;
114 
115 /* cleanup and exit */
shutdown()116 static void shutdown()
117 {
118 	if (channels) { free(channels); }
119 
120 	printf("* Destroying buffers\n");
121 	if (rxbuf) { iio_buffer_destroy(rxbuf); }
122 
123 	printf("* Disassociate trigger\n");
124 	if (dev) { iio_device_set_trigger(dev, NULL); }
125 
126 	printf("* Destroying context\n");
127 	if (ctx) { iio_context_destroy(ctx); }
128 	exit(0);
129 }
130 
handle_sig(int sig)131 static void handle_sig(int sig)
132 {
133 	printf("Waiting for process to finish...\n");
134 	stop = true;
135 }
136 
sample_cb(const struct iio_channel * chn,void * src,size_t bytes,void * d)137 static ssize_t sample_cb(const struct iio_channel *chn, void *src, size_t bytes, void *d)
138 {
139 	const struct iio_data_format *fmt = iio_channel_get_data_format(chn);
140 	unsigned int repeat = has_repeat ? fmt->repeat : 1;
141 
142 	printf("%s ", iio_channel_get_id(chn));
143 	for (int j = 0; j < repeat; ++j) {
144 		if (bytes == sizeof(int16_t))
145 			printf("%i ", ((int16_t *)src)[j]);
146 		else if (bytes == sizeof(int64_t))
147 			printf("%ld ", ((int64_t *)src)[j]);
148 	}
149 
150 	return bytes * repeat;
151 }
152 
usage(int argc,char * argv[])153 static void usage(int argc, char *argv[])
154 {
155 	printf("Usage: %s [OPTION]\n", argv[0]);
156 	printf("  -d\tdevice name (default \"iio_dummy_part_no\")\n");
157 	printf("  -t\ttrigger name (default \"instance1\")\n");
158 	printf("  -b\tbuffer length (default 1)\n");
159 	printf("  -r\tread method (default 0 pointer, 1 callback, 2 read, 3 read raw)\n");
160 	printf("  -c\tread count (default no limit)\n");
161 }
162 
parse_options(int argc,char * argv[])163 static void parse_options(int argc, char *argv[])
164 {
165 	int c;
166 
167 	while ((c = getopt(argc, argv, "d:t:b:r:c:h")) != -1) {
168 		switch (c)
169 		{
170 		case 'd':
171 			name = optarg;
172 			break;
173 		case 't':
174 			trigger_str = optarg;
175 			break;
176 		case 'b':
177 			buffer_length = atoi(optarg);
178 			break;
179 		case 'r':
180 			if (atoi(optarg) >= 0 && atoi(optarg) < MAX_READ_METHOD) {
181 				buffer_read_method = atoi(optarg);
182 			} else {
183 				usage(argc, argv);
184 				exit(1);
185 			}
186 			break;
187 		case 'c':
188 			if (atoi(optarg) > 0) {
189 				count = atoi(optarg);
190 			} else {
191 				usage(argc, argv);
192 				exit(1);
193 			}
194 			break;
195 		case 'h':
196 		default:
197 			usage(argc, argv);
198 			exit(1);
199 		}
200 	}
201 }
202 
203 /* simple configuration and streaming */
main(int argc,char ** argv)204 int main (int argc, char **argv)
205 {
206 	// Hardware trigger
207 	struct iio_device *trigger;
208 
209 	parse_options(argc, argv);
210 
211 	// Listen to ctrl+c and assert
212 	signal(SIGINT, handle_sig);
213 
214 	unsigned int major, minor;
215 	char git_tag[8];
216 	iio_library_get_version(&major, &minor, git_tag);
217 	printf("Library version: %u.%u (git tag: %s)\n", major, minor, git_tag);
218 
219 	/* check for struct iio_data_format.repeat support */
220 	has_repeat = major >= 0 && minor >= 8 ? true : false;
221 
222 	printf("* Acquiring IIO context\n");
223 	assert((ctx = iio_create_default_context()) && "No context");
224 	assert(iio_context_get_devices_count(ctx) > 0 && "No devices");
225 
226 	printf("* Acquiring device %s\n", name);
227 	dev = iio_context_find_device(ctx, name);
228 	if (!dev) {
229 		perror("No device found");
230 		shutdown();
231 	}
232 
233 	printf("* Initializing IIO streaming channels:\n");
234 	for (int i = 0; i < iio_device_get_channels_count(dev); ++i) {
235 		struct iio_channel *chn = iio_device_get_channel(dev, i);
236 		if (iio_channel_is_scan_element(chn)) {
237 			printf("%s\n", iio_channel_get_id(chn));
238 			channel_count++;
239 		}
240 	}
241 	if (channel_count == 0) {
242 		printf("No scan elements found (make sure the driver built with 'CONFIG_IIO_SIMPLE_DUMMY_BUFFER=y')\n");
243 		shutdown();
244 	}
245 	channels = calloc(channel_count, sizeof *channels);
246 	if (!channels) {
247 		perror("Channel array allocation failed");
248 		shutdown();
249 	}
250 	for (int i = 0; i < channel_count; ++i) {
251 		struct iio_channel *chn = iio_device_get_channel(dev, i);
252 		if (iio_channel_is_scan_element(chn))
253 			channels[i] = chn;
254 	}
255 
256 	printf("* Acquiring trigger %s\n", trigger_str);
257 	trigger = iio_context_find_device(ctx, trigger_str);
258 	if (!trigger || !iio_device_is_trigger(trigger)) {
259 		perror("No trigger found (try setting up the iio-trig-hrtimer module)");
260 		shutdown();
261 	}
262 
263 	printf("* Enabling IIO streaming channels for buffered capture\n");
264 	for (int i = 0; i < channel_count; ++i)
265 		iio_channel_enable(channels[i]);
266 
267 	printf("* Enabling IIO buffer trigger\n");
268 	if (iio_device_set_trigger(dev, trigger)) {
269 		perror("Could not set trigger\n");
270 		shutdown();
271 	}
272 
273 	printf("* Creating non-cyclic IIO buffers with %d samples\n", buffer_length);
274 	rxbuf = iio_device_create_buffer(dev, buffer_length, false);
275 	if (!rxbuf) {
276 		perror("Could not create buffer");
277 		shutdown();
278 	}
279 
280 	printf("* Starting IO streaming (press CTRL+C to cancel)\n");
281 	bool has_ts = strcmp(iio_channel_get_id(channels[channel_count-1]), "timestamp") == 0;
282 	int64_t last_ts = 0;
283 	while (!stop)
284 	{
285 		ssize_t nbytes_rx;
286 		void *p_dat, *p_end;
287 		ptrdiff_t p_inc;
288 		int64_t now_ts;
289 
290 		// Refill RX buffer
291 		nbytes_rx = iio_buffer_refill(rxbuf);
292 		if (nbytes_rx < 0) {
293 			printf("Error refilling buf: %d\n", (int)nbytes_rx);
294 			shutdown();
295 		}
296 
297 		p_inc = iio_buffer_step(rxbuf);
298 		p_end = iio_buffer_end(rxbuf);
299 
300 		// Print timestamp delta in ms
301 		if (has_ts)
302 			for (p_dat = iio_buffer_first(rxbuf, channels[channel_count-1]); p_dat < p_end; p_dat += p_inc) {
303 				now_ts = (((int64_t *)p_dat)[0]);
304 				printf("[%04ld] ", last_ts > 0 ? (now_ts - last_ts)/1000/1000 : 0);
305 				last_ts = now_ts;
306 			}
307 
308 		// Print each captured sample
309 		switch (buffer_read_method)
310 		{
311 		case BUFFER_POINTER:
312 			for (int i = 0; i < channel_count; ++i) {
313 				const struct iio_data_format *fmt = iio_channel_get_data_format(channels[i]);
314 				unsigned int repeat = has_repeat ? fmt->repeat : 1;
315 
316 				printf("%s ", iio_channel_get_id(channels[i]));
317 				for (p_dat = iio_buffer_first(rxbuf, channels[i]); p_dat < p_end; p_dat += p_inc) {
318 					for (int j = 0; j < repeat; ++j) {
319 						if (fmt->length/8 == sizeof(int16_t))
320 							printf("%i ", ((int16_t *)p_dat)[j]);
321 						else if (fmt->length/8 == sizeof(int64_t))
322 							printf("%ld ", ((int64_t *)p_dat)[j]);
323 					}
324 				}
325 			}
326 			printf("\n");
327 			break;
328 
329 		case SAMPLE_CALLBACK:
330 			iio_buffer_foreach_sample(rxbuf, sample_cb, NULL);
331 			printf("\n");
332 			break;
333 
334 		case CHANNEL_READ_RAW:
335 		case CHANNEL_READ:
336 			for (int i = 0; i < channel_count; ++i) {
337 				uint8_t *buf;
338 				size_t bytes;
339 				const struct iio_data_format *fmt = iio_channel_get_data_format(channels[i]);
340 				unsigned int repeat = has_repeat ? fmt->repeat : 1;
341 				size_t sample_size = fmt->length / 8 * repeat;
342 
343 				buf = malloc(sample_size * buffer_length);
344 
345 				if (buffer_read_method == CHANNEL_READ_RAW)
346 					bytes = iio_channel_read_raw(channels[i], rxbuf, buf, sample_size * buffer_length);
347 				else
348 					bytes = iio_channel_read(channels[i], rxbuf, buf, sample_size * buffer_length);
349 
350 				printf("%s ", iio_channel_get_id(channels[i]));
351 				for (int sample = 0; sample < bytes / sample_size; ++sample) {
352 					for (int j = 0; j < repeat; ++j) {
353 						if (fmt->length / 8 == sizeof(int16_t))
354 							printf("%i ", ((int16_t *)buf)[sample+j]);
355 						else if (fmt->length / 8 == sizeof(int64_t))
356 							printf("%li ", ((int64_t *)buf)[sample+j]);
357 					}
358 				}
359 
360 				free(buf);
361 			}
362 			printf("\n");
363 			break;
364 		}
365 
366 		if (count != -1 && --count == 0)
367 			break;
368 	}
369 
370 	shutdown();
371 
372 	return 0;
373 }
374 
375