This patch depends upon patches committed on "dev-bcb6-arm" branch between revision tags "dev-bcb6-arm-0052" and "dev-bcb6-arm-0055".
This patch modifies the following files: ChangeLog include/cc++/serial.h src/serial.cpp This patch is committed on "dev-bcb6-arm" branch between revision tags "dev-bcb6-arm-0055" and "dev-bcb6-arm-0056". Index: ChangeLog =================================================================== RCS file: /cvsroot/gnutelephony/testing/commoncpp2/ChangeLog,v retrieving revision 1.18.2.5 retrieving revision 1.18.2.6 diff -u -p -r1.18.2.5 -r1.18.2.6 --- ChangeLog 11 Sep 2005 04:45:01 -0000 1.18.2.5 +++ ChangeLog 11 Sep 2005 07:04:20 -0000 1.18.2.6 @@ -1,4 +1,5 @@ From Common C++ 1.3.18 to 1.3.19 +- add Serial::AnyPending enumeration and Serial::anyPending method - fix Win32 CreateEvent returns NULL on failure, not INVALID_HANDLE_VALUE - fix indentation error in WIN32 aRead method - fix WIN32 aRead buffer overflow when Length < available data Index: include/cc++/serial.h =================================================================== RCS file: /cvsroot/gnutelephony/testing/commoncpp2/include/cc++/serial.h,v retrieving revision 1.1.1.1.2.1 retrieving revision 1.1.1.1.2.2 diff -u -p -r1.1.1.1.2.1 -r1.1.1.1.2.2 --- include/cc++/serial.h 7 Sep 2005 19:01:20 -0000 1.1.1.1.2.1 +++ include/cc++/serial.h 11 Sep 2005 07:04:20 -0000 1.1.1.1.2.2 @@ -141,6 +141,25 @@ public: }; typedef enum Pending Pending; + enum AnyPending + { + // 1 taken 0 at a time + anyPendingNone = 0, + // 3 taken 1 at a time + anyPendingInput = 1 << pendingInput, + anyPendingOutput = 1 << pendingOutput, + anyPendingError = 1 << pendingError, + // 3 taken 2 at a time + anyPendingInputOutput = anyPendingInput | anyPendingOutput, + anyPendingInputError = anyPendingInput | anyPendingError, + anyPendingOutputError = anyPendingOutput | anyPendingError, + // 1 taken 3 at a time + anyPendingInputOutputError = anyPendingInput | anyPendingOutput | anyPendingError, + // synonyms + anyPendingAll = anyPendingInputOutputError + }; + typedef enum AnyPending AnyPending; + private: Error errid; const char *errstr; @@ -397,6 +416,17 @@ public: virtual size_t getBufferSize(void); /** + * Get the status of specified pending operations. This can be used to + * examine if input is waiting, if output is ready or if an error has + * occured on the serial device. + * + * @return AnyPending enumeration value. + * @param pendingMask check or checks to perform. + * @param timeout in milliseconds. + */ + virtual AnyPending anyPending(const AnyPending pendingMask, const timeout_t timeout = TIMEOUT_INF); + + /** * Get the status of pending operations. This can be used to * examine if input or output is waiting, or if an error has * occured on the serial device. Index: src/serial.cpp =================================================================== RCS file: /cvsroot/gnutelephony/testing/commoncpp2/src/serial.cpp,v retrieving revision 1.1.1.1.2.5 retrieving revision 1.1.1.1.2.6 diff -u -p -r1.1.1.1.2.5 -r1.1.1.1.2.6 --- src/serial.cpp 11 Sep 2005 04:45:01 -0000 1.1.1.1.2.5 +++ src/serial.cpp 11 Sep 2005 07:04:20 -0000 1.1.1.1.2.6 @@ -936,6 +936,226 @@ size_t Serial::getBufferSize(void) return maxsize; } +#if !defined(WIN32) && !defined(HAVE_POLL) +static fd_set *fd_set_init( fd_set *pfd_set, const HANDLE dev, + const Serial::AnyPending pendingMask, + const Serial::AnyPending pendingSelect + ) +{ + if(pendingMask & pendingSelect) + { + FD_ZERO(pfd_set); FD_SET(dev, pfd_set); + return pfd_set; + } + + return NULL; +} +#endif // !defined(WIN32) && !defined(HAVE_POLL) + +Serial::AnyPending Serial::anyPending(const AnyPending pendingMask, const timeout_t timeout) +{ + if(pendingMask == anyPendingNone) + return anyPendingNone; + + int isPending = anyPendingNone; + +#ifdef WIN32 + static const DWORD dwErrorMask = CE_FRAME | CE_IOE | CE_OVERRUN | CE_RXOVER | CE_RXPARITY | CE_TXFULL; + DWORD dwError; + COMSTAT cs; + + ClearCommError(dev, &dwError, &cs); + + if(dwError & dwErrorMask) + isPending |= anyPendingError; + + if(cs.cbInQue) + isPending |= anyPendingInput; + + if ( + ((isPending & pendingMask) == anyPendingNone) + || + ((pendingMask & anyPendingOutput) && (timeout == 0)) + ) + { + OVERLAPPED ol; + DWORD dwLastError, dwCommMask, dwCommMaskSaved, dwCommEvent = 0; + BOOL restoreMask; + + dwCommMask = 0; + if(pendingMask & anyPendingError) + dwCommMask |= EV_ERR; + if(pendingMask & anyPendingInput) + dwCommMask |= EV_RXCHAR | EV_RXFLAG; + if(pendingMask & anyPendingOutput) + dwCommMask |= EV_TXEMPTY; + + Thread::Cancel save = Thread::enterCancel(); + + if(! overlapped_init(&ol)) + dwLastError = GetLastError(); + else + if(! (restoreMask = GetCommMask(dev, &dwCommMaskSaved))) + dwLastError = GetLastError(); + else + if(! SetCommMask(dev, dwCommMask)) + dwLastError = GetLastError(); + else // let's wait for event or timeout + if(! WaitCommEvent(dev, &dwCommEvent, &ol)) + { + dwLastError = GetLastError(); + + if(dwLastError == ERROR_IO_PENDING) + { + DWORD dwActualLength; + + dwError = WaitForSingleObject(ol.hEvent, timeout); + switch(dwError) + { + case WAIT_OBJECT_0: + // dwCommEvent is valid only after GetOverlappedResult succeeds + if(GetOverlappedResult(dev, &ol, &dwActualLength, TRUE)) + dwLastError = NO_ERROR; + else + dwLastError = GetLastError(); + break; + + case WAIT_ABANDONED: + case WAIT_TIMEOUT: + dwLastError = ERROR_TIMEOUT; + CancelIo(dev); + break; + + case WAIT_FAILED: + dwLastError = GetLastError(); + CancelIo(dev); + break; + + default: + dwLastError = ~NO_ERROR; + CancelIo(dev); + } + } + } + else + dwLastError = NO_ERROR; + + if(restoreMask) + SetCommMask(dev, dwCommMaskSaved); + + overlapped_fini(&ol); + + switch(dwLastError) + { + case NO_ERROR: + + if(dwCommEvent & EV_ERR) + isPending |= anyPendingError; + + if(dwCommEvent & (EV_RXCHAR | EV_RXFLAG)) + isPending |= anyPendingInput; + + if(dwCommEvent & EV_TXEMPTY) + isPending |= anyPendingOutput; + + break; + + case ERROR_TIMEOUT: + break; + + default: + isPending |= anyPendingError; + } + + ClearCommError(dev, &dwError, &cs); + + if(dwError & dwErrorMask) + isPending |= anyPendingError; + + if(cs.cbInQue) + isPending |= anyPendingInput; + + Thread::exitCancel(save); + } +#else // WIN32 + + int status; +#ifdef HAVE_POLL + struct pollfd pfd; + int polltimeout; + + if(timeout == TIMEOUT_INF) + polltimeout = -1; + else + polltimeout = timeout; + + do { + pfd.fd = dev; + pfd.revents = 0; + pfd.events = 0; + if(pendingMask & anyPendingError) + pfd.events |= POLLERR | POLLHUP; + if(pendingMask & anyPendingInput) + pfd.events |= POLLIN | POLLPRI; + if(pendingMask & anyPendingOutput) + pfd.events |= POLLOUT; + + status = poll(&pfd, 1, polltimeout); + } while(status == -1 && errno == EINTR); + + if(status == -1) + isPending |= anyPendingError; + else + if(status > 0) + { + if(pfd.revents & (POLLERR | POLLHUP)) + isPending |= anyPendingError; + + if(pfd.revents & (POLLIN | POLLPRI)) + isPending |= anyPendingInput; + + if(pfd.revents & POLLOUT) + isPending |= anyPendingOutput; + } +#else // HAVE_POLL + struct timeval tv, *tvp; + fd_set egrp, *egrpp, rgrp, *rgrpp, wgrp, *wgrpp; + + if(timeout != TIMEOUT_INF) + { + tv.tv_usec = (timeout % 1000) * 1000; + tv.tv_sec = timeout / 1000; + tvp = &tv; + } + else + tvp = NULL; + + egrpp = fd_set_init(&egrp, dev, pendingMask, anyPendingError); + rgrpp = fd_set_init(&rgrp, dev, pendingMask, anyPendingInput); + wgrpp = fd_set_init(&wgrp, dev, pendingMask, anyPendingOutput); + + status = select(dev + 1, rgrpp, wgrpp, egrpp, tvp); + + if(status == -1) + isPending |= anyPendingError; + else + if(status > 0) + { + if(egrpp && FD_ISSET(dev, egrpp)) + isPending |= anyPendingError; + + if(rgrpp && FD_ISSET(dev, rgrpp)) + isPending |= anyPendingInput; + + if(wgrpp && FD_ISSET(dev, wgrpp)) + isPending |= anyPendingOutput; + } +#endif // HAVE_POLL +#endif // WIN32 + + return (AnyPending) isPending; +} + bool Serial::isPending(Pending pending, timeout_t timeout) { #ifdef WIN32 _______________________________________________ Bug-commoncpp mailing list Bug-commoncpp@gnu.org http://lists.gnu.org/mailman/listinfo/bug-commoncpp