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/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..de83d544a
--- /dev/null
+++ b/examples/dummy-iiostream.c
@@ -0,0 +1,323 @@
+/*
+ * 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 industrialio-sw-trigger
+ * 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
+ *
+ * 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
+#include
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+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 {
+ BUFFER_POINTER,
+ SAMPLE_CALLBACK,
+ CHANNEL_READ_RAW,
+ CHANNEL_READ,
+ MAX_READ_METHOD,
+};
+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);
+}
+
+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(" -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:b:r:c:h")) != -1) {
+ switch (c)
+ {
+ case 'd':
+ name = optarg;
+ break;
+ case 't':
+ trigger_str = optarg;
+ break;
+ case 'b':
+ 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 'c':
+ if (atoi(optarg) > 0) {
+ count = atoi(optarg);
+ } else {
+ usage(argc, argv);
+ exit(1);
+ }
+ break;
+ case 'h':
+ default:
+ usage(argc, argv);
+ 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);
+
+ 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;
+ }
+
+ if (--count == 0)
+ break;
+ }
+
+ shutdown();
+
+ return 0;
+}
+
diff --git a/iio.h b/iio.h
index 7100d955e..ab979c6ef 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,
@@ -1215,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/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,
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' ||