836 lines · 19.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* Industrialio buffer test code. * * Copyright (c) 2008 Jonathan Cameron * * 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>#include <stdlib.h>#include <dirent.h>#include <fcntl.h>#include <stdio.h>#include <errno.h>#include <sys/stat.h>#include <sys/dir.h>#include <linux/types.h>#include <string.h>#include <poll.h>#include <endian.h>#include <float.h>#include <getopt.h>#include <inttypes.h>#include <stdbool.h>#include <signal.h>#include <sys/ioctl.h>#include <linux/iio/buffer.h>#include "iio_utils.h" /** * enum autochan - state for the automatic channel enabling mechanism */enum autochan {	AUTOCHANNELS_DISABLED,	AUTOCHANNELS_ENABLED,	AUTOCHANNELS_ACTIVE,}; /** * size_from_channelarray() - calculate the storage size of a scan * @channels:		the channel info array * @num_channels:	number of channels * * Has the side effect of filling the channels[i].location values used * in processing the buffer output. **/static unsigned int size_from_channelarray(struct iio_channel_info *channels, int num_channels){	unsigned int bytes = 0;	int i = 0, max = 0;	unsigned int misalignment; 	while (i < num_channels) {		if (channels[i].bytes > max)			max = channels[i].bytes;		if (bytes % channels[i].bytes == 0)			channels[i].location = bytes;		else			channels[i].location = bytes - bytes % channels[i].bytes					       + channels[i].bytes; 		bytes = channels[i].location + channels[i].bytes;		i++;	}	/*	 * We want the data in next sample to also be properly aligned so	 * we'll add padding at the end if needed. Adding padding only	 * works for channel data which size is 2^n bytes.	 */	misalignment = bytes % max;	if (misalignment)		bytes += max - misalignment; 	return bytes;} static 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;	switch (info->format) {	case 's': {		int8_t val = (int8_t)(input << (8 - info->bits_used)) >>			     (8 - info->bits_used);		printf("%05f ", ((float)val + info->offset) * info->scale);		break;	}	case 'u':		printf("%05f ", ((float)input + info->offset) * info->scale);		break;	case 'f':		printf("<invalid 1-byte float> ");		break;	}} static void print2byte(uint16_t input, struct iio_channel_info *info){	/* First swap if incorrect endian */	if (info->be)		input = be16toh(input);	else		input = le16toh(input); 	/*	 * Shift before conversion to avoid sign extension	 * of left aligned data	 */	input >>= info->shift;	input &= info->mask;	switch (info->format) {	case 's': {		int16_t val = (int16_t)(input << (16 - info->bits_used)) >>			      (16 - info->bits_used);		printf("%05f ", ((float)val + info->offset) * info->scale);		break;	}	case 'u':		printf("%05f ", ((float)input + info->offset) * info->scale);		break;	case 'f': {#if defined(__FLT16_MAX__)		union {			uint16_t u;			_Float16 f;		} converter; 		converter.u = input;		printf("%05f ", ((float)converter.f + info->offset) * info->scale);#else		printf("<unsupported 2-byte float> ");#endif		break;	}	}} static 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;	switch (info->format) {	case 's': {		int32_t val = (int32_t)(input << (32 - info->bits_used)) >>			      (32 - info->bits_used);		printf("%05f ", ((float)val + info->offset) * info->scale);		break;	}	case 'u':		printf("%05f ", ((float)input + info->offset) * info->scale);		break;	case 'f': {		union {			uint32_t u;			float f;		} converter; 		converter.u = input;		printf("%05f ", (converter.f + info->offset) * info->scale);		break;	}	}} static 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;	switch (info->format) {	case 's': {		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);		break;	}	case 'u':		printf("%05f ", ((float)input + info->offset) * info->scale);		break;	case 'f': {		union {			uint64_t u;			double f;		} converter; 		converter.u = input;		printf("%05f ", (converter.f + info->offset) * info->scale);		break;	}	}} /** * process_scan() - print out the values in SI units * @data:		pointer to the start of the scan * @channels:		information about the channels. *			Note: size_from_channelarray must have been called first *			      to fill the location offsets. * @num_channels:	number of channels **/static void process_scan(char *data, struct iio_channel_info *channels,			 int num_channels){	int k; 	for (k = 0; k < num_channels; k++)		switch (channels[k].bytes) {			/* only a few cases implemented so far */		case 1:			print1byte(*(uint8_t *)(data + channels[k].location),				   &channels[k]);			break;		case 2:			print2byte(*(uint16_t *)(data + channels[k].location),				   &channels[k]);			break;		case 4:			print4byte(*(uint32_t *)(data + channels[k].location),				   &channels[k]);			break;		case 8:			print8byte(*(uint64_t *)(data + channels[k].location),				   &channels[k]);			break;		default:			break;		}	printf("\n");} static int enable_disable_all_channels(char *dev_dir_name, int buffer_idx, int enable){	const struct dirent *ent;	char scanelemdir[256];	DIR *dp;	int ret; 	snprintf(scanelemdir, sizeof(scanelemdir),		 FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name, buffer_idx);	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;} static void print_usage(void){	fprintf(stderr, "Usage: generic_buffer [options]...\n"		"Capture, convert and output data from IIO device buffer\n"		"  -a         Auto-activate all available channels\n"		"  -A         Force-activate ALL channels\n"		"  -b <n>     The buffer which to open (by index), default 0\n"		"  -c <n>     Do n conversions, or loop forever if n < 0\n"		"  -e         Disable wait for event (new data)\n"		"  -g         Use trigger-less mode\n"		"  -l <n>     Set buffer length to n samples\n"		"  --device-name -n <name>\n"		"  --device-num -N <num>\n"		"        Set device by name or number (mandatory)\n"		"  --trigger-name -t <name>\n"		"  --trigger-num -T <num>\n"		"        Set trigger by name or number\n"		"  -w <n>     Set delay between reads in us (event-less mode)\n");} static enum autochan autochannels = AUTOCHANNELS_DISABLED;static char *dev_dir_name = NULL;static char *buf_dir_name = NULL;static int buffer_idx = 0;static bool current_trigger_set = false; static 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, buffer_idx, 0);		if (ret)			fprintf(stderr, "Failed to disable all channels\n");		autochannels = AUTOCHANNELS_DISABLED;	}} static void sig_handler(int signum){	fprintf(stderr, "Caught signal %d\n", signum);	cleanup();	exit(-signum);} static 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);		}	}} static const struct option longopts[] = {	{ "device-name",	1, 0, 'n' },	{ "device-num",		1, 0, 'N' },	{ "trigger-name",	1, 0, 't' },	{ "trigger-num",	1, 0, 'T' },	{ }}; int main(int argc, char **argv){	long long num_loops = 2;	unsigned long timedelay = 1000000;	unsigned long buf_len = 128; 	ssize_t i;	unsigned long long j;	unsigned long toread;	int ret, c;	struct stat st;	int fd = -1;	int buf_fd = -1; 	int num_channels = 0;	char *trigger_name = NULL, *device_name = NULL; 	char *data = NULL;	ssize_t read_size;	int dev_num = -1, trig_num = -1;	char *buffer_access = NULL;	unsigned int scan_size;	int noevents = 0;	int notrigger = 0;	char *dummy;	bool force_autochannels = false; 	struct iio_channel_info *channels = NULL; 	register_cleanup(); 	while ((c = getopt_long(argc, argv, "aAb:c:egl:n:N:t:T:w:?", longopts,				NULL)) != -1) {		switch (c) {		case 'a':			autochannels = AUTOCHANNELS_ENABLED;			break;		case 'A':			autochannels = AUTOCHANNELS_ENABLED;			force_autochannels = true;			break;		case 'b':			errno = 0;			buffer_idx = strtoll(optarg, &dummy, 10);			if (errno) {				ret = -errno;				goto error;			}			if (buffer_idx < 0) {				ret = -ERANGE;				goto error;			} 			break;		case 'c':			errno = 0;			num_loops = strtoll(optarg, &dummy, 10);			if (errno) {				ret = -errno;				goto error;			} 			break;		case 'e':			noevents = 1;			break;		case 'g':			notrigger = 1;			break;		case 'l':			errno = 0;			buf_len = strtoul(optarg, &dummy, 10);			if (errno) {				ret = -errno;				goto error;			} 			break;		case 'n':			device_name = strdup(optarg);			break;		case 'N':			errno = 0;			dev_num = strtoul(optarg, &dummy, 10);			if (errno) {				ret = -errno;				goto error;			}			break;		case 't':			trigger_name = strdup(optarg);			break;		case 'T':			errno = 0;			trig_num = strtoul(optarg, &dummy, 10);			if (errno)				return -errno;			break;		case 'w':			errno = 0;			timedelay = strtoul(optarg, &dummy, 10);			if (errno) {				ret = -errno;				goto error;			}			break;

Lines 1–500 of 836.