iio_generic_buffer.c 16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* Industrialio buffer test code.
 *
 * Copyright (c) 2008 Jonathan Cameron
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is primarily intended as an example application.
 * Reads the current buffer setup from sysfs and starts a short capture
 * from the specified device, pretty printing the result after appropriate
 * conversion.
 *
 * Command line parameters
 * generic_buffer -n <device_name> -t <trigger_name>
 * If trigger name is not specified the program assumes you want a dataready
 * trigger associated with the device and goes looking for it.
 *
 */

#include <unistd.h>
22
#include <stdlib.h>
23 24 25 26 27 28 29
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/dir.h>
#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 36
#include <stdbool.h>
#include <signal.h>
37 38
#include "iio_utils.h"

39 40 41 42 43 44 45 46 47
/**
 * enum autochan - state for the automatic channel enabling mechanism
 */
enum autochan {
	AUTOCHANNELS_DISABLED,
	AUTOCHANNELS_ENABLED,
	AUTOCHANNELS_ACTIVE,
};

48 49
/**
 * size_from_channelarray() - calculate the storage size of a scan
50 51
 * @channels:		the channel info array
 * @num_channels:	number of channels
52 53 54 55 56 57 58 59
 *
 * Has the side effect of filling the channels[i].location values used
 * in processing the buffer output.
 **/
int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
{
	int bytes = 0;
	int i = 0;
60

61 62 63 64
	while (i < num_channels) {
		if (bytes % channels[i].bytes == 0)
			channels[i].location = bytes;
		else
65 66 67
			channels[i].location = bytes - bytes % channels[i].bytes
					       + channels[i].bytes;

68 69 70
		bytes = channels[i].location + channels[i].bytes;
		i++;
	}
71

72 73 74
	return bytes;
}

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
void print1byte(uint8_t input, struct iio_channel_info *info)
{
	/*
	 * Shift before conversion to avoid sign extension
	 * of left aligned data
	 */
	input >>= info->shift;
	input &= info->mask;
	if (info->is_signed) {
		int8_t val = (int8_t)(input << (8 - info->bits_used)) >>
			     (8 - info->bits_used);
		printf("%05f ", ((float)val + info->offset) * info->scale);
	} else {
		printf("%05f ", ((float)input + info->offset) * info->scale);
	}
}

92
void print2byte(uint16_t input, struct iio_channel_info *info)
93
{
94 95
	/* First swap if incorrect endian */
	if (info->be)
96
		input = be16toh(input);
97
	else
98
		input = le16toh(input);
99

100 101 102 103
	/*
	 * Shift before conversion to avoid sign extension
	 * of left aligned data
	 */
104
	input >>= info->shift;
105
	input &= info->mask;
106
	if (info->is_signed) {
107 108 109 110 111 112 113
		int16_t val = (int16_t)(input << (16 - info->bits_used)) >>
			      (16 - info->bits_used);
		printf("%05f ", ((float)val + info->offset) * info->scale);
	} else {
		printf("%05f ", ((float)input + info->offset) * info->scale);
	}
}
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
void print4byte(uint32_t input, struct iio_channel_info *info)
{
	/* First swap if incorrect endian */
	if (info->be)
		input = be32toh(input);
	else
		input = le32toh(input);

	/*
	 * Shift before conversion to avoid sign extension
	 * of left aligned data
	 */
	input >>= info->shift;
	input &= info->mask;
	if (info->is_signed) {
		int32_t val = (int32_t)(input << (32 - info->bits_used)) >>
			      (32 - info->bits_used);
		printf("%05f ", ((float)val + info->offset) * info->scale);
133
	} else {
134 135 136
		printf("%05f ", ((float)input + info->offset) * info->scale);
	}
}
137

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
void print8byte(uint64_t input, struct iio_channel_info *info)
{
	/* First swap if incorrect endian */
	if (info->be)
		input = be64toh(input);
	else
		input = le64toh(input);

	/*
	 * Shift before conversion to avoid sign extension
	 * of left aligned data
	 */
	input >>= info->shift;
	input &= info->mask;
	if (info->is_signed) {
		int64_t val = (int64_t)(input << (64 - info->bits_used)) >>
			      (64 - info->bits_used);
		/* special case for timestamp */
		if (info->scale == 1.0f && info->offset == 0.0f)
			printf("%" PRId64 " ", val);
		else
			printf("%05f ",
			       ((float)val + info->offset) * info->scale);
	} else {
		printf("%05f ", ((float)input + info->offset) * info->scale);
163 164
	}
}
165

