blob: 9d220e2cf003b984ee2572e416233766b272f4cf [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 Cercueil42d12352014-05-05 16:11:58 +020029 char *name = NULL, *filename = NULL;
Paul Cercueilb34e0222014-05-05 15:32:38 +020030 struct iio_channel_attr *attrs;
Paul Cercueil5d9db302014-02-18 18:16:51 +010031
32 for (attr = n->properties; attr; attr = attr->next) {
33 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +020034 name = iio_strdup((char *) attr->children->content);
Paul Cercueil42d12352014-05-05 16:11:58 +020035 } else if (!strcmp((char *) attr->name, "filename")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +020036 filename = iio_strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010037 } else {
38 WARNING("Unknown field \'%s\' in channel %s\n",
39 attr->name, chn->id);
40 }
41 }
42
Paul Cercueil7150c6e2015-04-14 16:26:21 +020043 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010044 ERROR("Incomplete attribute in channel %s\n", chn->id);
45 goto err_free;
46 }
47
Paul Cercueil7150c6e2015-04-14 16:26:21 +020048 if (!filename) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +020049 filename = iio_strdup(name);
Paul Cercueil7150c6e2015-04-14 16:26:21 +020050 if (!filename)
51 goto err_free;
52 }
53
Paul Cercueilb34e0222014-05-05 15:32:38 +020054 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
55 sizeof(struct iio_channel_attr));
Paul Cercueil5d9db302014-02-18 18:16:51 +010056 if (!attrs)
57 goto err_free;
58
Paul Cercueil42d12352014-05-05 16:11:58 +020059 attrs[chn->nb_attrs].filename = filename;
Paul Cercueilb34e0222014-05-05 15:32:38 +020060 attrs[chn->nb_attrs++].name = name;
Paul Cercueil5d9db302014-02-18 18:16:51 +010061 chn->attrs = attrs;
62 return 0;
63
Paul Cercueil5d9db302014-02-18 18:16:51 +010064err_free:
65 if (name)
66 free(name);
Paul Cercueil42d12352014-05-05 16:11:58 +020067 if (filename)
68 free(filename);
Paul Cercueil5d9db302014-02-18 18:16:51 +010069 return -1;
70}
71
Paul Cercueil501961b2014-04-15 11:23:30 +020072static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug)
Paul Cercueil5d9db302014-02-18 18:16:51 +010073{
74 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010075 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010076
77 for (attr = n->properties; attr; attr = attr->next) {
78 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +020079 name = iio_strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010080 } else {
81 WARNING("Unknown field \'%s\' in device %s\n",
82 attr->name, dev->id);
83 }
84 }
85
Paul Cercueil5cd260e2014-02-24 13:16:01 +010086 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010087 ERROR("Incomplete attribute in device %s\n", dev->id);
88 goto err_free;
89 }
90
Paul Cercueil501961b2014-04-15 11:23:30 +020091 if (is_debug)
92 attrs = realloc(dev->debug_attrs,
93 (1 + dev->nb_debug_attrs) * sizeof(char *));
94 else
95 attrs = realloc(dev->attrs,
96 (1 + dev->nb_attrs) * sizeof(char *));
Paul Cercueil5d9db302014-02-18 18:16:51 +010097 if (!attrs)
98 goto err_free;
99
Paul Cercueil501961b2014-04-15 11:23:30 +0200100 if (is_debug) {
101 attrs[dev->nb_debug_attrs++] = name;
102 dev->debug_attrs = attrs;
103 } else {
104 attrs[dev->nb_attrs++] = name;
105 dev->attrs = attrs;
106 }
Paul Cercueil5d9db302014-02-18 18:16:51 +0100107 return 0;
108
Paul Cercueil5d9db302014-02-18 18:16:51 +0100109err_free:
110 if (name)
111 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100112 return -1;
113}
114
Paul Cercueila7e80022014-06-11 11:41:26 +0200115static void setup_scan_element(struct iio_channel *chn, xmlNode *n)
116{
117 xmlAttr *attr;
118
119 for (attr = n->properties; attr; attr = attr->next) {
120 const char *name = (const char *) attr->name,
121 *content = (const char *) attr->children->content;
122 if (!strcmp(name, "index")) {
123 chn->index = atol(content);
124 } else if (!strcmp(name, "format")) {
125 char e, s;
Lucas Magasweran77fe2912016-08-29 13:47:29 -0700126 if (strchr(content, 'X')) {
127 sscanf(content, "%ce:%c%u/%uX%u>>%u", &e, &s,
128 &chn->format.bits,
129 &chn->format.length,
130 &chn->format.repeat,
131 &chn->format.shift);
132 } else {
133 chn->format.repeat = 1;
134 sscanf(content, "%ce:%c%u/%u>>%u", &e, &s,
Paul Cercueila7e80022014-06-11 11:41:26 +0200135 &chn->format.bits,
136 &chn->format.length,
137 &chn->format.shift);
Lucas Magasweran77fe2912016-08-29 13:47:29 -0700138 }
Paul Cercueila7e80022014-06-11 11:41:26 +0200139 chn->format.is_be = e == 'b';
Michael Hennerichfa3c6f62014-08-13 11:21:23 +0200140 chn->format.is_signed = (s == 's' || s == 'S');
141 chn->format.is_fully_defined = (s == 'S' || s == 'U' ||
142 chn->format.bits == chn->format.length);
Paul Cercueila7e80022014-06-11 11:41:26 +0200143 } else if (!strcmp(name, "scale")) {
144 chn->format.with_scale = true;
145 chn->format.scale = atof(content);
146 } else {
147 WARNING("Unknown attribute \'%s\' in <scan-element>\n",
148 name);
149 }
150 }
151}
152
Paul Cercueil5d9db302014-02-18 18:16:51 +0100153static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
154{
155 xmlAttr *attr;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +0100156 struct iio_channel *chn = zalloc(sizeof(*chn));
Paul Cercueil5d9db302014-02-18 18:16:51 +0100157 if (!chn)
158 return NULL;
159
160 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100161
Paul Cercueild8d58932014-06-12 10:08:36 +0200162 /* Set the default index value < 0 (== no index) */
163 chn->index = -ENOENT;
164
Paul Cercueil5d9db302014-02-18 18:16:51 +0100165 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +0100166 const char *name = (const char *) attr->name,
167 *content = (const char *) attr->children->content;
168 if (!strcmp(name, "name")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200169 chn->name = iio_strdup(content);
Paul Cercueil35a01312014-02-20 10:56:57 +0100170 } else if (!strcmp(name, "id")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200171 chn->id = iio_strdup(content);
Paul Cercueil35a01312014-02-20 10:56:57 +0100172 } else if (!strcmp(name, "type")) {
173 if (!strcmp(content, "output"))
174 chn->is_output = true;
175 else if (strcmp(content, "input"))
176 WARNING("Unknown channel type %s\n", content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100177 } else {
178 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +0100179 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100180 }
181 }
182
183 if (!chn->id) {
184 ERROR("Incomplete <attribute>\n");
185 goto err_free_channel;
186 }
187
188 for (n = n->children; n; n = n->next) {
189 if (!strcmp((char *) n->name, "attribute")) {
190 if (add_attr_to_channel(chn, n) < 0)
191 goto err_free_channel;
Paul Cercueila7e80022014-06-11 11:41:26 +0200192 } else if (!strcmp((char *) n->name, "scan-element")) {
193 chn->is_scan_element = true;
194 setup_scan_element(chn, n);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100195 } else if (strcmp((char *) n->name, "text")) {
Paul Cercueilf7361902015-04-16 16:31:49 +0200196 WARNING("Unknown children \'%s\' in <channel>\n",
Paul Cercueil5d9db302014-02-18 18:16:51 +0100197 n->name);
198 continue;
199 }
200 }
201
Lars-Peter Clausenc6f85922016-04-20 15:03:49 +0200202 iio_channel_init_finalize(chn);
203
Paul Cercueil5d9db302014-02-18 18:16:51 +0100204 return chn;
205
206err_free_channel:
207 free_channel(chn);
208 return NULL;
209}
210
211static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
212{
213 xmlAttr *attr;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +0100214 struct iio_device *dev = zalloc(sizeof(*dev));
Paul Cercueil5d9db302014-02-18 18:16:51 +0100215 if (!dev)
216 return NULL;
217
218 dev->ctx = ctx;
219
220 for (attr = n->properties; attr; attr = attr->next) {
221 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200222 dev->name = iio_strdup(
223 (char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100224 } else if (!strcmp((char *) attr->name, "id")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200225 dev->id = iio_strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100226 } else {
Paul Cercueilf7361902015-04-16 16:31:49 +0200227 WARNING("Unknown attribute \'%s\' in <device>\n",
Paul Cercueil5d9db302014-02-18 18:16:51 +0100228 attr->name);
229 }
230 }
231
232 if (!dev->id) {
233 ERROR("Unable to read device ID\n");
234 goto err_free_device;
235 }
236
237 for (n = n->children; n; n = n->next) {
238 if (!strcmp((char *) n->name, "channel")) {
239 struct iio_channel **chns,
240 *chn = create_channel(dev, n);
241 if (!chn) {
242 ERROR("Unable to create channel\n");
243 goto err_free_device;
244 }
245
246 chns = realloc(dev->channels, (1 + dev->nb_channels) *
247 sizeof(struct iio_channel *));
248 if (!chns) {
249 ERROR("Unable to allocate memory\n");
250 free(chn);
251 goto err_free_device;
252 }
253
254 chns[dev->nb_channels++] = chn;
255 dev->channels = chns;
256 } else if (!strcmp((char *) n->name, "attribute")) {
Paul Cercueil501961b2014-04-15 11:23:30 +0200257 if (add_attr_to_device(dev, n, false) < 0)
258 goto err_free_device;
259 } else if (!strcmp((char *) n->name, "debug-attribute")) {
260 if (add_attr_to_device(dev, n, true) < 0)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100261 goto err_free_device;
262 } else if (strcmp((char *) n->name, "text")) {
263 WARNING("Unknown children \'%s\' in <device>\n",
264 n->name);
265 continue;
266 }
267 }
268
Paul Cercueiledec1cb2015-04-20 10:40:28 +0200269 dev->words = (dev->nb_channels + 31) / 32;
270 if (dev->words) {
271 dev->mask = calloc(dev->words, sizeof(*dev->mask));
272 if (!dev->mask) {
273 errno = ENOMEM;
274 goto err_free_device;
275 }
276 }
277
Paul Cercueil5d9db302014-02-18 18:16:51 +0100278 return dev;
279
280err_free_device:
281 free_device(dev);
282 return NULL;
283}
284
Paul Cercueil927818d2014-10-28 14:38:24 +0100285static struct iio_context * xml_clone(const struct iio_context *ctx)
286{
Paul Cercueil63e52182014-12-11 12:52:48 +0100287 return xml_create_context_mem(ctx->xml, strlen(ctx->xml));
Paul Cercueil927818d2014-10-28 14:38:24 +0100288}
289
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +0100290static const struct iio_backend_ops xml_ops = {
Paul Cercueil927818d2014-10-28 14:38:24 +0100291 .clone = xml_clone,
Paul Cercueil5d9db302014-02-18 18:16:51 +0100292};
293
Paul Cercueil00dc2152016-11-15 16:37:35 +0100294static int parse_context_attr(struct iio_context *ctx, xmlNode *n)
295{
296 xmlAttr *attr;
297 const char *name = NULL, *value = NULL;
298
299 for (attr = n->properties; attr; attr = attr->next) {
300 if (!strcmp((const char *) attr->name, "name")) {
301 name = (const char *) attr->children->content;
302 } else if (!strcmp((const char *) attr->name, "value")) {
303 value = (const char *) attr->children->content;
304 }
305 }
306
307 if (!name || !value)
308 return -EINVAL;
309 else
310 return iio_context_add_attr(ctx, name, value);
311}
312
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100313static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100314{
315 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100316 xmlNode *root, *n;
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100317 xmlAttr *attr;
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100318 int err = ENOMEM;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +0100319 struct iio_context *ctx = zalloc(sizeof(*ctx));
Paul Cercueil5d9db302014-02-18 18:16:51 +0100320 if (!ctx)
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100321 goto err_set_errno;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100322
Paul Cercueil5d9db302014-02-18 18:16:51 +0100323 ctx->name = "xml";
324 ctx->ops = &xml_ops;
325
Paul Cercueil5d9db302014-02-18 18:16:51 +0100326 root = xmlDocGetRootElement(doc);
327 if (strcmp((char *) root->name, "context")) {
328 ERROR("Unrecognized XML file\n");
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100329 err = EINVAL;
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100330 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100331 }
332
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100333 for (attr = root->properties; attr; attr = attr->next) {
334 if (!strcmp((char *) attr->name, "description"))
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200335 ctx->description = iio_strdup(
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100336 (char *) attr->children->content);
337 else if (strcmp((char *) attr->name, "name"))
338 WARNING("Unknown parameter \'%s\' in <context>\n",
339 (char *) attr->children->content);
340 }
341
Paul Cercueil5d9db302014-02-18 18:16:51 +0100342 for (n = root->children; n; n = n->next) {
343 struct iio_device **devs, *dev;
344
Paul Cercueil00dc2152016-11-15 16:37:35 +0100345 if (!strcmp((char *) n->name, "context-attribute")) {
346 err = parse_context_attr(ctx, n);
347 if (err)
348 goto err_free_devices;
349 else
350 continue;
351 } else if (strcmp((char *) n->name, "device")) {
Paul Cercueil5d9db302014-02-18 18:16:51 +0100352 if (strcmp((char *) n->name, "text"))
353 WARNING("Unknown children \'%s\' in "
354 "<context>\n", n->name);
355 continue;
356 }
357
358 dev = create_device(ctx, n);
359 if (!dev) {
360 ERROR("Unable to create device\n");
361 goto err_free_devices;
362 }
363
364 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
365 sizeof(struct iio_device *));
366 if (!devs) {
367 ERROR("Unable to allocate memory\n");
368 free(dev);
369 goto err_free_devices;
370 }
371
372 devs[ctx->nb_devices++] = dev;
373 ctx->devices = devs;
374 }
375
Paul Cercueilfd387472015-08-05 10:34:19 +0200376 err = iio_context_init(ctx);
377 if (err)
378 goto err_free_devices;
379
Paul Cercueilc1ed8482014-06-11 16:29:43 +0200380 return ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100381
382err_free_devices:
383 for (i = 0; i < ctx->nb_devices; i++)
384 free_device(ctx->devices[i]);
385 if (ctx->nb_devices)
386 free(ctx->devices);
Paul Cercueil00dc2152016-11-15 16:37:35 +0100387 for (i = 0; i < ctx->nb_attrs; i++) {
388 free(ctx->attrs[i]);
389 free(ctx->values[i]);
390 }
391 free(ctx->attrs);
392 free(ctx->values);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100393err_free_ctx:
394 free(ctx);
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100395err_set_errno:
396 errno = err;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100397 return NULL;
398}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100399
Paul Cercueil63e52182014-12-11 12:52:48 +0100400struct iio_context * xml_create_context(const char *xml_file)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100401{
402 struct iio_context *ctx;
403 xmlDoc *doc;
404
405 LIBXML_TEST_VERSION;
406
407 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
408 if (!doc) {
409 ERROR("Unable to parse XML file\n");
410 return NULL;
411 }
412
413 ctx = iio_create_xml_context_helper(doc);
414 xmlFreeDoc(doc);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100415 return ctx;
416}
417
Paul Cercueil63e52182014-12-11 12:52:48 +0100418struct iio_context * xml_create_context_mem(const char *xml, size_t len)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100419{
420 struct iio_context *ctx;
421 xmlDoc *doc;
422
423 LIBXML_TEST_VERSION;
424
Paul Cercueil4012cff2015-05-11 10:47:40 +0200425 doc = xmlReadMemory(xml, (int) len, NULL, NULL, XML_PARSE_DTDVALID);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100426 if (!doc) {
427 ERROR("Unable to parse XML file\n");
428 return NULL;
429 }
430
431 ctx = iio_create_xml_context_helper(doc);
432 xmlFreeDoc(doc);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100433 return ctx;
434}