From 1911bf61dcf2626b4b9d1f3d0338ea9afde06bfa Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Wed, 31 Aug 2016 11:45:08 -0700 Subject: [PATCH 1/9] docs: clarify purpose of return value in callback --- iio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iio.h b/iio.h index 7100d955e..84527cd8d 100644 --- a/iio.h +++ b/iio.h @@ -1174,6 +1174,7 @@ __api void * iio_buffer_end(const struct iio_buffer *buf); * @param buf A pointer to an iio_buffer structure * @param callback A pointer to a function to call for each sample found * @param data A user-specified pointer that will be passed to the callback + * @return number of bytes processed. * * NOTE: The callback receives four arguments: * * A pointer to the iio_channel structure corresponding to the sample, From d66ff3fdea2e655b855e7ecf77802cededcfc545 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Mon, 29 Aug 2016 13:47:29 -0700 Subject: [PATCH 2/9] iio: support repeated channels Linux struct iio_chan_spec supports a 'repeat' scan_type attribute that represents the number of times the element repeats. Note that a value of 0 and 1 signifies no repeat. --- buffer.c | 6 +++-- channel.c | 77 ++++++++++++++++++++++++++++++++++++------------------- device.c | 3 ++- iio.h | 3 +++ local.c | 9 ++++++- xml.c | 11 +++++++- 6 files changed, 77 insertions(+), 32 deletions(-) diff --git a/buffer.c b/buffer.c index 7b84cd5bb..c9fe5fb6e 100644 --- a/buffer.c +++ b/buffer.c @@ -236,7 +236,8 @@ ssize_t iio_buffer_foreach_sample(struct iio_buffer *buffer, processed += ret; } - ptr += length; + ptr += length * + (chn->format.repeat ? chn->format.repeat : 1); } } return processed; @@ -259,7 +260,8 @@ void * iio_buffer_first(const struct iio_buffer *buffer, for (i = 0; i < buffer->dev->nb_channels; i++) { struct iio_channel *cur = buffer->dev->channels[i]; - len = cur->format.length / 8; + len = cur->format.length / 8 * + (cur->format.repeat ? cur->format.repeat : 1); /* NOTE: dev->channels are ordered by index */ if (cur->index < 0 || cur->index == chn->index) diff --git a/channel.c b/channel.c index 54533fae6..bc27323cb 100644 --- a/channel.c +++ b/channel.c @@ -184,14 +184,17 @@ static char *get_attr_xml(struct iio_channel_attr *attr, size_t *length) static char * get_scan_element(const struct iio_channel *chn, size_t *length) { - char buf[1024], *str; + char buf[1024], repeat[8] = "", *str; char processed = (chn->format.is_fully_defined ? 'A' - 'a' : 0); + if (chn->format.repeat) + snprintf(repeat, sizeof(repeat), "X%u", chn->format.repeat); + snprintf(buf, sizeof(buf), "", + "format=\"%ce:%c%u/%u%s>>%u\" />", chn->index, chn->format.is_be ? 'b' : 'l', chn->format.is_signed ? 's' + processed : 'u' + processed, - chn->format.bits, chn->format.length, + chn->format.bits, chn->format.length, repeat, chn->format.shift); if (chn->format.with_scale) { @@ -519,33 +522,46 @@ static void mask_upper_bits(uint8_t *dst, size_t bits, size_t len) void iio_channel_convert(const struct iio_channel *chn, void *dst, const void *src) { + uintptr_t src_ptr = (uintptr_t) src, dst_ptr = (uintptr_t) dst; unsigned int len = chn->format.length / 8; + ptrdiff_t end = len * (chn->format.repeat ? chn->format.repeat : 1); + uintptr_t end_ptr = src_ptr + end; #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ bool swap = chn->format.is_be; #else bool swap = !chn->format.is_be; #endif - if (len == 1 || !swap) - memcpy(dst, src, len); - else - byte_swap(dst, src, len); - - if (chn->format.shift) - shift_bits(dst, chn->format.shift, len, false); - - if (!chn->format.is_fully_defined) { - if (chn->format.is_signed) - sign_extend(dst, chn->format.bits, len); + for (src_ptr = (uintptr_t) src; src_ptr < end_ptr; + src_ptr += len, dst_ptr += len) { + if (len == 1 || !swap) + memcpy((void *) dst_ptr, (const void *) src_ptr, len); else - mask_upper_bits(dst, chn->format.bits, len); + byte_swap((void *) dst_ptr, (const void *) src_ptr, + len); + + if (chn->format.shift) + shift_bits((void *) dst_ptr, chn->format.shift, len, + false); + + if (!chn->format.is_fully_defined) { + if (chn->format.is_signed) + sign_extend((void *) dst_ptr, + chn->format.bits, len); + else + mask_upper_bits((void *) dst_ptr, + chn->format.bits, len); + } } } void iio_channel_convert_inverse(const struct iio_channel *chn, void *dst, const void *src) { + uintptr_t src_ptr = (uintptr_t) src, dst_ptr = (uintptr_t) dst; unsigned int len = chn->format.length / 8; + ptrdiff_t end = len * (chn->format.repeat ? chn->format.repeat : 1); + uintptr_t end_ptr = dst_ptr + end; #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ bool swap = chn->format.is_be; #else @@ -557,23 +573,27 @@ void iio_channel_convert_inverse(const struct iio_channel *chn, if (len > sizeof(buf)) return; - memcpy(buf, src, len); - mask_upper_bits(buf, chn->format.bits, len); + for (dst_ptr = (uintptr_t) dst; dst_ptr < end_ptr; + src_ptr += len, dst_ptr += len) { + memcpy(buf, (const void *) src_ptr, len); + mask_upper_bits(buf, chn->format.bits, len); - if (chn->format.shift) - shift_bits(buf, chn->format.shift, len, true); + if (chn->format.shift) + shift_bits(buf, chn->format.shift, len, true); - if (len == 1 || !swap) - memcpy(dst, buf, len); - else - byte_swap(dst, buf, len); + if (len == 1 || !swap) + memcpy((void *) dst_ptr, buf, len); + else + byte_swap((void *) dst_ptr, buf, len); + } } size_t iio_channel_read_raw(const struct iio_channel *chn, struct iio_buffer *buf, void *dst, size_t len) { uintptr_t src_ptr, dst_ptr = (uintptr_t) dst, end = dst_ptr + len; - unsigned int length = chn->format.length / 8; + unsigned int length = chn->format.length / 8 * + (chn->format.repeat ? chn->format.repeat : 1); uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf); ptrdiff_t buf_step = iio_buffer_step(buf); @@ -588,7 +608,8 @@ size_t iio_channel_read(const struct iio_channel *chn, struct iio_buffer *buf, void *dst, size_t len) { uintptr_t src_ptr, dst_ptr = (uintptr_t) dst, end = dst_ptr + len; - unsigned int length = chn->format.length / 8; + unsigned int length = chn->format.length / 8 * + (chn->format.repeat ? chn->format.repeat : 1); uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf); ptrdiff_t buf_step = iio_buffer_step(buf); @@ -604,7 +625,8 @@ size_t iio_channel_write_raw(const struct iio_channel *chn, struct iio_buffer *buf, const void *src, size_t len) { uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len; - unsigned int length = chn->format.length / 8; + unsigned int length = chn->format.length / 8 * + (chn->format.repeat ? chn->format.repeat : 1); uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf); ptrdiff_t buf_step = iio_buffer_step(buf); @@ -619,7 +641,8 @@ size_t iio_channel_write(const struct iio_channel *chn, struct iio_buffer *buf, const void *src, size_t len) { uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len; - unsigned int length = chn->format.length / 8; + unsigned int length = chn->format.length / 8 * + (chn->format.repeat ? chn->format.repeat : 1); uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf); ptrdiff_t buf_step = iio_buffer_step(buf); diff --git a/device.c b/device.c index 75247bbfc..b4caaea62 100644 --- a/device.c +++ b/device.c @@ -433,7 +433,8 @@ ssize_t iio_device_get_sample_size_mask(const struct iio_device *dev, for (i = 0; i < dev->nb_channels; i++) { const struct iio_channel *chn = dev->channels[i]; - unsigned int length = chn->format.length / 8; + unsigned int length = chn->format.length / 8 * + (chn->format.repeat ? chn->format.repeat : 1); if (chn->index < 0) break; diff --git a/iio.h b/iio.h index 84527cd8d..ab979c6ef 100644 --- a/iio.h +++ b/iio.h @@ -1216,6 +1216,9 @@ struct iio_data_format { /** @brief Length of valuable data in the sample, in bits */ unsigned int bits; + /** @brief Number of times length repeats */ + unsigned int repeat; + /** @brief Right-shift to apply when converting sample */ unsigned int shift; diff --git a/local.c b/local.c index 4d9559211..af29c9b09 100644 --- a/local.c +++ b/local.c @@ -1108,9 +1108,16 @@ static int handle_protected_scan_element_attr(struct iio_channel *chn, if (ret > 0) { char endian, sign; - sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign, + if (strchr(buf, 'X')) { + sscanf(buf, "%ce:%c%u/%uX%u>>%u", &endian, &sign, + &chn->format.bits, &chn->format.length, + &chn->format.repeat, &chn->format.shift); + } else { + chn->format.repeat = 0; + sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign, &chn->format.bits, &chn->format.length, &chn->format.shift); + } chn->format.is_signed = (sign == 's' || sign == 'S'); chn->format.is_fully_defined = (sign == 'S' || sign == 'U'|| diff --git a/xml.c b/xml.c index f06af7e14..90e084ff2 100644 --- a/xml.c +++ b/xml.c @@ -123,10 +123,19 @@ static void setup_scan_element(struct iio_channel *chn, xmlNode *n) chn->index = atol(content); } else if (!strcmp(name, "format")) { char e, s; - sscanf(content, "%ce:%c%u/%u>>%u", &e, &s, + if (strchr(content, 'X')) { + sscanf(content, "%ce:%c%u/%uX%u>>%u", &e, &s, &chn->format.bits, &chn->format.length, + &chn->format.repeat, &chn->format.shift); + } else { + chn->format.repeat = 0; + sscanf(content, "%ce:%c%u/%u>>%u", &e, &s, + &chn->format.bits, + &chn->format.length, + &chn->format.shift); + } chn->format.is_be = e == 'b'; chn->format.is_signed = (s == 's' || s == 'S'); chn->format.is_fully_defined = (s == 'S' || s == 'U' || From 81f5dc7ae35ae5a2f11a9ce2598056c032794d25 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Thu, 8 Sep 2016 17:17:39 -0700 Subject: [PATCH 3/9] examples: dummy: create example tool that uses iio-dummy and iio-trig-hrtimer --- examples/Makefile | 5 +- examples/dummy-iiostream.c | 257 +++++++++++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 examples/dummy-iiostream.c diff --git a/examples/Makefile b/examples/Makefile index 3b27bb351..29699e856 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -14,7 +14,7 @@ # Lesser General Public License for more details. -TARGETS := ad9361-iiostream iio-monitor +TARGETS := ad9361-iiostream dummy-iiostream iio-monitor CFLAGS = -Wall @@ -28,5 +28,8 @@ iio-monitor: iio-monitor.o ad9361-iiostream : ad9361-iiostream.o $(CC) -o $@ $^ $(LDFLAGS) -liio +dummy-iiostream : dummy-iiostream.o + $(CC) -o $@ $^ $(LDFLAGS) -liio + clean: rm -f $(TARGETS) $(TARGETS:%=%.o) diff --git a/examples/dummy-iiostream.c b/examples/dummy-iiostream.c new file mode 100644 index 000000000..4eeadd574 --- /dev/null +++ b/examples/dummy-iiostream.c @@ -0,0 +1,257 @@ +/* + * libiio - Dummy IIO streaming example + * + * Copyright (c) 2016, DAQRI. All rights reserved. + * Author: Lucas Magasweran + * + * Based on AD9361 example: + * Copyright (C) 2014 IABG mbH + * Author: Michael Feilen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +static char *name = "iio_dummy_part_no"; +static char *trigger_str = "instance1"; + +#define BUFFER_LENGTH 1 +#define SAMPLING_FREQUENCY_HZ "10" + +/* + * libiio supports multiple methods for reading data from a buffer. + * TODO make command line argument + */ +enum { + BUFFER_POINTER, + SAMPLE_CALLBACK, + CHANNEL_READ_RAW, + CHANNEL_READ, +}; +static int buffer_read_method = BUFFER_POINTER; + +// Streaming devices +static struct iio_device *dev; + +/* IIO structs required for streaming */ +static struct iio_context *ctx; +static struct iio_buffer *rxbuf; +static struct iio_channel **channels; +static int channel_count; + +static bool stop; + +/* cleanup and exit */ +static void shutdown() +{ + if (channels) { free(channels); } + + printf("* Destroying buffers\n"); + if (rxbuf) { iio_buffer_destroy(rxbuf); } + + printf("* Disassociate trigger\n"); + if (dev) { iio_device_set_trigger(dev, NULL); } + + printf("* Destroying context\n"); + if (ctx) { iio_context_destroy(ctx); } + exit(0); +} + +static void handle_sig(int sig) +{ + printf("Waiting for process to finish...\n"); + stop = true; +} + +static ssize_t sample_cb(const struct iio_channel *chn, void *src, size_t bytes, void *d) +{ + const struct iio_data_format *fmt = iio_channel_get_data_format(chn); + + printf("%s ", iio_channel_get_id(chn)); + for (int j = 0; j < (fmt->repeat ? fmt->repeat : 1); ++j) { + if (bytes == sizeof(int16_t)) + printf("%i ", ((int16_t *)src)[j]); + else if (bytes == sizeof(int64_t)) + printf("%ld ", ((int64_t *)src)[j]); + } + + return bytes * (fmt->repeat ? fmt->repeat : 1); +} + +/* simple configuration and streaming */ +int main (int argc, char **argv) +{ + // Hardware trigger + struct iio_device *trigger; + + // Listen to ctrl+c and assert + signal(SIGINT, handle_sig); + + printf("* Acquiring IIO context\n"); + assert((ctx = iio_create_default_context()) && "No context"); + assert(iio_context_get_devices_count(ctx) > 0 && "No devices"); + + printf("* Acquiring device %s\n", name); + dev = iio_context_find_device(ctx, name); + if (!dev) { + perror("No device found"); + shutdown(); + } + + printf("* Initializing IIO streaming channels:\n"); + for (int i = 0; i < iio_device_get_channels_count(dev); ++i) { + struct iio_channel *chn = iio_device_get_channel(dev, i); + const struct iio_data_format *fmt = iio_channel_get_data_format(chn); + if (iio_channel_is_scan_element(chn)) { + printf("%s bytes %d repeat %d\n", iio_channel_get_id(chn), fmt->length/8, fmt->repeat); + channel_count++; + } + } + if (channel_count == 0) { + printf("No scan elements found (make sure the driver built with 'CONFIG_IIO_SIMPLE_DUMMY_BUFFER=y')\n"); + shutdown(); + } + channels = calloc(channel_count, sizeof *channels); + if (!channels) { + perror("Channel array allocation failed"); + shutdown(); + } + for (int i = 0; i < channel_count; ++i) { + struct iio_channel *chn = iio_device_get_channel(dev, i); + if (iio_channel_is_scan_element(chn)) + channels[i] = chn; + } + + printf("* Acquiring trigger %s\n", trigger_str); + trigger = iio_context_find_device(ctx, trigger_str); + if (!trigger || !iio_device_is_trigger(trigger)) { + perror("No trigger found (try setting up the iio-trig-hrtimer module)"); + shutdown(); + } + + printf("* Enabling IIO streaming channels for buffered capture\n"); + for (int i = 0; i < channel_count; ++i) + iio_channel_enable(channels[i]); + + printf("* Enabling IIO buffer trigger\n"); + if (iio_device_set_trigger(dev, trigger)) { + perror("Could not set trigger\n"); + shutdown(); + } + + printf("* Creating non-cyclic IIO buffers with %d samples\n", BUFFER_LENGTH); + rxbuf = iio_device_create_buffer(dev, BUFFER_LENGTH, false); + if (!rxbuf) { + perror("Could not create buffer"); + shutdown(); + } + + printf("* Starting IO streaming (press CTRL+C to cancel)\n"); + bool has_ts = strcmp(iio_channel_get_id(channels[channel_count-1]), "timestamp") == 0; + int64_t last_ts = 0; + while (!stop) + { + ssize_t nbytes_rx; + void *p_dat, *p_end; + ptrdiff_t p_inc; + int64_t now_ts; + + // Refill RX buffer + nbytes_rx = iio_buffer_refill(rxbuf); + if (nbytes_rx < 0) { + printf("Error refilling buf: %d\n", (int)nbytes_rx); + shutdown(); + } + + p_inc = iio_buffer_step(rxbuf); + p_end = iio_buffer_end(rxbuf); + + // Print timestamp delta in ms + if (has_ts) + for (p_dat = iio_buffer_first(rxbuf, channels[channel_count-1]); p_dat < p_end; p_dat += p_inc) { + now_ts = (((int64_t *)p_dat)[0]); + printf("[%04ld] ", last_ts > 0 ? (now_ts - last_ts)/1000/1000 : 0); + last_ts = now_ts; + } + + // Print each captured sample + switch (buffer_read_method) + { + case BUFFER_POINTER: + for (int i = 0; i < channel_count; ++i) { + const struct iio_data_format *fmt = iio_channel_get_data_format(channels[i]); + printf("%s ", iio_channel_get_id(channels[i])); + for (p_dat = iio_buffer_first(rxbuf, channels[i]); p_dat < p_end; p_dat += p_inc) { + for (int j = 0; j < (fmt->repeat ? fmt->repeat : 1); ++j) { + if (fmt->length/8 == sizeof(int16_t)) + printf("%i ", ((int16_t *)p_dat)[j]); + else if (fmt->length/8 == sizeof(int64_t)) + printf("%ld ", ((int64_t *)p_dat)[j]); + } + } + } + printf("\n"); + break; + + case SAMPLE_CALLBACK: + iio_buffer_foreach_sample(rxbuf, sample_cb, NULL); + printf("\n"); + break; + + case CHANNEL_READ_RAW: + case CHANNEL_READ: + for (int i = 0; i < channel_count; ++i) { + uint8_t *buf; + size_t bytes; + const struct iio_data_format *fmt = iio_channel_get_data_format(channels[i]); + size_t sample_size = fmt->length / 8 * (fmt->repeat ? fmt->repeat : 1); + + buf = malloc(sample_size * BUFFER_LENGTH); + + if (buffer_read_method == CHANNEL_READ_RAW) + bytes = iio_channel_read_raw(channels[i], rxbuf, buf, sample_size * BUFFER_LENGTH); + else + bytes = iio_channel_read(channels[i], rxbuf, buf, sample_size * BUFFER_LENGTH); + + printf("%s ", iio_channel_get_id(channels[i])); + for (int sample = 0; sample < bytes / sample_size; ++sample) { + for (int j = 0; j < (fmt->repeat ? fmt->repeat : 1); ++j) { + if (fmt->length/8 == sizeof(int16_t)) + printf("%i ", ((int16_t *)buf)[sample+j]); + else if (fmt->length/8 == sizeof(int64_t)) + printf("%ld ", ((int64_t *)buf)[sample+j]); + } + } + + free(buf); + } + printf("\n"); + break; + } + } + + shutdown(); + + return 0; +} + From cc5b26fae825f3f23b552232d77d155d3022508b Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Mon, 12 Sep 2016 10:39:47 -0700 Subject: [PATCH 4/9] example: dummy: document setup --- examples/dummy-iiostream.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/dummy-iiostream.c b/examples/dummy-iiostream.c index 4eeadd574..109b24715 100644 --- a/examples/dummy-iiostream.c +++ b/examples/dummy-iiostream.c @@ -1,6 +1,19 @@ /* * libiio - Dummy IIO streaming example * + * This example libiio program is meant to exercise the features of IIO present + * in the sample dummy IIO device. For buffered access it relies on the hrtimer + * trigger but could be modified to use the sysfs trigger. No hardware should + * be required to run this program. + * + * How to setup the sample IIO dummy device and hrtimer trigger: + * + * 1. sudo modprobe industrialio kfifo_buf + * 2. sudo modprobe iio_dummy iio-trig-hrtimer + * 3. sudo mkdir /configfs + * 4. sudo mount -t configfs none /config + * 5. sudo mkdir /config/iio/triggers/hrtimer/instance1 + * * Copyright (c) 2016, DAQRI. All rights reserved. * Author: Lucas Magasweran * From ef5da2cd1e675b8fa7f1fb0fe6349a90f5ce6324 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Mon, 12 Sep 2016 14:08:50 -0700 Subject: [PATCH 5/9] examples: dummy: add dependency and remove unused define --- examples/dummy-iiostream.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/dummy-iiostream.c b/examples/dummy-iiostream.c index 109b24715..973bac2f8 100644 --- a/examples/dummy-iiostream.c +++ b/examples/dummy-iiostream.c @@ -8,7 +8,7 @@ * * How to setup the sample IIO dummy device and hrtimer trigger: * - * 1. sudo modprobe industrialio kfifo_buf + * 1. sudo modprobe industrialio kfifo_buf industrialio-sw-trigger * 2. sudo modprobe iio_dummy iio-trig-hrtimer * 3. sudo mkdir /configfs * 4. sudo mount -t configfs none /config @@ -45,11 +45,9 @@ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -static char *name = "iio_dummy_part_no"; -static char *trigger_str = "instance1"; - -#define BUFFER_LENGTH 1 -#define SAMPLING_FREQUENCY_HZ "10" +static char *name = "iio_dummy_part_no"; +static char *trigger_str = "instance1"; +#define BUFFER_LENGTH 1 /* * libiio supports multiple methods for reading data from a buffer. From d32fe575079f23071a0b943c373e9f773895c438 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Mon, 12 Sep 2016 14:28:43 -0700 Subject: [PATCH 6/9] examples: dummy: make device, trigger, and buffer length into command line arguments --- examples/dummy-iiostream.c | 48 +++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/examples/dummy-iiostream.c b/examples/dummy-iiostream.c index 973bac2f8..628022f5a 100644 --- a/examples/dummy-iiostream.c +++ b/examples/dummy-iiostream.c @@ -41,18 +41,16 @@ #include #include #include +#include #include #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -static char *name = "iio_dummy_part_no"; +static char *name = "iio_dummy_part_no"; static char *trigger_str = "instance1"; -#define BUFFER_LENGTH 1 +static int buffer_length = 1; -/* - * libiio supports multiple methods for reading data from a buffer. - * TODO make command line argument - */ +// libiio supports multiple methods for reading data from a buffer enum { BUFFER_POINTER, SAMPLE_CALLBACK, @@ -109,12 +107,40 @@ static ssize_t sample_cb(const struct iio_channel *chn, void *src, size_t bytes, return bytes * (fmt->repeat ? fmt->repeat : 1); } +static void parse_options(int argc, char *argv[]) +{ + int c; + + while ((c = getopt(argc, argv, "d:t:c:h")) != -1) + switch (c) + { + case 'd': + name = optarg; + break; + case 't': + trigger_str = optarg; + break; + case 'c': + buffer_length = atoi(optarg); + break; + case 'h': + default: + printf("Usage: %s [OPTION]\n", argv[0]); + printf(" -d\tdevice name (default \"iio_dummy_part_no\")\n"); + printf(" -t\ttrigger name (default \"instance1\")\n"); + printf(" -c\tbuffer length (default 1)\n"); + exit(1); + } +} + /* simple configuration and streaming */ int main (int argc, char **argv) { // Hardware trigger struct iio_device *trigger; + parse_options(argc, argv); + // Listen to ctrl+c and assert signal(SIGINT, handle_sig); @@ -170,8 +196,8 @@ int main (int argc, char **argv) shutdown(); } - printf("* Creating non-cyclic IIO buffers with %d samples\n", BUFFER_LENGTH); - rxbuf = iio_device_create_buffer(dev, BUFFER_LENGTH, false); + printf("* Creating non-cyclic IIO buffers with %d samples\n", buffer_length); + rxbuf = iio_device_create_buffer(dev, buffer_length, false); if (!rxbuf) { perror("Could not create buffer"); shutdown(); @@ -237,12 +263,12 @@ int main (int argc, char **argv) const struct iio_data_format *fmt = iio_channel_get_data_format(channels[i]); size_t sample_size = fmt->length / 8 * (fmt->repeat ? fmt->repeat : 1); - buf = malloc(sample_size * BUFFER_LENGTH); + buf = malloc(sample_size * buffer_length); if (buffer_read_method == CHANNEL_READ_RAW) - bytes = iio_channel_read_raw(channels[i], rxbuf, buf, sample_size * BUFFER_LENGTH); + bytes = iio_channel_read_raw(channels[i], rxbuf, buf, sample_size * buffer_length); else - bytes = iio_channel_read(channels[i], rxbuf, buf, sample_size * BUFFER_LENGTH); + bytes = iio_channel_read(channels[i], rxbuf, buf, sample_size * buffer_length); printf("%s ", iio_channel_get_id(channels[i])); for (int sample = 0; sample < bytes / sample_size; ++sample) { From 55f963b2420365e538aff73673f673f768c8df86 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Mon, 12 Sep 2016 14:38:39 -0700 Subject: [PATCH 7/9] examples: dummy: add option to select read method --- examples/dummy-iiostream.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/examples/dummy-iiostream.c b/examples/dummy-iiostream.c index 628022f5a..b27169e7c 100644 --- a/examples/dummy-iiostream.c +++ b/examples/dummy-iiostream.c @@ -56,6 +56,7 @@ enum { SAMPLE_CALLBACK, CHANNEL_READ_RAW, CHANNEL_READ, + MAX_READ_METHOD, }; static int buffer_read_method = BUFFER_POINTER; @@ -107,11 +108,20 @@ static ssize_t sample_cb(const struct iio_channel *chn, void *src, size_t bytes, return bytes * (fmt->repeat ? fmt->repeat : 1); } +static void usage(int argc, char *argv[]) +{ + printf("Usage: %s [OPTION]\n", argv[0]); + printf(" -d\tdevice name (default \"iio_dummy_part_no\")\n"); + printf(" -t\ttrigger name (default \"instance1\")\n"); + printf(" -c\tbuffer length (default 1)\n"); + printf(" -r\tread method (0 pointer, 1 callback, 2 read, 3 read raw)\n"); +} + static void parse_options(int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "d:t:c:h")) != -1) + while ((c = getopt(argc, argv, "d:t:c:r:h")) != -1) { switch (c) { case 'd': @@ -123,14 +133,20 @@ static void parse_options(int argc, char *argv[]) case 'c': buffer_length = atoi(optarg); break; + case 'r': + if (atoi(optarg) >= 0 && atoi(optarg) < MAX_READ_METHOD) { + buffer_read_method = atoi(optarg); + } else { + usage(argc, argv); + exit(1); + } + break; case 'h': default: - printf("Usage: %s [OPTION]\n", argv[0]); - printf(" -d\tdevice name (default \"iio_dummy_part_no\")\n"); - printf(" -t\ttrigger name (default \"instance1\")\n"); - printf(" -c\tbuffer length (default 1)\n"); + usage(argc, argv); exit(1); } + } } /* simple configuration and streaming */ From 2ac05ccc2bac07f94d30c996c2206eeac11c0258 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Mon, 12 Sep 2016 15:01:50 -0700 Subject: [PATCH 8/9] examples: dummy: change buffer length option and add loop count option --- examples/dummy-iiostream.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/examples/dummy-iiostream.c b/examples/dummy-iiostream.c index b27169e7c..de83d544a 100644 --- a/examples/dummy-iiostream.c +++ b/examples/dummy-iiostream.c @@ -49,6 +49,7 @@ static char *name = "iio_dummy_part_no"; static char *trigger_str = "instance1"; static int buffer_length = 1; +static int count = -1; // libiio supports multiple methods for reading data from a buffer enum { @@ -113,15 +114,16 @@ static void usage(int argc, char *argv[]) printf("Usage: %s [OPTION]\n", argv[0]); printf(" -d\tdevice name (default \"iio_dummy_part_no\")\n"); printf(" -t\ttrigger name (default \"instance1\")\n"); - printf(" -c\tbuffer length (default 1)\n"); - printf(" -r\tread method (0 pointer, 1 callback, 2 read, 3 read raw)\n"); + printf(" -b\tbuffer length (default 1)\n"); + printf(" -r\tread method (default 0 pointer, 1 callback, 2 read, 3 read raw)\n"); + printf(" -c\tread count (default no limit)\n"); } static void parse_options(int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "d:t:c:r:h")) != -1) { + while ((c = getopt(argc, argv, "d:t:b:r:c:h")) != -1) { switch (c) { case 'd': @@ -130,7 +132,7 @@ static void parse_options(int argc, char *argv[]) case 't': trigger_str = optarg; break; - case 'c': + case 'b': buffer_length = atoi(optarg); break; case 'r': @@ -141,6 +143,14 @@ static void parse_options(int argc, char *argv[]) exit(1); } break; + case 'c': + if (atoi(optarg) > 0) { + count = atoi(optarg); + } else { + usage(argc, argv); + exit(1); + } + break; case 'h': default: usage(argc, argv); @@ -301,6 +311,9 @@ int main (int argc, char **argv) printf("\n"); break; } + + if (--count == 0) + break; } shutdown(); From a98736770ca5b843a01e89750d55db094e59c0cb Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Tue, 13 Sep 2016 19:04:37 -0700 Subject: [PATCH 9/9] test: iio_info: include repeat X if defined --- tests/iio_info.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/iio_info.c b/tests/iio_info.c index bfd508801..abe4b16e9 100644 --- a/tests/iio_info.c +++ b/tests/iio_info.c @@ -248,7 +248,15 @@ int main(int argc, char **argv) if (format->is_fully_defined) sign += 'A' - 'a'; - printf(", index: %lu, format: %ce:%c%u/%u>>%u)\n", + if (format->repeat) + printf(", index: %lu, format: %ce:%c%u/%uX%u>>%u)\n", + iio_channel_get_index(ch), + format->is_be ? 'b' : 'l', + sign, format->bits, + format->length, format->repeat, + format->shift); + else + printf(", index: %lu, format: %ce:%c%u/%u>>%u)\n", iio_channel_get_index(ch), format->is_be ? 'b' : 'l', sign, format->bits,