Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: libserialport libxml2
Diff: iiod-client.c
- Revision:
- 0:df031b60ca29
- Child:
- 2:9eb0a9a1f958
diff -r 000000000000 -r df031b60ca29 iiod-client.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/iiod-client.c Thu Aug 25 15:54:09 2016 +0000
@@ -0,0 +1,589 @@
+#include "debug.h"
+#include "iiod-client.h"
+#include "iio-errno.h"
+#include "iio-lock.h"
+#include "iio-private.h"
+
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+
+struct iiod_client {
+ struct iio_context_pdata *pdata;
+ const struct iiod_client_ops *ops;
+ struct iio_mutex *lock;
+};
+
+static ssize_t iiod_client_read_integer(struct iiod_client *client,
+ void *desc, int *val)
+{
+ unsigned int i;
+ char buf[1024], *ptr = NULL, *end;
+ ssize_t ret;
+ int value;
+
+ do {
+ ret = client->ops->read_line(client->pdata,
+ desc, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < (unsigned int) ret; i++) {
+ if (buf[i] != '\n') {
+ if (!ptr)
+ ptr = &buf[i];
+ } else if (!!ptr) {
+ break;
+ }
+ }
+ } while (!ptr);
+
+ buf[i] = '\0';
+
+ value = (int) strtol(ptr, &end, 10);
+ if (ptr == end)
+ return -EINVAL;
+
+ *val = value;
+ return 0;
+}
+
+static int iiod_client_exec_command(struct iiod_client *client,
+ void *desc, const char *cmd)
+{
+ int resp;
+ ssize_t ret;
+
+ ret = client->ops->write(client->pdata, desc, cmd, strlen(cmd));
+ if (ret < 0)
+ return (int) ret;
+
+ ret = iiod_client_read_integer(client, desc, &resp);
+ return ret < 0 ? (int) ret : resp;
+}
+
+static ssize_t iiod_client_write_all(struct iiod_client *client,
+ void *desc, const void *src, size_t len)
+{
+ struct iio_context_pdata *pdata = client->pdata;
+ const struct iiod_client_ops *ops = client->ops;
+ uintptr_t ptr = (uintptr_t) src;
+
+ while (len) {
+ ssize_t ret = ops->write(pdata, desc, (const void *) ptr, len);
+
+ if (ret < 0) {
+ if (ret == -EINTR)
+ continue;
+ else
+ return ret;
+ }
+
+ if (ret == 0)
+ return -EPIPE;
+
+ ptr += ret;
+ len -= ret;
+ }
+
+ return (ssize_t) (ptr - (uintptr_t) src);
+}
+
+static ssize_t iiod_client_read_all(struct iiod_client *client,
+ void *desc, void *dst, size_t len)
+{
+ struct iio_context_pdata *pdata = client->pdata;
+ const struct iiod_client_ops *ops = client->ops;
+ uintptr_t ptr = (uintptr_t) dst;
+
+ while (len) {
+ ssize_t ret = ops->read(pdata, desc, (void *) ptr, len);
+
+ if (ret < 0) {
+ if (ret == -EINTR)
+ continue;
+ else
+ return ret;
+ }
+
+ if (ret == 0)
+ return -EPIPE;
+
+ ptr += ret;
+ len -= ret;
+ }
+
+ return (ssize_t) (ptr - (uintptr_t) dst);
+}
+
+struct iiod_client * iiod_client_new(struct iio_context_pdata *pdata,
+ struct iio_mutex *lock, const struct iiod_client_ops *ops)
+{
+ struct iiod_client *client;
+
+ client = malloc(sizeof(*client));
+ if (!client) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ client->lock = lock;
+ client->pdata = pdata;
+ client->ops = ops;
+ return client;
+}
+
+void iiod_client_destroy(struct iiod_client *client)
+{
+ free(client);
+}
+
+int iiod_client_get_version(struct iiod_client *client, void *desc,
+ unsigned int *major, unsigned int *minor, char *git_tag)
+{
+ struct iio_context_pdata *pdata = client->pdata;
+ const struct iiod_client_ops *ops = client->ops;
+ char buf[256], *ptr = buf, *end;
+ long maj, min;
+ int ret;
+
+ iio_mutex_lock(client->lock);
+
+ ret = ops->write(pdata, desc, "VERSION\r\n", sizeof("VERSION\r\n") - 1);
+ if (ret < 0) {
+ iio_mutex_unlock(client->lock);
+ return ret;
+ }
+
+ ret = ops->read_line(pdata, desc, buf, sizeof(buf));
+ iio_mutex_unlock(client->lock);
+
+ if (ret < 0)
+ return ret;
+
+ maj = strtol(ptr, &end, 10);
+ if (ptr == end)
+ return -EIO;
+
+ ptr = end + 1;
+ min = strtol(ptr, &end, 10);
+ if (ptr == end)
+ return -EIO;
+
+ ptr = end + 1;
+ if (buf + ret < ptr + 8)
+ return -EIO;
+
+ /* Strip the \n */
+ ptr[buf + ret - ptr - 1] = '\0';
+
+ if (major)
+ *major = (unsigned int) maj;
+ if (minor)
+ *minor = (unsigned int) min;
+ if (git_tag)
+ strncpy(git_tag, ptr, 8);
+ return 0;
+}
+
+int iiod_client_get_trigger(struct iiod_client *client, void *desc,
+ const struct iio_device *dev, const struct iio_device **trigger)
+{
+ const struct iio_context *ctx = iio_device_get_context(dev);
+ unsigned int i, nb_devices = iio_context_get_devices_count(ctx);
+ char buf[1024];
+ unsigned int name_len;
+ int ret;
+
+ snprintf(buf, sizeof(buf), "GETTRIG %s\r\n", iio_device_get_id(dev));
+
+ iio_mutex_lock(client->lock);
+ ret = iiod_client_exec_command(client, desc, buf);
+
+ if (ret == 0)
+ *trigger = NULL;
+ if (ret <= 0)
+ goto out_unlock;
+
+ if ((unsigned int) ret > sizeof(buf) - 1) {
+ ret = -EIO;
+ goto out_unlock;
+ }
+
+ name_len = ret;
+
+ ret = (int) iiod_client_read_all(client, desc, buf, name_len + 1);
+ if (ret < 0)
+ goto out_unlock;
+
+ ret = -ENXIO;
+
+ for (i = 0; i < nb_devices; i++) {
+ struct iio_device *cur = iio_context_get_device(ctx, i);
+
+ if (iio_device_is_trigger(cur)) {
+ const char *name = iio_device_get_name(cur);
+
+ if (!name)
+ continue;
+
+ if (!strncmp(name, buf, name_len)) {
+ *trigger = cur;
+ ret = 0;
+ goto out_unlock;
+ }
+ }
+ }
+
+out_unlock:
+ iio_mutex_unlock(client->lock);
+ return ret;
+}
+
+int iiod_client_set_trigger(struct iiod_client *client, void *desc,
+ const struct iio_device *dev, const struct iio_device *trigger)
+{
+ char buf[1024];
+ int ret;
+
+ if (trigger)
+ snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
+ iio_device_get_id(dev),
+ iio_device_get_id(trigger));
+ else
+ snprintf(buf, sizeof(buf), "SETTRIG %s\r\n",
+ iio_device_get_id(dev));
+
+ iio_mutex_lock(client->lock);
+ ret = iiod_client_exec_command(client, desc, buf);
+ iio_mutex_unlock(client->lock);
+ return ret;
+}
+
+int iiod_client_set_kernel_buffers_count(struct iiod_client *client, void *desc,
+ const struct iio_device *dev, unsigned int nb_blocks)
+{
+ int ret;
+ char buf[1024];
+
+ snprintf(buf, sizeof(buf), "SET %s BUFFERS_COUNT %u\r\n",
+ iio_device_get_id(dev), nb_blocks);
+
+ iio_mutex_lock(client->lock);
+ ret = iiod_client_exec_command(client, desc, buf);
+ iio_mutex_unlock(client->lock);
+ return ret;
+}
+
+int iiod_client_set_timeout(struct iiod_client *client,
+ void *desc, unsigned int timeout)
+{
+ int ret;
+ char buf[1024];
+
+ snprintf(buf, sizeof(buf), "TIMEOUT %u\r\n", timeout);
+
+ iio_mutex_lock(client->lock);
+ ret = iiod_client_exec_command(client, desc, buf);
+ iio_mutex_unlock(client->lock);
+ return ret;
+}
+
+ssize_t iiod_client_read_attr(struct iiod_client *client, void *desc,
+ const struct iio_device *dev, const struct iio_channel *chn,
+ const char *attr, char *dest, size_t len, bool is_debug)
+{
+ const char *id = iio_device_get_id(dev);
+ char buf[1024];
+ ssize_t ret;
+
+ if (attr) {
+ if (chn) {
+ if (!iio_channel_find_attr(chn, attr))
+ return -ENOENT;
+ } else if (is_debug) {
+ if (!iio_device_find_debug_attr(dev, attr))
+ return -ENOENT;
+ } else {
+ if (!iio_device_find_attr(dev, attr))
+ return -ENOENT;
+ }
+ }
+
+ if (chn)
+ snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id,
+ iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
+ iio_channel_get_id(chn), attr ? attr : "");
+ else if (is_debug)
+ snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n",
+ id, attr ? attr : "");
+ else
+ snprintf(buf, sizeof(buf), "READ %s %s\r\n",
+ id, attr ? attr : "");
+
+ iio_mutex_lock(client->lock);
+
+ ret = (ssize_t) iiod_client_exec_command(client, desc, buf);
+ if (ret < 0)
+ goto out_unlock;
+
+ if ((size_t) ret + 1 > len) {
+ ret = -EIO;
+ goto out_unlock;
+ }
+
+ /* +1: Also read the trailing \n */
+ ret = iiod_client_read_all(client, desc, dest, ret + 1);
+
+ if (ret > 0) {
+ /* Discard the trailing \n */
+ ret--;
+
+ /* Replace it with a \0 just in case */
+ dest[ret] = '\0';
+ }
+
+out_unlock:
+ iio_mutex_unlock(client->lock);
+ return ret;
+}
+
+ssize_t iiod_client_write_attr(struct iiod_client *client, void *desc,
+ const struct iio_device *dev, const struct iio_channel *chn,
+ const char *attr, const char *src, size_t len, bool is_debug)
+{
+ struct iio_context_pdata *pdata = client->pdata;
+ const struct iiod_client_ops *ops = client->ops;
+ const char *id = iio_device_get_id(dev);
+ char buf[1024];
+ ssize_t ret;
+ int resp;
+
+ if (attr) {
+ if (chn) {
+ if (!iio_channel_find_attr(chn, attr))
+ return -ENOENT;
+ } else if (is_debug) {
+ if (!iio_device_find_debug_attr(dev, attr))
+ return -ENOENT;
+ } else {
+ if (!iio_device_find_attr(dev, attr))
+ return -ENOENT;
+ }
+ }
+
+ if (chn)
+ snprintf(buf, sizeof(buf), "WRITE %s %s %s %s %lu\r\n", id,
+ iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
+ iio_channel_get_id(chn), attr ? attr : "",
+ (unsigned long) len);
+ else if (is_debug)
+ snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n",
+ id, attr ? attr : "", (unsigned long) len);
+ else
+ snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n",
+ id, attr ? attr : "", (unsigned long) len);
+
+ iio_mutex_lock(client->lock);
+ ret = ops->write(pdata, desc, buf, strlen(buf));
+ if (ret < 0)
+ goto out_unlock;
+
+ ret = iiod_client_write_all(client, desc, src, len);
+ if (ret < 0)
+ goto out_unlock;
+
+ ret = iiod_client_read_integer(client, desc, &resp);
+ if (ret < 0)
+ goto out_unlock;
+
+ ret = (ssize_t) resp;
+
+out_unlock:
+ iio_mutex_unlock(client->lock);
+ return ret;
+}
+
+struct iio_context * iiod_client_create_context(
+ struct iiod_client *client, void *desc)
+{
+ struct iio_context *ctx = NULL;
+ size_t xml_len;
+ char *xml;
+ int ret;
+
+ iio_mutex_lock(client->lock);
+ ret = iiod_client_exec_command(client, desc, "PRINT\r\n");
+ if (ret < 0)
+ goto out_unlock;
+
+ xml_len = (size_t) ret;
+ xml = malloc(xml_len + 1);
+ if (!xml) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ /* +1: Also read the trailing \n */
+ ret = (int) iiod_client_read_all(client, desc, xml, xml_len + 1);
+ if (ret < 0)
+ goto out_free_xml;
+
+ ctx = iio_create_xml_context_mem(xml, xml_len);
+ if (!ctx)
+ ret = -errno;
+
+out_free_xml:
+ free(xml);
+out_unlock:
+ iio_mutex_unlock(client->lock);
+ if (!ctx)
+ errno = -ret;
+ return ctx;
+}
+
+int iiod_client_open_unlocked(struct iiod_client *client, void *desc,
+ const struct iio_device *dev, size_t samples_count, bool cyclic)
+{
+ char buf[1024], *ptr;
+ size_t i;
+
+ snprintf(buf, sizeof(buf), "OPEN %s %lu ",
+ iio_device_get_id(dev), (unsigned long) samples_count);
+ ptr = buf + strlen(buf);
+
+ for (i = dev->words; i > 0; i--, ptr += 8)
+ snprintf(ptr, (ptr - buf) + i * 8, "%08" PRIx32,
+ dev->mask[i - 1]);
+
+ strcpy(ptr, cyclic ? " CYCLIC\r\n" : "\r\n");
+
+ return iiod_client_exec_command(client, desc, buf);
+}
+
+int iiod_client_close_unlocked(struct iiod_client *client, void *desc,
+ const struct iio_device *dev)
+{
+ char buf[1024];
+
+ snprintf(buf, sizeof(buf), "CLOSE %s\r\n", iio_device_get_id(dev));
+ return iiod_client_exec_command(client, desc, buf);
+}
+
+static int iiod_client_read_mask(struct iiod_client *client,
+ void *desc, uint32_t *mask, size_t words)
+{
+ size_t i;
+ ssize_t ret;
+ char *buf, *ptr;
+
+ buf = malloc(words * 8 + 1);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = iiod_client_read_all(client, desc, buf, words * 8 + 1);
+ if (ret < 0)
+ goto out_buf_free;
+ else
+ ret = 0;
+
+ buf[words*8] = '\0';
+
+ DEBUG("Reading mask\n");
+
+ for (i = words, ptr = buf; i > 0; i--) {
+ sscanf(ptr, "%08" PRIx32, &mask[i - 1]);
+ DEBUG("mask[%lu] = 0x%08" PRIx32 "\n",
+ (unsigned long)(i - 1), mask[i - 1]);
+
+ ptr = (char *) ((uintptr_t) ptr + 8);
+ }
+
+out_buf_free:
+ free(buf);
+ return (int) ret;
+}
+
+ssize_t iiod_client_read_unlocked(struct iiod_client *client, void *desc,
+ const struct iio_device *dev, void *dst, size_t len,
+ uint32_t *mask, size_t words)
+{
+ unsigned int nb_channels = iio_device_get_channels_count(dev);
+ uintptr_t ptr = (uintptr_t) dst;
+ char buf[1024];
+ ssize_t ret, read = 0;
+
+ if (!len || words != (nb_channels + 31) / 32)
+ return -EINVAL;
+
+ snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
+ iio_device_get_id(dev), (unsigned long) len);
+
+ ret = iiod_client_write_all(client, desc, buf, strlen(buf));
+ if (ret < 0)
+ return ret;
+
+ do {
+ int to_read;
+
+ ret = iiod_client_read_integer(client, desc, &to_read);
+ if (ret < 0)
+ return ret;
+ if (to_read < 0)
+ return (ssize_t) to_read;
+ if (!to_read)
+ break;
+
+ if (mask) {
+ ret = iiod_client_read_mask(client, desc, mask, words);
+ if (ret < 0)
+ return ret;
+
+ mask = NULL; /* We read the mask only once */
+ }
+
+ ret = iiod_client_read_all(client, desc, (char *) ptr, to_read);
+ if (ret < 0)
+ return ret;
+
+ ptr += ret;
+ read += ret;
+ len -= ret;
+ } while (len);
+
+ return read;
+}
+
+ssize_t iiod_client_write_unlocked(struct iiod_client *client, void *desc,
+ const struct iio_device *dev, const void *src, size_t len)
+{
+ ssize_t ret;
+ char buf[1024];
+ int val;
+
+ snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
+ dev->id, (unsigned long) len);
+
+ ret = iiod_client_write_all(client, desc, buf, strlen(buf));
+ if (ret < 0)
+ return ret;
+
+ ret = iiod_client_read_integer(client, desc, &val);
+ if (ret < 0)
+ return ret;
+ if (val < 0)
+ return (ssize_t) val;
+
+ ret = iiod_client_write_all(client, desc, src, len);
+ if (ret < 0)
+ return ret;
+
+ ret = iiod_client_read_integer(client, desc, &val);
+ if (ret < 0)
+ return ret;
+ if (val < 0)
+ return (ssize_t) val;
+
+ return (ssize_t) len;
+}
+