blob: db61f4ad0949f89aa74766d77a5f154045100237 [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 Cercueil42d12352014-05-05 16:11:58 +020047 if (!name || !filename) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010048 ERROR("Incomplete attribute in channel %s\n", chn->id);
49 goto err_free;
50 }
51
Paul Cercueilb34e0222014-05-05 15:32:38 +020052 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
53 sizeof(struct iio_channel_attr));
Paul Cercueil5d9db302014-02-18 18:16:51 +010054 if (!attrs)
55 goto err_free;
56
Paul Cercueil42d12352014-05-05 16:11:58 +020057 attrs[chn->nb_attrs].filename = filename;
Paul Cercueilb34e0222014-05-05 15:32:38 +020058 attrs[chn->nb_attrs++].name = name;
Paul Cercueil5d9db302014-02-18 18:16:51 +010059 chn->attrs = attrs;
60 return 0;
61
Paul Cercueil5d9db302014-02-18 18:16:51 +010062err_free:
63 if (name)
64 free(name);
Paul Cercueil42d12352014-05-05 16:11:58 +020065 if (filename)
66 free(filename);
Paul Cercueil5d9db302014-02-18 18:16:51 +010067 return -1;
68}
69
Paul Cercueil501961b2014-04-15 11:23:30 +020070static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug)
Paul Cercueil5d9db302014-02-18 18:16:51 +010071{
72 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010073 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010074
75 for (attr = n->properties; attr; attr = attr->next) {
76 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueild4378e72014-05-30 13:37:34 +020077 name = _strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010078 } else {
79 WARNING("Unknown field \'%s\' in device %s\n",
80 attr->name, dev->id);
81 }
82 }
83
Paul Cercueil5cd260e2014-02-24 13:16:01 +010084 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010085 ERROR("Incomplete attribute in device %s\n", dev->id);
86 goto err_free;
87 }
88
Paul Cercueil501961b2014-04-15 11:23:30 +020089 if (is_debug)
90 attrs = realloc(dev->debug_attrs,
91 (1 + dev->nb_debug_attrs) * sizeof(char *));
92 else
93 attrs = realloc(dev->attrs,
94 (1 + dev->nb_attrs) * sizeof(char *));
Paul Cercueil5d9db302014-02-18 18:16:51 +010095 if (!attrs)
96 goto err_free;
97
Paul Cercueil501961b2014-04-15 11:23:30 +020098 if (is_debug) {
99 attrs[dev->nb_debug_attrs++] = name;
100 dev->debug_attrs = attrs;
101 } else {
102 attrs[dev->nb_attrs++] = name;
103 dev->attrs = attrs;
104 }
Paul Cercueil5d9db302014-02-18 18:16:51 +0100105 return 0;
106
Paul Cercueil5d9db302014-02-18 18:16:51 +0100107err_free:
108 if (name)
109 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100110 return -1;
111}
112
Paul Cercueila7e80022014-06-11 11:41:26 +0200113static void setup_scan_element(struct iio_channel *chn, xmlNode *n)
114{
115 xmlAttr *attr;
116
117 for (attr = n->properties; attr; attr = attr->next) {
118 const char *name = (const char *) attr->name,
119 *content = (const char *) attr->children->content;
120 if (!strcmp(name, "index")) {
121 chn->index = atol(content);
122 } else if (!strcmp(name, "format")) {
123 char e, s;
Paul Cercueil04030a72014-09-03 11:27:21 +0200124 sscanf(content, "%ce:%c%u/%u>>%u", &e, &s,
Paul Cercueila7e80022014-06-11 11:41:26 +0200125 &chn->format.bits,
126 &chn->format.length,
127 &chn->format.shift);
128 chn->format.is_be = e == 'b';
Michael Hennerichfa3c6f62014-08-13 11:21:23 +0200129 chn->format.is_signed = (s == 's' || s == 'S');
130 chn->format.is_fully_defined = (s == 'S' || s == 'U' ||
131 chn->format.bits == chn->format.length);
Paul Cercueila7e80022014-06-11 11:41:26 +0200132 } else if (!strcmp(name, "scale")) {
133 chn->format.with_scale = true;
134 chn->format.scale = atof(content);
135 } else {
136 WARNING("Unknown attribute \'%s\' in <scan-element>\n",
137 name);
138 }
139 }
140}
141
Paul Cercueil5d9db302014-02-18 18:16:51 +0100142static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
143{
144 xmlAttr *attr;
145 struct iio_channel *chn = calloc(1, sizeof(*chn));
146 if (!chn)
147 return NULL;
148
149 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100150
Paul Cercueild8d58932014-06-12 10:08:36 +0200151 /* Set the default index value < 0 (== no index) */
152 chn->index = -ENOENT;
153
Paul Cercueil5d9db302014-02-18 18:16:51 +0100154 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +0100155 const char *name = (const char *) attr->name,
156 *content = (const char *) attr->children->content;
157 if (!strcmp(name, "name")) {
Paul Cercueild4378e72014-05-30 13:37:34 +0200158 chn->name = _strdup(content);
Paul Cercueil35a01312014-02-20 10:56:57 +0100159 } else if (!strcmp(name, "id")) {
Paul Cercueild4378e72014-05-30 13:37:34 +0200160 chn->id = _strdup(content);
Paul Cercueil35a01312014-02-20 10:56:57 +0100161 } else if (!strcmp(name, "type")) {
162 if (!strcmp(content, "output"))
163 chn->is_output = true;
164 else if (strcmp(content, "input"))
165 WARNING("Unknown channel type %s\n", content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100166 } else {
167 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +0100168 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100169 }
170 }
171
172 if (!chn->id) {
173 ERROR("Incomplete <attribute>\n");
174 goto err_free_channel;
175 }
176
177 for (n = n->children; n; n = n->next) {
178 if (!strcmp((char *) n->name, "attribute")) {
179 if (add_attr_to_channel(chn, n) < 0)
180 goto err_free_channel;
Paul Cercueila7e80022014-06-11 11:41:26 +0200181 } else if (!strcmp((char *) n->name, "scan-element")) {
182 chn->is_scan_element = true;
183 setup_scan_element(chn, n);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100184 } else if (strcmp((char *) n->name, "text")) {
185 WARNING("Unknown children \'%s\' in <device>\n",
186 n->name);
187 continue;
188 }
189 }
190
191 return chn;
192
193err_free_channel:
194 free_channel(chn);
195 return NULL;
196}
197
198static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
199{
200 xmlAttr *attr;
201 struct iio_device *dev = calloc(1, sizeof(*dev));
202 if (!dev)
203 return NULL;
204
205 dev->ctx = ctx;
206
207 for (attr = n->properties; attr; attr = attr->next) {
208 if (!strcmp((char *) attr->name, "name")) {
Paul Cercueild4378e72014-05-30 13:37:34 +0200209 dev->name = _strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100210 } else if (!strcmp((char *) attr->name, "id")) {
Paul Cercueild4378e72014-05-30 13:37:34 +0200211 dev->id = _strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100212 } else {
213 WARNING("Unknown attribute \'%s\' in <context>\n",
214 attr->name);
215 }
216 }
217
218 if (!dev->id) {
219 ERROR("Unable to read device ID\n");
220 goto err_free_device;
221 }
222
223 for (n = n->children; n; n = n->next) {
224 if (!strcmp((char *) n->name, "channel")) {
225 struct iio_channel **chns,
226 *chn = create_channel(dev, n);
227 if (!chn) {
228 ERROR("Unable to create channel\n");
229 goto err_free_device;
230 }
231
232 chns = realloc(dev->channels, (1 + dev->nb_channels) *
233 sizeof(struct iio_channel *));
234 if (!chns) {
235 ERROR("Unable to allocate memory\n");
236 free(chn);
237 goto err_free_device;
238 }
239
240 chns[dev->nb_channels++] = chn;
241 dev->channels = chns;
242 } else if (!strcmp((char *) n->name, "attribute")) {
Paul Cercueil501961b2014-04-15 11:23:30 +0200243 if (add_attr_to_device(dev, n, false) < 0)
244 goto err_free_device;
245 } else if (!strcmp((char *) n->name, "debug-attribute")) {
246 if (add_attr_to_device(dev, n, true) < 0)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100247 goto err_free_device;
248 } else if (strcmp((char *) n->name, "text")) {
249 WARNING("Unknown children \'%s\' in <device>\n",
250 n->name);
251 continue;
252 }
253 }
254
255 return dev;
256
257err_free_device:
258 free_device(dev);
259 return NULL;
260}
261
Paul Cercueil927818d2014-10-28 14:38:24 +0100262static struct iio_context * xml_clone(const struct iio_context *ctx)
263{
Paul Cercueil63e52182014-12-11 12:52:48 +0100264 return xml_create_context_mem(ctx->xml, strlen(ctx->xml));
Paul Cercueil927818d2014-10-28 14:38:24 +0100265}
266
Paul Cercueil5d9db302014-02-18 18:16:51 +0100267static struct iio_backend_ops xml_ops = {
Paul Cercueil927818d2014-10-28 14:38:24 +0100268 .clone = xml_clone,
Paul Cercueil5d9db302014-02-18 18:16:51 +0100269};
270
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100271static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100272{
273 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100274 xmlNode *root, *n;
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100275 xmlAttr *attr;
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100276 int err = ENOMEM;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100277 struct iio_context *ctx = calloc(1, sizeof(*ctx));
278 if (!ctx)
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100279 goto err_set_errno;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100280
Paul Cercueil5d9db302014-02-18 18:16:51 +0100281 ctx->name = "xml";
282 ctx->ops = &xml_ops;
283
Paul Cercueil5d9db302014-02-18 18:16:51 +0100284 root = xmlDocGetRootElement(doc);
285 if (strcmp((char *) root->name, "context")) {
286 ERROR("Unrecognized XML file\n");
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100287 err = EINVAL;
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100288 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100289 }
290
Paul Cercueil60ac1f62015-03-16 14:09:54 +0100291 for (attr = root->properties; attr; attr = attr->next) {
292 if (!strcmp((char *) attr->name, "description"))
293 ctx->description = _strdup(
294 (char *) attr->children->content);
295 else if (strcmp((char *) attr->name, "name"))
296 WARNING("Unknown parameter \'%s\' in <context>\n",
297 (char *) attr->children->content);
298 }
299
Paul Cercueil5d9db302014-02-18 18:16:51 +0100300 for (n = root->children; n; n = n->next) {
301 struct iio_device **devs, *dev;
302
303 if (strcmp((char *) n->name, "device")) {
304 if (strcmp((char *) n->name, "text"))
305 WARNING("Unknown children \'%s\' in "
306 "<context>\n", n->name);
307 continue;
308 }
309
310 dev = create_device(ctx, n);
311 if (!dev) {
312 ERROR("Unable to create device\n");
313 goto err_free_devices;
314 }
315
316 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
317 sizeof(struct iio_device *));
318 if (!devs) {
319 ERROR("Unable to allocate memory\n");
320 free(dev);
321 goto err_free_devices;
322 }
323
324 devs[ctx->nb_devices++] = dev;
325 ctx->devices = devs;
326 }
327
Paul Cercueilc1ed8482014-06-11 16:29:43 +0200328 iio_context_init(ctx);
329 return ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100330
331err_free_devices:
332 for (i = 0; i < ctx->nb_devices; i++)
333 free_device(ctx->devices[i]);
334 if (ctx->nb_devices)
335 free(ctx->devices);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100336err_free_ctx:
337 free(ctx);
Paul Cercueil8a85d3e2015-03-16 17:11:49 +0100338err_set_errno:
339 errno = err;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100340 return NULL;
341}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100342
Paul Cercueil63e52182014-12-11 12:52:48 +0100343struct iio_context * xml_create_context(const char *xml_file)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100344{
345 struct iio_context *ctx;
346 xmlDoc *doc;
347
348 LIBXML_TEST_VERSION;
349
350 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
351 if (!doc) {
352 ERROR("Unable to parse XML file\n");
353 return NULL;
354 }
355
356 ctx = iio_create_xml_context_helper(doc);
357 xmlFreeDoc(doc);
358 xmlCleanupParser();
359 return ctx;
360}
361
Paul Cercueil63e52182014-12-11 12:52:48 +0100362struct iio_context * xml_create_context_mem(const char *xml, size_t len)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100363{
364 struct iio_context *ctx;
365 xmlDoc *doc;
366
367 LIBXML_TEST_VERSION;
368
Paul Cercueildda33eb2014-03-03 15:00:11 +0100369 doc = xmlReadMemory(xml, len, NULL, NULL, XML_PARSE_DTDVALID);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100370 if (!doc) {
371 ERROR("Unable to parse XML file\n");
372 return NULL;
373 }
374
375 ctx = iio_create_xml_context_helper(doc);
376 xmlFreeDoc(doc);
377 xmlCleanupParser();
378 return ctx;
379}