blob: 367f25b46788ab03c551c5f06bc4e6e90d74737a [file] [log] [blame]
Paul Cercueilbb4401d2014-02-28 16:10:49 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * */
18
Paul Cercueil42090d12014-02-24 12:32:23 +010019#include "debug.h"
Paul Cercueil2814ed12016-08-25 17:08:18 +020020#include "iio-config.h"
Paul Cercueil0b2ce712014-02-17 15:04:18 +010021#include "iio-private.h"
22
Paul Cercueil4c6729d2014-04-04 17:24:41 +020023#include <errno.h>
Paul Cercueil42090d12014-02-24 12:32:23 +010024#include <string.h>
25
Paul Cercueil8f56ea72014-10-28 15:18:18 +010026#ifdef _WIN32
27#define LOCAL_BACKEND 0
28#define NETWORK_BACKEND 1
29#endif
30
Paul Cercueil42090d12014-02-24 12:32:23 +010031static const char xml_header[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
32"<!DOCTYPE context ["
Paul Cercueilc39540a2016-11-15 16:55:28 +010033"<!ELEMENT context (device | context-attribute)*>"
34"<!ELEMENT context-attribute EMPTY>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020035"<!ELEMENT device (channel | attribute | debug-attribute)*>"
Paul Cercueila7e80022014-06-11 11:41:26 +020036"<!ELEMENT channel (scan-element?, attribute*)>"
Paul Cercueil42090d12014-02-24 12:32:23 +010037"<!ELEMENT attribute EMPTY>"
Paul Cercueila7e80022014-06-11 11:41:26 +020038"<!ELEMENT scan-element EMPTY>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020039"<!ELEMENT debug-attribute EMPTY>"
Paul Cercueil87350372015-03-16 13:24:37 +010040"<!ATTLIST context name CDATA #REQUIRED description CDATA #IMPLIED>"
Paul Cercueilc39540a2016-11-15 16:55:28 +010041"<!ATTLIST context-attribute name CDATA #REQUIRED value CDATA #REQUIRED>"
Paul Cercueil42090d12014-02-24 12:32:23 +010042"<!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED>"
Paul Cercueila7e80022014-06-11 11:41:26 +020043"<!ATTLIST channel id CDATA #REQUIRED type (input|output) #REQUIRED name CDATA #IMPLIED>"
44"<!ATTLIST scan-element index CDATA #REQUIRED format CDATA #REQUIRED scale CDATA #IMPLIED>"
Paul Cercueil42d12352014-05-05 16:11:58 +020045"<!ATTLIST attribute name CDATA #REQUIRED filename CDATA #IMPLIED>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020046"<!ATTLIST debug-attribute name CDATA #REQUIRED>"
Paul Cercueil42090d12014-02-24 12:32:23 +010047"]>";
48
49/* Returns a string containing the XML representation of this context */
Paul Cercueilc1ed8482014-06-11 16:29:43 +020050char * iio_context_create_xml(const struct iio_context *ctx)
Paul Cercueil42090d12014-02-24 12:32:23 +010051{
Paul Cercueilc39540a2016-11-15 16:55:28 +010052 size_t len, *devices_len = NULL;
53 char *str, *ptr, **devices = NULL;
Paul Cercueil42090d12014-02-24 12:32:23 +010054 unsigned int i;
55
Paul Cercueil87350372015-03-16 13:24:37 +010056 len = strlen(ctx->name) + sizeof(xml_header) - 1 +
57 sizeof("<context name=\"\" ></context>");
58 if (ctx->description)
59 len += strlen(ctx->description) +
60 sizeof(" description=\"\"") - 1;
61
Paul Cercueilc39540a2016-11-15 16:55:28 +010062 for (i = 0; i < ctx->nb_attrs; i++)
63 len += strlen(ctx->attrs[i]) +
64 strlen(ctx->values[i]) +
65 sizeof("<context-attribute name=\"\" value=\"\" />");
66
67 if (ctx->nb_devices) {
Paul Cercueil002ba6e2017-02-02 11:43:52 +010068 devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
Paul Cercueilc39540a2016-11-15 16:55:28 +010069 if (!devices_len) {
Paul Cercueildfeca0d2015-03-16 17:18:00 +010070 errno = ENOMEM;
Paul Cercueil87350372015-03-16 13:24:37 +010071 return NULL;
Paul Cercueildfeca0d2015-03-16 17:18:00 +010072 }
Paul Cercueil87350372015-03-16 13:24:37 +010073
Paul Cercueil002ba6e2017-02-02 11:43:52 +010074 devices = calloc(ctx->nb_devices, sizeof(*devices));
Paul Cercueilc39540a2016-11-15 16:55:28 +010075 if (!devices)
76 goto err_free_devices_len;
Paul Cercueil9aab0192014-04-07 11:04:30 +020077
Paul Cercueilc39540a2016-11-15 16:55:28 +010078 for (i = 0; i < ctx->nb_devices; i++) {
79 char *xml = iio_device_get_xml(ctx->devices[i],
80 &devices_len[i]);
81 if (!xml)
82 goto err_free_devices;
83 devices[i] = xml;
84 len += devices_len[i];
85 }
Paul Cercueil42090d12014-02-24 12:32:23 +010086 }
87
88 str = malloc(len);
Paul Cercueildfeca0d2015-03-16 17:18:00 +010089 if (!str) {
90 errno = ENOMEM;
Paul Cercueil42090d12014-02-24 12:32:23 +010091 goto err_free_devices;
Paul Cercueildfeca0d2015-03-16 17:18:00 +010092 }
Paul Cercueil42090d12014-02-24 12:32:23 +010093
Paul Cercueil9c9a5562017-01-24 10:48:31 +010094 if (ctx->description) {
95 iio_snprintf(str, len, "%s<context name=\"%s\" "
Paul Cercueil87350372015-03-16 13:24:37 +010096 "description=\"%s\" >",
97 xml_header, ctx->name, ctx->description);
Paul Cercueil9c9a5562017-01-24 10:48:31 +010098 } else {
99 iio_snprintf(str, len, "%s<context name=\"%s\" >",
Paul Cercueil87350372015-03-16 13:24:37 +0100100 xml_header, ctx->name);
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100101 }
102
Paul Cercueil42090d12014-02-24 12:32:23 +0100103 ptr = strrchr(str, '\0');
104
Paul Cercueilc39540a2016-11-15 16:55:28 +0100105 for (i = 0; i < ctx->nb_attrs; i++)
106 ptr += sprintf(ptr, "<context-attribute name=\"%s\" value=\"%s\" />",
107 ctx->attrs[i], ctx->values[i]);
108
109
Paul Cercueil42090d12014-02-24 12:32:23 +0100110 for (i = 0; i < ctx->nb_devices; i++) {
111 strcpy(ptr, devices[i]);
112 ptr += devices_len[i];
113 free(devices[i]);
114 }
115
Paul Cercueil5822ab62014-04-04 13:29:17 +0200116 free(devices);
117 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100118 strcpy(ptr, "</context>");
119 return str;
120
121err_free_devices:
Paul Cercueil8e80a192017-02-01 12:11:33 +0100122 for (i = 0; i < ctx->nb_devices; i++)
Paul Cercueil42090d12014-02-24 12:32:23 +0100123 free(devices[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +0200124 free(devices);
125err_free_devices_len:
126 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100127 return NULL;
128}
129
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200130const char * iio_context_get_xml(const struct iio_context *ctx)
131{
132 return ctx->xml;
133}
134
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100135const char * iio_context_get_name(const struct iio_context *ctx)
136{
137 return ctx->name;
138}
139
Paul Cercueil3ac36c12015-01-08 14:44:00 +0100140const char * iio_context_get_description(const struct iio_context *ctx)
141{
142 if (ctx->description)
143 return ctx->description;
144 else
145 return "";
146}
147
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100148void iio_context_destroy(struct iio_context *ctx)
149{
Paul Cercueil50363542014-02-18 16:04:28 +0100150 unsigned int i;
151 if (ctx->ops->shutdown)
152 ctx->ops->shutdown(ctx);
153
Paul Cercueil60b4d1b2016-11-15 15:55:41 +0100154 for (i = 0; i < ctx->nb_attrs; i++) {
155 free(ctx->attrs[i]);
156 free(ctx->values[i]);
157 }
158 if (ctx->nb_attrs) {
159 free(ctx->attrs);
160 free(ctx->values);
161 }
Paul Cercueil50363542014-02-18 16:04:28 +0100162 for (i = 0; i < ctx->nb_devices; i++)
163 free_device(ctx->devices[i]);
164 if (ctx->nb_devices)
165 free(ctx->devices);
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200166 if (ctx->xml)
167 free(ctx->xml);
Paul Cercueil3ac36c12015-01-08 14:44:00 +0100168 if (ctx->description)
169 free(ctx->description);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100170 free(ctx);
171}
172
173unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
174{
175 return ctx->nb_devices;
176}
177
178struct iio_device * iio_context_get_device(const struct iio_context *ctx,
179 unsigned int index)
180{
181 if (index >= ctx->nb_devices)
182 return NULL;
183 else
184 return ctx->devices[index];
185}
Paul Cercueilae88fde2014-03-12 11:47:10 +0100186
Paul Cercueil17512b02014-03-28 11:15:24 +0100187struct iio_device * iio_context_find_device(const struct iio_context *ctx,
188 const char *name)
189{
190 unsigned int i;
191 for (i = 0; i < ctx->nb_devices; i++) {
192 struct iio_device *dev = ctx->devices[i];
193 if (!strcmp(dev->id, name) ||
194 (dev->name && !strcmp(dev->name, name)))
195 return dev;
196 }
197 return NULL;
198}
199
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100200static void reorder_channels(struct iio_device *dev)
201{
202 bool found;
203 unsigned int i;
204
205 /* Reorder channels by index */
206 do {
207 found = false;
208 for (i = 1; i < dev->nb_channels; i++) {
209 struct iio_channel **channels = dev->channels;
210 long ch1 = channels[i - 1]->index;
211 long ch2 = channels[i]->index;
212
Lars-Peter Clausen75baa4d2016-02-01 17:58:57 +0100213 if (ch1 == ch2 && ch1 >= 0) {
214 ch1 = channels[i - 1]->format.shift;
215 ch2 = channels[i]->format.shift;
216 }
217
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100218 if (ch2 >= 0 && ((ch1 > ch2) || ch1 < 0)) {
219 struct iio_channel *bak = channels[i];
220 channels[i] = channels[i - 1];
221 channels[i - 1] = bak;
222 found = true;
223 }
224 }
225 } while (found);
226}
227
Paul Cercueilfd387472015-08-05 10:34:19 +0200228int iio_context_init(struct iio_context *ctx)
Paul Cercueilae88fde2014-03-12 11:47:10 +0100229{
230 unsigned int i;
Paul Cercueilfd387472015-08-05 10:34:19 +0200231
Paul Cercueila7e80022014-06-11 11:41:26 +0200232 for (i = 0; i < ctx->nb_devices; i++)
233 reorder_channels(ctx->devices[i]);
Paul Cercueilfd387472015-08-05 10:34:19 +0200234
235 if (!ctx->xml) {
236 ctx->xml = iio_context_create_xml(ctx);
237 if (!ctx->xml)
238 return -ENOMEM;
239 }
240
241 return 0;
Paul Cercueilae88fde2014-03-12 11:47:10 +0100242}
Paul Cercueile45f8762014-05-02 11:19:26 +0200243
244int iio_context_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200245 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueile45f8762014-05-02 11:19:26 +0200246{
247 if (ctx->ops->get_version)
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200248 return ctx->ops->get_version(ctx, major, minor, git_tag);
Paul Cercueil53ed9432014-11-20 13:46:04 +0100249
250 iio_library_get_version(major, minor, git_tag);
Paul Cercueile45f8762014-05-02 11:19:26 +0200251 return 0;
252}
Paul Cercueil4ca73542014-06-10 16:23:29 +0200253
254int iio_context_set_timeout(struct iio_context *ctx, unsigned int timeout)
255{
256 if (ctx->ops->set_timeout)
257 return ctx->ops->set_timeout(ctx, timeout);
258 else
259 return -ENOSYS;
260}
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100261
262struct iio_context * iio_context_clone(const struct iio_context *ctx)
263{
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100264 if (ctx->ops->clone) {
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100265 return ctx->ops->clone(ctx);
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100266 } else {
267 errno = ENOSYS;
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100268 return NULL;
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100269 }
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100270}
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100271
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100272struct iio_context * iio_create_context_from_uri(const char *uri)
273{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200274#ifdef WITH_LOCAL_BACKEND
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100275 if (strcmp(uri, "local:") == 0) /* No address part */
276 return iio_create_local_context();
Paul Cercueilc399f512016-04-26 17:55:27 +0200277#endif
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100278
Paul Cercueil2814ed12016-08-25 17:08:18 +0200279#ifdef WITH_XML_BACKEND
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100280 if (strncmp(uri, "xml:", sizeof("xml:") - 1) == 0)
281 return iio_create_xml_context(uri + sizeof("xml:") - 1);
Paul Cercueilc399f512016-04-26 17:55:27 +0200282#endif
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100283
Paul Cercueil2814ed12016-08-25 17:08:18 +0200284#ifdef WITH_NETWORK_BACKEND
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100285 if (strncmp(uri, "ip:", sizeof("ip:") - 1) == 0)
286 return iio_create_network_context(uri+3);
Paul Cercueilc399f512016-04-26 17:55:27 +0200287#endif
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100288
Paul Cercueil2814ed12016-08-25 17:08:18 +0200289#ifdef WITH_USB_BACKEND
Paul Cercueilc399f512016-04-26 17:55:27 +0200290 if (strncmp(uri, "usb:", sizeof("usb:") - 1) == 0)
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100291 return usb_create_context_from_uri(uri);
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100292#endif
293
Paul Cercueil2814ed12016-08-25 17:08:18 +0200294#ifdef WITH_SERIAL_BACKEND
Paul Cercueilbcb04522016-03-22 17:03:29 +0100295 if (strncmp(uri, "serial:", sizeof("serial:") - 1) == 0)
296 return serial_create_context_from_uri(uri);
297#endif
298
Paul Cercueil10416462016-04-26 16:09:06 +0200299 errno = ENOSYS;
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100300 return NULL;
301}
302
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100303struct iio_context * iio_create_default_context(void)
304{
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100305 char *hostname = getenv("IIOD_REMOTE");
306
307 if (hostname) {
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100308 struct iio_context *ctx;
309
310 ctx = iio_create_context_from_uri(hostname);
311 if (ctx)
312 return ctx;
313
Paul Cercueil2814ed12016-08-25 17:08:18 +0200314#ifdef WITH_NETWORK_BACKEND
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100315 /* If the environment variable is an empty string, we will
316 * discover the server using ZeroConf */
317 if (strlen(hostname) == 0)
318 hostname = NULL;
319
320 return iio_create_network_context(hostname);
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100321#endif
Paul Cercueil3cce9652015-12-02 13:11:47 +0100322 }
323
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100324 return iio_create_local_context();
Paul Cercueil63e52182014-12-11 12:52:48 +0100325}
326
327struct iio_context * iio_create_local_context(void)
328{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200329#ifdef WITH_LOCAL_BACKEND
Paul Cercueil63e52182014-12-11 12:52:48 +0100330 return local_create_context();
331#else
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100332 errno = ENOSYS;
Paul Cercueil63e52182014-12-11 12:52:48 +0100333 return NULL;
334#endif
335}
336
337struct iio_context * iio_create_network_context(const char *hostname)
338{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200339#ifdef WITH_NETWORK_BACKEND
Paul Cercueil63e52182014-12-11 12:52:48 +0100340 return network_create_context(hostname);
341#else
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100342 errno = ENOSYS;
Paul Cercueil63e52182014-12-11 12:52:48 +0100343 return NULL;
344#endif
345}
346
347struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
348{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200349#ifdef WITH_XML_BACKEND
Paul Cercueil63e52182014-12-11 12:52:48 +0100350 return xml_create_context_mem(xml, len);
351#else
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100352 errno = ENOSYS;
Paul Cercueil63e52182014-12-11 12:52:48 +0100353 return NULL;
354#endif
355}
356
357struct iio_context * iio_create_xml_context(const char *xml_file)
358{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200359#ifdef WITH_XML_BACKEND
Paul Cercueil63e52182014-12-11 12:52:48 +0100360 return xml_create_context(xml_file);
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100361#else
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100362 errno = ENOSYS;
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100363 return NULL;
364#endif
365}
Paul Cercueil60b4d1b2016-11-15 15:55:41 +0100366
367unsigned int iio_context_get_attrs_count(const struct iio_context *ctx)
368{
369 return ctx->nb_attrs;
370}
371
372int iio_context_get_attr(const struct iio_context *ctx, unsigned int index,
373 const char **name, const char **value)
374{
375 if (index >= ctx->nb_attrs)
376 return -EINVAL;
377
378 if (name)
379 *name = ctx->attrs[index];
380 if (value)
381 *value = ctx->values[index];
382 return 0;
383}
384
385const char * iio_context_get_attr_value(
386 const struct iio_context *ctx, const char *name)
387{
388 unsigned int i;
389
390 for (i = 0; i < ctx->nb_attrs; i++) {
391 if (!strcmp(name, ctx->attrs[i]))
392 return ctx->values[i];
393 }
394
395 return NULL;
396}
Paul Cercueila09970b2016-11-24 17:30:07 +0100397
398int iio_context_add_attr(struct iio_context *ctx,
399 const char *key, const char *value)
400{
401 char **attrs, **values, *new_key, *new_val;
402
403 attrs = realloc(ctx->attrs,
404 (ctx->nb_attrs + 1) * sizeof(*ctx->attrs));
405 if (!attrs)
406 return -ENOMEM;
407
408 ctx->attrs = attrs;
409
410 values = realloc(ctx->values,
411 (ctx->nb_attrs + 1) * sizeof(*ctx->values));
412 if (!values)
413 return -ENOMEM;
414
415 ctx->values = values;
416
417 new_key = iio_strdup(key);
418 if (!new_key)
419 return -ENOMEM;
420
421 new_val = iio_strdup(value);
422 if (!new_val) {
423 free(new_key);
424 return -ENOMEM;
425 }
426
427 ctx->attrs[ctx->nb_attrs] = new_key;
428 ctx->values[ctx->nb_attrs] = new_val;
429 ctx->nb_attrs++;
430 return 0;
431}