• 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 "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