blob: 7b87327ff95b7ce9617e58b4a49dc2c7cabc85a3 [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
Matt Fornero81f04a52017-11-30 14:36:37 -050072static int add_attr_to_device(struct iio_device *dev, xmlNode *n, enum iio_attr_type type)
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
Matt Fornero81f04a52017-11-30 14:36:37 -050091 switch(type) {
92 case IIO_ATTR_TYPE_DEBUG:
93 attrs = realloc(dev->debug_attrs,
94 (1 + dev->nb_debug_attrs) * sizeof(char *));
95 break;
96 case IIO_ATTR_TYPE_DEVICE:
97 attrs = realloc(dev->attrs,
98 (1 + dev->nb_attrs) * sizeof(char *));
99 break;
100 case IIO_ATTR_TYPE_BUFFER:
101 attrs = realloc(dev->buffer_attrs,
102 (1 + dev->nb_buffer_attrs) * sizeof(char *));
103 break;
104 default:
105 attrs = NULL;
106 break;
107 }
Paul Cercueil5d9db302014-02-18 18:16:51 +0100108 if (!attrs)
109 goto err_free;
110
Matt Fornero81f04a52017-11-30 14:36:37 -0500111 switch(type) {
112 case IIO_ATTR_TYPE_DEBUG:
113 attrs[dev->nb_debug_attrs++] = name;
114 dev->debug_attrs = attrs;
115 break;
116 case IIO_ATTR_TYPE_DEVICE:
117 attrs[dev->nb_attrs++] = name;
118 dev->attrs = attrs;
119 break;
120 case IIO_ATTR_TYPE_BUFFER:
121 attrs[dev->nb_buffer_attrs++] = name;
122 dev->buffer_attrs = attrs;
123 break;
Paul Cercueil501961b2014-04-15 11:23:30 +0200124 }
Matt Fornero81f04a52017-11-30 14:36:37 -0500125
Paul Cercueil5d9db302014-02-18 18:16:51 +0100126 return 0;
127
Paul Cercueil5d9db302014-02-18 18:16:51 +0100128err_free:
129 if (name)
130 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100131 return -1;
132}
133
Paul Cercueila7e80022014-06-11 11:41:26 +0200134static void setup_scan_element(struct iio_channel *chn, xmlNode *n)
135{
136 xmlAttr *attr;
137
138 for (attr = n->properties; attr; attr = attr->next) {
139 const char *name = (const char *) attr->name,
140 *content = (const char *) attr->children->content;
141 if (!strcmp(name, "index")) {
142 chn->index = atol(content);
143 } else if (!strcmp(name, "format")) {
144 char e, s;
Lucas Magasweran77fe2912016-08-29 13:47:29 -0700145 if (strchr(content, 'X')) {
146 sscanf(content, "%ce:%c%u/%uX%u>>%u", &e, &s,
147 &chn->format.bits,
148 &chn->format.length,
149 &chn->format.repeat,
150 &chn->format.shift);
151 } else {
152 chn->format.repeat = 1;
153 sscanf(content, "%ce:%c%u/%u>>%u", &e, &s,
Paul Cercueila7e80022014-06-11 11:41:26 +0200154 &chn->format.bits,
155 &chn->format.length,
156 &chn->format.shift);
Lucas Magasweran77fe2912016-08-29 13:47:29 -0700157 }
Paul Cercueila7e80022014-06-11 11:41:26 +0200158 chn->format.is_be = e == 'b';
Michael Hennerichfa3c6f62014-08-13 11:21:23 +0200159 chn->format.is_signed = (s == 's' || s == 'S');
160 chn->format.is_fully_defined = (s == 'S' || s == 'U' ||
161 chn->format.bits == chn->format.length);
Paul Cercueila7e80022014-06-11 11:41:26 +0200162 } else if (!strcmp(name, "scale")) {
163 chn->format.with_scale = true;
164 chn->format.scale = atof(content);
165 } else {
166 WARNING("Unknown attribute \'%s\' in <scan-element>\n",
167 name);
168 }
169 }
170}
171
Paul Cercueil5d9db302014-02-18 18:16:51 +0100172static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
173{
174 xmlAttr *attr;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +0100175 struct iio_channel *chn = zalloc(sizeof(*chn));
Paul Cercueil5d9db302014-02-18 18:16:51 +0100176 if (!chn)
177 return NULL;
178
179 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100180
Paul Cercueild8d58932014-06-12 10:08:36 +0200181 /* Set the default index value < 0 (== no index) */
182 chn->index = -ENOENT;
183
Paul Cercueil5d9db302014-02-18 18:16:51 +0100184 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +0100185 const char *name = (const char *) attr->name,
186 *content = (const char *) attr->children->content;
187 if (!strcmp(name, "name")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200188 chn->name = iio_strdup(content);
Paul Cercueil35a01312014-02-20 10:56:57 +0100189 } else if (!strcmp(name, "id")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200190 chn->id = iio_strdup(content);
Paul Cercueil35a01312014-02-20 10:56:57 +0100191 } else if (!strcmp(name, "type")) {
192 if (!strcmp(content, "output"))
193 chn->is_output = true;
194 else if (strcmp(content, "input"))
195 WARNING("Unknown channel type %s\n", content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100196 } else {
197 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +0100198 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100199 }
200 }
201
202 if (!chn->id) {
203 ERROR("Incomplete <attribute>\n");
204 goto err_free_channel;
205 }
206
207 for (n = n->children; n; n = n->next) {
208 if (!strcmp((char *) n->name, "attribute")) {
209 if (add_attr_to_channel(chn, n) < 0)
210 goto err_free_channel;
Paul Cercueila7e80022014-06-11 11:41:26 +0200211 } else if (!strcmp((char *) n->name, "scan-element")) {
212 chn->is_scan_element = true;
213 setup_scan_element(chn, n);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100214 } else if (strcmp((char *) n->name, "text")) {
Paul Cercueilf7361902015-04-16 16:31:49 +0200215 WARNING("Unknown children \'%s\' in <channel>\n",
Paul Cercueil5d9db302014-02-18 18:16:51 +0100216 n->name);
217 continue;
218 }
219 }
220
Lars-Peter Clausenc6f85922016-04-20 15:03:49 +0200221 iio_channel_init_finalize(chn);
222
Paul Cercueil5d9db302014-02-18 18:16:51 +0100223 return chn;
224
225err_free_channel:
226 free_channel(chn);
227 return NULL;
228}
229
230static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
231{
232 xmlAttr *attr;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +0100233 struct iio_device *dev = zalloc(sizeof(*dev));
Paul Cercueil5d9db302014-02-18 18:16:51 +0100234 if (!dev)
235 return NULL;
236
237 dev->ctx = ctx;
238
239 for (attr = n->properties; attr; attr = attr->next) {
240 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200241 dev->name = iio_strdup(
242 (char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100243 } else if (!strcmp((char *) attr->name, "id")) {
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200244 dev->id = iio_strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100245 } else {
Paul Cercueilf7361902015-04-16 16:31:49 +0200246 WARNING("Unknown attribute \'%s\' in <device>\n",
Paul Cercueil5d9db302014-02-18 18:16:51 +0100247 attr->name);
248 }
249 }
250
251 if (!dev->id) {
252 ERROR("Unable to read device ID\n");
253 goto err_free_device;
254 }
255
256 for (n = n->children; n; n = n->next) {
257 if (!strcmp((char *) n->name, "channel")) {
258 struct iio_channel **chns,
259 *chn = create_channel(dev, n);
260 if (!chn) {
261 ERROR("Unable to create channel\n");
262 goto err_free_device;
263 }
264
265 chns = realloc(dev->channels, (1 + dev->nb_channels) *
266 sizeof(struct iio_channel *));
267 if (!chns) {
268 ERROR("Unable to allocate memory\n");
269 free(chn);
270 goto err_free_device;
271 }
272
273 chns[dev->nb_channels++] = chn;
274 dev->channels = chns;
275 } else if (!strcmp((char *) n->name, "attribute")) {
Matt Fornero81f04a52017-11-30 14:36:37 -0500276 if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_DEVICE) < 0)
Paul Cercueil501961b2014-04-15 11:23:30 +0200277 goto err_free_device;
278 } else if (!strcmp((char *) n->name, "debug-attribute")) {
Matt Fornero81f04a52017-11-30 14:36:37 -0500279 if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_DEBUG) < 0)
280 goto err_free_device;
281 } else if (!strcmp((char *) n->name, "buffer-attribute")) {
282 if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_BUFFER) < 0)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100283 goto err_free_device;
284 } else if (strcmp((char *) n->name, "text")) {
285 WARNING("Unknown children \'%s\' in <device>\n",
286 n->name);
287 continue;
288 }
289 }
290
Paul Cercueiledec1cb2015-04-20 10:40:28 +0200291 dev->words = (dev->nb_channels + 31) / 32;
292 if (dev->words) {
293 dev->mask = calloc(dev->words, sizeof(*dev->mask));
294 if (!dev->mask) {
295 errno = ENOMEM;
296 goto err_free_device;
297 }
298 }
299
Paul Cercueil5d9db302014-02-18 18:16:51 +0100300 return dev;
301
302err_free_device:
303 free_device(dev);
304 return NULL;
305}
306
Paul Cercueil927818d2014-10-28 14:38:24 +0100307static struct iio_context * xml_clone(const struct iio_context *ctx)
308{
Paul Cercueil63e52182014-12-11 12:52:48 +0100309 return xml_create_context_mem(ctx->xml, strlen(ctx->xml));
Paul Cercueil927818d2014-10-28 14:38:24 +0100310}
311
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +0100312static const struct iio_backend_ops xml_ops = {
Paul Cercueil927818d2014-10-28 14:38:24 +0100313 .clone = xml_clone,
Paul Cercueil5d9db302014-02-18 18:16:51 +0100314};
315
Paul Cercueil00dc2152016-11-15 16:37:35 +0100316static int parse_context_attr(struct iio_context *ctx, xmlNode *n)
317{
318 xmlAttr *attr;
319 const char *name = NULL, *value = NULL;
320
321 for (attr = n->properties; attr; attr = attr->next) {
322 if (!strcmp((const char *) attr->name, "name")) {
323 name = (const char *) attr->children->content;
324 } else if (!strcmp((const char *) attr->name, "value")) {
325 value = (const char *) attr->children->content;
326 }
327 }
328
329 if (!name || !value)
330 return -EINVAL;
331 else
332 return iio_context_add_attr(ctx, name, value);
333}
334
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100335static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100336{
337 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100338 xmlNode *root, *n;
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100339 xmlAttr *attr;
Paul Cercueil46793342016-12-15 16:54:44 +0100340 int err = -ENOMEM;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +0100341 struct iio_context *ctx = zalloc(sizeof(*ctx));
Paul Cercueil5d9db302014-02-18 18:16:51 +0100342 if (!ctx)
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100343 goto err_set_errno;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100344
Paul Cercueil5d9db302014-02-18 18:16:51 +0100345 ctx->name = "xml";
346 ctx->ops = &xml_ops;
Harvey Yangbc3f48e2019-10-22 11:17:28 +0800347 ctx->client_id = -1;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100348
Paul Cercueil5d9db302014-02-18 18:16:51 +0100349 root = xmlDocGetRootElement(doc);
350 if (strcmp((char *) root->name, "context")) {
351 ERROR("Unrecognized XML file\n");
Paul Cercueil46793342016-12-15 16:54:44 +0100352 err = -EINVAL;
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100353 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100354 }
355
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100356 for (attr = root->properties; attr; attr = attr->next) {
357 if (!strcmp((char *) attr->name, "description"))
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200358 ctx->description = iio_strdup(
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100359 (char *) attr->children->content);
360 else if (strcmp((char *) attr->name, "name"))
361 WARNING("Unknown parameter \'%s\' in <context>\n",
362 (char *) attr->children->content);
363 }
364
Paul Cercueil5d9db302014-02-18 18:16:51 +0100365 for (n = root->children; n; n = n->next) {
366 struct iio_device **devs, *dev;
367
Paul Cercueil00dc2152016-11-15 16:37:35 +0100368 if (!strcmp((char *) n->name, "context-attribute")) {
369 err = parse_context_attr(ctx, n);
370 if (err)
371 goto err_free_devices;
372 else
373 continue;
374 } else if (strcmp((char *) n->name, "device")) {
Paul Cercueil5d9db302014-02-18 18:16:51 +0100375 if (strcmp((char *) n->name, "text"))
376 WARNING("Unknown children \'%s\' in "
377 "<context>\n", n->name);
378 continue;
379 }
380
381 dev = create_device(ctx, n);
382 if (!dev) {
383 ERROR("Unable to create device\n");
384 goto err_free_devices;
385 }
386
387 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
388 sizeof(struct iio_device *));
389 if (!devs) {
390 ERROR("Unable to allocate memory\n");
391 free(dev);
392 goto err_free_devices;
393 }
394
395 devs[ctx->nb_devices++] = dev;
396 ctx->devices = devs;
397 }
398
Paul Cercueilfd387472015-08-05 10:34:19 +0200399 err = iio_context_init(ctx);
400 if (err)
401 goto err_free_devices;
402
Paul Cercueilc1ed8482014-06-11 16:29:43 +0200403 return ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100404
405err_free_devices:
406 for (i = 0; i < ctx->nb_devices; i++)
407 free_device(ctx->devices[i]);
408 if (ctx->nb_devices)
409 free(ctx->devices);
Paul Cercueil00dc2152016-11-15 16:37:35 +0100410 for (i = 0; i < ctx->nb_attrs; i++) {
411 free(ctx->attrs[i]);
412 free(ctx->values[i]);
413 }
414 free(ctx->attrs);
415 free(ctx->values);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100416err_free_ctx:
417 free(ctx);
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100418err_set_errno:
Paul Cercueil46793342016-12-15 16:54:44 +0100419 errno = -err;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100420 return NULL;
421}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100422
Paul Cercueil63e52182014-12-11 12:52:48 +0100423struct iio_context * xml_create_context(const char *xml_file)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100424{
425 struct iio_context *ctx;
426 xmlDoc *doc;
427
428 LIBXML_TEST_VERSION;
429
430 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
431 if (!doc) {
432 ERROR("Unable to parse XML file\n");
Paul Cercueil9efa26f2016-12-15 16:56:15 +0100433 errno = EINVAL;
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100434 return NULL;
435 }
436
437 ctx = iio_create_xml_context_helper(doc);
438 xmlFreeDoc(doc);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100439 return ctx;
440}
441
Paul Cercueil63e52182014-12-11 12:52:48 +0100442struct iio_context * xml_create_context_mem(const char *xml, size_t len)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100443{
444 struct iio_context *ctx;
445 xmlDoc *doc;
446
447 LIBXML_TEST_VERSION;
448
Paul Cercueil4012cff2015-05-11 10:47:40 +0200449 doc = xmlReadMemory(xml, (int) len, NULL, NULL, XML_PARSE_DTDVALID);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100450 if (!doc) {
451 ERROR("Unable to parse XML file\n");
Paul Cercueil9efa26f2016-12-15 16:56:15 +0100452 errno = EINVAL;
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100453 return NULL;
454 }
455
456 ctx = iio_create_xml_context_helper(doc);
457 xmlFreeDoc(doc);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100458 return ctx;
459}