blob: 98282ab5174900a34b4196333d5f075f4f039014 [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 Cercueil0b2ce712014-02-17 15:04:18 +010020#include "iio-private.h"
21
Paul Cercueil4c6729d2014-04-04 17:24:41 +020022#include <errno.h>
Paul Cercueil42090d12014-02-24 12:32:23 +010023#include <string.h>
24
Paul Cercueil8f56ea72014-10-28 15:18:18 +010025#ifdef _WIN32
26#define LOCAL_BACKEND 0
27#define NETWORK_BACKEND 1
28#endif
29
Paul Cercueil42090d12014-02-24 12:32:23 +010030static const char xml_header[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
31"<!DOCTYPE context ["
32"<!ELEMENT context (device)*>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020033"<!ELEMENT device (channel | attribute | debug-attribute)*>"
Paul Cercueila7e80022014-06-11 11:41:26 +020034"<!ELEMENT channel (scan-element?, attribute*)>"
Paul Cercueil42090d12014-02-24 12:32:23 +010035"<!ELEMENT attribute EMPTY>"
Paul Cercueila7e80022014-06-11 11:41:26 +020036"<!ELEMENT scan-element EMPTY>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020037"<!ELEMENT debug-attribute EMPTY>"
Paul Cercueil87350372015-03-16 13:24:37 +010038"<!ATTLIST context name CDATA #REQUIRED description CDATA #IMPLIED>"
Paul Cercueil42090d12014-02-24 12:32:23 +010039"<!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED>"
Paul Cercueila7e80022014-06-11 11:41:26 +020040"<!ATTLIST channel id CDATA #REQUIRED type (input|output) #REQUIRED name CDATA #IMPLIED>"
41"<!ATTLIST scan-element index CDATA #REQUIRED format CDATA #REQUIRED scale CDATA #IMPLIED>"
Paul Cercueil42d12352014-05-05 16:11:58 +020042"<!ATTLIST attribute name CDATA #REQUIRED filename CDATA #IMPLIED>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020043"<!ATTLIST debug-attribute name CDATA #REQUIRED>"
Paul Cercueil42090d12014-02-24 12:32:23 +010044"]>";
45
46/* Returns a string containing the XML representation of this context */
Paul Cercueilc1ed8482014-06-11 16:29:43 +020047char * iio_context_create_xml(const struct iio_context *ctx)
Paul Cercueil42090d12014-02-24 12:32:23 +010048{
Paul Cercueil87350372015-03-16 13:24:37 +010049 size_t len, *devices_len;
Paul Cercueil5822ab62014-04-04 13:29:17 +020050 char *str, *ptr, **devices;
Paul Cercueil42090d12014-02-24 12:32:23 +010051 unsigned int i;
52
Paul Cercueil87350372015-03-16 13:24:37 +010053 len = strlen(ctx->name) + sizeof(xml_header) - 1 +
54 sizeof("<context name=\"\" ></context>");
55 if (ctx->description)
56 len += strlen(ctx->description) +
57 sizeof(" description=\"\"") - 1;
58
Paul Cercueil9aab0192014-04-07 11:04:30 +020059 if (!ctx->nb_devices) {
60 str = malloc(len);
Paul Cercueil87350372015-03-16 13:24:37 +010061 if (!str)
62 return NULL;
63
64 if (ctx->description)
65 snprintf(str, len, "%s<context name=\"%s\" "
66 "description=\"%s\" ></context>",
67 xml_header, ctx->name,
68 ctx->description);
69 else
Paul Cercueil9aab0192014-04-07 11:04:30 +020070 snprintf(str, len, "%s<context name=\"%s\" ></context>",
71 xml_header, ctx->name);
72 return str;
73 }
74
Paul Cercueil5822ab62014-04-04 13:29:17 +020075 devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
76 if (!devices_len)
77 return NULL;
78
79 devices = malloc(ctx->nb_devices * sizeof(*devices));
80 if (!devices)
81 goto err_free_devices_len;
82
Paul Cercueil42090d12014-02-24 12:32:23 +010083 for (i = 0; i < ctx->nb_devices; i++) {
84 char *xml = iio_device_get_xml(ctx->devices[i],
85 &devices_len[i]);
86 if (!xml)
87 goto err_free_devices;
88 devices[i] = xml;
89 len += devices_len[i];
90 }
91
92 str = malloc(len);
93 if (!str)
94 goto err_free_devices;
95
Paul Cercueil87350372015-03-16 13:24:37 +010096 if (ctx->description)
97 snprintf(str, len, "%s<context name=\"%s\" "
98 "description=\"%s\" >",
99 xml_header, ctx->name, ctx->description);
100 else
101 snprintf(str, len, "%s<context name=\"%s\" >",
102 xml_header, ctx->name);
Paul Cercueil42090d12014-02-24 12:32:23 +0100103 ptr = strrchr(str, '\0');
104
105 for (i = 0; i < ctx->nb_devices; i++) {
106 strcpy(ptr, devices[i]);
107 ptr += devices_len[i];
108 free(devices[i]);
109 }
110
Paul Cercueil5822ab62014-04-04 13:29:17 +0200111 free(devices);
112 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100113 strcpy(ptr, "</context>");
114 return str;
115
116err_free_devices:
117 while (i--)
118 free(devices[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +0200119 free(devices);
120err_free_devices_len:
121 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +0100122 return NULL;
123}
124
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200125const char * iio_context_get_xml(const struct iio_context *ctx)
126{
127 return ctx->xml;
128}
129
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100130const char * iio_context_get_name(const struct iio_context *ctx)
131{
132 return ctx->name;
133}
134
Paul Cercueil3ac36c12015-01-08 14:44:00 +0100135const char * iio_context_get_description(const struct iio_context *ctx)
136{
137 if (ctx->description)
138 return ctx->description;
139 else
140 return "";
141}
142
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100143void iio_context_destroy(struct iio_context *ctx)
144{
Paul Cercueil50363542014-02-18 16:04:28 +0100145 unsigned int i;
146 if (ctx->ops->shutdown)
147 ctx->ops->shutdown(ctx);
148
149 for (i = 0; i < ctx->nb_devices; i++)
150 free_device(ctx->devices[i]);
151 if (ctx->nb_devices)
152 free(ctx->devices);
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200153 if (ctx->xml)
154 free(ctx->xml);
Paul Cercueil3ac36c12015-01-08 14:44:00 +0100155 if (ctx->description)
156 free(ctx->description);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100157 free(ctx);
158}
159
160unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
161{
162 return ctx->nb_devices;
163}
164
165struct iio_device * iio_context_get_device(const struct iio_context *ctx,
166 unsigned int index)
167{
168 if (index >= ctx->nb_devices)
169 return NULL;
170 else
171 return ctx->devices[index];
172}
Paul Cercueilae88fde2014-03-12 11:47:10 +0100173
Paul Cercueil17512b02014-03-28 11:15:24 +0100174struct iio_device * iio_context_find_device(const struct iio_context *ctx,
175 const char *name)
176{
177 unsigned int i;
178 for (i = 0; i < ctx->nb_devices; i++) {
179 struct iio_device *dev = ctx->devices[i];
180 if (!strcmp(dev->id, name) ||
181 (dev->name && !strcmp(dev->name, name)))
182 return dev;
183 }
184 return NULL;
185}
186
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100187static void reorder_channels(struct iio_device *dev)
188{
189 bool found;
190 unsigned int i;
191
192 /* Reorder channels by index */
193 do {
194 found = false;
195 for (i = 1; i < dev->nb_channels; i++) {
196 struct iio_channel **channels = dev->channels;
197 long ch1 = channels[i - 1]->index;
198 long ch2 = channels[i]->index;
199
200 if (ch2 >= 0 && ((ch1 > ch2) || ch1 < 0)) {
201 struct iio_channel *bak = channels[i];
202 channels[i] = channels[i - 1];
203 channels[i - 1] = bak;
204 found = true;
205 }
206 }
207 } while (found);
208}
209
Paul Cercueilc1ed8482014-06-11 16:29:43 +0200210void iio_context_init(struct iio_context *ctx)
Paul Cercueilae88fde2014-03-12 11:47:10 +0100211{
212 unsigned int i;
Paul Cercueila7e80022014-06-11 11:41:26 +0200213 for (i = 0; i < ctx->nb_devices; i++)
214 reorder_channels(ctx->devices[i]);
Paul Cercueilae88fde2014-03-12 11:47:10 +0100215}
Paul Cercueile45f8762014-05-02 11:19:26 +0200216
217int iio_context_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200218 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueile45f8762014-05-02 11:19:26 +0200219{
220 if (ctx->ops->get_version)
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200221 return ctx->ops->get_version(ctx, major, minor, git_tag);
Paul Cercueil53ed9432014-11-20 13:46:04 +0100222
223 iio_library_get_version(major, minor, git_tag);
Paul Cercueile45f8762014-05-02 11:19:26 +0200224 return 0;
225}
Paul Cercueil4ca73542014-06-10 16:23:29 +0200226
227int iio_context_set_timeout(struct iio_context *ctx, unsigned int timeout)
228{
229 if (ctx->ops->set_timeout)
230 return ctx->ops->set_timeout(ctx, timeout);
231 else
232 return -ENOSYS;
233}
Paul Cercueil63d5e7c2014-10-28 14:33:08 +0100234
235struct iio_context * iio_context_clone(const struct iio_context *ctx)
236{
237 if (ctx->ops->clone)
238 return ctx->ops->clone(ctx);
239 else
240 return NULL;
241}
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100242
243struct iio_context * iio_create_default_context(void)
244{
245#if NETWORK_BACKEND
246 char *hostname = getenv("IIOD_REMOTE");
247
248 if (hostname) {
249 /* If the environment variable is an empty string, we will
250 * discover the server using ZeroConf */
251 if (strlen(hostname) == 0)
252 hostname = NULL;
253
254 return iio_create_network_context(hostname);
255 }
256#endif
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100257 return iio_create_local_context();
Paul Cercueil63e52182014-12-11 12:52:48 +0100258}
259
260struct iio_context * iio_create_local_context(void)
261{
262#if LOCAL_BACKEND
263 return local_create_context();
264#else
265 return NULL;
266#endif
267}
268
269struct iio_context * iio_create_network_context(const char *hostname)
270{
271#if NETWORK_BACKEND
272 return network_create_context(hostname);
273#else
274 return NULL;
275#endif
276}
277
278struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
279{
280#if NETWORK_BACKEND
281 return xml_create_context_mem(xml, len);
282#else
283 return NULL;
284#endif
285}
286
287struct iio_context * iio_create_xml_context(const char *xml_file)
288{
289#if NETWORK_BACKEND
290 return xml_create_context(xml_file);
Paul Cercueil8f56ea72014-10-28 15:18:18 +0100291#else
292 return NULL;
293#endif
294}