166 167 168
/**
 * process_scan() - print out the values in SI units
 * @data:		pointer to the start of the scan
169 170 171
 * @channels:		information about the channels.
 *			Note: size_from_channelarray must have been called first
 *			      to fill the location offsets.
172
 * @num_channels:	number of channels
173 174
 **/
void process_scan(char *data,
175
		  struct iio_channel_info *channels,
176 177 178
		  int num_channels)
{
	int k;
179

180
	for (k = 0; k < num_channels; k++)
181
		switch (channels[k].bytes) {
182
			/* only a few cases implemented so far */
183 184 185 186
		case 1:
			print1byte(*(uint8_t *)(data + channels[k].location),
				   &channels[k]);
			break;
187
		case 2:
188 189
			print2byte(*(uint16_t *)(data + channels[k].location),
				   &channels[k]);
190
			break;
191
		case 4:
192 193
			print4byte(*(uint32_t *)(data + channels[k].location),
				   &channels[k]);
194
			break;
195
		case 8:
196 197
			print8byte(*(uint64_t *)(data + channels[k].location),
				   &channels[k]);
198 199 200 201 202 203 204
			break;
		default:
			break;
		}
	printf("\n");
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
static int enable_disable_all_channels(char *dev_dir_name, int enable)
{
	const struct dirent *ent;
	char scanelemdir[256];
	DIR *dp;
	int ret;

	snprintf(scanelemdir, sizeof(scanelemdir),
		 FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name);
	scanelemdir[sizeof(scanelemdir)-1] = '\0';

	dp = opendir(scanelemdir);
	if (!dp) {
		fprintf(stderr, "Enabling/disabling channels: can't open %s\n",
			scanelemdir);
		return -EIO;
	}

	ret = -ENOENT;
	while (ent = readdir(dp), ent) {
		if (iioutils_check_suffix(ent->d_name, "_en")) {
			printf("%sabling: %s\n",
			       enable ? "En" : "Dis",
			       ent->d_name);
			ret = write_sysfs_int(ent->d_name, scanelemdir,
					      enable);
			if (ret < 0)
				fprintf(stderr, "Failed to enable/disable %s\n",
					ent->d_name);
		}
	}

	if (closedir(dp) == -1) {
		perror("Enabling/disabling channels: "
		       "Failed to close directory");
		return -errno;
	}
	return 0;
}

245 246
void print_usage(void)
{
247 248
	fprintf(stderr, "Usage: generic_buffer [options]...\n"
		"Capture, convert and output data from IIO device buffer\n"
249
		"  -a         Auto-activate all available channels\n"
250 251 252 253
		"  -c <n>     Do n conversions\n"
		"  -e         Disable wait for event (new data)\n"
		"  -g         Use trigger-less mode\n"
		"  -l <n>     Set buffer length to n samples\n"
254 255 256
		"  --device-name -n <name>\n"
		"  --device-num -N <num>\n"
		"        Set device by name or number (mandatory)\n"
257 258 259
		"  --trigger-name -t <name>\n"
		"  --trigger-num -T <num>\n"
		"        Set trigger by name or number\n"
260
		"  -w <n>     Set delay between reads in us (event-less mode)\n");
261 262
}

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
enum autochan autochannels = AUTOCHANNELS_DISABLED;
char *dev_dir_name = NULL;
char *buf_dir_name = NULL;
bool current_trigger_set = false;

void cleanup(void)
{
	int ret;

	/* Disable trigger */
	if (dev_dir_name && current_trigger_set) {
		/* Disconnect the trigger - just write a dummy name. */
		ret = write_sysfs_string("trigger/current_trigger",
					 dev_dir_name, "NULL");
		if (ret < 0)
			fprintf(stderr, "Failed to disable trigger: %s\n",
				strerror(-ret));
		current_trigger_set = false;
	}

	/* Disable buffer */
	if (buf_dir_name) {
		ret = write_sysfs_int("enable", buf_dir_name, 0);
		if (ret < 0)
			fprintf(stderr, "Failed to disable buffer: %s\n",
				strerror(-ret));
	}

	/* Disable channels if auto-enabled */
	if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) {
		ret = enable_disable_all_channels(dev_dir_name, 0);
		if (ret)
			fprintf(stderr, "Failed to disable all channels\n");
		autochannels = AUTOCHANNELS_DISABLED;
	}
}

