1/* Industrialio buffer test code.
2 *
3 * Copyright (c) 2008 Jonathan Cameron
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is primarily intended as an example application.
10 * Reads the current buffer setup from sysfs and starts a short capture
11 * from the specified device, pretty printing the result after appropriate
12 * conversion.
13 *
14 * Command line parameters
15 * generic_buffer -n <device_name> -t <trigger_name>
16 * If trigger name is not specified the program assumes you want a dataready
17 * trigger associated with the device and goes looking for it.
18 *
19 */
20
21#include <unistd.h>
22#include <stdlib.h>
23#include <dirent.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <errno.h>
27#include <sys/stat.h>
28#include <sys/dir.h>
29#include <linux/types.h>
30#include <string.h>
31#include <poll.h>
32#include <endian.h>
33#include <getopt.h>
34#include <inttypes.h>
35#include "iio_utils.h"
36
37/**
38 * size_from_channelarray() - calculate the storage size of a scan
39 * @channels:		the channel info array
40 * @num_channels:	number of channels
41 *
42 * Has the side effect of filling the channels[i].location values used
43 * in processing the buffer output.
44 **/
45int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
46{
47	int bytes = 0;
48	int i = 0;
49
50	while (i < num_channels) {
51		if (bytes % channels[i].bytes == 0)
52			channels[i].location = bytes;
53		else
54			channels[i].location = bytes - bytes%channels[i].bytes
55				+ channels[i].bytes;
56		bytes = channels[i].location + channels[i].bytes;
57		i++;
58	}
59	return bytes;
60}
61
62void print2byte(int input, struct iio_channel_info *info)
63{
64	/* First swap if incorrect endian */
65	if (info->be)
66		input = be16toh((uint16_t)input);
67	else
68		input = le16toh((uint16_t)input);
69
70	/*
71	 * Shift before conversion to avoid sign extension
72	 * of left aligned data
73	 */
74	input >>= info->shift;
75	if (info->is_signed) {
76		int16_t val = input;
77
78		val &= (1 << info->bits_used) - 1;
79		val = (int16_t)(val << (16 - info->bits_used)) >>
80			(16 - info->bits_used);
81		printf("%05f ", ((float)val + info->offset)*info->scale);
82	} else {
83		uint16_t val = input;
84
85		val &= (1 << info->bits_used) - 1;
86		printf("%05f ", ((float)val + info->offset)*info->scale);
87	}
88}
89/**
90 * process_scan() - print out the values in SI units
91 * @data:		pointer to the start of the scan
92 * @channels:		information about the channels. Note
93 *  size_from_channelarray must have been called first to fill the
94 *  location offsets.
95 * @num_channels:	number of channels
96 **/
97void process_scan(char *data,
98		  struct iio_channel_info *channels,
99		  int num_channels)
100{
101	int k;
102
103	for (k = 0; k < num_channels; k++)
104		switch (channels[k].bytes) {
105			/* only a few cases implemented so far */
106		case 2:
107			print2byte(*(uint16_t *)(data + channels[k].location),
108				   &channels[k]);
109			break;
110		case 4:
111			if (!channels[k].is_signed) {
112				uint32_t val = *(uint32_t *)
113					(data + channels[k].location);
114				printf("%05f ", ((float)val +
115						 channels[k].offset)*
116				       channels[k].scale);
117
118			}
119			break;
120		case 8:
121			if (channels[k].is_signed) {
122				int64_t val = *(int64_t *)
123					(data +
124					 channels[k].location);
125				if ((val >> channels[k].bits_used) & 1)
126					val = (val & channels[k].mask) |
127						~channels[k].mask;
128				/* special case for timestamp */
129				if (channels[k].scale == 1.0f &&
130				    channels[k].offset == 0.0f)
131					printf("%" PRId64 " ", val);
132				else
133					printf("%05f ", ((float)val +
134							 channels[k].offset)*
135					       channels[k].scale);
136			}
137			break;
138		default:
139			break;
140		}
141	printf("\n");
142}
143
144int main(int argc, char **argv)
145{
146	unsigned long num_loops = 2;
147	unsigned long timedelay = 1000000;
148	unsigned long buf_len = 128;
149
150	int ret, c, i, j, toread;
151	int fp;
152
153	int num_channels;
154	char *trigger_name = NULL, *device_name = NULL;
155	char *dev_dir_name, *buf_dir_name;
156
157	int datardytrigger = 1;
158	char *data;
159	ssize_t read_size;
160	int dev_num, trig_num;
161	char *buffer_access;
162	int scan_size;
163	int noevents = 0;
164	int notrigger = 0;
165	char *dummy;
166
167	struct iio_channel_info *channels;
168
169	while ((c = getopt(argc, argv, "l:w:c:et:n:g")) != -1) {
170		switch (c) {
171		case 'n':
172			device_name = optarg;
173			break;
174		case 't':
175			trigger_name = optarg;
176			datardytrigger = 0;
177			break;
178		case 'e':
179			noevents = 1;
180			break;
181		case 'c':
182			num_loops = strtoul(optarg, &dummy, 10);
183			break;
184		case 'w':
185			timedelay = strtoul(optarg, &dummy, 10);
186			break;
187		case 'l':
188			buf_len = strtoul(optarg, &dummy, 10);
189			break;
190		case 'g':
191			notrigger = 1;
192			break;
193		case '?':
194			return -1;
195		}
196	}
197
198	if (device_name == NULL)
199		return -1;
200
201	/* Find the device requested */
202	dev_num = find_type_by_name(device_name, "iio:device");
203	if (dev_num < 0) {
204		printf("Failed to find the %s\n", device_name);
205		ret = -ENODEV;
206		goto error_ret;
207	}
208	printf("iio device number being used is %d\n", dev_num);
209
210	asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
211
212	if (!notrigger) {
213		if (trigger_name == NULL) {
214			/*
215			 * Build the trigger name. If it is device associated
216			 * its name is <device_name>_dev[n] where n matches
217			 * the device number found above.
218			 */
219			ret = asprintf(&trigger_name,
220				       "%s-dev%d", device_name, dev_num);
221			if (ret < 0) {
222				ret = -ENOMEM;
223				goto error_ret;
224			}
225		}
226
227		/* Verify the trigger exists */
228		trig_num = find_type_by_name(trigger_name, "trigger");
229		if (trig_num < 0) {
230			printf("Failed to find the trigger %s\n", trigger_name);
231			ret = -ENODEV;
232			goto error_free_triggername;
233		}
234		printf("iio trigger number being used is %d\n", trig_num);
235	} else
236		printf("trigger-less mode selected\n");
237
238	/*
239	 * Parse the files in scan_elements to identify what channels are
240	 * present
241	 */
242	ret = build_channel_array(dev_dir_name, &channels, &num_channels);
243	if (ret) {
244		printf("Problem reading scan element information\n");
245		printf("diag %s\n", dev_dir_name);
246		goto error_free_triggername;
247	}
248
249	/*
250	 * Construct the directory name for the associated buffer.
251	 * As we know that the lis3l02dq has only one buffer this may
252	 * be built rather than found.
253	 */
254	ret = asprintf(&buf_dir_name,
255		       "%siio:device%d/buffer", iio_dir, dev_num);
256	if (ret < 0) {
257		ret = -ENOMEM;
258		goto error_free_triggername;
259	}
260
261	if (!notrigger) {
262		printf("%s %s\n", dev_dir_name, trigger_name);
263		/* Set the device trigger to be the data ready trigger found
264		 * above */
265		ret = write_sysfs_string_and_verify("trigger/current_trigger",
266						    dev_dir_name,
267						    trigger_name);
268		if (ret < 0) {
269			printf("Failed to write current_trigger file\n");
270			goto error_free_buf_dir_name;
271		}
272	}
273
274	/* Setup ring buffer parameters */
275	ret = write_sysfs_int("length", buf_dir_name, buf_len);
276	if (ret < 0)
277		goto error_free_buf_dir_name;
278
279	/* Enable the buffer */
280	ret = write_sysfs_int("enable", buf_dir_name, 1);
281	if (ret < 0)
282		goto error_free_buf_dir_name;
283	scan_size = size_from_channelarray(channels, num_channels);
284	data = malloc(scan_size*buf_len);
285	if (!data) {
286		ret = -ENOMEM;
287		goto error_free_buf_dir_name;
288	}
289
290	ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num);
291	if (ret < 0) {
292		ret = -ENOMEM;
293		goto error_free_data;
294	}
295
296	/* Attempt to open non blocking the access dev */
297	fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
298	if (fp == -1) { /* If it isn't there make the node */
299		printf("Failed to open %s\n", buffer_access);
300		ret = -errno;
301		goto error_free_buffer_access;
302	}
303
304	/* Wait for events 10 times */
305	for (j = 0; j < num_loops; j++) {
306		if (!noevents) {
307			struct pollfd pfd = {
308				.fd = fp,
309				.events = POLLIN,
310			};
311
312			poll(&pfd, 1, -1);
313			toread = buf_len;
314
315		} else {
316			usleep(timedelay);
317			toread = 64;
318		}
319
320		read_size = read(fp,
321				 data,
322				 toread*scan_size);
323		if (read_size < 0) {
324			if (errno == -EAGAIN) {
325				printf("nothing available\n");
326				continue;
327			} else
328				break;
329		}
330		for (i = 0; i < read_size/scan_size; i++)
331			process_scan(data + scan_size*i,
332				     channels,
333				     num_channels);
334	}
335
336	/* Stop the buffer */
337	ret = write_sysfs_int("enable", buf_dir_name, 0);
338	if (ret < 0)
339		goto error_close_buffer_access;
340
341	if (!notrigger)
342		/* Disconnect the trigger - just write a dummy name. */
343		write_sysfs_string("trigger/current_trigger",
344				   dev_dir_name, "NULL");
345
346error_close_buffer_access:
347	close(fp);
348error_free_data:
349	free(data);
350error_free_buffer_access:
351	free(buffer_access);
352error_free_buf_dir_name:
353	free(buf_dir_name);
354error_free_triggername:
355	if (datardytrigger)
356		free(trigger_name);
357error_ret:
358	return ret;
359}
360