blob: c6c59648736ec48bd8bd5e6e876bad365426957a [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 Cercueild4378e72014-05-30 13:37:34 +020026#ifndef _WIN32
27#define _strdup strdup
28#endif
29
Paul Cercueil5d9db302014-02-18 18:16:51 +010030static int add_attr_to_channel(struct iio_channel *chn, xmlNode *n)
31{
32 xmlAttr *attr;
Paul Cercueil42d12352014-05-05 16:11:58 +020033 char *name = NULL, *filename = NULL;
Paul Cercueilb34e0222014-05-05 15:32:38 +020034 struct iio_channel_attr *attrs;
Paul Cercueil5d9db302014-02-18 18:16:51 +010035
36 for (attr = n->properties; attr; attr = attr->next) {
37 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueild4378e72014-05-30 13:37:34 +020038 name = _strdup((char *) attr->children->content);
Paul Cercueil42d12352014-05-05 16:11:58 +020039 } else if (!strcmp((char *) attr->name, "filename")) {
Paul Cercueild4378e72014-05-30 13:37:34 +020040 filename = _strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010041 } else {
42 WARNING("Unknown field \'%s\' in channel %s\n",
43 attr->name, chn->id);
44 }
45 }
46
Paul Cercueil7150c6e2015-04-14 16:26:21 +020047 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010048 ERROR("Incomplete attribute in channel %s\n", chn->id);
49 goto err_free;
50 }
51
Paul Cercueil7150c6e2015-04-14 16:26:21 +020052 if (!filename) {
53 filename = _strdup(name);
54 if (!filename)
55 goto err_free;
56 }
57
Paul Cercueilb34e0222014-05-05 15:32:38 +020058 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
59 sizeof(struct iio_channel_attr));
Paul Cercueil5d9db302014-02-18 18:16:51 +010060 if (!attrs)
61 goto err_free;
62
Paul Cercueil42d12352014-05-05 16:11:58 +020063 attrs[chn->nb_attrs].filename = filename;
Paul Cercueilb34e0222014-05-05 15:32:38 +020064 attrs[chn->nb_attrs++].name = name;
Paul Cercueil5d9db302014-02-18 18:16:51 +010065 chn->attrs = attrs;
66 return 0;
67
Paul Cercueil5d9db302014-02-18 18:16:51 +010068err_free:
69 if (name)
70 free(name);
Paul Cercueil42d12352014-05-05 16:11:58 +020071 if (filename)
72 free(filename);
Paul Cercueil5d9db302014-02-18 18:16:51 +010073 return -1;
74}
75
Paul Cercueil501961b2014-04-15 11:23:30 +020076static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug)
Paul Cercueil5d9db302014-02-18 18:16:51 +010077{
78 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010079 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010080
81 for (attr = n->properties; attr; attr = attr->next) {
82 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueild4378e72014-05-30 13:37:34 +020083 name = _strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010084 } else {
85 WARNING("Unknown field \'%s\' in device %s\n",
86 attr->name, dev->id);
87 }
88 }
89
Paul Cercueil5cd260e2014-02-24 13:16:01 +010090 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010091 ERROR("Incomplete attribute in device %s\n", dev->id);
92 goto err_free;
93 }
94
Paul Cercueil501961b2014-04-15 11:23:30 +020095 if (is_debug)
96 attrs = realloc(dev->debug_attrs,
97 (1 + dev->nb_debug_attrs) * sizeof(char *));
98 else
99 attrs = realloc(dev->attrs,
100 (1 + dev->nb_attrs) * sizeof(char *));
Paul Cercueil5d9db302014-02-18 18:16:51 +0100101 if (!attrs)
102 goto err_free;
103
Paul Cercueil501961b2014-04-15 11:23:30 +0200104 if (is_debug) {
105 attrs[dev->nb_debug_attrs++] = name;
106 dev->debug_attrs = attrs;
107 } else {
108 attrs[dev->nb_attrs++] = name;
109 dev->attrs = attrs;
110 }
Paul Cercueil5d9db302014-02-18 18:16:51 +0100111 return 0;
112
Paul Cercueil5d9db302014-02-18 18:16:51 +0100113err_free:
114 if (name)
115 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100116 return -1;
117}
118
Paul Cercueila7e80022014-06-11 11:41:26 +0200119static void setup_scan_element(struct iio_channel *chn, xmlNode *n)
120{
121 xmlAttr *attr;
122
123 for (attr = n->properties; attr; attr = attr->next) {
124 const char *name = (const char *) attr->name,
125 *content = (const char *) attr->children->content;
126 if (!strcmp(name, "index")) {
127 chn->index = atol(content);
128 } else if (!strcmp(name, "format")) {
129 char e, s;
Paul Cercueil04030a72014-09-03 11:27:21 +0200130 sscanf(content, "%ce:%c%u/%u>>%u", &e, &s,
Paul Cercueila7e80022014-06-11 11:41:26 +0200131 &chn->format.bits,
132 &chn->format.length,
133 &chn->format.shift);
134 chn->format.is_be = e == 'b';
Michael Hennerichfa3c6f62014-08-13 11:21:23 +0200135 chn->format.is_signed = (s == 's' || s == 'S');
136 chn->format.is_fully_defined = (s == 'S' || s == 'U' ||
137 chn->format.bits == chn->format.length);
Paul Cercueila7e80022014-06-11 11:41:26 +0200138 } else if (!strcmp(name, "scale")) {
139 chn->format.with_scale = true;
140 chn->format.scale = atof(content);
141 } else {
142 WARNING("Unknown attribute \'%s\' in <scan-element>\n",
143 name);
144 }
145 }
146}
147
Paul Cercueil5d9db302014-02-18 18:16:51 +0100148static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
149{
150 xmlAttr *attr;
151 struct iio_channel *chn = calloc(1, sizeof(*chn));
152 if (!chn)
153 return NULL;
154
155 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100156
Paul Cercueild8d58932014-06-12 10:08:36 +0200157 /* Set the default index value < 0 (== no index) */
158 chn->index = -ENOENT;
159
Paul Cercueil5d9db302014-02-18 18:16:51 +0100160 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +0100161 const char *name = (const char *) attr->name,
162 *content = (const char *) attr->children->content;
163 if (!strcmp(name, "name")) {
Paul Cercueild4378e72014-05-30 13:37:34 +0200164 chn->name = _strdup(content);
Paul Cercueil35a01312014-02-20 10:56:57 +0100165 } else if (!strcmp(name, "id")) {
Paul Cercueild4378e72014-05-30 13:37:34 +0200166 chn->id = _strdup(content);
Paul Cercueil35a01312014-02-20 10:56:57 +0100167 } else if (!strcmp(name, "type")) {
168 if (!strcmp(content, "output"))
169 chn->is_output = true;
170 else if (strcmp(content, "input"))
171 WARNING("Unknown channel type %s\n", content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100172 } else {
173 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +0100174 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100175 }
176 }
177
178 if (!chn->id) {
179 ERROR("Incomplete <attribute>\n");
180 goto err_free_channel;
181 }
182
183 for (n = n->children; n; n = n->next) {
184 if (!strcmp((char *) n->name, "attribute")) {
185 if (add_attr_to_channel(chn, n) < 0)
186 goto err_free_channel;
Paul Cercueila7e80022014-06-11 11:41:26 +0200187 } else if (!strcmp((char *) n->name, "scan-element")) {
188 chn->is_scan_element = true;
189 setup_scan_element(chn, n);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100190 } else if (strcmp((char *) n->name, "text")) {
Paul Cercueilf7361902015-04-16 16:31:49 +0200191 WARNING("Unknown children \'%s\' in <channel>\n",
Paul Cercueil5d9db302014-02-18 18:16:51 +0100192 n->name);
193 continue;
194 }
195 }
196
197 return chn;
198
199err_free_channel:
200 free_channel(chn);
201 return NULL;
202}
203
204static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
205{
206 xmlAttr *attr;
207 struct iio_device *dev = calloc(1, sizeof(*dev));
208 if (!dev)
209 return NULL;
210
211 dev->ctx = ctx;
212
213 for (attr = n->properties; attr; attr = attr->next) {
214 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueild4378e72014-05-30 13:37:34 +0200215 dev->name = _strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100216 } else if (!strcmp((char *) attr->name, "id")) {
Paul Cercueild4378e72014-05-30 13:37:34 +0200217 dev->id = _strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100218 } else {
Paul Cercueilf7361902015-04-16 16:31:49 +0200219 WARNING("Unknown attribute \'%s\' in <device>\n",
Paul Cercueil5d9db302014-02-18 18:16:51 +0100220 attr->name);
221 }
222 }
223
224 if (!dev->id) {
225 ERROR("Unable to read device ID\n");
226 goto err_free_device;
227 }
228
229 for (n = n->children; n; n = n->next) {
230 if (!strcmp((char *) n->name, "channel")) {
231 struct iio_channel **chns,
232 *chn = create_channel(dev, n);
233 if (!chn) {
234 ERROR("Unable to create channel\n");
235 goto err_free_device;
236 }
237
238 chns = realloc(dev->channels, (1 + dev->nb_channels) *
239 sizeof(struct iio_channel *));
240 if (!chns) {
241 ERROR("Unable to allocate memory\n");
242 free(chn);
243 goto err_free_device;
244 }
245
246 chns[dev->nb_channels++] = chn;
247 dev->channels = chns;
248 } else if (!strcmp((char *) n->name, "attribute")) {
Paul Cercueil501961b2014-04-15 11:23:30 +0200249 if (add_attr_to_device(dev, n, false) < 0)
250 goto err_free_device;
251 } else if (!strcmp((char *) n->name, "debug-attribute")) {
252 if (add_attr_to_device(dev, n, true) < 0)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100253 goto err_free_device;
254 } else if (strcmp((char *) n->name, "text")) {
255 WARNING("Unknown children \'%s\' in <device>\n",
256 n->name);
257 continue;
258 }
259 }
260
Paul Cercueiledec1cb2015-04-20 10:40:28 +0200261 dev->words = (dev->nb_channels + 31) / 32;
262 if (dev->words) {
263 dev->mask = calloc(dev->words, sizeof(*dev->mask));
264 if (!dev->mask) {
265 errno = ENOMEM;
266 goto err_free_device;
267 }
268 }
269
Paul Cercueil5d9db302014-02-18 18:16:51 +0100270 return dev;
271
272err_free_device:
273 free_device(dev);
274 return NULL;
275}
276
Paul Cercueil927818d2014-10-28 14:38:24 +0100277static struct iio_context * xml_clone(const struct iio_context *ctx)
278{
Paul Cercueil63e52182014-12-11 12:52:48 +0100279 return xml_create_context_mem(ctx->xml, strlen(ctx->xml));
Paul Cercueil927818d2014-10-28 14:38:24 +0100280}
281
Paul Cercueil5d9db302014-02-18 18:16:51 +0100282static struct iio_backend_ops xml_ops = {
Paul Cercueil927818d2014-10-28 14:38:24 +0100283 .clone = xml_clone,
Paul Cercueil5d9db302014-02-18 18:16:51 +0100284};
285
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100286static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100287{
288 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100289 xmlNode *root, *n;
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100290 xmlAttr *attr;
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100291 int err = ENOMEM;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100292 struct iio_context *ctx = calloc(1, sizeof(*ctx));
293 if (!ctx)
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100294 goto err_set_errno;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100295
Paul Cercueil5d9db302014-02-18 18:16:51 +0100296 ctx->name = "xml";
297 ctx->ops = &xml_ops;
298
Paul Cercueil5d9db302014-02-18 18:16:51 +0100299 root = xmlDocGetRootElement(doc);
300 if (strcmp((char *) root->name, "context")) {
301 ERROR("Unrecognized XML file\n");
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100302 err = EINVAL;
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100303 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100304 }
305
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100306 for (attr = root->properties; attr; attr = attr->next) {
307 if (!strcmp((char *) attr->name, "description"))
308 ctx->description = _strdup(
309 (char *) attr->children->content);
310 else if (strcmp((char *) attr->name, "name"))
311 WARNING("Unknown parameter \'%s\' in <context>\n",
312 (char *) attr->children->content);
313 }
314
Paul Cercueil5d9db302014-02-18 18:16:51 +0100315 for (n = root->children; n; n = n->next) {
316 struct iio_device **devs, *dev;
317
318 if (strcmp((char *) n->name, "device")) {
319 if (strcmp((char *) n->name, "text"))
320 WARNING("Unknown children \'%s\' in "
321 "<context>\n", n->name);
322 continue;
323 }
324
325 dev = create_device(ctx, n);
326 if (!dev) {
327 ERROR("Unable to create device\n");
328 goto err_free_devices;
329 }
330
331 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
332 sizeof(struct iio_device *));
333 if (!devs) {
334 ERROR("Unable to allocate memory\n");
335 free(dev);
336 goto err_free_devices;
337 }
338
339 devs[ctx->nb_devices++] = dev;
340 ctx->devices = devs;
341 }
342
Paul Cercueilc1ed8482014-06-11 16:29:43 +0200343 iio_context_init(ctx);
344 return ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100345
346err_free_devices:
347 for (i = 0; i < ctx->nb_devices; i++)
348 free_device(ctx->devices[i]);
349 if (ctx->nb_devices)
350 free(ctx->devices);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100351err_free_ctx:
352 free(ctx);
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100353err_set_errno:
354 errno = err;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100355 return NULL;
356}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100357
Paul Cercueil63e52182014-12-11 12:52:48 +0100358struct iio_context * xml_create_context(const char *xml_file)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100359{
360 struct iio_context *ctx;
361 xmlDoc *doc;
362
363 LIBXML_TEST_VERSION;
364
365 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
366 if (!doc) {
367 ERROR("Unable to parse XML file\n");
368 return NULL;
369 }
370
371 ctx = iio_create_xml_context_helper(doc);
372 xmlFreeDoc(doc);
373 xmlCleanupParser();
374 return ctx;
375}
376
Paul Cercueil63e52182014-12-11 12:52:48 +0100377struct iio_context * xml_create_context_mem(const char *xml, size_t len)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100378{
379 struct iio_context *ctx;
380 xmlDoc *doc;
381
382 LIBXML_TEST_VERSION;
383
Paul Cercueildda33eb2014-03-03 15:00:11 +0100384 doc = xmlReadMemory(xml, len, NULL, NULL, XML_PARSE_DTDVALID);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100385 if (!doc) {
386 ERROR("Unable to parse XML file\n");
387 return NULL;
388 }
389
390 ctx = iio_create_xml_context_helper(doc);
391 xmlFreeDoc(doc);
392 xmlCleanupParser();
393 return ctx;
394}