]> sigrok.org Git - libserialport.git/blame_incremental - serialport.c
Move commonly used start flag into timeout helpers.
[libserialport.git] / serialport.c
... / ...
CommitLineData
1/*
2 * This file is part of the libserialport project.
3 *
4 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
5 * Copyright (C) 2010-2015 Uwe Hermann <uwe@hermann-uwe.de>
6 * Copyright (C) 2013-2015 Martin Ling <martin-libserialport@earth.li>
7 * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
8 * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as
12 * published by the Free Software Foundation, either version 3 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include <config.h>
25#include "libserialport.h"
26#include "libserialport_internal.h"
27
28static const struct std_baudrate std_baudrates[] = {
29#ifdef _WIN32
30 /*
31 * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
32 * have documented CBR_* macros.
33 */
34 BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800),
35 BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600),
36 BAUD(115200), BAUD(128000), BAUD(256000),
37#else
38 BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200),
39 BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800),
40 BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200),
41 BAUD(230400),
42#if !defined(__APPLE__) && !defined(__OpenBSD__)
43 BAUD(460800),
44#endif
45#endif
46};
47
48#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
49
50void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
51
52static enum sp_return get_config(struct sp_port *port, struct port_data *data,
53 struct sp_port_config *config);
54
55static enum sp_return set_config(struct sp_port *port, struct port_data *data,
56 const struct sp_port_config *config);
57
58/* Timing abstraction */
59
60struct time {
61#ifdef _WIN32
62 int64_t ticks;
63#else
64 struct timeval tv;
65#endif
66};
67
68struct timeout {
69 unsigned int ms, limit_ms;
70 struct time start, now, end, delta, delta_max;
71 struct timeval delta_tv;
72 bool calls_started, overflow;
73};
74
75static void time_get(struct time *time)
76{
77#ifdef _WIN32
78 LARGE_INTEGER count;
79 QueryPerformanceCounter(&count);
80 time->ticks = count.QuadPart;
81#elif defined(HAVE_CLOCK_GETTIME)
82 struct timespec ts;
83 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
84 clock_gettime(CLOCK_REALTIME, &ts);
85 time->tv.tv_sec = ts.tv_sec;
86 time->tv.tv_usec = ts.tv_nsec / 1000;
87#elif defined(__APPLE__)
88 mach_timebase_info_data_t info;
89 mach_timebase_info(&info);
90 uint64_t ticks = mach_absolute_time();
91 uint64_t ns = (ticks * info.numer) / info.denom;
92 time->tv.tv_sec = ns / 1000000000;
93 time->tv.tv_usec = (ns % 1000000000) / 1000;
94#else
95 gettimeofday(&time->tv, NULL);
96#endif
97}
98
99static void time_set_ms(struct time *time, unsigned int ms)
100{
101#ifdef _WIN32
102 LARGE_INTEGER frequency;
103 QueryPerformanceFrequency(&frequency);
104 time->ticks = ms * (frequency.QuadPart / 1000);
105#else
106 time->tv.tv_sec = ms / 1000;
107 time->tv.tv_usec = (ms % 1000) * 1000;
108#endif
109}
110
111static void time_add(const struct time *a,
112 const struct time *b, struct time *result)
113{
114#ifdef _WIN32
115 result->ticks = a->ticks + b->ticks;
116#else
117 timeradd(&a->tv, &b->tv, &result->tv);
118#endif
119}
120
121static void time_sub(const struct time *a,
122 const struct time *b, struct time *result)
123{
124#ifdef _WIN32
125 result->ticks = a->ticks - b->ticks;
126#else
127 timersub(&a->tv, &b->tv, &result->tv);
128#endif
129}
130
131static bool time_greater(const struct time *a, const struct time *b)
132{
133#ifdef _WIN32
134 return (a->ticks > b->ticks);
135#else
136 return timercmp(&a->tv, &b->tv, >);
137#endif
138}
139
140static void time_as_timeval(const struct time *time, struct timeval *tv)
141{
142#ifdef _WIN32
143 LARGE_INTEGER frequency;
144 QueryPerformanceFrequency(&frequency);
145 tv->tv_sec = time->ticks / frequency.QuadPart;
146 tv->tv_usec = (time->ticks % frequency.QuadPart) /
147 (frequency.QuadPart / 1000000);
148#else
149 *tv = time->tv;
150#endif
151}
152
153static unsigned int time_as_ms(const struct time *time)
154{
155#ifdef _WIN32
156 LARGE_INTEGER frequency;
157 QueryPerformanceFrequency(&frequency);
158 return time->ticks / (frequency.QuadPart / 1000);
159#else
160 return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
161#endif
162}
163
164static void timeout_start(struct timeout *timeout, unsigned int timeout_ms)
165{
166 timeout->ms = timeout_ms;
167
168 /* Get time at start of operation. */
169 time_get(&timeout->start);
170 /* Define duration of timeout. */
171 time_set_ms(&timeout->delta, timeout_ms);
172 /* Calculate time at which we should give up. */
173 time_add(&timeout->start, &timeout->delta, &timeout->end);
174 /* Disable limit unless timeout_limit() called. */
175 timeout->limit_ms = 0;
176 /* First blocking call has not yet been made. */
177 timeout->calls_started = false;
178}
179
180static void timeout_limit(struct timeout *timeout, unsigned int limit_ms)
181{
182 timeout->limit_ms = limit_ms;
183 timeout->overflow = (timeout->ms > timeout->limit_ms);
184 time_set_ms(&timeout->delta_max, timeout->limit_ms);
185}
186
187static bool timeout_check(struct timeout *timeout)
188{
189 if (!timeout->calls_started)
190 return false;
191
192 if (timeout->ms == 0)
193 return false;
194
195 time_get(&timeout->now);
196 time_sub(&timeout->end, &timeout->now, &timeout->delta);
197 if (timeout->limit_ms)
198 if ((timeout->overflow = time_greater(&timeout->delta, &timeout->delta_max)))
199 timeout->delta = timeout->delta_max;
200
201 return time_greater(&timeout->now, &timeout->end);
202}
203
204static void timeout_update(struct timeout *timeout)
205{
206 timeout->calls_started = true;
207}
208
209#ifndef _WIN32
210static struct timeval *timeout_timeval(struct timeout *timeout)
211{
212 if (timeout->ms == 0)
213 return NULL;
214
215 time_as_timeval(&timeout->delta, &timeout->delta_tv);
216
217 return &timeout->delta_tv;
218}
219#endif
220
221static unsigned int timeout_remaining_ms(struct timeout *timeout)
222{
223 if (timeout->limit_ms && timeout->overflow)
224 return timeout->limit_ms;
225 else
226 return time_as_ms(&timeout->delta);
227}
228
229SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
230{
231 struct sp_port *port;
232#ifndef NO_PORT_METADATA
233 enum sp_return ret;
234#endif
235 int len;
236
237 TRACE("%s, %p", portname, port_ptr);
238
239 if (!port_ptr)
240 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
241
242 *port_ptr = NULL;
243
244 if (!portname)
245 RETURN_ERROR(SP_ERR_ARG, "Null port name");
246
247 DEBUG_FMT("Building structure for port %s", portname);
248
249#if !defined(_WIN32) && defined(HAVE_REALPATH)
250 /*
251 * get_port_details() below tries to be too smart and figure out
252 * some transport properties from the port name which breaks with
253 * symlinks. Therefore we canonicalize the portname first.
254 */
255 char pathbuf[PATH_MAX + 1];
256 char *res = realpath(portname, pathbuf);
257 if (!res)
258 RETURN_ERROR(SP_ERR_ARG, "Could not retrieve realpath behind port name");
259
260 portname = pathbuf;
261#endif
262
263 if (!(port = malloc(sizeof(struct sp_port))))
264 RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed");
265
266 len = strlen(portname) + 1;
267
268 if (!(port->name = malloc(len))) {
269 free(port);
270 RETURN_ERROR(SP_ERR_MEM, "Port name malloc failed");
271 }
272
273 memcpy(port->name, portname, len);
274
275#ifdef _WIN32
276 port->usb_path = NULL;
277 port->hdl = INVALID_HANDLE_VALUE;
278 port->write_buf = NULL;
279 port->write_buf_size = 0;
280#else
281 port->fd = -1;
282#endif
283
284 port->description = NULL;
285 port->transport = SP_TRANSPORT_NATIVE;
286 port->usb_bus = -1;
287 port->usb_address = -1;
288 port->usb_vid = -1;
289 port->usb_pid = -1;
290 port->usb_manufacturer = NULL;
291 port->usb_product = NULL;
292 port->usb_serial = NULL;
293 port->bluetooth_address = NULL;
294
295#ifndef NO_PORT_METADATA
296 if ((ret = get_port_details(port)) != SP_OK) {
297 sp_free_port(port);
298 return ret;
299 }
300#endif
301
302 *port_ptr = port;
303
304 RETURN_OK();
305}
306
307SP_API char *sp_get_port_name(const struct sp_port *port)
308{
309 TRACE("%p", port);
310
311 if (!port)
312 return NULL;
313
314 RETURN_STRING(port->name);
315}
316
317SP_API char *sp_get_port_description(const struct sp_port *port)
318{
319 TRACE("%p", port);
320
321 if (!port || !port->description)
322 return NULL;
323
324 RETURN_STRING(port->description);
325}
326
327SP_API enum sp_transport sp_get_port_transport(const struct sp_port *port)
328{
329 TRACE("%p", port);
330
331 if (!port)
332 RETURN_ERROR(SP_ERR_ARG, "Null port");
333
334 RETURN_INT(port->transport);
335}
336
337SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
338 int *usb_bus,int *usb_address)
339{
340 TRACE("%p", port);
341
342 if (!port)
343 RETURN_ERROR(SP_ERR_ARG, "Null port");
344 if (port->transport != SP_TRANSPORT_USB)
345 RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport");
346 if (port->usb_bus < 0 || port->usb_address < 0)
347 RETURN_ERROR(SP_ERR_SUPP, "Bus and address values are not available");
348
349 if (usb_bus)
350 *usb_bus = port->usb_bus;
351 if (usb_address)
352 *usb_address = port->usb_address;
353
354 RETURN_OK();
355}
356
357SP_API enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port,
358 int *usb_vid, int *usb_pid)
359{
360 TRACE("%p", port);
361
362 if (!port)
363 RETURN_ERROR(SP_ERR_ARG, "Null port");
364 if (port->transport != SP_TRANSPORT_USB)
365 RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport");
366 if (port->usb_vid < 0 || port->usb_pid < 0)
367 RETURN_ERROR(SP_ERR_SUPP, "VID:PID values are not available");
368
369 if (usb_vid)
370 *usb_vid = port->usb_vid;
371 if (usb_pid)
372 *usb_pid = port->usb_pid;
373
374 RETURN_OK();
375}
376
377SP_API char *sp_get_port_usb_manufacturer(const struct sp_port *port)
378{
379 TRACE("%p", port);
380
381 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_manufacturer)
382 return NULL;
383
384 RETURN_STRING(port->usb_manufacturer);
385}
386
387SP_API char *sp_get_port_usb_product(const struct sp_port *port)
388{
389 TRACE("%p", port);
390
391 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_product)
392 return NULL;
393
394 RETURN_STRING(port->usb_product);
395}
396
397SP_API char *sp_get_port_usb_serial(const struct sp_port *port)
398{
399 TRACE("%p", port);
400
401 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_serial)
402 return NULL;
403
404 RETURN_STRING(port->usb_serial);
405}
406
407SP_API char *sp_get_port_bluetooth_address(const struct sp_port *port)
408{
409 TRACE("%p", port);
410
411 if (!port || port->transport != SP_TRANSPORT_BLUETOOTH
412 || !port->bluetooth_address)
413 return NULL;
414
415 RETURN_STRING(port->bluetooth_address);
416}
417
418SP_API enum sp_return sp_get_port_handle(const struct sp_port *port,
419 void *result_ptr)
420{
421 TRACE("%p, %p", port, result_ptr);
422
423 if (!port)
424 RETURN_ERROR(SP_ERR_ARG, "Null port");
425 if (!result_ptr)
426 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
427
428#ifdef _WIN32
429 HANDLE *handle_ptr = result_ptr;
430 *handle_ptr = port->hdl;
431#else
432 int *fd_ptr = result_ptr;
433 *fd_ptr = port->fd;
434#endif
435
436 RETURN_OK();
437}
438
439SP_API enum sp_return sp_copy_port(const struct sp_port *port,
440 struct sp_port **copy_ptr)
441{
442 TRACE("%p, %p", port, copy_ptr);
443
444 if (!copy_ptr)
445 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
446
447 *copy_ptr = NULL;
448
449 if (!port)
450 RETURN_ERROR(SP_ERR_ARG, "Null port");
451
452 if (!port->name)
453 RETURN_ERROR(SP_ERR_ARG, "Null port name");
454
455 DEBUG("Copying port structure");
456
457 RETURN_INT(sp_get_port_by_name(port->name, copy_ptr));
458}
459
460SP_API void sp_free_port(struct sp_port *port)
461{
462 TRACE("%p", port);
463
464 if (!port) {
465 DEBUG("Null port");
466 RETURN();
467 }
468
469 DEBUG("Freeing port structure");
470
471 if (port->name)
472 free(port->name);
473 if (port->description)
474 free(port->description);
475 if (port->usb_manufacturer)
476 free(port->usb_manufacturer);
477 if (port->usb_product)
478 free(port->usb_product);
479 if (port->usb_serial)
480 free(port->usb_serial);
481 if (port->bluetooth_address)
482 free(port->bluetooth_address);
483#ifdef _WIN32
484 if (port->usb_path)
485 free(port->usb_path);
486 if (port->write_buf)
487 free(port->write_buf);
488#endif
489
490 free(port);
491
492 RETURN();
493}
494
495SP_PRIV struct sp_port **list_append(struct sp_port **list,
496 const char *portname)
497{
498 void *tmp;
499 unsigned int count;
500
501 for (count = 0; list[count]; count++)
502 ;
503 if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
504 goto fail;
505 list = tmp;
506 if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
507 goto fail;
508 list[count + 1] = NULL;
509 return list;
510
511fail:
512 sp_free_port_list(list);
513 return NULL;
514}
515
516SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr)
517{
518#ifndef NO_ENUMERATION
519 struct sp_port **list;
520 int ret;
521#endif
522
523 TRACE("%p", list_ptr);
524
525 if (!list_ptr)
526 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
527
528 *list_ptr = NULL;
529
530#ifdef NO_ENUMERATION
531 RETURN_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform");
532#else
533 DEBUG("Enumerating ports");
534
535 if (!(list = malloc(sizeof(struct sp_port *))))
536 RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed");
537
538 list[0] = NULL;
539
540 ret = list_ports(&list);
541
542 if (ret == SP_OK) {
543 *list_ptr = list;
544 } else {
545 sp_free_port_list(list);
546 *list_ptr = NULL;
547 }
548
549 RETURN_CODEVAL(ret);
550#endif
551}
552
553SP_API void sp_free_port_list(struct sp_port **list)
554{
555 unsigned int i;
556
557 TRACE("%p", list);
558
559 if (!list) {
560 DEBUG("Null list");
561 RETURN();
562 }
563
564 DEBUG("Freeing port list");
565
566 for (i = 0; list[i]; i++)
567 sp_free_port(list[i]);
568 free(list);
569
570 RETURN();
571}
572
573#define CHECK_PORT() do { \
574 if (!port) \
575 RETURN_ERROR(SP_ERR_ARG, "Null port"); \
576 if (!port->name) \
577 RETURN_ERROR(SP_ERR_ARG, "Null port name"); \
578} while (0)
579#ifdef _WIN32
580#define CHECK_PORT_HANDLE() do { \
581 if (port->hdl == INVALID_HANDLE_VALUE) \
582 RETURN_ERROR(SP_ERR_ARG, "Port not open"); \
583} while (0)
584#else
585#define CHECK_PORT_HANDLE() do { \
586 if (port->fd < 0) \
587 RETURN_ERROR(SP_ERR_ARG, "Port not open"); \
588} while (0)
589#endif
590#define CHECK_OPEN_PORT() do { \
591 CHECK_PORT(); \
592 CHECK_PORT_HANDLE(); \
593} while (0)
594
595#ifdef WIN32
596/** To be called after port receive buffer is emptied. */
597static enum sp_return restart_wait(struct sp_port *port)
598{
599 DWORD wait_result;
600
601 if (port->wait_running) {
602 /* Check status of running wait operation. */
603 if (GetOverlappedResult(port->hdl, &port->wait_ovl,
604 &wait_result, FALSE)) {
605 DEBUG("Previous wait completed");
606 port->wait_running = FALSE;
607 } else if (GetLastError() == ERROR_IO_INCOMPLETE) {
608 DEBUG("Previous wait still running");
609 RETURN_OK();
610 } else {
611 RETURN_FAIL("GetOverlappedResult() failed");
612 }
613 }
614
615 if (!port->wait_running) {
616 /* Start new wait operation. */
617 if (WaitCommEvent(port->hdl, &port->events,
618 &port->wait_ovl)) {
619 DEBUG("New wait returned, events already pending");
620 } else if (GetLastError() == ERROR_IO_PENDING) {
621 DEBUG("New wait running in background");
622 port->wait_running = TRUE;
623 } else {
624 RETURN_FAIL("WaitCommEvent() failed");
625 }
626 }
627
628 RETURN_OK();
629}
630#endif
631
632SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
633{
634 struct port_data data;
635 struct sp_port_config config;
636 enum sp_return ret;
637
638 TRACE("%p, 0x%x", port, flags);
639
640 CHECK_PORT();
641
642 if (flags > SP_MODE_READ_WRITE)
643 RETURN_ERROR(SP_ERR_ARG, "Invalid flags");
644
645 DEBUG_FMT("Opening port %s", port->name);
646
647#ifdef _WIN32
648 DWORD desired_access = 0, flags_and_attributes = 0, errors;
649 char *escaped_port_name;
650 COMSTAT status;
651
652 /* Prefix port name with '\\.\' to work with ports above COM9. */
653 if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
654 RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
655 sprintf(escaped_port_name, "\\\\.\\%s", port->name);
656
657 /* Map 'flags' to the OS-specific settings. */
658 flags_and_attributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
659 if (flags & SP_MODE_READ)
660 desired_access |= GENERIC_READ;
661 if (flags & SP_MODE_WRITE)
662 desired_access |= GENERIC_WRITE;
663
664 port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
665 OPEN_EXISTING, flags_and_attributes, 0);
666
667 free(escaped_port_name);
668
669 if (port->hdl == INVALID_HANDLE_VALUE)
670 RETURN_FAIL("Port CreateFile() failed");
671
672 /* All timeouts initially disabled. */
673 port->timeouts.ReadIntervalTimeout = 0;
674 port->timeouts.ReadTotalTimeoutMultiplier = 0;
675 port->timeouts.ReadTotalTimeoutConstant = 0;
676 port->timeouts.WriteTotalTimeoutMultiplier = 0;
677 port->timeouts.WriteTotalTimeoutConstant = 0;
678
679 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) {
680 sp_close(port);
681 RETURN_FAIL("SetCommTimeouts() failed");
682 }
683
684 /* Prepare OVERLAPPED structures. */
685#define INIT_OVERLAPPED(ovl) do { \
686 memset(&port->ovl, 0, sizeof(port->ovl)); \
687 port->ovl.hEvent = INVALID_HANDLE_VALUE; \
688 if ((port->ovl.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) \
689 == INVALID_HANDLE_VALUE) { \
690 sp_close(port); \
691 RETURN_FAIL(#ovl "CreateEvent() failed"); \
692 } \
693} while (0)
694
695 INIT_OVERLAPPED(read_ovl);
696 INIT_OVERLAPPED(write_ovl);
697 INIT_OVERLAPPED(wait_ovl);
698
699 /* Set event mask for RX and error events. */
700 if (SetCommMask(port->hdl, EV_RXCHAR | EV_ERR) == 0) {
701 sp_close(port);
702 RETURN_FAIL("SetCommMask() failed");
703 }
704
705 port->writing = FALSE;
706 port->wait_running = FALSE;
707
708 ret = restart_wait(port);
709
710 if (ret < 0) {
711 sp_close(port);
712 RETURN_CODEVAL(ret);
713 }
714#else
715 int flags_local = O_NONBLOCK | O_NOCTTY | O_CLOEXEC;
716
717 /* Map 'flags' to the OS-specific settings. */
718 if ((flags & SP_MODE_READ_WRITE) == SP_MODE_READ_WRITE)
719 flags_local |= O_RDWR;
720 else if (flags & SP_MODE_READ)
721 flags_local |= O_RDONLY;
722 else if (flags & SP_MODE_WRITE)
723 flags_local |= O_WRONLY;
724
725 if ((port->fd = open(port->name, flags_local)) < 0)
726 RETURN_FAIL("open() failed");
727#endif
728
729 ret = get_config(port, &data, &config);
730
731 if (ret < 0) {
732 sp_close(port);
733 RETURN_CODEVAL(ret);
734 }
735
736 /* Set sane port settings. */
737#ifdef _WIN32
738 data.dcb.fBinary = TRUE;
739 data.dcb.fDsrSensitivity = FALSE;
740 data.dcb.fErrorChar = FALSE;
741 data.dcb.fNull = FALSE;
742 data.dcb.fAbortOnError = FALSE;
743#else
744 /* Turn off all fancy termios tricks, give us a raw channel. */
745 data.term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IMAXBEL);
746#ifdef IUCLC
747 data.term.c_iflag &= ~IUCLC;
748#endif
749 data.term.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET);
750#ifdef OLCUC
751 data.term.c_oflag &= ~OLCUC;
752#endif
753#ifdef NLDLY
754 data.term.c_oflag &= ~NLDLY;
755#endif
756#ifdef CRDLY
757 data.term.c_oflag &= ~CRDLY;
758#endif
759#ifdef TABDLY
760 data.term.c_oflag &= ~TABDLY;
761#endif
762#ifdef BSDLY
763 data.term.c_oflag &= ~BSDLY;
764#endif
765#ifdef VTDLY
766 data.term.c_oflag &= ~VTDLY;
767#endif
768#ifdef FFDLY
769 data.term.c_oflag &= ~FFDLY;
770#endif
771#ifdef OFILL
772 data.term.c_oflag &= ~OFILL;
773#endif
774 data.term.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN);
775 data.term.c_cc[VMIN] = 0;
776 data.term.c_cc[VTIME] = 0;
777
778 /* Ignore modem status lines; enable receiver; leave control lines alone on close. */
779 data.term.c_cflag |= (CLOCAL | CREAD | HUPCL);
780#endif
781
782#ifdef _WIN32
783 if (ClearCommError(port->hdl, &errors, &status) == 0)
784 RETURN_FAIL("ClearCommError() failed");
785#endif
786
787 ret = set_config(port, &data, &config);
788
789 if (ret < 0) {
790 sp_close(port);
791 RETURN_CODEVAL(ret);
792 }
793
794 RETURN_OK();
795}
796
797SP_API enum sp_return sp_close(struct sp_port *port)
798{
799 TRACE("%p", port);
800
801 CHECK_OPEN_PORT();
802
803 DEBUG_FMT("Closing port %s", port->name);
804
805#ifdef _WIN32
806 /* Returns non-zero upon success, 0 upon failure. */
807 if (CloseHandle(port->hdl) == 0)
808 RETURN_FAIL("Port CloseHandle() failed");
809 port->hdl = INVALID_HANDLE_VALUE;
810
811 /* Close event handles for overlapped structures. */
812#define CLOSE_OVERLAPPED(ovl) do { \
813 if (port->ovl.hEvent != INVALID_HANDLE_VALUE && \
814 CloseHandle(port->ovl.hEvent) == 0) \
815 RETURN_FAIL(# ovl "event CloseHandle() failed"); \
816} while (0)
817 CLOSE_OVERLAPPED(read_ovl);
818 CLOSE_OVERLAPPED(write_ovl);
819 CLOSE_OVERLAPPED(wait_ovl);
820
821 if (port->write_buf) {
822 free(port->write_buf);
823 port->write_buf = NULL;
824 }
825#else
826 /* Returns 0 upon success, -1 upon failure. */
827 if (close(port->fd) == -1)
828 RETURN_FAIL("close() failed");
829 port->fd = -1;
830#endif
831
832 RETURN_OK();
833}
834
835SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers)
836{
837 TRACE("%p, 0x%x", port, buffers);
838
839 CHECK_OPEN_PORT();
840
841 if (buffers > SP_BUF_BOTH)
842 RETURN_ERROR(SP_ERR_ARG, "Invalid buffer selection");
843
844 const char *buffer_names[] = {"no", "input", "output", "both"};
845
846 DEBUG_FMT("Flushing %s buffers on port %s",
847 buffer_names[buffers], port->name);
848
849#ifdef _WIN32
850 DWORD flags = 0;
851 if (buffers & SP_BUF_INPUT)
852 flags |= PURGE_RXCLEAR;
853 if (buffers & SP_BUF_OUTPUT)
854 flags |= PURGE_TXCLEAR;
855
856 /* Returns non-zero upon success, 0 upon failure. */
857 if (PurgeComm(port->hdl, flags) == 0)
858 RETURN_FAIL("PurgeComm() failed");
859
860 if (buffers & SP_BUF_INPUT)
861 TRY(restart_wait(port));
862#else
863 int flags = 0;
864 if (buffers == SP_BUF_BOTH)
865 flags = TCIOFLUSH;
866 else if (buffers == SP_BUF_INPUT)
867 flags = TCIFLUSH;
868 else if (buffers == SP_BUF_OUTPUT)
869 flags = TCOFLUSH;
870
871 /* Returns 0 upon success, -1 upon failure. */
872 if (tcflush(port->fd, flags) < 0)
873 RETURN_FAIL("tcflush() failed");
874#endif
875 RETURN_OK();
876}
877
878SP_API enum sp_return sp_drain(struct sp_port *port)
879{
880 TRACE("%p", port);
881
882 CHECK_OPEN_PORT();
883
884 DEBUG_FMT("Draining port %s", port->name);
885
886#ifdef _WIN32
887 /* Returns non-zero upon success, 0 upon failure. */
888 if (FlushFileBuffers(port->hdl) == 0)
889 RETURN_FAIL("FlushFileBuffers() failed");
890 RETURN_OK();
891#else
892 int result;
893 while (1) {
894#if defined(__ANDROID__) && (__ANDROID_API__ < 21)
895 /* Android only has tcdrain from platform 21 onwards.
896 * On previous API versions, use the ioctl directly. */
897 int arg = 1;
898 result = ioctl(port->fd, TCSBRK, &arg);
899#else
900 result = tcdrain(port->fd);
901#endif
902 if (result < 0) {
903 if (errno == EINTR) {
904 DEBUG("tcdrain() was interrupted");
905 continue;
906 } else {
907 RETURN_FAIL("tcdrain() failed");
908 }
909 } else {
910 RETURN_OK();
911 }
912 }
913#endif
914}
915
916#ifdef _WIN32
917static enum sp_return await_write_completion(struct sp_port *port)
918{
919 TRACE("%p", port);
920 DWORD bytes_written;
921 BOOL result;
922
923 /* Wait for previous non-blocking write to complete, if any. */
924 if (port->writing) {
925 DEBUG("Waiting for previous write to complete");
926 result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
927 port->writing = 0;
928 if (!result)
929 RETURN_FAIL("Previous write failed to complete");
930 DEBUG("Previous write completed");
931 }
932
933 RETURN_OK();
934}
935#endif
936
937SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf,
938 size_t count, unsigned int timeout_ms)
939{
940 TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms);
941
942 CHECK_OPEN_PORT();
943
944 if (!buf)
945 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
946
947 if (timeout_ms)
948 DEBUG_FMT("Writing %d bytes to port %s, timeout %d ms",
949 count, port->name, timeout_ms);
950 else
951 DEBUG_FMT("Writing %d bytes to port %s, no timeout",
952 count, port->name);
953
954 if (count == 0)
955 RETURN_INT(0);
956
957#ifdef _WIN32
958 DWORD bytes_written = 0;
959
960 TRY(await_write_completion(port));
961
962 /* Set timeout. */
963 if (port->timeouts.WriteTotalTimeoutConstant != timeout_ms) {
964 port->timeouts.WriteTotalTimeoutConstant = timeout_ms;
965 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
966 RETURN_FAIL("SetCommTimeouts() failed");
967 }
968
969 /* Reduce count if it exceeds the WriteFile limit. */
970 if (count > WRITEFILE_MAX_SIZE)
971 count = WRITEFILE_MAX_SIZE;
972
973 /* Start write. */
974 if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl)) {
975 DEBUG("Write completed immediately");
976 RETURN_INT(count);
977 } else if (GetLastError() == ERROR_IO_PENDING) {
978 DEBUG("Waiting for write to complete");
979 if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE) == 0) {
980 if (GetLastError() == ERROR_SEM_TIMEOUT) {
981 DEBUG("Write timed out");
982 RETURN_INT(0);
983 } else {
984 RETURN_FAIL("GetOverlappedResult() failed");
985 }
986 }
987 DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count);
988 RETURN_INT(bytes_written);
989 } else {
990 RETURN_FAIL("WriteFile() failed");
991 }
992#else
993 size_t bytes_written = 0;
994 unsigned char *ptr = (unsigned char *) buf;
995 struct timeout timeout;
996 fd_set fds;
997 int result;
998
999 timeout_start(&timeout, timeout_ms);
1000
1001 FD_ZERO(&fds);
1002 FD_SET(port->fd, &fds);
1003
1004 /* Loop until we have written the requested number of bytes. */
1005 while (bytes_written < count) {
1006
1007 if (timeout_check(&timeout))
1008 break;
1009
1010 result = select(port->fd + 1, NULL, &fds, NULL, timeout_timeval(&timeout));
1011
1012 timeout_update(&timeout);
1013
1014 if (result < 0) {
1015 if (errno == EINTR) {
1016 DEBUG("select() call was interrupted, repeating");
1017 continue;
1018 } else {
1019 RETURN_FAIL("select() failed");
1020 }
1021 } else if (result == 0) {
1022 /* Timeout has expired. */
1023 break;
1024 }
1025
1026 /* Do write. */
1027 result = write(port->fd, ptr, count - bytes_written);
1028
1029 if (result < 0) {
1030 if (errno == EAGAIN)
1031 /* This shouldn't happen because we did a select() first, but handle anyway. */
1032 continue;
1033 else
1034 /* This is an actual failure. */
1035 RETURN_FAIL("write() failed");
1036 }
1037
1038 bytes_written += result;
1039 ptr += result;
1040 }
1041
1042 if (bytes_written < count)
1043 DEBUG("Write timed out");
1044
1045 RETURN_INT(bytes_written);
1046#endif
1047}
1048
1049SP_API enum sp_return sp_nonblocking_write(struct sp_port *port,
1050 const void *buf, size_t count)
1051{
1052 TRACE("%p, %p, %d", port, buf, count);
1053
1054 CHECK_OPEN_PORT();
1055
1056 if (!buf)
1057 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1058
1059 DEBUG_FMT("Writing up to %d bytes to port %s", count, port->name);
1060
1061 if (count == 0)
1062 RETURN_INT(0);
1063
1064#ifdef _WIN32
1065 DWORD buf_bytes;
1066
1067 /* Check whether previous write is complete. */
1068 if (port->writing) {
1069 if (HasOverlappedIoCompleted(&port->write_ovl)) {
1070 DEBUG("Previous write completed");
1071 port->writing = 0;
1072 } else {
1073 DEBUG("Previous write not complete");
1074 /* Can't take a new write until the previous one finishes. */
1075 RETURN_INT(0);
1076 }
1077 }
1078
1079 /* Set timeout. */
1080 if (port->timeouts.WriteTotalTimeoutConstant != 0) {
1081 port->timeouts.WriteTotalTimeoutConstant = 0;
1082 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1083 RETURN_FAIL("SetCommTimeouts() failed");
1084 }
1085
1086 /* Reduce count if it exceeds the WriteFile limit. */
1087 if (count > WRITEFILE_MAX_SIZE)
1088 count = WRITEFILE_MAX_SIZE;
1089
1090 /* Copy data to our write buffer. */
1091 buf_bytes = min(port->write_buf_size, count);
1092 memcpy(port->write_buf, buf, buf_bytes);
1093
1094 /* Start asynchronous write. */
1095 if (WriteFile(port->hdl, port->write_buf, buf_bytes, NULL, &port->write_ovl) == 0) {
1096 if (GetLastError() == ERROR_IO_PENDING) {
1097 if ((port->writing = !HasOverlappedIoCompleted(&port->write_ovl)))
1098 DEBUG("Asynchronous write completed immediately");
1099 else
1100 DEBUG("Asynchronous write running");
1101 } else {
1102 /* Actual failure of some kind. */
1103 RETURN_FAIL("WriteFile() failed");
1104 }
1105 }
1106
1107 DEBUG("All bytes written immediately");
1108
1109 RETURN_INT(buf_bytes);
1110#else
1111 /* Returns the number of bytes written, or -1 upon failure. */
1112 ssize_t written = write(port->fd, buf, count);
1113
1114 if (written < 0) {
1115 if (errno == EAGAIN)
1116 // Buffer is full, no bytes written.
1117 RETURN_INT(0);
1118 else
1119 RETURN_FAIL("write() failed");
1120 } else {
1121 RETURN_INT(written);
1122 }
1123#endif
1124}
1125
1126#ifdef _WIN32
1127/* Restart wait operation if buffer was emptied. */
1128static enum sp_return restart_wait_if_needed(struct sp_port *port, unsigned int bytes_read)
1129{
1130 DWORD errors;
1131 COMSTAT comstat;
1132
1133 if (bytes_read == 0)
1134 RETURN_OK();
1135
1136 if (ClearCommError(port->hdl, &errors, &comstat) == 0)
1137 RETURN_FAIL("ClearCommError() failed");
1138
1139 if (comstat.cbInQue == 0)
1140 TRY(restart_wait(port));
1141
1142 RETURN_OK();
1143}
1144#endif
1145
1146SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
1147 size_t count, unsigned int timeout_ms)
1148{
1149 TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms);
1150
1151 CHECK_OPEN_PORT();
1152
1153 if (!buf)
1154 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1155
1156 if (timeout_ms)
1157 DEBUG_FMT("Reading %d bytes from port %s, timeout %d ms",
1158 count, port->name, timeout_ms);
1159 else
1160 DEBUG_FMT("Reading %d bytes from port %s, no timeout",
1161 count, port->name);
1162
1163 if (count == 0)
1164 RETURN_INT(0);
1165
1166#ifdef _WIN32
1167 DWORD bytes_read = 0;
1168
1169 /* Set timeout. */
1170 if (port->timeouts.ReadIntervalTimeout != 0 ||
1171 port->timeouts.ReadTotalTimeoutMultiplier != 0 ||
1172 port->timeouts.ReadTotalTimeoutConstant != timeout_ms) {
1173 port->timeouts.ReadIntervalTimeout = 0;
1174 port->timeouts.ReadTotalTimeoutMultiplier = 0;
1175 port->timeouts.ReadTotalTimeoutConstant = timeout_ms;
1176 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1177 RETURN_FAIL("SetCommTimeouts() failed");
1178 }
1179
1180 /* Start read. */
1181 if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl)) {
1182 DEBUG("Read completed immediately");
1183 bytes_read = count;
1184 } else if (GetLastError() == ERROR_IO_PENDING) {
1185 DEBUG("Waiting for read to complete");
1186 if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
1187 RETURN_FAIL("GetOverlappedResult() failed");
1188 DEBUG_FMT("Read completed, %d/%d bytes read", bytes_read, count);
1189 } else {
1190 RETURN_FAIL("ReadFile() failed");
1191 }
1192
1193 TRY(restart_wait_if_needed(port, bytes_read));
1194
1195 RETURN_INT(bytes_read);
1196
1197#else
1198 size_t bytes_read = 0;
1199 unsigned char *ptr = (unsigned char *) buf;
1200 struct timeout timeout;
1201 fd_set fds;
1202 int result;
1203
1204 timeout_start(&timeout, timeout_ms);
1205
1206 FD_ZERO(&fds);
1207 FD_SET(port->fd, &fds);
1208
1209 /* Loop until we have the requested number of bytes. */
1210 while (bytes_read < count) {
1211
1212 if (timeout_check(&timeout))
1213 /* Timeout has expired. */
1214 break;
1215
1216 result = select(port->fd + 1, &fds, NULL, NULL, timeout_timeval(&timeout));
1217
1218 timeout_update(&timeout);
1219
1220 if (result < 0) {
1221 if (errno == EINTR) {
1222 DEBUG("select() call was interrupted, repeating");
1223 continue;
1224 } else {
1225 RETURN_FAIL("select() failed");
1226 }
1227 } else if (result == 0) {
1228 /* Timeout has expired. */
1229 break;
1230 }
1231
1232 /* Do read. */
1233 result = read(port->fd, ptr, count - bytes_read);
1234
1235 if (result < 0) {
1236 if (errno == EAGAIN)
1237 /*
1238 * This shouldn't happen because we did a
1239 * select() first, but handle anyway.
1240 */
1241 continue;
1242 else
1243 /* This is an actual failure. */
1244 RETURN_FAIL("read() failed");
1245 }
1246
1247 bytes_read += result;
1248 ptr += result;
1249 }
1250
1251 if (bytes_read < count)
1252 DEBUG("Read timed out");
1253
1254 RETURN_INT(bytes_read);
1255#endif
1256}
1257
1258SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf,
1259 size_t count, unsigned int timeout_ms)
1260{
1261 TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms);
1262
1263 CHECK_OPEN_PORT();
1264
1265 if (!buf)
1266 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1267
1268 if (count == 0)
1269 RETURN_ERROR(SP_ERR_ARG, "Zero count");
1270
1271 if (timeout_ms)
1272 DEBUG_FMT("Reading next max %d bytes from port %s, timeout %d ms",
1273 count, port->name, timeout_ms);
1274 else
1275 DEBUG_FMT("Reading next max %d bytes from port %s, no timeout",
1276 count, port->name);
1277
1278#ifdef _WIN32
1279 DWORD bytes_read = 0;
1280
1281 /* If timeout_ms == 0, set maximum timeout. */
1282 DWORD timeout_val = (timeout_ms == 0 ? MAXDWORD - 1 : timeout_ms);
1283
1284 /* Set timeout. */
1285 if (port->timeouts.ReadIntervalTimeout != MAXDWORD ||
1286 port->timeouts.ReadTotalTimeoutMultiplier != MAXDWORD ||
1287 port->timeouts.ReadTotalTimeoutConstant != timeout_val) {
1288 port->timeouts.ReadIntervalTimeout = MAXDWORD;
1289 port->timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
1290 port->timeouts.ReadTotalTimeoutConstant = timeout_val;
1291 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1292 RETURN_FAIL("SetCommTimeouts() failed");
1293 }
1294
1295 /* Loop until we have at least one byte, or timeout is reached. */
1296 while (bytes_read == 0) {
1297 /* Start read. */
1298 if (ReadFile(port->hdl, buf, count, &bytes_read, &port->read_ovl)) {
1299 DEBUG("Read completed immediately");
1300 } else if (GetLastError() == ERROR_IO_PENDING) {
1301 DEBUG("Waiting for read to complete");
1302 if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
1303 RETURN_FAIL("GetOverlappedResult() failed");
1304 if (bytes_read > 0) {
1305 DEBUG("Read completed");
1306 } else if (timeout_ms > 0) {
1307 DEBUG("Read timed out");
1308 break;
1309 } else {
1310 DEBUG("Restarting read");
1311 }
1312 } else {
1313 RETURN_FAIL("ReadFile() failed");
1314 }
1315 }
1316
1317 TRY(restart_wait_if_needed(port, bytes_read));
1318
1319 RETURN_INT(bytes_read);
1320
1321#else
1322 size_t bytes_read = 0;
1323 struct timeout timeout;
1324 fd_set fds;
1325 int result;
1326
1327 timeout_start(&timeout, timeout_ms);
1328
1329 FD_ZERO(&fds);
1330 FD_SET(port->fd, &fds);
1331
1332 /* Loop until we have at least one byte, or timeout is reached. */
1333 while (bytes_read == 0) {
1334
1335 if (timeout_check(&timeout))
1336 /* Timeout has expired. */
1337 break;
1338
1339 result = select(port->fd + 1, &fds, NULL, NULL, timeout_timeval(&timeout));
1340
1341 timeout_update(&timeout);
1342
1343 if (result < 0) {
1344 if (errno == EINTR) {
1345 DEBUG("select() call was interrupted, repeating");
1346 continue;
1347 } else {
1348 RETURN_FAIL("select() failed");
1349 }
1350 } else if (result == 0) {
1351 /* Timeout has expired. */
1352 break;
1353 }
1354
1355 /* Do read. */
1356 result = read(port->fd, buf, count);
1357
1358 if (result < 0) {
1359 if (errno == EAGAIN)
1360 /* This shouldn't happen because we did a select() first, but handle anyway. */
1361 continue;
1362 else
1363 /* This is an actual failure. */
1364 RETURN_FAIL("read() failed");
1365 }
1366
1367 bytes_read = result;
1368 }
1369
1370 if (bytes_read == 0)
1371 DEBUG("Read timed out");
1372
1373 RETURN_INT(bytes_read);
1374#endif
1375}
1376
1377SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf,
1378 size_t count)
1379{
1380 TRACE("%p, %p, %d", port, buf, count);
1381
1382 CHECK_OPEN_PORT();
1383
1384 if (!buf)
1385 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1386
1387 DEBUG_FMT("Reading up to %d bytes from port %s", count, port->name);
1388
1389#ifdef _WIN32
1390 DWORD bytes_read;
1391
1392 /* Set timeout. */
1393 if (port->timeouts.ReadIntervalTimeout != MAXDWORD ||
1394 port->timeouts.ReadTotalTimeoutMultiplier != 0 ||
1395 port->timeouts.ReadTotalTimeoutConstant != 0) {
1396 port->timeouts.ReadIntervalTimeout = MAXDWORD;
1397 port->timeouts.ReadTotalTimeoutMultiplier = 0;
1398 port->timeouts.ReadTotalTimeoutConstant = 0;
1399 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1400 RETURN_FAIL("SetCommTimeouts() failed");
1401 }
1402
1403 /* Do read. */
1404 if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0)
1405 if (GetLastError() != ERROR_IO_PENDING)
1406 RETURN_FAIL("ReadFile() failed");
1407
1408 /* Get number of bytes read. */
1409 if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, FALSE) == 0)
1410 RETURN_FAIL("GetOverlappedResult() failed");
1411
1412 TRY(restart_wait_if_needed(port, bytes_read));
1413
1414 RETURN_INT(bytes_read);
1415#else
1416 ssize_t bytes_read;
1417
1418 /* Returns the number of bytes read, or -1 upon failure. */
1419 if ((bytes_read = read(port->fd, buf, count)) < 0) {
1420 if (errno == EAGAIN)
1421 /* No bytes available. */
1422 bytes_read = 0;
1423 else
1424 /* This is an actual failure. */
1425 RETURN_FAIL("read() failed");
1426 }
1427 RETURN_INT(bytes_read);
1428#endif
1429}
1430
1431SP_API enum sp_return sp_input_waiting(struct sp_port *port)
1432{
1433 TRACE("%p", port);
1434
1435 CHECK_OPEN_PORT();
1436
1437 DEBUG_FMT("Checking input bytes waiting on port %s", port->name);
1438
1439#ifdef _WIN32
1440 DWORD errors;
1441 COMSTAT comstat;
1442
1443 if (ClearCommError(port->hdl, &errors, &comstat) == 0)
1444 RETURN_FAIL("ClearCommError() failed");
1445 RETURN_INT(comstat.cbInQue);
1446#else
1447 int bytes_waiting;
1448 if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0)
1449 RETURN_FAIL("TIOCINQ ioctl failed");
1450 RETURN_INT(bytes_waiting);
1451#endif
1452}
1453
1454SP_API enum sp_return sp_output_waiting(struct sp_port *port)
1455{
1456 TRACE("%p", port);
1457
1458 CHECK_OPEN_PORT();
1459
1460 DEBUG_FMT("Checking output bytes waiting on port %s", port->name);
1461
1462#ifdef _WIN32
1463 DWORD errors;
1464 COMSTAT comstat;
1465
1466 if (ClearCommError(port->hdl, &errors, &comstat) == 0)
1467 RETURN_FAIL("ClearCommError() failed");
1468 RETURN_INT(comstat.cbOutQue);
1469#else
1470 int bytes_waiting;
1471 if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0)
1472 RETURN_FAIL("TIOCOUTQ ioctl failed");
1473 RETURN_INT(bytes_waiting);
1474#endif
1475}
1476
1477SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr)
1478{
1479 struct sp_event_set *result;
1480
1481 TRACE("%p", result_ptr);
1482
1483 if (!result_ptr)
1484 RETURN_ERROR(SP_ERR_ARG, "Null result");
1485
1486 *result_ptr = NULL;
1487
1488 if (!(result = malloc(sizeof(struct sp_event_set))))
1489 RETURN_ERROR(SP_ERR_MEM, "sp_event_set malloc() failed");
1490
1491 memset(result, 0, sizeof(struct sp_event_set));
1492
1493 *result_ptr = result;
1494
1495 RETURN_OK();
1496}
1497
1498static enum sp_return add_handle(struct sp_event_set *event_set,
1499 event_handle handle, enum sp_event mask)
1500{
1501 void *new_handles;
1502 enum sp_event *new_masks;
1503
1504 TRACE("%p, %d, %d", event_set, handle, mask);
1505
1506 if (!(new_handles = realloc(event_set->handles,
1507 sizeof(event_handle) * (event_set->count + 1))))
1508 RETURN_ERROR(SP_ERR_MEM, "Handle array realloc() failed");
1509
1510 event_set->handles = new_handles;
1511
1512 if (!(new_masks = realloc(event_set->masks,
1513 sizeof(enum sp_event) * (event_set->count + 1))))
1514 RETURN_ERROR(SP_ERR_MEM, "Mask array realloc() failed");
1515
1516 event_set->masks = new_masks;
1517
1518 ((event_handle *) event_set->handles)[event_set->count] = handle;
1519 event_set->masks[event_set->count] = mask;
1520
1521 event_set->count++;
1522
1523 RETURN_OK();
1524}
1525
1526SP_API enum sp_return sp_add_port_events(struct sp_event_set *event_set,
1527 const struct sp_port *port, enum sp_event mask)
1528{
1529 TRACE("%p, %p, %d", event_set, port, mask);
1530
1531 if (!event_set)
1532 RETURN_ERROR(SP_ERR_ARG, "Null event set");
1533
1534 if (!port)
1535 RETURN_ERROR(SP_ERR_ARG, "Null port");
1536
1537 if (mask > (SP_EVENT_RX_READY | SP_EVENT_TX_READY | SP_EVENT_ERROR))
1538 RETURN_ERROR(SP_ERR_ARG, "Invalid event mask");
1539
1540 if (!mask)
1541 RETURN_OK();
1542
1543#ifdef _WIN32
1544 enum sp_event handle_mask;
1545 if ((handle_mask = mask & SP_EVENT_TX_READY))
1546 TRY(add_handle(event_set, port->write_ovl.hEvent, handle_mask));
1547 if ((handle_mask = mask & (SP_EVENT_RX_READY | SP_EVENT_ERROR)))
1548 TRY(add_handle(event_set, port->wait_ovl.hEvent, handle_mask));
1549#else
1550 TRY(add_handle(event_set, port->fd, mask));
1551#endif
1552
1553 RETURN_OK();
1554}
1555
1556SP_API void sp_free_event_set(struct sp_event_set *event_set)
1557{
1558 TRACE("%p", event_set);
1559
1560 if (!event_set) {
1561 DEBUG("Null event set");
1562 RETURN();
1563 }
1564
1565 DEBUG("Freeing event set");
1566
1567 if (event_set->handles)
1568 free(event_set->handles);
1569 if (event_set->masks)
1570 free(event_set->masks);
1571
1572 free(event_set);
1573
1574 RETURN();
1575}
1576
1577SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
1578 unsigned int timeout_ms)
1579{
1580 TRACE("%p, %d", event_set, timeout_ms);
1581
1582 if (!event_set)
1583 RETURN_ERROR(SP_ERR_ARG, "Null event set");
1584
1585#ifdef _WIN32
1586 if (WaitForMultipleObjects(event_set->count, event_set->handles, FALSE,
1587 timeout_ms ? timeout_ms : INFINITE) == WAIT_FAILED)
1588 RETURN_FAIL("WaitForMultipleObjects() failed");
1589
1590 RETURN_OK();
1591#else
1592 struct timeout timeout;
1593 int result;
1594 struct pollfd *pollfds;
1595 unsigned int i;
1596
1597 if (!(pollfds = malloc(sizeof(struct pollfd) * event_set->count)))
1598 RETURN_ERROR(SP_ERR_MEM, "pollfds malloc() failed");
1599
1600 for (i = 0; i < event_set->count; i++) {
1601 pollfds[i].fd = ((int *)event_set->handles)[i];
1602 pollfds[i].events = 0;
1603 pollfds[i].revents = 0;
1604 if (event_set->masks[i] & SP_EVENT_RX_READY)
1605 pollfds[i].events |= POLLIN;
1606 if (event_set->masks[i] & SP_EVENT_TX_READY)
1607 pollfds[i].events |= POLLOUT;
1608 if (event_set->masks[i] & SP_EVENT_ERROR)
1609 pollfds[i].events |= POLLERR;
1610 }
1611
1612 timeout_start(&timeout, timeout_ms);
1613 timeout_limit(&timeout, INT_MAX);
1614
1615 /* Loop until an event occurs. */
1616 while (1) {
1617
1618 if (timeout_check(&timeout)) {
1619 DEBUG("Wait timed out");
1620 break;
1621 }
1622
1623 result = poll(pollfds, event_set->count, timeout_remaining_ms(&timeout) || -1);
1624
1625 timeout_update(&timeout);
1626
1627 if (result < 0) {
1628 if (errno == EINTR) {
1629 DEBUG("poll() call was interrupted, repeating");
1630 continue;
1631 } else {
1632 free(pollfds);
1633 RETURN_FAIL("poll() failed");
1634 }
1635 } else if (result == 0) {
1636 DEBUG("poll() timed out");
1637 if (!timeout.overflow)
1638 break;
1639 } else {
1640 DEBUG("poll() completed");
1641 break;
1642 }
1643 }
1644
1645 free(pollfds);
1646 RETURN_OK();
1647#endif
1648}
1649
1650#ifdef USE_TERMIOS_SPEED
1651static enum sp_return get_baudrate(int fd, int *baudrate)
1652{
1653 void *data;
1654
1655 TRACE("%d, %p", fd, baudrate);
1656
1657 DEBUG("Getting baud rate");
1658
1659 if (!(data = malloc(get_termios_size())))
1660 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
1661
1662 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
1663 free(data);
1664 RETURN_FAIL("Getting termios failed");
1665 }
1666
1667 *baudrate = get_termios_speed(data);
1668
1669 free(data);
1670
1671 RETURN_OK();
1672}
1673
1674static enum sp_return set_baudrate(int fd, int baudrate)
1675{
1676 void *data;
1677
1678 TRACE("%d, %d", fd, baudrate);
1679
1680 DEBUG("Getting baud rate");
1681
1682 if (!(data = malloc(get_termios_size())))
1683 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
1684
1685 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
1686 free(data);
1687 RETURN_FAIL("Getting termios failed");
1688 }
1689
1690 DEBUG("Setting baud rate");
1691
1692 set_termios_speed(data, baudrate);
1693
1694 if (ioctl(fd, get_termios_set_ioctl(), data) < 0) {
1695 free(data);
1696 RETURN_FAIL("Setting termios failed");
1697 }
1698
1699 free(data);
1700
1701 RETURN_OK();
1702}
1703#endif /* USE_TERMIOS_SPEED */
1704
1705#ifdef USE_TERMIOX
1706static enum sp_return get_flow(int fd, struct port_data *data)
1707{
1708 void *termx;
1709
1710 TRACE("%d, %p", fd, data);
1711
1712 DEBUG("Getting advanced flow control");
1713
1714 if (!(termx = malloc(get_termiox_size())))
1715 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
1716
1717 if (ioctl(fd, TCGETX, termx) < 0) {
1718 free(termx);
1719 RETURN_FAIL("Getting termiox failed");
1720 }
1721
1722 get_termiox_flow(termx, &data->rts_flow, &data->cts_flow,
1723 &data->dtr_flow, &data->dsr_flow);
1724
1725 free(termx);
1726
1727 RETURN_OK();
1728}
1729
1730static enum sp_return set_flow(int fd, struct port_data *data)
1731{
1732 void *termx;
1733
1734 TRACE("%d, %p", fd, data);
1735
1736 DEBUG("Getting advanced flow control");
1737
1738 if (!(termx = malloc(get_termiox_size())))
1739 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
1740
1741 if (ioctl(fd, TCGETX, termx) < 0) {
1742 free(termx);
1743 RETURN_FAIL("Getting termiox failed");
1744 }
1745
1746 DEBUG("Setting advanced flow control");
1747
1748 set_termiox_flow(termx, data->rts_flow, data->cts_flow,
1749 data->dtr_flow, data->dsr_flow);
1750
1751 if (ioctl(fd, TCSETX, termx) < 0) {
1752 free(termx);
1753 RETURN_FAIL("Setting termiox failed");
1754 }
1755
1756 free(termx);
1757
1758 RETURN_OK();
1759}
1760#endif /* USE_TERMIOX */
1761
1762static enum sp_return get_config(struct sp_port *port, struct port_data *data,
1763 struct sp_port_config *config)
1764{
1765 unsigned int i;
1766
1767 TRACE("%p, %p, %p", port, data, config);
1768
1769 DEBUG_FMT("Getting configuration for port %s", port->name);
1770
1771#ifdef _WIN32
1772 if (!GetCommState(port->hdl, &data->dcb))
1773 RETURN_FAIL("GetCommState() failed");
1774
1775 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1776 if (data->dcb.BaudRate == std_baudrates[i].index) {
1777 config->baudrate = std_baudrates[i].value;
1778 break;
1779 }
1780 }
1781
1782 if (i == NUM_STD_BAUDRATES)
1783 /* BaudRate field can be either an index or a custom baud rate. */
1784 config->baudrate = data->dcb.BaudRate;
1785
1786 config->bits = data->dcb.ByteSize;
1787
1788 if (data->dcb.fParity)
1789 switch (data->dcb.Parity) {
1790 case NOPARITY:
1791 config->parity = SP_PARITY_NONE;
1792 break;
1793 case ODDPARITY:
1794 config->parity = SP_PARITY_ODD;
1795 break;
1796 case EVENPARITY:
1797 config->parity = SP_PARITY_EVEN;
1798 break;
1799 case MARKPARITY:
1800 config->parity = SP_PARITY_MARK;
1801 break;
1802 case SPACEPARITY:
1803 config->parity = SP_PARITY_SPACE;
1804 break;
1805 default:
1806 config->parity = -1;
1807 }
1808 else
1809 config->parity = SP_PARITY_NONE;
1810
1811 switch (data->dcb.StopBits) {
1812 case ONESTOPBIT:
1813 config->stopbits = 1;
1814 break;
1815 case TWOSTOPBITS:
1816 config->stopbits = 2;
1817 break;
1818 default:
1819 config->stopbits = -1;
1820 }
1821
1822 switch (data->dcb.fRtsControl) {
1823 case RTS_CONTROL_DISABLE:
1824 config->rts = SP_RTS_OFF;
1825 break;
1826 case RTS_CONTROL_ENABLE:
1827 config->rts = SP_RTS_ON;
1828 break;
1829 case RTS_CONTROL_HANDSHAKE:
1830 config->rts = SP_RTS_FLOW_CONTROL;
1831 break;
1832 default:
1833 config->rts = -1;
1834 }
1835
1836 config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
1837
1838 switch (data->dcb.fDtrControl) {
1839 case DTR_CONTROL_DISABLE:
1840 config->dtr = SP_DTR_OFF;
1841 break;
1842 case DTR_CONTROL_ENABLE:
1843 config->dtr = SP_DTR_ON;
1844 break;
1845 case DTR_CONTROL_HANDSHAKE:
1846 config->dtr = SP_DTR_FLOW_CONTROL;
1847 break;
1848 default:
1849 config->dtr = -1;
1850 }
1851
1852 config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
1853
1854 if (data->dcb.fInX) {
1855 if (data->dcb.fOutX)
1856 config->xon_xoff = SP_XONXOFF_INOUT;
1857 else
1858 config->xon_xoff = SP_XONXOFF_IN;
1859 } else {
1860 if (data->dcb.fOutX)
1861 config->xon_xoff = SP_XONXOFF_OUT;
1862 else
1863 config->xon_xoff = SP_XONXOFF_DISABLED;
1864 }
1865
1866#else // !_WIN32
1867
1868 if (tcgetattr(port->fd, &data->term) < 0)
1869 RETURN_FAIL("tcgetattr() failed");
1870
1871 if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
1872 RETURN_FAIL("TIOCMGET ioctl failed");
1873
1874#ifdef USE_TERMIOX
1875 int ret = get_flow(port->fd, data);
1876
1877 if (ret == SP_ERR_FAIL && errno == EINVAL)
1878 data->termiox_supported = 0;
1879 else if (ret < 0)
1880 RETURN_CODEVAL(ret);
1881 else
1882 data->termiox_supported = 1;
1883#else
1884 data->termiox_supported = 0;
1885#endif
1886
1887 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1888 if (cfgetispeed(&data->term) == std_baudrates[i].index) {
1889 config->baudrate = std_baudrates[i].value;
1890 break;
1891 }
1892 }
1893
1894 if (i == NUM_STD_BAUDRATES) {
1895#ifdef __APPLE__
1896 config->baudrate = (int)data->term.c_ispeed;
1897#elif defined(USE_TERMIOS_SPEED)
1898 TRY(get_baudrate(port->fd, &config->baudrate));
1899#else
1900 config->baudrate = -1;
1901#endif
1902 }
1903
1904 switch (data->term.c_cflag & CSIZE) {
1905 case CS8:
1906 config->bits = 8;
1907 break;
1908 case CS7:
1909 config->bits = 7;
1910 break;
1911 case CS6:
1912 config->bits = 6;
1913 break;
1914 case CS5:
1915 config->bits = 5;
1916 break;
1917 default:
1918 config->bits = -1;
1919 }
1920
1921 if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR))
1922 config->parity = SP_PARITY_NONE;
1923 else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR))
1924 config->parity = -1;
1925#ifdef CMSPAR
1926 else if (data->term.c_cflag & CMSPAR)
1927 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_MARK : SP_PARITY_SPACE;
1928#endif
1929 else
1930 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
1931
1932 config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
1933
1934 if (data->term.c_cflag & CRTSCTS) {
1935 config->rts = SP_RTS_FLOW_CONTROL;
1936 config->cts = SP_CTS_FLOW_CONTROL;
1937 } else {
1938 if (data->termiox_supported && data->rts_flow)
1939 config->rts = SP_RTS_FLOW_CONTROL;
1940 else
1941 config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
1942
1943 config->cts = (data->termiox_supported && data->cts_flow) ?
1944 SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
1945 }
1946
1947 if (data->termiox_supported && data->dtr_flow)
1948 config->dtr = SP_DTR_FLOW_CONTROL;
1949 else
1950 config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
1951
1952 config->dsr = (data->termiox_supported && data->dsr_flow) ?
1953 SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
1954
1955 if (data->term.c_iflag & IXOFF) {
1956 if (data->term.c_iflag & IXON)
1957 config->xon_xoff = SP_XONXOFF_INOUT;
1958 else
1959 config->xon_xoff = SP_XONXOFF_IN;
1960 } else {
1961 if (data->term.c_iflag & IXON)
1962 config->xon_xoff = SP_XONXOFF_OUT;
1963 else
1964 config->xon_xoff = SP_XONXOFF_DISABLED;
1965 }
1966#endif
1967
1968 RETURN_OK();
1969}
1970
1971static enum sp_return set_config(struct sp_port *port, struct port_data *data,
1972 const struct sp_port_config *config)
1973{
1974 unsigned int i;
1975#ifdef __APPLE__
1976 BAUD_TYPE baud_nonstd;
1977
1978 baud_nonstd = B0;
1979#endif
1980#ifdef USE_TERMIOS_SPEED
1981 int baud_nonstd = 0;
1982#endif
1983
1984 TRACE("%p, %p, %p", port, data, config);
1985
1986 DEBUG_FMT("Setting configuration for port %s", port->name);
1987
1988#ifdef _WIN32
1989
1990 TRY(await_write_completion(port));
1991
1992 if (config->baudrate >= 0) {
1993 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
1994 if (config->baudrate == std_baudrates[i].value) {
1995 data->dcb.BaudRate = std_baudrates[i].index;
1996 break;
1997 }
1998 }
1999
2000 if (i == NUM_STD_BAUDRATES)
2001 data->dcb.BaudRate = config->baudrate;
2002
2003 /* Allocate write buffer for 50ms of data at baud rate. */
2004 port->write_buf_size = max(config->baudrate / (8 * 20), 1);
2005 port->write_buf = realloc(port->write_buf,
2006 port->write_buf_size);
2007
2008 if (!port->write_buf)
2009 RETURN_ERROR(SP_ERR_MEM, "Allocating write buffer failed");
2010 }
2011
2012 if (config->bits >= 0)
2013 data->dcb.ByteSize = config->bits;
2014
2015 if (config->parity >= 0) {
2016 switch (config->parity) {
2017 case SP_PARITY_NONE:
2018 data->dcb.Parity = NOPARITY;
2019 break;
2020 case SP_PARITY_ODD:
2021 data->dcb.Parity = ODDPARITY;
2022 break;
2023 case SP_PARITY_EVEN:
2024 data->dcb.Parity = EVENPARITY;
2025 break;
2026 case SP_PARITY_MARK:
2027 data->dcb.Parity = MARKPARITY;
2028 break;
2029 case SP_PARITY_SPACE:
2030 data->dcb.Parity = SPACEPARITY;
2031 break;
2032 default:
2033 RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
2034 }
2035 }
2036
2037 if (config->stopbits >= 0) {
2038 switch (config->stopbits) {
2039 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
2040 case 1:
2041 data->dcb.StopBits = ONESTOPBIT;
2042 break;
2043 case 2:
2044 data->dcb.StopBits = TWOSTOPBITS;
2045 break;
2046 default:
2047 RETURN_ERROR(SP_ERR_ARG, "Invalid stop bit setting");
2048 }
2049 }
2050
2051 if (config->rts >= 0) {
2052 switch (config->rts) {
2053 case SP_RTS_OFF:
2054 data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
2055 break;
2056 case SP_RTS_ON:
2057 data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
2058 break;
2059 case SP_RTS_FLOW_CONTROL:
2060 data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
2061 break;
2062 default:
2063 RETURN_ERROR(SP_ERR_ARG, "Invalid RTS setting");
2064 }
2065 }
2066
2067 if (config->cts >= 0) {
2068 switch (config->cts) {
2069 case SP_CTS_IGNORE:
2070 data->dcb.fOutxCtsFlow = FALSE;
2071 break;
2072 case SP_CTS_FLOW_CONTROL:
2073 data->dcb.fOutxCtsFlow = TRUE;
2074 break;
2075 default:
2076 RETURN_ERROR(SP_ERR_ARG, "Invalid CTS setting");
2077 }
2078 }
2079
2080 if (config->dtr >= 0) {
2081 switch (config->dtr) {
2082 case SP_DTR_OFF:
2083 data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
2084 break;
2085 case SP_DTR_ON:
2086 data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
2087 break;
2088 case SP_DTR_FLOW_CONTROL:
2089 data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
2090 break;
2091 default:
2092 RETURN_ERROR(SP_ERR_ARG, "Invalid DTR setting");
2093 }
2094 }
2095
2096 if (config->dsr >= 0) {
2097 switch (config->dsr) {
2098 case SP_DSR_IGNORE:
2099 data->dcb.fOutxDsrFlow = FALSE;
2100 break;
2101 case SP_DSR_FLOW_CONTROL:
2102 data->dcb.fOutxDsrFlow = TRUE;
2103 break;
2104 default:
2105 RETURN_ERROR(SP_ERR_ARG, "Invalid DSR setting");
2106 }
2107 }
2108
2109 if (config->xon_xoff >= 0) {
2110 switch (config->xon_xoff) {
2111 case SP_XONXOFF_DISABLED:
2112 data->dcb.fInX = FALSE;
2113 data->dcb.fOutX = FALSE;
2114 break;
2115 case SP_XONXOFF_IN:
2116 data->dcb.fInX = TRUE;
2117 data->dcb.fOutX = FALSE;
2118 break;
2119 case SP_XONXOFF_OUT:
2120 data->dcb.fInX = FALSE;
2121 data->dcb.fOutX = TRUE;
2122 break;
2123 case SP_XONXOFF_INOUT:
2124 data->dcb.fInX = TRUE;
2125 data->dcb.fOutX = TRUE;
2126 break;
2127 default:
2128 RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
2129 }
2130 }
2131
2132 if (!SetCommState(port->hdl, &data->dcb))
2133 RETURN_FAIL("SetCommState() failed");
2134
2135#else /* !_WIN32 */
2136
2137 int controlbits;
2138
2139 if (config->baudrate >= 0) {
2140 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
2141 if (config->baudrate == std_baudrates[i].value) {
2142 if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
2143 RETURN_FAIL("cfsetospeed() failed");
2144
2145 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
2146 RETURN_FAIL("cfsetispeed() failed");
2147 break;
2148 }
2149 }
2150
2151 /* Non-standard baud rate */
2152 if (i == NUM_STD_BAUDRATES) {
2153#ifdef __APPLE__
2154 /* Set "dummy" baud rate. */
2155 if (cfsetspeed(&data->term, B9600) < 0)
2156 RETURN_FAIL("cfsetspeed() failed");
2157 baud_nonstd = config->baudrate;
2158#elif defined(USE_TERMIOS_SPEED)
2159 baud_nonstd = 1;
2160#else
2161 RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported");
2162#endif
2163 }
2164 }
2165
2166 if (config->bits >= 0) {
2167 data->term.c_cflag &= ~CSIZE;
2168 switch (config->bits) {
2169 case 8:
2170 data->term.c_cflag |= CS8;
2171 break;
2172 case 7:
2173 data->term.c_cflag |= CS7;
2174 break;
2175 case 6:
2176 data->term.c_cflag |= CS6;
2177 break;
2178 case 5:
2179 data->term.c_cflag |= CS5;
2180 break;
2181 default:
2182 RETURN_ERROR(SP_ERR_ARG, "Invalid data bits setting");
2183 }
2184 }
2185
2186 if (config->parity >= 0) {
2187 data->term.c_iflag &= ~IGNPAR;
2188 data->term.c_cflag &= ~(PARENB | PARODD);
2189#ifdef CMSPAR
2190 data->term.c_cflag &= ~CMSPAR;
2191#endif
2192 switch (config->parity) {
2193 case SP_PARITY_NONE:
2194 data->term.c_iflag |= IGNPAR;
2195 break;
2196 case SP_PARITY_EVEN:
2197 data->term.c_cflag |= PARENB;
2198 break;
2199 case SP_PARITY_ODD:
2200 data->term.c_cflag |= PARENB | PARODD;
2201 break;
2202#ifdef CMSPAR
2203 case SP_PARITY_MARK:
2204 data->term.c_cflag |= PARENB | PARODD;
2205 data->term.c_cflag |= CMSPAR;
2206 break;
2207 case SP_PARITY_SPACE:
2208 data->term.c_cflag |= PARENB;
2209 data->term.c_cflag |= CMSPAR;
2210 break;
2211#else
2212 case SP_PARITY_MARK:
2213 case SP_PARITY_SPACE:
2214 RETURN_ERROR(SP_ERR_SUPP, "Mark/space parity not supported");
2215#endif
2216 default:
2217 RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
2218 }
2219 }
2220
2221 if (config->stopbits >= 0) {
2222 data->term.c_cflag &= ~CSTOPB;
2223 switch (config->stopbits) {
2224 case 1:
2225 data->term.c_cflag &= ~CSTOPB;
2226 break;
2227 case 2:
2228 data->term.c_cflag |= CSTOPB;
2229 break;
2230 default:
2231 RETURN_ERROR(SP_ERR_ARG, "Invalid stop bits setting");
2232 }
2233 }
2234
2235 if (config->rts >= 0 || config->cts >= 0) {
2236 if (data->termiox_supported) {
2237 data->rts_flow = data->cts_flow = 0;
2238 switch (config->rts) {
2239 case SP_RTS_OFF:
2240 case SP_RTS_ON:
2241 controlbits = TIOCM_RTS;
2242 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
2243 RETURN_FAIL("Setting RTS signal level failed");
2244 break;
2245 case SP_RTS_FLOW_CONTROL:
2246 data->rts_flow = 1;
2247 break;
2248 default:
2249 break;
2250 }
2251 if (config->cts == SP_CTS_FLOW_CONTROL)
2252 data->cts_flow = 1;
2253
2254 if (data->rts_flow && data->cts_flow)
2255 data->term.c_iflag |= CRTSCTS;
2256 else
2257 data->term.c_iflag &= ~CRTSCTS;
2258 } else {
2259 /* Asymmetric use of RTS/CTS not supported. */
2260 if (data->term.c_iflag & CRTSCTS) {
2261 /* Flow control can only be disabled for both RTS & CTS together. */
2262 if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) {
2263 if (config->cts != SP_CTS_IGNORE)
2264 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
2265 }
2266 if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) {
2267 if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL)
2268 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
2269 }
2270 } else {
2271 /* Flow control can only be enabled for both RTS & CTS together. */
2272 if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) ||
2273 ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL)))
2274 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be enabled together");
2275 }
2276
2277 if (config->rts >= 0) {
2278 if (config->rts == SP_RTS_FLOW_CONTROL) {
2279 data->term.c_iflag |= CRTSCTS;
2280 } else {
2281 controlbits = TIOCM_RTS;
2282 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
2283 &controlbits) < 0)
2284 RETURN_FAIL("Setting RTS signal level failed");
2285 }
2286 }
2287 }
2288 }
2289
2290 if (config->dtr >= 0 || config->dsr >= 0) {
2291 if (data->termiox_supported) {
2292 data->dtr_flow = data->dsr_flow = 0;
2293 switch (config->dtr) {
2294 case SP_DTR_OFF:
2295 case SP_DTR_ON:
2296 controlbits = TIOCM_DTR;
2297 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
2298 RETURN_FAIL("Setting DTR signal level failed");
2299 break;
2300 case SP_DTR_FLOW_CONTROL:
2301 data->dtr_flow = 1;
2302 break;
2303 default:
2304 break;
2305 }
2306 if (config->dsr == SP_DSR_FLOW_CONTROL)
2307 data->dsr_flow = 1;
2308 } else {
2309 /* DTR/DSR flow control not supported. */
2310 if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL)
2311 RETURN_ERROR(SP_ERR_SUPP, "DTR/DSR flow control not supported");
2312
2313 if (config->dtr >= 0) {
2314 controlbits = TIOCM_DTR;
2315 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
2316 &controlbits) < 0)
2317 RETURN_FAIL("Setting DTR signal level failed");
2318 }
2319 }
2320 }
2321
2322 if (config->xon_xoff >= 0) {
2323 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
2324 switch (config->xon_xoff) {
2325 case SP_XONXOFF_DISABLED:
2326 break;
2327 case SP_XONXOFF_IN:
2328 data->term.c_iflag |= IXOFF;
2329 break;
2330 case SP_XONXOFF_OUT:
2331 data->term.c_iflag |= IXON | IXANY;
2332 break;
2333 case SP_XONXOFF_INOUT:
2334 data->term.c_iflag |= IXON | IXOFF | IXANY;
2335 break;
2336 default:
2337 RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
2338 }
2339 }
2340
2341 if (tcsetattr(port->fd, TCSANOW, &data->term) < 0)
2342 RETURN_FAIL("tcsetattr() failed");
2343
2344#ifdef __APPLE__
2345 if (baud_nonstd != B0) {
2346 if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1)
2347 RETURN_FAIL("IOSSIOSPEED ioctl failed");
2348 /*
2349 * Set baud rates in data->term to correct, but incompatible
2350 * with tcsetattr() value, same as delivered by tcgetattr().
2351 */
2352 if (cfsetspeed(&data->term, baud_nonstd) < 0)
2353 RETURN_FAIL("cfsetspeed() failed");
2354 }
2355#elif defined(__linux__)
2356#ifdef USE_TERMIOS_SPEED
2357 if (baud_nonstd)
2358 TRY(set_baudrate(port->fd, config->baudrate));
2359#endif
2360#ifdef USE_TERMIOX
2361 if (data->termiox_supported)
2362 TRY(set_flow(port->fd, data));
2363#endif
2364#endif
2365
2366#endif /* !_WIN32 */
2367
2368 RETURN_OK();
2369}
2370
2371SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr)
2372{
2373 struct sp_port_config *config;
2374
2375 TRACE("%p", config_ptr);
2376
2377 if (!config_ptr)
2378 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
2379
2380 *config_ptr = NULL;
2381
2382 if (!(config = malloc(sizeof(struct sp_port_config))))
2383 RETURN_ERROR(SP_ERR_MEM, "Config malloc failed");
2384
2385 config->baudrate = -1;
2386 config->bits = -1;
2387 config->parity = -1;
2388 config->stopbits = -1;
2389 config->rts = -1;
2390 config->cts = -1;
2391 config->dtr = -1;
2392 config->dsr = -1;
2393
2394 *config_ptr = config;
2395
2396 RETURN_OK();
2397}
2398
2399SP_API void sp_free_config(struct sp_port_config *config)
2400{
2401 TRACE("%p", config);
2402
2403 if (!config)
2404 DEBUG("Null config");
2405 else
2406 free(config);
2407
2408 RETURN();
2409}
2410
2411SP_API enum sp_return sp_get_config(struct sp_port *port,
2412 struct sp_port_config *config)
2413{
2414 struct port_data data;
2415
2416 TRACE("%p, %p", port, config);
2417
2418 CHECK_OPEN_PORT();
2419
2420 if (!config)
2421 RETURN_ERROR(SP_ERR_ARG, "Null config");
2422
2423 TRY(get_config(port, &data, config));
2424
2425 RETURN_OK();
2426}
2427
2428SP_API enum sp_return sp_set_config(struct sp_port *port,
2429 const struct sp_port_config *config)
2430{
2431 struct port_data data;
2432 struct sp_port_config prev_config;
2433
2434 TRACE("%p, %p", port, config);
2435
2436 CHECK_OPEN_PORT();
2437
2438 if (!config)
2439 RETURN_ERROR(SP_ERR_ARG, "Null config");
2440
2441 TRY(get_config(port, &data, &prev_config));
2442 TRY(set_config(port, &data, config));
2443
2444 RETURN_OK();
2445}
2446
2447#define CREATE_ACCESSORS(x, type) \
2448SP_API enum sp_return sp_set_##x(struct sp_port *port, type x) { \
2449 struct port_data data; \
2450 struct sp_port_config config; \
2451 TRACE("%p, %d", port, x); \
2452 CHECK_OPEN_PORT(); \
2453 TRY(get_config(port, &data, &config)); \
2454 config.x = x; \
2455 TRY(set_config(port, &data, &config)); \
2456 RETURN_OK(); \
2457} \
2458SP_API enum sp_return sp_get_config_##x(const struct sp_port_config *config, \
2459 type *x) { \
2460 TRACE("%p, %p", config, x); \
2461 if (!x) \
2462 RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); \
2463 if (!config) \
2464 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
2465 *x = config->x; \
2466 RETURN_OK(); \
2467} \
2468SP_API enum sp_return sp_set_config_##x(struct sp_port_config *config, \
2469 type x) { \
2470 TRACE("%p, %d", config, x); \
2471 if (!config) \
2472 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
2473 config->x = x; \
2474 RETURN_OK(); \
2475}
2476
2477CREATE_ACCESSORS(baudrate, int)
2478CREATE_ACCESSORS(bits, int)
2479CREATE_ACCESSORS(parity, enum sp_parity)
2480CREATE_ACCESSORS(stopbits, int)
2481CREATE_ACCESSORS(rts, enum sp_rts)
2482CREATE_ACCESSORS(cts, enum sp_cts)
2483CREATE_ACCESSORS(dtr, enum sp_dtr)
2484CREATE_ACCESSORS(dsr, enum sp_dsr)
2485CREATE_ACCESSORS(xon_xoff, enum sp_xonxoff)
2486
2487SP_API enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config,
2488 enum sp_flowcontrol flowcontrol)
2489{
2490 if (!config)
2491 RETURN_ERROR(SP_ERR_ARG, "Null configuration");
2492
2493 if (flowcontrol > SP_FLOWCONTROL_DTRDSR)
2494 RETURN_ERROR(SP_ERR_ARG, "Invalid flow control setting");
2495
2496 if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
2497 config->xon_xoff = SP_XONXOFF_INOUT;
2498 else
2499 config->xon_xoff = SP_XONXOFF_DISABLED;
2500
2501 if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
2502 config->rts = SP_RTS_FLOW_CONTROL;
2503 config->cts = SP_CTS_FLOW_CONTROL;
2504 } else {
2505 if (config->rts == SP_RTS_FLOW_CONTROL)
2506 config->rts = SP_RTS_ON;
2507 config->cts = SP_CTS_IGNORE;
2508 }
2509
2510 if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
2511 config->dtr = SP_DTR_FLOW_CONTROL;
2512 config->dsr = SP_DSR_FLOW_CONTROL;
2513 } else {
2514 if (config->dtr == SP_DTR_FLOW_CONTROL)
2515 config->dtr = SP_DTR_ON;
2516 config->dsr = SP_DSR_IGNORE;
2517 }
2518
2519 RETURN_OK();
2520}
2521
2522SP_API enum sp_return sp_set_flowcontrol(struct sp_port *port,
2523 enum sp_flowcontrol flowcontrol)
2524{
2525 struct port_data data;
2526 struct sp_port_config config;
2527
2528 TRACE("%p, %d", port, flowcontrol);
2529
2530 CHECK_OPEN_PORT();
2531
2532 TRY(get_config(port, &data, &config));
2533
2534 TRY(sp_set_config_flowcontrol(&config, flowcontrol));
2535
2536 TRY(set_config(port, &data, &config));
2537
2538 RETURN_OK();
2539}
2540
2541SP_API enum sp_return sp_get_signals(struct sp_port *port,
2542 enum sp_signal *signals)
2543{
2544 TRACE("%p, %p", port, signals);
2545
2546 CHECK_OPEN_PORT();
2547
2548 if (!signals)
2549 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
2550
2551 DEBUG_FMT("Getting control signals for port %s", port->name);
2552
2553 *signals = 0;
2554#ifdef _WIN32
2555 DWORD bits;
2556 if (GetCommModemStatus(port->hdl, &bits) == 0)
2557 RETURN_FAIL("GetCommModemStatus() failed");
2558 if (bits & MS_CTS_ON)
2559 *signals |= SP_SIG_CTS;
2560 if (bits & MS_DSR_ON)
2561 *signals |= SP_SIG_DSR;
2562 if (bits & MS_RLSD_ON)
2563 *signals |= SP_SIG_DCD;
2564 if (bits & MS_RING_ON)
2565 *signals |= SP_SIG_RI;
2566#else
2567 int bits;
2568 if (ioctl(port->fd, TIOCMGET, &bits) < 0)
2569 RETURN_FAIL("TIOCMGET ioctl failed");
2570 if (bits & TIOCM_CTS)
2571 *signals |= SP_SIG_CTS;
2572 if (bits & TIOCM_DSR)
2573 *signals |= SP_SIG_DSR;
2574 if (bits & TIOCM_CAR)
2575 *signals |= SP_SIG_DCD;
2576 if (bits & TIOCM_RNG)
2577 *signals |= SP_SIG_RI;
2578#endif
2579 RETURN_OK();
2580}
2581
2582SP_API enum sp_return sp_start_break(struct sp_port *port)
2583{
2584 TRACE("%p", port);
2585
2586 CHECK_OPEN_PORT();
2587#ifdef _WIN32
2588 if (SetCommBreak(port->hdl) == 0)
2589 RETURN_FAIL("SetCommBreak() failed");
2590#else
2591 if (ioctl(port->fd, TIOCSBRK, 1) < 0)
2592 RETURN_FAIL("TIOCSBRK ioctl failed");
2593#endif
2594
2595 RETURN_OK();
2596}
2597
2598SP_API enum sp_return sp_end_break(struct sp_port *port)
2599{
2600 TRACE("%p", port);
2601
2602 CHECK_OPEN_PORT();
2603#ifdef _WIN32
2604 if (ClearCommBreak(port->hdl) == 0)
2605 RETURN_FAIL("ClearCommBreak() failed");
2606#else
2607 if (ioctl(port->fd, TIOCCBRK, 1) < 0)
2608 RETURN_FAIL("TIOCCBRK ioctl failed");
2609#endif
2610
2611 RETURN_OK();
2612}
2613
2614SP_API int sp_last_error_code(void)
2615{
2616 TRACE_VOID();
2617#ifdef _WIN32
2618 RETURN_INT(GetLastError());
2619#else
2620 RETURN_INT(errno);
2621#endif
2622}
2623
2624SP_API char *sp_last_error_message(void)
2625{
2626 TRACE_VOID();
2627
2628#ifdef _WIN32
2629 TCHAR *message;
2630 DWORD error = GetLastError();
2631
2632 DWORD length = FormatMessage(
2633 FORMAT_MESSAGE_ALLOCATE_BUFFER |
2634 FORMAT_MESSAGE_FROM_SYSTEM |
2635 FORMAT_MESSAGE_IGNORE_INSERTS,
2636 NULL,
2637 error,
2638 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2639 (LPTSTR) &message,
2640 0, NULL );
2641
2642 if (length >= 2 && message[length - 2] == '\r')
2643 message[length - 2] = '\0';
2644
2645 RETURN_STRING(message);
2646#else
2647 RETURN_STRING(strerror(errno));
2648#endif
2649}
2650
2651SP_API void sp_free_error_message(char *message)
2652{
2653 TRACE("%s", message);
2654
2655#ifdef _WIN32
2656 LocalFree(message);
2657#else
2658 (void)message;
2659#endif
2660
2661 RETURN();
2662}
2663
2664SP_API void sp_set_debug_handler(void (*handler)(const char *format, ...))
2665{
2666 TRACE("%p", handler);
2667
2668 sp_debug_handler = handler;
2669
2670 RETURN();
2671}
2672
2673SP_API void sp_default_debug_handler(const char *format, ...)
2674{
2675 va_list args;
2676 va_start(args, format);
2677 if (getenv("LIBSERIALPORT_DEBUG")) {
2678 fputs("sp: ", stderr);
2679 vfprintf(stderr, format, args);
2680 }
2681 va_end(args);
2682}
2683
2684SP_API int sp_get_major_package_version(void)
2685{
2686 return SP_PACKAGE_VERSION_MAJOR;
2687}
2688
2689SP_API int sp_get_minor_package_version(void)
2690{
2691 return SP_PACKAGE_VERSION_MINOR;
2692}
2693
2694SP_API int sp_get_micro_package_version(void)
2695{
2696 return SP_PACKAGE_VERSION_MICRO;
2697}
2698
2699SP_API const char *sp_get_package_version_string(void)
2700{
2701 return SP_PACKAGE_VERSION_STRING;
2702}
2703
2704SP_API int sp_get_current_lib_version(void)
2705{
2706 return SP_LIB_VERSION_CURRENT;
2707}
2708
2709SP_API int sp_get_revision_lib_version(void)
2710{
2711 return SP_LIB_VERSION_REVISION;
2712}
2713
2714SP_API int sp_get_age_lib_version(void)
2715{
2716 return SP_LIB_VERSION_AGE;
2717}
2718
2719SP_API const char *sp_get_lib_version_string(void)
2720{
2721 return SP_LIB_VERSION_STRING;
2722}
2723
2724/** @} */