blob: 3e28e35074cfc9f3b56a645f44d060302f6bae8f [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"
Robin Getz57295ce2018-05-24 21:45:08 +000022#include "sort.h"
Paul Cercueil0b2ce712014-02-17 15:04:18 +010023
Paul Cercueil4c6729d2014-04-04 17:24:41 +020024#include <errno.h>
Paul Cercueil42090d12014-02-24 12:32:23 +010025#include <string.h>
26
Paul Cercueil8f56ea72014-10-28 15:18:18 +010027#ifdef _WIN32
28#define LOCAL_BACKEND 0
29#define NETWORK_BACKEND 1
30#endif
31
Paul Cercueil42090d12014-02-24 12:32:23 +010032static const char xml_header[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
33"<!DOCTYPE context ["
Paul Cercueilc39540a2016-11-15 16:55:28 +010034"<!ELEMENT context (device | context-attribute)*>"
35"<!ELEMENT context-attribute EMPTY>"
Matt Fornero81f04a52017-11-30 14:36:37 -050036"<!ELEMENT device (channel | attribute | debug-attribute | buffer-attribute)*>"
Paul Cercueila7e80022014-06-11 11:41:26 +020037"<!ELEMENT channel (scan-element?, attribute*)>"
Paul Cercueil42090d12014-02-24 12:32:23 +010038"<!ELEMENT attribute EMPTY>"
Paul Cercueila7e80022014-06-11 11:41:26 +020039"<!ELEMENT scan-element EMPTY>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020040"<!ELEMENT debug-attribute EMPTY>"
Matt Fornero81f04a52017-11-30 14:36:37 -050041"<!ELEMENT buffer-attribute EMPTY>"
Paul Cercueil87350372015-03-16 13:24:37 +010042"<!ATTLIST context name CDATA #REQUIRED description CDATA #IMPLIED>"
Paul Cercueilc39540a2016-11-15 16:55:28 +010043"<!ATTLIST context-attribute name CDATA #REQUIRED value CDATA #REQUIRED>"
Paul Cercueil42090d12014-02-24 12:32:23 +010044"<!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED>"
Paul Cercueila7e80022014-06-11 11:41:26 +020045"<!ATTLIST channel id CDATA #REQUIRED type (input|output) #REQUIRED name CDATA #IMPLIED>"
46"<!ATTLIST scan-element index CDATA #REQUIRED format CDATA #REQUIRED scale CDATA #IMPLIED>"
Paul Cercueil42d12352014-05-05 16:11:58 +020047"<!ATTLIST attribute name CDATA #REQUIRED filename CDATA #IMPLIED>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020048"<!ATTLIST debug-attribute name CDATA #REQUIRED>"
Matt Fornero81f04a52017-11-30 14:36:37 -050049"<!ATTLIST buffer-attribute name CDATA #REQUIRED>"
Paul Cercueil42090d12014-02-24 12:32:23 +010050"]>";
51
52/* Returns a string containing the XML representation of this context */
Paul Cercueilc1ed8482014-06-11 16:29:43 +020053char * iio_context_create_xml(const struct iio_context *ctx)
Paul Cercueil42090d12014-02-24 12:32:23 +010054{
Paul Cercueilc39540a2016-11-15 16:55:28 +010055 size_t len, *devices_len = NULL;
56 char *str, *ptr, **devices = NULL;
Paul Cercueil42090d12014-02-24 12:32:23 +010057 unsigned int i;
58
Paul Cercueil87350372015-03-16 13:24:37 +010059 len = strlen(ctx->name) + sizeof(xml_header) - 1 +
60 sizeof("<context name=\"\" ></context>");
61 if (ctx->description)
62 len += strlen(ctx->description) +
63 sizeof(" description=\"\"") - 1;
64
Paul Cercueilc39540a2016-11-15 16:55:28 +010065 for (i = 0; i < ctx->nb_attrs; i++)
66 len += strlen(ctx->attrs[i]) +
67 strlen(ctx->values[i]) +
68 sizeof("<context-attribute name=\"\" value=\"\" />");
69
70 if (ctx->nb_devices) {
Paul Cercueil002ba6e2017-02-02 11:43:52 +010071 devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
Paul Cercueilc39540a2016-11-15 16:55:28 +010072 if (!devices_len) {
Paul Cercueildfeca0d2015-03-16 17:18:00 +010073 errno = ENOMEM;
Paul Cercueil87350372015-03-16 13:24:37 +010074 return NULL;
Paul Cercueildfeca0d2015-03-16 17:18:00 +010075 }
Paul Cercueil87350372015-03-16 13:24:37 +010076
Paul Cercueil002ba6e2017-02-02 11:43:52 +010077 devices = calloc(ctx->nb_devices, sizeof(*devices));
Paul Cercueilc39540a2016-11-15 16:55:28 +010078 if (!devices)
79 goto err_free_devices_len;
Paul Cercueil9aab0192014-04-07 11:04:30 +020080
Paul Cercueilc39540a2016-11-15 16:55:28 +010081 for (i = 0; i < ctx->nb_devices; i++) {
82 char *xml = iio_device_get_xml(ctx->devices[i],
83 &devices_len[i]);
84 if (!xml)
85 goto err_free_devices;
86 devices[i] = xml;
87 len += devices_len[i];
88 }
Paul Cercueil42090d12014-02-24 12:32:23 +010089 }
90
91 str = malloc(len);
Paul Cercueildfeca0d2015-03-16 17:18:00 +010092 if (!str) {
93 errno = ENOMEM;
Paul Cercueil42090d12014-02-24 12:32:23 +010094 goto err_free_devices;
Paul Cercueildfeca0d2015-03-16 17:18:00 +010095 }
Paul Cercueil42090d12014-02-24 12:32:23 +010096
Paul Cercueil9c9a5562017-01-24 10:48:31 +010097 if (ctx->description) {
98 iio_snprintf(str, len, "%s<context name=\"%s\" "
Paul Cercueil87350372015-03-16 13:24:37 +010099 "description=\"%s\" >",
100 xml_header, ctx->name, ctx->description);
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100101 } else {
102 iio_snprintf(str, len, "%s<context name=\"%s\" >",
Paul Cercueil87350372015-03-16 13:24:37 +0100103 xml_header, ctx->name);
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100104 }
105
Paul Cercueil42090d12014-02-24 12:32:23 +0100106 ptr = strrchr(str, '\0');
107
Paul Cercueilc39540a2016-11-15 16:55:28 +0100108 for (i = 0; i < ctx->nb_attrs; i++)
109 ptr += sprintf(ptr, "<context-attribute name=\"%s\" value=\"%s\" />",
110 ctx->attrs[i], ctx->values[i]);
111
112
Paul Cercueil42090d12014-02-24 12:32:23 +0100113 for (i = 0; i < ctx->nb_devices; i++) {
114 strcpy(ptr, devices[i]);
115 ptr += devices_len[i];
116 free(devices[i]);
117 }
118
Paul Cercueil5822ab62014-04-04 13:29:17 +0200119 free(devices);
120 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100121 strcpy(ptr, "</context>");
122 return str;
123
124err_free_devices:
Paul Cercueil8e80a192017-02-01 12:11:33 +0100125 for (i = 0; i < ctx->nb_devices; i++)
Paul Cercueil42090d12014-02-24 12:32:23 +0100126 free(devices[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +0200127 free(devices);
128err_free_devices_len:
129 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100130 return NULL;
131}
132
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200133const char * iio_context_get_xml(const struct iio_context *ctx)
134{
135 return ctx->xml;
136}
137
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100138const char * iio_context_get_name(const struct iio_context *ctx)
139{
140 return ctx->name;
141}
142
Paul Cercueil3ac36c12015-01-08 14:44:00 +0100143const char * iio_context_get_description(const struct iio_context *ctx)
144{
145 if (ctx->description)
146 return ctx->description;
147 else
148 return "";
149}
150
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100151void iio_context_destroy(struct iio_context *ctx)
152{
Paul Cercueil50363542014-02-18 16:04:28 +0100153 unsigned int i;
154 if (ctx->ops->shutdown)
155 ctx->ops->shutdown(ctx);
156
Paul Cercueil60b4d1b2016-11-15 15:55:41 +0100157 for (i = 0; i < ctx->nb_attrs; i++) {
158 free(ctx->attrs[i]);
159 free(ctx->values[i]);
160 }
161 if (ctx->nb_attrs) {
162 free(ctx->attrs);
163 free(ctx->values);
164 }
Paul Cercueil50363542014-02-18 16:04:28 +0100165 for (i = 0; i < ctx->nb_devices; i++)
166 free_device(ctx->devices[i]);
167 if (ctx->nb_devices)
168 free(ctx->devices);
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200169 if (ctx->xml)
170 free(ctx->xml);
Paul Cercueil3ac36c12015-01-08 14:44:00 +0100171 if (ctx->description)
172 free(ctx->description);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100173 free(ctx);
174}
175
176unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
177{
178 return ctx->nb_devices;
179}
180
181struct iio_device * iio_context_get_device(const struct iio_context *ctx,
182 unsigned int index)
183{
184 if (index >= ctx->nb_devices)
185 return NULL;
186 else
187 return ctx->devices[index];
188}
Paul Cercueilae88fde2014-03-12 11:47:10 +0100189
Paul Cercueil17512b02014-03-28 11:15:24 +0100190struct iio_device * iio_context_find_device(const struct iio_context *ctx,
191 const char *name)
192{
193 unsigned int i;
194 for (i = 0; i < ctx->nb_devices; i++) {
195 struct iio_device *dev = ctx->devices[i];
196 if (!strcmp(dev->id, name) ||
197 (dev->name && !strcmp(dev->name, name)))
198 return dev;
199 }
200 return NULL;
201}
202
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100203static void reorder_channels(struct iio_device *dev)
204{
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100205 unsigned int i;
206
207 /* Reorder channels by index */
Robin Getz57295ce2018-05-24 21:45:08 +0000208 qsort(dev->channels, dev->nb_channels, sizeof(struct iio_channel *),
Robin Getzb8634362018-10-24 12:39:11 +0000209 iio_channel_compare);
Paul Cercueil5e3b9cd2017-04-11 17:31:46 +0200210
Robin Getzad170382018-10-24 12:47:17 +0000211 for (i = 0; i < dev->nb_channels; i++) {
212 struct iio_channel *chn = dev->channels[i];
213 chn->number = i;
214 qsort(chn->attrs, chn->nb_attrs, sizeof(struct iio_channel_attr),
215 iio_channel_attr_compare);
216 }
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100217}
218
Paul Cercueilfd387472015-08-05 10:34:19 +0200219int iio_context_init(struct iio_context *ctx)
Paul Cercueilae88fde2014-03-12 11:47:10 +0100220{
221 unsigned int i;
Paul Cercueilfd387472015-08-05 10:34:19 +0200222
Paul Cercueila7e80022014-06-11 11:41:26 +0200223 for (i = 0; i < ctx->nb_devices; i++)
224 reorder_channels(ctx->devices[i]);
Paul Cercueilfd387472015-08-05 10:34:19 +0200225
226 if (!ctx->xml) {
227 ctx->xml = iio_context_create_xml(ctx);
228 if (!ctx->xml)
229 return -ENOMEM;
230 }
231
232 return 0;
Paul Cercueilae88fde2014-03-12 11:47:10 +0100233}
Paul Cercueile45f8762014-05-02 11:19:26 +0200234
235int iio_context_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200236 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueile45f8762014-05-02 11:19:26 +0200237{
238 if (ctx->ops->get_version)
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200239 return ctx->ops->get_version(ctx, major, minor, git_tag);
Paul Cercueil53ed9432014-11-20 13:46:04 +0100240
241 iio_library_get_version(major, minor, git_tag);
Paul Cercueile45f8762014-05-02 11:19:26 +0200242 return 0;
243}
Paul Cercueil4ca73542014-06-10 16:23:29 +0200244
245int iio_context_set_timeout(struct iio_context *ctx, unsigned int timeout)
246{
247 if (ctx->ops->set_timeout)
248 return ctx->ops->set_timeout(ctx, timeout);
249 else
250 return -ENOSYS;
251}
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100252
253struct iio_context * iio_context_clone(const struct iio_context *ctx)
254{
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100255 if (ctx->ops->clone) {
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100256 return ctx->ops->clone(ctx);
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100257 } else {
258 errno = ENOSYS;
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100259 return NULL;
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100260 }
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100261}
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100262
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100263struct iio_context * iio_create_context_from_uri(const char *uri)
264{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200265#ifdef WITH_LOCAL_BACKEND
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100266 if (strcmp(uri, "local:") == 0) /* No address part */
267 return iio_create_local_context();
Paul Cercueilc399f512016-04-26 17:55:27 +0200268#endif
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100269
Paul Cercueil2814ed12016-08-25 17:08:18 +0200270#ifdef WITH_XML_BACKEND
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100271 if (strncmp(uri, "xml:", sizeof("xml:") - 1) == 0)
272 return iio_create_xml_context(uri + sizeof("xml:") - 1);
Paul Cercueilc399f512016-04-26 17:55:27 +0200273#endif
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100274
Paul Cercueil2814ed12016-08-25 17:08:18 +0200275#ifdef WITH_NETWORK_BACKEND
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100276 if (strncmp(uri, "ip:", sizeof("ip:") - 1) == 0)
277 return iio_create_network_context(uri+3);
Paul Cercueilc399f512016-04-26 17:55:27 +0200278#endif
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100279
Paul Cercueil2814ed12016-08-25 17:08:18 +0200280#ifdef WITH_USB_BACKEND
Paul Cercueilc399f512016-04-26 17:55:27 +0200281 if (strncmp(uri, "usb:", sizeof("usb:") - 1) == 0)
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100282 return usb_create_context_from_uri(uri);
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100283#endif
284
Paul Cercueil2814ed12016-08-25 17:08:18 +0200285#ifdef WITH_SERIAL_BACKEND
Paul Cercueilbcb04522016-03-22 17:03:29 +0100286 if (strncmp(uri, "serial:", sizeof("serial:") - 1) == 0)
287 return serial_create_context_from_uri(uri);
288#endif
289
Paul Cercueil10416462016-04-26 16:09:06 +0200290 errno = ENOSYS;
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100291 return NULL;
292}
293
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100294struct iio_context * iio_create_default_context(void)
295{
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100296 char *hostname = getenv("IIOD_REMOTE");
297
298 if (hostname) {
Lars-Peter Clausen60f1c9a2016-02-22 13:20:40 +0100299 struct iio_context *ctx;
300
301 ctx = iio_create_context_from_uri(hostname);
302 if (ctx)
303 return ctx;
304
Paul Cercueil2814ed12016-08-25 17:08:18 +0200305#ifdef WITH_NETWORK_BACKEND
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100306 /* If the environment variable is an empty string, we will
307 * discover the server using ZeroConf */
308 if (strlen(hostname) == 0)
309 hostname = NULL;
310
311 return iio_create_network_context(hostname);
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100312#endif
Paul Cercueil3cce9652015-12-02 13:11:47 +0100313 }
314
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100315 return iio_create_local_context();
Paul Cercueil63e52182014-12-11 12:52:48 +0100316}
317
318struct iio_context * iio_create_local_context(void)
319{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200320#ifdef WITH_LOCAL_BACKEND
Paul Cercueil63e52182014-12-11 12:52:48 +0100321 return local_create_context();
322#else
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100323 errno = ENOSYS;
Paul Cercueil63e52182014-12-11 12:52:48 +0100324 return NULL;
325#endif
326}
327
328struct iio_context * iio_create_network_context(const char *hostname)
329{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200330#ifdef WITH_NETWORK_BACKEND
Paul Cercueil63e52182014-12-11 12:52:48 +0100331 return network_create_context(hostname);
332#else
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100333 errno = ENOSYS;
Paul Cercueil63e52182014-12-11 12:52:48 +0100334 return NULL;
335#endif
336}
337
338struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
339{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200340#ifdef WITH_XML_BACKEND
Paul Cercueil63e52182014-12-11 12:52:48 +0100341 return xml_create_context_mem(xml, len);
342#else
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100343 errno = ENOSYS;
Paul Cercueil63e52182014-12-11 12:52:48 +0100344 return NULL;
345#endif
346}
347
348struct iio_context * iio_create_xml_context(const char *xml_file)
349{
Paul Cercueil2814ed12016-08-25 17:08:18 +0200350#ifdef WITH_XML_BACKEND
Paul Cercueil63e52182014-12-11 12:52:48 +0100351 return xml_create_context(xml_file);
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100352#else
Paul Cercueildfeca0d2015-03-16 17:18:00 +0100353 errno = ENOSYS;
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100354 return NULL;
355#endif
356}
Paul Cercueil60b4d1b2016-11-15 15:55:41 +0100357
358unsigned int iio_context_get_attrs_count(const struct iio_context *ctx)
359{
360 return ctx->nb_attrs;
361}
362
363int iio_context_get_attr(const struct iio_context *ctx, unsigned int index,
364 const char **name, const char **value)
365{
366 if (index >= ctx->nb_attrs)
367 return -EINVAL;
368
369 if (name)
370 *name = ctx->attrs[index];
371 if (value)
372 *value = ctx->values[index];
373 return 0;
374}
375
376const char * iio_context_get_attr_value(
377 const struct iio_context *ctx, const char *name)
378{
379 unsigned int i;
380
381 for (i = 0; i < ctx->nb_attrs; i++) {
382 if (!strcmp(name, ctx->attrs[i]))
383 return ctx->values[i];
384 }
385
386 return NULL;
387}
Paul Cercueila09970b2016-11-24 17:30:07 +0100388
389int iio_context_add_attr(struct iio_context *ctx,
390 const char *key, const char *value)
391{
392 char **attrs, **values, *new_key, *new_val;
393
394 attrs = realloc(ctx->attrs,
395 (ctx->nb_attrs + 1) * sizeof(*ctx->attrs));
396 if (!attrs)
397 return -ENOMEM;
398
399 ctx->attrs = attrs;
400
401 values = realloc(ctx->values,
402 (ctx->nb_attrs + 1) * sizeof(*ctx->values));
403 if (!values)
404 return -ENOMEM;
405
406 ctx->values = values;
407
408 new_key = iio_strdup(key);
409 if (!new_key)
410 return -ENOMEM;
411
412 new_val = iio_strdup(value);
413 if (!new_val) {
414 free(new_key);
415 return -ENOMEM;
416 }
417
418 ctx->attrs[ctx->nb_attrs] = new_key;
419 ctx->values[ctx->nb_attrs] = new_val;
420 ctx->nb_attrs++;
421 return 0;
422}