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