1 /*
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
19 #include "debug.h"
20 #include "iio-config.h"
21 #include "iio-private.h"
22 #include "sort.h"
23
24 #include <errno.h>
25 #include <string.h>
26
27 #ifdef _WIN32
28 #define LOCAL_BACKEND 0
29 #define NETWORK_BACKEND 1
30 #endif
31
32 static const char xml_header[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
33 "<!DOCTYPE context ["
34 "<!ELEMENT context (device | context-attribute)*>"
35 "<!ELEMENT context-attribute EMPTY>"
36 "<!ELEMENT device (channel | attribute | debug-attribute | buffer-attribute)*>"
37 "<!ELEMENT channel (scan-element?, attribute*)>"
38 "<!ELEMENT attribute EMPTY>"
39 "<!ELEMENT scan-element EMPTY>"
40 "<!ELEMENT debug-attribute EMPTY>"
41 "<!ELEMENT buffer-attribute EMPTY>"
42 "<!ATTLIST context name CDATA #REQUIRED description CDATA #IMPLIED>"
43 "<!ATTLIST context-attribute name CDATA #REQUIRED value CDATA #REQUIRED>"
44 "<!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED>"
45 "<!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>"
47 "<!ATTLIST attribute name CDATA #REQUIRED filename CDATA #IMPLIED>"
48 "<!ATTLIST debug-attribute name CDATA #REQUIRED>"
49 "<!ATTLIST buffer-attribute name CDATA #REQUIRED>"
50 "]>";
51
52 /* Returns a string containing the XML representation of this context */
iio_context_create_xml(const struct iio_context * ctx)53 char * iio_context_create_xml(const struct iio_context *ctx)
54 {
55 size_t len, *devices_len = NULL;
56 char *str, *ptr, **devices = NULL;
57 unsigned int i;
58
59 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
65 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) {
71 devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
72 if (!devices_len) {
73 errno = ENOMEM;
74 return NULL;
75 }
76
77 devices = calloc(ctx->nb_devices, sizeof(*devices));
78 if (!devices)
79 goto err_free_devices_len;
80
81 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 }
89 }
90
91 str = malloc(len);
92 if (!str) {
93 errno = ENOMEM;
94 goto err_free_devices;
95 }
96
97 if (ctx->description) {
98 iio_snprintf(str, len, "%s<context name=\"%s\" "
99 "description=\"%s\" >",
100 xml_header, ctx->name, ctx->description);
101 } else {
102 iio_snprintf(str, len, "%s<context name=\"%s\" >",
103 xml_header, ctx->name);
104 }
105
106 ptr = strrchr(str, '\0');
107
108 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
113 for (i = 0; i < ctx->nb_devices; i++) {
114 strcpy(ptr, devices[i]);
115 ptr += devices_len[i];
116 free(devices[i]);
117 }
118
119 free(devices);
120 free(devices_len);
121 strcpy(ptr, "</context>");
122 return str;
123
124 err_free_devices:
125 for (i = 0; i < ctx->nb_devices; i++)
126 free(devices[i]);
127 free(devices);
128 err_free_devices_len:
129 free(devices_len);
130 return NULL;
131 }
132
iio_context_get_xml(const struct iio_context * ctx)133 const char * iio_context_get_xml(const struct iio_context *ctx)
134 {
135 return ctx->xml;
136 }
137
iio_context_get_name(const struct iio_context * ctx)138 const char * iio_context_get_name(const struct iio_context *ctx)
139 {
140 return ctx->name;
141 }
142
iio_context_get_description(const struct iio_context * ctx)143 const 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
iio_context_destroy(struct iio_context * ctx)151 void iio_context_destroy(struct iio_context *ctx)
152 {
153 unsigned int i;
154 if (ctx->ops->shutdown)
155 ctx->ops->shutdown(ctx);
156
157 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 }
165 for (i = 0; i < ctx->nb_devices; i++)
166 free_device(ctx->devices[i]);
167 if (ctx->nb_devices)
168 free(ctx->devices);
169 if (ctx->xml)
170 free(ctx->xml);
171 if (ctx->description)
172 free(ctx->description);
173 free(ctx);
174 }
175
iio_context_get_devices_count(const struct iio_context * ctx)176 unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
177 {
178 return ctx->nb_devices;
179 }
180
iio_context_get_device(const struct iio_context * ctx,unsigned int index)181 struct 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 }
189
iio_context_find_device(const struct iio_context * ctx,const char * name)190 struct 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
reorder_channels(struct iio_device * dev)203 static void reorder_channels(struct iio_device *dev)
204 {
205 bool found;
206 unsigned int i;
207
208 /* Reorder channels by index */
209 do {
210 found = false;
211 for (i = 1; i < dev->nb_channels; i++) {
212 struct iio_channel **channels = dev->channels;
213 long ch1 = channels[i - 1]->index;
214 long ch2 = channels[i]->index;
215
216 if (ch1 == ch2 && ch1 >= 0) {
217 ch1 = channels[i - 1]->format.shift;
218 ch2 = channels[i]->format.shift;
219 }
220
221 if (ch2 >= 0 && ((ch1 > ch2) || ch1 < 0)) {
222 struct iio_channel *bak = channels[i];
223 channels[i] = channels[i - 1];
224 channels[i - 1] = bak;
225 found = true;
226 }
227 }
228 } while (found);
229
230 for (i = 0; i < dev->nb_channels; i++)
231 dev->channels[i]->number = i;
232 }
233
iio_context_init(struct iio_context * ctx)234 int iio_context_init(struct iio_context *ctx)
235 {
236 unsigned int i;
237
238 for (i = 0; i < ctx->nb_devices; i++)
239 reorder_channels(ctx->devices[i]);
240
241 if (!ctx->xml) {
242 ctx->xml = iio_context_create_xml(ctx);
243 if (!ctx->xml)
244 return -ENOMEM;
245 }
246
247 return 0;
248 }
249
iio_context_get_version(const struct iio_context * ctx,unsigned int * major,unsigned int * minor,char git_tag[8])250 int iio_context_get_version(const struct iio_context *ctx,
251 unsigned int *major, unsigned int *minor, char git_tag[8])
252 {
253 if (ctx->ops->get_version)
254 return ctx->ops->get_version(ctx, major, minor, git_tag);
255
256 iio_library_get_version(major, minor, git_tag);
257 return 0;
258 }
259
iio_context_set_timeout(struct iio_context * ctx,unsigned int timeout)260 int iio_context_set_timeout(struct iio_context *ctx, unsigned int timeout)
261 {
262 if (ctx->ops->set_timeout)
263 return ctx->ops->set_timeout(ctx, timeout);
264 else
265 return -ENOSYS;
266 }
267
iio_context_clone(const struct iio_context * ctx)268 struct iio_context * iio_context_clone(const struct iio_context *ctx)
269 {
270 if (ctx->ops->clone) {
271 return ctx->ops->clone(ctx);
272 } else {
273 errno = ENOSYS;
274 return NULL;
275 }
276 }
277
iio_create_context_from_uri(const char * uri)278 struct iio_context * iio_create_context_from_uri(const char *uri)
279 {
280 #ifdef WITH_LOCAL_BACKEND
281 if (strcmp(uri, "local:") == 0) /* No address part */
282 return iio_create_local_context();
283 #endif
284
285 #ifdef WITH_XML_BACKEND
286 if (strncmp(uri, "xml:", sizeof("xml:") - 1) == 0)
287 return iio_create_xml_context(uri + sizeof("xml:") - 1);
288 #endif
289
290 #ifdef WITH_NETWORK_BACKEND
291 if (strncmp(uri, "ip:", sizeof("ip:") - 1) == 0)
292 return iio_create_network_context(uri+3);
293 #endif
294
295 #ifdef WITH_USB_BACKEND
296 if (strncmp(uri, "usb:", sizeof("usb:") - 1) == 0)
297 return usb_create_context_from_uri(uri);
298 #endif
299
300 #ifdef WITH_SERIAL_BACKEND
301 if (strncmp(uri, "serial:", sizeof("serial:") - 1) == 0)
302 return serial_create_context_from_uri(uri);
303 #endif
304
305 errno = ENOSYS;
306 return NULL;
307 }
308
iio_create_default_context(void)309 struct iio_context * iio_create_default_context(void)
310 {
311 char *hostname = getenv("IIOD_REMOTE");
312
313 if (hostname) {
314 struct iio_context *ctx;
315
316 ctx = iio_create_context_from_uri(hostname);
317 if (ctx)
318 return ctx;
319
320 #ifdef WITH_NETWORK_BACKEND
321 /* If the environment variable is an empty string, we will
322 * discover the server using ZeroConf */
323 if (strlen(hostname) == 0)
324 hostname = NULL;
325
326 return iio_create_network_context(hostname);
327 #endif
328 }
329
330 return iio_create_local_context();
331 }
332
iio_create_local_context(void)333 struct iio_context * iio_create_local_context(void)
334 {
335 #ifdef WITH_LOCAL_BACKEND
336 return local_create_context();
337 #else
338 errno = ENOSYS;
339 return NULL;
340 #endif
341 }
342
iio_create_network_context(const char * hostname)343 struct iio_context * iio_create_network_context(const char *hostname)
344 {
345 #ifdef WITH_NETWORK_BACKEND
346 return network_create_context(hostname);
347 #else
348 errno = ENOSYS;
349 return NULL;
350 #endif
351 }
352
iio_create_xml_context_mem(const char * xml,size_t len)353 struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
354 {
355 #ifdef WITH_XML_BACKEND
356 return xml_create_context_mem(xml, len);
357 #else
358 errno = ENOSYS;
359 return NULL;
360 #endif
361 }
362
iio_create_xml_context(const char * xml_file)363 struct iio_context * iio_create_xml_context(const char *xml_file)
364 {
365 #ifdef WITH_XML_BACKEND
366 return xml_create_context(xml_file);
367 #else
368 errno = ENOSYS;
369 return NULL;
370 #endif
371 }
372
iio_context_get_attrs_count(const struct iio_context * ctx)373 unsigned int iio_context_get_attrs_count(const struct iio_context *ctx)
374 {
375 return ctx->nb_attrs;
376 }
377
iio_context_get_attr(const struct iio_context * ctx,unsigned int index,const char ** name,const char ** value)378 int iio_context_get_attr(const struct iio_context *ctx, unsigned int index,
379 const char **name, const char **value)
380 {
381 if (index >= ctx->nb_attrs)
382 return -EINVAL;
383
384 if (name)
385 *name = ctx->attrs[index];
386 if (value)
387 *value = ctx->values[index];
388 return 0;
389 }
390
iio_context_get_attr_value(const struct iio_context * ctx,const char * name)391 const char * iio_context_get_attr_value(
392 const struct iio_context *ctx, const char *name)
393 {
394 unsigned int i;
395
396 for (i = 0; i < ctx->nb_attrs; i++) {
397 if (!strcmp(name, ctx->attrs[i]))
398 return ctx->values[i];
399 }
400
401 return NULL;
402 }
403
iio_context_add_attr(struct iio_context * ctx,const char * key,const char * value)404 int iio_context_add_attr(struct iio_context *ctx,
405 const char *key, const char *value)
406 {
407 char **attrs, **values, *new_key, *new_val;
408
409 attrs = realloc(ctx->attrs,
410 (ctx->nb_attrs + 1) * sizeof(*ctx->attrs));
411 if (!attrs)
412 return -ENOMEM;
413
414 ctx->attrs = attrs;
415
416 values = realloc(ctx->values,
417 (ctx->nb_attrs + 1) * sizeof(*ctx->values));
418 if (!values)
419 return -ENOMEM;
420
421 ctx->values = values;
422
423 new_key = iio_strdup(key);
424 if (!new_key)
425 return -ENOMEM;
426
427 new_val = iio_strdup(value);
428 if (!new_val) {
429 free(new_key);
430 return -ENOMEM;
431 }
432
433 ctx->attrs[ctx->nb_attrs] = new_key;
434 ctx->values[ctx->nb_attrs] = new_val;
435 ctx->nb_attrs++;
436 return 0;
437 }
438