• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libiio - Library for interfacing industrial I/O (IIO) devices
3  *
4  * Copyright (C) 2014-2016 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 "iiod-client.h"
21 #include "iio-lock.h"
22 #include "iio-private.h"
23 
24 #include <errno.h>
25 #include <inttypes.h>
26 #include <string.h>
27 #include <stdio.h>
28 
29 struct iiod_client {
30 	struct iio_context_pdata *pdata;
31 	const struct iiod_client_ops *ops;
32 	struct iio_mutex *lock;
33 };
34 
iiod_client_read_integer(struct iiod_client * client,void * desc,int * val)35 static ssize_t iiod_client_read_integer(struct iiod_client *client,
36 		void *desc, int *val)
37 {
38 	unsigned int i;
39 	char buf[1024], *ptr = NULL, *end;
40 	ssize_t ret;
41 	int value;
42 
43 	do {
44 		ret = client->ops->read_line(client->pdata,
45 				desc, buf, sizeof(buf));
46 		if (ret < 0)
47 			return ret;
48 
49 		for (i = 0; i < (unsigned int) ret; i++) {
50 			if (buf[i] != '\n') {
51 				if (!ptr)
52 					ptr = &buf[i];
53 			} else if (!!ptr) {
54 				break;
55 			}
56 		}
57 	} while (!ptr);
58 
59 	buf[i] = '\0';
60 
61 	value = (int) strtol(ptr, &end, 10);
62 	if (ptr == end)
63 		return -EINVAL;
64 
65 	*val = value;
66 	return 0;
67 }
68 
iiod_client_exec_command(struct iiod_client * client,void * desc,const char * cmd)69 static int iiod_client_exec_command(struct iiod_client *client,
70 		void *desc, const char *cmd)
71 {
72 	int resp;
73 	ssize_t ret;
74 
75 	ret = client->ops->write(client->pdata, desc, cmd, strlen(cmd));
76 	if (ret < 0)
77 		return (int) ret;
78 
79 	ret = iiod_client_read_integer(client, desc, &resp);
80 	return ret < 0 ? (int) ret : resp;
81 }
82 
iiod_client_write_all(struct iiod_client * client,void * desc,const void * src,size_t len)83 static ssize_t iiod_client_write_all(struct iiod_client *client,
84 		void *desc, const void *src, size_t len)
85 {
86 	struct iio_context_pdata *pdata = client->pdata;
87 	const struct iiod_client_ops *ops = client->ops;
88 	uintptr_t ptr = (uintptr_t) src;
89 
90 	while (len) {
91 		ssize_t ret = ops->write(pdata, desc, (const void *) ptr, len);
92 
93 		if (ret < 0) {
94 			if (ret == -EINTR)
95 				continue;
96 			else
97 				return ret;
98 		}
99 
100 		if (ret == 0)
101 			return -EPIPE;
102 
103 		ptr += ret;
104 		len -= ret;
105 	}
106 
107 	return (ssize_t) (ptr - (uintptr_t) src);
108 }
109 
iiod_client_read_all(struct iiod_client * client,void * desc,void * dst,size_t len)110 static ssize_t iiod_client_read_all(struct iiod_client *client,
111 		void *desc, void *dst, size_t len)
112 {
113 	struct iio_context_pdata *pdata = client->pdata;
114 	const struct iiod_client_ops *ops = client->ops;
115 	uintptr_t ptr = (uintptr_t) dst;
116 
117 	while (len) {
118 		ssize_t ret = ops->read(pdata, desc, (void *) ptr, len);
119 
120 		if (ret < 0) {
121 			if (ret == -EINTR)
122 				continue;
123 			else
124 				return ret;
125 		}
126 
127 		if (ret == 0)
128 			return -EPIPE;
129 
130 		ptr += ret;
131 		len -= ret;
132 	}
133 
134 	return (ssize_t) (ptr - (uintptr_t) dst);
135 }
136 
iiod_client_new(struct iio_context_pdata * pdata,struct iio_mutex * lock,const struct iiod_client_ops * ops)137 struct iiod_client * iiod_client_new(struct iio_context_pdata *pdata,
138 		struct iio_mutex *lock, const struct iiod_client_ops *ops)
139 {
140 	struct iiod_client *client;
141 
142 	client = malloc(sizeof(*client));
143 	if (!client) {
144 		errno = ENOMEM;
145 		return NULL;
146 	}
147 
148 	client->lock = lock;
149 	client->pdata = pdata;
150 	client->ops = ops;
151 	return client;
152 }
153 
iiod_client_destroy(struct iiod_client * client)154 void iiod_client_destroy(struct iiod_client *client)
155 {
156 	free(client);
157 }
158 
iiod_client_get_version(struct iiod_client * client,void * desc,unsigned int * major,unsigned int * minor,char * git_tag)159 int iiod_client_get_version(struct iiod_client *client, void *desc,
160 		unsigned int *major, unsigned int *minor, char *git_tag)
161 {
162 	struct iio_context_pdata *pdata = client->pdata;
163 	const struct iiod_client_ops *ops = client->ops;
164 	char buf[256], *ptr = buf, *end;
165 	long maj, min;
166 	int ret;
167 
168 	iio_mutex_lock(client->lock);
169 
170 	ret = ops->write(pdata, desc, "VERSION\r\n", sizeof("VERSION\r\n") - 1);
171 	if (ret < 0) {
172 		iio_mutex_unlock(client->lock);
173 		return ret;
174 	}
175 
176 	ret = ops->read_line(pdata, desc, buf, sizeof(buf));
177 	iio_mutex_unlock(client->lock);
178 
179 	if (ret < 0)
180 		return ret;
181 
182 	maj = strtol(ptr, &end, 10);
183 	if (ptr == end)
184 		return -EIO;
185 
186 	ptr = end + 1;
187 	min = strtol(ptr, &end, 10);
188 	if (ptr == end)
189 		return -EIO;
190 
191 	ptr = end + 1;
192 	if (buf + ret < ptr + 8)
193 		return -EIO;
194 
195 	/* Strip the \n */
196 	ptr[buf + ret - ptr - 1] = '\0';
197 
198 	if (major)
199 		*major = (unsigned int) maj;
200 	if (minor)
201 		*minor = (unsigned int) min;
202 	if (git_tag)
203 		strncpy(git_tag, ptr, 8);
204 	return 0;
205 }
206 
iiod_client_get_trigger(struct iiod_client * client,void * desc,const struct iio_device * dev,const struct iio_device ** trigger)207 int iiod_client_get_trigger(struct iiod_client *client, void *desc,
208 		const struct iio_device *dev, const struct iio_device **trigger)
209 {
210 	const struct iio_context *ctx = iio_device_get_context(dev);
211 	unsigned int i, nb_devices = iio_context_get_devices_count(ctx);
212 	char buf[1024];
213 	unsigned int name_len;
214 	int ret;
215 
216 	iio_snprintf(buf, sizeof(buf), "GETTRIG %s\r\n",
217 			iio_device_get_id(dev));
218 
219 	iio_mutex_lock(client->lock);
220 	ret = iiod_client_exec_command(client, desc, buf);
221 
222 	if (ret == 0)
223 		*trigger = NULL;
224 	if (ret <= 0)
225 		goto out_unlock;
226 
227 	if ((unsigned int) ret > sizeof(buf) - 1) {
228 		ret = -EIO;
229 		goto out_unlock;
230 	}
231 
232 	name_len = ret;
233 
234 	ret = (int) iiod_client_read_all(client, desc, buf, name_len + 1);
235 	if (ret < 0)
236 		goto out_unlock;
237 
238 	ret = -ENXIO;
239 
240 	for (i = 0; i < nb_devices; i++) {
241 		struct iio_device *cur = iio_context_get_device(ctx, i);
242 
243 		if (iio_device_is_trigger(cur)) {
244 			const char *name = iio_device_get_name(cur);
245 
246 			if (!name)
247 				continue;
248 
249 			if (!strncmp(name, buf, name_len)) {
250 				*trigger = cur;
251 				ret = 0;
252 				goto out_unlock;
253 			}
254 		}
255 	}
256 
257 out_unlock:
258 	iio_mutex_unlock(client->lock);
259 	return ret;
260 }
261 
iiod_client_set_trigger(struct iiod_client * client,void * desc,const struct iio_device * dev,const struct iio_device * trigger)262 int iiod_client_set_trigger(struct iiod_client *client, void *desc,
263 		const struct iio_device *dev, const struct iio_device *trigger)
264 {
265 	char buf[1024];
266 	int ret;
267 
268 	if (trigger) {
269 		iio_snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
270 				iio_device_get_id(dev),
271 				iio_device_get_id(trigger));
272 	} else {
273 		iio_snprintf(buf, sizeof(buf), "SETTRIG %s\r\n",
274 				iio_device_get_id(dev));
275 	}
276 
277 	iio_mutex_lock(client->lock);
278 	ret = iiod_client_exec_command(client, desc, buf);
279 	iio_mutex_unlock(client->lock);
280 	return ret;
281 }
282 
iiod_client_set_kernel_buffers_count(struct iiod_client * client,void * desc,const struct iio_device * dev,unsigned int nb_blocks)283 int iiod_client_set_kernel_buffers_count(struct iiod_client *client, void *desc,
284 		const struct iio_device *dev, unsigned int nb_blocks)
285 {
286 	int ret;
287 	char buf[1024];
288 
289 	iio_snprintf(buf, sizeof(buf), "SET %s BUFFERS_COUNT %u\r\n",
290 			iio_device_get_id(dev), nb_blocks);
291 
292 	iio_mutex_lock(client->lock);
293 	ret = iiod_client_exec_command(client, desc, buf);
294 	iio_mutex_unlock(client->lock);
295 	return ret;
296 }
297 
iiod_client_set_timeout(struct iiod_client * client,void * desc,unsigned int timeout)298 int iiod_client_set_timeout(struct iiod_client *client,
299 		void *desc, unsigned int timeout)
300 {
301 	int ret;
302 	char buf[1024];
303 
304 	iio_snprintf(buf, sizeof(buf), "TIMEOUT %u\r\n", timeout);
305 
306 	iio_mutex_lock(client->lock);
307 	ret = iiod_client_exec_command(client, desc, buf);
308 	iio_mutex_unlock(client->lock);
309 	return ret;
310 }
311 
iiod_client_discard(struct iiod_client * client,void * desc,char * buf,size_t buf_len,size_t to_discard)312 static int iiod_client_discard(struct iiod_client *client, void *desc,
313 		char *buf, size_t buf_len, size_t to_discard)
314 {
315 	do {
316 		size_t read_len;
317 		ssize_t ret;
318 
319 		if (to_discard > buf_len)
320 			read_len = buf_len;
321 		else
322 			read_len = to_discard;
323 
324 		ret = iiod_client_read_all(client, desc, buf, read_len);
325 		if (ret < 0)
326 			return ret;
327 
328 		to_discard -= (size_t) ret;
329 	} while (to_discard);
330 
331 	return 0;
332 }
333 
iiod_client_read_attr(struct iiod_client * client,void * desc,const struct iio_device * dev,const struct iio_channel * chn,const char * attr,char * dest,size_t len,enum iio_attr_type type)334 ssize_t iiod_client_read_attr(struct iiod_client *client, void *desc,
335 		const struct iio_device *dev, const struct iio_channel *chn,
336 		const char *attr, char *dest, size_t len, enum iio_attr_type type)
337 {
338 	const char *id = iio_device_get_id(dev);
339 	char buf[1024];
340 	ssize_t ret;
341 
342 	if (attr) {
343 		if (chn) {
344 			if (!iio_channel_find_attr(chn, attr))
345 				return -ENOENT;
346 		} else {
347 			switch (type) {
348 				case IIO_ATTR_TYPE_DEVICE:
349 					if (!iio_device_find_attr(dev, attr))
350 						return -ENOENT;
351 					break;
352 				case IIO_ATTR_TYPE_DEBUG:
353 					if (!iio_device_find_debug_attr(dev, attr))
354 						return -ENOENT;
355 					break;
356 				case IIO_ATTR_TYPE_BUFFER:
357 					if (!iio_device_find_buffer_attr(dev, attr))
358 						return -ENOENT;
359 					break;
360 				default:
361 					return -EINVAL;
362 			}
363 		}
364 	}
365 
366 	if (chn) {
367 		iio_snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id,
368 				iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
369 				iio_channel_get_id(chn), attr ? attr : "");
370 	} else {
371 		switch (type) {
372 			case IIO_ATTR_TYPE_DEVICE:
373 				iio_snprintf(buf, sizeof(buf), "READ %s %s\r\n",
374 						id, attr ? attr : "");
375 				break;
376 			case IIO_ATTR_TYPE_DEBUG:
377 				iio_snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n",
378 						id, attr ? attr : "");
379 				break;
380 			case IIO_ATTR_TYPE_BUFFER:
381 				iio_snprintf(buf, sizeof(buf), "READ %s BUFFER %s\r\n",
382 						id, attr ? attr : "");
383 				break;
384 		}
385 	}
386 
387 	iio_mutex_lock(client->lock);
388 
389 	ret = (ssize_t) iiod_client_exec_command(client, desc, buf);
390 	if (ret < 0)
391 		goto out_unlock;
392 
393 	if ((size_t) ret + 1 > len) {
394 		iiod_client_discard(client, desc, dest, len, ret + 1);
395 		ret = -EIO;
396 		goto out_unlock;
397 	}
398 
399 	/* +1: Also read the trailing \n */
400 	ret = iiod_client_read_all(client, desc, dest, ret + 1);
401 
402 	if (ret > 0) {
403 		/* Discard the trailing \n */
404 		ret--;
405 
406 		/* Replace it with a \0 just in case */
407 		dest[ret] = '\0';
408 	}
409 
410 out_unlock:
411 	iio_mutex_unlock(client->lock);
412 	return ret;
413 }
414 
iiod_client_write_attr(struct iiod_client * client,void * desc,const struct iio_device * dev,const struct iio_channel * chn,const char * attr,const char * src,size_t len,enum iio_attr_type type)415 ssize_t iiod_client_write_attr(struct iiod_client *client, void *desc,
416 		const struct iio_device *dev, const struct iio_channel *chn,
417 		const char *attr, const char *src, size_t len, enum iio_attr_type type)
418 {
419 	struct iio_context_pdata *pdata = client->pdata;
420 	const struct iiod_client_ops *ops = client->ops;
421 	const char *id = iio_device_get_id(dev);
422 	char buf[1024];
423 	ssize_t ret;
424 	int resp;
425 
426 	if (attr) {
427 		if (chn) {
428 			if (!iio_channel_find_attr(chn, attr))
429 				return -ENOENT;
430 		} else {
431 			switch (type) {
432 				case IIO_ATTR_TYPE_DEVICE:
433 					if (!iio_device_find_attr(dev, attr))
434 						return -ENOENT;
435 					break;
436 				case IIO_ATTR_TYPE_DEBUG:
437 					if (!iio_device_find_debug_attr(dev, attr))
438 						return -ENOENT;
439 					break;
440 				case IIO_ATTR_TYPE_BUFFER:
441 					if (!iio_device_find_buffer_attr(dev, attr))
442 						return -ENOENT;
443 					break;
444 				default:
445 					return -EINVAL;
446 			}
447 		}
448 	}
449 
450 	if (chn) {
451 		iio_snprintf(buf, sizeof(buf), "WRITE %s %s %s %s %lu\r\n", id,
452 				iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
453 				iio_channel_get_id(chn), attr ? attr : "",
454 				(unsigned long) len);
455 	} else {
456 		switch (type) {
457 			case IIO_ATTR_TYPE_DEVICE:
458 				iio_snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n",
459 						id, attr ? attr : "", (unsigned long) len);
460 				break;
461 			case IIO_ATTR_TYPE_DEBUG:
462 				iio_snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n",
463 						id, attr ? attr : "", (unsigned long) len);
464 				break;
465 			case IIO_ATTR_TYPE_BUFFER:
466 				iio_snprintf(buf, sizeof(buf), "WRITE %s BUFFER %s %lu\r\n",
467 						id, attr ? attr : "", (unsigned long) len);
468 				break;
469 		}
470 	}
471 
472 	iio_mutex_lock(client->lock);
473 	ret = ops->write(pdata, desc, buf, strlen(buf));
474 	if (ret < 0)
475 		goto out_unlock;
476 
477 	ret = iiod_client_write_all(client, desc, src, len);
478 	if (ret < 0)
479 		goto out_unlock;
480 
481 	ret = iiod_client_read_integer(client, desc, &resp);
482 	if (ret < 0)
483 		goto out_unlock;
484 
485 	ret = (ssize_t) resp;
486 
487 out_unlock:
488 	iio_mutex_unlock(client->lock);
489 	return ret;
490 }
491 
iiod_client_create_context(struct iiod_client * client,void * desc)492 struct iio_context * iiod_client_create_context(
493 		struct iiod_client *client, void *desc)
494 {
495 	struct iio_context *ctx = NULL;
496 	size_t xml_len;
497 	char *xml;
498 	int ret;
499 
500 	iio_mutex_lock(client->lock);
501 	ret = iiod_client_exec_command(client, desc, "PRINT\r\n");
502 	if (ret < 0)
503 		goto out_unlock;
504 
505 	xml_len = (size_t) ret;
506 	xml = malloc(xml_len + 1);
507 	if (!xml) {
508 		ret = -ENOMEM;
509 		goto out_unlock;
510 	}
511 
512 	/* +1: Also read the trailing \n */
513 	ret = (int) iiod_client_read_all(client, desc, xml, xml_len + 1);
514 	if (ret < 0)
515 		goto out_free_xml;
516 
517 	ctx = iio_create_xml_context_mem(xml, xml_len);
518 	if (!ctx)
519 		ret = -errno;
520 
521 out_free_xml:
522 	free(xml);
523 out_unlock:
524 	iio_mutex_unlock(client->lock);
525 	if (!ctx)
526 		errno = -ret;
527 	return ctx;
528 }
529 
iiod_client_open_unlocked(struct iiod_client * client,void * desc,const struct iio_device * dev,size_t samples_count,bool cyclic)530 int iiod_client_open_unlocked(struct iiod_client *client, void *desc,
531 		const struct iio_device *dev, size_t samples_count, bool cyclic)
532 {
533 	char buf[1024], *ptr;
534 	size_t i;
535 
536 	iio_snprintf(buf, sizeof(buf), "OPEN %s %lu ",
537 			iio_device_get_id(dev), (unsigned long) samples_count);
538 	ptr = buf + strlen(buf);
539 
540 	for (i = dev->words; i > 0; i--, ptr += 8) {
541 		iio_snprintf(ptr, (ptr - buf) + i * 8, "%08" PRIx32,
542 				dev->mask[i - 1]);
543 	}
544 
545 	strcpy(ptr, cyclic ? " CYCLIC\r\n" : "\r\n");
546 
547 	return iiod_client_exec_command(client, desc, buf);
548 }
549 
iiod_client_close_unlocked(struct iiod_client * client,void * desc,const struct iio_device * dev)550 int iiod_client_close_unlocked(struct iiod_client *client, void *desc,
551 		const struct iio_device *dev)
552 {
553 	char buf[1024];
554 
555 	iio_snprintf(buf, sizeof(buf), "CLOSE %s\r\n", iio_device_get_id(dev));
556 	return iiod_client_exec_command(client, desc, buf);
557 }
558 
iiod_client_read_mask(struct iiod_client * client,void * desc,uint32_t * mask,size_t words)559 static int iiod_client_read_mask(struct iiod_client *client,
560 		void *desc, uint32_t *mask, size_t words)
561 {
562 	size_t i;
563 	ssize_t ret;
564 	char *buf, *ptr;
565 
566 	buf = malloc(words * 8 + 1);
567 	if (!buf)
568 		return -ENOMEM;
569 
570 	ret = iiod_client_read_all(client, desc, buf, words * 8 + 1);
571 	if (ret < 0)
572 		goto out_buf_free;
573 	else
574 		ret = 0;
575 
576 	buf[words*8] = '\0';
577 
578 	DEBUG("Reading mask\n");
579 
580 	for (i = words, ptr = buf; i > 0; i--) {
581 		sscanf(ptr, "%08" PRIx32, &mask[i - 1]);
582 		DEBUG("mask[%lu] = 0x%08" PRIx32 "\n",
583 				(unsigned long)(i - 1), mask[i - 1]);
584 
585 		ptr = (char *) ((uintptr_t) ptr + 8);
586 	}
587 
588 out_buf_free:
589 	free(buf);
590 	return (int) ret;
591 }
592 
iiod_client_read_unlocked(struct iiod_client * client,void * desc,const struct iio_device * dev,void * dst,size_t len,uint32_t * mask,size_t words)593 ssize_t iiod_client_read_unlocked(struct iiod_client *client, void *desc,
594 		const struct iio_device *dev, void *dst, size_t len,
595 		uint32_t *mask, size_t words)
596 {
597 	unsigned int nb_channels = iio_device_get_channels_count(dev);
598 	uintptr_t ptr = (uintptr_t) dst;
599 	char buf[1024];
600 	ssize_t ret, read = 0;
601 
602 	if (!len || words != (nb_channels + 31) / 32)
603 		return -EINVAL;
604 
605 	iio_snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
606 			iio_device_get_id(dev), (unsigned long) len);
607 
608 	ret = iiod_client_write_all(client, desc, buf, strlen(buf));
609 	if (ret < 0)
610 		return ret;
611 
612 	do {
613 		int to_read;
614 
615 		ret = iiod_client_read_integer(client, desc, &to_read);
616 		if (ret < 0)
617 			return ret;
618 		if (to_read < 0)
619 			return (ssize_t) to_read;
620 		if (!to_read)
621 			break;
622 
623 		if (mask) {
624 			ret = iiod_client_read_mask(client, desc, mask, words);
625 			if (ret < 0)
626 				return ret;
627 
628 			mask = NULL; /* We read the mask only once */
629 		}
630 
631 		ret = iiod_client_read_all(client, desc, (char *) ptr, to_read);
632 		if (ret < 0)
633 			return ret;
634 
635 		ptr += ret;
636 		read += ret;
637 		len -= ret;
638 	} while (len);
639 
640 	return read;
641 }
642 
iiod_client_write_unlocked(struct iiod_client * client,void * desc,const struct iio_device * dev,const void * src,size_t len)643 ssize_t iiod_client_write_unlocked(struct iiod_client *client, void *desc,
644 		const struct iio_device *dev, const void *src, size_t len)
645 {
646 	ssize_t ret;
647 	char buf[1024];
648 	int val;
649 
650 	iio_snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
651 			dev->id, (unsigned long) len);
652 
653 	ret = iiod_client_write_all(client, desc, buf, strlen(buf));
654 	if (ret < 0)
655 		return ret;
656 
657 	ret = iiod_client_read_integer(client, desc, &val);
658 	if (ret < 0)
659 		return ret;
660 	if (val < 0)
661 		return (ssize_t) val;
662 
663 	ret = iiod_client_write_all(client, desc, src, len);
664 	if (ret < 0)
665 		return ret;
666 
667 	ret = iiod_client_read_integer(client, desc, &val);
668 	if (ret < 0)
669 		return ret;
670 	if (val < 0)
671 		return (ssize_t) val;
672 
673 	return (ssize_t) len;
674 }
675