• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
19 #include "debug.h"
20 #include "iio-private.h"
21 
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 static const char * const iio_chan_type_name_spec[] = {
27 	[IIO_VOLTAGE] = "voltage",
28 	[IIO_CURRENT] = "current",
29 	[IIO_POWER] = "power",
30 	[IIO_ACCEL] = "accel",
31 	[IIO_ANGL_VEL] = "anglvel",
32 	[IIO_MAGN] = "magn",
33 	[IIO_LIGHT] = "illuminance",
34 	[IIO_INTENSITY] = "intensity",
35 	[IIO_PROXIMITY] = "proximity",
36 	[IIO_TEMP] = "temp",
37 	[IIO_INCLI] = "incli",
38 	[IIO_ROT] = "rot",
39 	[IIO_ANGL] = "angl",
40 	[IIO_TIMESTAMP] = "timestamp",
41 	[IIO_CAPACITANCE] = "capacitance",
42 	[IIO_ALTVOLTAGE] = "altvoltage",
43 	[IIO_CCT] = "cct",
44 	[IIO_PRESSURE] = "pressure",
45 	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
46 	[IIO_ACTIVITY] = "activity",
47 	[IIO_STEPS] = "steps",
48 	[IIO_ENERGY] = "energy",
49 	[IIO_DISTANCE] = "distance",
50 	[IIO_VELOCITY] = "velocity",
51 	[IIO_CONCENTRATION] = "concentration",
52 	[IIO_RESISTANCE] = "resistance",
53 	[IIO_PH] = "ph",
54 	[IIO_UVINDEX] = "uvindex",
55 	[IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity",
56 	[IIO_COUNT] = "count",
57 	[IIO_INDEX] = "index",
58 	[IIO_GRAVITY] = "gravity",
59 };
60 
61 static const char * const modifier_names[] = {
62 	[IIO_MOD_X] = "x",
63 	[IIO_MOD_Y] = "y",
64 	[IIO_MOD_Z] = "z",
65 	[IIO_MOD_X_AND_Y] = "x&y",
66 	[IIO_MOD_X_AND_Z] = "x&z",
67 	[IIO_MOD_Y_AND_Z] = "y&z",
68 	[IIO_MOD_X_AND_Y_AND_Z] = "x&y&z",
69 	[IIO_MOD_X_OR_Y] = "x|y",
70 	[IIO_MOD_X_OR_Z] = "x|z",
71 	[IIO_MOD_Y_OR_Z] = "y|z",
72 	[IIO_MOD_X_OR_Y_OR_Z] = "x|y|z",
73 	[IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)",
74 	[IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
75 	[IIO_MOD_LIGHT_BOTH] = "both",
76 	[IIO_MOD_LIGHT_IR] = "ir",
77 	[IIO_MOD_LIGHT_CLEAR] = "clear",
78 	[IIO_MOD_LIGHT_RED] = "red",
79 	[IIO_MOD_LIGHT_GREEN] = "green",
80 	[IIO_MOD_LIGHT_BLUE] = "blue",
81 	[IIO_MOD_LIGHT_UV] = "uv",
82 	[IIO_MOD_QUATERNION] = "quaternion",
83 	[IIO_MOD_TEMP_AMBIENT] = "ambient",
84 	[IIO_MOD_TEMP_OBJECT] = "object",
85 	[IIO_MOD_NORTH_MAGN] = "from_north_magnetic",
86 	[IIO_MOD_NORTH_TRUE] = "from_north_true",
87 	[IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
88 	[IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
89 	[IIO_MOD_RUNNING] = "running",
90 	[IIO_MOD_JOGGING] = "jogging",
91 	[IIO_MOD_WALKING] = "walking",
92 	[IIO_MOD_STILL] = "still",
93 	[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
94 	[IIO_MOD_I] = "i",
95 	[IIO_MOD_Q] = "q",
96 	[IIO_MOD_CO2] = "co2",
97 	[IIO_MOD_VOC] = "voc",
98 };
99 
100 /*
101  * Looks for a IIO channel modifier at the beginning of the string s. If a
102  * modifier was found the symbolic constant (IIO_MOD_*) is returned, otherwise
103  * IIO_NO_MOD is returned. If a modifier was found len_p will be updated with
104  * the length of the modifier.
105  */
find_channel_modifier(const char * s,size_t * len_p)106 unsigned int find_channel_modifier(const char *s, size_t *len_p)
107 {
108 	unsigned int i;
109 	size_t len;
110 
111 	for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
112 		if (!modifier_names[i])
113 			continue;
114 		len = strlen(modifier_names[i]);
115 		if (strncmp(s, modifier_names[i], len) == 0 &&
116 				(s[len] == '\0' || s[len] == '_')) {
117 			if (len_p)
118 				*len_p = len;
119 			return i;
120 		}
121 	}
122 
123 	return IIO_NO_MOD;
124 }
125 
126 /*
127  * Initializes all auto-detected fields of the channel struct. Must be called
128  * after the channel has been otherwise fully initialized.
129  */
iio_channel_init_finalize(struct iio_channel * chn)130 void iio_channel_init_finalize(struct iio_channel *chn)
131 {
132 	unsigned int i;
133 	size_t len;
134 	char *mod;
135 
136 	chn->type = IIO_CHAN_TYPE_UNKNOWN;
137 	chn->modifier = IIO_NO_MOD;
138 
139 	for (i = 0; i < ARRAY_SIZE(iio_chan_type_name_spec); i++) {
140 		len = strlen(iio_chan_type_name_spec[i]);
141 		if (strncmp(iio_chan_type_name_spec[i], chn->id, len) != 0)
142 			continue;
143 		/* Type must be followed by either a '_' or a digit */
144 		if (chn->id[len] != '_' && (chn->id[len] < '0' || chn->id[len] > '9'))
145 			continue;
146 
147 		chn->type = (enum iio_chan_type) i;
148 	}
149 
150 	mod = strchr(chn->id, '_');
151 	if (!mod)
152 		return;
153 
154 	mod++;
155 
156 	for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
157 		if (!modifier_names[i])
158 			continue;
159 		len = strlen(modifier_names[i]);
160 		if (strncmp(modifier_names[i], mod, len) != 0)
161 			continue;
162 
163 		chn->modifier = (enum iio_modifier) i;
164 		break;
165 	}
166 }
167 
get_attr_xml(struct iio_channel_attr * attr,size_t * length)168 static char *get_attr_xml(struct iio_channel_attr *attr, size_t *length)
169 {
170 	char *str;
171 	size_t len = strlen(attr->name) + sizeof("<attribute name=\"\" />");
172 	if (attr->filename)
173 		len += strlen(attr->filename) + sizeof("filename=\"\"");
174 
175 	str = malloc(len);
176 	if (!str)
177 		return NULL;
178 
179 	*length = len - 1; /* Skip the \0 */
180 	if (attr->filename)
181 		iio_snprintf(str, len, "<attribute name=\"%s\" filename=\"%s\" />",
182 				attr->name, attr->filename);
183 	else
184 		iio_snprintf(str, len, "<attribute name=\"%s\" />", attr->name);
185 	return str;
186 }
187 
get_scan_element(const struct iio_channel * chn,size_t * length)188 static char * get_scan_element(const struct iio_channel *chn, size_t *length)
189 {
190 	char buf[1024], repeat[12] = "", *str;
191 	char processed = (chn->format.is_fully_defined ? 'A' - 'a' : 0);
192 
193 	if (chn->format.repeat > 1)
194 		iio_snprintf(repeat, sizeof(repeat), "X%u", chn->format.repeat);
195 
196 	iio_snprintf(buf, sizeof(buf), "<scan-element index=\"%li\" "
197 			"format=\"%ce:%c%u/%u%s&gt;&gt;%u\" />",
198 			chn->index, chn->format.is_be ? 'b' : 'l',
199 			chn->format.is_signed ? 's' + processed : 'u' + processed,
200 			chn->format.bits, chn->format.length, repeat,
201 			chn->format.shift);
202 
203 	if (chn->format.with_scale) {
204 		char *ptr = strrchr(buf, '\0');
205 		iio_snprintf(ptr - 2, buf + sizeof(buf) - ptr + 2,
206 				"scale=\"%f\" />", chn->format.scale);
207 	}
208 
209 	str = iio_strdup(buf);
210 	if (str)
211 		*length = strlen(str);
212 	return str;
213 }
214 
215 /* Returns a string containing the XML representation of this channel */
iio_channel_get_xml(const struct iio_channel * chn,size_t * length)216 char * iio_channel_get_xml(const struct iio_channel *chn, size_t *length)
217 {
218 	size_t len = sizeof("<channel id=\"\" name=\"\" "
219 			"type=\"output\" ></channel>")
220 		+ strlen(chn->id) + (chn->name ? strlen(chn->name) : 0);
221 	char *ptr, *str, **attrs, *scan_element = NULL;
222 	size_t *attrs_len, scan_element_len = 0;
223 	unsigned int i;
224 
225 	if (chn->is_scan_element) {
226 		scan_element = get_scan_element(chn, &scan_element_len);
227 		if (!scan_element)
228 			return NULL;
229 		else
230 			len += scan_element_len;
231 	}
232 
233 	attrs_len = malloc(chn->nb_attrs * sizeof(*attrs_len));
234 	if (!attrs_len)
235 		goto err_free_scan_element;
236 
237 	attrs = malloc(chn->nb_attrs * sizeof(*attrs));
238 	if (!attrs)
239 		goto err_free_attrs_len;
240 
241 	for (i = 0; i < chn->nb_attrs; i++) {
242 		char *xml = get_attr_xml(&chn->attrs[i], &attrs_len[i]);
243 		if (!xml)
244 			goto err_free_attrs;
245 		attrs[i] = xml;
246 		len += attrs_len[i];
247 	}
248 
249 	str = malloc(len);
250 	if (!str)
251 		goto err_free_attrs;
252 
253 	iio_snprintf(str, len, "<channel id=\"%s\"", chn->id);
254 	ptr = strrchr(str, '\0');
255 
256 	if (chn->name) {
257 		sprintf(ptr, " name=\"%s\"", chn->name);
258 		ptr = strrchr(ptr, '\0');
259 	}
260 
261 	sprintf(ptr, " type=\"%s\" >", chn->is_output ? "output" : "input");
262 	ptr = strrchr(ptr, '\0');
263 
264 	if (chn->is_scan_element) {
265 		strcpy(ptr, scan_element);
266 		ptr += scan_element_len;
267 	}
268 
269 	for (i = 0; i < chn->nb_attrs; i++) {
270 		strcpy(ptr, attrs[i]);
271 		ptr += attrs_len[i];
272 		free(attrs[i]);
273 	}
274 
275 	free(scan_element);
276 	free(attrs);
277 	free(attrs_len);
278 
279 	strcpy(ptr, "</channel>");
280 	*length = ptr - str + sizeof("</channel>") - 1;
281 	return str;
282 
283 err_free_attrs:
284 	while (i--)
285 		free(attrs[i]);
286 	free(attrs);
287 err_free_attrs_len:
288 	free(attrs_len);
289 err_free_scan_element:
290 	if (chn->is_scan_element)
291 		free(scan_element);
292 	return NULL;
293 }
294 
iio_channel_get_id(const struct iio_channel * chn)295 const char * iio_channel_get_id(const struct iio_channel *chn)
296 {
297 	return chn->id;
298 }
299 
iio_channel_get_name(const struct iio_channel * chn)300 const char * iio_channel_get_name(const struct iio_channel *chn)
301 {
302 	return chn->name;
303 }
304 
iio_channel_is_output(const struct iio_channel * chn)305 bool iio_channel_is_output(const struct iio_channel *chn)
306 {
307 	return chn->is_output;
308 }
309 
iio_channel_is_scan_element(const struct iio_channel * chn)310 bool iio_channel_is_scan_element(const struct iio_channel *chn)
311 {
312 	return chn->is_scan_element;
313 }
314 
iio_channel_get_modifier(const struct iio_channel * chn)315 enum iio_modifier iio_channel_get_modifier(const struct iio_channel *chn)
316 {
317 	return chn->modifier;
318 }
319 
iio_channel_get_type(const struct iio_channel * chn)320 enum iio_chan_type iio_channel_get_type(const struct iio_channel *chn)
321 {
322 	return chn->type;
323 }
324 
iio_channel_get_attrs_count(const struct iio_channel * chn)325 unsigned int iio_channel_get_attrs_count(const struct iio_channel *chn)
326 {
327 	return chn->nb_attrs;
328 }
329 
iio_channel_get_attr(const struct iio_channel * chn,unsigned int index)330 const char * iio_channel_get_attr(const struct iio_channel *chn,
331 		unsigned int index)
332 {
333 	if (index >= chn->nb_attrs)
334 		return NULL;
335 	else
336 		return chn->attrs[index].name;
337 }
338 
iio_channel_find_attr(const struct iio_channel * chn,const char * name)339 const char * iio_channel_find_attr(const struct iio_channel *chn,
340 		const char *name)
341 {
342 	unsigned int i;
343 	for (i = 0; i < chn->nb_attrs; i++) {
344 		const char *attr = chn->attrs[i].name;
345 		if (!strcmp(attr, name))
346 			return attr;
347 	}
348 	return NULL;
349 }
350 
iio_channel_attr_read(const struct iio_channel * chn,const char * attr,char * dst,size_t len)351 ssize_t iio_channel_attr_read(const struct iio_channel *chn,
352 		const char *attr, char *dst, size_t len)
353 {
354 	if (chn->dev->ctx->ops->read_channel_attr)
355 		return chn->dev->ctx->ops->read_channel_attr(chn,
356 				attr, dst, len);
357 	else
358 		return -ENOSYS;
359 }
360 
iio_channel_attr_write_raw(const struct iio_channel * chn,const char * attr,const void * src,size_t len)361 ssize_t iio_channel_attr_write_raw(const struct iio_channel *chn,
362 		const char *attr, const void *src, size_t len)
363 {
364 	if (chn->dev->ctx->ops->write_channel_attr)
365 		return chn->dev->ctx->ops->write_channel_attr(chn,
366 				attr, src, len);
367 	else
368 		return -ENOSYS;
369 }
370 
iio_channel_attr_write(const struct iio_channel * chn,const char * attr,const char * src)371 ssize_t iio_channel_attr_write(const struct iio_channel *chn,
372 		const char *attr, const char *src)
373 {
374 	return iio_channel_attr_write_raw(chn, attr, src, strlen(src) + 1);
375 }
376 
iio_channel_set_data(struct iio_channel * chn,void * data)377 void iio_channel_set_data(struct iio_channel *chn, void *data)
378 {
379 	chn->userdata = data;
380 }
381 
iio_channel_get_data(const struct iio_channel * chn)382 void * iio_channel_get_data(const struct iio_channel *chn)
383 {
384 	return chn->userdata;
385 }
386 
iio_channel_get_index(const struct iio_channel * chn)387 long iio_channel_get_index(const struct iio_channel *chn)
388 {
389 	return chn->index;
390 }
391 
iio_channel_get_data_format(const struct iio_channel * chn)392 const struct iio_data_format * iio_channel_get_data_format(
393 		const struct iio_channel *chn)
394 {
395 	return &chn->format;
396 }
397 
iio_channel_is_enabled(const struct iio_channel * chn)398 bool iio_channel_is_enabled(const struct iio_channel *chn)
399 {
400 	return chn->index >= 0 && chn->dev->mask &&
401 		TEST_BIT(chn->dev->mask, chn->number);
402 }
403 
iio_channel_enable(struct iio_channel * chn)404 void iio_channel_enable(struct iio_channel *chn)
405 {
406 	if (chn->is_scan_element && chn->index >= 0 && chn->dev->mask)
407 		SET_BIT(chn->dev->mask, chn->number);
408 }
409 
iio_channel_disable(struct iio_channel * chn)410 void iio_channel_disable(struct iio_channel *chn)
411 {
412 	if (chn->index >= 0 && chn->dev->mask)
413 		CLEAR_BIT(chn->dev->mask, chn->number);
414 }
415 
free_channel(struct iio_channel * chn)416 void free_channel(struct iio_channel *chn)
417 {
418 	size_t i;
419 	for (i = 0; i < chn->nb_attrs; i++) {
420 		free(chn->attrs[i].name);
421 		free(chn->attrs[i].filename);
422 	}
423 	if (chn->nb_attrs)
424 		free(chn->attrs);
425 	if (chn->name)
426 		free(chn->name);
427 	if (chn->id)
428 		free(chn->id);
429 	free(chn);
430 }
431 
byte_swap(uint8_t * dst,const uint8_t * src,size_t len)432 static void byte_swap(uint8_t *dst, const uint8_t *src, size_t len)
433 {
434 	size_t i;
435 	for (i = 0; i < len; i++)
436 		dst[i] = src[len - i - 1];
437 }
438 
shift_bits(uint8_t * dst,size_t shift,size_t len,bool left)439 static void shift_bits(uint8_t *dst, size_t shift, size_t len, bool left)
440 {
441 	size_t i, shift_bytes = shift / 8;
442 	shift %= 8;
443 
444 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
445 	if (!left)
446 #else
447 	if (left)
448 #endif
449 	{
450 		if (shift_bytes) {
451 			memmove(dst, dst + shift_bytes, len - shift_bytes);
452 			memset(dst + len - shift_bytes, 0, shift_bytes);
453 		}
454 		if (shift) {
455 			for (i = 0; i < len; i++) {
456 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
457 				dst[i] >>= shift;
458 				if (i < len - 1)
459 					dst[i] |= dst[i + 1] << (8 - shift);
460 #else
461 				dst[i] <<= shift;
462 				if (i < len - 1)
463 					dst[i] |= dst[i + 1] >> (8 - shift);
464 #endif
465 			}
466 		}
467 	} else {
468 		if (shift_bytes) {
469 			memmove(dst + shift_bytes, dst, len - shift_bytes);
470 			memset(dst, 0, shift_bytes);
471 		}
472 		if (shift) {
473 			for (i = len; i > 0; i--) {
474 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
475 				dst[i - 1] <<= shift;
476 				if (i > 1)
477 					dst[i - 1] |= dst[i - 2] >> (8 - shift);
478 #else
479 				dst[i - 1] >>= shift;
480 				if (i > 1)
481 					dst[i - 1] |= dst[i - 2] << (8 - shift);
482 #endif
483 			}
484 		}
485 	}
486 }
487 
sign_extend(uint8_t * dst,size_t bits,size_t len)488 static void sign_extend(uint8_t *dst, size_t bits, size_t len)
489 {
490 	size_t upper_bytes = ((len * 8 - bits) / 8);
491 	uint8_t msb, msb_bit = 1 << ((bits - 1) % 8);
492 
493 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
494 	msb = dst[len - 1 - upper_bytes] & msb_bit;
495 	if (upper_bytes)
496 		memset(dst + len - upper_bytes, msb ? 0xff : 0x00, upper_bytes);
497 	if (msb)
498 		dst[len - 1 - upper_bytes] |= ~(msb_bit - 1);
499 	else
500 		dst[len - 1 - upper_bytes] &= (msb_bit - 1);
501 #else
502 	/* XXX: untested */
503 	msb = dst[upper_bytes] & msb_bit;
504 	if (upper_bytes)
505 		memset(dst, msb ? 0xff : 0x00, upper_bytes);
506 	if (msb)
507 		dst[upper_bytes] |= ~(msb_bit - 1);
508 #endif
509 }
510 
mask_upper_bits(uint8_t * dst,size_t bits,size_t len)511 static void mask_upper_bits(uint8_t *dst, size_t bits, size_t len)
512 {
513 	size_t i;
514 
515 	/* Clear upper bits */
516 	if (bits % 8)
517 		dst[bits / 8] &= (1 << (bits % 8)) - 1;
518 
519 	/* Clear upper bytes */
520 	for (i = (bits + 7) / 8; i < len; i++)
521 		dst[i] = 0;
522 }
523 
524 
iio_channel_convert(const struct iio_channel * chn,void * dst,const void * src)525 void iio_channel_convert(const struct iio_channel *chn,
526 		void *dst, const void *src)
527 {
528 	uintptr_t src_ptr = (uintptr_t) src, dst_ptr = (uintptr_t) dst;
529 	unsigned int len = chn->format.length / 8;
530 	ptrdiff_t end = len * chn->format.repeat;
531 	uintptr_t end_ptr = src_ptr + end;
532 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
533 	bool swap = chn->format.is_be;
534 #else
535 	bool swap = !chn->format.is_be;
536 #endif
537 
538 	for (src_ptr = (uintptr_t) src; src_ptr < end_ptr;
539 			src_ptr += len, dst_ptr += len) {
540 		if (len == 1 || !swap)
541 			memcpy((void *) dst_ptr, (const void *) src_ptr, len);
542 		else
543 			byte_swap((void *) dst_ptr, (const void *) src_ptr,
544 				len);
545 
546 		if (chn->format.shift)
547 			shift_bits((void *) dst_ptr, chn->format.shift, len,
548 				false);
549 
550 		if (!chn->format.is_fully_defined) {
551 			if (chn->format.is_signed)
552 				sign_extend((void *) dst_ptr,
553 					chn->format.bits, len);
554 			else
555 				mask_upper_bits((void *) dst_ptr,
556 					chn->format.bits, len);
557 		}
558 	}
559 }
560 
iio_channel_convert_inverse(const struct iio_channel * chn,void * dst,const void * src)561 void iio_channel_convert_inverse(const struct iio_channel *chn,
562 		void *dst, const void *src)
563 {
564 	uintptr_t src_ptr = (uintptr_t) src, dst_ptr = (uintptr_t) dst;
565 	unsigned int len = chn->format.length / 8;
566 	ptrdiff_t end = len * chn->format.repeat;
567 	uintptr_t end_ptr = dst_ptr + end;
568 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
569 	bool swap = chn->format.is_be;
570 #else
571 	bool swap = !chn->format.is_be;
572 #endif
573 	uint8_t buf[1024];
574 
575 	/* Somehow I doubt we will have samples of 8192 bits each. */
576 	if (len > sizeof(buf))
577 		return;
578 
579 	for (dst_ptr = (uintptr_t) dst; dst_ptr < end_ptr;
580 			src_ptr += len, dst_ptr += len) {
581 		memcpy(buf, (const void *) src_ptr, len);
582 		mask_upper_bits(buf, chn->format.bits, len);
583 
584 		if (chn->format.shift)
585 			shift_bits(buf, chn->format.shift, len, true);
586 
587 		if (len == 1 || !swap)
588 			memcpy((void *) dst_ptr, buf, len);
589 		else
590 			byte_swap((void *) dst_ptr, buf, len);
591 	}
592 }
593 
iio_channel_read_raw(const struct iio_channel * chn,struct iio_buffer * buf,void * dst,size_t len)594 size_t iio_channel_read_raw(const struct iio_channel *chn,
595 		struct iio_buffer *buf, void *dst, size_t len)
596 {
597 	uintptr_t src_ptr, dst_ptr = (uintptr_t) dst, end = dst_ptr + len;
598 	unsigned int length = chn->format.length / 8 * chn->format.repeat;
599 	uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf);
600 	ptrdiff_t buf_step = iio_buffer_step(buf);
601 
602 	for (src_ptr = (uintptr_t) iio_buffer_first(buf, chn);
603 			src_ptr < buf_end && dst_ptr + length <= end;
604 			src_ptr += buf_step, dst_ptr += length)
605 		memcpy((void *) dst_ptr, (const void *) src_ptr, length);
606 	return dst_ptr - (uintptr_t) dst;
607 }
608 
iio_channel_read(const struct iio_channel * chn,struct iio_buffer * buf,void * dst,size_t len)609 size_t iio_channel_read(const struct iio_channel *chn,
610 		struct iio_buffer *buf, void *dst, size_t len)
611 {
612 	uintptr_t src_ptr, dst_ptr = (uintptr_t) dst, end = dst_ptr + len;
613 	unsigned int length = chn->format.length / 8 * chn->format.repeat;
614 	uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf);
615 	ptrdiff_t buf_step = iio_buffer_step(buf);
616 
617 	for (src_ptr = (uintptr_t) iio_buffer_first(buf, chn);
618 			src_ptr < buf_end && dst_ptr + length <= end;
619 			src_ptr += buf_step, dst_ptr += length)
620 		iio_channel_convert(chn,
621 				(void *) dst_ptr, (const void *) src_ptr);
622 	return dst_ptr - (uintptr_t) dst;
623 }
624 
iio_channel_write_raw(const struct iio_channel * chn,struct iio_buffer * buf,const void * src,size_t len)625 size_t iio_channel_write_raw(const struct iio_channel *chn,
626 		struct iio_buffer *buf, const void *src, size_t len)
627 {
628 	uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len;
629 	unsigned int length = chn->format.length / 8 * chn->format.repeat;
630 	uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf);
631 	ptrdiff_t buf_step = iio_buffer_step(buf);
632 
633 	for (dst_ptr = (uintptr_t) iio_buffer_first(buf, chn);
634 			dst_ptr < buf_end && src_ptr + length <= end;
635 			dst_ptr += buf_step, src_ptr += length)
636 		memcpy((void *) dst_ptr, (const void *) src_ptr, length);
637 	return src_ptr - (uintptr_t) src;
638 }
639 
iio_channel_write(const struct iio_channel * chn,struct iio_buffer * buf,const void * src,size_t len)640 size_t iio_channel_write(const struct iio_channel *chn,
641 		struct iio_buffer *buf, const void *src, size_t len)
642 {
643 	uintptr_t dst_ptr, src_ptr = (uintptr_t) src, end = src_ptr + len;
644 	unsigned int length = chn->format.length / 8 * chn->format.repeat;
645 	uintptr_t buf_end = (uintptr_t) iio_buffer_end(buf);
646 	ptrdiff_t buf_step = iio_buffer_step(buf);
647 
648 	for (dst_ptr = (uintptr_t) iio_buffer_first(buf, chn);
649 			dst_ptr < buf_end && src_ptr + length <= end;
650 			dst_ptr += buf_step, src_ptr += length)
651 		iio_channel_convert_inverse(chn,
652 				(void *) dst_ptr, (const void *) src_ptr);
653 	return src_ptr - (uintptr_t) src;
654 }
655 
iio_channel_attr_read_longlong(const struct iio_channel * chn,const char * attr,long long * val)656 int iio_channel_attr_read_longlong(const struct iio_channel *chn,
657 		const char *attr, long long *val)
658 {
659 	char *end, buf[1024];
660 	long long value;
661 	ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
662 	if (ret < 0)
663 		return (int) ret;
664 
665 	value = strtoll(buf, &end, 0);
666 	if (end == buf)
667 		return -EINVAL;
668 	*val = value;
669 	return 0;
670 }
671 
iio_channel_attr_read_bool(const struct iio_channel * chn,const char * attr,bool * val)672 int iio_channel_attr_read_bool(const struct iio_channel *chn,
673 		const char *attr, bool *val)
674 {
675 	long long value;
676 	int ret = iio_channel_attr_read_longlong(chn, attr, &value);
677 	if (ret < 0)
678 		return ret;
679 
680 	*val = !!value;
681 	return 0;
682 }
683 
iio_channel_attr_read_double(const struct iio_channel * chn,const char * attr,double * val)684 int iio_channel_attr_read_double(const struct iio_channel *chn,
685 		const char *attr, double *val)
686 {
687 	char buf[1024];
688 	ssize_t ret = iio_channel_attr_read(chn, attr, buf, sizeof(buf));
689 	if (ret < 0)
690 		return (int) ret;
691 	else
692 		return read_double(buf, val);
693 }
694 
iio_channel_attr_write_longlong(const struct iio_channel * chn,const char * attr,long long val)695 int iio_channel_attr_write_longlong(const struct iio_channel *chn,
696 		const char *attr, long long val)
697 {
698 	ssize_t ret;
699 	char buf[1024];
700 	iio_snprintf(buf, sizeof(buf), "%lld", val);
701 	ret = iio_channel_attr_write(chn, attr, buf);
702 	return ret < 0 ? ret : 0;
703 }
704 
iio_channel_attr_write_double(const struct iio_channel * chn,const char * attr,double val)705 int iio_channel_attr_write_double(const struct iio_channel *chn,
706 		const char *attr, double val)
707 {
708 	ssize_t ret;
709 	char buf[1024];
710 
711 	ret = (ssize_t) write_double(buf, sizeof(buf), val);
712 	if (!ret)
713 		ret = iio_channel_attr_write(chn, attr, buf);
714 	return ret < 0 ? ret : 0;
715 }
716 
iio_channel_attr_write_bool(const struct iio_channel * chn,const char * attr,bool val)717 int iio_channel_attr_write_bool(const struct iio_channel *chn,
718 		const char *attr, bool val)
719 {
720 	ssize_t ret;
721 	if (val)
722 		ret = iio_channel_attr_write_raw(chn, attr, "1", 2);
723 	else
724 		ret = iio_channel_attr_write_raw(chn, attr, "0", 2);
725 	return ret < 0 ? ret : 0;
726 }
727 
iio_channel_attr_get_filename(const struct iio_channel * chn,const char * attr)728 const char * iio_channel_attr_get_filename(
729 		const struct iio_channel *chn, const char *attr)
730 {
731 	unsigned int i;
732 	for (i = 0; i < chn->nb_attrs; i++) {
733 		if (!strcmp(chn->attrs[i].name, attr))
734 			return chn->attrs[i].filename;
735 	}
736 	return NULL;
737 }
738 
iio_channel_attr_read_all(struct iio_channel * chn,int (* cb)(struct iio_channel * chn,const char * attr,const char * val,size_t len,void * d),void * data)739 int iio_channel_attr_read_all(struct iio_channel *chn,
740 		int (*cb)(struct iio_channel *chn,
741 			const char *attr, const char *val, size_t len, void *d),
742 		void *data)
743 {
744 	int ret, buf_size;
745 	char *buf, *ptr;
746 	unsigned int i;
747 
748 	/* We need a big buffer here; 1 MiB should be enough */
749 	buf = malloc(0x100000);
750 	if (!buf)
751 		return -ENOMEM;
752 
753 	ret = (int) iio_channel_attr_read(chn, NULL, buf, 0x100000);
754 	if (ret < 0)
755 		goto err_free_buf;
756 
757 	ptr = buf;
758 	buf_size = ret;
759 
760 	for (i = 0; i < iio_channel_get_attrs_count(chn); i++) {
761 		const char *attr = iio_channel_get_attr(chn, i);
762 		int32_t len;
763 
764 		if (buf_size < 4) {
765 			ret = -EPROTO;
766 			break;
767 		}
768 
769 		len = (int32_t) iio_be32toh(*(uint32_t *) ptr);
770 		ptr += 4;
771 		buf_size -= 4;
772 
773 		if (len > 0 && buf_size < len) {
774 			ret = -EPROTO;
775 			break;
776 		}
777 
778 		if (len > 0) {
779 			ret = cb(chn, attr, ptr, (size_t) len, data);
780 			if (ret < 0)
781 				goto err_free_buf;
782 
783 			if (len & 0x3)
784 				len = ((len >> 2) + 1) << 2;
785 			ptr += len;
786 			if (len >= buf_size)
787 				buf_size = 0;
788 			else
789 				buf_size -= len;
790 		}
791 	}
792 
793 err_free_buf:
794 	free(buf);
795 	return ret < 0 ? ret : 0;
796 }
797 
iio_channel_attr_write_all(struct iio_channel * chn,ssize_t (* cb)(struct iio_channel * chn,const char * attr,void * buf,size_t len,void * d),void * data)798 int iio_channel_attr_write_all(struct iio_channel *chn,
799 		ssize_t (*cb)(struct iio_channel *chn,
800 			const char *attr, void *buf, size_t len, void *d),
801 		void *data)
802 {
803 	char *buf, *ptr;
804 	unsigned int i;
805 	size_t len = 0x100000;
806 	int ret;
807 
808 	/* We need a big buffer here; 1 MiB should be enough */
809 	buf = malloc(len);
810 	if (!buf)
811 		return -ENOMEM;
812 
813 	ptr = buf;
814 
815 	for (i = 0; i < iio_channel_get_attrs_count(chn); i++) {
816 		const char *attr = iio_channel_get_attr(chn, i);
817 
818 		ret = (int) cb(chn, attr, ptr + 4, len - 4, data);
819 		if (ret < 0)
820 			goto err_free_buf;
821 
822 		*(int32_t *) ptr = (int32_t) iio_htobe32((uint32_t) ret);
823 		ptr += 4;
824 		len -= 4;
825 
826 		if (ret > 0) {
827 			if (ret & 0x3)
828 				ret = ((ret >> 2) + 1) << 2;
829 			ptr += ret;
830 			len -= ret;
831 		}
832 	}
833 
834 	ret = (int) iio_channel_attr_write_raw(chn, NULL, buf, ptr - buf);
835 
836 err_free_buf:
837 	free(buf);
838 	return ret < 0 ? ret : 0;
839 }
840 
iio_channel_get_device(const struct iio_channel * chn)841 const struct iio_device * iio_channel_get_device(const struct iio_channel *chn)
842 {
843 	return chn->dev;
844 }
845