예제 #1
0
        internal BufferedPipeThread(WinUSBDevice dev, byte pipeId, int bufferCount, int bufferSize)
        {
            Device       = dev;
            DevicePipeId = pipeId;
            int maxTransferSize = (int)dev.GetPipePolicy(pipeId, WinUsbPipePolicy.MAXIMUM_TRANSFER_SIZE);

            if (bufferSize > maxTransferSize)
            {
                bufferSize = maxTransferSize;
            }

            Buffers    = new QueuedBuffer[bufferCount];
            ReadEvents = new ManualResetEvent[bufferCount + 1];
            for (int i = 0; i < bufferCount; i++)
            {
                Buffers[i]    = new QueuedBuffer(bufferSize);
                ReadEvents[i] = Buffers[i].Overlapped.WaitEvent;
            }
            StopEvent = new ManualResetEvent(false);
            ReadEvents[bufferCount] = StopEvent;

            PipeThread = new Thread(ThreadFunc);
            PipeThread.IsBackground = true;

            foreach (QueuedBuffer qb in Buffers)
            {
                Device.BeginReadPipe(pipeId, qb);
            }
            PipeThread.Start();
        }
예제 #2
0
        // Asynchronous read bits, only for use with buffered reader for now.
        internal void BeginReadPipe(byte pipeId, QueuedBuffer buffer)
        {
            buffer.Overlapped.WaitEvent.Reset();

            if (!NativeMethods.WinUsb_ReadPipe(WinusbHandle, pipeId, buffer.PinnedBuffer, (uint)buffer.BufferSize, IntPtr.Zero, buffer.Overlapped.OverlappedStruct))
            {
                if (Marshal.GetLastWin32Error() != NativeMethods.ERROR_IO_PENDING)
                {
                    throw new Exception("ReadPipe failed. " + (new Win32Exception()).ToString());
                }
            }
        }
예제 #3
0
 private void EndReadingBuffer(QueuedBuffer buf)
 {
     if (Device.EndReadPipe(buf))
     {
         PipeReadReceivedSub.OnNext(buf.GetBufferCopy());
         buf.Overlapped.WaitEvent.Reset();
         Device.BeginReadPipe(DevicePipeId, buf);
     }
     else
     {
         //read failed due timeout
         //todo handle this case
         //use PipeReadExceptionSub??
     }
 }
예제 #4
0
        internal bool EndReadPipe(QueuedBuffer buf)
        {
            UInt32 transferSize;

            if (!NativeMethods.WinUsb_GetOverlappedResult(WinusbHandle, buf.Overlapped.OverlappedStruct, out transferSize, true))
            {
                if (Marshal.GetLastWin32Error() == NativeMethods.ERROR_SEM_TIMEOUT)
                {
                    // This was a pipe timeout. Return an empty byte array to indicate this case.
                    //System.Diagnostics.Debug.WriteLine("Timed out");
                    return(false);
                }
                throw new Exception("ReadPipe's overlapped result failed. " + (new Win32Exception()).ToString());
            }
            buf.CompletedSize = (int)transferSize;
            return(true);
        }
예제 #5
0
        public BufferedPipeThread(WinUSBDevice dev, byte pipeId, int bufferCount, int bufferSize)
        {
            int maxTransferSize = (int)dev.GetPipePolicy(pipeId, WinUsbPipePolicy.MAXIMUM_TRANSFER_SIZE);

            if (bufferSize > maxTransferSize)
            {
                bufferSize = maxTransferSize;
            }

            BufferLock      = new object();
            PendingBuffers  = new Queue <QueuedBuffer>(bufferCount);
            ReceivedBuffers = new Queue <QueuedBuffer>(bufferCount);
            RequeuePending  = new Queue <QueuedBuffer>(bufferCount);
            BufferList      = new QueuedBuffer[bufferCount];
            for (int i = 0; i < bufferCount; i++)
            {
                BufferList[i] = new QueuedBuffer(bufferSize);
            }

            Device                    = dev;
            DevicePipeId              = pipeId;
            QueuedLength              = 0;
            ReceivedData              = new Queue <byte[]>();
            ReceiveTick               = new ManualResetEvent(false);
            PipeThread                = new Thread(ThreadFunc);
            PipeThread.IsBackground   = true;
            WorkerThread              = new Thread(WorkerThreadFunc);
            WorkerThread.IsBackground = true;
            ThreadNewData             = new AutoResetEvent(false);


            //dev.SetPipePolicy(pipeId, WinUsbPipePolicy.PIPE_TRANSFER_TIMEOUT, 1000);

            // Start reading on all the buffers.
            foreach (QueuedBuffer qb in BufferList)
            {
                dev.BeginReadPipe(pipeId, qb);
                PendingBuffers.Enqueue(qb);
            }

            //dev.SetPipePolicy(pipeId, WinUsbPipePolicy.RAW_IO, 1);

            PipeThread.Start();
            WorkerThread.Start();
        }
