blob: b644b318cc365c0d4eb504281a42498e0cf13e69 [file] [log] [blame]
Paul Cercueil1f75a8f2015-12-02 11:51:14 +01001#include "debug.h"
Paul Cercueil2cb884a2015-11-30 15:01:25 +01002#include "iiod-client.h"
3#include "iio-lock.h"
Paul Cercueilba870932015-12-01 18:17:57 +01004#include "iio-private.h"
Paul Cercueil2cb884a2015-11-30 15:01:25 +01005
6#include <errno.h>
7#include <string.h>
Paul Cercueil6a785882015-11-30 16:36:19 +01008#include <stdio.h>
Paul Cercueil2cb884a2015-11-30 15:01:25 +01009
10struct iiod_client {
11 struct iio_context_pdata *pdata;
12 const struct iiod_client_ops *ops;
13 struct iio_mutex *lock;
14};
15
Paul Cercueil6a785882015-11-30 16:36:19 +010016static ssize_t iiod_client_read_integer(struct iiod_client *client,
17 int desc, int *val)
18{
19 const struct iiod_client_ops *ops = client->ops;
20 unsigned int i;
21 char buf[1024], *ptr = NULL, *end;
22 ssize_t ret;
23 int value;
24
25 do {
26 ret = client->ops->read_line(client->pdata,
27 desc, buf, sizeof(buf));
28 if (ret < 0)
29 return ret;
30
31 for (i = 0; i < (unsigned int) ret; i++) {
32 if (buf[i] != '\n') {
33 if (!ptr)
34 ptr = &buf[i];
35 } else if (!!ptr) {
36 break;
37 }
38 }
39 } while (!ptr);
40
41 buf[i] = '\0';
42
43 value = (int) strtol(ptr, &end, 10);
44 if (ptr == end)
45 return -EINVAL;
46
47 *val = value;
48 return 0;
49}
50
51static int iiod_client_exec_command(struct iiod_client *client,
52 int desc, const char *cmd)
53{
54 int resp;
55 ssize_t ret;
56
57 ret = client->ops->write(client->pdata, desc, cmd, strlen(cmd));
58 if (ret < 0)
59 return (int) ret;
60
61 ret = iiod_client_read_integer(client, desc, &resp);
62 return ret < 0 ? (int) ret : resp;
63}
64
Paul Cercueil408b9672015-11-30 18:39:31 +010065static ssize_t iiod_client_write_all(struct iiod_client *client,
66 int desc, const void *src, size_t len)
67{
68 struct iio_context_pdata *pdata = client->pdata;
69 const struct iiod_client_ops *ops = client->ops;
70 uintptr_t ptr = (uintptr_t) src;
71
72 while (len) {
73 ssize_t ret = ops->write(pdata, desc, (const void *) ptr, len);
74
75 if (ret < 0) {
76 if (ret == -EINTR)
77 continue;
78 else
79 return ret;
80 }
81
82 if (ret == 0)
83 return -EPIPE;
84
85 ptr += ret;
86 len -= ret;
87 }
88
89 return (ssize_t) (ptr - (uintptr_t) src);
90}
91
92static ssize_t iiod_client_read_all(struct iiod_client *client,
93 int desc, void *dst, size_t len)
94{
95 struct iio_context_pdata *pdata = client->pdata;
96 const struct iiod_client_ops *ops = client->ops;
97 uintptr_t ptr = (uintptr_t) dst;
98
99 while (len) {
100 ssize_t ret = ops->read(pdata, desc, (void *) ptr, len);
101
102 if (ret < 0) {
103 if (ret == -EINTR)
104 continue;
105 else
106 return ret;
107 }
108
109 if (ret == 0)
110 return -EPIPE;
111
112 ptr += ret;
113 len -= ret;
114 }
115
116 return (ssize_t) (ptr - (uintptr_t) dst);
117}
118
Paul Cercueil2cb884a2015-11-30 15:01:25 +0100119struct iiod_client * iiod_client_new(struct iio_context_pdata *pdata,
120 struct iio_mutex *lock, const struct iiod_client_ops *ops)
121{
122 struct iiod_client *client;
123
124 client = malloc(sizeof(*client));
125 if (!client) {
126 errno = ENOMEM;
127 return NULL;
128 }
129
130 client->lock = lock;
131 client->pdata = pdata;
132 client->ops = ops;
133 return client;
134}
135
136void iiod_client_destroy(struct iiod_client *client)
137{
138 free(client);
139}
140
141int iiod_client_get_version(struct iiod_client *client, int desc,
142 unsigned int *major, unsigned int *minor, char *git_tag)
143{
144 struct iio_context_pdata *pdata = client->pdata;
145 const struct iiod_client_ops *ops = client->ops;
146 char buf[256], *ptr = buf, *end;
147 long maj, min;
148 int ret;
149
150 iio_mutex_lock(client->lock);
151
152 ret = ops->write(pdata, desc, "VERSION\r\n", sizeof("VERSION\r\n") - 1);
153 if (ret < 0) {
154 iio_mutex_unlock(client->lock);
155 return ret;
156 }
157
158 ret = ops->read(pdata, desc, buf, sizeof(buf));
159 iio_mutex_unlock(client->lock);
160
161 if (ret < 0)
162 return ret;
163
164 maj = strtol(ptr, &end, 10);
165 if (ptr == end)
166 return -EIO;
167
168 ptr = end + 1;
169 min = strtol(ptr, &end, 10);
170 if (ptr == end)
171 return -EIO;
172
173 ptr = end + 1;
174 if (buf + ret < ptr + 8)
175 return -EIO;
176
177 /* Strip the \n */
178 ptr[buf + ret - ptr - 1] = '\0';
179
180 if (major)
181 *major = (unsigned int) maj;
182 if (minor)
183 *minor = (unsigned int) min;
184 if (git_tag)
185 strncpy(git_tag, ptr, 8);
186 return 0;
187}
Paul Cercueil6a785882015-11-30 16:36:19 +0100188
189int iiod_client_get_trigger(struct iiod_client *client, int desc,
190 const struct iio_device *dev, const struct iio_device **trigger)
191{
192 struct iio_context_pdata *pdata = client->pdata;
193 const struct iio_context *ctx = iio_device_get_context(dev);
194 unsigned int i, nb_devices = iio_context_get_devices_count(ctx);
195 char buf[1024];
196 unsigned int name_len;
197 int ret;
198
199 snprintf(buf, sizeof(buf), "GETTRIG %s\r\n", iio_device_get_id(dev));
200
201 iio_mutex_lock(client->lock);
202 ret = iiod_client_exec_command(client, desc, buf);
203
204 if (ret == 0)
205 *trigger = NULL;
206 if (ret <= 0)
207 goto out_unlock;
208
209 if ((unsigned int) ret > sizeof(buf)) {
210 ret = -EIO;
211 goto out_unlock;
212 }
213
214 name_len = ret;
215
216 ret = (int) client->ops->read(pdata, desc, buf, name_len);
217 if (ret < 0)
218 goto out_unlock;
219
220 ret = -ENXIO;
221
222 for (i = 0; i < nb_devices; i++) {
223 struct iio_device *cur = iio_context_get_device(ctx, i);
224
225 if (iio_device_is_trigger(cur)) {
226 const char *name = iio_device_get_name(cur);
227
228 if (!name)
229 continue;
230
231 if (!strncmp(name, buf, name_len)) {
232 *trigger = cur;
233 return 0;
234 }
235 }
236 }
237
238out_unlock:
239 iio_mutex_unlock(client->lock);
240 return ret;
241}
242
243int iiod_client_set_trigger(struct iiod_client *client, int desc,
244 const struct iio_device *dev, const struct iio_device *trigger)
245{
246 const struct iiod_client_ops *ops = client->ops;
247 char buf[1024];
248 int ret;
249
250 if (trigger)
251 snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
252 iio_device_get_id(dev),
253 iio_device_get_id(trigger));
254 else
255 snprintf(buf, sizeof(buf), "SETTRIG %s\r\n",
256 iio_device_get_id(dev));
257
258 iio_mutex_lock(client->lock);
259 ret = iiod_client_exec_command(client, desc, buf);
260 iio_mutex_unlock(client->lock);
261 return ret;
262}
Paul Cercueile7d4db32015-11-30 16:54:51 +0100263
264int iiod_client_set_kernel_buffers_count(struct iiod_client *client, int desc,
265 const struct iio_device *dev, unsigned int nb_blocks)
266{
267 int ret;
268 char buf[1024];
269
270 snprintf(buf, sizeof(buf), "SET %s BUFFERS_COUNT %u\r\n",
271 iio_device_get_id(dev), nb_blocks);
272
273 iio_mutex_lock(client->lock);
274 ret = iiod_client_exec_command(client, desc, buf);
275 iio_mutex_unlock(client->lock);
276 return ret;
277}
Paul Cercueil408b9672015-11-30 18:39:31 +0100278
Paul Cercueil3ce60382015-12-03 12:28:48 +0100279int iiod_client_set_timeout(struct iiod_client *client,
280 int desc, unsigned int timeout)
281{
282 int ret;
283 char buf[1024];
284
285 snprintf(buf, sizeof(buf), "TIMEOUT %u\r\n", timeout);
286
287 iio_mutex_lock(client->lock);
288 ret = iiod_client_exec_command(client, desc, buf);
289 iio_mutex_unlock(client->lock);
290 return ret;
291}
292
Paul Cercueil408b9672015-11-30 18:39:31 +0100293ssize_t iiod_client_read_attr(struct iiod_client *client, int desc,
294 const struct iio_device *dev, const struct iio_channel *chn,
295 const char *attr, char *dest, size_t len, bool is_debug)
296{
297 struct iio_context_pdata *pdata = client->pdata;
298 const struct iiod_client_ops *ops = client->ops;
299 const char *id = iio_device_get_id(dev);
300 char buf[1024];
Paul Cercueil58bcbd42015-12-11 11:35:55 +0100301 ssize_t ret;
Paul Cercueil408b9672015-11-30 18:39:31 +0100302
303 if (attr) {
304 if (chn) {
305 if (!iio_channel_find_attr(chn, attr))
306 return -ENOENT;
307 } else if (is_debug) {
308 if (!iio_device_find_debug_attr(dev, attr))
309 return -ENOENT;
310 } else {
311 if (!iio_device_find_attr(dev, attr))
312 return -ENOENT;
313 }
314 }
315
316 if (chn)
317 snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id,
318 iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
319 iio_channel_get_id(chn), attr ? attr : "");
320 else if (is_debug)
321 snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n",
322 id, attr ? attr : "");
323 else
324 snprintf(buf, sizeof(buf), "READ %s %s\r\n",
325 id, attr ? attr : "");
326
327 iio_mutex_lock(client->lock);
328
329 ret = (ssize_t) iiod_client_exec_command(client, desc, buf);
330 if (ret < 0)
331 goto out_unlock;
332
333 if ((size_t) ret + 1 > len) {
334 ret = -EIO;
335 goto out_unlock;
336 }
337
338 /* +1: Also read the trailing \n */
339 ret = iiod_client_read_all(client, desc, dest, ret + 1);
340
Paul Cercueil08bb36b2015-12-18 10:51:13 +0100341 if (ret > 0) {
342 /* Discard the trailing \n */
343 ret--;
344
345 /* Replace it with a \0 just in case */
346 dest[ret] = '\0';
347 }
348
Paul Cercueil408b9672015-11-30 18:39:31 +0100349out_unlock:
350 iio_mutex_unlock(client->lock);
351 return ret;
352}
353
354ssize_t iiod_client_write_attr(struct iiod_client *client, int desc,
355 const struct iio_device *dev, const struct iio_channel *chn,
356 const char *attr, const char *src, size_t len, bool is_debug)
357{
358 struct iio_context_pdata *pdata = client->pdata;
359 const struct iiod_client_ops *ops = client->ops;
360 const char *id = iio_device_get_id(dev);
361 char buf[1024];
Paul Cercueil58bcbd42015-12-11 11:35:55 +0100362 ssize_t ret;
Paul Cercueil408b9672015-11-30 18:39:31 +0100363 int resp;
364
365 if (attr) {
366 if (chn) {
367 if (!iio_channel_find_attr(chn, attr))
368 return -ENOENT;
369 } else if (is_debug) {
370 if (!iio_device_find_debug_attr(dev, attr))
371 return -ENOENT;
372 } else {
373 if (!iio_device_find_attr(dev, attr))
374 return -ENOENT;
375 }
376 }
377
378 if (chn)
379 snprintf(buf, sizeof(buf), "WRITE %s %s %s %s %lu\r\n", id,
380 iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
381 iio_channel_get_id(chn), attr ? attr : "",
382 (unsigned long) len);
383 else if (is_debug)
384 snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n",
385 id, attr ? attr : "", (unsigned long) len);
386 else
387 snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n",
388 id, attr ? attr : "", (unsigned long) len);
389
390 iio_mutex_lock(client->lock);
391 ret = ops->write(pdata, desc, buf, strlen(buf));
392 if (ret < 0)
393 goto out_unlock;
394
395 ret = iiod_client_write_all(client, desc, src, len);
396 if (ret < 0)
397 goto out_unlock;
398
399 ret = iiod_client_read_integer(client, desc, &resp);
400 if (ret < 0)
401 goto out_unlock;
402
403 ret = (ssize_t) resp;
404
405out_unlock:
406 iio_mutex_unlock(client->lock);
407 return ret;
408}
Paul Cercueil8fd10d22015-12-01 11:15:36 +0100409
410struct iio_context * iiod_client_create_context(
411 struct iiod_client *client, int desc)
412{
413 struct iio_context *ctx = NULL;
414 size_t xml_len;
415 char *xml, c;
416 int ret;
417
418 iio_mutex_lock(client->lock);
419 ret = iiod_client_exec_command(client, desc, "PRINT\r\n");
420 if (ret < 0)
421 goto out_unlock;
422
423 xml_len = (size_t) ret;
424 xml = malloc(xml_len);
425 if (!xml) {
426 ret = -ENOMEM;
427 goto out_unlock;
428 }
429
430 ret = (int) iiod_client_read_all(client, desc, xml, xml_len);
431 if (ret < 0)
432 goto out_free_xml;
433
434 /* Discard \n character */
435 client->ops->read(client->pdata, desc, &c, 1);
436
437 ctx = iio_create_xml_context_mem(xml, xml_len);
438 if (!ctx)
439 ret = -errno;
440
441out_free_xml:
442 free(xml);
443out_unlock:
444 iio_mutex_unlock(client->lock);
445 if (!ctx)
446 errno = -ret;
447 return ctx;
448}
Paul Cercueilba870932015-12-01 18:17:57 +0100449
450int iiod_client_open_unlocked(struct iiod_client *client, int desc,
451 const struct iio_device *dev, size_t samples_count, bool cyclic)
452{
453 char buf[1024], *ptr;
454 size_t i;
455
456 snprintf(buf, sizeof(buf), "OPEN %s %lu ",
457 iio_device_get_id(dev), (unsigned long) samples_count);
458 ptr = buf + strlen(buf);
459
460 for (i = dev->words; i > 0; i--, ptr += 8)
461 snprintf(ptr, (ptr - buf) + i * 8, "%08x", dev->mask[i - 1]);
462
463 strcpy(ptr, cyclic ? " CYCLIC\r\n" : "\r\n");
464
465 return iiod_client_exec_command(client, desc, buf);
466}
467
468int iiod_client_close_unlocked(struct iiod_client *client, int desc,
469 const struct iio_device *dev)
470{
471 char buf[1024];
472
473 snprintf(buf, sizeof(buf), "CLOSE %s\r\n", iio_device_get_id(dev));
474 return iiod_client_exec_command(client, desc, buf);
475}
Paul Cercueil1f75a8f2015-12-02 11:51:14 +0100476
477static int iiod_client_read_mask(struct iiod_client *client,
478 int desc, uint32_t *mask, size_t words)
479{
480 size_t i;
481 ssize_t ret;
482 char *buf, *ptr;
483
484 buf = malloc(words * 8 + 1);
485 if (!buf)
486 return -ENOMEM;
487
488 ret = iiod_client_read_all(client, desc, buf, words * 8 + 1);
489 if (ret < 0)
490 goto out_buf_free;
491 else
492 ret = 0;
493
494 DEBUG("Reading mask\n");
495
496 for (i = words, ptr = buf; i > 0; i--) {
497 sscanf(ptr, "%08x", &mask[i - 1]);
498 DEBUG("mask[%i] = 0x%08x\n", i - 1, mask[i - 1]);
499
500 ptr = (char *) ((uintptr_t) ptr + 8);
501 }
502
503out_buf_free:
504 free(buf);
505 return (int) ret;
506}
507
508ssize_t iiod_client_read_unlocked(struct iiod_client *client, int desc,
509 const struct iio_device *dev, void *dst, size_t len,
510 uint32_t *mask, size_t words)
511{
512 unsigned int nb_channels = iio_device_get_channels_count(dev);
513 uintptr_t ptr = (uintptr_t) dst;
514 struct iio_device_pdata *pdata = dev->pdata;
515 char buf[1024];
516 ssize_t ret, read = 0;
517
518 if (!len || words != (nb_channels + 31) / 32)
519 return -EINVAL;
520
521 snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
522 iio_device_get_id(dev), (unsigned long) len);
523
524 ret = iiod_client_write_all(client, desc, buf, strlen(buf));
525 if (ret < 0)
526 return ret;
527
528 do {
529 int to_read;
530
531 ret = iiod_client_read_integer(client, desc, &to_read);
532 if (ret < 0)
533 return ret;
534 if (!to_read)
535 break;
536
537 if (mask) {
538 ret = iiod_client_read_mask(client, desc, mask, words);
539 if (ret < 0)
540 return ret;
541
542 mask = NULL; /* We read the mask only once */
543 }
544
545 ret = iiod_client_read_all(client, desc, (char *) ptr, to_read);
546 if (ret < 0)
547 return ret;
548
549 ptr += ret;
550 read += ret;
551 len -= ret;
552 } while (len);
553
554 return read;
555}
Paul Cercueil90fd85c2015-12-02 17:57:07 +0100556
557ssize_t iiod_client_write_unlocked(struct iiod_client *client, int desc,
558 const struct iio_device *dev, const void *src, size_t len)
559{
560 struct iio_device_pdata *pdata = dev->pdata;
561 ssize_t ret;
562 char buf[1024];
563 int val;
564
565 snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
566 dev->id, (unsigned long) len);
567
568 ret = iiod_client_write_all(client, desc, buf, strlen(buf));
569 if (ret < 0)
570 return ret;
571
572 ret = iiod_client_read_integer(client, desc, &val);
573 if (ret < 0)
574 return ret;
575 if (val < 0)
576 return (ssize_t) val;
577
578 ret = iiod_client_write_all(client, desc, src, len);
579 if (ret < 0)
580 return ret;
581
582 ret = iiod_client_read_integer(client, desc, &val);
583 if (ret < 0)
584 return ret;
585 if (val < 0)
586 return (ssize_t) val;
587
588 return (ssize_t) len;
589}