//Author: LabJack
//April 29, 2008
//This example program reads analog inputs AI0-AI4 using stream mode.  Requires
//a U3 with hardware version 1.21 or higher.

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using LabJack;

namespace u3Stream
{
	public class u3Stream : System.Windows.Forms.Form
	{
		private U3 u3Dev;
		private System.Windows.Forms.Button StreamButton;
		private System.Windows.Forms.Label statusText;
		private System.Windows.Forms.Label ai3;
		private System.Windows.Forms.Label ai2;
		private System.Windows.Forms.Label ai1;
		private System.Windows.Forms.Label ai0;
		private System.Windows.Forms.TextBox aiV3;
		private System.Windows.Forms.TextBox aiV2;
		private System.Windows.Forms.TextBox aiV1;
		private System.Windows.Forms.TextBox aiV0;
		private System.Windows.Forms.Label aiVoltageText;
		private System.Windows.Forms.Label aiText;
		private System.Windows.Forms.Label noScansText;
		private System.Windows.Forms.TextBox noScansBox;
		private System.Windows.Forms.TextBox totPacketsBox;
		private System.Windows.Forms.Label TotPacketsText;
		private System.Windows.Forms.TextBox curPacketsBox;
		private System.Windows.Forms.Label curPacketsText;
		private System.Windows.Forms.MainMenu mainMenu1;
		private System.Windows.Forms.Label idLabel;
		private System.Windows.Forms.NumericUpDown idBox;
		private System.Windows.Forms.TextBox statusBox;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.TextBox backlogBox;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.TextBox aiV4;		
		

		/// <summary>
		/// For this example to work proper, SamplesPerPacket needs to be a multiple of NumChannels.
		/// </summary>
		private const byte NumChannels = 5;
		private System.Windows.Forms.Label label3;
		private System.Windows.Forms.Label label4;
		private System.Windows.Forms.TextBox sampleRateBox;
		private System.Windows.Forms.TextBox scanRateBox;


		/// <summary>
		/// Needs to be 25 to read multiple StreamData responses in one large packet, otherwise can be any value between
		/// 1-25 for 1 StreamData response per packet.
		/// </summary>
		private const byte SamplesPerPacket = 25;
  

