blob: 0616eecaf690e25e5fd780a1b003b497cc7d29f5 [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")) {
34 name = strdup((char *) attr->children->content);
Paul Cercueil42d12352014-05-05 16:11:58 +020035 } else if (!strcmp((char *) attr->name, "filename")) {
36 filename = 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 Cercueil42d12352014-05-05 16:11:58 +020043 if (!name || !filename) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010044 ERROR("Incomplete attribute in channel %s\n", chn->id);
45 goto err_free;
46 }
47
Paul Cercueilb34e0222014-05-05 15:32:38 +020048 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
49 sizeof(struct iio_channel_attr));
Paul Cercueil5d9db302014-02-18 18:16:51 +010050 if (!attrs)
51 goto err_free;
52
Paul Cercueil42d12352014-05-05 16:11:58 +020053 attrs[chn->nb_attrs].filename = filename;
Paul Cercueilb34e0222014-05-05 15:32:38 +020054 attrs[chn->nb_attrs++].name = name;
Paul Cercueil5d9db302014-02-18 18:16:51 +010055 chn->attrs = attrs;
56 return 0;
57
Paul Cercueil5d9db302014-02-18 18:16:51 +010058err_free:
59 if (name)
60 free(name);
Paul Cercueil42d12352014-05-05 16:11:58 +020061 if (filename)
62 free(filename);
Paul Cercueil5d9db302014-02-18 18:16:51 +010063 return -1;
64}
65
Paul Cercueil501961b2014-04-15 11:23:30 +020066static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug)
Paul Cercueil5d9db302014-02-18 18:16:51 +010067{
68 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010069 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010070
71 for (attr = n->properties; attr; attr = attr->next) {
72 if (!strcmp((char *) attr->name, "name")) {
73 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010074 } else {
75 WARNING("Unknown field \'%s\' in device %s\n",
76 attr->name, dev->id);
77 }
78 }
79
Paul Cercueil5cd260e2014-02-24 13:16:01 +010080 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010081 ERROR("Incomplete attribute in device %s\n", dev->id);
82 goto err_free;
83 }
84
Paul Cercueil501961b2014-04-15 11:23:30 +020085 if (is_debug)
86 attrs = realloc(dev->debug_attrs,
87 (1 + dev->nb_debug_attrs) * sizeof(char *));
88 else
89 attrs = realloc(dev->attrs,
90 (1 + dev->nb_attrs) * sizeof(char *));
Paul Cercueil5d9db302014-02-18 18:16:51 +010091 if (!attrs)
92 goto err_free;
93
Paul Cercueil501961b2014-04-15 11:23:30 +020094 if (is_debug) {
95 attrs[dev->nb_debug_attrs++] = name;
96 dev->debug_attrs = attrs;
97 } else {
98 attrs[dev->nb_attrs++] = name;
99 dev->attrs = attrs;
100 }
Paul Cercueil5d9db302014-02-18 18:16:51 +0100101 return 0;
102
Paul Cercueil5d9db302014-02-18 18:16:51 +0100103err_free:
104 if (name)
105 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100106 return -1;
107}
108
109static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
110{
111 xmlAttr *attr;
112 struct iio_channel *chn = calloc(1, sizeof(*chn));
113 if (!chn)
114 return NULL;
115
116 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100117
118 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +0100119 const char *name = (const char *) attr->name,
120 *content = (const char *) attr->children->content;
121 if (!strcmp(name, "name")) {
122 chn->name = strdup(content);
123 } else if (!strcmp(name, "id")) {
124 chn->id = strdup(content);
125 } else if (!strcmp(name, "type")) {
126 if (!strcmp(content, "output"))
127 chn->is_output = true;
128 else if (strcmp(content, "input"))
129 WARNING("Unknown channel type %s\n", content);
Paul Cercueil88526632014-04-24 17:09:29 +0200130 } else if (!strcmp(name, "scan_element")) {
131 chn->is_scan_element = !strcmp(content, "true");
Paul Cercueil5d9db302014-02-18 18:16:51 +0100132 } else {
133 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +0100134 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100135 }
136 }
137
138 if (!chn->id) {
139 ERROR("Incomplete <attribute>\n");
140 goto err_free_channel;
141 }
142
143 for (n = n->children; n; n = n->next) {
144 if (!strcmp((char *) n->name, "attribute")) {
145 if (add_attr_to_channel(chn, n) < 0)
146 goto err_free_channel;
147 } else if (strcmp((char *) n->name, "text")) {
148 WARNING("Unknown children \'%s\' in <device>\n",
149 n->name);
150 continue;
151 }
152 }
153
154 return chn;
155
156err_free_channel:
157 free_channel(chn);
158 return NULL;
159}
160
161static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
162{
163 xmlAttr *attr;
164 struct iio_device *dev = calloc(1, sizeof(*dev));
165 if (!dev)
166 return NULL;
167
168 dev->ctx = ctx;
169
170 for (attr = n->properties; attr; attr = attr->next) {
171 if (!strcmp((char *) attr->name, "name")) {
172 dev->name = strdup((char *) attr->children->content);
173 } else if (!strcmp((char *) attr->name, "id")) {
174 dev->id = strdup((char *) attr->children->content);
175 } else {
176 WARNING("Unknown attribute \'%s\' in <context>\n",
177 attr->name);
178 }
179 }
180
181 if (!dev->id) {
182 ERROR("Unable to read device ID\n");
183 goto err_free_device;
184 }
185
186 for (n = n->children; n; n = n->next) {
187 if (!strcmp((char *) n->name, "channel")) {
188 struct iio_channel **chns,
189 *chn = create_channel(dev, n);
190 if (!chn) {
191 ERROR("Unable to create channel\n");
192 goto err_free_device;
193 }
194
195 chns = realloc(dev->channels, (1 + dev->nb_channels) *
196 sizeof(struct iio_channel *));
197 if (!chns) {
198 ERROR("Unable to allocate memory\n");
199 free(chn);
200 goto err_free_device;
201 }
202
203 chns[dev->nb_channels++] = chn;
204 dev->channels = chns;
205 } else if (!strcmp((char *) n->name, "attribute")) {
Paul Cercueil501961b2014-04-15 11:23:30 +0200206 if (add_attr_to_device(dev, n, false) < 0)
207 goto err_free_device;
208 } else if (!strcmp((char *) n->name, "debug-attribute")) {
209 if (add_attr_to_device(dev, n, true) < 0)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100210 goto err_free_device;
211 } else if (strcmp((char *) n->name, "text")) {
212 WARNING("Unknown children \'%s\' in <device>\n",
213 n->name);
214 continue;
215 }
216 }
217
218 return dev;
219
220err_free_device:
221 free_device(dev);
222 return NULL;
223}
224
Paul Cercueil5d9db302014-02-18 18:16:51 +0100225static struct iio_backend_ops xml_ops = {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200226 .read = NULL, /* ISO C99 forbids empty initializer braces */
Paul Cercueil5d9db302014-02-18 18:16:51 +0100227};
228
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100229static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100230{
231 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100232 xmlNode *root, *n;
233 struct iio_context *ctx = calloc(1, sizeof(*ctx));
234 if (!ctx)
235 return NULL;
236
Paul Cercueil5d9db302014-02-18 18:16:51 +0100237 ctx->name = "xml";
238 ctx->ops = &xml_ops;
239
Paul Cercueil5d9db302014-02-18 18:16:51 +0100240 root = xmlDocGetRootElement(doc);
241 if (strcmp((char *) root->name, "context")) {
242 ERROR("Unrecognized XML file\n");
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100243 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100244 }
245
246 for (n = root->children; n; n = n->next) {
247 struct iio_device **devs, *dev;
248
249 if (strcmp((char *) n->name, "device")) {
250 if (strcmp((char *) n->name, "text"))
251 WARNING("Unknown children \'%s\' in "
252 "<context>\n", n->name);
253 continue;
254 }
255
256 dev = create_device(ctx, n);
257 if (!dev) {
258 ERROR("Unable to create device\n");
259 goto err_free_devices;
260 }
261
262 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
263 sizeof(struct iio_device *));
264 if (!devs) {
265 ERROR("Unable to allocate memory\n");
266 free(dev);
267 goto err_free_devices;
268 }
269
270 devs[ctx->nb_devices++] = dev;
271 ctx->devices = devs;
272 }
273
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200274 if (!iio_context_init(ctx))
275 return ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100276
277err_free_devices:
278 for (i = 0; i < ctx->nb_devices; i++)
279 free_device(ctx->devices[i]);
280 if (ctx->nb_devices)
281 free(ctx->devices);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100282err_free_ctx:
283 free(ctx);
284 return NULL;
285}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100286
287struct iio_context * iio_create_xml_context(const char *xml_file)
288{
289 struct iio_context *ctx;
290 xmlDoc *doc;
291
292 LIBXML_TEST_VERSION;
293
294 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
295 if (!doc) {
296 ERROR("Unable to parse XML file\n");
297 return NULL;
298 }
299
300 ctx = iio_create_xml_context_helper(doc);
301 xmlFreeDoc(doc);
302 xmlCleanupParser();
303 return ctx;
304}
305
Paul Cercueildda33eb2014-03-03 15:00:11 +0100306struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100307{
308 struct iio_context *ctx;
309 xmlDoc *doc;
310
311 LIBXML_TEST_VERSION;
312
Paul Cercueildda33eb2014-03-03 15:00:11 +0100313 doc = xmlReadMemory(xml, len, NULL, NULL, XML_PARSE_DTDVALID);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100314 if (!doc) {
315 ERROR("Unable to parse XML file\n");
316 return NULL;
317 }
318
319 ctx = iio_create_xml_context_helper(doc);
320 xmlFreeDoc(doc);
321 xmlCleanupParser();
322 return ctx;
323}