162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Industrialio buffer test code. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2008 Jonathan Cameron 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This program is primarily intended as an example application. 762306a36Sopenharmony_ci * Reads the current buffer setup from sysfs and starts a short capture 862306a36Sopenharmony_ci * from the specified device, pretty printing the result after appropriate 962306a36Sopenharmony_ci * conversion. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Command line parameters 1262306a36Sopenharmony_ci * generic_buffer -n <device_name> -t <trigger_name> 1362306a36Sopenharmony_ci * If trigger name is not specified the program assumes you want a dataready 1462306a36Sopenharmony_ci * trigger associated with the device and goes looking for it. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <unistd.h> 1862306a36Sopenharmony_ci#include <stdlib.h> 1962306a36Sopenharmony_ci#include <dirent.h> 2062306a36Sopenharmony_ci#include <fcntl.h> 2162306a36Sopenharmony_ci#include <stdio.h> 2262306a36Sopenharmony_ci#include <errno.h> 2362306a36Sopenharmony_ci#include <sys/stat.h> 2462306a36Sopenharmony_ci#include <sys/dir.h> 2562306a36Sopenharmony_ci#include <linux/types.h> 2662306a36Sopenharmony_ci#include <string.h> 2762306a36Sopenharmony_ci#include <poll.h> 2862306a36Sopenharmony_ci#include <endian.h> 2962306a36Sopenharmony_ci#include <getopt.h> 3062306a36Sopenharmony_ci#include <inttypes.h> 3162306a36Sopenharmony_ci#include <stdbool.h> 3262306a36Sopenharmony_ci#include <signal.h> 3362306a36Sopenharmony_ci#include <sys/ioctl.h> 3462306a36Sopenharmony_ci#include <linux/iio/buffer.h> 3562306a36Sopenharmony_ci#include "iio_utils.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/** 3862306a36Sopenharmony_ci * enum autochan - state for the automatic channel enabling mechanism 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_cienum autochan { 4162306a36Sopenharmony_ci AUTOCHANNELS_DISABLED, 4262306a36Sopenharmony_ci AUTOCHANNELS_ENABLED, 4362306a36Sopenharmony_ci AUTOCHANNELS_ACTIVE, 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/** 4762306a36Sopenharmony_ci * size_from_channelarray() - calculate the storage size of a scan 4862306a36Sopenharmony_ci * @channels: the channel info array 4962306a36Sopenharmony_ci * @num_channels: number of channels 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * Has the side effect of filling the channels[i].location values used 5262306a36Sopenharmony_ci * in processing the buffer output. 5362306a36Sopenharmony_ci **/ 5462306a36Sopenharmony_cistatic unsigned int size_from_channelarray(struct iio_channel_info *channels, int num_channels) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci unsigned int bytes = 0; 5762306a36Sopenharmony_ci int i = 0, max = 0; 5862306a36Sopenharmony_ci unsigned int misalignment; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci while (i < num_channels) { 6162306a36Sopenharmony_ci if (channels[i].bytes > max) 6262306a36Sopenharmony_ci max = channels[i].bytes; 6362306a36Sopenharmony_ci if (bytes % channels[i].bytes == 0) 6462306a36Sopenharmony_ci channels[i].location = bytes; 6562306a36Sopenharmony_ci else 6662306a36Sopenharmony_ci channels[i].location = bytes - bytes % channels[i].bytes 6762306a36Sopenharmony_ci + channels[i].bytes; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci bytes = channels[i].location + channels[i].bytes; 7062306a36Sopenharmony_ci i++; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci /* 7362306a36Sopenharmony_ci * We want the data in next sample to also be properly aligned so 7462306a36Sopenharmony_ci * we'll add padding at the end if needed. Adding padding only 7562306a36Sopenharmony_ci * works for channel data which size is 2^n bytes. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci misalignment = bytes % max; 7862306a36Sopenharmony_ci if (misalignment) 7962306a36Sopenharmony_ci bytes += max - misalignment; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return bytes; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void print1byte(uint8_t input, struct iio_channel_info *info) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * Shift before conversion to avoid sign extension 8862306a36Sopenharmony_ci * of left aligned data 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci input >>= info->shift; 9162306a36Sopenharmony_ci input &= info->mask; 9262306a36Sopenharmony_ci if (info->is_signed) { 9362306a36Sopenharmony_ci int8_t val = (int8_t)(input << (8 - info->bits_used)) >> 9462306a36Sopenharmony_ci (8 - info->bits_used); 9562306a36Sopenharmony_ci printf("%05f ", ((float)val + info->offset) * info->scale); 9662306a36Sopenharmony_ci } else { 9762306a36Sopenharmony_ci printf("%05f ", ((float)input + info->offset) * info->scale); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic void print2byte(uint16_t input, struct iio_channel_info *info) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci /* First swap if incorrect endian */ 10462306a36Sopenharmony_ci if (info->be) 10562306a36Sopenharmony_ci input = be16toh(input); 10662306a36Sopenharmony_ci else 10762306a36Sopenharmony_ci input = le16toh(input); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* 11062306a36Sopenharmony_ci * Shift before conversion to avoid sign extension 11162306a36Sopenharmony_ci * of left aligned data 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci input >>= info->shift; 11462306a36Sopenharmony_ci input &= info->mask; 11562306a36Sopenharmony_ci if (info->is_signed) { 11662306a36Sopenharmony_ci int16_t val = (int16_t)(input << (16 - info->bits_used)) >> 11762306a36Sopenharmony_ci (16 - info->bits_used); 11862306a36Sopenharmony_ci printf("%05f ", ((float)val + info->offset) * info->scale); 11962306a36Sopenharmony_ci } else { 12062306a36Sopenharmony_ci printf("%05f ", ((float)input + info->offset) * info->scale); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void print4byte(uint32_t input, struct iio_channel_info *info) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci /* First swap if incorrect endian */ 12762306a36Sopenharmony_ci if (info->be) 12862306a36Sopenharmony_ci input = be32toh(input); 12962306a36Sopenharmony_ci else 13062306a36Sopenharmony_ci input = le32toh(input); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* 13362306a36Sopenharmony_ci * Shift before conversion to avoid sign extension 13462306a36Sopenharmony_ci * of left aligned data 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci input >>= info->shift; 13762306a36Sopenharmony_ci input &= info->mask; 13862306a36Sopenharmony_ci if (info->is_signed) { 13962306a36Sopenharmony_ci int32_t val = (int32_t)(input << (32 - info->bits_used)) >> 14062306a36Sopenharmony_ci (32 - info->bits_used); 14162306a36Sopenharmony_ci printf("%05f ", ((float)val + info->offset) * info->scale); 14262306a36Sopenharmony_ci } else { 14362306a36Sopenharmony_ci printf("%05f ", ((float)input + info->offset) * info->scale); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic void print8byte(uint64_t input, struct iio_channel_info *info) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci /* First swap if incorrect endian */ 15062306a36Sopenharmony_ci if (info->be) 15162306a36Sopenharmony_ci input = be64toh(input); 15262306a36Sopenharmony_ci else 15362306a36Sopenharmony_ci input = le64toh(input); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* 15662306a36Sopenharmony_ci * Shift before conversion to avoid sign extension 15762306a36Sopenharmony_ci * of left aligned data 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci input >>= info->shift; 16062306a36Sopenharmony_ci input &= info->mask; 16162306a36Sopenharmony_ci if (info->is_signed) { 16262306a36Sopenharmony_ci int64_t val = (int64_t)(input << (64 - info->bits_used)) >> 16362306a36Sopenharmony_ci (64 - info->bits_used); 16462306a36Sopenharmony_ci /* special case for timestamp */ 16562306a36Sopenharmony_ci if (info->scale == 1.0f && info->offset == 0.0f) 16662306a36Sopenharmony_ci printf("%" PRId64 " ", val); 16762306a36Sopenharmony_ci else 16862306a36Sopenharmony_ci printf("%05f ", 16962306a36Sopenharmony_ci ((float)val + info->offset) * info->scale); 17062306a36Sopenharmony_ci } else { 17162306a36Sopenharmony_ci printf("%05f ", ((float)input + info->offset) * info->scale); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/** 17662306a36Sopenharmony_ci * process_scan() - print out the values in SI units 17762306a36Sopenharmony_ci * @data: pointer to the start of the scan 17862306a36Sopenharmony_ci * @channels: information about the channels. 17962306a36Sopenharmony_ci * Note: size_from_channelarray must have been called first 18062306a36Sopenharmony_ci * to fill the location offsets. 18162306a36Sopenharmony_ci * @num_channels: number of channels 18262306a36Sopenharmony_ci **/ 18362306a36Sopenharmony_cistatic void process_scan(char *data, struct iio_channel_info *channels, 18462306a36Sopenharmony_ci int num_channels) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci int k; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci for (k = 0; k < num_channels; k++) 18962306a36Sopenharmony_ci switch (channels[k].bytes) { 19062306a36Sopenharmony_ci /* only a few cases implemented so far */ 19162306a36Sopenharmony_ci case 1: 19262306a36Sopenharmony_ci print1byte(*(uint8_t *)(data + channels[k].location), 19362306a36Sopenharmony_ci &channels[k]); 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci case 2: 19662306a36Sopenharmony_ci print2byte(*(uint16_t *)(data + channels[k].location), 19762306a36Sopenharmony_ci &channels[k]); 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci case 4: 20062306a36Sopenharmony_ci print4byte(*(uint32_t *)(data + channels[k].location), 20162306a36Sopenharmony_ci &channels[k]); 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci case 8: 20462306a36Sopenharmony_ci print8byte(*(uint64_t *)(data + channels[k].location), 20562306a36Sopenharmony_ci &channels[k]); 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci default: 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci printf("\n"); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int enable_disable_all_channels(char *dev_dir_name, int buffer_idx, int enable) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci const struct dirent *ent; 21662306a36Sopenharmony_ci char scanelemdir[256]; 21762306a36Sopenharmony_ci DIR *dp; 21862306a36Sopenharmony_ci int ret; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci snprintf(scanelemdir, sizeof(scanelemdir), 22162306a36Sopenharmony_ci FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name, buffer_idx); 22262306a36Sopenharmony_ci scanelemdir[sizeof(scanelemdir)-1] = '\0'; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci dp = opendir(scanelemdir); 22562306a36Sopenharmony_ci if (!dp) { 22662306a36Sopenharmony_ci fprintf(stderr, "Enabling/disabling channels: can't open %s\n", 22762306a36Sopenharmony_ci scanelemdir); 22862306a36Sopenharmony_ci return -EIO; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci ret = -ENOENT; 23262306a36Sopenharmony_ci while (ent = readdir(dp), ent) { 23362306a36Sopenharmony_ci if (iioutils_check_suffix(ent->d_name, "_en")) { 23462306a36Sopenharmony_ci printf("%sabling: %s\n", 23562306a36Sopenharmony_ci enable ? "En" : "Dis", 23662306a36Sopenharmony_ci ent->d_name); 23762306a36Sopenharmony_ci ret = write_sysfs_int(ent->d_name, scanelemdir, 23862306a36Sopenharmony_ci enable); 23962306a36Sopenharmony_ci if (ret < 0) 24062306a36Sopenharmony_ci fprintf(stderr, "Failed to enable/disable %s\n", 24162306a36Sopenharmony_ci ent->d_name); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (closedir(dp) == -1) { 24662306a36Sopenharmony_ci perror("Enabling/disabling channels: " 24762306a36Sopenharmony_ci "Failed to close directory"); 24862306a36Sopenharmony_ci return -errno; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void print_usage(void) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci fprintf(stderr, "Usage: generic_buffer [options]...\n" 25662306a36Sopenharmony_ci "Capture, convert and output data from IIO device buffer\n" 25762306a36Sopenharmony_ci " -a Auto-activate all available channels\n" 25862306a36Sopenharmony_ci " -A Force-activate ALL channels\n" 25962306a36Sopenharmony_ci " -b <n> The buffer which to open (by index), default 0\n" 26062306a36Sopenharmony_ci " -c <n> Do n conversions, or loop forever if n < 0\n" 26162306a36Sopenharmony_ci " -e Disable wait for event (new data)\n" 26262306a36Sopenharmony_ci " -g Use trigger-less mode\n" 26362306a36Sopenharmony_ci " -l <n> Set buffer length to n samples\n" 26462306a36Sopenharmony_ci " --device-name -n <name>\n" 26562306a36Sopenharmony_ci " --device-num -N <num>\n" 26662306a36Sopenharmony_ci " Set device by name or number (mandatory)\n" 26762306a36Sopenharmony_ci " --trigger-name -t <name>\n" 26862306a36Sopenharmony_ci " --trigger-num -T <num>\n" 26962306a36Sopenharmony_ci " Set trigger by name or number\n" 27062306a36Sopenharmony_ci " -w <n> Set delay between reads in us (event-less mode)\n"); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic enum autochan autochannels = AUTOCHANNELS_DISABLED; 27462306a36Sopenharmony_cistatic char *dev_dir_name = NULL; 27562306a36Sopenharmony_cistatic char *buf_dir_name = NULL; 27662306a36Sopenharmony_cistatic int buffer_idx = 0; 27762306a36Sopenharmony_cistatic bool current_trigger_set = false; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void cleanup(void) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci int ret; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Disable trigger */ 28462306a36Sopenharmony_ci if (dev_dir_name && current_trigger_set) { 28562306a36Sopenharmony_ci /* Disconnect the trigger - just write a dummy name. */ 28662306a36Sopenharmony_ci ret = write_sysfs_string("trigger/current_trigger", 28762306a36Sopenharmony_ci dev_dir_name, "NULL"); 28862306a36Sopenharmony_ci if (ret < 0) 28962306a36Sopenharmony_ci fprintf(stderr, "Failed to disable trigger: %s\n", 29062306a36Sopenharmony_ci strerror(-ret)); 29162306a36Sopenharmony_ci current_trigger_set = false; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Disable buffer */ 29562306a36Sopenharmony_ci if (buf_dir_name) { 29662306a36Sopenharmony_ci ret = write_sysfs_int("enable", buf_dir_name, 0); 29762306a36Sopenharmony_ci if (ret < 0) 29862306a36Sopenharmony_ci fprintf(stderr, "Failed to disable buffer: %s\n", 29962306a36Sopenharmony_ci strerror(-ret)); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* Disable channels if auto-enabled */ 30362306a36Sopenharmony_ci if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { 30462306a36Sopenharmony_ci ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 0); 30562306a36Sopenharmony_ci if (ret) 30662306a36Sopenharmony_ci fprintf(stderr, "Failed to disable all channels\n"); 30762306a36Sopenharmony_ci autochannels = AUTOCHANNELS_DISABLED; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void sig_handler(int signum) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci fprintf(stderr, "Caught signal %d\n", signum); 31462306a36Sopenharmony_ci cleanup(); 31562306a36Sopenharmony_ci exit(-signum); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic void register_cleanup(void) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct sigaction sa = { .sa_handler = sig_handler }; 32162306a36Sopenharmony_ci const int signums[] = { SIGINT, SIGTERM, SIGABRT }; 32262306a36Sopenharmony_ci int ret, i; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(signums); ++i) { 32562306a36Sopenharmony_ci ret = sigaction(signums[i], &sa, NULL); 32662306a36Sopenharmony_ci if (ret) { 32762306a36Sopenharmony_ci perror("Failed to register signal handler"); 32862306a36Sopenharmony_ci exit(-1); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic const struct option longopts[] = { 33462306a36Sopenharmony_ci { "device-name", 1, 0, 'n' }, 33562306a36Sopenharmony_ci { "device-num", 1, 0, 'N' }, 33662306a36Sopenharmony_ci { "trigger-name", 1, 0, 't' }, 33762306a36Sopenharmony_ci { "trigger-num", 1, 0, 'T' }, 33862306a36Sopenharmony_ci { }, 33962306a36Sopenharmony_ci}; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ciint main(int argc, char **argv) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci long long num_loops = 2; 34462306a36Sopenharmony_ci unsigned long timedelay = 1000000; 34562306a36Sopenharmony_ci unsigned long buf_len = 128; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ssize_t i; 34862306a36Sopenharmony_ci unsigned long long j; 34962306a36Sopenharmony_ci unsigned long toread; 35062306a36Sopenharmony_ci int ret, c; 35162306a36Sopenharmony_ci struct stat st; 35262306a36Sopenharmony_ci int fd = -1; 35362306a36Sopenharmony_ci int buf_fd = -1; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci int num_channels = 0; 35662306a36Sopenharmony_ci char *trigger_name = NULL, *device_name = NULL; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci char *data = NULL; 35962306a36Sopenharmony_ci ssize_t read_size; 36062306a36Sopenharmony_ci int dev_num = -1, trig_num = -1; 36162306a36Sopenharmony_ci char *buffer_access = NULL; 36262306a36Sopenharmony_ci unsigned int scan_size; 36362306a36Sopenharmony_ci int noevents = 0; 36462306a36Sopenharmony_ci int notrigger = 0; 36562306a36Sopenharmony_ci char *dummy; 36662306a36Sopenharmony_ci bool force_autochannels = false; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci struct iio_channel_info *channels = NULL; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci register_cleanup(); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci while ((c = getopt_long(argc, argv, "aAb:c:egl:n:N:t:T:w:?", longopts, 37362306a36Sopenharmony_ci NULL)) != -1) { 37462306a36Sopenharmony_ci switch (c) { 37562306a36Sopenharmony_ci case 'a': 37662306a36Sopenharmony_ci autochannels = AUTOCHANNELS_ENABLED; 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci case 'A': 37962306a36Sopenharmony_ci autochannels = AUTOCHANNELS_ENABLED; 38062306a36Sopenharmony_ci force_autochannels = true; 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci case 'b': 38362306a36Sopenharmony_ci errno = 0; 38462306a36Sopenharmony_ci buffer_idx = strtoll(optarg, &dummy, 10); 38562306a36Sopenharmony_ci if (errno) { 38662306a36Sopenharmony_ci ret = -errno; 38762306a36Sopenharmony_ci goto error; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci if (buffer_idx < 0) { 39062306a36Sopenharmony_ci ret = -ERANGE; 39162306a36Sopenharmony_ci goto error; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci case 'c': 39662306a36Sopenharmony_ci errno = 0; 39762306a36Sopenharmony_ci num_loops = strtoll(optarg, &dummy, 10); 39862306a36Sopenharmony_ci if (errno) { 39962306a36Sopenharmony_ci ret = -errno; 40062306a36Sopenharmony_ci goto error; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci case 'e': 40562306a36Sopenharmony_ci noevents = 1; 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci case 'g': 40862306a36Sopenharmony_ci notrigger = 1; 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci case 'l': 41162306a36Sopenharmony_ci errno = 0; 41262306a36Sopenharmony_ci buf_len = strtoul(optarg, &dummy, 10); 41362306a36Sopenharmony_ci if (errno) { 41462306a36Sopenharmony_ci ret = -errno; 41562306a36Sopenharmony_ci goto error; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci case 'n': 42062306a36Sopenharmony_ci device_name = strdup(optarg); 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case 'N': 42362306a36Sopenharmony_ci errno = 0; 42462306a36Sopenharmony_ci dev_num = strtoul(optarg, &dummy, 10); 42562306a36Sopenharmony_ci if (errno) { 42662306a36Sopenharmony_ci ret = -errno; 42762306a36Sopenharmony_ci goto error; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci case 't': 43162306a36Sopenharmony_ci trigger_name = strdup(optarg); 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci case 'T': 43462306a36Sopenharmony_ci errno = 0; 43562306a36Sopenharmony_ci trig_num = strtoul(optarg, &dummy, 10); 43662306a36Sopenharmony_ci if (errno) 43762306a36Sopenharmony_ci return -errno; 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci case 'w': 44062306a36Sopenharmony_ci errno = 0; 44162306a36Sopenharmony_ci timedelay = strtoul(optarg, &dummy, 10); 44262306a36Sopenharmony_ci if (errno) { 44362306a36Sopenharmony_ci ret = -errno; 44462306a36Sopenharmony_ci goto error; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci case '?': 44862306a36Sopenharmony_ci print_usage(); 44962306a36Sopenharmony_ci ret = -1; 45062306a36Sopenharmony_ci goto error; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Find the device requested */ 45562306a36Sopenharmony_ci if (dev_num < 0 && !device_name) { 45662306a36Sopenharmony_ci fprintf(stderr, "Device not set\n"); 45762306a36Sopenharmony_ci print_usage(); 45862306a36Sopenharmony_ci ret = -1; 45962306a36Sopenharmony_ci goto error; 46062306a36Sopenharmony_ci } else if (dev_num >= 0 && device_name) { 46162306a36Sopenharmony_ci fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n"); 46262306a36Sopenharmony_ci print_usage(); 46362306a36Sopenharmony_ci ret = -1; 46462306a36Sopenharmony_ci goto error; 46562306a36Sopenharmony_ci } else if (dev_num < 0) { 46662306a36Sopenharmony_ci dev_num = find_type_by_name(device_name, "iio:device"); 46762306a36Sopenharmony_ci if (dev_num < 0) { 46862306a36Sopenharmony_ci fprintf(stderr, "Failed to find the %s\n", device_name); 46962306a36Sopenharmony_ci ret = dev_num; 47062306a36Sopenharmony_ci goto error; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci printf("iio device number being used is %d\n", dev_num); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); 47662306a36Sopenharmony_ci if (ret < 0) 47762306a36Sopenharmony_ci return -ENOMEM; 47862306a36Sopenharmony_ci /* Fetch device_name if specified by number */ 47962306a36Sopenharmony_ci if (!device_name) { 48062306a36Sopenharmony_ci device_name = malloc(IIO_MAX_NAME_LENGTH); 48162306a36Sopenharmony_ci if (!device_name) { 48262306a36Sopenharmony_ci ret = -ENOMEM; 48362306a36Sopenharmony_ci goto error; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci ret = read_sysfs_string("name", dev_dir_name, device_name); 48662306a36Sopenharmony_ci if (ret < 0) { 48762306a36Sopenharmony_ci fprintf(stderr, "Failed to read name of device %d\n", dev_num); 48862306a36Sopenharmony_ci goto error; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (notrigger) { 49362306a36Sopenharmony_ci printf("trigger-less mode selected\n"); 49462306a36Sopenharmony_ci } else if (trig_num >= 0) { 49562306a36Sopenharmony_ci char *trig_dev_name; 49662306a36Sopenharmony_ci ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); 49762306a36Sopenharmony_ci if (ret < 0) { 49862306a36Sopenharmony_ci return -ENOMEM; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci trigger_name = malloc(IIO_MAX_NAME_LENGTH); 50162306a36Sopenharmony_ci ret = read_sysfs_string("name", trig_dev_name, trigger_name); 50262306a36Sopenharmony_ci free(trig_dev_name); 50362306a36Sopenharmony_ci if (ret < 0) { 50462306a36Sopenharmony_ci fprintf(stderr, "Failed to read trigger%d name from\n", trig_num); 50562306a36Sopenharmony_ci return ret; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci printf("iio trigger number being used is %d\n", trig_num); 50862306a36Sopenharmony_ci } else { 50962306a36Sopenharmony_ci if (!trigger_name) { 51062306a36Sopenharmony_ci /* 51162306a36Sopenharmony_ci * Build the trigger name. If it is device associated 51262306a36Sopenharmony_ci * its name is <device_name>_dev[n] where n matches 51362306a36Sopenharmony_ci * the device number found above. 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ci ret = asprintf(&trigger_name, 51662306a36Sopenharmony_ci "%s-dev%d", device_name, dev_num); 51762306a36Sopenharmony_ci if (ret < 0) { 51862306a36Sopenharmony_ci ret = -ENOMEM; 51962306a36Sopenharmony_ci goto error; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Look for this "-devN" trigger */ 52462306a36Sopenharmony_ci trig_num = find_type_by_name(trigger_name, "trigger"); 52562306a36Sopenharmony_ci if (trig_num < 0) { 52662306a36Sopenharmony_ci /* OK try the simpler "-trigger" suffix instead */ 52762306a36Sopenharmony_ci free(trigger_name); 52862306a36Sopenharmony_ci ret = asprintf(&trigger_name, 52962306a36Sopenharmony_ci "%s-trigger", device_name); 53062306a36Sopenharmony_ci if (ret < 0) { 53162306a36Sopenharmony_ci ret = -ENOMEM; 53262306a36Sopenharmony_ci goto error; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci trig_num = find_type_by_name(trigger_name, "trigger"); 53762306a36Sopenharmony_ci if (trig_num < 0) { 53862306a36Sopenharmony_ci fprintf(stderr, "Failed to find the trigger %s\n", 53962306a36Sopenharmony_ci trigger_name); 54062306a36Sopenharmony_ci ret = trig_num; 54162306a36Sopenharmony_ci goto error; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci printf("iio trigger number being used is %d\n", trig_num); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* 54862306a36Sopenharmony_ci * Parse the files in scan_elements to identify what channels are 54962306a36Sopenharmony_ci * present 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels); 55262306a36Sopenharmony_ci if (ret) { 55362306a36Sopenharmony_ci fprintf(stderr, "Problem reading scan element information\n" 55462306a36Sopenharmony_ci "diag %s\n", dev_dir_name); 55562306a36Sopenharmony_ci goto error; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci if (num_channels && autochannels == AUTOCHANNELS_ENABLED && 55862306a36Sopenharmony_ci !force_autochannels) { 55962306a36Sopenharmony_ci fprintf(stderr, "Auto-channels selected but some channels " 56062306a36Sopenharmony_ci "are already activated in sysfs\n"); 56162306a36Sopenharmony_ci fprintf(stderr, "Proceeding without activating any channels\n"); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || 56562306a36Sopenharmony_ci (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { 56662306a36Sopenharmony_ci fprintf(stderr, "Enabling all channels\n"); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 1); 56962306a36Sopenharmony_ci if (ret) { 57062306a36Sopenharmony_ci fprintf(stderr, "Failed to enable all channels\n"); 57162306a36Sopenharmony_ci goto error; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* This flags that we need to disable the channels again */ 57562306a36Sopenharmony_ci autochannels = AUTOCHANNELS_ACTIVE; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci ret = build_channel_array(dev_dir_name, buffer_idx, &channels, 57862306a36Sopenharmony_ci &num_channels); 57962306a36Sopenharmony_ci if (ret) { 58062306a36Sopenharmony_ci fprintf(stderr, "Problem reading scan element " 58162306a36Sopenharmony_ci "information\n" 58262306a36Sopenharmony_ci "diag %s\n", dev_dir_name); 58362306a36Sopenharmony_ci goto error; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci if (!num_channels) { 58662306a36Sopenharmony_ci fprintf(stderr, "Still no channels after " 58762306a36Sopenharmony_ci "auto-enabling, giving up\n"); 58862306a36Sopenharmony_ci goto error; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { 59362306a36Sopenharmony_ci fprintf(stderr, 59462306a36Sopenharmony_ci "No channels are enabled, we have nothing to scan.\n"); 59562306a36Sopenharmony_ci fprintf(stderr, "Enable channels manually in " 59662306a36Sopenharmony_ci FORMAT_SCAN_ELEMENTS_DIR 59762306a36Sopenharmony_ci "/*_en or pass -a to autoenable channels and " 59862306a36Sopenharmony_ci "try again.\n", dev_dir_name, buffer_idx); 59962306a36Sopenharmony_ci ret = -ENOENT; 60062306a36Sopenharmony_ci goto error; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* 60462306a36Sopenharmony_ci * Construct the directory name for the associated buffer. 60562306a36Sopenharmony_ci * As we know that the lis3l02dq has only one buffer this may 60662306a36Sopenharmony_ci * be built rather than found. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_ci ret = asprintf(&buf_dir_name, 60962306a36Sopenharmony_ci "%siio:device%d/buffer%d", iio_dir, dev_num, buffer_idx); 61062306a36Sopenharmony_ci if (ret < 0) { 61162306a36Sopenharmony_ci ret = -ENOMEM; 61262306a36Sopenharmony_ci goto error; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (stat(buf_dir_name, &st)) { 61662306a36Sopenharmony_ci fprintf(stderr, "Could not stat() '%s', got error %d: %s\n", 61762306a36Sopenharmony_ci buf_dir_name, errno, strerror(errno)); 61862306a36Sopenharmony_ci ret = -errno; 61962306a36Sopenharmony_ci goto error; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (!S_ISDIR(st.st_mode)) { 62362306a36Sopenharmony_ci fprintf(stderr, "File '%s' is not a directory\n", buf_dir_name); 62462306a36Sopenharmony_ci ret = -EFAULT; 62562306a36Sopenharmony_ci goto error; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (!notrigger) { 62962306a36Sopenharmony_ci printf("%s %s\n", dev_dir_name, trigger_name); 63062306a36Sopenharmony_ci /* 63162306a36Sopenharmony_ci * Set the device trigger to be the data ready trigger found 63262306a36Sopenharmony_ci * above 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci ret = write_sysfs_string_and_verify("trigger/current_trigger", 63562306a36Sopenharmony_ci dev_dir_name, 63662306a36Sopenharmony_ci trigger_name); 63762306a36Sopenharmony_ci if (ret < 0) { 63862306a36Sopenharmony_ci fprintf(stderr, 63962306a36Sopenharmony_ci "Failed to write current_trigger file\n"); 64062306a36Sopenharmony_ci goto error; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); 64562306a36Sopenharmony_ci if (ret < 0) { 64662306a36Sopenharmony_ci ret = -ENOMEM; 64762306a36Sopenharmony_ci goto error; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* Attempt to open non blocking the access dev */ 65162306a36Sopenharmony_ci fd = open(buffer_access, O_RDONLY | O_NONBLOCK); 65262306a36Sopenharmony_ci if (fd == -1) { /* TODO: If it isn't there make the node */ 65362306a36Sopenharmony_ci ret = -errno; 65462306a36Sopenharmony_ci fprintf(stderr, "Failed to open %s\n", buffer_access); 65562306a36Sopenharmony_ci goto error; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* specify for which buffer index we want an FD */ 65962306a36Sopenharmony_ci buf_fd = buffer_idx; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci ret = ioctl(fd, IIO_BUFFER_GET_FD_IOCTL, &buf_fd); 66262306a36Sopenharmony_ci if (ret == -1 || buf_fd == -1) { 66362306a36Sopenharmony_ci ret = -errno; 66462306a36Sopenharmony_ci if (ret == -ENODEV || ret == -EINVAL) 66562306a36Sopenharmony_ci fprintf(stderr, 66662306a36Sopenharmony_ci "Device does not have this many buffers\n"); 66762306a36Sopenharmony_ci else 66862306a36Sopenharmony_ci fprintf(stderr, "Failed to retrieve buffer fd\n"); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci goto error; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* Setup ring buffer parameters */ 67462306a36Sopenharmony_ci ret = write_sysfs_int("length", buf_dir_name, buf_len); 67562306a36Sopenharmony_ci if (ret < 0) 67662306a36Sopenharmony_ci goto error; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* Enable the buffer */ 67962306a36Sopenharmony_ci ret = write_sysfs_int("enable", buf_dir_name, 1); 68062306a36Sopenharmony_ci if (ret < 0) { 68162306a36Sopenharmony_ci fprintf(stderr, 68262306a36Sopenharmony_ci "Failed to enable buffer '%s': %s\n", 68362306a36Sopenharmony_ci buf_dir_name, strerror(-ret)); 68462306a36Sopenharmony_ci goto error; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci scan_size = size_from_channelarray(channels, num_channels); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci size_t total_buf_len = scan_size * buf_len; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (scan_size > 0 && total_buf_len / scan_size != buf_len) { 69262306a36Sopenharmony_ci ret = -EFAULT; 69362306a36Sopenharmony_ci perror("Integer overflow happened when calculate scan_size * buf_len"); 69462306a36Sopenharmony_ci goto error; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci data = malloc(total_buf_len); 69862306a36Sopenharmony_ci if (!data) { 69962306a36Sopenharmony_ci ret = -ENOMEM; 70062306a36Sopenharmony_ci goto error; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /** 70462306a36Sopenharmony_ci * This check is being done here for sanity reasons, however it 70562306a36Sopenharmony_ci * should be omitted under normal operation. 70662306a36Sopenharmony_ci * If this is buffer0, we check that we get EBUSY after this point. 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci if (buffer_idx == 0) { 70962306a36Sopenharmony_ci errno = 0; 71062306a36Sopenharmony_ci read_size = read(fd, data, 1); 71162306a36Sopenharmony_ci if (read_size > -1 || errno != EBUSY) { 71262306a36Sopenharmony_ci ret = -EFAULT; 71362306a36Sopenharmony_ci perror("Reading from '%s' should not be possible after ioctl()"); 71462306a36Sopenharmony_ci goto error; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* close now the main chardev FD and let the buffer FD work */ 71962306a36Sopenharmony_ci if (close(fd) == -1) 72062306a36Sopenharmony_ci perror("Failed to close character device file"); 72162306a36Sopenharmony_ci fd = -1; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci for (j = 0; j < num_loops || num_loops < 0; j++) { 72462306a36Sopenharmony_ci if (!noevents) { 72562306a36Sopenharmony_ci struct pollfd pfd = { 72662306a36Sopenharmony_ci .fd = buf_fd, 72762306a36Sopenharmony_ci .events = POLLIN, 72862306a36Sopenharmony_ci }; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ret = poll(&pfd, 1, -1); 73162306a36Sopenharmony_ci if (ret < 0) { 73262306a36Sopenharmony_ci ret = -errno; 73362306a36Sopenharmony_ci goto error; 73462306a36Sopenharmony_ci } else if (ret == 0) { 73562306a36Sopenharmony_ci continue; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci } else { 73962306a36Sopenharmony_ci usleep(timedelay); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci toread = buf_len; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci read_size = read(buf_fd, data, toread * scan_size); 74562306a36Sopenharmony_ci if (read_size < 0) { 74662306a36Sopenharmony_ci if (errno == EAGAIN) { 74762306a36Sopenharmony_ci fprintf(stderr, "nothing available\n"); 74862306a36Sopenharmony_ci continue; 74962306a36Sopenharmony_ci } else { 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci for (i = 0; i < read_size / scan_size; i++) 75462306a36Sopenharmony_ci process_scan(data + scan_size * i, channels, 75562306a36Sopenharmony_ci num_channels); 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cierror: 75962306a36Sopenharmony_ci cleanup(); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (fd >= 0 && close(fd) == -1) 76262306a36Sopenharmony_ci perror("Failed to close character device"); 76362306a36Sopenharmony_ci if (buf_fd >= 0 && close(buf_fd) == -1) 76462306a36Sopenharmony_ci perror("Failed to close buffer"); 76562306a36Sopenharmony_ci free(buffer_access); 76662306a36Sopenharmony_ci free(data); 76762306a36Sopenharmony_ci free(buf_dir_name); 76862306a36Sopenharmony_ci for (i = num_channels - 1; i >= 0; i--) { 76962306a36Sopenharmony_ci free(channels[i].name); 77062306a36Sopenharmony_ci free(channels[i].generic_name); 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci free(channels); 77362306a36Sopenharmony_ci free(trigger_name); 77462306a36Sopenharmony_ci free(device_name); 77562306a36Sopenharmony_ci free(dev_dir_name); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return ret; 77862306a36Sopenharmony_ci} 779