void sig_handler(int signum)
{
	fprintf(stderr, "Caught signal %d\n", signum);
	cleanup();
	exit(-signum);
}

void register_cleanup(void)
{
	struct sigaction sa = { .sa_handler = sig_handler };
	const int signums[] = { SIGINT, SIGTERM, SIGABRT };
	int ret, i;

	for (i = 0; i < ARRAY_SIZE(signums); ++i) {
		ret = sigaction(signums[i], &sa, NULL);
		if (ret) {
			perror("Failed to register signal handler");
			exit(-1);
		}
	}
}

322 323 324
static const struct option longopts[] = {
	{ "device-name",	1, 0, 'n' },
	{ "device-num",		1, 0, 'N' },
325 326
	{ "trigger-name",	1, 0, 't' },
	{ "trigger-num",	1, 0, 'T' },
327 328 329
	{ },
};

330 331
int main(int argc, char **argv)
{
332 333 334 335
	unsigned long num_loops = 2;
	unsigned long timedelay = 1000000;
	unsigned long buf_len = 128;

336
	int ret, c, i, j, toread;
337
	int fp = -1;
338

339
	int num_channels = 0;
340 341
	char *trigger_name = NULL, *device_name = NULL;

342
	char *data = NULL;
343
	ssize_t read_size;
344
	int dev_num = -1, trig_num = -1;
345
	char *buffer_access = NULL;
346
	int scan_size;
347
	int noevents = 0;
348
	int notrigger = 0;
349
	char *dummy;
350

351
	struct iio_channel_info *channels = NULL;
352

353 354
	register_cleanup();

355
	while ((c = getopt_long(argc, argv, "ac:egl:n:N:t:T:w:", longopts, NULL)) != -1) {
356
		switch (c) {
357 358 359
		case 'a':
			autochannels = AUTOCHANNELS_ENABLED;
			break;
360
		case 'c':
361
			errno = 0;
362
			num_loops = strtoul(optarg, &dummy, 10);
363 364 365 366
			if (errno) {
				ret = -errno;
				goto error;
			}
367

368
			break;
369 370 371 372 373
		case 'e':
			noevents = 1;
			break;
		case 'g':
			notrigger = 1;
374 375
			break;
		case 'l':
376
			errno = 0;
377
			buf_len = strtoul(optarg, &dummy, 10);
378 379 380 381
			if (errno) {
				ret = -errno;
				goto error;
			}
382

383
			break;
384
		case 'n':
385 386 387 388 389 390 391 392 393
			device_name = strdup(optarg);
			break;
		case 'N':
			errno = 0;
			dev_num = strtoul(optarg, &dummy, 10);
			if (errno) {
				ret = -errno;
				goto error;
			}
394 395
			break;
		case 't':
396
			trigger_name = strdup(optarg);
397
			break;
398 399 400 401 402 403
		case 'T':
			errno = 0;
			trig_num = strtoul(optarg, &dummy, 10);
			if (errno)
				return -errno;
			break;
404 405 406
		case 'w':
			errno = 0;
			timedelay = strtoul(optarg, &dummy, 10);
407 408 409 410
			if (errno) {
				ret = -errno;
				goto error;
			}
411
			break;
412
		case '?':
413
			print_usage();
414 415
			ret = -1;
			goto error;
416 417 418 419
		}
	}

	/* Find the device requested */
420 421 422 423 424 425 426 427 428
	if (dev_num < 0 && !device_name) {
		fprintf(stderr, "Device not set\n");
		print_usage();
		ret = -1;
		goto error;
	} else if (dev_num >= 0 && device_name) {
		fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n");
		print_usage();
		ret = -1;
429
		goto error;
430 431 432 433 434 435 436
	} else if (dev_num < 0) {
		dev_num = find_type_by_name(device_name, "iio:device");
		if (dev_num < 0) {
			fprintf(stderr, "Failed to find the %s\n", device_name);
			ret = dev_num;
			goto error;
		}
437 438 439
	}
	printf("iio device number being used is %d\n", dev_num);

440
	ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
441 442 443 444 445 446 447 448 449 450 451 452 453 454
	if (ret < 0)
		return -ENOMEM;
	/* Fetch device_name if specified by number */
	if (!device_name) {
		device_name = malloc(IIO_MAX_NAME_LENGTH);
		if (!device_name) {
			ret = -ENOMEM;
			goto error;
		}
		ret = read_sysfs_string("name", dev_dir_name, device_name);
		if (ret < 0) {
			fprintf(stderr, "Failed to read name of device %d\n", dev_num);
			goto error;
		}
455
	}
456

457 458
	if (notrigger) {
		printf("trigger-less mode selected\n");
459
	} else if (trig_num >= 0) {
460 461 462 463 464 465 466 467 468 469 470 471 472 473
		char *trig_dev_name;
		ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num);
		if (ret < 0) {
			return -ENOMEM;
		}
		trigger_name = malloc(IIO_MAX_NAME_LENGTH);
		ret = read_sysfs_string("name", trig_dev_name, trigger_name);
		free(trig_dev_name);
		if (ret < 0) {
			fprintf(stderr, "Failed to read trigger%d name from\n", trig_num);
			return ret;
		}
		printf("iio trigger number being used is %d\n", trig_num);
	} else {
474
		if (!trigger_name) {
475 476 477 478 479 480 481 482 483
			/*
			 * Build the trigger name. If it is device associated
			 * its name is <device_name>_dev[n] where n matches
			 * the device number found above.
			 */
			ret = asprintf(&trigger_name,
				       "%s-dev%d", device_name, dev_num);
			if (ret < 0) {
				ret = -ENOMEM;
484
				goto error;
485
			}
486 487
		}

488 489 490 491 492 493 494 495 496
		/* Look for this "-devN" trigger */
		trig_num = find_type_by_name(trigger_name, "trigger");
		if (trig_num < 0) {
			/* OK try the simpler "-trigger" suffix instead */
			free(trigger_name);
			ret = asprintf(&trigger_name,
				       "%s-trigger", device_name);
			if (ret < 0) {
				ret = -ENOMEM;
497
				goto error;
498 499 500
			}
		}

501 502
		trig_num = find_type_by_name(trigger_name, "trigger");
		if (trig_num < 0) {
503 504
			fprintf(stderr, "Failed to find the trigger %s\n",
				trigger_name);
505
			ret = trig_num;
506
			goto error;
507
		}
508

509
		printf("iio trigger number being used is %d\n", trig_num);
510
	}
