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(); }
// 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()); } } }
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?? } }
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); }
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(); }
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(); }
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); }
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; }
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(); }
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; }
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; }