summaryrefslogtreecommitdiff
path: root/src/context.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/context.c')
-rw-r--r--src/context.c436
1 files changed, 436 insertions, 0 deletions
diff --git a/src/context.c b/src/context.c
new file mode 100644
index 0000000..b124801
--- /dev/null
+++ b/src/context.c
@@ -0,0 +1,436 @@
+/*
+ * libiio - Library for interfacing industrial I/O (IIO) devices
+ *
+ * Copyright (C) 2014 Analog Devices, Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * 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 "debug.h"
+#include "iio-config.h"
+#include "iio-private.h"
+
+#include <errno.h>
+#include <string.h>
+
+#ifdef _WIN32
+#define LOCAL_BACKEND 0
+#define NETWORK_BACKEND 1
+#endif
+
+static const char xml_header[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+"<!DOCTYPE context ["
+"<!ELEMENT context (device | context-attribute)*>"
+"<!ELEMENT context-attribute EMPTY>"
+"<!ELEMENT device (channel | attribute | debug-attribute | buffer-attribute)*>"
+"<!ELEMENT channel (scan-element?, attribute*)>"
+"<!ELEMENT attribute EMPTY>"
+"<!ELEMENT scan-element EMPTY>"
+"<!ELEMENT debug-attribute EMPTY>"
+"<!ELEMENT buffer-attribute EMPTY>"
+"<!ATTLIST context name CDATA #REQUIRED description CDATA #IMPLIED>"
+"<!ATTLIST context-attribute name CDATA #REQUIRED value CDATA #REQUIRED>"
+"<!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED>"
+"<!ATTLIST channel id CDATA #REQUIRED type (input|output) #REQUIRED name CDATA #IMPLIED>"
+"<!ATTLIST scan-element index CDATA #REQUIRED format CDATA #REQUIRED scale CDATA #IMPLIED>"
+"<!ATTLIST attribute name CDATA #REQUIRED filename CDATA #IMPLIED>"
+"<!ATTLIST debug-attribute name CDATA #REQUIRED>"
+"<!ATTLIST buffer-attribute name CDATA #REQUIRED>"
+"]>";
+
+/* Returns a string containing the XML representation of this context */
+char * iio_context_create_xml(const struct iio_context *ctx)
+{
+ size_t len, *devices_len = NULL;
+ char *str, *ptr, **devices = NULL;
+ unsigned int i;
+
+ len = strlen(ctx->name) + sizeof(xml_header) - 1 +
+ sizeof("<context name=\"\" ></context>");
+ if (ctx->description)
+ len += strlen(ctx->description) +
+ sizeof(" description=\"\"") - 1;
+
+ for (i = 0; i < ctx->nb_attrs; i++)
+ len += strlen(ctx->attrs[i]) +
+ strlen(ctx->values[i]) +
+ sizeof("<context-attribute name=\"\" value=\"\" />");
+
+ if (ctx->nb_devices) {
+ devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
+ if (!devices_len) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ devices = calloc(ctx->nb_devices, sizeof(*devices));
+ if (!devices)
+ goto err_free_devices_len;
+
+ for (i = 0; i < ctx->nb_devices; i++) {
+ char *xml = iio_device_get_xml(ctx->devices[i],
+ &devices_len[i]);
+ if (!xml)
+ goto err_free_devices;
+ devices[i] = xml;
+ len += devices_len[i];
+ }
+ }
+
+ str = malloc(len);
+ if (!str) {
+ errno = ENOMEM;
+ goto err_free_devices;
+ }
+
+ if (ctx->description) {
+ iio_snprintf(str, len, "%s<context name=\"%s\" "
+ "description=\"%s\" >",
+ xml_header, ctx->name, ctx->description);
+ } else {
+ iio_snprintf(str, len, "%s<context name=\"%s\" >",
+ xml_header, ctx->name);
+ }
+
+ ptr = strrchr(str, '\0');
+
+ for (i = 0; i < ctx->nb_attrs; i++)
+ ptr += sprintf(ptr, "<context-attribute name=\"%s\" value=\"%s\" />",
+ ctx->attrs[i], ctx->values[i]);
+
+
+ for (i = 0; i < ctx->nb_devices; i++) {
+ strcpy(ptr, devices[i]);
+ ptr += devices_len[i];
+ free(devices[i]);
+ }
+
+ free(devices);
+ free(devices_len);
+ strcpy(ptr, "</context>");
+ return str;
+
+err_free_devices:
+ for (i = 0; i < ctx->nb_devices; i++)
+ free(devices[i]);
+ free(devices);
+err_free_devices_len:
+ free(devices_len);
+ return NULL;
+}
+
+const char * iio_context_get_xml(const struct iio_context *ctx)
+{
+ return ctx->xml;
+}
+
+const char * iio_context_get_name(const struct iio_context *ctx)
+{
+ return ctx->name;
+}
+
+const char * iio_context_get_description(const struct iio_context *ctx)
+{
+ if (ctx->description)
+ return ctx->description;
+ else
+ return "";
+}
+
+void iio_context_destroy(struct iio_context *ctx)
+{
+ unsigned int i;
+ if (ctx->ops->shutdown)
+ ctx->ops->shutdown(ctx);
+
+ for (i = 0; i < ctx->nb_attrs; i++) {
+ free(ctx->attrs[i]);
+ free(ctx->values[i]);
+ }
+ if (ctx->nb_attrs) {
+ free(ctx->attrs);
+ free(ctx->values);
+ }
+ for (i = 0; i < ctx->nb_devices; i++)
+ free_device(ctx->devices[i]);
+ if (ctx->nb_devices)
+ free(ctx->devices);
+ if (ctx->xml)
+ free(ctx->xml);
+ if (ctx->description)
+ free(ctx->description);
+ free(ctx);
+}
+
+unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
+{
+ return ctx->nb_devices;
+}
+
+struct iio_device * iio_context_get_device(const struct iio_context *ctx,
+ unsigned int index)
+{
+ if (index >= ctx->nb_devices)
+ return NULL;
+ else
+ return ctx->devices[index];
+}
+
+struct iio_device * iio_context_find_device(const struct iio_context *ctx,
+ const char *name)
+{
+ unsigned int i;
+ for (i = 0; i < ctx->nb_devices; i++) {
+ struct iio_device *dev = ctx->devices[i];
+ if (!strcmp(dev->id, name) ||
+ (dev->name && !strcmp(dev->name, name)))
+ return dev;
+ }
+ return NULL;
+}
+
+static void reorder_channels(struct iio_device *dev)
+{
+ bool found;
+ unsigned int i;
+
+ /* Reorder channels by index */
+ do {
+ found = false;
+ for (i = 1; i < dev->nb_channels; i++) {
+ struct iio_channel **channels = dev->channels;
+ long ch1 = channels[i - 1]->index;
+ long ch2 = channels[i]->index;
+
+ if (ch1 == ch2 && ch1 >= 0) {
+ ch1 = channels[i - 1]->format.shift;
+ ch2 = channels[i]->format.shift;
+ }
+
+ if (ch2 >= 0 && ((ch1 > ch2) || ch1 < 0)) {
+ struct iio_channel *bak = channels[i];
+ channels[i] = channels[i - 1];
+ channels[i - 1] = bak;
+ found = true;
+ }
+ }
+ } while (found);
+
+ for (i = 0; i < dev->nb_channels; i++)
+ dev->channels[i]->number = i;
+}
+
+int iio_context_init(struct iio_context *ctx)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->nb_devices; i++)
+ reorder_channels(ctx->devices[i]);
+
+ if (!ctx->xml) {
+ ctx->xml = iio_context_create_xml(ctx);
+ if (!ctx->xml)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int iio_context_get_version(const struct iio_context *ctx,
+ unsigned int *major, unsigned int *minor, char git_tag[8])
+{
+ if (ctx->ops->get_version)
+ return ctx->ops->get_version(ctx, major, minor, git_tag);
+
+ iio_library_get_version(major, minor, git_tag);
+ return 0;
+}
+
+int iio_context_set_timeout(struct iio_context *ctx, unsigned int timeout)
+{
+ if (ctx->ops->set_timeout)
+ return ctx->ops->set_timeout(ctx, timeout);
+ else
+ return -ENOSYS;
+}
+
+struct iio_context * iio_context_clone(const struct iio_context *ctx)
+{
+ if (ctx->ops->clone) {
+ return ctx->ops->clone(ctx);
+ } else {
+ errno = ENOSYS;
+ return NULL;
+ }
+}
+
+struct iio_context * iio_create_context_from_uri(const char *uri)
+{
+#ifdef WITH_LOCAL_BACKEND
+ if (strcmp(uri, "local:") == 0) /* No address part */
+ return iio_create_local_context();
+#endif
+
+#ifdef WITH_XML_BACKEND
+ if (strncmp(uri, "xml:", sizeof("xml:") - 1) == 0)
+ return iio_create_xml_context(uri + sizeof("xml:") - 1);
+#endif
+
+#ifdef WITH_NETWORK_BACKEND
+ if (strncmp(uri, "ip:", sizeof("ip:") - 1) == 0)
+ return iio_create_network_context(uri+3);
+#endif
+
+#ifdef WITH_USB_BACKEND
+ if (strncmp(uri, "usb:", sizeof("usb:") - 1) == 0)
+ return usb_create_context_from_uri(uri);
+#endif
+
+#ifdef WITH_SERIAL_BACKEND
+ if (strncmp(uri, "serial:", sizeof("serial:") - 1) == 0)
+ return serial_create_context_from_uri(uri);
+#endif
+
+ errno = ENOSYS;
+ return NULL;
+}
+
+struct iio_context * iio_create_default_context(void)
+{
+ char *hostname = getenv("IIOD_REMOTE");
+
+ if (hostname) {
+ struct iio_context *ctx;
+
+ ctx = iio_create_context_from_uri(hostname);
+ if (ctx)
+ return ctx;
+
+#ifdef WITH_NETWORK_BACKEND
+ /* If the environment variable is an empty string, we will
+ * discover the server using ZeroConf */
+ if (strlen(hostname) == 0)
+ hostname = NULL;
+
+ return iio_create_network_context(hostname);
+#endif
+ }
+
+ return iio_create_local_context();
+}
+
+struct iio_context * iio_create_local_context(void)
+{
+#ifdef WITH_LOCAL_BACKEND
+ return local_create_context();
+#else
+ errno = ENOSYS;
+ return NULL;
+#endif
+}
+
+struct iio_context * iio_create_network_context(const char *hostname)
+{
+#ifdef WITH_NETWORK_BACKEND
+ return network_create_context(hostname);
+#else
+ errno = ENOSYS;
+ return NULL;
+#endif
+}
+
+struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
+{
+#ifdef WITH_XML_BACKEND
+ return xml_create_context_mem(xml, len);
+#else
+ errno = ENOSYS;
+ return NULL;
+#endif
+}
+
+struct iio_context * iio_create_xml_context(const char *xml_file)
+{
+#ifdef WITH_XML_BACKEND
+ return xml_create_context(xml_file);
+#else
+ errno = ENOSYS;
+ return NULL;
+#endif
+}
+
+unsigned int iio_context_get_attrs_count(const struct iio_context *ctx)
+{
+ return ctx->nb_attrs;
+}
+
+int iio_context_get_attr(const struct iio_context *ctx, unsigned int index,
+ const char **name, const char **value)
+{
+ if (index >= ctx->nb_attrs)
+ return -EINVAL;
+
+ if (name)
+ *name = ctx->attrs[index];
+ if (value)
+ *value = ctx->values[index];
+ return 0;
+}
+
+const char * iio_context_get_attr_value(
+ const struct iio_context *ctx, const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->nb_attrs; i++) {
+ if (!strcmp(name, ctx->attrs[i]))
+ return ctx->values[i];
+ }
+
+ return NULL;
+}
+
+int iio_context_add_attr(struct iio_context *ctx,
+ const char *key, const char *value)
+{
+ char **attrs, **values, *new_key, *new_val;
+
+ attrs = realloc(ctx->attrs,
+ (ctx->nb_attrs + 1) * sizeof(*ctx->attrs));
+ if (!attrs)
+ return -ENOMEM;
+
+ ctx->attrs = attrs;
+
+ values = realloc(ctx->values,
+ (ctx->nb_attrs + 1) * sizeof(*ctx->values));
+ if (!values)
+ return -ENOMEM;
+
+ ctx->values = values;
+
+ new_key = iio_strdup(key);
+ if (!new_key)
+ return -ENOMEM;
+
+ new_val = iio_strdup(value);
+ if (!new_val) {
+ free(new_key);
+ return -ENOMEM;
+ }
+
+ ctx->attrs[ctx->nb_attrs] = new_key;
+ ctx->values[ctx->nb_attrs] = new_val;
+ ctx->nb_attrs++;
+ return 0;
+}