예제 #6
0
        public BufferedPipeThread(WinUSBDevice dev, byte pipeId, int bufferCount, int multiPacketCount)
        {
            int maxTransferSize = (int)dev.GetPipePolicy(pipeId, WinUsbPipePolicy.MAXIMUM_TRANSFER_SIZE);

            int pipeSize   = 512; // Todo: query pipe transfer size for 1:1 mapping to packets.
            int bufferSize = pipeSize * multiPacketCount;

            if (bufferSize > maxTransferSize)
            {
                bufferSize = maxTransferSize;
            }

            PendingBuffers = new Queue <QueuedBuffer>(bufferCount);
            BufferList     = new QueuedBuffer[bufferCount];
            for (int i = 0; i < bufferCount; i++)
            {
                BufferList[i] = new QueuedBuffer(bufferSize);
            }

            EventConcurrency        = new Semaphore(3, 3);
            Device                  = dev;
            DevicePipeId            = pipeId;
            QueuedLength            = 0;
            ReceivedData            = new Queue <byte[]>();
            ReceiveTick             = new ManualResetEvent(false);
            PipeThread              = new Thread(ThreadFunc);
            PipeThread.IsBackground = true;

            //dev.SetPipePolicy(pipeId, WinUsbPipePolicy.PIPE_TRANSFER_TIMEOUT, 1000);

            // Start reading on all the buffers.
            foreach (QueuedBuffer qb in BufferList)
            {
                dev.BeginReadPipe(pipeId, qb);
                PendingBuffers.Enqueue(qb);
            }

            //dev.SetPipePolicy(pipeId, WinUsbPipePolicy.RAW_IO, 1);

            PipeThread.Start();
        }
예제 #7
0
        public int ReadPacket(byte[] target, int offset)
        {
            QueuedBuffer buf = null;

            lock (BufferLock)
            {
                if (ReceivedBuffers.Count > 0)
                {
                    buf = ReceivedBuffers.Dequeue();
                }
                else
                {
                    return(0);
                }
            }
            int length = buf.CompletedSize;

            Marshal.Copy(buf.PinnedBuffer, target, offset, buf.CompletedSize);
            lock (RequeuePending)
            {
                RequeuePending.Enqueue(buf);
            }
            return(length);
        }
