blob: 148b0d9e95bb0100a50edd073990659ac56541ec [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 Cercueilb34e0222014-05-05 15:32:38 +020029 char *name = NULL;
30 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")) {
34 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010035 } else {
36 WARNING("Unknown field \'%s\' in channel %s\n",
37 attr->name, chn->id);
38 }
39 }
40
Paul Cercueil5cd260e2014-02-24 13:16:01 +010041 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010042 ERROR("Incomplete attribute in channel %s\n", chn->id);
43 goto err_free;
44 }
45
Paul Cercueilb34e0222014-05-05 15:32:38 +020046 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
47 sizeof(struct iio_channel_attr));
Paul Cercueil5d9db302014-02-18 18:16:51 +010048 if (!attrs)
49 goto err_free;
50
Paul Cercueilb34e0222014-05-05 15:32:38 +020051 attrs[chn->nb_attrs++].name = name;
Paul Cercueil5d9db302014-02-18 18:16:51 +010052 chn->attrs = attrs;
53 return 0;
54
Paul Cercueil5d9db302014-02-18 18:16:51 +010055err_free:
56 if (name)
57 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +010058 return -1;
59}
60
Paul Cercueil501961b2014-04-15 11:23:30 +020061static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug)
Paul Cercueil5d9db302014-02-18 18:16:51 +010062{
63 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010064 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010065
66 for (attr = n->properties; attr; attr = attr->next) {
67 if (!strcmp((char *) attr->name, "name")) {
68 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010069 } else {
70 WARNING("Unknown field \'%s\' in device %s\n",
71 attr->name, dev->id);
72 }
73 }
74
Paul Cercueil5cd260e2014-02-24 13:16:01 +010075 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010076 ERROR("Incomplete attribute in device %s\n", dev->id);
77 goto err_free;
78 }
79
Paul Cercueil501961b2014-04-15 11:23:30 +020080 if (is_debug)
81 attrs = realloc(dev->debug_attrs,
82 (1 + dev->nb_debug_attrs) * sizeof(char *));
83 else
84 attrs = realloc(dev->attrs,
85 (1 + dev->nb_attrs) * sizeof(char *));
Paul Cercueil5d9db302014-02-18 18:16:51 +010086 if (!attrs)
87 goto err_free;
88
Paul Cercueil501961b2014-04-15 11:23:30 +020089 if (is_debug) {
90 attrs[dev->nb_debug_attrs++] = name;
91 dev->debug_attrs = attrs;
92 } else {
93 attrs[dev->nb_attrs++] = name;
94 dev->attrs = attrs;
95 }
Paul Cercueil5d9db302014-02-18 18:16:51 +010096 return 0;
97
Paul Cercueil5d9db302014-02-18 18:16:51 +010098err_free:
99 if (name)
100 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100101 return -1;
102}
103
104static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
105{
106 xmlAttr *attr;
107 struct iio_channel *chn = calloc(1, sizeof(*chn));
108 if (!chn)
109 return NULL;
110
111 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100112
113 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +0100114 const char *name = (const char *) attr->name,
115 *content = (const char *) attr->children->content;
116 if (!strcmp(name, "name")) {
117 chn->name = strdup(content);
118 } else if (!strcmp(name, "id")) {
119 chn->id = strdup(content);
120 } else if (!strcmp(name, "type")) {
121 if (!strcmp(content, "output"))
122 chn->is_output = true;
123 else if (strcmp(content, "input"))
124 WARNING("Unknown channel type %s\n", content);
Paul Cercueil88526632014-04-24 17:09:29 +0200125 } else if (!strcmp(name, "scan_element")) {
126 chn->is_scan_element = !strcmp(content, "true");
Paul Cercueil5d9db302014-02-18 18:16:51 +0100127 } else {
128 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +0100129 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100130 }
131 }
132
133 if (!chn->id) {
134 ERROR("Incomplete <attribute>\n");
135 goto err_free_channel;
136 }
137
138 for (n = n->children; n; n = n->next) {
139 if (!strcmp((char *) n->name, "attribute")) {
140 if (add_attr_to_channel(chn, n) < 0)
141 goto err_free_channel;
142 } else if (strcmp((char *) n->name, "text")) {
143 WARNING("Unknown children \'%s\' in <device>\n",
144 n->name);
145 continue;
146 }
147 }
148
149 return chn;
150
151err_free_channel:
152 free_channel(chn);
153 return NULL;
154}
155
156static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
157{
158 xmlAttr *attr;
159 struct iio_device *dev = calloc(1, sizeof(*dev));
160 if (!dev)
161 return NULL;
162
163 dev->ctx = ctx;
164
165 for (attr = n->properties; attr; attr = attr->next) {
166 if (!strcmp((char *) attr->name, "name")) {
167 dev->name = strdup((char *) attr->children->content);
168 } else if (!strcmp((char *) attr->name, "id")) {
169 dev->id = strdup((char *) attr->children->content);
170 } else {
171 WARNING("Unknown attribute \'%s\' in <context>\n",
172 attr->name);
173 }
174 }
175
176 if (!dev->id) {
177 ERROR("Unable to read device ID\n");
178 goto err_free_device;
179 }
180
181 for (n = n->children; n; n = n->next) {
182 if (!strcmp((char *) n->name, "channel")) {
183 struct iio_channel **chns,
184 *chn = create_channel(dev, n);
185 if (!chn) {
186 ERROR("Unable to create channel\n");
187 goto err_free_device;
188 }
189
190 chns = realloc(dev->channels, (1 + dev->nb_channels) *
191 sizeof(struct iio_channel *));
192 if (!chns) {
193 ERROR("Unable to allocate memory\n");
194 free(chn);
195 goto err_free_device;
196 }
197
198 chns[dev->nb_channels++] = chn;
199 dev->channels = chns;
200 } else if (!strcmp((char *) n->name, "attribute")) {
Paul Cercueil501961b2014-04-15 11:23:30 +0200201 if (add_attr_to_device(dev, n, false) < 0)
202 goto err_free_device;
203 } else if (!strcmp((char *) n->name, "debug-attribute")) {
204 if (add_attr_to_device(dev, n, true) < 0)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100205 goto err_free_device;
206 } else if (strcmp((char *) n->name, "text")) {
207 WARNING("Unknown children \'%s\' in <device>\n",
208 n->name);
209 continue;
210 }
211 }
212
213 return dev;
214
215err_free_device:
216 free_device(dev);
217 return NULL;
218}
219
Paul Cercueil5d9db302014-02-18 18:16:51 +0100220static struct iio_backend_ops xml_ops = {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200221 .read = NULL, /* ISO C99 forbids empty initializer braces */
Paul Cercueil5d9db302014-02-18 18:16:51 +0100222};
223
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100224static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100225{
226 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100227 xmlNode *root, *n;
228 struct iio_context *ctx = calloc(1, sizeof(*ctx));
229 if (!ctx)
230 return NULL;
231
Paul Cercueil5d9db302014-02-18 18:16:51 +0100232 ctx->name = "xml";
233 ctx->ops = &xml_ops;
234
Paul Cercueil5d9db302014-02-18 18:16:51 +0100235 root = xmlDocGetRootElement(doc);
236 if (strcmp((char *) root->name, "context")) {
237 ERROR("Unrecognized XML file\n");
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100238 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100239 }
240
241 for (n = root->children; n; n = n->next) {
242 struct iio_device **devs, *dev;
243
244 if (strcmp((char *) n->name, "device")) {
245 if (strcmp((char *) n->name, "text"))
246 WARNING("Unknown children \'%s\' in "
247 "<context>\n", n->name);
248 continue;
249 }
250
251 dev = create_device(ctx, n);
252 if (!dev) {
253 ERROR("Unable to create device\n");
254 goto err_free_devices;
255 }
256
257 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
258 sizeof(struct iio_device *));
259 if (!devs) {
260 ERROR("Unable to allocate memory\n");
261 free(dev);
262 goto err_free_devices;
263 }
264
265 devs[ctx->nb_devices++] = dev;
266 ctx->devices = devs;
267 }
268
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200269 if (!iio_context_init(ctx))
270 return ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100271
272err_free_devices:
273 for (i = 0; i < ctx->nb_devices; i++)
274 free_device(ctx->devices[i]);
275 if (ctx->nb_devices)
276 free(ctx->devices);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100277err_free_ctx:
278 free(ctx);
279 return NULL;
280}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100281
282struct iio_context * iio_create_xml_context(const char *xml_file)
283{
284 struct iio_context *ctx;
285 xmlDoc *doc;
286
287 LIBXML_TEST_VERSION;
288
289 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
290 if (!doc) {
291 ERROR("Unable to parse XML file\n");
292 return NULL;
293 }
294
295 ctx = iio_create_xml_context_helper(doc);
296 xmlFreeDoc(doc);
297 xmlCleanupParser();
298 return ctx;
299}
300
Paul Cercueildda33eb2014-03-03 15:00:11 +0100301struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100302{
303 struct iio_context *ctx;
304 xmlDoc *doc;
305
306 LIBXML_TEST_VERSION;
307
Paul Cercueildda33eb2014-03-03 15:00:11 +0100308 doc = xmlReadMemory(xml, len, NULL, NULL, XML_PARSE_DTDVALID);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100309 if (!doc) {
310 ERROR("Unable to parse XML file\n");
311 return NULL;
312 }
313
314 ctx = iio_create_xml_context_helper(doc);
315 xmlFreeDoc(doc);
316 xmlCleanupParser();
317 return ctx;
318}