• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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