/*Summary * This is a recursive routine for pinning all the buffers used in the transfer in memory. * It will get recursively called QueueSz times. On the QueueSz_th call, it will call * XferData, which will loop, transferring data, until the stop button is clicked. * Then, the recursion will unwind. */ public unsafe void LockNLoad(ref int j, byte[][] cBufs, byte[][] xBufs, byte[][] oLaps, ISO_PKT_INFO[][] pktsInfo) { // Allocate one set of buffers for the queue. Buffered IO method require user to allocate a buffer as a part of command buffer, // the BeginDataXfer does not allocated it. BeginDataXfer will copy the data from the main buffer to the allocated while initializing the commands. cBufs[j] = new byte[CyConst.SINGLE_XFER_LEN + IsoPktBlockSize + ((EndPoint.XferMode == XMODE.BUFFERED) ? BufSz : 0)]; xBufs[j] = new byte[BufSz]; oLaps[j] = new byte[20]; pktsInfo[j] = new ISO_PKT_INFO[PPX]; fixed(byte *tL0 = oLaps[j], tc0 = cBufs[j], tb0 = xBufs[j]) // Pin the buffers in memory { OVERLAPPED *ovLapStatus = (OVERLAPPED *)tL0; ovLapStatus->hEvent = (IntPtr)PInvoke.CreateEvent(0, 0, 0, 0); // Pre-load the queue with a request int len = BufSz; EndPoint.BeginDataXfer(ref cBufs[j], ref xBufs[j], ref len, ref oLaps[j]); j++; if (j < QueueSz) { LockNLoad(ref j, cBufs, xBufs, oLaps, pktsInfo); // Recursive call to pin next buffers in memory } else { XferData(cBufs, xBufs, oLaps, pktsInfo); // All loaded. Let's go! } } }
/// <summary> /// Equivalent to the CyUSBEndPoint.XferData(...) but with pointer pinning to ensure that the garbage collector does not move buffers /// </summary> /// <param name="buf">The buffer to transfer data into or out</param> /// <param name="len">Length of data to transfer. Can be overwritten with actual transfer length</param> /// <param name="endpoint">Endpoint to perform the transfer operation on</param> /// <returns>Bool indicating success of the transfer operation</returns> static public unsafe bool XferData(ref byte[] buf, ref int len, ref CyUSBEndPoint endpoint) { byte[] ov = new byte[endpoint.OverlapSignalAllocSize]; fixed(byte *numPtr = ov) { ((OVERLAPPED *)numPtr)->hEvent = PInvoke.CreateEvent(0U, 0U, 0U, 0U); byte[] singleXfer = new byte[38 + (endpoint.XferMode == XMODE.DIRECT ? 0 : len)]; // These pinned pointers ensure that the buffers don't move in memory var cmd_buff_handle = GCHandle.Alloc(singleXfer, GCHandleType.Pinned); var data_handle = GCHandle.Alloc(buf, GCHandleType.Pinned); //Perform async transfer endpoint.BeginDataXfer(ref singleXfer, ref buf, ref len, ref ov); bool flag1 = WaitForIO(((OVERLAPPED *)numPtr)->hEvent, ref endpoint); bool flag2 = endpoint.FinishDataXfer(ref singleXfer, ref buf, ref len, ref ov); PInvoke.CloseHandle(((OVERLAPPED *)numPtr)->hEvent); //release memory cmd_buff_handle.Free(); data_handle.Free(); //return operation flags return(flag1 && flag2); } }
/*Summary * This is a recursive routine for pinning all the buffers used in the transfer in memory. * It will get recursively called QueueSz times. On the QueueSz_th call, it will call * XferData, which will loop, transferring data, until the stop button is clicked. * Then, the recursion will unwind. */ public unsafe void LockNLoad(ref int j, byte[][] cBufs, byte[][] xBufs, byte[][] oLaps, ISO_PKT_INFO[][] pktsInfo) { // Allocate one set of buffers for the queue, Buffered IO method require user to allocate a buffer as a part of command buffer, // the BeginDataXfer does not allocated it. BeginDataXfer will copy the data from the main buffer to the allocated while initializing the commands. cBufs[j] = new byte[CyConst.SINGLE_XFER_LEN + IsoPktBlockSize + ((EndPoint.XferMode == XMODE.BUFFERED) ? BufSz : 0)]; xBufs[j] = new byte[BufSz]; //initialize the buffer with initial value 0xA5 for (int iIndex = 0; iIndex < BufSz; iIndex++) { xBufs[j][iIndex] = DefaultBufInitValue; } oLaps[j] = new byte[20]; pktsInfo[j] = new ISO_PKT_INFO[PPX]; fixed(byte *tL0 = oLaps[j], tc0 = cBufs[j], tb0 = xBufs[j]) // Pin the buffers in memory { OVERLAPPED *ovLapStatus = (OVERLAPPED *)tL0; ovLapStatus->hEvent = (IntPtr)PInvoke.CreateEvent(0, 0, 0, 0); // Pre-load the queue with a request int len = BufSz; EndPoint.BeginDataXfer(ref cBufs[j], ref xBufs[j], ref len, ref oLaps[j]); //if (Save == true) //mady //{ // Buffer.BlockCopy(xBufs[j], 0, temp, j * PPX * EndPoint.MaxPktSize, PPX * EndPoint.MaxPktSize); //mady: Take Backup of received data to Temp Buffer //} j++; if (j < QueueSz) { LockNLoad(ref j, cBufs, xBufs, oLaps, pktsInfo); // Recursive call to pin next buffers in memory } else { XferData(cBufs, xBufs, oLaps, pktsInfo); } } }
/*Summary * This is a recursive routine for pinning all the buffers used in the transfer in memory. * It will get recursively called QueueSz times. On the QueueSz_th call, it will call * XferData, which will loop, transferring data, until the stop button is clicked. * Then, the recursion will unwind. */ public unsafe void LockNLoad(byte[][] cBufs, byte[][] xBufs, byte[][] oLaps, ISO_PKT_INFO[][] pktsInfo) { int j = 0; int nLocalCount = j; GCHandle[] bufSingleTransfer = new GCHandle[QueueSz]; GCHandle[] bufDataAllocation = new GCHandle[QueueSz]; GCHandle[] bufPktsInfo = new GCHandle[QueueSz]; GCHandle[] handleOverlap = new GCHandle[QueueSz]; while (j < QueueSz) { // Allocate one set of buffers for the queue, Buffered IO method require user to allocate a buffer as a part of command buffer, // the BeginDataXfer does not allocated it. BeginDataXfer will copy the data from the main buffer to the allocated while initializing the commands. cBufs[j] = new byte[CyConst.SINGLE_XFER_LEN + IsoPktBlockSize + ((EndPoint.XferMode == XMODE.BUFFERED) ? BufSz : 0)]; xBufs[j] = new byte[BufSz]; //initialize the buffer with initial value 0xA5 for (int iIndex = 0; iIndex < BufSz; iIndex++) { xBufs[j][iIndex] = DefaultBufInitValue; } int sz = Math.Max(CyConst.OverlapSignalAllocSize, sizeof(OVERLAPPED)); oLaps[j] = new byte[sz]; pktsInfo[j] = new ISO_PKT_INFO[PPX]; /*///////////////////////////////////////////////////////////////////////////// * * fixed keyword is getting thrown own by the compiler because the temporary variables * tL0, tc0 and tb0 aren't used. And for jagged C# array there is no way, we can use this * temporary variable. * * Solution for Variable Pinning: * Its expected that application pin memory before passing the variable address to the * library and subsequently to the windows driver. * * Cypress Windows Driver is using this very same memory location for data reception or * data delivery to the device. * And, hence .Net Garbage collector isn't expected to move the memory location. And, * Pinning the memory location is essential. And, not through FIXED keyword, because of * non-usability of temporary variable. * * /////////////////////////////////////////////////////////////////////////////*/ //fixed (byte* tL0 = oLaps[j], tc0 = cBufs[j], tb0 = xBufs[j]) // Pin the buffers in memory ////////////////////////////////////////////////////////////////////////////////////////////// bufSingleTransfer[j] = GCHandle.Alloc(cBufs[j], GCHandleType.Pinned); bufDataAllocation[j] = GCHandle.Alloc(xBufs[j], GCHandleType.Pinned); bufPktsInfo[j] = GCHandle.Alloc(pktsInfo[j], GCHandleType.Pinned); handleOverlap[j] = GCHandle.Alloc(oLaps[j], GCHandleType.Pinned); // oLaps "fixed" keyword variable is in use. So, we are good. ///////////////////////////////////////////////////////////////////////////////////////////// unsafe { //fixed (byte* tL0 = oLaps[j]) { CyUSB.OVERLAPPED ovLapStatus = new CyUSB.OVERLAPPED(); ovLapStatus = (CyUSB.OVERLAPPED)Marshal.PtrToStructure(handleOverlap[j].AddrOfPinnedObject(), typeof(CyUSB.OVERLAPPED)); ovLapStatus.hEvent = (IntPtr)PInvoke.CreateEvent(0, 0, 0, 0); Marshal.StructureToPtr(ovLapStatus, handleOverlap[j].AddrOfPinnedObject(), true); // Pre-load the queue with a request int len = BufSz; if (EndPoint.BeginDataXfer(ref cBufs[j], ref xBufs[j], ref len, ref oLaps[j]) == false) { Failures++; } } j++; } } XferData(cBufs, xBufs, oLaps, pktsInfo, handleOverlap); // All loaded. Let's go! unsafe { for (nLocalCount = 0; nLocalCount < QueueSz; nLocalCount++) { CyUSB.OVERLAPPED ovLapStatus = new CyUSB.OVERLAPPED(); ovLapStatus = (CyUSB.OVERLAPPED)Marshal.PtrToStructure(handleOverlap[nLocalCount].AddrOfPinnedObject(), typeof(CyUSB.OVERLAPPED)); PInvoke.CloseHandle(ovLapStatus.hEvent); /*//////////////////////////////////////////////////////////////////////////////////////////// * * Release the pinned allocation handles. * * ////////////////////////////////////////////////////////////////////////////////////////////*/ bufSingleTransfer[nLocalCount].Free(); bufDataAllocation[nLocalCount].Free(); bufPktsInfo[nLocalCount].Free(); handleOverlap[nLocalCount].Free(); cBufs[nLocalCount] = null; xBufs[nLocalCount] = null; oLaps[nLocalCount] = null; } } GC.Collect(); }