		public u3Stream()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			base.Dispose( disposing );
		}
		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.StreamButton = new System.Windows.Forms.Button();
			this.idLabel = new System.Windows.Forms.Label();
			this.statusText = new System.Windows.Forms.Label();
			this.statusBox = new System.Windows.Forms.TextBox();
			this.ai3 = new System.Windows.Forms.Label();
			this.ai2 = new System.Windows.Forms.Label();
			this.ai1 = new System.Windows.Forms.Label();
			this.ai0 = new System.Windows.Forms.Label();
			this.aiV3 = new System.Windows.Forms.TextBox();
			this.aiV2 = new System.Windows.Forms.TextBox();
			this.aiV1 = new System.Windows.Forms.TextBox();
			this.aiV0 = new System.Windows.Forms.TextBox();
			this.aiVoltageText = new System.Windows.Forms.Label();
			this.aiText = new System.Windows.Forms.Label();
			this.noScansText = new System.Windows.Forms.Label();
			this.noScansBox = new System.Windows.Forms.TextBox();
			this.totPacketsBox = new System.Windows.Forms.TextBox();
			this.TotPacketsText = new System.Windows.Forms.Label();
			this.curPacketsBox = new System.Windows.Forms.TextBox();
			this.curPacketsText = new System.Windows.Forms.Label();
			this.mainMenu1 = new System.Windows.Forms.MainMenu();
			this.idBox = new System.Windows.Forms.NumericUpDown();
			this.label1 = new System.Windows.Forms.Label();
			this.aiV4 = new System.Windows.Forms.TextBox();
			this.backlogBox = new System.Windows.Forms.TextBox();
			this.label2 = new System.Windows.Forms.Label();
			this.sampleRateBox = new System.Windows.Forms.TextBox();
			this.label3 = new System.Windows.Forms.Label();
			this.scanRateBox = new System.Windows.Forms.TextBox();
			this.label4 = new System.Windows.Forms.Label();
			// 
			// StreamButton
			// 
			this.StreamButton.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.StreamButton.Location = new System.Drawing.Point(152, 208);
			this.StreamButton.Size = new System.Drawing.Size(72, 24);
			this.StreamButton.Text = "Run";
			this.StreamButton.Click += new System.EventHandler(this.StreamButton_Click);
			// 
			// idLabel
			// 
			this.idLabel.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.idLabel.Location = new System.Drawing.Point(8, 208);
			this.idLabel.Size = new System.Drawing.Size(56, 16);
			this.idLabel.Text = "Local ID";
			// 
			// statusText
			// 
			this.statusText.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.statusText.Location = new System.Drawing.Point(8, 240);
			this.statusText.Size = new System.Drawing.Size(48, 20);
			this.statusText.Text = "Status";
			// 
			// statusBox
			// 
			this.statusBox.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.statusBox.Location = new System.Drawing.Point(56, 240);
			this.statusBox.ReadOnly = true;
			this.statusBox.Size = new System.Drawing.Size(168, 21);
			this.statusBox.Text = "";
			// 
			// ai3
			// 
			this.ai3.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.ai3.Location = new System.Drawing.Point(136, 104);
			this.ai3.Size = new System.Drawing.Size(16, 16);
			this.ai3.Text = "3";
			// 
			// ai2
			// 
			this.ai2.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.ai2.Location = new System.Drawing.Point(136, 80);
			this.ai2.Size = new System.Drawing.Size(16, 16);
			this.ai2.Text = "2";
			// 
			// ai1
			// 
			this.ai1.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.ai1.Location = new System.Drawing.Point(136, 56);
			this.ai1.Size = new System.Drawing.Size(16, 16);
			this.ai1.Text = "1";
			// 
			// ai0
			// 
			this.ai0.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.ai0.Location = new System.Drawing.Point(136, 32);
			this.ai0.Size = new System.Drawing.Size(16, 16);
			this.ai0.Text = "0";
			// 
			// aiV3
			// 
			this.aiV3.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.aiV3.Location = new System.Drawing.Point(160, 104);
			this.aiV3.ReadOnly = true;
			this.aiV3.Size = new System.Drawing.Size(64, 21);
			this.aiV3.Text = "";
			// 
			// aiV2
			// 
			this.aiV2.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.aiV2.Location = new System.Drawing.Point(160, 80);
			this.aiV2.ReadOnly = true;
			this.aiV2.Size = new System.Drawing.Size(64, 21);
			this.aiV2.Text = "";
			// 
			// aiV1
			// 
			this.aiV1.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.aiV1.Location = new System.Drawing.Point(160, 56);
			this.aiV1.ReadOnly = true;
			this.aiV1.Size = new System.Drawing.Size(64, 21);
			this.aiV1.Text = "";
			// 
			// aiV0
			// 
			this.aiV0.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.aiV0.Location = new System.Drawing.Point(160, 32);
			this.aiV0.ReadOnly = true;
			this.aiV0.Size = new System.Drawing.Size(64, 21);
			this.aiV0.Text = "";
			// 
			// aiVoltageText
			// 
			this.aiVoltageText.Font = new System.Drawing.Font("Tahoma", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline))));
			this.aiVoltageText.Location = new System.Drawing.Point(168, 8);
			this.aiVoltageText.Size = new System.Drawing.Size(56, 16);
			this.aiVoltageText.Text = "Voltage";
			this.aiVoltageText.TextAlign = System.Drawing.ContentAlignment.TopCenter;
			// 
			// aiText
			// 
			this.aiText.Font = new System.Drawing.Font("Tahoma", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline))));
			this.aiText.Location = new System.Drawing.Point(128, 8);
			this.aiText.Size = new System.Drawing.Size(24, 16);
			this.aiText.Text = "AI";
			this.aiText.TextAlign = System.Drawing.ContentAlignment.TopCenter;
			// 
			// noScansText
			// 
			this.noScansText.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.noScansText.Location = new System.Drawing.Point(8, 8);
			this.noScansText.Size = new System.Drawing.Size(56, 32);
			this.noScansText.Text = "# of Scans";
			// 
			// noScansBox
			// 
			this.noScansBox.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.noScansBox.Location = new System.Drawing.Point(64, 8);
			this.noScansBox.ReadOnly = true;
			this.noScansBox.Size = new System.Drawing.Size(56, 21);
			this.noScansBox.Text = "";
			// 
			// totPacketsBox
			// 
			this.totPacketsBox.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.totPacketsBox.Location = new System.Drawing.Point(64, 48);
			this.totPacketsBox.ReadOnly = true;
			this.totPacketsBox.Size = new System.Drawing.Size(56, 21);
			this.totPacketsBox.Text = "";
			// 
			// TotPacketsText
			// 
			this.TotPacketsText.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.TotPacketsText.Location = new System.Drawing.Point(8, 48);
			this.TotPacketsText.Size = new System.Drawing.Size(56, 32);
			this.TotPacketsText.Text = "Total Packets";
			// 
			// curPacketsBox
			// 
			this.curPacketsBox.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.curPacketsBox.Location = new System.Drawing.Point(64, 88);
			this.curPacketsBox.ReadOnly = true;
			this.curPacketsBox.Size = new System.Drawing.Size(56, 21);
			this.curPacketsBox.Text = "";
			// 
			// curPacketsText
			// 
			this.curPacketsText.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.curPacketsText.Location = new System.Drawing.Point(8, 88);
			this.curPacketsText.Size = new System.Drawing.Size(56, 32);
			this.curPacketsText.Text = "Packet Counter";
			// 
			// idBox
			// 
			this.idBox.Location = new System.Drawing.Point(64, 208);
			this.idBox.Maximum = new System.Decimal(new int[] {
																  255,
																  0,
																  0,
																  0});
			this.idBox.Minimum = new System.Decimal(new int[] {
																  1,
																  0,
																  0,
																  -2147483648});
			this.idBox.Size = new System.Drawing.Size(56, 20);
			this.idBox.Value = new System.Decimal(new int[] {
																1,
																0,
																0,
																-2147483648});
			// 
			// label1
			// 
			this.label1.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label1.Location = new System.Drawing.Point(136, 128);
			this.label1.Size = new System.Drawing.Size(16, 16);
			this.label1.Text = "4";
			// 
			// aiV4
			// 
			this.aiV4.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.aiV4.Location = new System.Drawing.Point(160, 128);
			this.aiV4.ReadOnly = true;
			this.aiV4.Size = new System.Drawing.Size(64, 21);
			this.aiV4.Text = "";
			// 
			// backlogBox
			// 
			this.backlogBox.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.backlogBox.Location = new System.Drawing.Point(64, 128);
			this.backlogBox.ReadOnly = true;
			this.backlogBox.Size = new System.Drawing.Size(56, 21);
			this.backlogBox.Text = "";
			// 
			// label2
			// 
			this.label2.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.label2.Location = new System.Drawing.Point(8, 128);
			this.label2.Size = new System.Drawing.Size(56, 32);
			this.label2.Text = "Back Log";
			// 
			// sampleRateBox
			// 
			this.sampleRateBox.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.sampleRateBox.Location = new System.Drawing.Point(16, 176);
			this.sampleRateBox.ReadOnly = true;
			this.sampleRateBox.Size = new System.Drawing.Size(88, 21);
			this.sampleRateBox.Text = "";
			// 
			// label3
			// 
			this.label3.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.label3.Location = new System.Drawing.Point(8, 160);
			this.label3.Size = new System.Drawing.Size(96, 16);
			this.label3.Text = "Sample Rate";
			// 
			// scanRateBox
			// 
			this.scanRateBox.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.scanRateBox.Location = new System.Drawing.Point(128, 176);
			this.scanRateBox.ReadOnly = true;
			this.scanRateBox.Size = new System.Drawing.Size(88, 21);
			this.scanRateBox.Text = "";
			// 
			// label4
			// 
			this.label4.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.label4.Location = new System.Drawing.Point(120, 160);
			this.label4.Size = new System.Drawing.Size(96, 16);
			this.label4.Text = "Scan Rate";
			// 
			// u3Stream
			// 
			this.Controls.Add(this.scanRateBox);
			this.Controls.Add(this.label4);
			this.Controls.Add(this.sampleRateBox);
			this.Controls.Add(this.label3);
			this.Controls.Add(this.backlogBox);
			this.Controls.Add(this.label2);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.aiV4);
			this.Controls.Add(this.idBox);
			this.Controls.Add(this.curPacketsBox);
			this.Controls.Add(this.curPacketsText);
			this.Controls.Add(this.totPacketsBox);
			this.Controls.Add(this.TotPacketsText);
			this.Controls.Add(this.noScansBox);
			this.Controls.Add(this.noScansText);
			this.Controls.Add(this.ai3);
			this.Controls.Add(this.ai2);
			this.Controls.Add(this.ai1);
			this.Controls.Add(this.ai0);
			this.Controls.Add(this.aiV3);
			this.Controls.Add(this.aiV2);
			this.Controls.Add(this.aiV1);
			this.Controls.Add(this.aiV0);
			this.Controls.Add(this.aiVoltageText);
			this.Controls.Add(this.aiText);
			this.Controls.Add(this.statusText);
			this.Controls.Add(this.statusBox);
			this.Controls.Add(this.idLabel);
			this.Controls.Add(this.StreamButton);
			this.Menu = this.mainMenu1;
			this.MinimizeBox = false;
			this.Text = "u3Stream USB";

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		static void Main() 
		{
			Application.Run(new u3Stream());
		}

		private void StreamButton_Click(object sender, System.EventArgs e)
		{
			int err = 0;
			u3Dev = new U3();
			clearLabels();

			//Opening U3 over USB
			if( u3Dev.openUSBConnection(Convert.ToInt32(idBox.Value)) < 0)
			{
				statusBox.Text = u3Dev.errorText;
				return;
			}

			//Getting calibration information from U3			
			if( u3Dev.getCalibrationInfo() < 0)
			{
				statusBox.Text = u3Dev.errorText;
				u3Dev.closeUSBConnection();				
				return;
			}

			if( (err = configIO_example()) < 0)
			{
				if(err != -100)
					statusBox.Text = getError(err);
				statusBox.Text += " (ConfigIO)";
			
				u3Dev.closeUSBConnection();
				return;
			}	

			if( (err = StreamConfig_example()) < 0 )
			{			
				statusBox.Text = getError(err) + " (StreamConfig)";
				u3Dev.closeUSBConnection();
				return;
			}

			if( (err = StreamStart()) < 0)
			{
				statusBox.Text = getError(err) + " (StreamStart)";
				u3Dev.closeUSBConnection();
				return;
			}

			statusBox.Text = "Reading Samples...";
			if( (err = StreamData_example()) < 0)
			{
				if(err != -100)
					statusBox.Text = getError(err);
				statusBox.Text += " (StreamData)";

				StreamStop();
				u3Dev.closeUSBConnection();
				return;
			}


			if( (err = StreamStop()) < 0)
			{
				statusBox.Text = getError(err) + " (StreamStop)";
				u3Dev.closeUSBConnection();
				return;
			}

			if( u3Dev.closeUSBConnection() < 0)
			{
				statusBox.Text = u3Dev.errorText;					
				return;
			}

			statusBox.Text = "Done";
		}


		/// <summary>
		/// Sends a ConfigIO low-level command that configures the FIOs as analog and disables DAC1, Timers and Counters for this example. 
		/// </summary>
		/// <returns>Negative number on error, 0 on success.</returns>
		private int configIO_example()
		{
			byte []sendBuff = new byte[12];
			byte []recBuff = new byte[12];
			ushort checksumTotal;

			sendBuff[1] = (byte)(0xF8);	//Command byte
			sendBuff[2] = (byte)(0x03);	//Number of data words
			sendBuff[3] = (byte)(0x0B);	//Extended command number

			sendBuff[6] = 7;	//Writemask : Setting writemask for timerCounterConfig (bit 0),
								//DAC1Enable (bit 1) and FIOAnalog (bit 2)

			sendBuff[7] = 0;	//Reserved
			sendBuff[8] = 64;	//TimerCounterConfig: Disabling all timers and counters, setting
								//                    TimerCounterPinOffset to 4 (bits 4-7)
			sendBuff[9] = 0;	//DAC1Enable : Disabling (For U3 hardware version 1.30 DAC1Enable
								//is always enabled, so setting will be ignored)

			sendBuff[10] = 255;	//FIOAnalog : setting all FIOs as analog inputs
			sendBuff[11] = 0;	//EIOAnalog

			U3.extendedChecksum(ref sendBuff, 12);

			if( U3.LJUSB_BulkWrite(u3Dev.handle, U3.U3_PIPE_EP1_OUT, sendBuff, 12) < 12)
				return -1;;
			
			if( U3.LJUSB_BulkRead(u3Dev.handle, U3.U3_PIPE_EP1_IN, recBuff, 12) < 12)
				return -2;

			checksumTotal = U3.extendedChecksum16(recBuff, 12);
			if( (byte)((checksumTotal/256) & 0xff) != recBuff[5]
				|| (byte)(checksumTotal & 0xff) != recBuff[4])
				return -4;
			
			if( U3.extendedChecksum8(recBuff) != recBuff[0])
				return -3;

			if( recBuff[1] != (byte)(0xF8) || recBuff[2] != (byte)(0x03) || recBuff[3] != (byte)(0x0B) )
				return -6;

			if( recBuff[6] != 0)
			{
				u3Dev.errorcode = recBuff[6];
				return -200;
			}
  
			if( recBuff[8] != 64)
			{
				statusBox.Text = "error : incorrect TimerCounterConfig set";
				return -100;
			}

			if( (recBuff[10]) != 255)
			{
				statusBox.Text = "error : incorrect FIOAnalog set";
				return -100;
			}

			return 0;  
		}


		/// <summary>
		/// Sends a StreamConfig low-level command to configure the stream for AIN0-4. 
		/// </summary>
		/// <returns>Negative number on error, 0 on success.</returns>
		int StreamConfig_example()
		{
			int sendBuffSize = 12 + NumChannels * 2;

			byte []sendBuff = new byte[sendBuffSize];
			byte []recBuff = new byte[8];
			ushort checksumTotal;
			ushort scanInterval;

			sendBuff[1] = (byte)(0xF8);		//command byte
			sendBuff[2] = NumChannels + 3;	//number of data words = NumChannels + 3
			sendBuff[3] = (byte)(0x11);	    //extended command number
			sendBuff[6] = NumChannels;		//NumChannels
			sendBuff[7] = SamplesPerPacket;	//SamplesPerPacket
			sendBuff[8] = 0;				//Reserved
			sendBuff[9] = 1;				//ScanConfig:
											// Bit 7: Reserved
											// Bit 6: Reserved
											// Bit 3: Internal stream clock frequency = b0: 4 MHz
											// Bit 2: Divide Clock by 256 = b0
											// Bits 0-1: Resolution = b01: 11.9-bit effective

			scanInterval = 4000;
			sendBuff[10] = (byte)(scanInterval&(0x00FF));  //scan interval (low byte)
			sendBuff[11] = (byte)(scanInterval/256);       //scan interval (high byte)

			for(int i = 0; i < NumChannels; i++)
			{
				sendBuff[12 + i*2] = (byte)i;	//PChannel = i
				sendBuff[13 + i*2] = 31;		//NChannel = 31: Single Ended
			}

			U3.extendedChecksum(ref sendBuff, sendBuffSize);
			
			try
			{
				if(U3.LJUSB_BulkWrite(u3Dev.handle, U3.U3_PIPE_EP1_OUT, sendBuff, (uint)sendBuffSize) != sendBuffSize)
					throw new Exception();
			}
			catch(System.Exception)
			{
				return -1;
			}

			try
			{
				if(U3.LJUSB_BulkRead(u3Dev.handle, U3.U3_PIPE_EP1_IN, recBuff, 8) != 8)
					throw new Exception();
			}
			catch(System.Exception)
			{
				return -2;
			}

			checksumTotal = U3.extendedChecksum16(recBuff, 8);

			if( (byte)((checksumTotal / 256) & 0xff) != recBuff[5])
				return -4;

			if( (byte)(checksumTotal & 0xff) != recBuff[4])
				return -4;

			if( U3.extendedChecksum8(recBuff) != recBuff[0])
				return -3;

			if( recBuff[1] != (byte)(0xF8) || recBuff[2] != (byte)(0x01) || recBuff[3] != (byte)(0x11) || recBuff[7] != (byte)(0x00))
				return -6;

			if(recBuff[6] != 0)
			{
				u3Dev.errorcode = (int)recBuff[6];
				return -200;
			}

			return 0;
		}

		/// <summary>
		/// Sends a StreamStart low-level command to start streaming.
		/// </summary>
		/// <returns>Negative number on error, 0 on success.</returns>
		int StreamStart()
		{
			byte []sendBuff = new byte[2];
			byte []recBuff = new byte[4];
			
			sendBuff[0] = (byte)(0xA8);  //checksum8
			sendBuff[1] = (byte)(0xA8);  //command byte
  
			try
			{
				if(U3.LJUSB_BulkWrite(u3Dev.handle, U3.U3_PIPE_EP1_OUT, sendBuff, 2) != 2)
					throw new Exception();
			}
			catch(System.Exception)
			{
				return -1;
			}

			try
			{
				if(U3.LJUSB_BulkRead(u3Dev.handle, U3.U3_PIPE_EP1_IN, recBuff, 4) != 4)
					throw new Exception();
			}
			catch(System.Exception)
			{
				return -2;
			}

			if( recBuff[1] != (byte)(0xA9) || recBuff[3] != (byte)(0x00) )
				return -6;

			if(recBuff[2] != 0)
			{
				u3Dev.errorcode = (int)recBuff[2];
				return -200;
			}

			return 0;
		}

		/// <summary>
		/// Reads the StreamData low-level function response in a loop.
		/// All voltages from the stream are stored in the voltages 2D array.
		/// </summary>
		/// <returns>Negative number on error, 0 on success.</returns>
		int StreamData_example()
		{
			long startTime, endTime;
			int recBuffSize = 14 + SamplesPerPacket*2;
			int backLog = 0, packetCounter = 0, currChannel = 0, scanNumber = 0;
			int totalPackets = 0;   //The total number of StreamData responses read
			ushort checksumTotal = 0;
			bool autoRecoveryOn = false;

			int numDisplay = 6;				//Number of times to display streaming information
			int numReadsPerDisplay = 24;	//Number of packets to read before displaying streaming information
			int readSizeMultiplier = 5;		//Multiplier for the StreamData receive buffer size
			int responseSize = 14 + SamplesPerPacket*2;	//The number of bytes in a StreamData response (differs with SamplesPerPacket)

			/* Each StreamData response contains (SamplesPerPacket / NumChannels) * readSizeMultiplier
			* samples for each channel.
			* Total number of scans = (SamplesPerPacket / NumChannels) * readSizeMultiplier * numReadsPerDisplay * numDisplay
			*/
			double [,]voltages = new double[(SamplesPerPacket/NumChannels)*readSizeMultiplier*numReadsPerDisplay*numDisplay, NumChannels];
			byte []recBuff = new byte[responseSize*readSizeMultiplier];
			
			byte []streamData = new byte[responseSize];
			
			statusBox.Text = "Reading Samples...";

			startTime = U3.getTickCount();

			for (int i = 0; i < numDisplay; i++)
			{
				for(int j = 0; j < numReadsPerDisplay; j++)
				{
					/* For USB StreamData, use Endpoint 2 for reads.  You can read the multiple
					 * StreamData responses of 64 bytes only if SamplesPerPacket is 25 to help
					 * improve streaming performance.  In this example this multiple is adjusted
					 * by the readSizeMultiplier variable.
					 */

					//Reading stream response from U3
					try
					{
						if(U3.LJUSB_BulkRead(u3Dev.handle, U3.U3_PIPE_EP2_IN, recBuff, (uint)(responseSize*readSizeMultiplier)) != responseSize*readSizeMultiplier)
							throw new Exception();
					}
					catch(System.Exception)
					{
						return -2;
					}

					//Checking for errors and getting data out of each StreamData response
					for (int m = 0; m < readSizeMultiplier; m++)
					{
						totalPackets++;
						Array.Copy(recBuff, m*responseSize, streamData, 0, responseSize);
						checksumTotal = U3.extendedChecksum16(streamData, recBuffSize);
						if( (byte)((checksumTotal / 256 ) & 0xff) != streamData[5] ||
							(byte)(checksumTotal & 0xff) != streamData[4])
							return -4;

						checksumTotal = U3.extendedChecksum8(streamData);
						if( checksumTotal != streamData[0])
							return -3;

						if( streamData[1] != (byte)(0xF9) || streamData[2] != 4 + SamplesPerPacket || streamData[3] != (byte)(0xC0) )
							return -6;

						//U3 data buffer overflow detected in packet.  Using auto-recovery and reading buffered samples.
						if(streamData[11] == 59)
						{
							if(!autoRecoveryOn)
							{
								statusBox.Text = "Overflow detected in packet " + totalPackets + ".  Using auto-recovery.";
								autoRecoveryOn = true;
							}
						}
						//Auto-recovery report in packet, bytes 6 (LSB) and 7 (MSB) is the number of scans dropped.
						//Auto-recovery is now off.
						else if(streamData[11] == 60)
						{
							statusBox.Text = "Report in packet " + totalPackets + ": " + (recBuff[m*recBuffSize + 6] + recBuff[m*recBuffSize + 7]*256) + " scans dropped.  Auto-recovery off";
							autoRecoveryOn = false;
						}
						//Error not relating to error recovery found
						else if(streamData[11] != 0)
						{
							u3Dev.errorcode = streamData[11];
							return -200;
						}

						if(packetCounter != (int)streamData[10])
						{
							statusBox.Text = "Error : packet cnt. = " + packetCounter + ", received packet cnt. = " + (int) streamData[10];
							return -100;
						}

						backLog = (int)streamData[12 + SamplesPerPacket*2];

						for(int k = 12; k < (12 + SamplesPerPacket*2); k += 2)
						{
							if(u3Dev.calibrationInfo.hardwareVersion >= 1.30)
								u3Dev.binaryToCalibratedAnalogVoltage_hw130((byte)currChannel, 31, (ushort)(streamData[k] + streamData[k+1]*256), ref (voltages[scanNumber, currChannel]));
							else
								u3Dev.binaryToCalibratedAnalogVoltage(false, 31, (ushort)(streamData[k] + streamData[k+1]*256), ref (voltages[scanNumber, currChannel]));
							currChannel++;
							if(currChannel >= NumChannels)
							{
								currChannel = 0;
								scanNumber++;
							}
						}

						if(packetCounter >= 255)
							packetCounter = 0;
						else
							packetCounter++;
					}
				}

				noScansBox.Text = Convert.ToInt32(scanNumber).ToString();
				totPacketsBox.Text = Convert.ToInt32(totalPackets).ToString();
				curPacketsBox.Text = Convert.ToInt32(((packetCounter == 0) ? 255 : packetCounter-1)).ToString();
				backlogBox.Text = Convert.ToInt32(backLog).ToString();

				aiV0.Text = string.Format("{0:f3}", voltages[scanNumber - 1, 0]);
				aiV1.Text = string.Format("{0:f3}", voltages[scanNumber - 1, 1]);
				aiV2.Text = string.Format("{0:f3}", voltages[scanNumber - 1, 2]);
				aiV3.Text = string.Format("{0:f3}", voltages[scanNumber - 1, 3]);
				aiV4.Text = string.Format("{0:f3}", voltages[scanNumber - 1, 4]);
			}

			endTime = U3.getTickCount();

			sampleRateBox.Text = string.Format("{0:f1} per sec", (scanNumber*NumChannels)/((endTime - startTime)/1000.0));
			scanRateBox.Text = string.Format("{0:f1} per sec", scanNumber/((endTime - startTime)/1000.0));

			return 0;
		}

		/// <summary>
		///  Sends a StreamStop low-level command to stop streaming.
		/// </summary>
		/// <returns>Negative number on error, 0 on success.</returns>
		int StreamStop()
		{
			byte []sendBuff = new byte[2];
			byte []recBuff = new byte[4];
			
			sendBuff[0] = (byte)(0xB0);  //checksum8
			sendBuff[1] = (byte)(0xB0);  //command byte
  
			try
			{
				if(U3.LJUSB_BulkWrite(u3Dev.handle, U3.U3_PIPE_EP1_OUT, sendBuff, 2) != 2)
					throw new Exception();
			}
			catch(System.Exception)
			{
				return -1;
			}

			try
			{
				if(U3.LJUSB_BulkRead(u3Dev.handle, U3.U3_PIPE_EP1_IN, recBuff, 4) != 4)
					throw new Exception();
			}
			catch(System.Exception)
			{
				return -2;
			}

			if( recBuff[1] != (byte)(0xB1) || recBuff[3] != (byte)(0x00) )
				return -6;

			if(recBuff[2] != 0)
			{
				u3Dev.errorcode = (int)recBuff[2];
				return -200;
			}

			return 0;
		}

		private void clearLabels()
		{
			//clearing all the info labels
			statusBox.Text = "";
			noScansBox.Text = "";
			totPacketsBox.Text = "";
			curPacketsBox.Text = "";
			backlogBox.Text = "";
			aiV0.Text = "";
			aiV1.Text = "";
			aiV2.Text = "";
			aiV3.Text = "";
			aiV4.Text = "";
			scanRateBox.Text = "";
			sampleRateBox.Text = "";
		}

		/// <summary>
		///  Gets the error message for the application (Does not translate U3 errorcodes). 
		/// </summary>
		/// <param name="error">The error number.</param>
		/// <returns>The error text.</returns>
		private string getError(int error)
		{
			switch(error)
			{
				case 0: return("");  //no errors
				case -1: return("error : send failed");
				case -2: return("error : receive failed");
				case -3: return("error : received bad checksum8");
				case -4: return("error : received bad checksum16");
				case -5: return("error : received bad checksum");
				case -6: return("error : received wrong command bytes");
				case -7: return("error : received buffer has wrong IOType");
				case -200: return("error : received error code " + u3Dev.errorcode + " from the response"); 
				default: return("error");
			}
		}
	}
}