blob: 975bc1b9896018877954e6229fe111fb38758cf1 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <ucommon-config.h>
40#include <commoncpp/config.h>
41#include <commoncpp/export.h>
42#include <commoncpp/exception.h>
43#include <commoncpp/thread.h>
44#include <commoncpp/serial.h>
45#include <cstdlib>
46#include <climits>
47
48#ifdef _MSWINDOWS_
49
50#define B256000 CBR_256000
51#define B128000 CBR_128000
52#define B115200 CBR_115200
53#define B57600 CBR_57600
54#define B56000 CBR_56000
55#define B38400 CBR_38400
56#define B19200 CBR_19200
57#define B14400 CBR_14400
58#define B9600 CBR_9600
59#define B4800 CBR_4800
60#define B2400 CBR_2400
61#define B1200 CBR_1200
62#define B600 CBR_600
63#define B300 CBR_300
64#define B110 CBR_110
65
66#include <io.h>
67#else
68#include <sys/ioctl.h>
69#ifdef HAVE_TERMIOS_H
70#include <termios.h>
71#endif
72#endif
73
74#include <fcntl.h>
75#include <cerrno>
76#include <iostream>
77
78NAMESPACE_COMMONCPP
79using std::streambuf;
80using std::iostream;
81using std::ios;
82
83#ifndef MAX_INPUT
84#define MAX_INPUT 255
85#endif
86
87#ifndef MAX_CANON
88#define MAX_CANON MAX_INPUT
89#endif
90
91#ifdef __FreeBSD__
92#undef _PC_MAX_INPUT
93#undef _PC_MAX_CANON
94#endif
95
96#if defined(__QNX__)
97#define CRTSCTS (IHFLOW | OHFLOW)
98#endif
99
100#if defined(_THR_UNIXWARE) || defined(__hpux) || defined(_AIX)
101#include <sys/termiox.h>
102#define CRTSCTS (CTSXON | RTSXOFF)
103#endif
104
105// IRIX
106
107#ifndef CRTSCTS
108#ifdef CNEW_RTSCTS
109#define CRTSCTS (CNEW_RTSCTS)
110#endif
111#endif
112
113#if defined(CTSXON) && defined(RTSXOFF) && !defined(CRTSCTS)
114#define CRTSCTS (CTSXON | RTSXOFF)
115#endif
116
117#ifndef CRTSCTS
118#define CRTSCTS 0
119#endif
120
121Serial::Serial(const char *fname)
122{
123 initSerial();
124
125#if defined(_MSWINDOWS_) || defined(HAVE_TERMIOS_H)
126 open(fname);
127#endif
128
129#ifdef _MSWINDOWS_
130 if(dev == INVALID_HANDLE_VALUE)
131#elif defined(HAVE_TERMIOS_H)
132 if(dev < 0)
133#else
134 if(1)
135#endif
136 {
137 error(errOpenFailed);
138 return;
139 }
140
141#ifdef _MSWINDOWS_
142 COMMTIMEOUTS CommTimeOuts ;
143
144 GetCommTimeouts(dev, &CommTimeOuts);
145
146// CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
147 CommTimeOuts.ReadIntervalTimeout = 0;
148
149 CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
150 CommTimeOuts.ReadTotalTimeoutConstant = 0;
151 CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ;
152 CommTimeOuts.WriteTotalTimeoutConstant = 1000;
153
154 SetCommTimeouts(dev, &CommTimeOuts) ;
155
156#elif defined(HAVE_TERMIOS_H)
157
158 if(!isatty(dev)) {
159 Serial::close();
160 error(errOpenNoTty);
161 return;
162 }
163#endif
164}
165
166Serial::~Serial()
167{
168 endSerial();
169}
170
171void Serial::initConfig(void)
172{
173#ifdef _MSWINDOWS_
174
175#define ASCII_XON 0x11
176#define ASCII_XOFF 0x13
177
178 DCB * attr = (DCB *)current;
179 DCB * orig = (DCB *)original;
180
181 attr->DCBlength = sizeof(DCB);
182 orig->DCBlength = sizeof(DCB);
183
184 GetCommState(dev, orig);
185 GetCommState(dev, attr);
186
187 attr->DCBlength = sizeof(DCB);
188 attr->BaudRate = 1200;
189 attr->Parity = NOPARITY;
190 attr->ByteSize = 8;
191
192 attr->XonChar = ASCII_XON;
193 attr->XoffChar = ASCII_XOFF;
194 attr->XonLim = 100;
195 attr->XoffLim = 100;
196 attr->fOutxDsrFlow = 0;
197 attr->fDtrControl = DTR_CONTROL_ENABLE;
198 attr->fOutxCtsFlow = 1;
199 attr->fRtsControl = RTS_CONTROL_ENABLE;
200 attr->fInX = attr->fOutX = 0;
201
202 attr->fBinary = true;
203 attr->fParity = true;
204
205 SetCommState(dev, attr);
206
207#elif defined(HAVE_TERMIOS_H)
208 struct termios *attr = (struct termios *)current;
209 struct termios *orig = (struct termios *)original;
210 long ioflags = fcntl(dev, F_GETFL);
211
212 tcgetattr(dev, (struct termios *)original);
213 tcgetattr(dev, (struct termios *)current);
214
215 attr->c_oflag = attr->c_lflag = 0;
216 attr->c_cflag = CLOCAL | CREAD | HUPCL;
217 attr->c_iflag = IGNBRK;
218
219 memset(attr->c_cc, 0, sizeof(attr->c_cc));
220 attr->c_cc[VMIN] = 1;
221
222 // inherit original settings, maybe we should keep more??
223 cfsetispeed(attr, cfgetispeed(orig));
224 cfsetospeed(attr, cfgetospeed(orig));
225 attr->c_cflag |= orig->c_cflag & (CRTSCTS | CSIZE | PARENB | PARODD | CSTOPB);
226 attr->c_iflag |= orig->c_iflag & (IXON | IXANY | IXOFF);
227
228 tcsetattr(dev, TCSANOW, attr);
229 fcntl(dev, F_SETFL, ioflags & ~O_NDELAY);
230
231#if defined(TIOCM_RTS) && defined(TIOCMODG)
232 int mcs = 0;
233 ioctl(dev, TIOCMODG, &mcs);
234 mcs |= TIOCM_RTS;
235 ioctl(dev, TIOCMODS, &mcs);
236#endif
237
238#ifdef _COHERENT
239 ioctl(dev, TIOCSRTS, 0);
240#endif
241
242#endif // WIN32
243 }
244
245void Serial::restore(void)
246{
247#ifdef _MSWINDOWS_
248 memcpy(current, original, sizeof(DCB));
249 SetCommState(dev, (DCB *)current);
250#elif defined(HAVE_TERMIOS_H)
251 memcpy(current, original, sizeof(struct termios));
252 tcsetattr(dev, TCSANOW, (struct termios *)current);
253#endif
254}
255
256void Serial::initSerial(void)
257{
258 flags.thrown = false;
259 flags.linebuf = false;
260 errid = errSuccess;
261 errstr = NULL;
262
263 dev = INVALID_HANDLE_VALUE;
264#ifdef _MSWINDOWS_
265 current = new DCB;
266 original = new DCB;
267#elif defined(HAVE_TERMIOS_H)
268 current = new struct termios;
269 original = new struct termios;
270#endif
271}
272
273void Serial::endSerial(void)
274{
275#ifdef _MSWINDOWS_
276 if(dev == INVALID_HANDLE_VALUE && original)
277 SetCommState(dev, (DCB *)original);
278
279 if(current)
280 delete (DCB *)current;
281
282 if(original)
283 delete (DCB *)original;
284#elif defined(HAVE_TERMIOS_H)
285 if(dev < 0 && original)
286 tcsetattr(dev, TCSANOW, (struct termios *)original);
287
288 if(current)
289 delete (struct termios *)current;
290
291 if(original)
292 delete (struct termios *)original;
293#endif
294 Serial::close();
295
296 current = NULL;
297 original = NULL;
298}
299
300Serial::Error Serial::error(Error err, char *errs)
301{
302 errid = err;
303 errstr = errs;
304 if(!err)
305 return err;
306
307 if(flags.thrown)
308 return err;
309
310 // prevents recursive throws
311
312 flags.thrown = true;
313#ifdef CCXX_EXCEPTIONS
314 if(Thread::getException() == Thread::throwObject)
315 throw((Serial *)this);
316#ifdef COMMON_STD_EXCEPTION
317 else if(Thread::getException() == Thread::throwException) {
318 if(!errs)
319 errs = (char *)"";
320 throw SerException(String(errs));
321 }
322#endif
323#endif
324 return err;
325}
326
327int Serial::setPacketInput(int size, unsigned char btimer)
328{
329#ifdef _MSWINDOWS_
330 // Still to be done......
331 return 0;
332#elif defined(HAVE_TERMIOS_H)
333
334#ifdef _PC_MAX_INPUT
335 int max = fpathconf(dev, _PC_MAX_INPUT);
336#else
337 int max = MAX_INPUT;
338#endif
339 struct termios *attr = (struct termios *)current;
340
341 if(size > max)
342 size = max;
343
344 attr->c_cc[VEOL] = attr->c_cc[VEOL2] = 0;
345 attr->c_cc[VMIN] = (unsigned char)size;
346 attr->c_cc[VTIME] = btimer;
347 attr->c_lflag &= ~ICANON;
348 tcsetattr(dev, TCSANOW, attr);
349 bufsize = size;
350 return size;
351#endif
352}
353
354int Serial::setLineInput(char newline, char nl1)
355{
356#ifdef _MSWINDOWS_
357 // Still to be done......
358 return 0;
359#elif defined(HAVE_TERMIOS_H)
360
361 struct termios *attr = (struct termios *)current;
362 attr->c_cc[VMIN] = attr->c_cc[VTIME] = 0;
363 attr->c_cc[VEOL] = newline;
364 attr->c_cc[VEOL2] = nl1;
365 attr->c_lflag |= ICANON;
366 tcsetattr(dev, TCSANOW, attr);
367#ifdef _PC_MAX_CANON
368 bufsize = fpathconf(dev, _PC_MAX_CANON);
369#else
370 bufsize = MAX_CANON;
371#endif
372 return bufsize;
373#endif
374}
375
376void Serial::flushInput(void)
377{
378#ifdef _MSWINDOWS_
379 PurgeComm(dev, PURGE_RXABORT | PURGE_RXCLEAR);
380#elif defined(HAVE_TERMIOS_H)
381 tcflush(dev, TCIFLUSH);
382#endif
383}
384
385void Serial::flushOutput(void)
386{
387#ifdef _MSWINDOWS_
388 PurgeComm(dev, PURGE_TXABORT | PURGE_TXCLEAR);
389#elif defined(HAVE_TERMIOS_H)
390 tcflush(dev, TCOFLUSH);
391#endif
392}
393
394void Serial::waitOutput(void)
395{
396#ifdef _MSWINDOWS_
397
398#elif defined(HAVE_TERMIOS_H)
399 tcdrain(dev);
400#endif
401}
402
403Serial &Serial::operator=(const Serial &ser)
404{
405 Serial::close();
406
407 if(ser.dev < 0)
408 return *this;
409
410#ifdef _MSWINDOWS_
411 HANDLE process = GetCurrentProcess();
412
413 int result = DuplicateHandle(process, ser.dev, process, &dev, DUPLICATE_SAME_ACCESS, 0, 0);
414
415 if (0 == result) {
416 memcpy(current, ser.current, sizeof(DCB));
417 memcpy(original, ser.original, sizeof(DCB));
418 }
419#elif defined(HAVE_TERMIOS_H)
420 dev = dup(ser.dev);
421
422 memcpy(current, ser.current, sizeof(struct termios));
423 memcpy(original, ser.original, sizeof(struct termios));
424#endif
425 return *this;
426}
427
428
429void Serial::open(const char * fname)
430{
431
432#ifndef _MSWINDOWS_
433 int cflags = O_RDWR | O_NDELAY;
434 dev = ::open(fname, cflags);
435 if(dev > -1)
436 initConfig();
437#elif defined(HAVE_TERMIOS_H)
438 // open COMM device
439 dev = CreateFile(fname,
440 GENERIC_READ | GENERIC_WRITE,
441 0, // exclusive access
442 NULL, // no security attrs
443 OPEN_EXISTING,
444 FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING,
445 NULL);
446 if(dev != INVALID_HANDLE_VALUE)
447 initConfig();
448#endif
449}
450
451#ifdef _MSWINDOWS_
452int Serial::aRead(char * Data, const int Length)
453{
454
455 unsigned long dwLength = 0, dwError, dwReadLength;
456 COMSTAT cs;
457 OVERLAPPED ol;
458
459 // Return zero if handle is invalid
460 if(dev == INVALID_HANDLE_VALUE)
461 return 0;
462
463 // Read max length or only what is available
464 ClearCommError(dev, &dwError, &cs);
465
466 // If not requiring an exact byte count, get whatever is available
467 if(Length > (int)cs.cbInQue)
468 dwReadLength = cs.cbInQue;
469 else
470 dwReadLength = Length;
471
472 memset(&ol, 0, sizeof(OVERLAPPED));
473 ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
474
475 if(dwReadLength > 0) {
476 if(ReadFile(dev, Data, dwReadLength, &dwLength, &ol) == FALSE) {
477 if(GetLastError() == ERROR_IO_PENDING) {
478 WaitForSingleObject(ol.hEvent, INFINITE);
479 GetOverlappedResult(dev, &ol, &dwLength, TRUE);
480 }
481 else
482 ClearCommError(dev, &dwError, &cs);
483 }
484 }
485
486 if(ol.hEvent != INVALID_HANDLE_VALUE)
487 CloseHandle(ol.hEvent);
488
489 return dwLength;
490}
491
492int Serial::aWrite(const char * Data, const int Length)
493{
494 COMSTAT cs;
495 unsigned long dwError = 0;
496 OVERLAPPED ol;
497
498 // Clear the com port of any error condition prior to read
499 ClearCommError(dev, &dwError, &cs);
500
501 unsigned long retSize = 0;
502
503 memset(&ol, 0, sizeof(OVERLAPPED));
504 ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
505
506 if(WriteFile(dev, Data, Length, &retSize, &ol) == FALSE) {
507 if(GetLastError() == ERROR_IO_PENDING) {
508 WaitForSingleObject(ol.hEvent, INFINITE);
509 GetOverlappedResult(dev, &ol, &retSize, TRUE);
510 }
511 else
512 ClearCommError(dev, &dwError, &cs);
513 }
514
515 if(ol.hEvent != INVALID_HANDLE_VALUE)
516 CloseHandle(ol.hEvent);
517
518 return retSize;
519}
520#else
521int Serial::aRead(char *Data, const int Length)
522{
523 return ::read(dev, Data, Length);
524}
525
526int Serial::aWrite(const char *Data, const int Length)
527{
528 return ::write(dev, Data, Length);
529}
530#endif
531
532void Serial::close()
533{
534#ifdef _MSWINDOWS_
535 CloseHandle(dev);
536#else
537 ::close(dev);
538#endif
539
540 dev = INVALID_HANDLE_VALUE;
541}
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566/*
567const int iAsync::getTimeOuts(unsigned long & readTimeout, unsigned long & writeTimeout)
568{
569 return GetCommTimeouts(_TheHandle, &CommTimeOuts);
570 }
571
572const int iAsync::setTimeOuts(unsigned long readTimeout, unsigned long writeTimeout)
573{
574 COMMTIMEOUTS CommTimeOuts ;
575
576 getTimeOuts(CommTimeOuts);
577
578 CommTimeOuts.ReadIntervalTimeout = readTimeout;
579 CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
580 CommTimeOuts.ReadTotalTimeoutConstant = 0;
581 CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ;
582 CommTimeOuts.WriteTotalTimeoutConstant = 1000;
583
584 return GetCommTimeouts(_TheHandle, &CommTimeOuts);
585 }
586 return SetCommTimeouts(_TheHandle, &CommTimeOuts) ;
587{
588 DCB dcb ;
589
590 dcb.DCBlength = sizeof(DCB) ;
591
592 GetCommState(_TheHandle, &dcb) ;
593
594 // hardcode this stuff for now.....
595 dcb.BaudRate = _TheBaudrate;
596 dcb.ByteSize = 8;
597 dcb.Parity = NOPARITY;
598 dcb.StopBits = ONESTOPBIT;
599 dcb.fOutxDsrFlow = 0;
600 dcb.fDtrControl = DTR_CONTROL_ENABLE ;
601 dcb.fOutxCtsFlow = 1;
602 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ;
603 dcb.fInX = dcb.fOutX = 0;
604
605 dcb.XonChar = ASCII_XON;
606 dcb.XoffChar = ASCII_XOFF;
607 dcb.XonLim = 100;
608 dcb.XoffLim = 100;
609
610 // other various settings
611
612 dcb.fBinary = TRUE;
613 dcb.fParity = TRUE;
614
615 GetCommState(_TheHandle, &dcb) ;
616 dcb.DCBlength = sizeof(DCB) ;
617 dcb.BaudRate = _TheBaudrate;
618 SetCommState(_TheHandle, &dcb) ;
619
620 }
621*/
622
623Serial::Error Serial::setSpeed(unsigned long speed)
624{
625 unsigned long rate;
626
627 switch(speed) {
628#ifdef B115200
629 case 115200:
630 rate = B115200;
631 break;
632#endif
633#ifdef B57600
634 case 57600:
635 rate = B57600;
636 break;
637#endif
638#ifdef B38400
639 case 38400:
640 rate = B38400;
641 break;
642#endif
643 case 19200:
644 rate = B19200;
645 break;
646 case 9600:
647 rate = B9600;
648 break;
649 case 4800:
650 rate = B4800;
651 break;
652 case 2400:
653 rate = B2400;
654 break;
655 case 1200:
656 rate = B1200;
657 break;
658 case 600:
659 rate = B600;
660 break;
661 case 300:
662 rate = B300;
663 break;
664 case 110:
665 rate = B110;
666 break;
667#ifdef B0
668 case 0:
669 rate = B0;
670 break;
671#endif
672 default:
673 return error(errSpeedInvalid);
674 }
675
676#ifdef _MSWINDOWS_
677
678 DCB * dcb = (DCB *)current;
679 dcb->DCBlength = sizeof(DCB);
680 GetCommState(dev, dcb);
681
682 dcb->BaudRate = rate;
683 SetCommState(dev, dcb) ;
684
685#else
686 struct termios *attr = (struct termios *)current;
687 cfsetispeed(attr, rate);
688 cfsetospeed(attr, rate);
689 tcsetattr(dev, TCSANOW, attr);
690#endif
691 return errSuccess;
692 }
693
694Serial::Error Serial::setFlowControl(Flow flow)
695{
696#ifdef _MSWINDOWS_
697
698 DCB * attr = (DCB *)current;
699 attr->XonChar = ASCII_XON;
700 attr->XoffChar = ASCII_XOFF;
701 attr->XonLim = 100;
702 attr->XoffLim = 100;
703
704 switch(flow) {
705 case flowSoft:
706 attr->fInX = attr->fOutX = 1;
707 break;
708 case flowBoth:
709 attr->fInX = attr->fOutX = 1;
710 case flowHard:
711 attr->fOutxCtsFlow = 1;
712 attr->fRtsControl = RTS_CONTROL_HANDSHAKE;
713 break;
714 case flowNone:
715 break;
716 default:
717 return error(errFlowInvalid);
718 }
719
720 SetCommState(dev, attr);
721#else
722
723 struct termios *attr = (struct termios *)current;
724
725 attr->c_cflag &= ~CRTSCTS;
726 attr->c_iflag &= ~(IXON | IXANY | IXOFF);
727
728 switch(flow) {
729 case flowSoft:
730 attr->c_iflag |= (IXON | IXANY | IXOFF);
731 break;
732 case flowBoth:
733 attr->c_iflag |= (IXON | IXANY | IXOFF);
734 case flowHard:
735 attr->c_cflag |= CRTSCTS;
736 break;
737 case flowNone:
738 break;
739 default:
740 return error(errFlowInvalid);
741 }
742
743 tcsetattr(dev, TCSANOW, attr);
744
745#endif
746 return errSuccess;
747 }
748
749Serial::Error Serial::setStopBits(int bits)
750{
751#ifdef _MSWINDOWS_
752
753 DCB * attr = (DCB *)current;
754 switch(bits) {
755 case 1:
756 attr->StopBits = ONESTOPBIT;
757 break;
758 case 2:
759 attr->StopBits = TWOSTOPBITS;
760 break;
761 default:
762 return error(errStopbitsInvalid);
763 }
764
765 SetCommState(dev, attr);
766#else
767 struct termios *attr = (struct termios *)current;
768 attr->c_cflag &= ~CSTOPB;
769
770 switch(bits) {
771 case 1:
772 break;
773 case 2:
774 attr->c_cflag |= CSTOPB;
775 break;
776 default:
777 return error(errStopbitsInvalid);
778 }
779 tcsetattr(dev, TCSANOW, attr);
780#endif
781 return errSuccess;
782 }
783
784Serial::Error Serial::setCharBits(int bits)
785{
786#ifdef _MSWINDOWS_
787
788 DCB * attr = (DCB *)current;
789 switch(bits) {
790 case 5:
791 case 6:
792 case 7:
793 case 8:
794 attr->ByteSize = bits;
795 break;
796 default:
797 return error(errCharsizeInvalid);
798 }
799 SetCommState(dev, attr);
800#else
801 struct termios *attr = (struct termios *)current;
802 attr->c_cflag &= ~CSIZE;
803
804 switch(bits) {
805 case 5:
806 attr->c_cflag |= CS5;
807 break;
808 case 6:
809 attr->c_cflag |= CS6;
810 break;
811 case 7:
812 attr->c_cflag |= CS7;
813 break;
814 case 8:
815 attr->c_cflag |= CS8;
816 break;
817 default:
818 return error(errCharsizeInvalid);
819 }
820 tcsetattr(dev, TCSANOW, attr);
821#endif
822 return errSuccess;
823 }
824
825Serial::Error Serial::setParity(Parity parity)
826{
827#ifdef _MSWINDOWS_
828
829 DCB * attr = (DCB *)current;
830 switch(parity) {
831 case parityEven:
832 attr->Parity = EVENPARITY;
833 break;
834 case parityOdd:
835 attr->Parity = ODDPARITY;
836 break;
837 case parityNone:
838 attr->Parity = NOPARITY;
839 break;
840 default:
841 return error(errParityInvalid);
842 }
843 SetCommState(dev, attr);
844#else
845 struct termios *attr = (struct termios *)current;
846 attr->c_cflag &= ~(PARENB | PARODD);
847
848 switch(parity) {
849 case parityEven:
850 attr->c_cflag |= PARENB;
851 break;
852 case parityOdd:
853 attr->c_cflag |= (PARENB | PARODD);
854 break;
855 case parityNone:
856 break;
857 default:
858 return error(errParityInvalid);
859 }
860 tcsetattr(dev, TCSANOW, attr);
861#endif
862 return errSuccess;
863 }
864
865void Serial::sendBreak(void)
866{
867#ifdef _MSWINDOWS_
868 SetCommBreak(dev);
869 Thread::sleep(100L);
870 ClearCommBreak(dev);
871#else
872 tcsendbreak(dev, 0);
873#endif
874 }
875
876void Serial::toggleDTR(timeout_t millisec)
877{
878#ifdef _MSWINDOWS_
879 EscapeCommFunction(dev, CLRDTR);
880 if(millisec) {
881 Thread::sleep(millisec);
882 EscapeCommFunction(dev, SETDTR);
883 }
884
885#else
886 struct termios tty, old;
887 tcgetattr(dev, &tty);
888 tcgetattr(dev, &old);
889 cfsetospeed(&tty, B0);
890 cfsetispeed(&tty, B0);
891 tcsetattr(dev, TCSANOW, &tty);
892
893 if(millisec) {
894 Thread::sleep(millisec);
895 tcsetattr(dev, TCSANOW, &old);
896 }
897#endif
898 }
899
900bool Serial::isPending(Pending pending, timeout_t timeout)
901{
902#ifdef _MSWINDOWS_
903 unsigned long dwError;
904 COMSTAT cs;
905
906 ClearCommError(dev, &dwError, &cs);
907
908 if(timeout == 0 || ((pending == pendingInput) && (0 != cs.cbInQue)) ||
909 ((pending == pendingOutput) && (0 != cs.cbOutQue)) || (pending == pendingError))
910 {
911 switch(pending) {
912 case pendingInput:
913 return (0 != cs.cbInQue);
914 case pendingOutput:
915 return (0 != cs.cbOutQue);
916 case pendingError:
917 return false;
918 }
919 }
920 else {
921 OVERLAPPED ol;
922 DWORD dwMask;
923 DWORD dwEvents = 0;
924 BOOL suc;
925
926 memset(&ol, 0, sizeof(OVERLAPPED));
927 ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
928
929 if(pending == pendingInput)
930 dwMask = EV_RXCHAR;
931 else if(pending == pendingOutput)
932 dwMask = EV_TXEMPTY;
933 else // on error
934 dwMask = EV_ERR;
935
936 SetCommMask(dev, dwMask);
937 // let's wait for event or timeout
938 if((suc = WaitCommEvent(dev, &dwEvents, &ol)) == FALSE) {
939 if(GetLastError() == ERROR_IO_PENDING) {
940 DWORD transferred;
941
942 dwError = WaitForSingleObject(ol.hEvent, timeout);
943 if (dwError != WAIT_OBJECT_0)
944 SetCommMask(dev, 0);
945
946 suc = GetOverlappedResult(dev, &ol, &transferred, TRUE);
947 if (suc)
948 suc = (dwEvents & dwMask) ? TRUE : FALSE;
949 }
950 else
951 ClearCommError(dev, &dwError, &cs);
952 }
953
954 if(ol.hEvent != INVALID_HANDLE_VALUE)
955 CloseHandle(ol.hEvent);
956
957 if(suc == FALSE)
958 return false;
959 return true;
960 }
961#else
962
963
964 int status = 0;
965#ifdef HAVE_POLL
966 struct pollfd pfd;
967
968 pfd.fd = dev;
969 pfd.revents = 0;
970 switch(pending) {
971 case pendingInput:
972 pfd.events = POLLIN;
973 break;
974 case pendingOutput:
975 pfd.events = POLLOUT;
976 break;
977 case pendingError:
978 pfd.events = POLLERR | POLLHUP;
979 break;
980 }
981
982 status = 0;
983 while(status < 1) {
984 if(timeout == TIMEOUT_INF)
985 status = poll(&pfd, 1, -1);
986 else
987 status = poll(&pfd, 1, timeout);
988
989 if(status < 1) {
990 if(status == -1 && errno == EINTR)
991 continue;
992 return false;
993 }
994 }
995
996 if(pfd.revents & pfd.events)
997 return true;
998
999#else
1000 struct timeval tv;
1001 fd_set grp;
1002 struct timeval *tvp = &tv;
1003
1004 if(timeout == TIMEOUT_INF)
1005 tvp = NULL;
1006 else {
1007 tv.tv_usec = (timeout % 1000) * 1000;
1008 tv.tv_sec = timeout / 1000;
1009 }
1010
1011 FD_ZERO(&grp);
1012 FD_SET(dev, &grp);
1013 switch(pending) {
1014 case pendingInput:
1015 status = select(dev + 1, &grp, NULL, NULL, tvp);
1016 break;
1017 case pendingOutput:
1018 status = select(dev + 1, NULL, &grp, NULL, tvp);
1019 break;
1020 case pendingError:
1021 status = select(dev + 1, NULL, NULL, &grp, tvp);
1022 break;
1023 }
1024 if(status < 1)
1025 return false;
1026
1027 if(FD_ISSET(dev, &grp))
1028 return true;
1029
1030#endif
1031
1032#endif // WIN32
1033
1034 return false;
1035 }
1036
1037
1038
1039
1040
1041TTYStream::TTYStream(const char *filename, timeout_t to)
1042 : streambuf(),
1043 Serial(filename),
1044#ifdef HAVE_OLD_IOSTREAM
1045 iostream()
1046#else
1047 iostream((streambuf *)this)
1048#endif
1049{
1050#ifdef HAVE_OLD_IOSTREAM
1051 init((streambuf *)this);
1052#endif
1053 gbuf = pbuf = NULL;
1054 timeout = to;
1055
1056 if(INVALID_HANDLE_VALUE != dev)
1057 allocate();
1058 }
1059
1060TTYStream::TTYStream()
1061 : streambuf(),
1062 Serial(),
1063#ifdef HAVE_OLD_IOSTREAM
1064 iostream()
1065#else
1066 iostream((streambuf *)this)
1067#endif
1068{
1069#ifdef HAVE_OLD_IOSTREAM
1070 init((streambuf *)this);
1071#endif
1072 timeout = 0;
1073 gbuf = pbuf = NULL;
1074 }
1075
1076TTYStream::~TTYStream()
1077{
1078 endStream();
1079 endSerial();
1080 }
1081
1082void TTYStream::endStream(void)
1083{
1084 if(bufsize)
1085 sync();
1086
1087 if(gbuf) {
1088 delete[] gbuf;
1089 gbuf = NULL;
1090 }
1091 if(pbuf) {
1092 delete[] pbuf;
1093 pbuf = NULL;
1094 }
1095 bufsize = 0;
1096 clear();
1097 }
1098
1099void TTYStream::allocate(void)
1100{
1101 if(INVALID_HANDLE_VALUE == dev)
1102 return;
1103
1104#ifdef _PC_MAX_INPUT
1105 bufsize = fpathconf(dev, _PC_MAX_INPUT);
1106#else
1107 bufsize = MAX_INPUT;
1108#endif
1109
1110 gbuf = new char[bufsize];
1111 pbuf = new char[bufsize];
1112
1113 if(!pbuf || !gbuf) {
1114 error(errResourceFailure);
1115 return;
1116 }
1117
1118 clear();
1119
1120#if !(defined(STLPORT) || defined(__KCC))
1121 setg(gbuf, gbuf + bufsize, 0);
1122#endif
1123
1124 setg(gbuf, gbuf + bufsize, gbuf + bufsize);
1125 setp(pbuf, pbuf + bufsize);
1126 }
1127
1128int TTYStream::doallocate()
1129{
1130 if(bufsize)
1131 return 0;
1132
1133 allocate();
1134 return 1;
1135 }
1136
1137void TTYStream::interactive(bool iflag)
1138{
1139#ifdef _MSWINDOWS_
1140 if(dev == INVALID_HANDLE_VALUE)
1141#else
1142 if(dev < 0)
1143#endif
1144 return;
1145
1146 if(bufsize >= 1)
1147 endStream();
1148
1149 if(iflag) {
1150 // setting to unbuffered mode
1151
1152 bufsize = 1;
1153 gbuf = new char[bufsize];
1154
1155#if !(defined(STLPORT) || defined(__KCC))
1156#if defined(__GNUC__) && (__GNUC__ < 3)
1157 setb(0,0);
1158#endif
1159#endif
1160 setg(gbuf, gbuf+bufsize, gbuf+bufsize);
1161 setp(pbuf, pbuf);
1162 return;
1163 }
1164
1165 if(bufsize < 2)
1166 allocate();
1167 }
1168
1169int TTYStream::uflow(void)
1170{
1171 int rlen;
1172 unsigned char ch;
1173
1174 if(bufsize < 2) {
1175 if(timeout) {
1176 if(Serial::isPending(pendingInput, timeout))
1177 rlen = aRead((char *)&ch, 1);
1178 else
1179 rlen = -1;
1180 }
1181 else
1182 rlen = aRead((char *)&ch, 1);
1183 if(rlen < 1) {
1184 if(rlen < 0)
1185 clear(ios::failbit | rdstate());
1186 return EOF;
1187 }
1188 return ch;
1189 }
1190 else {
1191 ch = underflow();
1192 gbump(1);
1193 return ch;
1194 }
1195 }
1196
1197int TTYStream::underflow(void)
1198{
1199 ssize_t rlen = 1;
1200
1201 if(!gptr())
1202 return EOF;
1203
1204 if(gptr() < egptr())
1205 return (unsigned char)*gptr();
1206
1207 rlen = (ssize_t)((gbuf + bufsize) - eback());
1208 if(timeout && !Serial::isPending(pendingInput, timeout))
1209 rlen = -1;
1210 else
1211 rlen = aRead((char *)eback(), rlen);
1212
1213 if(rlen < 1) {
1214 if(rlen < 0) {
1215 clear(ios::failbit | rdstate());
1216 error(errInput);
1217 }
1218 return EOF;
1219 }
1220
1221 setg(eback(), eback(), eback() + rlen);
1222 return (unsigned char) *gptr();
1223 }
1224
1225int TTYStream::sync(void)
1226{
1227 if(bufsize > 1 && pbase() && ((pptr() - pbase()) > 0)) {
1228 overflow(0);
1229 waitOutput();
1230 setp(pbuf, pbuf + bufsize);
1231 }
1232 setg(gbuf, gbuf + bufsize, gbuf + bufsize);
1233 return 0;
1234 }
1235
1236int TTYStream::overflow(int c)
1237{
1238 unsigned char ch;
1239 ssize_t rlen, req;
1240
1241 if(bufsize < 2) {
1242 if(c == EOF)
1243 return 0;
1244
1245 ch = (unsigned char)(c);
1246 rlen = aWrite((char *)&ch, 1);
1247 if(rlen < 1) {
1248 if(rlen < 0)
1249 clear(ios::failbit | rdstate());
1250 return EOF;
1251 }
1252 else
1253 return c;
1254 }
1255
1256 if(!pbase())
1257 return EOF;
1258
1259 req = (ssize_t)(pptr() - pbase());
1260 if(req) {
1261 rlen = aWrite((char *)pbase(), req);
1262 if(rlen < 1) {
1263 if(rlen < 0)
1264 clear(ios::failbit | rdstate());
1265 return EOF;
1266 }
1267 req -= rlen;
1268 }
1269
1270 if(req)
1271// memmove(pptr(), pptr() + rlen, req);
1272 memmove(pbuf, pbuf + rlen, req);
1273 setp(pbuf + req, pbuf + bufsize);
1274
1275 if(c != EOF) {
1276 *pptr() = (unsigned char)c;
1277 pbump(1);
1278 }
1279 return c;
1280 }
1281
1282bool TTYStream::isPending(Pending pending, timeout_t timer)
1283{
1284// if(pending == pendingInput && in_avail())
1285// return true;
1286// else if(pending == pendingOutput)
1287// flush();
1288
1289 return Serial::isPending(pending, timer);
1290 }
1291
1292
1293
1294
1295
1296
1297ttystream::ttystream() :
1298TTYStream()
1299{
1300 setError(false);
1301 }
1302
1303ttystream::ttystream(const char *name) :
1304TTYStream()
1305{
1306 setError(false);
1307 open(name);
1308 }
1309
1310void ttystream::close(void)
1311{
1312#ifdef _MSWINDOWS_
1313 if (INVALID_HANDLE_VALUE == dev)
1314#else
1315 if(dev < 0)
1316#endif
1317 return;
1318
1319 endStream();
1320 restore();
1321 TTYStream::close();
1322 }
1323
1324void ttystream::open(const char *name)
1325{
1326 const char *cpp;
1327 char *cp;
1328 char pathname[256];
1329 size_t namelen;
1330 long opt;
1331
1332 if (INVALID_HANDLE_VALUE != dev) {
1333 restore();
1334 close();
1335 }
1336
1337 cpp = strrchr(name, ':');
1338 if(cpp)
1339 namelen = cpp - name;
1340 else
1341 namelen = strlen(name);
1342
1343 cp = pathname;
1344
1345#ifndef _MSWINDOWS_
1346 if(*name != '/') {
1347 strcpy(pathname, "/dev/");
1348 cp += 5;
1349 }
1350
1351 if((cp - pathname) + namelen > 255) {
1352 error(errResourceFailure);
1353 return;
1354 }
1355#endif
1356 setString(cp, pathname - cp + sizeof(pathname), name);
1357 cp += namelen;
1358#ifdef _MSWINDOWS_
1359 *cp++ = ':';
1360#endif
1361 *cp = 0;
1362
1363 Serial::open(pathname);
1364
1365 if(INVALID_HANDLE_VALUE == dev) {
1366 error(errOpenFailed);
1367 return;
1368 }
1369
1370 allocate();
1371
1372 setString(pathname, sizeof(pathname), name + namelen);
1373 cp = pathname + 1;
1374
1375 if(*pathname == ':')
1376 cp = strtok(cp, ",");
1377 else
1378 cp = NULL;
1379
1380 while(cp) {
1381 switch(*cp) {
1382 case 'h':
1383 case 'H':
1384 setFlowControl(flowHard);
1385 break;
1386 case 's':
1387 case 'S':
1388 setFlowControl(flowSoft);
1389 break;
1390 case 'b':
1391 case 'B':
1392 setFlowControl(flowBoth);
1393 break;
1394 case 'n':
1395 case 'N':
1396 setParity(parityNone);
1397 break;
1398 case 'O':
1399 case 'o':
1400 setParity(parityOdd);
1401 break;
1402 case 'e':
1403 case 'E':
1404 setParity(parityEven);
1405 break;
1406 case '0':
1407 case '1':
1408 case '2':
1409 case '3':
1410 case '4':
1411 case '5':
1412 case '6':
1413 case '7':
1414 case '8':
1415 case '9':
1416 opt = atol(cp);
1417 if(opt == 1 || opt == 2) {
1418 setStopBits((int)opt);
1419 break;
1420 }
1421 if(opt > 4 && opt < 9) {
1422 setCharBits((int)opt);
1423 break;
1424 }
1425 setSpeed(opt);
1426 break;
1427 default:
1428 error(errOptionInvalid);
1429 }
1430 cp = strtok(NULL, ",");
1431 }
1432 }
1433
1434TTYSession::TTYSession(const char *filename, int pri, int stack) :
1435Thread(pri, stack), TTYStream(filename)
1436{
1437 setError(false);
1438 }
1439
1440
1441TTYSession::~TTYSession()
1442{
1443 terminate();
1444 endSerial();
1445 }
1446
1447#ifndef _MSWINDOWS_
1448// Not supporting this right now........
1449//
1450
1451SerialPort::SerialPort(SerialService *svc, const char *name) :
1452Serial(name),
1453detect_pending(true),
1454detect_output(false),
1455detect_disconnect(true)
1456{
1457 next = prev = NULL;
1458 service = NULL;
1459
1460#ifdef _MSWINDOWS_
1461 if(INVALID_HANDLE_VALUE != dev)
1462#else
1463 if(dev > -1)
1464#endif
1465 {
1466 setError(false);
1467 service = svc;
1468 svc->attach(this);
1469 }
1470 }
1471
1472SerialPort::~SerialPort()
1473{
1474 if(service)
1475 service->detach(this);
1476
1477 endSerial();
1478 }
1479
1480void SerialPort::expired(void)
1481{
1482 }
1483
1484void SerialPort::pending(void)
1485{
1486 }
1487
1488void SerialPort::disconnect(void)
1489{
1490 }
1491
1492void SerialPort::output(void)
1493{
1494 }
1495
1496void SerialPort::setTimer(timeout_t ptimer)
1497{
1498 TimerPort::setTimer(ptimer);
1499 service->update();
1500 }
1501
1502void SerialPort::incTimer(timeout_t ptimer)
1503{
1504 TimerPort::incTimer(ptimer);
1505 service->update();
1506 }
1507
1508
1509void SerialPort::setDetectPending( bool val )
1510{
1511 if ( detect_pending != val ) {
1512 detect_pending = val;
1513#ifdef USE_POLL
1514 if ( ufd ) {
1515 if ( val ) {
1516 ufd->events |= POLLIN;
1517 } else {
1518 ufd->events &= ~POLLIN;
1519 }
1520 }
1521#endif
1522 service->update();
1523 }
1524 }
1525
1526void SerialPort::setDetectOutput( bool val )
1527{
1528 if ( detect_output != val ) {
1529 detect_output = val;
1530#ifdef USE_POLL
1531 if ( ufd ) {
1532 if ( val ) {
1533 ufd->events |= POLLOUT;
1534 } else {
1535 ufd->events &= ~POLLOUT;
1536 }
1537 }
1538#endif
1539 service->update();
1540 }
1541 }
1542
1543
1544SerialService::SerialService(int pri, size_t stack, const char *id) :
1545Thread(pri, stack), Mutex()
1546{
1547 long opt;
1548
1549 first = last = NULL;
1550 count = 0;
1551 FD_ZERO(&connect);
1552 if(::pipe(iosync)) {
1553#ifdef CCXX_EXCEPTIONS
1554 switch(Thread::getException()) {
1555 case throwObject:
1556 throw(this);
1557 return;
1558#ifdef COMMON_STD_EXCEPTION
1559 case throwException:
1560 throw(ThrException("no service pipe"));
1561 return;
1562#endif
1563 default:
1564 return;
1565 }
1566#else
1567 return;
1568#endif
1569 }
1570 hiwater = iosync[0] + 1;
1571 FD_SET(iosync[0], &connect);
1572
1573 opt = fcntl(iosync[0], F_GETFL);
1574 fcntl(iosync[0], F_SETFL, opt | O_NDELAY);
1575 }
1576
1577SerialService::~SerialService()
1578{
1579 update(0);
1580 terminate();
1581
1582 while(first)
1583 delete first;
1584 }
1585
1586void SerialService::onUpdate(unsigned char flag)
1587{
1588 }
1589
1590void SerialService::onEvent(void)
1591{
1592 }
1593
1594void SerialService::onCallback(SerialPort *port)
1595{
1596 }
1597
1598void SerialService::attach(SerialPort *port)
1599{
1600 enterMutex();
1601#ifdef USE_POLL
1602 port->ufd = 0;
1603#endif
1604 if(last)
1605 last->next = port;
1606
1607 port->prev = last;
1608 last = port;
1609 FD_SET(port->dev, &connect);
1610 if(port->dev >= hiwater)
1611 hiwater = port->dev + 1;
1612
1613 if(!first) {
1614 first = port;
1615 leaveMutex();
1616 ++count;
1617 start();
1618 }
1619 else {
1620 leaveMutex();
1621 update();
1622 ++count;
1623 }
1624 }
1625
1626void SerialService::detach(SerialPort *port)
1627{
1628 enterMutex();
1629
1630#ifndef USE_POLL
1631 FD_CLR(port->dev, &connect);
1632#endif
1633
1634 if(port->prev)
1635 port->prev->next = port->next;
1636 else
1637 first = port->next;
1638
1639 if(port->next)
1640 port->next->prev = port->prev;
1641 else
1642 last = port->prev;
1643
1644 --count;
1645 leaveMutex();
1646 update();
1647 }
1648
1649void SerialService::update(unsigned char flag)
1650{
1651 if(::write(iosync[1], (char *)&flag, 1) < 1) {
1652
1653#ifdef CCXX_EXCEPTIONS
1654 switch(Thread::getException()) {
1655 case throwObject:
1656 throw(this);
1657 return;
1658#ifdef COMMON_STD_EXCEPTION
1659 case throwException:
1660 throw(ThrException("update failed"));
1661 return;
1662#endif
1663 default:
1664 return;
1665 }
1666#else
1667 return;
1668#endif
1669 }
1670 }
1671
1672
1673void SerialService::run(void)
1674{
1675 timeout_t timer, expires;
1676 SerialPort *port;
1677 unsigned char buf;
1678
1679#ifdef USE_POLL
1680
1681 Poller mfd;
1682 pollfd *p_ufd;
1683 int lastcount = 0;
1684
1685 // initialize ufd in all attached ports :
1686 // probably don't need this but it can't hurt.
1687 enterMutex();
1688 port = first;
1689 while(port) {
1690 port->ufd = 0;
1691 port = port->next;
1692 }
1693 leaveMutex();
1694
1695#else
1696 struct timeval timeout, *tvp;
1697 fd_set inp, out, err;
1698 int dev;
1699 FD_ZERO(&inp);
1700 FD_ZERO(&out);
1701 FD_ZERO(&err);
1702#endif
1703
1704 for(;;) {
1705 timer = TIMEOUT_INF;
1706 while(1 == ::read(iosync[0], (char *)&buf, 1)) {
1707 if(buf) {
1708 onUpdate(buf);
1709 continue;
1710 }
1711
1712 Thread::exit();
1713 }
1714
1715#ifdef USE_POLL
1716
1717 bool reallocate = false;
1718
1719 enterMutex();
1720 onEvent();
1721 port = first;
1722 while(port) {
1723 onCallback(port);
1724 if ( ( p_ufd = port->ufd ) ) {
1725
1726 if ( ( POLLHUP | POLLNVAL ) & p_ufd->revents ) {
1727 // Avoid infinite loop from disconnected sockets
1728 port->detect_disconnect = false;
1729 p_ufd->events &= ~POLLHUP;
1730 port->disconnect();
1731 }
1732
1733 if ( ( POLLIN | POLLPRI ) & p_ufd->revents )
1734 port->pending();
1735
1736 if ( POLLOUT & p_ufd->revents )
1737 port->output();
1738
1739 } else {
1740 reallocate = true;
1741 }
1742
1743retry:
1744 expires = port->getTimer();
1745 if(expires > 0)
1746 if(expires < timer)
1747 timer = expires;
1748
1749 if(!expires) {
1750 port->endTimer();
1751 port->expired();
1752 goto retry;
1753 }
1754
1755 port = port->next;
1756 }
1757
1758 //
1759 // reallocate things if we saw a ServerPort without
1760 // ufd set !
1761 if ( reallocate || ( ( count + 1 ) != lastcount ) ) {
1762 lastcount = count + 1;
1763 p_ufd = mfd.getList( count + 1 );
1764
1765 // Set up iosync polling
1766 p_ufd->fd = iosync[0];
1767 p_ufd->events = POLLIN | POLLHUP;
1768 p_ufd ++;
1769
1770 port = first;
1771 while(port) {
1772 p_ufd->fd = port->dev;
1773 p_ufd->events =
1774 ( port->detect_disconnect ? POLLHUP : 0 )
1775 | ( port->detect_output ? POLLOUT : 0 )
1776 | ( port->detect_pending ? POLLIN : 0 )
1777 ;
1778 port->ufd = p_ufd;
1779 p_ufd ++;
1780 port = port->next;
1781 }
1782 }
1783 leaveMutex();
1784
1785 poll( mfd.getList(), count + 1, timer );
1786
1787#else
1788 enterMutex();
1789 onEvent();
1790 port = first;
1791
1792 while(port) {
1793 onCallback(port);
1794 dev = port->dev;
1795 if(FD_ISSET(dev, &err)) {
1796 port->detect_disconnect = false;
1797 port->disconnect();
1798 }
1799
1800 if(FD_ISSET(dev, &inp))
1801 port->pending();
1802
1803 if(FD_ISSET(dev, &out))
1804 port->output();
1805
1806retry:
1807 expires = port->getTimer();
1808 if(expires > 0)
1809 if(expires < timer)
1810 timer = expires;
1811
1812 if(!expires) {
1813 port->endTimer();
1814 port->expired();
1815 goto retry;
1816 }
1817
1818 port = port->next;
1819 }
1820
1821 FD_ZERO(&inp);
1822 FD_ZERO(&out);
1823 FD_ZERO(&err);
1824 int so;
1825 port = first;
1826 while(port) {
1827 so = port->dev;
1828
1829 if(port->detect_pending)
1830 FD_SET(so, &inp);
1831
1832 if(port->detect_output)
1833 FD_SET(so, &out);
1834
1835 if(port->detect_disconnect)
1836 FD_SET(so, &err);
1837
1838 port = port->next;
1839 }
1840
1841 leaveMutex();
1842 if(timer == TIMEOUT_INF)
1843 tvp = NULL;
1844 else {
1845 tvp = &timeout;
1846 timeout.tv_sec = timer / 1000;
1847 timeout.tv_usec = (timer % 1000) * 1000;
1848 }
1849 select(hiwater, &inp, &out, &err, tvp);
1850#endif
1851 }
1852 }
1853
1854#endif
1855
1856END_NAMESPACE
1857
1858/** EMACS **
1859 * Local variables:
1860 * mode: c++
1861 * c-basic-offset: 8
1862 * End:
1863 */