bug-commoncpp
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Patch: Add Serial::AnyPending enumeration and Serial::anyPending method


From: Conrad T. Pino
Subject: Patch: Add Serial::AnyPending enumeration and Serial::anyPending method
Date: Sun, 11 Sep 2005 01:00:34 -0700

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]