511 512 513 514 515

	/*
	 * Parse the files in scan_elements to identify what channels are
	 * present
	 */
516
	ret = build_channel_array(dev_dir_name, &channels, &num_channels);
517
	if (ret) {
518 519
		fprintf(stderr, "Problem reading scan element information\n"
			"diag %s\n", dev_dir_name);
520
		goto error;
521
	}
522 523 524 525 526 527 528 529 530 531 532 533 534
	if (num_channels && autochannels == AUTOCHANNELS_ENABLED) {
		fprintf(stderr, "Auto-channels selected but some channels "
			"are already activated in sysfs\n");
		fprintf(stderr, "Proceeding without activating any channels\n");
	}

	if (!num_channels && autochannels == AUTOCHANNELS_ENABLED) {
		fprintf(stderr,
			"No channels are enabled, enabling all channels\n");

		ret = enable_disable_all_channels(dev_dir_name, 1);
		if (ret) {
			fprintf(stderr, "Failed to enable all channels\n");
535
			goto error;
536 537 538 539 540 541 542 543 544 545 546
		}

		/* This flags that we need to disable the channels again */
		autochannels = AUTOCHANNELS_ACTIVE;

		ret = build_channel_array(dev_dir_name, &channels,
					  &num_channels);
		if (ret) {
			fprintf(stderr, "Problem reading scan element "
				"information\n"
				"diag %s\n", dev_dir_name);
547
			goto error;
548 549 550 551
		}
		if (!num_channels) {
			fprintf(stderr, "Still no channels after "
				"auto-enabling, giving up\n");
552
			goto error;
553 554 555 556
		}
	}

	if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) {
557 558 559 560
		fprintf(stderr,
			"No channels are enabled, we have nothing to scan.\n");
		fprintf(stderr, "Enable channels manually in "
			FORMAT_SCAN_ELEMENTS_DIR
561 562
			"/*_en or pass -a to autoenable channels and "
			"try again.\n", dev_dir_name);
563
		ret = -ENOENT;
564
		goto error;
565
	}
