blob: 81bacb3e27be1124e6bacc493b42c365103bd3dd [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 Cercueil5cd260e2014-02-24 13:16:01 +010029 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010030
31 for (attr = n->properties; attr; attr = attr->next) {
32 if (!strcmp((char *) attr->name, "name")) {
33 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010034 } else {
35 WARNING("Unknown field \'%s\' in channel %s\n",
36 attr->name, chn->id);
37 }
38 }
39
Paul Cercueil5cd260e2014-02-24 13:16:01 +010040 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010041 ERROR("Incomplete attribute in channel %s\n", chn->id);
42 goto err_free;
43 }
44
45 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) * sizeof(char *));
46 if (!attrs)
47 goto err_free;
48
Paul Cercueil5d9db302014-02-18 18:16:51 +010049 attrs[chn->nb_attrs++] = name;
50 chn->attrs = attrs;
51 return 0;
52
Paul Cercueil5d9db302014-02-18 18:16:51 +010053err_free:
54 if (name)
55 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +010056 return -1;
57}
58
59static int add_attr_to_device(struct iio_device *dev, xmlNode *n)
60{
61 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010062 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010063
64 for (attr = n->properties; attr; attr = attr->next) {
65 if (!strcmp((char *) attr->name, "name")) {
66 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010067 } else {
68 WARNING("Unknown field \'%s\' in device %s\n",
69 attr->name, dev->id);
70 }
71 }
72
Paul Cercueil5cd260e2014-02-24 13:16:01 +010073 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010074 ERROR("Incomplete attribute in device %s\n", dev->id);
75 goto err_free;
76 }
77
78 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
79 if (!attrs)
80 goto err_free;
81
Paul Cercueil5d9db302014-02-18 18:16:51 +010082 attrs[dev->nb_attrs++] = name;
83 dev->attrs = attrs;
84 return 0;
85
Paul Cercueil5d9db302014-02-18 18:16:51 +010086err_free:
87 if (name)
88 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +010089 return -1;
90}
91
92static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
93{
94 xmlAttr *attr;
95 struct iio_channel *chn = calloc(1, sizeof(*chn));
96 if (!chn)
97 return NULL;
98
99 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100100
101 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +0100102 const char *name = (const char *) attr->name,
103 *content = (const char *) attr->children->content;
104 if (!strcmp(name, "name")) {
105 chn->name = strdup(content);
106 } else if (!strcmp(name, "id")) {
107 chn->id = strdup(content);
108 } else if (!strcmp(name, "type")) {
109 if (!strcmp(content, "output"))
110 chn->is_output = true;
111 else if (strcmp(content, "input"))
112 WARNING("Unknown channel type %s\n", content);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100113 } else {
114 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +0100115 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100116 }
117 }
118
119 if (!chn->id) {
120 ERROR("Incomplete <attribute>\n");
121 goto err_free_channel;
122 }
123
124 for (n = n->children; n; n = n->next) {
125 if (!strcmp((char *) n->name, "attribute")) {
126 if (add_attr_to_channel(chn, n) < 0)
127 goto err_free_channel;
128 } else if (strcmp((char *) n->name, "text")) {
129 WARNING("Unknown children \'%s\' in <device>\n",
130 n->name);
131 continue;
132 }
133 }
134
135 return chn;
136
137err_free_channel:
138 free_channel(chn);
139 return NULL;
140}
141
142static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
143{
144 xmlAttr *attr;
145 struct iio_device *dev = calloc(1, sizeof(*dev));
146 if (!dev)
147 return NULL;
148
149 dev->ctx = ctx;
150
151 for (attr = n->properties; attr; attr = attr->next) {
152 if (!strcmp((char *) attr->name, "name")) {
153 dev->name = strdup((char *) attr->children->content);
154 } else if (!strcmp((char *) attr->name, "id")) {
155 dev->id = strdup((char *) attr->children->content);
156 } else {
157 WARNING("Unknown attribute \'%s\' in <context>\n",
158 attr->name);
159 }
160 }
161
162 if (!dev->id) {
163 ERROR("Unable to read device ID\n");
164 goto err_free_device;
165 }
166
167 for (n = n->children; n; n = n->next) {
168 if (!strcmp((char *) n->name, "channel")) {
169 struct iio_channel **chns,
170 *chn = create_channel(dev, n);
171 if (!chn) {
172 ERROR("Unable to create channel\n");
173 goto err_free_device;
174 }
175
176 chns = realloc(dev->channels, (1 + dev->nb_channels) *
177 sizeof(struct iio_channel *));
178 if (!chns) {
179 ERROR("Unable to allocate memory\n");
180 free(chn);
181 goto err_free_device;
182 }
183
184 chns[dev->nb_channels++] = chn;
185 dev->channels = chns;
186 } else if (!strcmp((char *) n->name, "attribute")) {
187 if (add_attr_to_device(dev, n) < 0)
188 goto err_free_device;
189 } else if (strcmp((char *) n->name, "text")) {
190 WARNING("Unknown children \'%s\' in <device>\n",
191 n->name);
192 continue;
193 }
194 }
195
196 return dev;
197
198err_free_device:
199 free_device(dev);
200 return NULL;
201}
202
Paul Cercueil5d9db302014-02-18 18:16:51 +0100203static struct iio_backend_ops xml_ops = {
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200204 .read = NULL, /* ISO C99 forbids empty initializer braces */
Paul Cercueil5d9db302014-02-18 18:16:51 +0100205};
206
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100207static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100208{
209 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100210 xmlNode *root, *n;
211 struct iio_context *ctx = calloc(1, sizeof(*ctx));
212 if (!ctx)
213 return NULL;
214
Paul Cercueil5d9db302014-02-18 18:16:51 +0100215 ctx->name = "xml";
216 ctx->ops = &xml_ops;
217
Paul Cercueil5d9db302014-02-18 18:16:51 +0100218 root = xmlDocGetRootElement(doc);
219 if (strcmp((char *) root->name, "context")) {
220 ERROR("Unrecognized XML file\n");
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100221 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100222 }
223
224 for (n = root->children; n; n = n->next) {
225 struct iio_device **devs, *dev;
226
227 if (strcmp((char *) n->name, "device")) {
228 if (strcmp((char *) n->name, "text"))
229 WARNING("Unknown children \'%s\' in "
230 "<context>\n", n->name);
231 continue;
232 }
233
234 dev = create_device(ctx, n);
235 if (!dev) {
236 ERROR("Unable to create device\n");
237 goto err_free_devices;
238 }
239
240 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
241 sizeof(struct iio_device *));
242 if (!devs) {
243 ERROR("Unable to allocate memory\n");
244 free(dev);
245 goto err_free_devices;
246 }
247
248 devs[ctx->nb_devices++] = dev;
249 ctx->devices = devs;
250 }
251
252 return ctx;
253
254err_free_devices:
255 for (i = 0; i < ctx->nb_devices; i++)
256 free_device(ctx->devices[i]);
257 if (ctx->nb_devices)
258 free(ctx->devices);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100259err_free_ctx:
260 free(ctx);
261 return NULL;
262}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100263
264struct iio_context * iio_create_xml_context(const char *xml_file)
265{
266 struct iio_context *ctx;
267 xmlDoc *doc;
268
269 LIBXML_TEST_VERSION;
270
271 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
272 if (!doc) {
273 ERROR("Unable to parse XML file\n");
274 return NULL;
275 }
276
277 ctx = iio_create_xml_context_helper(doc);
278 xmlFreeDoc(doc);
279 xmlCleanupParser();
280 return ctx;
281}
282
Paul Cercueildda33eb2014-03-03 15:00:11 +0100283struct iio_context * iio_create_xml_context_mem(const char *xml, size_t len)
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100284{
285 struct iio_context *ctx;
286 xmlDoc *doc;
287
288 LIBXML_TEST_VERSION;
289
Paul Cercueildda33eb2014-03-03 15:00:11 +0100290 doc = xmlReadMemory(xml, len, NULL, NULL, XML_PARSE_DTDVALID);
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100291 if (!doc) {
292 ERROR("Unable to parse XML file\n");
293 return NULL;
294 }
295
296 ctx = iio_create_xml_context_helper(doc);
297 xmlFreeDoc(doc);
298 xmlCleanupParser();
299 return ctx;
300}