18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Industrialio buffer test code. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008 Jonathan Cameron 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is primarily intended as an example application. 78c2ecf20Sopenharmony_ci * Reads the current buffer setup from sysfs and starts a short capture 88c2ecf20Sopenharmony_ci * from the specified device, pretty printing the result after appropriate 98c2ecf20Sopenharmony_ci * conversion. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Command line parameters 128c2ecf20Sopenharmony_ci * generic_buffer -n <device_name> -t <trigger_name> 138c2ecf20Sopenharmony_ci * If trigger name is not specified the program assumes you want a dataready 148c2ecf20Sopenharmony_ci * trigger associated with the device and goes looking for it. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <unistd.h> 188c2ecf20Sopenharmony_ci#include <stdlib.h> 198c2ecf20Sopenharmony_ci#include <dirent.h> 208c2ecf20Sopenharmony_ci#include <fcntl.h> 218c2ecf20Sopenharmony_ci#include <stdio.h> 228c2ecf20Sopenharmony_ci#include <errno.h> 238c2ecf20Sopenharmony_ci#include <sys/stat.h> 248c2ecf20Sopenharmony_ci#include <sys/dir.h> 258c2ecf20Sopenharmony_ci#include <linux/types.h> 268c2ecf20Sopenharmony_ci#include <string.h> 278c2ecf20Sopenharmony_ci#include <poll.h> 288c2ecf20Sopenharmony_ci#include <endian.h> 298c2ecf20Sopenharmony_ci#include <getopt.h> 308c2ecf20Sopenharmony_ci#include <inttypes.h> 318c2ecf20Sopenharmony_ci#include <stdbool.h> 328c2ecf20Sopenharmony_ci#include <signal.h> 338c2ecf20Sopenharmony_ci#include "iio_utils.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * enum autochan - state for the automatic channel enabling mechanism 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cienum autochan { 398c2ecf20Sopenharmony_ci AUTOCHANNELS_DISABLED, 408c2ecf20Sopenharmony_ci AUTOCHANNELS_ENABLED, 418c2ecf20Sopenharmony_ci AUTOCHANNELS_ACTIVE, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/** 458c2ecf20Sopenharmony_ci * size_from_channelarray() - calculate the storage size of a scan 468c2ecf20Sopenharmony_ci * @channels: the channel info array 478c2ecf20Sopenharmony_ci * @num_channels: number of channels 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * Has the side effect of filling the channels[i].location values used 508c2ecf20Sopenharmony_ci * in processing the buffer output. 518c2ecf20Sopenharmony_ci **/ 528c2ecf20Sopenharmony_cistatic unsigned int size_from_channelarray(struct iio_channel_info *channels, int num_channels) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci unsigned int bytes = 0; 558c2ecf20Sopenharmony_ci int i = 0, max = 0; 568c2ecf20Sopenharmony_ci unsigned int misalignment; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci while (i < num_channels) { 598c2ecf20Sopenharmony_ci if (channels[i].bytes > max) 608c2ecf20Sopenharmony_ci max = channels[i].bytes; 618c2ecf20Sopenharmony_ci if (bytes % channels[i].bytes == 0) 628c2ecf20Sopenharmony_ci channels[i].location = bytes; 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci channels[i].location = bytes - bytes % channels[i].bytes 658c2ecf20Sopenharmony_ci + channels[i].bytes; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci bytes = channels[i].location + channels[i].bytes; 688c2ecf20Sopenharmony_ci i++; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci /* 718c2ecf20Sopenharmony_ci * We want the data in next sample to also be properly aligned so 728c2ecf20Sopenharmony_ci * we'll add padding at the end if needed. Adding padding only 738c2ecf20Sopenharmony_ci * works for channel data which size is 2^n bytes. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci misalignment = bytes % max; 768c2ecf20Sopenharmony_ci if (misalignment) 778c2ecf20Sopenharmony_ci bytes += max - misalignment; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return bytes; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void print1byte(uint8_t input, struct iio_channel_info *info) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci /* 858c2ecf20Sopenharmony_ci * Shift before conversion to avoid sign extension 868c2ecf20Sopenharmony_ci * of left aligned data 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci input >>= info->shift; 898c2ecf20Sopenharmony_ci input &= info->mask; 908c2ecf20Sopenharmony_ci if (info->is_signed) { 918c2ecf20Sopenharmony_ci int8_t val = (int8_t)(input << (8 - info->bits_used)) >> 928c2ecf20Sopenharmony_ci (8 - info->bits_used); 938c2ecf20Sopenharmony_ci printf("%05f ", ((float)val + info->offset) * info->scale); 948c2ecf20Sopenharmony_ci } else { 958c2ecf20Sopenharmony_ci printf("%05f ", ((float)input + info->offset) * info->scale); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void print2byte(uint16_t input, struct iio_channel_info *info) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci /* First swap if incorrect endian */ 1028c2ecf20Sopenharmony_ci if (info->be) 1038c2ecf20Sopenharmony_ci input = be16toh(input); 1048c2ecf20Sopenharmony_ci else 1058c2ecf20Sopenharmony_ci input = le16toh(input); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* 1088c2ecf20Sopenharmony_ci * Shift before conversion to avoid sign extension 1098c2ecf20Sopenharmony_ci * of left aligned data 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci input >>= info->shift; 1128c2ecf20Sopenharmony_ci input &= info->mask; 1138c2ecf20Sopenharmony_ci if (info->is_signed) { 1148c2ecf20Sopenharmony_ci int16_t val = (int16_t)(input << (16 - info->bits_used)) >> 1158c2ecf20Sopenharmony_ci (16 - info->bits_used); 1168c2ecf20Sopenharmony_ci printf("%05f ", ((float)val + info->offset) * info->scale); 1178c2ecf20Sopenharmony_ci } else { 1188c2ecf20Sopenharmony_ci printf("%05f ", ((float)input + info->offset) * info->scale); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void print4byte(uint32_t input, struct iio_channel_info *info) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci /* First swap if incorrect endian */ 1258c2ecf20Sopenharmony_ci if (info->be) 1268c2ecf20Sopenharmony_ci input = be32toh(input); 1278c2ecf20Sopenharmony_ci else 1288c2ecf20Sopenharmony_ci input = le32toh(input); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * Shift before conversion to avoid sign extension 1328c2ecf20Sopenharmony_ci * of left aligned data 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci input >>= info->shift; 1358c2ecf20Sopenharmony_ci input &= info->mask; 1368c2ecf20Sopenharmony_ci if (info->is_signed) { 1378c2ecf20Sopenharmony_ci int32_t val = (int32_t)(input << (32 - info->bits_used)) >> 1388c2ecf20Sopenharmony_ci (32 - info->bits_used); 1398c2ecf20Sopenharmony_ci printf("%05f ", ((float)val + info->offset) * info->scale); 1408c2ecf20Sopenharmony_ci } else { 1418c2ecf20Sopenharmony_ci printf("%05f ", ((float)input + info->offset) * info->scale); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void print8byte(uint64_t input, struct iio_channel_info *info) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci /* First swap if incorrect endian */ 1488c2ecf20Sopenharmony_ci if (info->be) 1498c2ecf20Sopenharmony_ci input = be64toh(input); 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci input = le64toh(input); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * Shift before conversion to avoid sign extension 1558c2ecf20Sopenharmony_ci * of left aligned data 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci input >>= info->shift; 1588c2ecf20Sopenharmony_ci input &= info->mask; 1598c2ecf20Sopenharmony_ci if (info->is_signed) { 1608c2ecf20Sopenharmony_ci int64_t val = (int64_t)(input << (64 - info->bits_used)) >> 1618c2ecf20Sopenharmony_ci (64 - info->bits_used); 1628c2ecf20Sopenharmony_ci /* special case for timestamp */ 1638c2ecf20Sopenharmony_ci if (info->scale == 1.0f && info->offset == 0.0f) 1648c2ecf20Sopenharmony_ci printf("%" PRId64 " ", val); 1658c2ecf20Sopenharmony_ci else 1668c2ecf20Sopenharmony_ci printf("%05f ", 1678c2ecf20Sopenharmony_ci ((float)val + info->offset) * info->scale); 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci printf("%05f ", ((float)input + info->offset) * info->scale); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * process_scan() - print out the values in SI units 1758c2ecf20Sopenharmony_ci * @data: pointer to the start of the scan 1768c2ecf20Sopenharmony_ci * @channels: information about the channels. 1778c2ecf20Sopenharmony_ci * Note: size_from_channelarray must have been called first 1788c2ecf20Sopenharmony_ci * to fill the location offsets. 1798c2ecf20Sopenharmony_ci * @num_channels: number of channels 1808c2ecf20Sopenharmony_ci **/ 1818c2ecf20Sopenharmony_cistatic void process_scan(char *data, struct iio_channel_info *channels, 1828c2ecf20Sopenharmony_ci int num_channels) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci int k; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci for (k = 0; k < num_channels; k++) 1878c2ecf20Sopenharmony_ci switch (channels[k].bytes) { 1888c2ecf20Sopenharmony_ci /* only a few cases implemented so far */ 1898c2ecf20Sopenharmony_ci case 1: 1908c2ecf20Sopenharmony_ci print1byte(*(uint8_t *)(data + channels[k].location), 1918c2ecf20Sopenharmony_ci &channels[k]); 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci case 2: 1948c2ecf20Sopenharmony_ci print2byte(*(uint16_t *)(data + channels[k].location), 1958c2ecf20Sopenharmony_ci &channels[k]); 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci case 4: 1988c2ecf20Sopenharmony_ci print4byte(*(uint32_t *)(data + channels[k].location), 1998c2ecf20Sopenharmony_ci &channels[k]); 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci case 8: 2028c2ecf20Sopenharmony_ci print8byte(*(uint64_t *)(data + channels[k].location), 2038c2ecf20Sopenharmony_ci &channels[k]); 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci default: 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci printf("\n"); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int enable_disable_all_channels(char *dev_dir_name, int enable) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci const struct dirent *ent; 2148c2ecf20Sopenharmony_ci char scanelemdir[256]; 2158c2ecf20Sopenharmony_ci DIR *dp; 2168c2ecf20Sopenharmony_ci int ret; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci snprintf(scanelemdir, sizeof(scanelemdir), 2198c2ecf20Sopenharmony_ci FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); 2208c2ecf20Sopenharmony_ci scanelemdir[sizeof(scanelemdir)-1] = '\0'; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci dp = opendir(scanelemdir); 2238c2ecf20Sopenharmony_ci if (!dp) { 2248c2ecf20Sopenharmony_ci fprintf(stderr, "Enabling/disabling channels: can't open %s\n", 2258c2ecf20Sopenharmony_ci scanelemdir); 2268c2ecf20Sopenharmony_ci return -EIO; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ret = -ENOENT; 2308c2ecf20Sopenharmony_ci while (ent = readdir(dp), ent) { 2318c2ecf20Sopenharmony_ci if (iioutils_check_suffix(ent->d_name, "_en")) { 2328c2ecf20Sopenharmony_ci printf("%sabling: %s\n", 2338c2ecf20Sopenharmony_ci enable ? "En" : "Dis", 2348c2ecf20Sopenharmony_ci ent->d_name); 2358c2ecf20Sopenharmony_ci ret = write_sysfs_int(ent->d_name, scanelemdir, 2368c2ecf20Sopenharmony_ci enable); 2378c2ecf20Sopenharmony_ci if (ret < 0) 2388c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to enable/disable %s\n", 2398c2ecf20Sopenharmony_ci ent->d_name); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (closedir(dp) == -1) { 2448c2ecf20Sopenharmony_ci perror("Enabling/disabling channels: " 2458c2ecf20Sopenharmony_ci "Failed to close directory"); 2468c2ecf20Sopenharmony_ci return -errno; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void print_usage(void) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci fprintf(stderr, "Usage: generic_buffer [options]...\n" 2548c2ecf20Sopenharmony_ci "Capture, convert and output data from IIO device buffer\n" 2558c2ecf20Sopenharmony_ci " -a Auto-activate all available channels\n" 2568c2ecf20Sopenharmony_ci " -A Force-activate ALL channels\n" 2578c2ecf20Sopenharmony_ci " -c <n> Do n conversions, or loop forever if n < 0\n" 2588c2ecf20Sopenharmony_ci " -e Disable wait for event (new data)\n" 2598c2ecf20Sopenharmony_ci " -g Use trigger-less mode\n" 2608c2ecf20Sopenharmony_ci " -l <n> Set buffer length to n samples\n" 2618c2ecf20Sopenharmony_ci " --device-name -n <name>\n" 2628c2ecf20Sopenharmony_ci " --device-num -N <num>\n" 2638c2ecf20Sopenharmony_ci " Set device by name or number (mandatory)\n" 2648c2ecf20Sopenharmony_ci " --trigger-name -t <name>\n" 2658c2ecf20Sopenharmony_ci " --trigger-num -T <num>\n" 2668c2ecf20Sopenharmony_ci " Set trigger by name or number\n" 2678c2ecf20Sopenharmony_ci " -w <n> Set delay between reads in us (event-less mode)\n"); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic enum autochan autochannels = AUTOCHANNELS_DISABLED; 2718c2ecf20Sopenharmony_cistatic char *dev_dir_name = NULL; 2728c2ecf20Sopenharmony_cistatic char *buf_dir_name = NULL; 2738c2ecf20Sopenharmony_cistatic bool current_trigger_set = false; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void cleanup(void) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Disable trigger */ 2808c2ecf20Sopenharmony_ci if (dev_dir_name && current_trigger_set) { 2818c2ecf20Sopenharmony_ci /* Disconnect the trigger - just write a dummy name. */ 2828c2ecf20Sopenharmony_ci ret = write_sysfs_string("trigger/current_trigger", 2838c2ecf20Sopenharmony_ci dev_dir_name, "NULL"); 2848c2ecf20Sopenharmony_ci if (ret < 0) 2858c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to disable trigger: %s\n", 2868c2ecf20Sopenharmony_ci strerror(-ret)); 2878c2ecf20Sopenharmony_ci current_trigger_set = false; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Disable buffer */ 2918c2ecf20Sopenharmony_ci if (buf_dir_name) { 2928c2ecf20Sopenharmony_ci ret = write_sysfs_int("enable", buf_dir_name, 0); 2938c2ecf20Sopenharmony_ci if (ret < 0) 2948c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to disable buffer: %s\n", 2958c2ecf20Sopenharmony_ci strerror(-ret)); 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Disable channels if auto-enabled */ 2998c2ecf20Sopenharmony_ci if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { 3008c2ecf20Sopenharmony_ci ret = enable_disable_all_channels(dev_dir_name, 0); 3018c2ecf20Sopenharmony_ci if (ret) 3028c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to disable all channels\n"); 3038c2ecf20Sopenharmony_ci autochannels = AUTOCHANNELS_DISABLED; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void sig_handler(int signum) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci fprintf(stderr, "Caught signal %d\n", signum); 3108c2ecf20Sopenharmony_ci cleanup(); 3118c2ecf20Sopenharmony_ci exit(-signum); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic void register_cleanup(void) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct sigaction sa = { .sa_handler = sig_handler }; 3178c2ecf20Sopenharmony_ci const int signums[] = { SIGINT, SIGTERM, SIGABRT }; 3188c2ecf20Sopenharmony_ci int ret, i; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(signums); ++i) { 3218c2ecf20Sopenharmony_ci ret = sigaction(signums[i], &sa, NULL); 3228c2ecf20Sopenharmony_ci if (ret) { 3238c2ecf20Sopenharmony_ci perror("Failed to register signal handler"); 3248c2ecf20Sopenharmony_ci exit(-1); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic const struct option longopts[] = { 3308c2ecf20Sopenharmony_ci { "device-name", 1, 0, 'n' }, 3318c2ecf20Sopenharmony_ci { "device-num", 1, 0, 'N' }, 3328c2ecf20Sopenharmony_ci { "trigger-name", 1, 0, 't' }, 3338c2ecf20Sopenharmony_ci { "trigger-num", 1, 0, 'T' }, 3348c2ecf20Sopenharmony_ci { }, 3358c2ecf20Sopenharmony_ci}; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciint main(int argc, char **argv) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci long long num_loops = 2; 3408c2ecf20Sopenharmony_ci unsigned long timedelay = 1000000; 3418c2ecf20Sopenharmony_ci unsigned long buf_len = 128; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ssize_t i; 3448c2ecf20Sopenharmony_ci unsigned long long j; 3458c2ecf20Sopenharmony_ci unsigned long toread; 3468c2ecf20Sopenharmony_ci int ret, c; 3478c2ecf20Sopenharmony_ci int fp = -1; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci int num_channels = 0; 3508c2ecf20Sopenharmony_ci char *trigger_name = NULL, *device_name = NULL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci char *data = NULL; 3538c2ecf20Sopenharmony_ci ssize_t read_size; 3548c2ecf20Sopenharmony_ci int dev_num = -1, trig_num = -1; 3558c2ecf20Sopenharmony_ci char *buffer_access = NULL; 3568c2ecf20Sopenharmony_ci unsigned int scan_size; 3578c2ecf20Sopenharmony_ci int noevents = 0; 3588c2ecf20Sopenharmony_ci int notrigger = 0; 3598c2ecf20Sopenharmony_ci char *dummy; 3608c2ecf20Sopenharmony_ci bool force_autochannels = false; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci struct iio_channel_info *channels = NULL; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci register_cleanup(); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, 3678c2ecf20Sopenharmony_ci NULL)) != -1) { 3688c2ecf20Sopenharmony_ci switch (c) { 3698c2ecf20Sopenharmony_ci case 'a': 3708c2ecf20Sopenharmony_ci autochannels = AUTOCHANNELS_ENABLED; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci case 'A': 3738c2ecf20Sopenharmony_ci autochannels = AUTOCHANNELS_ENABLED; 3748c2ecf20Sopenharmony_ci force_autochannels = true; 3758c2ecf20Sopenharmony_ci break; 3768c2ecf20Sopenharmony_ci case 'c': 3778c2ecf20Sopenharmony_ci errno = 0; 3788c2ecf20Sopenharmony_ci num_loops = strtoll(optarg, &dummy, 10); 3798c2ecf20Sopenharmony_ci if (errno) { 3808c2ecf20Sopenharmony_ci ret = -errno; 3818c2ecf20Sopenharmony_ci goto error; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci case 'e': 3868c2ecf20Sopenharmony_ci noevents = 1; 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci case 'g': 3898c2ecf20Sopenharmony_ci notrigger = 1; 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci case 'l': 3928c2ecf20Sopenharmony_ci errno = 0; 3938c2ecf20Sopenharmony_ci buf_len = strtoul(optarg, &dummy, 10); 3948c2ecf20Sopenharmony_ci if (errno) { 3958c2ecf20Sopenharmony_ci ret = -errno; 3968c2ecf20Sopenharmony_ci goto error; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci case 'n': 4018c2ecf20Sopenharmony_ci device_name = strdup(optarg); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci case 'N': 4048c2ecf20Sopenharmony_ci errno = 0; 4058c2ecf20Sopenharmony_ci dev_num = strtoul(optarg, &dummy, 10); 4068c2ecf20Sopenharmony_ci if (errno) { 4078c2ecf20Sopenharmony_ci ret = -errno; 4088c2ecf20Sopenharmony_ci goto error; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci case 't': 4128c2ecf20Sopenharmony_ci trigger_name = strdup(optarg); 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci case 'T': 4158c2ecf20Sopenharmony_ci errno = 0; 4168c2ecf20Sopenharmony_ci trig_num = strtoul(optarg, &dummy, 10); 4178c2ecf20Sopenharmony_ci if (errno) 4188c2ecf20Sopenharmony_ci return -errno; 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci case 'w': 4218c2ecf20Sopenharmony_ci errno = 0; 4228c2ecf20Sopenharmony_ci timedelay = strtoul(optarg, &dummy, 10); 4238c2ecf20Sopenharmony_ci if (errno) { 4248c2ecf20Sopenharmony_ci ret = -errno; 4258c2ecf20Sopenharmony_ci goto error; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci case '?': 4298c2ecf20Sopenharmony_ci print_usage(); 4308c2ecf20Sopenharmony_ci ret = -1; 4318c2ecf20Sopenharmony_ci goto error; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Find the device requested */ 4368c2ecf20Sopenharmony_ci if (dev_num < 0 && !device_name) { 4378c2ecf20Sopenharmony_ci fprintf(stderr, "Device not set\n"); 4388c2ecf20Sopenharmony_ci print_usage(); 4398c2ecf20Sopenharmony_ci ret = -1; 4408c2ecf20Sopenharmony_ci goto error; 4418c2ecf20Sopenharmony_ci } else if (dev_num >= 0 && device_name) { 4428c2ecf20Sopenharmony_ci fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n"); 4438c2ecf20Sopenharmony_ci print_usage(); 4448c2ecf20Sopenharmony_ci ret = -1; 4458c2ecf20Sopenharmony_ci goto error; 4468c2ecf20Sopenharmony_ci } else if (dev_num < 0) { 4478c2ecf20Sopenharmony_ci dev_num = find_type_by_name(device_name, "iio:device"); 4488c2ecf20Sopenharmony_ci if (dev_num < 0) { 4498c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to find the %s\n", device_name); 4508c2ecf20Sopenharmony_ci ret = dev_num; 4518c2ecf20Sopenharmony_ci goto error; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci printf("iio device number being used is %d\n", dev_num); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); 4578c2ecf20Sopenharmony_ci if (ret < 0) 4588c2ecf20Sopenharmony_ci return -ENOMEM; 4598c2ecf20Sopenharmony_ci /* Fetch device_name if specified by number */ 4608c2ecf20Sopenharmony_ci if (!device_name) { 4618c2ecf20Sopenharmony_ci device_name = malloc(IIO_MAX_NAME_LENGTH); 4628c2ecf20Sopenharmony_ci if (!device_name) { 4638c2ecf20Sopenharmony_ci ret = -ENOMEM; 4648c2ecf20Sopenharmony_ci goto error; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci ret = read_sysfs_string("name", dev_dir_name, device_name); 4678c2ecf20Sopenharmony_ci if (ret < 0) { 4688c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to read name of device %d\n", dev_num); 4698c2ecf20Sopenharmony_ci goto error; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (notrigger) { 4748c2ecf20Sopenharmony_ci printf("trigger-less mode selected\n"); 4758c2ecf20Sopenharmony_ci } else if (trig_num >= 0) { 4768c2ecf20Sopenharmony_ci char *trig_dev_name; 4778c2ecf20Sopenharmony_ci ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); 4788c2ecf20Sopenharmony_ci if (ret < 0) { 4798c2ecf20Sopenharmony_ci return -ENOMEM; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci trigger_name = malloc(IIO_MAX_NAME_LENGTH); 4828c2ecf20Sopenharmony_ci ret = read_sysfs_string("name", trig_dev_name, trigger_name); 4838c2ecf20Sopenharmony_ci free(trig_dev_name); 4848c2ecf20Sopenharmony_ci if (ret < 0) { 4858c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to read trigger%d name from\n", trig_num); 4868c2ecf20Sopenharmony_ci return ret; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci printf("iio trigger number being used is %d\n", trig_num); 4898c2ecf20Sopenharmony_ci } else { 4908c2ecf20Sopenharmony_ci if (!trigger_name) { 4918c2ecf20Sopenharmony_ci /* 4928c2ecf20Sopenharmony_ci * Build the trigger name. If it is device associated 4938c2ecf20Sopenharmony_ci * its name is <device_name>_dev[n] where n matches 4948c2ecf20Sopenharmony_ci * the device number found above. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci ret = asprintf(&trigger_name, 4978c2ecf20Sopenharmony_ci "%s-dev%d", device_name, dev_num); 4988c2ecf20Sopenharmony_ci if (ret < 0) { 4998c2ecf20Sopenharmony_ci ret = -ENOMEM; 5008c2ecf20Sopenharmony_ci goto error; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Look for this "-devN" trigger */ 5058c2ecf20Sopenharmony_ci trig_num = find_type_by_name(trigger_name, "trigger"); 5068c2ecf20Sopenharmony_ci if (trig_num < 0) { 5078c2ecf20Sopenharmony_ci /* OK try the simpler "-trigger" suffix instead */ 5088c2ecf20Sopenharmony_ci free(trigger_name); 5098c2ecf20Sopenharmony_ci ret = asprintf(&trigger_name, 5108c2ecf20Sopenharmony_ci "%s-trigger", device_name); 5118c2ecf20Sopenharmony_ci if (ret < 0) { 5128c2ecf20Sopenharmony_ci ret = -ENOMEM; 5138c2ecf20Sopenharmony_ci goto error; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci trig_num = find_type_by_name(trigger_name, "trigger"); 5188c2ecf20Sopenharmony_ci if (trig_num < 0) { 5198c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to find the trigger %s\n", 5208c2ecf20Sopenharmony_ci trigger_name); 5218c2ecf20Sopenharmony_ci ret = trig_num; 5228c2ecf20Sopenharmony_ci goto error; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci printf("iio trigger number being used is %d\n", trig_num); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* 5298c2ecf20Sopenharmony_ci * Parse the files in scan_elements to identify what channels are 5308c2ecf20Sopenharmony_ci * present 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_ci ret = build_channel_array(dev_dir_name, &channels, &num_channels); 5338c2ecf20Sopenharmony_ci if (ret) { 5348c2ecf20Sopenharmony_ci fprintf(stderr, "Problem reading scan element information\n" 5358c2ecf20Sopenharmony_ci "diag %s\n", dev_dir_name); 5368c2ecf20Sopenharmony_ci goto error; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci if (num_channels && autochannels == AUTOCHANNELS_ENABLED && 5398c2ecf20Sopenharmony_ci !force_autochannels) { 5408c2ecf20Sopenharmony_ci fprintf(stderr, "Auto-channels selected but some channels " 5418c2ecf20Sopenharmony_ci "are already activated in sysfs\n"); 5428c2ecf20Sopenharmony_ci fprintf(stderr, "Proceeding without activating any channels\n"); 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || 5468c2ecf20Sopenharmony_ci (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { 5478c2ecf20Sopenharmony_ci fprintf(stderr, "Enabling all channels\n"); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci ret = enable_disable_all_channels(dev_dir_name, 1); 5508c2ecf20Sopenharmony_ci if (ret) { 5518c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to enable all channels\n"); 5528c2ecf20Sopenharmony_ci goto error; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* This flags that we need to disable the channels again */ 5568c2ecf20Sopenharmony_ci autochannels = AUTOCHANNELS_ACTIVE; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = build_channel_array(dev_dir_name, &channels, 5598c2ecf20Sopenharmony_ci &num_channels); 5608c2ecf20Sopenharmony_ci if (ret) { 5618c2ecf20Sopenharmony_ci fprintf(stderr, "Problem reading scan element " 5628c2ecf20Sopenharmony_ci "information\n" 5638c2ecf20Sopenharmony_ci "diag %s\n", dev_dir_name); 5648c2ecf20Sopenharmony_ci goto error; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci if (!num_channels) { 5678c2ecf20Sopenharmony_ci fprintf(stderr, "Still no channels after " 5688c2ecf20Sopenharmony_ci "auto-enabling, giving up\n"); 5698c2ecf20Sopenharmony_ci goto error; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { 5748c2ecf20Sopenharmony_ci fprintf(stderr, 5758c2ecf20Sopenharmony_ci "No channels are enabled, we have nothing to scan.\n"); 5768c2ecf20Sopenharmony_ci fprintf(stderr, "Enable channels manually in " 5778c2ecf20Sopenharmony_ci FORMAT_SCAN_ELEMENTS_DIR 5788c2ecf20Sopenharmony_ci "/*_en or pass -a to autoenable channels and " 5798c2ecf20Sopenharmony_ci "try again.\n", dev_dir_name); 5808c2ecf20Sopenharmony_ci ret = -ENOENT; 5818c2ecf20Sopenharmony_ci goto error; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* 5858c2ecf20Sopenharmony_ci * Construct the directory name for the associated buffer. 5868c2ecf20Sopenharmony_ci * As we know that the lis3l02dq has only one buffer this may 5878c2ecf20Sopenharmony_ci * be built rather than found. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci ret = asprintf(&buf_dir_name, 5908c2ecf20Sopenharmony_ci "%siio:device%d/buffer", iio_dir, dev_num); 5918c2ecf20Sopenharmony_ci if (ret < 0) { 5928c2ecf20Sopenharmony_ci ret = -ENOMEM; 5938c2ecf20Sopenharmony_ci goto error; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (!notrigger) { 5978c2ecf20Sopenharmony_ci printf("%s %s\n", dev_dir_name, trigger_name); 5988c2ecf20Sopenharmony_ci /* 5998c2ecf20Sopenharmony_ci * Set the device trigger to be the data ready trigger found 6008c2ecf20Sopenharmony_ci * above 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci ret = write_sysfs_string_and_verify("trigger/current_trigger", 6038c2ecf20Sopenharmony_ci dev_dir_name, 6048c2ecf20Sopenharmony_ci trigger_name); 6058c2ecf20Sopenharmony_ci if (ret < 0) { 6068c2ecf20Sopenharmony_ci fprintf(stderr, 6078c2ecf20Sopenharmony_ci "Failed to write current_trigger file\n"); 6088c2ecf20Sopenharmony_ci goto error; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* Setup ring buffer parameters */ 6138c2ecf20Sopenharmony_ci ret = write_sysfs_int("length", buf_dir_name, buf_len); 6148c2ecf20Sopenharmony_ci if (ret < 0) 6158c2ecf20Sopenharmony_ci goto error; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Enable the buffer */ 6188c2ecf20Sopenharmony_ci ret = write_sysfs_int("enable", buf_dir_name, 1); 6198c2ecf20Sopenharmony_ci if (ret < 0) { 6208c2ecf20Sopenharmony_ci fprintf(stderr, 6218c2ecf20Sopenharmony_ci "Failed to enable buffer: %s\n", strerror(-ret)); 6228c2ecf20Sopenharmony_ci goto error; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci scan_size = size_from_channelarray(channels, num_channels); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci size_t total_buf_len = scan_size * buf_len; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (scan_size > 0 && total_buf_len / scan_size != buf_len) { 6308c2ecf20Sopenharmony_ci ret = -EFAULT; 6318c2ecf20Sopenharmony_ci perror("Integer overflow happened when calculate scan_size * buf_len"); 6328c2ecf20Sopenharmony_ci goto error; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci data = malloc(total_buf_len); 6368c2ecf20Sopenharmony_ci if (!data) { 6378c2ecf20Sopenharmony_ci ret = -ENOMEM; 6388c2ecf20Sopenharmony_ci goto error; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); 6428c2ecf20Sopenharmony_ci if (ret < 0) { 6438c2ecf20Sopenharmony_ci ret = -ENOMEM; 6448c2ecf20Sopenharmony_ci goto error; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Attempt to open non blocking the access dev */ 6488c2ecf20Sopenharmony_ci fp = open(buffer_access, O_RDONLY | O_NONBLOCK); 6498c2ecf20Sopenharmony_ci if (fp == -1) { /* TODO: If it isn't there make the node */ 6508c2ecf20Sopenharmony_ci ret = -errno; 6518c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to open %s\n", buffer_access); 6528c2ecf20Sopenharmony_ci goto error; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci for (j = 0; j < num_loops || num_loops < 0; j++) { 6568c2ecf20Sopenharmony_ci if (!noevents) { 6578c2ecf20Sopenharmony_ci struct pollfd pfd = { 6588c2ecf20Sopenharmony_ci .fd = fp, 6598c2ecf20Sopenharmony_ci .events = POLLIN, 6608c2ecf20Sopenharmony_ci }; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci ret = poll(&pfd, 1, -1); 6638c2ecf20Sopenharmony_ci if (ret < 0) { 6648c2ecf20Sopenharmony_ci ret = -errno; 6658c2ecf20Sopenharmony_ci goto error; 6668c2ecf20Sopenharmony_ci } else if (ret == 0) { 6678c2ecf20Sopenharmony_ci continue; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci toread = buf_len; 6718c2ecf20Sopenharmony_ci } else { 6728c2ecf20Sopenharmony_ci usleep(timedelay); 6738c2ecf20Sopenharmony_ci toread = 64; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci read_size = read(fp, data, toread * scan_size); 6778c2ecf20Sopenharmony_ci if (read_size < 0) { 6788c2ecf20Sopenharmony_ci if (errno == EAGAIN) { 6798c2ecf20Sopenharmony_ci fprintf(stderr, "nothing available\n"); 6808c2ecf20Sopenharmony_ci continue; 6818c2ecf20Sopenharmony_ci } else { 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci for (i = 0; i < read_size / scan_size; i++) 6868c2ecf20Sopenharmony_ci process_scan(data + scan_size * i, channels, 6878c2ecf20Sopenharmony_ci num_channels); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cierror: 6918c2ecf20Sopenharmony_ci cleanup(); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (fp >= 0 && close(fp) == -1) 6948c2ecf20Sopenharmony_ci perror("Failed to close buffer"); 6958c2ecf20Sopenharmony_ci free(buffer_access); 6968c2ecf20Sopenharmony_ci free(data); 6978c2ecf20Sopenharmony_ci free(buf_dir_name); 6988c2ecf20Sopenharmony_ci for (i = num_channels - 1; i >= 0; i--) { 6998c2ecf20Sopenharmony_ci free(channels[i].name); 7008c2ecf20Sopenharmony_ci free(channels[i].generic_name); 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci free(channels); 7038c2ecf20Sopenharmony_ci free(trigger_name); 7048c2ecf20Sopenharmony_ci free(device_name); 7058c2ecf20Sopenharmony_ci free(dev_dir_name); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci return ret; 7088c2ecf20Sopenharmony_ci} 709