예제 #8
0
        void ThreadFunc(object context)
        {
            Queue <byte[]> receivedData = new Queue <byte[]>(BufferList.Length);

            while (true)
            {
                if (Device.Stopping)
                {
                    break;
                }

                try
                {
                    PendingBuffers.Peek().Wait();
                    // Process a large group of received buffers in a batch, if available.
                    int n = 0;
                    try
                    {
                        while (n < BufferList.Length)
                        {
                            QueuedBuffer buf = PendingBuffers.Peek();
                            if (n == 0 || buf.Ready)
                            {
                                byte[] data = Device.EndReadPipe(buf);
                                PendingBuffers.Dequeue();
                                if (data != null)
                                {   // null is a timeout condition.
                                    receivedData.Enqueue(data);
                                }
                                Device.BeginReadPipe(DevicePipeId, buf);
                                // Todo: If this operation fails during normal operation, the buffer is lost from rotation.
                                // Should never happen during normal operation, but should confirm and mitigate if it's possible.
                                PendingBuffers.Enqueue(buf);
                            }
                            n++;
                        }
                    }
                    finally
                    {
                        // Unless we're exiting, ensure we always indicate the data, even if some operation failed.
                        if (!Device.Stopping && receivedData.Count > 0)
                        {
                            lock (this)
                            {
                                foreach (byte[] data in receivedData)
                                {
                                    ReceivedData.Enqueue(data);
                                    QueuedLength  += data.Length;
                                    TotalReceived += data.Length;
                                }
                            }
                            ThreadPool.QueueUserWorkItem(RaiseNewData);
                            receivedData.Clear();
                        }
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.Print("Should not happen: Exception in background thread. {0}", ex.ToString());
                    Thread.Sleep(15);
                }

                ReceiveTick.Set();
            }
            Stopped = true;
        }
예제 #9
0
        public BufferedPipeThread(WinUSBDevice dev, byte pipeId, int bufferCount, int bufferSize)
        {


            int maxTransferSize = (int)dev.GetPipePolicy(pipeId, WinUsbPipePolicy.MAXIMUM_TRANSFER_SIZE);

            if (bufferSize > maxTransferSize) { bufferSize = maxTransferSize; }

            BufferLock = new object();
            PendingBuffers = new Queue<QueuedBuffer>(bufferCount);
            ReceivedBuffers = new Queue<QueuedBuffer>(bufferCount);
            RequeuePending = new Queue<QueuedBuffer>(bufferCount);
            BufferList = new QueuedBuffer[bufferCount];
            for (int i = 0; i < bufferCount;i++)
            {
                BufferList[i] = new QueuedBuffer(bufferSize);
            }

            Device = dev;
            DevicePipeId = pipeId;
            QueuedLength = 0;
            ReceivedData = new Queue<byte[]>();
            ReceiveTick = new ManualResetEvent(false);
            PipeThread = new Thread(ThreadFunc);
            PipeThread.IsBackground = true;
            WorkerThread = new Thread(WorkerThreadFunc);
            WorkerThread.IsBackground = true;
            ThreadNewData = new AutoResetEvent(false);


            //dev.SetPipePolicy(pipeId, WinUsbPipePolicy.PIPE_TRANSFER_TIMEOUT, 1000);

            // Start reading on all the buffers.
            foreach(QueuedBuffer qb in BufferList)
            {
                dev.BeginReadPipe(pipeId, qb);
                PendingBuffers.Enqueue(qb);
            }

            //dev.SetPipePolicy(pipeId, WinUsbPipePolicy.RAW_IO, 1);

            PipeThread.Start();
            WorkerThread.Start();
        }
예제 #10
0
        internal bool EndReadPipe(QueuedBuffer buf)
        {
            UInt32 transferSize;

            if (!NativeMethods.WinUsb_GetOverlappedResult(WinusbHandle, buf.Overlapped.OverlappedStruct, out transferSize, true))
            {
                if (Marshal.GetLastWin32Error() == NativeMethods.ERROR_SEM_TIMEOUT)
                {
                    // This was a pipe timeout. Return an empty byte array to indicate this case.
                    //System.Diagnostics.Debug.WriteLine("Timed out");
                    return false;
                }
                throw new Exception("ReadPipe's overlapped result failed. " + (new Win32Exception()).ToString());
            }
            buf.CompletedSize = (int)transferSize;
            return true;
        }
예제 #11
0
        // Asynchronous read bits, only for use with buffered reader for now.
        internal void BeginReadPipe(byte pipeId, QueuedBuffer buffer)
        {
            buffer.Overlapped.WaitEvent.Reset();

            if (!NativeMethods.WinUsb_ReadPipe(WinusbHandle, pipeId, buffer.PinnedBuffer, (uint)buffer.BufferSize, IntPtr.Zero, buffer.Overlapped.OverlappedStruct))
            {
                if (Marshal.GetLastWin32Error() != NativeMethods.ERROR_IO_PENDING)
                {
                    throw new Exception("ReadPipe failed. " + (new Win32Exception()).ToString());
                }
            }
        }
예제 #12
0
        void ThreadFunc(object context)
        {
            int recvBytes;

            while (true)
            {
                if (Device.Stopping)
                {
                    break;
                }

                try
                {
                    recvBytes = 0;
                    if (PendingBuffers.Count > 0)
                    {
                        PendingBuffers.Peek().Wait();
                    }
                    // Process a large group of received buffers in a batch, if available.
                    int  n        = 0;
                    bool shortcut = PendingBuffers.Count > 0;
                    try
                    {
                        lock (RequeuePending)
                        {
                            // Requeue buffers that were drained.
                            while (RequeuePending.Count > 0)
                            {
                                QueuedBuffer buf = RequeuePending.Dequeue();
                                Device.BeginReadPipe(DevicePipeId, buf);
                                // Todo: If this operation fails during normal operation, the buffer is lost from rotation.
                                // Should never happen during normal operation, but should confirm and mitigate if it's possible.
                                PendingBuffers.Enqueue(buf);
                            }
                        }
                        if (PendingBuffers.Count == 0)
                        {
                            Thread.Sleep(0);
                        }
                        else
                        {
                            lock (BufferLock)
                            {
                                while (n < BufferList.Length && PendingBuffers.Count > 0)
                                {
                                    QueuedBuffer buf = PendingBuffers.Peek();
                                    if (shortcut || buf.Ready)
                                    {
                                        shortcut = false;
                                        PendingBuffers.Dequeue();
                                        if (Device.EndReadPipe(buf))
                                        {
                                            ReceivedBuffers.Enqueue(buf);
                                            recvBytes += buf.CompletedSize;
                                        }
                                        else
                                        {
                                            // Timeout condition. Requeue.
                                            Device.BeginReadPipe(DevicePipeId, buf);
                                            // Todo: If this operation fails during normal operation, the buffer is lost from rotation.
                                            // Should never happen during normal operation, but should confirm and mitigate if it's possible.
                                            PendingBuffers.Enqueue(buf);
                                        }
                                    }
                                    n++;
                                }
                            }
                        }
                    }
                    finally
                    {
                        // Unless we're exiting, ensure we always indicate the data, even if some operation failed.
                        if (!Device.Stopping && recvBytes > 0)
                        {
                            lock (this)
                            {
                                QueuedLength  += recvBytes;
                                TotalReceived += recvBytes;
                            }
                            ThreadNewData.Set();
                            //ThreadPool.QueueUserWorkItem(RaiseNewData);
                        }
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.Print("Should not happen: Exception in background thread. {0}", ex.ToString());
                    Thread.Sleep(15);
                }

                ReceiveTick.Set();
            }
            Stopped = true;
        }