Part of the libiio-utilites, iio_readdev is a utility for reading buffers from connected IIO devices, and sending resutls to standard out.
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "iio_common.h"
#define MY_NAME "iio_readdev"
#define SAMPLES_PER_READ 256
#define DEFAULT_FREQ_HZ 100
static const struct option options[] = {
{"trigger", required_argument, 0, 't'},
{"buffer-size", required_argument, 0, 'b'},
{"samples", required_argument, 0, 's' },
{"timeout", required_argument, 0, 'T'},
{"auto", no_argument, 0, 'a'},
{0, 0, 0, 0},
};
static const char *options_descriptions[] = {
"[-t <trigger>] [-T <timeout-ms>] [-b <buffer-size>]"
"[-s <samples>] <iio_device> [<channel> ...]",
"Use the specified trigger.",
"Size of the capture buffer. Default is 256.",
"Number of samples to capture, 0 = infinite. Default is 0.",
"Buffer timeout in milliseconds. 0 = no timeout",
"Scan for available contexts and if only one is available use it.",
};
static const char *trigger_name = NULL;
static size_t num_samples;
static volatile sig_atomic_t app_running = true;
static int exit_code = EXIT_SUCCESS;
static void quit_all(int sig)
{
exit_code = sig;
app_running = false;
if (buffer)
}
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#include <fcntl.h>
BOOL WINAPI sig_handler_fn(DWORD dwCtrlType)
{
switch (dwCtrlType) {
case CTRL_C_EVENT:
case CTRL_CLOSE_EVENT:
quit_all(SIGTERM);
return TRUE;
default:
return FALSE;
}
}
static void setup_sig_handler(void)
{
SetConsoleCtrlHandler(sig_handler_fn, TRUE);
}
#elif NO_THREADS
static void sig_handler(int sig)
{
if (!app_running)
exit(sig);
app_running = false;
}
static void set_handler(int sig)
{
struct sigaction action;
sigaction(sig, NULL, &action);
action.sa_handler = sig_handler;
sigaction(sig, &action, NULL);
}
static void setup_sig_handler(void)
{
set_handler(SIGHUP);
set_handler(SIGPIPE);
set_handler(SIGINT);
set_handler(SIGSEGV);
set_handler(SIGTERM);
}
#else
#include <pthread.h>
static void * sig_handler_thd(void *data)
{
sigset_t *mask = data;
int ret, sig;
do {
ret = sigwait(mask, &sig);
} while (ret == EINTR);
quit_all(ret);
return NULL;
}
static void setup_sig_handler(void)
{
sigset_t mask, oldmask;
pthread_t thd;
int ret;
sigemptyset(&mask);
sigaddset(&mask, SIGHUP);
sigaddset(&mask, SIGPIPE);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGSEGV);
sigaddset(&mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &mask, &oldmask);
ret = pthread_create(&thd, NULL, sig_handler_thd, &mask);
if (ret) {
fprintf(stderr, "Failed to create signal handler thread: %d\n", ret);
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
}
}
#endif
static ssize_t print_sample(
const struct iio_channel *chn,
void *buf, size_t len, void *d)
{
fwrite(buf, 1, len, stdout);
if (num_samples != 0) {
num_samples--;
if (num_samples == 0) {
quit_all(EXIT_SUCCESS);
return -1;
}
}
return (ssize_t) len;
}
#define MY_OPTS "t:b:s:T:"
int main(int argc, char **argv)
{
char **argw;
unsigned int i, nb_channels;
unsigned int nb_active_channels = 0;
unsigned int buffer_size = SAMPLES_PER_READ;
int c;
ssize_t sample_size;
int timeout = -1;
ssize_t ret;
struct option *opts;
argw = dup_argv(MY_NAME, argc, argv);
ctx = handle_common_opts(MY_NAME, argc, argw, MY_OPTS, options, options_descriptions);
opts = add_common_options(options);
if (!opts) {
fprintf(stderr, "Failed to add common options\n");
return EXIT_FAILURE;
}
while ((c = getopt_long(argc, argw, "+" COMMON_OPTIONS MY_OPTS,
opts, NULL)) != -1) {
switch (c) {
case 'h':
case 'n':
case 'x':
case 'u':
break;
case 'S':
case 'a':
if (!optarg && argc > optind && argv[optind] != NULL
&& argv[optind][0] != '-')
optind++;
break;
case 't':
if (!optarg) {
fprintf(stderr, "Trigger requires an argument\n");
return EXIT_FAILURE;
}
trigger_name = optarg;
break;
case 'b':
if (!optarg) {
fprintf(stderr, "Buffersize requires an argument\n");
return EXIT_FAILURE;
}
buffer_size = sanitize_clamp("buffer size", optarg, 64, 4 * 1024 * 1024);
break;
case 's':
if (!optarg) {
fprintf(stderr, "Number of Samples requires an argument\n");
return EXIT_FAILURE;
}
num_samples = sanitize_clamp("number of samples", optarg, 0, SIZE_MAX);
break;
case 'T':
if (!optarg) {
fprintf(stderr, "Timeout requires an argument\n");
return EXIT_FAILURE;
}
timeout = sanitize_clamp("timeout", optarg, 0, INT_MAX);
break;
case '?':
printf("Unknown argument '%c'\n", c);
return EXIT_FAILURE;
}
}
free(opts);
if (argc == optind) {
fprintf(stderr, "Incorrect number of arguments.\n\n");
usage(MY_NAME, options, options_descriptions);
return EXIT_FAILURE;
}
if (!ctx)
return EXIT_FAILURE;
setup_sig_handler();
if (timeout >= 0) {
if (ret < 0) {
char err_str[1024];
fprintf(stderr, "IIO contexts set timeout failed : %s (%zd)\n",
err_str, ret);
}
}
if (!dev) {
fprintf(stderr, "Device %s not found\n", argw[optind]);
return EXIT_FAILURE;
}
if (trigger_name) {
ctx, trigger_name);
if (!trigger) {
fprintf(stderr, "Trigger %s not found\n", trigger_name);
return EXIT_FAILURE;
}
fprintf(stderr, "Specified device is not a trigger\n");
return EXIT_FAILURE;
}
"sampling_frequency", DEFAULT_FREQ_HZ) < 0) {
"frequency", DEFAULT_FREQ_HZ);
if (ret < 0) {
char buf[256];
fprintf(stderr, "sample rate not set : %s (%zd)\n",
buf, ret);
}
}
if (ret < 0) {
char buf[256];
fprintf(stderr, "set triffer failed : %s (%zd)\n",
buf, ret);
}
}
if (argc == optind + 1) {
for (i = 0; i < nb_channels; i++) {
nb_active_channels++;
}
}
} else {
for (i = 0; i < nb_channels; i++) {
unsigned int j;
for (j = optind + 1; j < (unsigned int) argc; j++) {
(n && !strcmp(n, argw[j]))) &&
nb_active_channels++;
}
}
}
}
if (!nb_active_channels) {
fprintf(stderr, "No input channels found.\n");
return EXIT_FAILURE;
}
if (sample_size == 0) {
fprintf(stderr, "Unable to get sample size, returned 0\n");
return EXIT_FAILURE;
} else if (sample_size < 0) {
char buf[256];
fprintf(stderr, "Unable to get sample size : %s\n", buf);
return EXIT_FAILURE;
}
if (!buffer) {
char buf[256];
fprintf(stderr, "Unable to allocate buffer: %s\n", buf);
return EXIT_FAILURE;
}
#ifdef _WIN32
_setmode(_fileno(stdout), _O_BINARY);
#endif
while (app_running) {
if (ret < 0) {
if (app_running) {
char buf[256];
fprintf(stderr, "Unable to refill buffer: %s\n", buf);
}
break;
}
- (intptr_t) start;
if (num_samples && len > num_samples * sample_size)
len = num_samples * sample_size;
for (read_len = len; len; ) {
size_t nb = fwrite(start, 1, len, stdout);
if (!nb)
goto err_destroy_buffer;
len -= nb;
start = (void *)((intptr_t) start + nb);
}
if (num_samples) {
num_samples -= read_len / sample_size;
if (!num_samples)
quit_all(EXIT_SUCCESS);
}
} else {
if (ret < 0) {
char buf[256];
fprintf(stderr, "buffer processing failed : %s (%zi)\n",
buf, ret);
}
}
}
err_destroy_buffer:
free_argw(argc, argw);
return exit_code;
}