blob: 62d3f6ed03a56ea7b9f9441dc40146ca3dd437cf [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 Cercueil42090d12014-02-24 12:32:23 +010019#include "debug.h"
Paul Cercueil0b2ce712014-02-17 15:04:18 +010020#include "iio-private.h"
21
Paul Cercueil4c6729d2014-04-04 17:24:41 +020022#include <errno.h>
Paul Cercueil42090d12014-02-24 12:32:23 +010023#include <string.h>
24
25static const char xml_header[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
26"<!DOCTYPE context ["
27"<!ELEMENT context (device)*>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020028"<!ELEMENT device (channel | attribute | debug-attribute)*>"
Paul Cercueil42090d12014-02-24 12:32:23 +010029"<!ELEMENT channel (attribute)*>"
30"<!ELEMENT attribute EMPTY>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020031"<!ELEMENT debug-attribute EMPTY>"
Paul Cercueil42090d12014-02-24 12:32:23 +010032"<!ATTLIST context name CDATA #REQUIRED>"
33"<!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED>"
Paul Cercueil85aaf482014-04-24 16:39:09 +020034"<!ATTLIST channel id CDATA #REQUIRED type (input|output) #REQUIRED scan_element (true|false) \"false\" name CDATA #IMPLIED>"
Paul Cercueil42d12352014-05-05 16:11:58 +020035"<!ATTLIST attribute name CDATA #REQUIRED filename CDATA #IMPLIED>"
Paul Cercueild9d9f9f2014-04-15 10:08:17 +020036"<!ATTLIST debug-attribute name CDATA #REQUIRED>"
Paul Cercueil42090d12014-02-24 12:32:23 +010037"]>";
38
39/* Returns a string containing the XML representation of this context */
Paul Cercueil4c6729d2014-04-04 17:24:41 +020040static char * context_create_xml(const struct iio_context *ctx)
Paul Cercueil42090d12014-02-24 12:32:23 +010041{
Paul Cercueil9aab0192014-04-07 11:04:30 +020042 size_t len = strlen(ctx->name) + sizeof(xml_header) - 1 +
Paul Cercueil42090d12014-02-24 12:32:23 +010043 sizeof("<context name=\"\" ></context>");
Paul Cercueil5822ab62014-04-04 13:29:17 +020044 size_t *devices_len;
45 char *str, *ptr, **devices;
Paul Cercueil42090d12014-02-24 12:32:23 +010046 unsigned int i;
47
Paul Cercueil9aab0192014-04-07 11:04:30 +020048 if (!ctx->nb_devices) {
49 str = malloc(len);
50 if (str)
51 snprintf(str, len, "%s<context name=\"%s\" ></context>",
52 xml_header, ctx->name);
53 return str;
54 }
55
Paul Cercueil5822ab62014-04-04 13:29:17 +020056 devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
57 if (!devices_len)
58 return NULL;
59
60 devices = malloc(ctx->nb_devices * sizeof(*devices));
61 if (!devices)
62 goto err_free_devices_len;
63
Paul Cercueil42090d12014-02-24 12:32:23 +010064 for (i = 0; i < ctx->nb_devices; i++) {
65 char *xml = iio_device_get_xml(ctx->devices[i],
66 &devices_len[i]);
67 if (!xml)
68 goto err_free_devices;
69 devices[i] = xml;
70 len += devices_len[i];
71 }
72
73 str = malloc(len);
74 if (!str)
75 goto err_free_devices;
76
Paul Cercueil8c29e412014-04-07 09:46:45 +020077 snprintf(str, len, "%s<context name=\"%s\" >", xml_header, ctx->name);
Paul Cercueil42090d12014-02-24 12:32:23 +010078 ptr = strrchr(str, '\0');
79
80 for (i = 0; i < ctx->nb_devices; i++) {
81 strcpy(ptr, devices[i]);
82 ptr += devices_len[i];
83 free(devices[i]);
84 }
85
Paul Cercueil5822ab62014-04-04 13:29:17 +020086 free(devices);
87 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +010088 strcpy(ptr, "</context>");
89 return str;
90
91err_free_devices:
92 while (i--)
93 free(devices[i]);
Paul Cercueil5822ab62014-04-04 13:29:17 +020094 free(devices);
95err_free_devices_len:
96 free(devices_len);
Paul Cercueil42090d12014-02-24 12:32:23 +010097 return NULL;
98}
99
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200100const char * iio_context_get_xml(const struct iio_context *ctx)
101{
102 return ctx->xml;
103}
104
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100105const char * iio_context_get_name(const struct iio_context *ctx)
106{
107 return ctx->name;
108}
109
110void iio_context_destroy(struct iio_context *ctx)
111{
Paul Cercueil50363542014-02-18 16:04:28 +0100112 unsigned int i;
113 if (ctx->ops->shutdown)
114 ctx->ops->shutdown(ctx);
115
116 for (i = 0; i < ctx->nb_devices; i++)
117 free_device(ctx->devices[i]);
118 if (ctx->nb_devices)
119 free(ctx->devices);
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200120 if (ctx->xml)
121 free(ctx->xml);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100122 free(ctx);
123}
124
125unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
126{
127 return ctx->nb_devices;
128}
129
130struct iio_device * iio_context_get_device(const struct iio_context *ctx,
131 unsigned int index)
132{
133 if (index >= ctx->nb_devices)
134 return NULL;
135 else
136 return ctx->devices[index];
137}
Paul Cercueilae88fde2014-03-12 11:47:10 +0100138
Paul Cercueil17512b02014-03-28 11:15:24 +0100139struct iio_device * iio_context_find_device(const struct iio_context *ctx,
140 const char *name)
141{
142 unsigned int i;
143 for (i = 0; i < ctx->nb_devices; i++) {
144 struct iio_device *dev = ctx->devices[i];
145 if (!strcmp(dev->id, name) ||
146 (dev->name && !strcmp(dev->name, name)))
147 return dev;
148 }
149 return NULL;
150}
151
Paul Cercueilae88fde2014-03-12 11:47:10 +0100152static void init_index(struct iio_channel *chn)
153{
154 char buf[1024];
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100155 long ret = (long) iio_channel_attr_read(chn, "index", buf, sizeof(buf));
Paul Cercueilae88fde2014-03-12 11:47:10 +0100156 if (ret < 0)
157 chn->index = ret;
158 else
159 chn->index = strtol(buf, NULL, 0);
160}
161
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100162static void init_data_format(struct iio_channel *chn)
163{
164 char buf[1024];
Paul Cercueilfacd9f12014-05-09 17:38:34 +0200165 int ret;
166
167 if (chn->is_scan_element) {
168 ret = iio_channel_attr_read(chn, "type", buf, sizeof(buf));
169 if (ret < 0) {
170 chn->format.length = 0;
171 } else {
172 char endian, sign;
173 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
174 &chn->format.bits,
175 &chn->format.length,
176 &chn->format.shift);
177 chn->format.is_signed = sign == 's';
178 chn->format.is_be = endian == 'b';
179 }
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100180 }
181
182 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
183 if (ret < 0) {
184 chn->format.with_scale = false;
185 } else {
186 chn->format.with_scale = true;
187 chn->format.scale = strtod(buf, NULL);
188 }
189}
190
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100191static void reorder_channels(struct iio_device *dev)
192{
193 bool found;
194 unsigned int i;
195
196 /* Reorder channels by index */
197 do {
198 found = false;
199 for (i = 1; i < dev->nb_channels; i++) {
200 struct iio_channel **channels = dev->channels;
201 long ch1 = channels[i - 1]->index;
202 long ch2 = channels[i]->index;
203
204 if (ch2 >= 0 && ((ch1 > ch2) || ch1 < 0)) {
205 struct iio_channel *bak = channels[i];
206 channels[i] = channels[i - 1];
207 channels[i - 1] = bak;
208 found = true;
209 }
210 }
211 } while (found);
212}
213
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200214int iio_context_init(struct iio_context *ctx)
Paul Cercueilae88fde2014-03-12 11:47:10 +0100215{
216 unsigned int i;
217 for (i = 0; i < ctx->nb_devices; i++) {
218 unsigned int j;
219 struct iio_device *dev = ctx->devices[i];
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100220 for (j = 0; j < dev->nb_channels; j++) {
Paul Cercueilfacd9f12014-05-09 17:38:34 +0200221 struct iio_channel *chn = dev->channels[j];
222 if (chn->is_scan_element)
223 init_index(chn);
224 else
225 chn->index = -1;
226 init_data_format(chn);
Paul Cercueilcd6ce842014-03-14 13:21:06 +0100227 }
Paul Cercueil1f7bc152014-03-14 13:48:43 +0100228
229 reorder_channels(dev);
Paul Cercueilae88fde2014-03-12 11:47:10 +0100230 }
Paul Cercueil4c6729d2014-04-04 17:24:41 +0200231
232 ctx->xml = context_create_xml(ctx);
233 return ctx->xml ? 0 : -ENOMEM;
Paul Cercueilae88fde2014-03-12 11:47:10 +0100234}
Paul Cercueile45f8762014-05-02 11:19:26 +0200235
236int iio_context_get_version(const struct iio_context *ctx,
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200237 unsigned int *major, unsigned int *minor, char git_tag[8])
Paul Cercueile45f8762014-05-02 11:19:26 +0200238{
239 if (ctx->ops->get_version)
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200240 return ctx->ops->get_version(ctx, major, minor, git_tag);
Paul Cercueild15d9952014-05-20 11:40:08 +0200241 if (major)
242 *major = LIBIIO_VERSION_MAJOR;
243 if (minor)
244 *minor = LIBIIO_VERSION_MINOR;
Paul Cercueil9de9e9d2014-05-20 13:18:19 +0200245 if (git_tag) {
246 strncpy(git_tag, LIBIIO_VERSION_GIT, 8);
247 git_tag[7] = '\0';
248 }
Paul Cercueile45f8762014-05-02 11:19:26 +0200249 return 0;
250}