566 567 568 569 570 571

	/*
	 * Construct the directory name for the associated buffer.
	 * As we know that the lis3l02dq has only one buffer this may
	 * be built rather than found.
	 */
572 573
	ret = asprintf(&buf_dir_name,
		       "%siio:device%d/buffer", iio_dir, dev_num);
574 575
	if (ret < 0) {
		ret = -ENOMEM;
576
		goto error;
577
	}
578 579 580

	if (!notrigger) {
		printf("%s %s\n", dev_dir_name, trigger_name);
581 582 583 584
		/*
		 * Set the device trigger to be the data ready trigger found
		 * above
		 */
585 586 587 588
		ret = write_sysfs_string_and_verify("trigger/current_trigger",
						    dev_dir_name,
						    trigger_name);
		if (ret < 0) {
589 590
			fprintf(stderr,
				"Failed to write current_trigger file\n");
591
			goto error;
592
		}
593 594 595 596 597
	}

	/* Setup ring buffer parameters */
	ret = write_sysfs_int("length", buf_dir_name, buf_len);
	if (ret < 0)
598
		goto error;
599 600 601

	/* Enable the buffer */
	ret = write_sysfs_int("enable", buf_dir_name, 1);
602 603 604
	if (ret < 0) {
		fprintf(stderr,
			"Failed to enable buffer: %s\n", strerror(-ret));
605
		goto error;
606
	}
607

608
	scan_size = size_from_channelarray(channels, num_channels);
609
	data = malloc(scan_size * buf_len);
610 611
	if (!data) {
		ret = -ENOMEM;
612
		goto error;
613 614
	}

615
	ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num);
616 617
	if (ret < 0) {
		ret = -ENOMEM;
618
		goto error;
619 620 621 622
	}

	/* Attempt to open non blocking the access dev */
	fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
623
	if (fp == -1) { /* TODO: If it isn't there make the node */
624
		ret = -errno;
625
		fprintf(stderr, "Failed to open %s\n", buffer_access);
626
		goto error;
627 628 629
	}

	for (j = 0; j < num_loops; j++) {
630
		if (!noevents) {
631 632 633 634 635
			struct pollfd pfd = {
				.fd = fp,
				.events = POLLIN,
			};

636 637 638
			ret = poll(&pfd, 1, -1);
			if (ret < 0) {
				ret = -errno;
639
				goto error;
640 641 642 643
			} else if (ret == 0) {
				continue;
			}

644
			toread = buf_len;
645
		} else {
646
			usleep(timedelay);
647
			toread = 64;
648
		}
649

650
		read_size = read(fp, data, toread * scan_size);
651
		if (read_size < 0) {
652
			if (errno == EAGAIN) {
653
				fprintf(stderr, "nothing available\n");
654
				continue;
655
			} else {
656
				break;
657
			}
658
		}
659 660
		for (i = 0; i < read_size / scan_size; i++)
			process_scan(data + scan_size * i, channels,
661 662 663
				     num_channels);
	}

664 665
error:
	cleanup();
666

667
	if (fp >= 0 && close(fp) == -1)
668
		perror("Failed to close buffer");
669
	free(buffer_access);
670
	free(data);
671
	free(buf_dir_name);
672 673 674 675 676
	for (i = num_channels - 1; i >= 0; i--) {
		free(channels[i].name);
		free(channels[i].generic_name);
	}
	free(channels);
677
	free(trigger_name);
678
	free(device_name);
679
	free(dev_dir_name);
680

681 682
	return ret;
}