public int GetPktBlockSize(Int32 len) { if (MaxPktSize == 0) { return(0); } int pkts = len / MaxPktSize; if ((len % MaxPktSize) > 0) { pkts++; } if (pkts == 0) { return(0); } ISO_PKT_INFO p = new ISO_PKT_INFO(); int blkSize = pkts * Marshal.SizeOf(p); return(blkSize); }
public int GetPktBlockSize(Int32 len) { if (MaxPktSize==0) return 0; int pkts = len / MaxPktSize; if ((len % MaxPktSize) > 0) pkts++; if (pkts == 0) return 0; ISO_PKT_INFO p = new ISO_PKT_INFO(); int blkSize = pkts * Marshal.SizeOf(p); return blkSize; }
// Call this one if you want the PacketInfo data passed-back public unsafe bool XferData(ref byte[] buf, ref int len, ref ISO_PKT_INFO[] pktInfos) { byte[] ovLap = new byte[OverlapSignalAllocSize]; fixed (byte* tmp0 = ovLap) { OVERLAPPED* ovLapStatus = (OVERLAPPED*)tmp0; ovLapStatus->hEvent = PInvoke.CreateEvent(0, 0, 0, 0); // This SINGLE_TRANSFER buffer must be allocated at this level. int bufSz = CyConst.SINGLE_XFER_LEN + GetPktBlockSize(len) + ((XferMode == XMODE.DIRECT) ? 0 : len); byte[] cmdBuf = new byte[bufSz]; fixed (byte* tmp1 = cmdBuf, tmp2 = buf) { bool bResult = BeginDataXfer(ref cmdBuf, ref buf, ref len, ref ovLap); bool wResult = WaitForIO(ovLapStatus->hEvent); bool fResult = FinishDataXfer(ref cmdBuf, ref buf, ref len, ref ovLap, ref pktInfos); PInvoke.CloseHandle(ovLapStatus->hEvent); return wResult && fResult; } } }
/*Summary Data Xfer Thread entry point. Starts the thread on Start Button click */ public unsafe void XferThread() { // Setup the queue buffers byte[][] cmdBufs = new byte[QueueSz][]; byte[][] xferBufs = new byte[QueueSz][]; byte[][] ovLaps = new byte[QueueSz][]; ISO_PKT_INFO[][] pktsInfo = new ISO_PKT_INFO[QueueSz][]; int xStart = 0; try { LockNLoad(ref xStart, cmdBufs, xferBufs, ovLaps, pktsInfo); } catch (NullReferenceException e) { // This exception gets thrown if the device is unplugged // while we're streaming data e.GetBaseException(); //this.Invoke(handleException); Dispatcher.CurrentDispatcher.Invoke(handleException); //this.Dispatcher.Invoke(handleException); } }
// This FinishDataXfer is only called by the second XferData method of CyIsocEndPoint // This called when ISO_PKT_INFO data is requested public unsafe virtual bool FinishDataXfer(ref byte[] singleXfer, ref byte[] buffer, ref int len, ref byte[] ov, ref ISO_PKT_INFO[] pktInfo) { // Call the base class' FinishDataXfer to do most of the work bool rResult = FinishDataXfer(ref singleXfer, ref buffer, ref len, ref ov); // Pass-back the Isoc packet info records if (len > 0) { fixed (byte* buf = singleXfer) { SINGLE_TRANSFER* transfer = (SINGLE_TRANSFER*)buf; ISO_PKT_INFO* packets = (ISO_PKT_INFO*)(buf + transfer->IsoPacketOffset); int pktCnt = (int)transfer->IsoPacketLength / Marshal.SizeOf(*packets); for (int i = 0; i < pktCnt; i++) pktInfo[i] = packets[i]; } } return rResult; }
/*Summary Called at the end of recursive method, LockNLoad(). XferData() implements the infinite transfer loop */ public unsafe void XferData(byte[][] cBufs, byte[][] xBufs, byte[][] oLaps, ISO_PKT_INFO[][] pktsInfo) { IAsyncResult ar; int k = 0; int len = 0; Successes = 0; Failures = 0; XferBytes = 0; t1 = DateTime.Now; for (; bRunning; ) { // WaitForXfer fixed (byte* tmpOvlap = oLaps[k]) { OVERLAPPED* ovLapStatus = (OVERLAPPED*)tmpOvlap; if (!EndPoint.WaitForXfer(ovLapStatus->hEvent, 5000)) { EndPoint.Abort(); PInvoke.WaitForSingleObject(ovLapStatus->hEvent, 5000); } } if (EndPoint.Attributes == 1) { CyIsocEndPoint isoc = EndPoint as CyIsocEndPoint; // FinishDataXfer if (isoc.FinishDataXfer(ref cBufs[k], ref xBufs[k], ref len, ref oLaps[k], ref pktsInfo[k])) { //XferBytes += len; //Successes++; ISO_PKT_INFO[] pkts = pktsInfo[k]; for (int j = 0; j < PPX; j++) { if (pkts[j].Status == 0) { XferBytes += pkts[j].Length; Successes++; } else Failures++; pkts[j].Length = 0; } } else Failures++; } else { // FinishDataXfer if (EndPoint.FinishDataXfer(ref cBufs[k], ref xBufs[k], ref len, ref oLaps[k])) { XferBytes += len; Successes++; if (active_buffer == 1) { if (data_buf1_pos < DATA_BUF_SIZE && ((data_buf1_pos + len) <= DATA_BUF_SIZE)) { Array.Copy(xBufs[k], 0, data_buffer_1, data_buf1_pos, len); data_buf1_pos += len; if (data_buf1_pos >= DATA_BUF_SIZE) { active_buffer = 2; } } else { active_buffer = 2; } } else { if (data_buf2_pos < DATA_BUF_SIZE && ((data_buf2_pos + len) <= DATA_BUF_SIZE)) { Array.Copy(xBufs[k], 0, data_buffer_2, data_buf2_pos, len); data_buf2_pos += len; if (data_buf2_pos >= DATA_BUF_SIZE) { active_buffer = 1; } } else { active_buffer = 1; } } //file.Write(xBufs[k], 0, xBufs[k].Length); } else Failures++; } // ar = file.BeginWrite(xBufs[k], 0, xBufs[k].Length, null, null); k++; if (k == QueueSz) // Only update displayed stats once each time through the queue { k = 0; t2 = DateTime.Now; elapsed = t2 - t1; xferRate = (long)(XferBytes / elapsed.TotalMilliseconds); xferRate = xferRate / (int)100 * (int)100; // Call StatusUpdate() in the main thread //this.Dispatcher.Invoke(updateUI); Dispatcher.CurrentDispatcher.Invoke(updateUI); //************************** Adding write to file *********************************// // for (int j = 0; j < QueueSz; j++) // { // file.Write(xBufs[j], 0, xBufs[j].Length); // } //file.Close(); // For small QueueSz or PPX, the loop is too tight for UI thread to ever get service. // Without this, app hangs in those scenarios. //Thread.Sleep(1); } /* if (!ar.IsCompleted) { file.EndWrite(ar); } else { file.EndWrite(ar); }*/ // Re-submit this buffer into the queue len = BufSz; EndPoint.BeginDataXfer(ref cBufs[k], ref xBufs[k], ref len, ref oLaps[k]); } // End infinite loop }
/*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 cBufs[j] = new byte[CyConst.SINGLE_XFER_LEN + IsoPktBlockSize]; 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 Event handler for Transfer Data button */ private void DataXferBtn_Click(object sender, EventArgs e) { if (curHidReport != null) { DoHidXfer(sender, e); return; } if (curHidDev != null) { MessageBox.Show("Select a HID feature, input or output in the device tree.", "No report selected"); return; } if (curEndpt == null) { MessageBox.Show("Select <bulk> <iso> <int> endpoint enabled in the device tree.", "No endpoint selected"); return; } int bytes = 0; try { if (!NumBytesBox.Text.Contains("-")) { if (NumBytesBox.Text.Contains("0X") || NumBytesBox.Text.Contains("0x")) bytes = Convert.ToInt32(NumBytesBox.Text, 16); else bytes = Convert.ToInt32(NumBytesBox.Text); } else { MessageBox.Show("Enter a valid number of bytes to transfer.", "Invalid Bytes to tranfer"); return; } } catch (Exception exc) { if (bytes < 1) { //Just to remove warning exc.ToString(); MessageBox.Show("Enter a valid number of bytes to transfer.", "Invalid Bytes to Transfer"); return; } } byte[] buffer = new byte[bytes]; bool bXferCompleted = false; // Setting control endpt direction needs to occur before BuildDataCaption call CyControlEndPoint ctrlEpt = curEndpt as CyControlEndPoint; if (ctrlEpt != null) ctrlEpt.Direction = DirectionBox.Text.Equals("In") ? CyConst.DIR_FROM_DEVICE : CyConst.DIR_TO_DEVICE; // Stuff the output buffer if (!curEndpt.bIn) { string[] hexTokens = XferDataBox.Text.Split(' '); int i = 0; //foreach (string tok in hexTokens) for (int j = 0; j <hexTokens.Length; j++) { string tok; try { tok = hexTokens[j]; } catch { tok = ""; } if ((tok.Length > 0) && (bytes>j)) { try { buffer[i++] = (byte)Convert.ToInt32(tok, 16); } catch (Exception exc) { MessageBox.Show(exc.Message, "Input Error"); return; } } } } BuildDataCaption(); OutputBox.Text += dataCaption; OutputBox.SelectionStart = OutputBox.Text.Length; OutputBox.ScrollToCaret(); curEndpt.TimeOut = 2000; if (ctrlEpt != null) { if (TargetBox.Text.Equals("Device")) ctrlEpt.Target = CyConst.TGT_DEVICE; else if (TargetBox.Text.Equals("Interface")) ctrlEpt.Target = CyConst.TGT_INTFC; else if (TargetBox.Text.Equals("Endpoint")) ctrlEpt.Target = CyConst.TGT_ENDPT; else if (TargetBox.Text.Equals("Other")) ctrlEpt.Target = CyConst.TGT_OTHER; if (ReqTypeBox.Text.Equals("Standard")) ctrlEpt.ReqType = CyConst.REQ_STD; else if (ReqTypeBox.Text.Equals("Class")) ctrlEpt.ReqType = CyConst.REQ_CLASS; else if (ReqTypeBox.Text.Equals("Vendor")) ctrlEpt.ReqType = CyConst.REQ_VENDOR; ctrlEpt.Direction = DirectionBox.Text.Equals("In") ? CyConst.DIR_FROM_DEVICE : CyConst.DIR_TO_DEVICE; try { ctrlEpt.ReqCode = (byte)Convert.ToInt16(ReqCodeBox.Text, 16); //(byte)Util.HexToInt(ReqCodeBox.Text); ctrlEpt.Value = (ushort)Convert.ToInt16(wValueBox.Text, 16); //(ushort)Util.HexToInt(wValueBox.Text); ctrlEpt.Index = (ushort)Convert.ToInt16(wIndexBox.Text, 16); //(ushort)Util.HexToInt(wIndexBox.Text); } catch (Exception exc) { MessageBox.Show(exc.Message, "Input Error"); return; } bXferCompleted = ctrlEpt.XferData(ref buffer, ref bytes); if (bRecording && (script_stream != null)) { Xaction.ConfigNum = FxDev.Config; Xaction.IntfcNum = 0; Xaction.AltIntfc = FxDev.AltIntfc; Xaction.EndPtAddr = ctrlEpt.Address; Xaction.Tag = 0; Xaction.bReqType = (byte)(ctrlEpt.Direction | ctrlEpt.ReqType | ctrlEpt.Target); Xaction.CtlReqCode = ctrlEpt.ReqCode; Xaction.wValue = ctrlEpt.Value; Xaction.wIndex = ctrlEpt.Index; Xaction.DataLen = (uint)bytes; Xaction.Timeout = ctrlEpt.TimeOut / 1000; Xaction.RecordSize = (uint)bytes + TTransaction.TotalHeaderSize; //Write xaction and buffer Xaction.WriteToStream(script_stream); Xaction.WriteFromBuffer(script_stream, ref buffer, ref bytes); } } bool IsPkt = IsPacket.Checked ? true : false; CyBulkEndPoint bulkEpt = curEndpt as CyBulkEndPoint; if (bulkEpt != null) { bXferCompleted = bulkEpt.XferData(ref buffer, ref bytes, IsPkt); CheckForScripting(ref buffer, ref bytes); } CyIsocEndPoint isocEpt = curEndpt as CyIsocEndPoint; if (isocEpt != null) { isocEpt.XferSize = Convert.ToInt32(NumBytesBox.Text); // if (isocEpt.MaxPktSize == 0) { MessageBox.Show("Please correct MaxPacketSize in Descriptor", "Invalid MaxPacketSize"); return; } int pkts = bytes / isocEpt.MaxPktSize; if ((bytes % isocEpt.MaxPktSize) > 0) pkts++; ISO_PKT_INFO[] Iskpt = new ISO_PKT_INFO[pkts]; bXferCompleted = isocEpt.XferData(ref buffer, ref bytes, ref Iskpt); if (bXferCompleted) { int MainBufOffset = 0; int tmpBufOffset = 0; byte[] tmpbuf = new byte[bytes]; // Check all packets and if Iso in/out packet is not succeeded then don't update the buffer. for (int i = 0; i < pkts; i++) { if (Iskpt[i].Status != 0 ) { //updated the buffer based on the status of the packets //skip that buffer } else if (bytes <= MainBufOffset) { // We have already read all the received data. } else { int j = 0; try { for (j = 0; j < Iskpt[i].Length; j++) { tmpbuf[tmpBufOffset] = buffer[MainBufOffset + j]; // get the received/transfered data in the temparary buffer tmpBufOffset++; } } catch (Exception pExp) { MessageBox.Show(pExp.Message, "Exception Caught"); } } MainBufOffset += isocEpt.MaxPktSize; } // Now copy the temparary buffer to main buffer to display for (int x = 0; x < tmpBufOffset; x++) { buffer[x] = tmpbuf[x]; // Updated the main buffer with the whatever data has been received / transfered. } } //bXferCompleted = isocEpt.XferData(ref buffer, ref bytes); CheckForScripting(ref buffer, ref bytes); } CyInterruptEndPoint intEpt = curEndpt as CyInterruptEndPoint; if (intEpt != null) { bXferCompleted = intEpt.XferData(ref buffer, ref bytes, IsPkt); CheckForScripting(ref buffer, ref bytes); } DisplayXferData(buffer, bytes, bXferCompleted); }
/*Summary Called at the end of recursive method, LockNLoad(). XferData() implements the infinite transfer loop */ public unsafe void XferData(byte[][] cBufs, byte[][] xBufs, byte[][] oLaps, ISO_PKT_INFO[][] pktsInfo) { int k = 0; int len = 0; Successes = 0; Failures = 0; XferBytes = 0; t1 = DateTime.Now; for (; bRunning; ) { // WaitForXfer fixed (byte* tmpOvlap = oLaps[k]) { OVERLAPPED* ovLapStatus = (OVERLAPPED*)tmpOvlap; if (!EndPoint.WaitForXfer(ovLapStatus->hEvent, 500)) { EndPoint.Abort(); PInvoke.WaitForSingleObject(ovLapStatus->hEvent, 500); } } if (EndPoint.Attributes == 1) { CyIsocEndPoint isoc = EndPoint as CyIsocEndPoint; // FinishDataXfer if (isoc.FinishDataXfer(ref cBufs[k], ref xBufs[k], ref len, ref oLaps[k], ref pktsInfo[k])) { //XferBytes += len; //Successes++; ISO_PKT_INFO[] pkts = pktsInfo[k]; for (int j = 0; j < PPX; j++) { if (pkts[j].Status == 0) { XferBytes += pkts[j].Length; Successes++; } else Failures++; pkts[j].Length = 0; } } else Failures++; } else { // FinishDataXfer if (EndPoint.FinishDataXfer(ref cBufs[k], ref xBufs[k], ref len, ref oLaps[k])) { XferBytes += len; Successes++; } else Failures++; } k++; if (k == QueueSz) // Only update displayed stats once each time through the queue { k = 0; t2 = DateTime.Now; elapsed = t2 - t1; xferRate = (long)(XferBytes / elapsed.TotalMilliseconds); xferRate = xferRate / (int)100 * (int)100; // Call StatusUpdate() in the main thread this.Invoke(updateUI); // For small QueueSz or PPX, the loop is too tight for UI thread to ever get service. // Without this, app hangs in those scenarios. Thread.Sleep(1); } // Re-submit this buffer into the queue len = BufSz; EndPoint.BeginDataXfer(ref cBufs[k], ref xBufs[k], ref len, ref oLaps[k]); } // End infinite loop }
/*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]); 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! } }