void StopAcquisition() { // Close the module qResult = qusb.Close(); // Free buffers for (int k = 0; k < NumBuffers; ++k) { Marshal.FreeHGlobal(BufferArray[k]); Marshal.FreeHGlobal(BulkStream[k]); } aquiring = false; timer1.Enabled = false; }
private void bStopStreaming_Click(object sender, EventArgs e) { bool qResult; tbLog.AppendText(String.Format("********** Stopping stream **********\n", qusbError)); // Stop the timer timer.Stop(); // Stop the data stream qResult = qusb.StopStream(streamID, false); if (!qResult) { qusbError = qusb.LastError(); tbLog.AppendText(String.Format("BulkDataStopStream failed with error {0}\n", qusbError)); } // Close the module qResult = qusb.Close(); if (!qResult) { Console.WriteLine("QuickUSB Error: {0}", qusb.LastError()); return; } // Reset variables streaming = false; // Reset buttons bStartStreaming.Enabled = true; bStopStreaming.Enabled = false; }
public void CloseTest() { QuickUsb target = new QuickUsb("QUSB-0"); target.Open(); bool expected = true; bool actual; actual = target.Close(); Assert.AreEqual(expected, actual); }
private void bStartStreaming_Click(object sender, EventArgs e) { bool qResult; qusb = qusbControl.SelectedModule; tbLog.AppendText(String.Format("********** Starting stream **********\n", qusbError)); // Open the module qResult = qusb.Open(); if (!qResult) { tbLog.AppendText(String.Format("Unable to open module\n", qusbError)); return; } // Start the data stream if (UserAllocatedBuffers) { // Start streaming data to our user allocated data buffers qResult = qusb.ReadBulkDataStartStream(BufferArray, NumBuffers, BufferByteSize, cbDelegate, IntPtr.Zero, out streamID, NumThreads, ThreadConcurrency); } else { // Start streaming data to data buffers that will be allocated interally by the Streaming API qResult = qusb.ReadBulkDataStartStream(IntPtr.Zero, NumBuffers, BufferByteSize, cbDelegate, IntPtr.Zero, out streamID, NumThreads, ThreadConcurrency); } // Check for an error starting the stream if (!qResult) { qusbError = qusb.LastError(); qusb.Close(); tbLog.AppendText(String.Format("ReadBulkDataStartStream failed with error {0}\n", qusbError)); return; } // Reset buttons bStartStreaming.Enabled = false; bStopStreaming.Enabled = true; // Reset variables TotalKiloBytes = 0; ErrorCount = 0; streaming = true; // Start throughput timer QueryPerformanceFrequency(out freq); QueryPerformanceCounter(out tStart); // Start timer timer.Start(); }
private void timer_Tick(object sender, EventArgs e) { if (numPendingRequests != 0) { // If we are not multithreading the stream in this example, we must // allow time for processing requests. Processing requests simply // means checking if a request has completed, execute its completion // routine, and re-issue the requests. QuickUsb.ProcessStream will // return when either any request has completed or the specified time // has elapsed. if (NumThreads == 0) { // Check if the next request has completed bool qResult = qusb.BulkWait(bulkStream[nextRequestToProcess], true); // Don't block if (!qResult) { qusbError = qusb.LastError(); if (qusbError != QuickUsb.Error.NotCompleted) { Console.WriteLine("ProcessStream failed with error {0}", qusbError); } } } } else { // All the requests have completed bIssueRead.Enabled = true; bIssueWrite.Enabled = true; timer.Stop(); // Close the module now that we're done with it qusb.Close(); } // Report our data throughput dataRate.Text = String.Format("Data Rate: {0:0.0} MB/s Overall, {1:0.0} MB/s Instantaneously", overallRate, instRate); // Dump data to log lock (log) { tbLog.AppendText(log.ToString()); log = new StringBuilder(); } }
void StartAcquisition() { // Query connected modules nameList = QuickUsb.FindModules(); if (nameList.Length == 0) { return; } // Open the first module qusb = new QuickUsb(nameList[0]); qusb.Open(nameList[0]); // Allocate buffers for (int k = 0; k < NumBuffers; ++k) { BufferArray.Add(Marshal.AllocHGlobal(FrameByteSize)); BulkStream[k] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(QuickUsb.BulkStream))); } QueryPerformanceFrequency(out freq); QueryPerformanceCounter(out tStart); aquiring = true; timer1.Enabled = true; // Issue a new transaction qResult = qusb.ReadBulkDataAsync( BufferArray[0], FrameByteSize, BulkStream[0], cbDelegate, IntPtr.Zero); if (!qResult) { toolStripStatusLabel1.Text = "Error: Unable to issue data read"; qusb.Close(); return; } }
private void bIssueWrite_Click(object sender, EventArgs e) { bool qResult; qusb = qusbControl.SelectedModule; tbLog.AppendText(String.Format("********** Issuing {0} async writes **********\n", NumRequests)); // Open the module qResult = qusb.Open(); if (!qResult) { tbLog.AppendText(String.Format("Unable to open module\n", qusbError)); return; } // Reset buttons bIssueRead.Enabled = false; bIssueWrite.Enabled = true; // Reset variables TotalKiloBytes = 0; ErrorCount = 0; numPendingRequests = 0; nextRequestToProcess = 0; // Set num threads and thread concurrency qResult = qusb.SetNumAsyncThreads(NumThreads, ThreadConcurrency); if (!qResult) { qusbError = qusb.LastError(); tbLog.AppendText(String.Format("SetNumAsyncThreads failed with error {0}\n", qusbError)); bIssueRead.Enabled = false; bIssueWrite.Enabled = false; qusb.Close(); return; } // Start throughput timer QueryPerformanceFrequency(out freq); QueryPerformanceCounter(out tStart); // Start streaming data to our user allocated data buffers for (int k = 0; k < NumRequests; ++k) { qResult = qusb.WriteBulkDataAsync(BufferArray[k], BufferByteSize, bulkStream[k], cbDelegate, IntPtr.Zero); // Check for an error issuing the request if (!qResult) { qusbError = qusb.LastError(); tbLog.AppendText(String.Format("WriteBulkDataAsync failed with error {0}\n", qusbError)); } else { ++numPendingRequests; } } // Start timer timer.Start(); }
private double MeasureThroughput(int count) { // Open the module string[] modules = QuickUsb.FindModules(); if (modules.Length == 0) { return(0.0f); } QuickUsb qusb = new QuickUsb(modules[0]); // Perform throughput test int transBytes; long startTime, stopTime; double duration; double throughput; int dataSize = 0; byte[] data = null; uint size; QuickUsb.Error qusbError; // Check for modification to configuration parameters if (dataSize != testPackSize) { dataSize = testPackSize; data = new byte[dataSize]; } // Start timing transBytes = 0; QueryPerformanceCounter(out startTime); // Perform the test for (int k = 0; k < count; ++k) { // Perform the data R/W size = (uint)dataSize; if (rbRead.Checked) { if (!qusb.ReadData(data, ref size)) { // Error MessageBox.Show("QuickUsbReadData() failed!", "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); transBytes = 0; size = 0; return(0.0f); } else if ((int)size != dataSize) { // Error MessageBox.Show(String.Format("QuickUsbReadData() did not read correct amount of data ({0} of {1} bytes)!", size, dataSize), "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); transBytes = 0; size = 0; return(0.0f); } } else { if (!qusb.WriteData(data, size)) { qusbError = qusb.LastError(); // Error MessageBox.Show("QuickUsbWriteData() failed!", "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); transBytes = 0; size = 0; return(0.0f); } } transBytes += (int)size; } // Calculate the throughput QueryPerformanceCounter(out stopTime); duration = (double)(stopTime - startTime) / (double)freq; qusb.Close(); throughput = ((double)(transBytes) / (1024.0f * 1024.0f * (double)duration)); return(throughput); }
private void performTest() { // Open the module string[] modules = QuickUsb.FindModules(); if (modules.Length == 0) { return; } qusb = new QuickUsb(modules[0]); qusb.Open(modules[0]); int k, transBytes = 0; bool transOk; // Async Variables QuickUsb.BulkStream[] pBulkStream = null; ushort[][] pDataBuffer = null; AsyncBulkStreamTag[] asyncTag = null; GCHandle[] hAsyncTag = null; // Legacy Async Variables int issuedTrans = 0, nextToComplete = 0; IntPtr[] bufferArray = null; byte[] transId = null; // Streaming Variables bool streaming = false; int dataSize = 0; int numBuffers = 0; byte[] data = null; uint size, bytesTransferred; QuickUsb.Error qusbError; // Start timing QueryPerformanceCounter(out startTime); // Perform the test do { // Check for modification to configuration parameters if (dataSize != testPackSize || numBuffers != (int)nNumBuffers.Value) { dataSize = testPackSize; numBuffers = (int)nNumBuffers.Value; if (rbSync.Checked) { data = new byte[dataSize]; } if (rbAsync.Checked) { // Wait for all issued transactions to complete while (issuedTrans > 0) { if (!qusb.BulkWait(pBulkStream[nextToComplete], false)) { } else { transOk = true; --issuedTrans; if (++nextToComplete == pBulkStream.Length) { nextToComplete = 0; } } } // Free memories if (hAsyncTag != null) { for (k = 0; k < hAsyncTag.Length; ++k) { hAsyncTag[k].Free(); } } // Allocate memories pDataBuffer = new ushort[numBuffers][]; pBulkStream = new QuickUsb.BulkStream[numBuffers]; asyncTag = new AsyncBulkStreamTag[numBuffers]; hAsyncTag = new GCHandle[numBuffers]; for (k = 0; k < numBuffers; ++k) { pBulkStream[k] = new QuickUsb.BulkStream(); pDataBuffer[k] = new ushort[dataSize / 2]; asyncTag[k] = new AsyncBulkStreamTag(); hAsyncTag[k] = GCHandle.Alloc(asyncTag[k], GCHandleType.Pinned); asyncTag[k].shutdown = 0; } // Reset varaibles issuedTrans = 0; nextToComplete = 0; // Issue new transactions while (issuedTrans != numBuffers) { if (!qusb.ReadBulkDataAsync(pDataBuffer[nextToComplete], (uint)dataSize, pBulkStream[nextToComplete], AsyncCompletionRoutineDelegate, GCHandle.ToIntPtr(hAsyncTag[nextToComplete]))) { } else { ++issuedTrans; if (++nextToComplete == numBuffers) { nextToComplete = 0; } } } } if (rbAsyncLegacy.Checked) { // Wait for all issued transactions to complete while (issuedTrans > 0) { if (!qusb.AsyncWait(out bytesTransferred, transId[nextToComplete], false)) { } else { transOk = true; --issuedTrans; if (++nextToComplete == transId.Length) { nextToComplete = 0; } } } // Free old memories if (bufferArray != null) { for (k = 0; k < bufferArray.Length; ++k) { Marshal.FreeHGlobal(bufferArray[k]); } } // Allocate memories transId = new byte[numBuffers]; bufferArray = new IntPtr[numBuffers]; for (k = 0; k < bufferArray.Length; ++k) { bufferArray[k] = Marshal.AllocHGlobal(dataSize); } // Reset varaibles issuedTrans = 0; nextToComplete = 0; } if (rbStreaming.Checked) { // Stop the stream if one is running if (streaming) { if (!qusb.StopStream(streamID, false)) { } } // Restart the stream with new parameters if (!qusb.ReadBulkDataStartStream(IntPtr.Zero, (uint)numBuffers, (uint)dataSize, StreamCompletionRoutineDelegate, IntPtr.Zero, out streamID, 4, 2)) { } } } // Perform the data R/W size = (uint)dataSize; transOk = false; if (testRead) { // Synchronous data read if (rbSync.Checked) { if (!qusb.ReadData(data, ref size)) { qusbError = qusb.LastError(); // Error MessageBox.Show(String.Format("QuickUsbReadData() failed! - {0}", qusbError.ToString()), "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); quit = true; transBytes = 0; size = 0; } else if ((int)size != dataSize) { // Error MessageBox.Show(String.Format("QuickUsbReadData() did not read correct amount of data ({0} of {1} bytes)!", size, dataSize), "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); quit = true; transBytes = 0; size = 0; } else { transOk = true; totalBytes += size; } } // Asynchronous data read else if (rbAsync.Checked) { transOk = true; lock (testThread) { size = (uint)streamBytes; streamBytes = 0; } } // Legacy asynchronous data read else if (rbAsyncLegacy.Checked) { // First wait on the next transaction to complete bytesTransferred = 0; if (issuedTrans > 0) { if (!qusb.AsyncWait(out bytesTransferred, transId[nextToComplete], false)) { qusbError = qusb.LastError(); // Error MessageBox.Show("Error", "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); quit = true; transBytes = 0; size = 0; } else { transOk = true; --issuedTrans; } } // Issue new transactions while (issuedTrans != numBuffers && !quit) { if (!qusb.ReadDataAsync(bufferArray[nextToComplete], ref size, out transId[nextToComplete])) { qusbError = qusb.LastError(); // Error MessageBox.Show("Error", "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); quit = true; transBytes = 0; size = 0; } else { ++issuedTrans; if (++nextToComplete == numBuffers) { nextToComplete = 0; } } } if (transOk) { size = bytesTransferred; } } // Streaming data read else if (rbStreaming.Checked) { transOk = true; lock (testThread) { size = (uint)streamBytes; streamBytes = 0; } // Nothing to do here Thread.Sleep(250); } } else if (rbSync.Checked) { // Sychronous data write if (!qusb.WriteData(data, size)) { qusbError = qusb.LastError(); // Error MessageBox.Show("QuickUsbWriteData() failed!", "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); quit = true; transBytes = 0; size = 0; } else { transOk = true; totalBytes += size; } } if (transOk) { transBytes += (int)size; } } while (!quit); if (rbAsync.Checked) { // Wait for all issued transactions to complete for (k = 0; k < pBulkStream.Length; ++k) { asyncTag[k].shutdown = 1; } // Wait for pending transactions to complete qusb.BulkWait(null, false); /*while (issuedTrans > 0) * { * if (!qusb.BulkWait(pBulkStream[nextToComplete], false)) * { * } * else * { * transOk = true; * --issuedTrans; * if (++nextToComplete == numBuffers) * { * nextToComplete = 0; * } * } * }*/ // Free memory for (k = 0; k < pBulkStream.Length; ++k) { hAsyncTag[k].Free(); } } if (rbAsyncLegacy.Checked) { // Wait for all issued transactions to complete /*while (issuedTrans > 0) * { * qusb.AsyncWait(out size, transId[nextToComplete], false); * * --issuedTrans; * if (++nextToComplete == numBuffers) * { * nextToComplete = 0; * } * }*/ } if (rbStreaming.Checked) { // Stop the stream if one is running if (streaming) { if (!qusb.StopStream(streamID, false)) { qusbError = qusb.LastError(); // Error MessageBox.Show("Error", "QuickUSB Throughput Test", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } qusb.Close(); if (rbAsyncLegacy.Checked) { // Free memory for (k = 0; k < bufferArray.Length; ++k) { Marshal.FreeHGlobal(bufferArray[k]); } } }
private void bStart_Click(object sender, EventArgs e) { string[] modules = QuickUsb.FindModules(); if (modules.Length == 0) { return; } bStart.Enabled = false; bStop.Enabled = true; // Open the module QuickUsb qusb = new QuickUsb(modules[0]); // Perform throughput test int transBytes; double[] samples = new double[20]; int sampleIndex = 0; long startTime, stopTime; double duration, throughput; int dataSize = 0; byte[] data = null; uint size; // Start timing transBytes = 0; QueryPerformanceCounter(out startTime); progressBar.Value = 0; // Perform the test do { // Check for modification to configuration parameters if (dataSize != (int)packetSize.Value * (int)Math.Pow((double)1024, (double)packetSizeUnit.SelectedIndex)) { dataSize = (int)packetSize.Value * (int)Math.Pow((double)1024, (double)packetSizeUnit.SelectedIndex); data = new byte[dataSize]; } size = (uint)dataSize; if (!qusb.ReadData(data, ref size)) { // Error } if ((int)size != dataSize) { // Error } transBytes += (int)size; // Calculate the throughput QueryPerformanceCounter(out stopTime); duration = (double)(stopTime - startTime) / (double)freq; samples[sampleIndex++] = transBytes / (1024 * 1024 * duration); if (sampleIndex >= samples.Length) { sampleIndex = 0; } throughput = 0; for (int k = 0; k < samples.Length; ++k) { throughput += samples[k]; } throughput /= samples.Length; lthroughput.Text = String.Format("Throughput: {0:0.0} MB/s", throughput); progressBar.Value = Math.Min(30, (int)throughput); // Restart timer transBytes = 0; QueryPerformanceCounter(out startTime); // Perform GUI operations Application.DoEvents(); } while (!quit); qusb.Close(); }
///////////////////////////////////// // QuickUSB Bulk Streaming Example // ///////////////////////////////////// static void Main(string[] args) { // The number of data buffers to use. An asynchronous data request is issued // for each data buffer, then the main thread waits for each request to complete // then issues a new asynchrnonous request using the same data buffer as the // completed request. To maximize throughout, the number of buffers should be // at least equal to the number of threads (see the SETTING_THREADS setting). uint NumBuffers = 4; // The byte size of the buffers. To maximize performance the buffer size should // be as large as possible and a power of 2. uint BufferByteSize = 512 * 1024; // 512 KB // The number of threads to process the data stream. If NumThreads > 0, then // you are multithreading and must make sure to process access to shared data // from within completion routines. Note that all threads may not be used. The // more processing a completion routine does the more likely another thread will // be used. ushort NumThreads = 4; // The number of processing threads allowed to execute completion routines // concurrenty. If NumThreads > 0, you are multithreading and // ThreadConcurrency must be at least 1. ushort ThreadConcurrency = 2; // The Streaming API (for data reads) can use either data buffers allocated // internally by the QuickUSB API or data buffers allocate by the user. This // example demonstrates how to do either. bool UserAllocatedBuffers = true; // Variables QuickUsb qusb; int k; string[] nameList; bool qResult; QuickUsb.Error qusbError; byte streamID; // The data buffers, BulkStream objects, and tag objects. Because these objects // are passed to and used by unmanaged code in QuickUSB land, they must be handled // with care. They cannot be relocated by the garbage collector and must either // be pinned or allocated in unmanaged memory. Refer to the QuickUsbBulkAsyncCs // sample on how to properly use user 'tag' data. ushort[][] BufferArray = new ushort[NumBuffers][]; // We must keep an active reference to the delegate so it is not garbage collected. // This reference must minimally stay alive until all pending asynchronous requests // have completed. QuickUsb.BulkStreamCompletionRoutine cbDelegate = new QuickUsb.BulkStreamCompletionRoutine(CompletionRoutine); // Query connected modules nameList = QuickUsb.FindModules(); if (nameList.Length == 0) { Console.WriteLine("No modules found."); return; } // Open the first module string name = nameList[0]; Console.WriteLine("Using Device: " + name); qusb = new QuickUsb(name); qResult = qusb.Open(name); if (!qResult) { qusb.Close(); return; } // Display the ID of the currently executing thread (the main thread) Console.WriteLine("Number of processors: " + Environment.ProcessorCount.ToString()); Console.WriteLine("Main thread id: " + Thread.CurrentThread.ManagedThreadId.ToString()); Console.WriteLine(); // Allocate buffers if (UserAllocatedBuffers) { for (k = 0; k < NumBuffers; ++k) { // Allocate the data buffers in unmanaged memory BufferArray[k] = new ushort[BufferByteSize / 2]; } } // Start throughput timer QueryPerformanceFrequency(out freq); QueryPerformanceCounter(out tStart); // Start the data stream Console.WriteLine("Acquiring data. Press any key to stop..."); if (UserAllocatedBuffers) { // Start streaming data to our user allocated data buffers qResult = qusb.ReadBulkDataStartStream(BufferArray, NumBuffers, BufferByteSize, cbDelegate, IntPtr.Zero, out streamID, NumThreads, ThreadConcurrency); } else { // Start streaming data to data buffers that will be allocated interally by the Streaming API qResult = qusb.ReadBulkDataStartStream(IntPtr.Zero, NumBuffers, BufferByteSize, cbDelegate, IntPtr.Zero, out streamID, NumThreads, ThreadConcurrency); } if (!qResult) { qusbError = qusb.LastError(); Console.WriteLine("ReadBulkDataStartStream failed with error {0}", qusbError); } else { // Wait will data gets acquired and processed in the background while (!Console.KeyAvailable) { //--------------------------------------------------------- // Performing some background tasks //--------------------------------------------------------- // If we are not multithreading the stream in this example, we must // allow time for processing requests. Processing requests simply // means checking if a request has completed, execute its completion // routine, and re-issue the requests. QuickUsb.ProcessStream will // return when either any request has completed or the specified time // has elapsed. if (NumThreads == 0) { qResult = qusb.ProcessStream(streamID, 50); if (!qResult) { qusbError = qusb.LastError(); Console.WriteLine("ProcessStream failed with error {0}", qusbError); break; } } else { // Our background threads are processing the stream so we will // just not hog the processor Thread.Sleep(50); } } // Stop the data stream Console.WriteLine("Stopping data aquisition"); qResult = qusb.StopStream(streamID, false); if (!qResult) { qusbError = qusb.LastError(); Console.WriteLine("BulkDataStopStream failed with error {0}", qusbError); } } // Stop the throughput timer QueryPerformanceCounter(out tEnd); tElapsed = (double)(tEnd - tStart) / (double)(freq); Console.WriteLine(); Console.WriteLine("Time elapsed: {0:0.000} s", tElapsed); Console.WriteLine("Total bytes transferred: {0:0.000} MB", ((float)TotalBytes / (1024.0 * 1024.0))); Console.WriteLine("Data rate: {0:0.000} MS/s", ((TotalBytes / (1024.0 * 1024.0)) / tElapsed)); Console.WriteLine(); // Report any leaks or errors Console.WriteLine("{0} transaction(s) failed", ErrorCount); Console.WriteLine(); foreach (KeyValuePair <int, int> kv in ThreadIds) { Console.WriteLine("Thread #{0} used for {1} completion routine callbacks", kv.Key, kv.Value); } // Close the module qResult = qusb.Close(); if (!qResult) { Console.WriteLine("QuickUSB Error: {0}", qusb.LastError()); return; } return; }
/////////////////////////////////// // QuickUSB Asynchronous Example // /////////////////////////////////// static void Main(string[] args) { // The number of data buffers to use. An asynchronous data request is issued // for each data buffer, then the main thread waits for each request to complete // then issues a new asynchrnonous request using the same data buffer as the // completed request. To maximize throughout, the number of buffers should be // at least equal to the number of threads (see the SETTING_THREADS setting). const int NumBuffers = 8; // The byte size of the buffers. To maximize performance the buffer size should // be as large as possible and a power of 2. const int BufferByteSize = 512 * 1024; // 512 KB // The number of times to issue a request for each buffer. const int LOOPS = 50; // Variables int k, j, Id = 0; string[] nameList; bool qResult; QuickUsb.Error qusbError; // Variables to track time and performace long tStart, tEnd, freq; double tElapsed; // The data buffers, BulkStream objects, and tag objects. Because these objects // are passed to and used by unmanaged code in QuickUSB land, they must be handled // with care. They cannot be relocated by the garbage collector and must either // be pinned or allocated in unmanaged memory. ushort[][] BufferArray = new ushort[NumBuffers][]; QuickUsb.BulkStream[] BulkStream = new QuickUsb.BulkStream[NumBuffers]; BulkStreamTag[] tag = new BulkStreamTag[NumBuffers]; // We must keep an active reference to the delegate so it is not garbage collected. // This reference must minimally stay alive until all pending asynchronous requests // have completed. QuickUsb.BulkStreamCompletionRoutine cbDelegate = new QuickUsb.BulkStreamCompletionRoutine(CompletionRoutine); // Query connected modules nameList = QuickUsb.FindModules(); if (nameList.Length == 0) { Console.WriteLine("No modules found."); return; } // Open the first module qusb = new QuickUsb(nameList[0]); qusb.Open(nameList[0]); // Allocate buffers for (k = 0; k < NumBuffers; ++k) { // Allocate the data buffers in unmanaged memory BufferArray[k] = new ushort[BufferByteSize / 2]; // Allocate the BulkStream objects BulkStream[k] = new QuickUsb.BulkStream(); // Create the tag object as normal. We will later get a pinned reference to this // object to use in issuing the request, that we will later be able to use to // reconstruct a reference to the managed tag object in the completion routine. // We can do this because the tag data is never accessed or modified in unmanaged // land and only ever used in managed land. tag[k] = new BulkStreamTag(); } // Start throughput timer QueryPerformanceFrequency(out freq); QueryPerformanceCounter(out tStart); Console.WriteLine("Acquiring data...please wait"); // Aquire for (j = 0; j < (LOOPS + 1); ++j) { for (k = 0; k < NumBuffers; ++k) { // If this is not the first loop, wait for the last transaction to complete if (j != 0) { // Wait for the transaction to complete. Once this function returns successfully // the completion routine has already been executed and the transaction is // entirely complete. qResult = qusb.BulkWait(BulkStream[k], false); if (!qResult) { qusbError = qusb.LastError(); Console.WriteLine("Request failed (QuickUSB Error: {0})", qusb.LastError()); } else { // Now that this request has completed we may process the data here or in the // completion routine, though it is better to perform all processing in the // completion routine as they can be multi-threaded, allowing the main thread // to simply issue and re-issue data requests. } } // If this is not the last loop, issue a new transaction if (j != LOOPS) { //Console.WriteLine("Issuing Request #{0}", (Id + 1)); // Issue a new transaction tag[k].Id = ++Id; qResult = qusb.ReadBulkDataAsync( BufferArray[k], BufferByteSize, BulkStream[k], cbDelegate, GCHandle.ToIntPtr(GCHandle.Alloc(tag[k]))); if (!qResult) { Console.WriteLine(String.Format("QuickUSB Error: {0}", qusb.LastError())); qusb.Close(); return; } else { ++RefCount; ++TransCount; } } } } // Stop the throughput timer QueryPerformanceCounter(out tEnd); tElapsed = (double)(tEnd - tStart) / (double)(freq); Console.WriteLine(); Console.WriteLine("Time elapsed: {0:0.000} s", tElapsed); Console.WriteLine("Total bytes transferred: {0:0.000} MB", ((float)TotalBytes / (1024.0 * 1024.0))); Console.WriteLine("Data rate: {0:0.000} MS/s", ((TotalBytes / (1024.0 * 1024.0)) / tElapsed)); Console.WriteLine(); // Close the module qResult = qusb.Close(); if (!qResult) { Console.WriteLine("QuickUSB Error: {0}", qusb.LastError()); return; } // Report any leaks or errors Console.WriteLine("{0} transaction(s) issued in total", TransCount); Console.WriteLine("{0} transaction(s) failed", ErrorCount); Console.WriteLine("{0} transaction(s) are still outstanding", RefCount); return; }