]> sigrok.org Git - libsigrok.git/blame_incremental - hardware/common/serial.c
configure.ac: Update NEED_SERIAL list.
[libsigrok.git] / hardware / common / serial.c
... / ...
CommitLineData
1/*
2 * This file is part of the sigrok project.
3 *
4 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
5 * Copyright (C) 2010-2012 Uwe Hermann <uwe@hermann-uwe.de>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <string.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <unistd.h>
26#ifdef _WIN32
27#include <windows.h>
28#else
29#include <glob.h>
30#include <termios.h>
31#endif
32#include <stdlib.h>
33#include <errno.h>
34#include <glib.h>
35#include "libsigrok.h"
36#include "libsigrok-internal.h"
37
38/* Message logging helpers with driver-specific prefix string. */
39#define DRIVER_LOG_DOMAIN "serial: "
40#define sr_log(l, s, args...) sr_log(l, DRIVER_LOG_DOMAIN s, ## args)
41#define sr_spew(s, args...) sr_spew(DRIVER_LOG_DOMAIN s, ## args)
42#define sr_dbg(s, args...) sr_dbg(DRIVER_LOG_DOMAIN s, ## args)
43#define sr_info(s, args...) sr_info(DRIVER_LOG_DOMAIN s, ## args)
44#define sr_warn(s, args...) sr_warn(DRIVER_LOG_DOMAIN s, ## args)
45#define sr_err(s, args...) sr_err(DRIVER_LOG_DOMAIN s, ## args)
46
47// FIXME: Must be moved, or rather passed as function argument.
48#ifdef _WIN32
49static HANDLE hdl;
50#endif
51
52/**
53 * Open the specified serial port.
54 *
55 * @param serial Previously initialized serial port structure.
56 * @param flags Flags to use when opening the serial port.
57 * TODO: Abstract 'flags', currently they're OS-specific!
58 *
59 * If the serial structure contains a serialcomm string, it will be
60 * passed to serial_set_paramstr() after the port is opened.
61 *
62 * @return SR_OK on success, SR_ERR on failure.
63 */
64SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags)
65{
66
67 if (!serial) {
68 sr_dbg("Invalid serial port.");
69 return SR_ERR;
70 }
71
72 sr_spew("Opening serial port '%s' (flags %d).", serial->port, flags);
73
74#ifdef _WIN32
75 hdl = CreateFile(serial->port, GENERIC_READ | GENERIC_WRITE, 0, 0,
76 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
77 if (hdl == INVALID_HANDLE_VALUE) {
78 sr_err("Error opening serial port '%s'.", serial->port);
79 return SR_ERR;
80 }
81#else
82 if ((serial->fd = open(serial->port, flags)) < 0) {
83 sr_err("Error opening serial port '%s': %s.", serial->port,
84 strerror(errno));
85 return SR_ERR;
86 } else
87 sr_spew("Opened serial port '%s' (fd %d).", serial->port, serial->fd);
88#endif
89
90 if (serial->serialcomm)
91 return serial_set_paramstr(serial, serial->serialcomm);
92 else
93 return SR_OK;
94}
95
96/**
97 * Close the specified serial port.
98 *
99 * @param serial Previously initialized serial port structure.
100 *
101 * @return SR_OK on success, SR_ERR on failure.
102 */
103SR_PRIV int serial_close(struct sr_serial_dev_inst *serial)
104{
105 int ret;
106
107 if (!serial) {
108 sr_dbg("Invalid serial port.");
109 return SR_ERR;
110 }
111
112 if (serial->fd == -1) {
113 sr_dbg("Cannot close unopened serial port %s (fd %d).",
114 serial->port, serial->fd);
115 return SR_ERR;
116 }
117
118 sr_spew("Closing serial port %s (fd %d).", serial->port, serial->fd);
119 ret = SR_OK;
120
121#ifdef _WIN32
122 /* Returns non-zero upon success, 0 upon failure. */
123 if (CloseHandle(hdl) == 0)
124 ret = SR_ERR;
125#else
126 /* Returns 0 upon success, -1 upon failure. */
127 if (close(serial->fd) < 0) {
128 sr_err("Error closing serial port: %s (fd %d).", strerror(errno),
129 serial->fd);
130 ret = SR_ERR;
131 }
132#endif
133
134 serial->fd = -1;
135
136 return ret;
137}
138
139/**
140 * Flush serial port buffers.
141 *
142 * @param serial Previously initialized serial port structure.
143 *
144 * @return SR_OK on success, SR_ERR on failure.
145 */
146SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial)
147{
148 int ret;
149
150 if (!serial) {
151 sr_dbg("Invalid serial port.");
152 return SR_ERR;
153 }
154
155 if (serial->fd == -1) {
156 sr_dbg("Cannot flush unopened serial port %s (fd %d).",
157 serial->port, serial->fd);
158 return SR_ERR;
159 }
160
161 sr_spew("Flushing serial port %s (fd %d).", serial->port, serial->fd);
162 ret = SR_OK;
163
164#ifdef _WIN32
165 /* Returns non-zero upon success, 0 upon failure. */
166 if (PurgeComm(hdl, PURGE_RXCLEAR | PURGE_TXCLEAR) == 0) {
167 sr_err("Error flushing serial port: %s.", strerror(errno));
168 ret = SR_ERR;
169 }
170#else
171 /* Returns 0 upon success, -1 upon failure. */
172 if (tcflush(serial->fd, TCIOFLUSH) < 0) {
173 sr_err("Error flushing serial port: %s.", strerror(errno));
174 ret = SR_ERR;
175 }
176
177 return ret;
178#endif
179}
180
181/**
182 * Write a number of bytes to the specified serial port.
183 *
184 * @param serial Previously initialized serial port structure.
185 * @param buf Buffer containing the bytes to write.
186 * @param count Number of bytes to write.
187 *
188 * @return The number of bytes written, or -1 upon failure.
189 */
190SR_PRIV int serial_write(struct sr_serial_dev_inst *serial,
191 const void *buf, size_t count)
192{
193 ssize_t ret;
194
195 if (!serial) {
196 sr_dbg("Invalid serial port.");
197 return -1;
198 }
199
200 if (serial->fd == -1) {
201 sr_dbg("Cannot use unopened serial port %s (fd %d).",
202 serial->port, serial->fd);
203 return -1;
204 }
205
206#ifdef _WIN32
207 DWORD tmp = 0;
208
209 /* FIXME */
210 /* Returns non-zero upon success, 0 upon failure. */
211 WriteFile(hdl, buf, count, &tmp, NULL);
212#else
213 /* Returns the number of bytes written, or -1 upon failure. */
214 ret = write(serial->fd, buf, count);
215 if (ret < 0)
216 sr_err("Write error: %s.", strerror(errno));
217 else
218 sr_spew("Wrote %d/%d bytes (fd %d).", ret, count, serial->fd);
219#endif
220
221 return ret;
222}
223
224/**
225 * Read a number of bytes from the specified serial port.
226 *
227 * @param serial Previously initialized serial port structure.
228 * @param buf Buffer where to store the bytes that are read.
229 * @param count The number of bytes to read.
230 *
231 * @return The number of bytes read, or -1 upon failure.
232 */
233SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf,
234 size_t count)
235{
236 ssize_t ret;
237
238 if (!serial) {
239 sr_dbg("Invalid serial port.");
240 return -1;
241 }
242
243 if (serial->fd == -1) {
244 sr_dbg("Cannot use unopened serial port %s (fd %d).",
245 serial->port, serial->fd);
246 return -1;
247 }
248
249#ifdef _WIN32
250 DWORD tmp = 0;
251
252 /* FIXME */
253 /* Returns non-zero upon success, 0 upon failure. */
254 return ReadFile(hdl, buf, count, &tmp, NULL);
255#else
256 /* Returns the number of bytes read, or -1 upon failure. */
257 ret = read(serial->fd, buf, count);
258 if (ret < 0)
259 /*
260 * Should be sr_err(), but that would yield lots of
261 * "Resource temporarily unavailable" messages.
262 */
263 sr_spew("Read error: %s (fd %d).", strerror(errno), serial->fd);
264 else
265 sr_spew("Read %d/%d bytes (fd %d).", ret, count, serial->fd);
266#endif
267
268 return ret;
269}
270
271/**
272 * Set serial parameters for the specified serial port.
273 *
274 * @param serial Previously initialized serial port structure.
275 * @param baudrate The baudrate to set.
276 * @param bits The number of data bits to use.
277 * @param parity The parity setting to use (0 = none, 1 = even, 2 = odd).
278 * @param stopbits The number of stop bits to use (1 or 2).
279 * @param flowcontrol The flow control settings to use (0 = none, 1 = RTS/CTS,
280 * 2 = XON/XOFF).
281 *
282 * @return SR_OK upon success, SR_ERR upon failure.
283 */
284SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate,
285 int bits, int parity, int stopbits, int flowcontrol)
286{
287
288 if (!serial) {
289 sr_dbg("Invalid serial port.");
290 return SR_ERR;
291 }
292
293 if (serial->fd == -1) {
294 sr_dbg("Cannot configure unopened serial port %s (fd %d).",
295 serial->port, serial->fd);
296 return SR_ERR;
297 }
298
299 sr_spew("Setting serial parameters on port %s (fd %d).", serial->port,
300 serial->fd);
301
302#ifdef _WIN32
303 DCB dcb;
304
305 if (!GetCommState(hdl, &dcb))
306 return SR_ERR;
307
308 switch (baudrate) {
309 case 115200:
310 dcb.BaudRate = CBR_115200;
311 break;
312 case 57600:
313 dcb.BaudRate = CBR_57600;
314 break;
315 case 38400:
316 dcb.BaudRate = CBR_38400;
317 break;
318 case 19200:
319 dcb.BaudRate = CBR_19200;
320 break;
321 case 9600:
322 dcb.BaudRate = CBR_9600;
323 break;
324 case 4800:
325 dcb.BaudRate = CBR_4800;
326 break;
327 case 2400:
328 dcb.BaudRate = CBR_2400;
329 break;
330 default:
331 sr_err("Unsupported baudrate %d.", baudrate);
332 return SR_ERR;
333 }
334 dcb.ByteSize = bits;
335 dcb.Parity = NOPARITY; /* TODO: Don't hardcode. */
336 dcb.StopBits = ONESTOPBIT; /* TODO: Don't hardcode. */
337
338 if (!SetCommState(hdl, &dcb))
339 return SR_ERR;
340#else
341 struct termios term;
342 speed_t baud;
343
344 if (tcgetattr(serial->fd, &term) < 0) {
345 sr_err("tcgetattr() error on port %s (fd %d): %s.",
346 serial->port, serial->fd, strerror(errno));
347 return SR_ERR;
348 }
349
350 switch (baudrate) {
351 case 50:
352 baud = B50;
353 break;
354 case 75:
355 baud = B75;
356 break;
357 case 110:
358 baud = B110;
359 break;
360 case 134:
361 baud = B134;
362 break;
363 case 150:
364 baud = B150;
365 break;
366 case 200:
367 baud = B200;
368 break;
369 case 300:
370 baud = B300;
371 break;
372 case 600:
373 baud = B600;
374 break;
375 case 1200:
376 baud = B1200;
377 break;
378 case 1800:
379 baud = B1800;
380 break;
381 case 2400:
382 baud = B2400;
383 break;
384 case 4800:
385 baud = B4800;
386 break;
387 case 9600:
388 baud = B9600;
389 break;
390 case 19200:
391 baud = B19200;
392 break;
393 case 38400:
394 baud = B38400;
395 break;
396 case 57600:
397 baud = B57600;
398 break;
399 case 115200:
400 baud = B115200;
401 break;
402 case 230400:
403 baud = B230400;
404 break;
405#ifndef __APPLE__
406 case 460800:
407 baud = B460800;
408 break;
409#endif
410 default:
411 sr_err("Unsupported baudrate %d.", baudrate);
412 return SR_ERR;
413 }
414
415 sr_spew("Configuring output baudrate to %d (%d).", baudrate, baud);
416 if (cfsetospeed(&term, baud) < 0) {
417 sr_err("cfsetospeed() error: %s.", strerror(errno));
418 return SR_ERR;
419 }
420
421 sr_spew("Configuring input baudrate to %d (%d).", baudrate, baud);
422 if (cfsetispeed(&term, baud) < 0) {
423 sr_err("cfsetispeed() error: %s.", strerror(errno));
424 return SR_ERR;
425 }
426
427 sr_spew("Configuring %d data bits.", bits);
428 term.c_cflag &= ~CSIZE;
429 switch (bits) {
430 case 8:
431 term.c_cflag |= CS8;
432 break;
433 case 7:
434 term.c_cflag |= CS7;
435 break;
436 default:
437 sr_err("Unsupported data bits number %d.", bits);
438 return SR_ERR;
439 }
440
441 sr_spew("Configuring %d stop bits.", stopbits);
442 term.c_cflag &= ~CSTOPB;
443 switch (stopbits) {
444 case 1:
445 term.c_cflag &= ~CSTOPB;
446 break;
447 case 2:
448 term.c_cflag |= CSTOPB;
449 break;
450 default:
451 sr_err("Unsupported stopbits number %d.", stopbits);
452 return SR_ERR;
453 }
454
455 term.c_iflag &= ~(IXON | IXOFF);
456 term.c_cflag &= ~CRTSCTS;
457 switch (flowcontrol) {
458 case 0:
459 /* No flow control. */
460 sr_spew("Configuring no flow control.");
461 break;
462 case 1:
463 sr_spew("Configuring RTS/CTS flow control.");
464 term.c_cflag |= CRTSCTS;
465 break;
466 case 2:
467 sr_spew("Configuring XON/XOFF flow control.");
468 term.c_iflag |= IXON | IXOFF;
469 break;
470 default:
471 sr_err("Unsupported flow control setting %d.", flowcontrol);
472 return SR_ERR;
473 }
474
475 term.c_iflag &= ~IGNPAR;
476 term.c_cflag &= ~(PARODD | PARENB);
477 switch (parity) {
478 case SERIAL_PARITY_NONE:
479 sr_spew("Configuring no parity.");
480 term.c_iflag |= IGNPAR;
481 break;
482 case SERIAL_PARITY_EVEN:
483 sr_spew("Configuring even parity.");
484 term.c_cflag |= PARENB;
485 break;
486 case SERIAL_PARITY_ODD:
487 sr_spew("Configuring odd parity.");
488 term.c_cflag |= PARENB | PARODD;
489 break;
490 default:
491 sr_err("Unsupported parity setting %d.", parity);
492 return SR_ERR;
493 }
494
495 /* Do not translate carriage return to newline on input. */
496 term.c_iflag &= ~(ICRNL);
497
498 /* Disable canonical mode, and don't echo input characters. */
499 term.c_lflag &= ~(ICANON | ECHO);
500
501 /* Write the configured settings. */
502 if (tcsetattr(serial->fd, TCSADRAIN, &term) < 0) {
503 sr_err("tcsetattr() error: %s.", strerror(errno));
504 return SR_ERR;
505 }
506#endif
507
508 return SR_OK;
509}
510
511/**
512 * Set serial parameters for the specified serial port.
513 *
514 * @param serial Previously initialized serial port structure.
515 * @param paramstr A serial communication parameters string, in the form
516 * of <speed>/<data bits><parity><stopbits>, for example "9600/8n1" or
517 * "600/7o2".
518 *
519 * @return SR_OK upon success, SR_ERR upon failure.
520 */
521#define SERIAL_COMM_SPEC "^(\\d+)/([78])([neo])([12])$"
522SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
523 const char *paramstr)
524{
525 GRegex *reg;
526 GMatchInfo *match;
527 int speed, databits, parity, stopbits;
528 char *mstr;
529
530 speed = databits = parity = stopbits = 0;
531 reg = g_regex_new(SERIAL_COMM_SPEC, 0, 0, NULL);
532 if (g_regex_match(reg, paramstr, 0, &match)) {
533 if ((mstr = g_match_info_fetch(match, 1)))
534 speed = strtoul(mstr, NULL, 10);
535 g_free(mstr);
536 if ((mstr = g_match_info_fetch(match, 2)))
537 databits = strtoul(mstr, NULL, 10);
538 g_free(mstr);
539 if ((mstr = g_match_info_fetch(match, 3))) {
540 switch (mstr[0]) {
541 case 'n':
542 parity = SERIAL_PARITY_NONE;
543 break;
544 case 'e':
545 parity = SERIAL_PARITY_EVEN;
546 break;
547 case 'o':
548 parity = SERIAL_PARITY_ODD;
549 break;
550 }
551 }
552 g_free(mstr);
553 if ((mstr = g_match_info_fetch(match, 4)))
554 stopbits = strtoul(mstr, NULL, 10);
555 g_free(mstr);
556 }
557 g_match_info_unref(match);
558 g_regex_unref(reg);
559
560 if (speed)
561 return serial_set_params(serial, speed, databits, parity, stopbits, 0);
562 else
563 return SR_ERR_ARG;
564}
565
566/**
567 * Read a line from the specified serial port.
568 *
569 * @param serial Previously initialized serial port structure.
570 * @param buf Buffer where to store the bytes that are read.
571 * @param buflen Size of the buffer.
572 * @param timeout_ms How long to wait for a line to come in.
573 *
574 * Reading stops when CR of LR is found, which is stripped from the buffer.
575 *
576 * @return SR_OK on success, SR_ERR on failure.
577 */
578SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, char **buf,
579 int *buflen, gint64 timeout_ms)
580{
581 gint64 start;
582 int maxlen, len;
583
584 if (!serial || serial->fd == -1) {
585 sr_dbg("Invalid serial port.");
586 return SR_ERR;
587 }
588
589 if (serial->fd == -1) {
590 sr_dbg("Cannot use unopened serial port %s (fd %d).",
591 serial->port, serial->fd);
592 return -1;
593 }
594
595 timeout_ms *= 1000;
596 start = g_get_monotonic_time();
597
598 maxlen = *buflen;
599 *buflen = len = 0;
600 while(1) {
601 len = maxlen - *buflen - 1;
602 if (len < 1)
603 break;
604 len = serial_read(serial, *buf + *buflen, 1);
605 if (len > 0) {
606 *buflen += len;
607 *(*buf + *buflen) = '\0';
608 if (*buflen > 0 && (*(*buf + *buflen - 1) == '\r'
609 || *(*buf + *buflen - 1) == '\n')) {
610 /* Strip CR/LF and terminate. */
611 *(*buf + --*buflen) = '\0';
612 break;
613 }
614 }
615 if (g_get_monotonic_time() - start > timeout_ms)
616 /* Timeout */
617 break;
618 g_usleep(2000);
619 }
620 if (*buflen)
621 sr_dbg("Received %d: '%s'.", *buflen, *buf);
622
623 return SR_OK;
624}