blob: e1e8f0d998107333b9321ee29ddd53542ccf537c [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 Cercueil5d9db302014-02-18 18:16:51 +010019#include "debug.h"
20#include "iio-private.h"
21
22#include <errno.h>
23#include <libxml/tree.h>
24#include <string.h>
25
Paul Cercueil5d9db302014-02-18 18:16:51 +010026static int add_attr_to_channel(struct iio_channel *chn, xmlNode *n)
27{
28 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010029 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010030
31 for (attr = n->properties; attr; attr = attr->next) {
32 if (!strcmp((char *) attr->name, "name")) {
33 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010034 } else {
35 WARNING("Unknown field \'%s\' in channel %s\n",
36 attr->name, chn->id);
37 }
38 }
39
Paul Cercueil5cd260e2014-02-24 13:16:01 +010040 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010041 ERROR("Incomplete attribute in channel %s\n", chn->id);
42 goto err_free;
43 }
44
45 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) * sizeof(char *));
46 if (!attrs)
47 goto err_free;
48
Paul Cercueil5d9db302014-02-18 18:16:51 +010049 attrs[chn->nb_attrs++] = name;
50 chn->attrs = attrs;
51 return 0;
52
Paul Cercueil5d9db302014-02-18 18:16:51 +010053err_free:
54 if (name)
55 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +010056 return -1;
57}
58
Paul Cercueil501961b2014-04-15 11:23:30 +020059static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug)
Paul Cercueil5d9db302014-02-18 18:16:51 +010060{
61 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010062 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010063
64 for (attr = n->properties; attr; attr = attr->next) {
65 if (!strcmp((char *) attr->name, "name")) {
66 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010067 } else {
68 WARNING("Unknown field \'%s\' in device %s\n",
69 attr->name, dev->id);
70 }
71 }
72
Paul Cercueil5cd260e2014-02-24 13:16:01 +010073 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010074 ERROR("Incomplete attribute in device %s\n", dev->id);
75 goto err_free;
76 }
77
Paul Cercueil501961b2014-04-15 11:23:30 +020078 if (is_debug)
79 attrs = realloc(dev->debug_attrs,
80 (1 + dev->nb_debug_attrs) * sizeof(char *));
81 else
82 attrs = realloc(dev->attrs,
83 (1 + dev->nb_attrs) * sizeof(char *));
Paul Cercueil5d9db302014-02-18 18:16:51 +010084 if (!attrs)
85 goto err_free;
86
Paul Cercueil501961b2014-04-15 11:23:30 +020087 if (is_debug) {
88 attrs[dev->nb_debug_attrs++] = name;
89 dev->debug_attrs = attrs;
90 } else {
91 attrs[dev->nb_attrs++] = name;
92 dev->attrs = attrs;
93 }
Paul Cercueil5d9db302014-02-18 18:16:51 +010094 return 0;
95
Paul Cercueil5d9db302014-02-18 18:16:51 +010096err_free:
97 if (name)
98 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +010099 return -1;
100}
101
102static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
103{
104 xmlAttr *attr;
105 struct iio_channel *chn = calloc(1, sizeof(*chn));
106 if (!chn)
107 return NULL;
108
109 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100110
111 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +0100112 const char *name = (const char *) attr->name,
113 *content = (const char *) attr->children->content;
114 if (!strcmp(name, "name")) {
115 chn->name = strdup(content);
116 } else if (!strcmp(name, "id")) {
117 chn->id = strdup(content);
118 } else if (!strcmp(name, "type")) {
119 if (!strcmp(content, "output"))
120 chn->is_output = true;
121 else if (strcmp(content, "input"))
122 WARNING("Unknown channel type %s\n", content);
Paul Cercueil88526632014-04-24 17:09:29 +0200123 } else if (!strcmp(name, "scan_element")) {
124 chn->is_scan_element = !strcmp(content, "true");
Paul Cercueil5d9db302014-02-18 18:16:51 +0100125 } else {
126 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +0100127 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100128 }
129 }
130
131 if (!chn->id) {
132 ERROR("Incomplete <attribute>\n");
133 goto err_free_channel;
134 }
135
136 for (n = n->children; n; n = n->next) {
137 if (!strcmp((char *) n->name, "attribute")) {
138 if (add_attr_to_channel(chn, n) < 0)
139 goto err_free_channel;
140 } else if (strcmp((char *) n->name, "text")) {
141 WARNING("Unknown children \'%s\' in <device>\n",
142 n->name);
143 continue;
144 }
145 }
146
147 return chn;
148
149err_free_channel:
150 free_channel(chn);
151 return NULL;
152}
153
154static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
155{
156 xmlAttr *attr;
157 struct iio_device *dev = calloc(1, sizeof(*dev));
158 if (!dev)
159 return NULL;
160
161 dev->ctx = ctx;
162
163 for (attr = n->properties; attr; attr = attr->next) {
164 if (!strcmp((char *) attr->name, "name")) {
165 dev->name = strdup((char *) attr->children->content);
166 } else if (!strcmp((char *) attr->name, "id")) {
167 dev->id = strdup((char *) attr->children->content);
168 } else {
169 WARNING("Unknown attribute \'%s\' in <context>\n",
170 attr->name);
171 }
172 }
173
174 if (!dev->id) {
175 ERROR("Unable to read device ID\n");
176 goto err_free_device;
177 }
178
179 for (n = n->children; n; n = n->next) {
180 if (!strcmp((char *) n->name, "channel")) {
181 struct iio_channel **chns,
182 *chn = create_channel(dev, n);
183 if (!chn) {
184 ERROR("Unable to create channel\n");
185 goto err_free_device;
186 }
187
188 chns = realloc(dev->channels, (1 + dev->nb_channels) *
189 sizeof(struct iio_channel *));
190 if (!chns) {
191 ERROR("Unable to allocate memory\n");
192 free(chn);
193 goto err_free_device;
194 }
195
196 chns[dev->nb_channels++] = chn;
197 dev->channels = chns;
198 } else if (!strcmp((char *) n->name, "attribute")) {
Paul Cercueil501961b2014-04-15 11:23:30 +0200199 if (add_attr_to_device(dev, n, false) < 0)
200 goto err_free_device;
201 } else if (!strcmp((char *) n->name, "debug-attribute")) {
202 if (add_attr_to_device(dev, n, true) < 0)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100203 goto err_free_device;
204 } else if (strcmp((char *) n->name, "text")) {
205 WARNING("Unknown children \'%s\' in <device>\n",
206 n->name);
207 continue;
208 }
209 }
210
211 return dev;
212
213err_free_device:
214 free_device(dev);
215 return NULL;
216}
217
Paul Cercueil5d9db302014-02-18 18:16:51 +0100218static struct iio_backend_ops xml_ops = {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200219 .read = NULL, /* ISO C99 forbids empty initializer braces */
Paul Cercueil5d9db302014-02-18 18:16:51 +0100220};
221
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100222static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100223{
224 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100225 xmlNode *root, *n;
226 struct iio_context *ctx = calloc(1, sizeof(*ctx));
227 if (!ctx)
228 return NULL;
229
Paul Cercueil5d9db302014-02-18 18:16:51 +0100230 ctx->name = "xml";
231 ctx->ops = &xml_ops;
232
Paul Cercueil5d9db302014-02-18 18:16:51 +0100233 root = xmlDocGetRootElement(doc);
234 if (strcmp((char *) root->name, "context")) {
235 ERROR("Unrecognized XML file\n");
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100236 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100237 }
238
239 for (n = root->children; n; n = n->next) {
240 struct iio_device **devs, *dev;
241
242 if (strcmp((char *) n->name, "device")) {
243 if (strcmp((char *) n->name, "text"))
244 WARNING("Unknown children \'%s\' in "
245 "<context>\n", n->name);
246 continue;
247 }
248
249 dev = create_device(ctx, n);
250 if (!dev) {
251 ERROR("Unable to create device\n");
252 goto err_free_devices;
253 }
254
255 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
256 sizeof(struct iio_device *));
257 if (!devs) {
258 ERROR("Unable to allocate memory\n");
259 free(dev);
260 goto err_free_devices;
261 }
262
263 devs[ctx->nb_devices++] = dev;
264 ctx->devices = devs;
265 }
266
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200267 if (!iio_context_init(ctx))
268 return ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100269
270err_free_devices:
271 for (i = 0; i < ctx->nb_devices; i++)
272 free_device(ctx->devices[i]);
273 if (ctx->nb_devices)
274 free(ctx->devices);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100275err_free_ctx:
276 free(ctx);
277 return NULL;
278}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100279
280struct iio_context * iio_create_xml_context(const char *xml_file)
281{
282 struct iio_context *ctx;
283 xmlDoc *doc;
284
285 LIBXML_TEST_VERSION;
286
287 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
288 if (!doc) {
289 ERROR("Unable to parse XML file\n");
290 return NULL;
291 }
292
293 ctx = iio_create_xml_context_helper(doc);
294 xmlFreeDoc(doc);
295 xmlCleanupParser();
296 return ctx;
297}
298
Paul Cercueildda33eb2014-03-03 15:00:11 +0100299struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100300{
301 struct iio_context *ctx;
302 xmlDoc *doc;
303
304 LIBXML_TEST_VERSION;
305
Paul Cercueildda33eb2014-03-03 15:00:11 +0100306 doc = xmlReadMemory(xml, len, NULL, NULL, XML_PARSE_DTDVALID);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100307 if (!doc) {
308 ERROR("Unable to parse XML file\n");
309 return NULL;
310 }
311
312 ctx = iio_create_xml_context_helper(doc);
313 xmlFreeDoc(doc);
314 xmlCleanupParser();
315 return ctx;
316}