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 "iio-private.h"
21 #include "iio-lock.h"
22 #include "iiod-client.h"
23
24 #include <errno.h>
25 #include <libserialport.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #define DEFAULT_TIMEOUT_MS 1000
31
32 struct iio_context_pdata {
33 struct sp_port *port;
34 struct iio_mutex *lock;
35 struct iiod_client *iiod_client;
36
37 unsigned int timeout_ms;
38 };
39
40 struct iio_device_pdata {
41 bool opened;
42 };
43
libserialport_to_errno(enum sp_return ret)44 static inline int libserialport_to_errno(enum sp_return ret)
45 {
46 switch (ret) {
47 case SP_ERR_ARG:
48 return -EINVAL;
49 case SP_ERR_FAIL:
50 return -sp_last_error_code();
51 case SP_ERR_MEM:
52 return -ENOMEM;
53 case SP_ERR_SUPP:
54 return -ENOSYS;
55 default:
56 return (int) ret;
57 }
58 }
59
serial_get_version(const struct iio_context * ctx,unsigned int * major,unsigned int * minor,char git_tag[8])60 static int serial_get_version(const struct iio_context *ctx,
61 unsigned int *major, unsigned int *minor, char git_tag[8])
62 {
63 struct iio_context_pdata *pdata = ctx->pdata;
64
65 return iiod_client_get_version(pdata->iiod_client, NULL,
66 major, minor, git_tag);
67 }
68
serial_open(const struct iio_device * dev,size_t samples_count,bool cyclic)69 static int serial_open(const struct iio_device *dev,
70 size_t samples_count, bool cyclic)
71 {
72 const struct iio_context *ctx = iio_device_get_context(dev);
73 struct iio_context_pdata *ctx_pdata = ctx->pdata;
74 struct iio_device_pdata *pdata = dev->pdata;
75 int ret = -EBUSY;
76
77 iio_mutex_lock(ctx_pdata->lock);
78 if (pdata->opened)
79 goto out_unlock;
80
81 ret = iiod_client_open_unlocked(ctx_pdata->iiod_client, NULL,
82 dev, samples_count, cyclic);
83
84 pdata->opened = !ret;
85
86 out_unlock:
87 iio_mutex_unlock(ctx_pdata->lock);
88 return ret;
89 }
90
serial_close(const struct iio_device * dev)91 static int serial_close(const struct iio_device *dev)
92 {
93 const struct iio_context *ctx = iio_device_get_context(dev);
94 struct iio_context_pdata *ctx_pdata = ctx->pdata;
95 struct iio_device_pdata *pdata = dev->pdata;
96 int ret = -EBADF;
97
98 iio_mutex_lock(ctx_pdata->lock);
99 if (!pdata->opened)
100 goto out_unlock;
101
102 ret = iiod_client_close_unlocked(ctx_pdata->iiod_client, NULL, dev);
103 pdata->opened = false;
104
105 out_unlock:
106 iio_mutex_unlock(ctx_pdata->lock);
107 return ret;
108 }
109
serial_read(const struct iio_device * dev,void * dst,size_t len,uint32_t * mask,size_t words)110 static ssize_t serial_read(const struct iio_device *dev, void *dst, size_t len,
111 uint32_t *mask, size_t words)
112 {
113 const struct iio_context *ctx = iio_device_get_context(dev);
114 struct iio_context_pdata *pdata = ctx->pdata;
115 ssize_t ret;
116
117 iio_mutex_lock(pdata->lock);
118 ret = iiod_client_read_unlocked(pdata->iiod_client, NULL,
119 dev, dst, len, mask, words);
120 iio_mutex_unlock(pdata->lock);
121
122 return ret;
123 }
124
serial_write(const struct iio_device * dev,const void * src,size_t len)125 static ssize_t serial_write(const struct iio_device *dev,
126 const void *src, size_t len)
127 {
128 const struct iio_context *ctx = iio_device_get_context(dev);
129 struct iio_context_pdata *pdata = ctx->pdata;
130 ssize_t ret;
131
132 iio_mutex_lock(pdata->lock);
133 ret = iiod_client_write_unlocked(pdata->iiod_client, NULL, dev, src, len);
134 iio_mutex_unlock(pdata->lock);
135
136 return ret;
137 }
138
serial_read_dev_attr(const struct iio_device * dev,const char * attr,char * dst,size_t len,enum iio_attr_type type)139 static ssize_t serial_read_dev_attr(const struct iio_device *dev,
140 const char *attr, char *dst, size_t len, enum iio_attr_type type)
141 {
142 const struct iio_context *ctx = iio_device_get_context(dev);
143 struct iio_context_pdata *pdata = ctx->pdata;
144
145 return iiod_client_read_attr(pdata->iiod_client, NULL,
146 dev, NULL, attr, dst, len, type);
147 }
148
serial_write_dev_attr(const struct iio_device * dev,const char * attr,const char * src,size_t len,enum iio_attr_type type)149 static ssize_t serial_write_dev_attr(const struct iio_device *dev,
150 const char *attr, const char *src, size_t len, enum iio_attr_type type)
151 {
152 const struct iio_context *ctx = iio_device_get_context(dev);
153 struct iio_context_pdata *pdata = ctx->pdata;
154
155 return iiod_client_write_attr(pdata->iiod_client, NULL,
156 dev, NULL, attr, src, len, type);
157 }
158
serial_read_chn_attr(const struct iio_channel * chn,const char * attr,char * dst,size_t len)159 static ssize_t serial_read_chn_attr(const struct iio_channel *chn,
160 const char *attr, char *dst, size_t len)
161 {
162 const struct iio_device *dev = iio_channel_get_device(chn);
163 const struct iio_context *ctx = iio_device_get_context(dev);
164 struct iio_context_pdata *pdata = ctx->pdata;
165
166 return iiod_client_read_attr(pdata->iiod_client, NULL,
167 chn->dev, chn, attr, dst, len, false);
168 }
169
serial_write_chn_attr(const struct iio_channel * chn,const char * attr,const char * src,size_t len)170 static ssize_t serial_write_chn_attr(const struct iio_channel *chn,
171 const char *attr, const char *src, size_t len)
172 {
173 const struct iio_device *dev = iio_channel_get_device(chn);
174 const struct iio_context *ctx = iio_device_get_context(dev);
175 struct iio_context_pdata *pdata = ctx->pdata;
176
177 return iiod_client_write_attr(pdata->iiod_client, NULL,
178 dev, chn, attr, src, len, false);
179 }
180
serial_set_kernel_buffers_count(const struct iio_device * dev,unsigned int nb_blocks)181 static int serial_set_kernel_buffers_count(const struct iio_device *dev,
182 unsigned int nb_blocks)
183 {
184 const struct iio_context *ctx = iio_device_get_context(dev);
185 struct iio_context_pdata *pdata = ctx->pdata;
186
187 return iiod_client_set_kernel_buffers_count(pdata->iiod_client, NULL,
188 dev, nb_blocks);
189 }
190
serial_write_data(struct iio_context_pdata * pdata,void * io_data,const char * data,size_t len)191 static ssize_t serial_write_data(struct iio_context_pdata *pdata,
192 void *io_data, const char *data, size_t len)
193 {
194 ssize_t ret = (ssize_t) libserialport_to_errno(sp_blocking_write(
195 pdata->port, data, len, pdata->timeout_ms));
196
197 DEBUG("Write returned %li: %s\n", (long) ret, data);
198 return ret;
199 }
200
serial_read_data(struct iio_context_pdata * pdata,void * io_data,char * buf,size_t len)201 static ssize_t serial_read_data(struct iio_context_pdata *pdata,
202 void *io_data, char *buf, size_t len)
203 {
204 ssize_t ret = (ssize_t) libserialport_to_errno(sp_blocking_read_next(
205 pdata->port, buf, len, pdata->timeout_ms));
206
207 DEBUG("Read returned %li: %.*s\n", (long) ret, (int) ret, buf);
208 return ret;
209 }
210
serial_read_line(struct iio_context_pdata * pdata,void * io_data,char * buf,size_t len)211 static ssize_t serial_read_line(struct iio_context_pdata *pdata,
212 void *io_data, char *buf, size_t len)
213 {
214 size_t i;
215 bool found = false;
216 int ret;
217
218 DEBUG("Readline size 0x%lx\n", (unsigned long) len);
219
220 for (i = 0; i < len - 1; i++) {
221 ret = libserialport_to_errno(sp_blocking_read_next(
222 pdata->port, &buf[i], 1,
223 pdata->timeout_ms));
224 if (ret < 0) {
225 ERROR("sp_blocking_read_next returned %i\n", ret);
226 return (ssize_t) ret;
227 }
228
229 DEBUG("Character: %c\n", buf[i]);
230
231 if (buf[i] != '\n')
232 found = true;
233 else if (found)
234 break;
235 }
236
237 /* No \n found? Just garbage data */
238 if (!found || i == len - 1)
239 return -EIO;
240
241 return (ssize_t) i + 1;
242 }
243
serial_shutdown(struct iio_context * ctx)244 static void serial_shutdown(struct iio_context *ctx)
245 {
246 struct iio_context_pdata *ctx_pdata = ctx->pdata;
247 unsigned int i;
248
249 iiod_client_destroy(ctx_pdata->iiod_client);
250 iio_mutex_destroy(ctx_pdata->lock);
251 sp_close(ctx_pdata->port);
252 sp_free_port(ctx_pdata->port);
253
254 for (i = 0; i < iio_context_get_devices_count(ctx); i++) {
255 const struct iio_device *dev = iio_context_get_device(ctx, i);
256 struct iio_device_pdata *pdata = dev->pdata;
257
258 free(pdata);
259 }
260
261 free(ctx_pdata);
262 }
263
serial_set_timeout(struct iio_context * ctx,unsigned int timeout)264 static int serial_set_timeout(struct iio_context *ctx, unsigned int timeout)
265 {
266 ctx->pdata->timeout_ms = timeout;
267 return 0;
268 }
269
270 static const struct iio_backend_ops serial_ops = {
271 .get_version = serial_get_version,
272 .open = serial_open,
273 .close = serial_close,
274 .read = serial_read,
275 .write = serial_write,
276 .read_device_attr = serial_read_dev_attr,
277 .write_device_attr = serial_write_dev_attr,
278 .read_channel_attr = serial_read_chn_attr,
279 .write_channel_attr = serial_write_chn_attr,
280 .set_kernel_buffers_count = serial_set_kernel_buffers_count,
281 .shutdown = serial_shutdown,
282 .set_timeout = serial_set_timeout,
283 };
284
285 static const struct iiod_client_ops serial_iiod_client_ops = {
286 .write = serial_write_data,
287 .read = serial_read_data,
288 .read_line = serial_read_line,
289 };
290
apply_settings(struct sp_port * port,unsigned int baud_rate,unsigned int bits,unsigned int stop_bits,enum sp_parity parity,enum sp_flowcontrol flow)291 static int apply_settings(struct sp_port *port, unsigned int baud_rate,
292 unsigned int bits, unsigned int stop_bits,
293 enum sp_parity parity, enum sp_flowcontrol flow)
294 {
295 int ret;
296
297 ret = libserialport_to_errno(sp_set_baudrate(port, (int) baud_rate));
298 if (ret)
299 return ret;
300
301 ret = libserialport_to_errno(sp_set_bits(port, (int) bits));
302 if (ret)
303 return ret;
304
305 ret = libserialport_to_errno(sp_set_stopbits(port, (int) stop_bits));
306 if (ret)
307 return ret;
308
309 ret = libserialport_to_errno(sp_set_parity(port, parity));
310 if (ret)
311 return ret;
312
313 return libserialport_to_errno(sp_set_flowcontrol(port, flow));
314 }
315
serial_create_context(const char * port_name,unsigned int baud_rate,unsigned int bits,enum sp_parity parity,enum sp_flowcontrol flow)316 static struct iio_context * serial_create_context(const char *port_name,
317 unsigned int baud_rate, unsigned int bits,
318 enum sp_parity parity, enum sp_flowcontrol flow)
319 {
320 struct sp_port *port;
321 struct iio_context_pdata *pdata;
322 struct iio_context *ctx;
323 char *name, *desc, *description;
324 size_t desc_len;
325 unsigned int i;
326 int ret;
327
328 ret = libserialport_to_errno(sp_get_port_by_name(port_name, &port));
329 if (ret) {
330 errno = -ret;
331 return NULL;
332 }
333
334 ret = libserialport_to_errno(sp_open(port, SP_MODE_READ_WRITE));
335 if (ret) {
336 errno = -ret;
337 goto err_free_port;
338 }
339
340 ret = apply_settings(port, baud_rate, bits, 1, parity, flow);
341 if (ret) {
342 errno = -ret;
343 goto err_close_port;
344 }
345
346 /* Empty the buffers */
347 sp_flush(port, SP_BUF_BOTH);
348
349 name = sp_get_port_name(port);
350 desc = sp_get_port_description(port);
351
352 desc_len = sizeof(": \0") + strlen(name) + strlen(desc);
353 description = malloc(desc_len);
354 if (!description) {
355 errno = ENOMEM;
356 goto err_close_port;
357 }
358
359 iio_snprintf(description, desc_len, "%s: %s", name, desc);
360
361 pdata = zalloc(sizeof(*pdata));
362 if (!pdata) {
363 errno = ENOMEM;
364 goto err_free_description;
365 }
366
367 pdata->port = port;
368 pdata->timeout_ms = DEFAULT_TIMEOUT_MS;
369
370 pdata->lock = iio_mutex_create();
371 if (!pdata->lock) {
372 errno = ENOMEM;
373 goto err_free_pdata;
374 }
375
376 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
377 &serial_iiod_client_ops);
378 if (!pdata->iiod_client)
379 goto err_destroy_mutex;
380
381 ctx = iiod_client_create_context(pdata->iiod_client, NULL);
382 if (!ctx)
383 goto err_destroy_iiod_client;
384
385 ctx->name = "serial";
386 ctx->ops = &serial_ops;
387 ctx->pdata = pdata;
388 ctx->description = description;
389
390 for (i = 0; i < iio_context_get_devices_count(ctx); i++) {
391 struct iio_device *dev = iio_context_get_device(ctx, i);
392
393 dev->pdata = zalloc(sizeof(*dev->pdata));
394 if (!dev->pdata) {
395 ret = -ENOMEM;
396 goto err_context_destroy;
397 }
398 }
399
400 return ctx;
401
402 err_context_destroy:
403 iio_context_destroy(ctx);
404 errno = -ret;
405 return NULL;
406
407 err_destroy_iiod_client:
408 iiod_client_destroy(pdata->iiod_client);
409 err_destroy_mutex:
410 iio_mutex_destroy(pdata->lock);
411 err_free_pdata:
412 free(pdata);
413 err_free_description:
414 free(description);
415 err_close_port:
416 sp_close(port);
417 err_free_port:
418 sp_free_port(port);
419 return NULL;
420 }
421
serial_parse_params(const char * params,unsigned int * baud_rate,unsigned int * bits,enum sp_parity * parity,enum sp_flowcontrol * flow)422 static int serial_parse_params(const char *params,
423 unsigned int *baud_rate, unsigned int *bits,
424 enum sp_parity *parity, enum sp_flowcontrol *flow)
425 {
426 char *end;
427
428 *baud_rate = strtoul(params, &end, 10);
429 if (params == end)
430 return -EINVAL;
431
432 switch (*end) {
433 case '\0':
434 /* Default settings */
435 *bits = 8;
436 *parity = SP_PARITY_NONE;
437 *flow = SP_FLOWCONTROL_NONE;
438 return 0;
439 case 'n':
440 *parity = SP_PARITY_NONE;
441 break;
442 case 'o':
443 *parity = SP_PARITY_ODD;
444 break;
445 case 'e':
446 *parity = SP_PARITY_EVEN;
447 break;
448 case 'm':
449 *parity = SP_PARITY_MARK;
450 break;
451 case 's':
452 *parity = SP_PARITY_SPACE;
453 break;
454 default:
455 return -EINVAL;
456 }
457
458 params = (const char *)((uintptr_t) end + 1);
459
460 if (!*params) {
461 *bits = 8;
462 *flow = SP_FLOWCONTROL_NONE;
463 return 0;
464 }
465
466 *bits = strtoul(params, &end, 10);
467 if (params == end)
468 return -EINVAL;
469
470 switch (*end) {
471 case '\0':
472 *flow = SP_FLOWCONTROL_NONE;
473 return 0;
474 case 'x':
475 *flow = SP_FLOWCONTROL_XONXOFF;
476 break;
477 case 'r':
478 *flow = SP_FLOWCONTROL_RTSCTS;
479 break;
480 case 'd':
481 *flow = SP_FLOWCONTROL_DTRDSR;
482 break;
483 default:
484 return -EINVAL;
485 }
486
487 /* We should have a '\0' after the flow character */
488 if (end[1])
489 return -EINVAL;
490 else
491 return 0;
492 }
493
serial_create_context_from_uri(const char * uri)494 struct iio_context * serial_create_context_from_uri(const char *uri)
495 {
496 struct iio_context *ctx = NULL;
497 char *comma, *uri_dup;
498 unsigned int baud_rate, bits;
499 enum sp_parity parity;
500 enum sp_flowcontrol flow;
501 int ret;
502
503 if (strncmp(uri, "serial:", sizeof("serial:") - 1) != 0)
504 goto err_bad_uri;
505
506 uri_dup = iio_strdup((const char *)
507 ((uintptr_t) uri + sizeof("serial:") - 1));
508 if (!uri_dup) {
509 errno = ENOMEM;
510 return NULL;
511 }
512
513 comma = strchr(uri_dup, ',');
514 if (!comma)
515 goto err_free_dup;
516
517 *comma = '\0';
518
519 ret = serial_parse_params((char *)((uintptr_t) comma + 1),
520 &baud_rate, &bits, &parity, &flow);
521 if (ret)
522 goto err_free_dup;
523
524 ctx = serial_create_context(uri_dup, baud_rate, bits, parity, flow);
525
526 free(uri_dup);
527 return ctx;
528
529 err_free_dup:
530 free(uri_dup);
531 err_bad_uri:
532 ERROR("Bad URI: \'%s\'\n", uri);
533 errno = EINVAL;
534 return NULL;
535 }
536