//Author: LabJack
//July 18, 2007
//This example program calls the Feedback low-level function in a continuous loop
//and logs readings to a file.  It will read the voltages from AIN0-AIN3, set and 
//read the states and directions from FIO2 - FIO3, set DAC0, read Counter0 (FIO1).  
//This example also uses the ConfigIO and ConfigTimerClock low-level functions to configure the 
//IO channels and set the timer clock.  The first UE9 device found is used in this example. 
//For the example to run the UE9 needs Control firmware version 1.83 or above for timer
//and counter reads to work properly from a Feedback call.

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

namespace ue9Logger
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class ue9Logger : System.Windows.Forms.Form
	{
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.Label label3;
		private System.Windows.Forms.Label label4;
		private System.Windows.Forms.Label label5;
		private System.Windows.Forms.Label label6;
		private System.Windows.Forms.Label label8;
		private System.Windows.Forms.Label label9;
		private System.Windows.Forms.TextBox errorBox;
		private System.Windows.Forms.Label ain0lbl;
		private System.Windows.Forms.Label ain1lbl;
		private System.Windows.Forms.Label ain2lbl;
		private System.Windows.Forms.Panel panel1;
		private System.Windows.Forms.Panel panel2;
		private System.Windows.Forms.Label label10;
		private System.Windows.Forms.Label label11;
		private System.Windows.Forms.Label label12;
		private System.Windows.Forms.Label label13;
		private System.Windows.Forms.Label label14;
		private System.Windows.Forms.Panel panel3;
		private System.Windows.Forms.Panel panel4;
		private System.Windows.Forms.Label label16;
		private System.Windows.Forms.MainMenu mainMenu1;
		private System.Windows.Forms.TextBox dac0Box;
		private System.Windows.Forms.Label ain3lbl;
		private System.Windows.Forms.Panel panel5;
		private System.Windows.Forms.Label label7;
		private System.Windows.Forms.Button startButton;
		private System.Windows.Forms.CheckBox hzCB;
		private System.Windows.Forms.TextBox intervalBox;
		private System.Windows.Forms.Label count0lbl;
		private System.Windows.Forms.CheckBox fio2StateCB;
		private System.Windows.Forms.CheckBox fio2DirCB;
		private System.Windows.Forms.CheckBox fio3DirCB;
		private System.Windows.Forms.CheckBox fio3StateCB;	

		//ain0-3 voltage
		private double ain0;
		private double ain1;
		private double ain2;
		private double ain3;
		
		//fio4-5 state
		private bool fio2State;	
		private bool fio3State;
		
		private UInt32 count0;		//Counter0 count
		private UInt32 lastCount0;	//The previous counter count
		private string error;		//error
		private double dac0;		//dac0
		private bool updateFIODAC;	//update dac0, fio4, and fio5?
		private bool openUE9;		//open ue9 device?
		private bool exitApp;		//exit application?
		private UE9 ue9;			//UE9 device object

		private StreamWriter sWriter;	//Writes to a log file
		private long intervalTickCount;	//The tick count at the start of each backround thread loop iteration.
										//Used to keep track of the time elapsed.

		private UInt32 lastUE9SystemTimer;	//The previous UE9 system timer value
		private UInt32 UE9SystemTimer;		//The current UE9 system timer value

		private long tickCount;			//The tick count after a Feedback call
		private long startingTickCount;	//The tick count that will be written to the file (TimeStamp)
		private long tickCountOverlap;	//The number of times the windows TickCount has started over and passed startingTickCount (to handle the 32bit signed int wrap around)
		private bool logging;			//Indicates whether logging to a file should be performed
		private bool firstLog;			//Indicates that this is the first time logging to this file
		private bool resetCounter;		//Indicates whether the counter should be reset or not
		private long loggingTimeTrack;  //The time elapsed in ms since the last log file write
		private long displayTimeTrack;	//The time elapsed in ms since the last GUI display update
		private const long displayTimeInterval = 1000;	//How often the GUI display should update (in ms)
		private int loggingTimeInterval;  //How often the log file should be written to

		private const int backgroundTimeInterval = 10;	//How often the background thread executes (in ms)

		private byte resolution;


		public ue9Logger()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			myInit();
			fio2State = false;
			fio3State = false;
			dac0 = 0;
			error = "";
			errorBox.Text = "";
			exitApp = false;
			sWriter = null;
			tickCount = 0;
			logging = false;
			resetCounter = false;
			firstLog = false;
			resolution = 17;
			loggingTimeInterval = 1000;
			intervalTickCount = UE9.getTickCount();

			Thread updateThread = new Thread(new ThreadStart(backgroundThread));
			updateThread.Start();
		}

		/// <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.mainMenu1 = new System.Windows.Forms.MainMenu();
			this.label1 = new System.Windows.Forms.Label();
			this.label2 = new System.Windows.Forms.Label();
			this.label3 = new System.Windows.Forms.Label();
			this.label4 = new System.Windows.Forms.Label();
			this.label5 = new System.Windows.Forms.Label();
			this.label6 = new System.Windows.Forms.Label();
			this.label8 = new System.Windows.Forms.Label();
			this.label9 = new System.Windows.Forms.Label();
			this.errorBox = new System.Windows.Forms.TextBox();
			this.ain0lbl = new System.Windows.Forms.Label();
			this.ain1lbl = new System.Windows.Forms.Label();
			this.ain2lbl = new System.Windows.Forms.Label();
			this.ain3lbl = new System.Windows.Forms.Label();
			this.count0lbl = new System.Windows.Forms.Label();
			this.panel1 = new System.Windows.Forms.Panel();
			this.label13 = new System.Windows.Forms.Label();
			this.label10 = new System.Windows.Forms.Label();
			this.panel2 = new System.Windows.Forms.Panel();
			this.fio2StateCB = new System.Windows.Forms.CheckBox();
			this.fio2DirCB = new System.Windows.Forms.CheckBox();
			this.label14 = new System.Windows.Forms.Label();
			this.label12 = new System.Windows.Forms.Label();
			this.label11 = new System.Windows.Forms.Label();
			this.fio3DirCB = new System.Windows.Forms.CheckBox();
			this.fio3StateCB = new System.Windows.Forms.CheckBox();
			this.panel3 = new System.Windows.Forms.Panel();
			this.hzCB = new System.Windows.Forms.CheckBox();
			this.panel4 = new System.Windows.Forms.Panel();
			this.dac0Box = new System.Windows.Forms.TextBox();
			this.label16 = new System.Windows.Forms.Label();
			this.panel5 = new System.Windows.Forms.Panel();
			this.startButton = new System.Windows.Forms.Button();
			this.intervalBox = new System.Windows.Forms.TextBox();
			this.label7 = new System.Windows.Forms.Label();
			// 
			// label1
			// 
			this.label1.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label1.Location = new System.Drawing.Point(16, 32);
			this.label1.Size = new System.Drawing.Size(16, 16);
			this.label1.Text = "0";
			// 
			// label2
			// 
			this.label2.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label2.Location = new System.Drawing.Point(16, 56);
			this.label2.Size = new System.Drawing.Size(16, 16);
			this.label2.Text = "1";
			// 
			// label3
			// 
			this.label3.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label3.Location = new System.Drawing.Point(16, 80);
			this.label3.Size = new System.Drawing.Size(16, 16);
			this.label3.Text = "2";
			// 
			// label4
			// 
			this.label4.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label4.Location = new System.Drawing.Point(16, 104);
			this.label4.Size = new System.Drawing.Size(16, 16);
			this.label4.Text = "3";
			// 
			// label5
			// 
			this.label5.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label5.Location = new System.Drawing.Point(16, 32);
			this.label5.Size = new System.Drawing.Size(16, 20);
			this.label5.Text = "2";
			// 
			// label6
			// 
			this.label6.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label6.Location = new System.Drawing.Point(16, 56);
			this.label6.Size = new System.Drawing.Size(16, 20);
			this.label6.Text = "3";
			// 
			// label8
			// 
			this.label8.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label8.Location = new System.Drawing.Point(8, 8);
			this.label8.Size = new System.Drawing.Size(80, 16);
			this.label8.Text = "Cnt0(FIO1):";
			// 
			// label9
			// 
			this.label9.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label9.Location = new System.Drawing.Point(8, 240);
			this.label9.Size = new System.Drawing.Size(56, 16);
			this.label9.Text = "Error";
			// 
			// errorBox
			// 
			this.errorBox.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(224)), ((System.Byte)(224)), ((System.Byte)(224)));
			this.errorBox.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular);
			this.errorBox.Location = new System.Drawing.Point(56, 232);
			this.errorBox.Multiline = true;
			this.errorBox.ReadOnly = true;
			this.errorBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
			this.errorBox.Size = new System.Drawing.Size(168, 32);
			this.errorBox.Text = "";
			// 
			// ain0lbl
			// 
			this.ain0lbl.Location = new System.Drawing.Point(48, 32);
			this.ain0lbl.Size = new System.Drawing.Size(48, 16);
			this.ain0lbl.Text = "99999.999";
			// 
			// ain1lbl
			// 
			this.ain1lbl.Location = new System.Drawing.Point(48, 56);
			this.ain1lbl.Size = new System.Drawing.Size(48, 16);
			this.ain1lbl.Text = "99999.999";
			// 
			// ain2lbl
			// 
			this.ain2lbl.Location = new System.Drawing.Point(48, 80);
			this.ain2lbl.Size = new System.Drawing.Size(48, 16);
			this.ain2lbl.Text = "99999.999";
			// 
			// ain3lbl
			// 
			this.ain3lbl.Location = new System.Drawing.Point(48, 104);
			this.ain3lbl.Size = new System.Drawing.Size(48, 16);
			this.ain3lbl.Text = "99999.999";
			// 
			// count0lbl
			// 
			this.count0lbl.Location = new System.Drawing.Point(96, 8);
			this.count0lbl.Size = new System.Drawing.Size(76, 16);
			this.count0lbl.Text = "4294967296";
			// 
			// panel1
			// 
			this.panel1.BackColor = System.Drawing.Color.White;
			this.panel1.Controls.Add(this.label13);
			this.panel1.Controls.Add(this.label10);
			this.panel1.Controls.Add(this.ain1lbl);
			this.panel1.Controls.Add(this.label2);
			this.panel1.Controls.Add(this.label4);
			this.panel1.Controls.Add(this.label1);
			this.panel1.Controls.Add(this.label3);
			this.panel1.Controls.Add(this.ain3lbl);
			this.panel1.Controls.Add(this.ain0lbl);
			this.panel1.Controls.Add(this.ain2lbl);
			this.panel1.Location = new System.Drawing.Point(8, 56);
			this.panel1.Size = new System.Drawing.Size(104, 128);
			// 
			// label13
			// 
			this.label13.Font = new System.Drawing.Font("Tahoma", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline))));
			this.label13.Location = new System.Drawing.Point(8, 8);
			this.label13.Size = new System.Drawing.Size(32, 16);
			this.label13.Text = "AIN";
			// 
			// label10
			// 
			this.label10.Font = new System.Drawing.Font("Tahoma", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline))));
			this.label10.Location = new System.Drawing.Point(40, 8);
			this.label10.Size = new System.Drawing.Size(56, 16);
			this.label10.Text = "Voltage";
			// 
			// panel2
			// 
			this.panel2.BackColor = System.Drawing.Color.White;
			this.panel2.Controls.Add(this.fio2StateCB);
			this.panel2.Controls.Add(this.fio2DirCB);
			this.panel2.Controls.Add(this.label14);
			this.panel2.Controls.Add(this.label12);
			this.panel2.Controls.Add(this.label11);
			this.panel2.Controls.Add(this.label6);
			this.panel2.Controls.Add(this.label5);
			this.panel2.Controls.Add(this.fio3DirCB);
			this.panel2.Controls.Add(this.fio3StateCB);
			this.panel2.Location = new System.Drawing.Point(120, 56);
			this.panel2.Size = new System.Drawing.Size(112, 80);
			// 
			// fio2StateCB
			// 
			this.fio2StateCB.Location = new System.Drawing.Point(78, 32);
			this.fio2StateCB.Size = new System.Drawing.Size(16, 16);
			this.fio2StateCB.Click += new System.EventHandler(this.fio2StateCB_Click);
			// 
			// fio2DirCB
			// 
			this.fio2DirCB.Location = new System.Drawing.Point(46, 32);
			this.fio2DirCB.Size = new System.Drawing.Size(16, 16);
			this.fio2DirCB.Click += new System.EventHandler(this.fioDirCB_Click);
			// 
			// label14
			// 
			this.label14.Font = new System.Drawing.Font("Tahoma", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline))));
			this.label14.Location = new System.Drawing.Point(8, 8);
			this.label14.Size = new System.Drawing.Size(28, 16);
			this.label14.Text = "FIO";
			// 
			// label12
			// 
			this.label12.Font = new System.Drawing.Font("Tahoma", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline))));
			this.label12.Location = new System.Drawing.Point(64, 8);
			this.label12.Size = new System.Drawing.Size(40, 16);
			this.label12.Text = "State";
			// 
			// label11
			// 
			this.label11.Font = new System.Drawing.Font("Tahoma", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline))));
			this.label11.Location = new System.Drawing.Point(40, 8);
			this.label11.Size = new System.Drawing.Size(24, 16);
			this.label11.Text = "Dir";
			// 
			// fio3DirCB
			// 
			this.fio3DirCB.Location = new System.Drawing.Point(46, 56);
			this.fio3DirCB.Size = new System.Drawing.Size(16, 16);
			this.fio3DirCB.Click += new System.EventHandler(this.fioDirCB_Click);
			// 
			// fio3StateCB
			// 
			this.fio3StateCB.Location = new System.Drawing.Point(78, 56);
			this.fio3StateCB.Size = new System.Drawing.Size(16, 16);
			this.fio3StateCB.Click += new System.EventHandler(this.fio3StateCB_Click);
			// 
			// panel3
			// 
			this.panel3.BackColor = System.Drawing.Color.White;
			this.panel3.Controls.Add(this.hzCB);
			this.panel3.Controls.Add(this.count0lbl);
			this.panel3.Controls.Add(this.label8);
			this.panel3.Location = new System.Drawing.Point(8, 192);
			this.panel3.Size = new System.Drawing.Size(224, 32);
			// 
			// hzCB
			// 
			this.hzCB.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.hzCB.Location = new System.Drawing.Point(184, 8);
			this.hzCB.Size = new System.Drawing.Size(40, 20);
			this.hzCB.Text = "Hz";
			this.hzCB.CheckStateChanged += new System.EventHandler(this.hzCB_CheckStateChanged);
			// 
			// panel4
			// 
			this.panel4.BackColor = System.Drawing.Color.White;
			this.panel4.Controls.Add(this.dac0Box);
			this.panel4.Controls.Add(this.label16);
			this.panel4.Location = new System.Drawing.Point(120, 144);
			this.panel4.Size = new System.Drawing.Size(112, 40);
			// 
			// dac0Box
			// 
			this.dac0Box.Location = new System.Drawing.Point(56, 8);
			this.dac0Box.Size = new System.Drawing.Size(48, 22);
			this.dac0Box.Text = "0.000";
			this.dac0Box.LostFocus += new System.EventHandler(this.dac0Box_LostFocus);
			this.dac0Box.GotFocus += new System.EventHandler(this.dac0Box_GotFocus);
			this.dac0Box.Validating += new System.ComponentModel.CancelEventHandler(this.dac0Box_Validating);
			// 
			// label16
			// 
			this.label16.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Bold);
			this.label16.Location = new System.Drawing.Point(8, 8);
			this.label16.Size = new System.Drawing.Size(44, 16);
			this.label16.Text = "DAC0:";
			// 
			// panel5
			// 
			this.panel5.BackColor = System.Drawing.Color.White;
			this.panel5.Controls.Add(this.startButton);
			this.panel5.Controls.Add(this.intervalBox);
			this.panel5.Controls.Add(this.label7);
			this.panel5.Location = new System.Drawing.Point(8, 8);
			this.panel5.Size = new System.Drawing.Size(224, 40);
			// 
			// startButton
			// 
			this.startButton.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.startButton.Location = new System.Drawing.Point(120, 8);
			this.startButton.Size = new System.Drawing.Size(96, 24);
			this.startButton.Text = "Start Logging";
			this.startButton.Click += new System.EventHandler(this.startButton_Click);
			// 
			// intervalBox
			// 
			this.intervalBox.Location = new System.Drawing.Point(64, 8);
			this.intervalBox.Size = new System.Drawing.Size(48, 22);
			this.intervalBox.Text = "1.00";
			this.intervalBox.LostFocus += new System.EventHandler(this.intervalBox_LostFocus);
			this.intervalBox.GotFocus += new System.EventHandler(this.intervalBox_GotFocus);
			this.intervalBox.Validating += new System.ComponentModel.CancelEventHandler(this.intervalBox_Validating);
			// 
			// label7
			// 
			this.label7.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold);
			this.label7.Location = new System.Drawing.Point(8, 8);
			this.label7.Size = new System.Drawing.Size(56, 32);
			this.label7.Text = "Interval (in sec):";
			// 
			// ue9Logger
			// 
			this.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(224)), ((System.Byte)(224)), ((System.Byte)(224)));
			this.Controls.Add(this.panel5);
			this.Controls.Add(this.panel4);
			this.Controls.Add(this.panel3);
			this.Controls.Add(this.panel2);
			this.Controls.Add(this.panel1);
			this.Controls.Add(this.errorBox);
			this.Controls.Add(this.label9);
			this.Menu = this.mainMenu1;
			this.MinimizeBox = false;
			this.Text = "UE9 Logger";
			this.Click += new System.EventHandler(this.focusClick);
			this.Closing += new System.ComponentModel.CancelEventHandler(this.ue9Logging_Closing);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>

		static void Main() 
		{
			Application.Run(new ue9Logger());
		}

		/// <summary>
		///
		/// </summary>
		private void myInit()
		{
			//Initializing variables
			ain0 = 99999.999;
			ain1 = 99999.999;
			ain2 = 99999.999;
			ain3 = 99999.999;
			count0 = 0;
			lastCount0 = 0;
			updateFIODAC = true;
			openUE9 = true;
			this.Invoke(new EventHandler(updateAINLabels));
			this.Invoke(new EventHandler(updateCount0Label));
		}


		/// <summary>
		/// This thread is responsible for UE9 operations, file logging and updating
		/// the GUI's diplayed readings.  All this is done in a while loop that executes
		/// every timerTimeInterval milliseconds
		/// </summary>
		private void backgroundThread()
		{
			int err = 0;
			long curTickCount = 0;
			long timeElapsed = 0;
			double controlFW = 0;

			while(true) 
			{		
				try 
				{
					if(exitApp == true )
					{
						try
						{
							if(openUE9 == false)
							{
								timerCounterConfig_example(false);
								ue9.closeUSBConnection();
							}

							sWriter.Flush();
							sWriter.Close();
						}
						catch{}

						this.Close();
						return;
					}

					err = 0;

					try
					{
						curTickCount = UE9.getTickCount();
						timeElapsed = ((curTickCount < intervalTickCount)?(2147483648 - intervalTickCount + curTickCount):(curTickCount - intervalTickCount));

						intervalTickCount = curTickCount;

						if(logging == true) 
							loggingTimeTrack += timeElapsed;
						displayTimeTrack += timeElapsed;

						if((updateFIODAC || logNow() || displayNow()) && this.Visible) 
						{
							if(displayNow())
							{
								error = "";
								this.Invoke(new EventHandler(updateErrorBox));
							}

							if(openUE9 == true)
							{
								
								//Creating new UE9 object and opening first found UE9
								ue9 = new UE9();
								if( (err = ue9.openUSBConnection(-1)) < 0)
								{
									error = getError(err);
									throw new Exception();
								}

								openUE9 = false;

								controlFW = getUE9ControlFWVersion();

								//UE9 needs Control firmware version 1.83 or above for timers
								//and counters reads to work properly from a Feedback call.
								if(controlFW < 1.83) 
								{
									error = "Error: UE9 needs Control Firmware V1.83";
									throw new Exception();
								}

								//Getting the opened UE9's calibration information
								if( (err = ue9.getCalibrationInfo()) < 0)
								{
									error = getError(err);
									throw new Exception();
								}

								//Configure counters and timers
								if( (err = timerCounterConfig_example(true)) < 0)
								{
									error = getError(err);
									throw new Exception();
								}
							}
							
							if( (err = feedbacklog_example()) < 0)
							{
								error = getError(err);
								throw new Exception();
							}
						}

					}
					catch(Exception e)
					{
						if(displayNow())
						{
							this.Invoke(new EventHandler(updateErrorBox));
							while(displayTimeTrack >= displayTimeInterval)
								displayTimeTrack -= displayTimeInterval;
						}
						if(openUE9 == false)
							ue9.closeUSBConnection();
		
						myInit();
						controlFW = 0;
					}
			
					Thread.Sleep(backgroundTimeInterval);
				}
				catch(Exception e)
				{
					if(displayNow())
					{
						error += ", " + e.ToString();
						this.Invoke(new EventHandler(updateErrorBox));
					}
				}				
			}
			exitApp = true;
			this.Close();
		}

		/// <summary>
		/// Gets the UE9 Control firmware version using the ControlConfig low-level function.
		/// </summary>
		/// <returns>UE9 Control firmware version, or negative value on error.</returns>
		private double getUE9ControlFWVersion()
		{
			byte []sendBuff = new byte[18];
			byte []recBuff = new byte[24];
			ushort checksumTotal;

			sendBuff[1] = (byte)(0xF8);  //command byte
			sendBuff[2] = (byte)(0x06);  //number of data words
			sendBuff[3] = (byte)(0x08);  //extended command number

			for(int i = 6; i < 18; i++)
				sendBuff[i] = (byte)(0x00);

			UE9.extendedChecksum(ref sendBuff,18);
  
			try
			{
				if(UE9.LJUSB_BulkWrite(ue9.handle, UE9.UE9_PIPE_EP1_OUT, sendBuff, 18) != 18)
					throw new Exception();
			}
			catch(System.Exception)
			{
				return -14;
			}

			try
			{
				if(UE9.LJUSB_BulkRead(ue9.handle, UE9.UE9_PIPE_EP1_IN, recBuff, 24) != 24)
					throw new Exception();
			}
			catch(System.Exception)
			{
				return -15;
			}

			
			checksumTotal = UE9.extendedChecksum16(recBuff, 24);
			if( (byte)((checksumTotal / 256) & 0xff) != recBuff[5])
				return -16;

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

			if( UE9.extendedChecksum8(recBuff) != recBuff[0])
				return -17;


			if( recBuff[1] != (byte)(0xF8) || recBuff[2] != (byte)(0x09) || recBuff[3] != (byte)(0x08) )
				return -10;

			if( recBuff[6] != 0)
			{
				ue9.errorcode = (int)recBuff[6];
				return -18;
			}
 
			return ((double)recBuff[10]  + (double)recBuff[9]/100.0);
		}

		/// <summary>
		/// Configures the timer 0 mode and its value using, and counter 0 using TimerCounter 
		/// low-level function.  The timer mode will be set to a system timer low. 
		/// </summary>
		/// <param name="enable">Pass true enable timer and counter, or false to disable.</param>
		/// <returns>A negative error value on error, 0 on success.</returns>
		private int timerCounterConfig_example(bool enable)
		{
			byte []sendBuff = new byte[30];
			byte []recBuff = new byte[40];
			ushort checksumTotal;


			sendBuff[1] = (byte)(0xF8);	//command byte
			sendBuff[2] = (byte)(0x0C);	//number of data words
			sendBuff[3] = (byte)(0x18);	//extended command number

			if(enable)
			{
				sendBuff[6] = 1;			//TimerClockDivisor = 1
				sendBuff[7] = 137;			//EnableMask : Updating Config,  1 Timer enabled, Counter0 enabled
				sendBuff[8] = (byte)(0x00);	//TimerClockConfig = 750 kHz
				sendBuff[9] = 0;			//UpdateReset

				sendBuff[10] = 10;			//Timer0Mode = System timer low read
				sendBuff[11] = 0;			//Timer0Value (low byte)
				sendBuff[12] = 0;			//Timer0Value (high byte)
  
				//Timers 1-5 are not enabled, modes and values are set to zero
				for(int i = 13; i < 28; i++)
					sendBuff[i] = 0;

				sendBuff[28] = 0;	//Counter0Mode (pass 0)
				sendBuff[29] = 0;	//Counter1Mode (not enabled) 
			}
			else
			{
				sendBuff[6] = 1;			//TimerClockDivisor = 1
				sendBuff[7] = 128;			//EnableMask : disabling timers and counters
				sendBuff[8] = (byte)(0x00);	//TimerClockConfig = 750 kHz

				for(int i = 9; i < 30; i++)
					sendBuff[i] = 0;
			}

			UE9.extendedChecksum(ref sendBuff, 30);

			if(UE9.LJUSB_BulkWrite(ue9.handle, UE9.UE9_PIPE_EP1_OUT, sendBuff, 30) != 30)
				return -14;
			
			if(UE9.LJUSB_BulkRead(ue9.handle, UE9.UE9_PIPE_EP1_IN, recBuff, 40) != 40)
				return -15;
			
			checksumTotal = UE9.extendedChecksum16(recBuff, 40);
			if( (byte)((checksumTotal / 256) & 0xff) != recBuff[5] || (byte)(checksumTotal & 0xff) != recBuff[4])
				return -16;

			if( UE9.extendedChecksum8(recBuff) != recBuff[0])
				return -17;

			if(recBuff[1] != (byte)(0xF8) || recBuff[2] != (byte)(0x11) || recBuff[3] != (byte)(0x18))
				return -10;
  
			if(recBuff[6] != 0)
			{
				ue9.errorcode = (int)recBuff[6];
				return -18;
			}

			return 0;
		}

		/// <summary>
		///  Resets Counter 0.
		/// </summary>
		/// <returns>A negative error value on error, 0 on success.</returns>
		private int resetCounter0() 
		{
			byte []sendBuff = new byte[30];
			byte []recBuff = new byte[40];
			ushort checksumTotal;


			sendBuff[1] = (byte)(0xF8);	//command byte
			sendBuff[2] = (byte)(0x0C);	//number of data words
			sendBuff[3] = (byte)(0x18);	//extended command number

			sendBuff[6] = 1;			//TimerClockDivisor = 1
			sendBuff[7] = 0;			//EnableMask
			sendBuff[8] = (byte)(0x00);	//TimerClockConfig = 750 kHz
			sendBuff[9] = 64;			//UpdateReset: Counter 0

			for(int i = 10; i < 30; i++)
				sendBuff[i] = 0;

			UE9.extendedChecksum(ref sendBuff, 30);

			if(UE9.LJUSB_BulkWrite(ue9.handle, UE9.UE9_PIPE_EP1_OUT, sendBuff, 30) != 30)
				return -14;

			if(UE9.LJUSB_BulkRead(ue9.handle, UE9.UE9_PIPE_EP1_IN, recBuff, 40) != 40)
				return -15;
			
			checksumTotal = UE9.extendedChecksum16(recBuff, 40);
			if( (byte)((checksumTotal / 256) & 0xff) != recBuff[5] || (byte)(checksumTotal & 0xff) != recBuff[4])
				return -16;

			if( UE9.extendedChecksum8(recBuff) != recBuff[0])
				return -17;

			if(recBuff[1] != (byte)(0xF8) || recBuff[2] != (byte)(0x11) || recBuff[3] != (byte)(0x18))
				return -10;
  
			if(recBuff[6] != 0)
			{
				ue9.errorcode = (int)recBuff[6];
				return -18;
			}

			return 0;	
		}

		/// <summary>
		/// Reads the voltages of AIN0-4, states of FIO2-3 and the count of counter0 using the Feedback
		/// low-level function.  Also, the direction and states of FIO5-6 and the voltage of DAC0 will
		/// be updated.
		/// </summary>
		/// <returns>A negative error value on error, 0 on success.</returns>
		private int feedbacklog_example()
		{
			byte []sendBuff = new byte[34];
			byte []recBuff = new byte[64];
			ushort checksumTotal = 0;
			ushort voltageBitsS = 0;
			long tempTickCount = 0;

			if(resetCounter)
			{
				resetCounter0();
				resetCounter = false;
				count0 = 0;
			}
			
			sendBuff[1] = (byte)(0xF8);  //command byte
			sendBuff[2] = (byte)(0x0E);  //number of data words
			sendBuff[3] = (byte)(0x00);  //extended command number
			
			sendBuff[6] = 12;	//FIOMask - enabling mask for FIO2-3

			//FIODir - setting directions of FIO2-3
			sendBuff[7] = Convert.ToByte(
				(Convert.ToByte(fio2DirCB.Checked) * 4) + 
				(Convert.ToByte(fio3DirCB.Checked) * 8));
			
			//FIOState - setting states of FIO2-3
			sendBuff[8] = Convert.ToByte(
				(Convert.ToByte(fio2StateCB.Checked) * 4) + 
				(Convert.ToByte(fio3StateCB.Checked) * 8));
			
			//Not enabling masks and not setting direction and state values
			//for EIOs, CIOs and MIOs
			for(int i = 9; i <= 15; i++)
				sendBuff[i] = 0;

			//DAC0: Enabling, updating and setting the voltage
			ue9.analogToCalibratedBinaryVoltage(0, dac0, ref voltageBitsS);
			sendBuff[16] = (byte)(voltageBitsS & 0xff);          //DAC0 (low bits)
			sendBuff[17] = (byte)((voltageBitsS / 256) + 0xc0);  //DAC0 (high bits)

			//DAC1: not setting anything
			sendBuff[18] = 0;  //DAC1 (low bits)
			sendBuff[19] = 0;  //DAC1 (high bits)

			sendBuff[20] = 15;	//AINMask (low bits) - enabling mask of AIN0-4
			sendBuff[21] = 0;	//AINMask (high bits)
			sendBuff[22] = 0;	//AIN14ChannelNumber
			sendBuff[23] = 0;	//AIN15ChannelNumber
			sendBuff[24] = resolution;	//Resolution : setting to 17
			sendBuff[25] = 0;	 //SettlingTime : 0
			sendBuff[26] = (byte)(0x88);  //AIN1_0_BipGain : setting AIN0-1 as bipolar
			sendBuff[27] = (byte)(0x88);  //AIN3_2_BipGain : setting AIN2-3 as bipolar

			//AIN5_4_BipGain - AIN15_14_BipGain
			for(int i = 28; i < 34; i++)
				sendBuff[i] = 0;

			UE9.extendedChecksum(ref sendBuff, 34);
  
			if(UE9.LJUSB_BulkWrite(ue9.handle, UE9.UE9_PIPE_EP1_OUT, sendBuff, 34) != 34)
				return -14;

			if(UE9.LJUSB_BulkRead(ue9.handle, UE9.UE9_PIPE_EP1_IN, recBuff, 64) != 64)
				return -15;

			tempTickCount = UE9.getTickCount();
			lastCount0 = count0;

			if(firstLog && logNow() && logging)
			{
				firstLog = false;
				startingTickCount = tempTickCount;
				tickCount = tempTickCount;
			}

			if(logging) 
			{
				if(tempTickCount >= startingTickCount && tickCount < startingTickCount)
					tickCountOverlap++;

				tickCount = tempTickCount;
			}

			checksumTotal = UE9.extendedChecksum16(recBuff, 64);
			
			if( (byte)((checksumTotal / 256) & 0xff) != recBuff[5])
				return -16;

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

			if( UE9.extendedChecksum8(recBuff) != recBuff[0])
				return -17;

			if(recBuff[1] != (byte)(0xF8) || recBuff[2] != (byte)(0x1D) || recBuff[3] != (byte)(0x00))
				return -10;
		
			updateFIODAC = false;

			//Gwtting FIO4 and 5 states
			fio2State = Convert.ToBoolean( (recBuff[7] / 4) & (0x01));
			fio3State = Convert.ToBoolean( (recBuff[7] / 8) & (0x01));

			//Converting AIN readings from 16 bit value to a voltage
			ue9.binaryToCalibratedAnalogVoltage(8, resolution, (ushort)(recBuff[12] + (recBuff[13] * 256)), ref ain0);
			ue9.binaryToCalibratedAnalogVoltage(8, resolution, (ushort)(recBuff[14] + (recBuff[15] * 256)), ref ain1);
			ue9.binaryToCalibratedAnalogVoltage(8, resolution, (ushort)(recBuff[16] + (recBuff[17] * 256)), ref ain2);
			ue9.binaryToCalibratedAnalogVoltage(8, resolution, (ushort)(recBuff[18] + (recBuff[19] * 256)), ref ain3);

			//Getting the count of Counter0
			count0 = (uint)recBuff[44] + (uint)recBuff[45]*256 + (uint)recBuff[46]*65536 + (uint)recBuff[47]*16777216;

			lastUE9SystemTimer = UE9SystemTimer;
			UE9SystemTimer = (uint)recBuff[52] + (uint)recBuff[53]*256 + (uint)recBuff[54]*65536 + (uint)recBuff[55]*16777216;

			if(logNow() && logging)
			{
				long tickCountElapsed = 0;

				if (tickCount < startingTickCount) 
				{
					tickCountElapsed = 2147483648 - startingTickCount + tickCount + tickCountOverlap*2147483648;
				}
				else
					tickCountElapsed = tickCount - startingTickCount + tickCountOverlap*2147483648;

				//Writing to file
				sWriter.WriteLine( tickCountElapsed + ";" + string.Format("{0:f3}", ain0) + ";" + string.Format("{0:f3}", ain1) + ";" + string.Format("{0:f3}", ain2) + ";" + string.Format("{0:f3}", ain3) + ";" + Convert.ToInt32(fio2DirCB.Checked) + ";" + Convert.ToInt32(fio2State) + ";" + Convert.ToInt32(fio3DirCB.Checked) + ";" + Convert.ToInt32(fio3State) + ";" + getCounter0Value().ToString());
			
				if(loggingTimeInterval == 0)
					loggingTimeTrack = 0;
				else
				{
					while(loggingTimeTrack >= loggingTimeInterval)
						loggingTimeTrack -= loggingTimeInterval;
				}
			}

			if(displayNow()) 
			{
				//Updating the values and check boxes of the application
				this.Invoke(new EventHandler(updateAINLabels));
				this.Invoke(new EventHandler(updateFIOStateCB));
				this.Invoke(new EventHandler(updateCount0Label));
				while(displayTimeTrack >= displayTimeInterval)
					displayTimeTrack -= displayTimeInterval;
			}

			return 0;
		}

		private uint getCounter0Value() 
		{
			if(hzCB.Checked == true) 
			{
				double countDiff = 0;
				double timeDiff = 0;
				if (count0 < lastCount0)
					countDiff = 4294967296 - lastCount0 + count0;
				else
					countDiff = count0 - lastCount0;
				
				if (UE9SystemTimer < lastUE9SystemTimer)
					timeDiff = 4294967296 - lastUE9SystemTimer + UE9SystemTimer;
				else
					timeDiff = UE9SystemTimer - lastUE9SystemTimer;

				//converting UE9 system timer value difference to secs
				timeDiff = timeDiff * 0.0000013;

				if(timeDiff == 0)
					return 0;
				else
					return Convert.ToUInt32(countDiff/timeDiff); 
			}
			else 
				return count0;
		}

		private bool displayNow() 
		{
			if(displayTimeTrack >= displayTimeInterval) 
				return true;
			else return false;
		}

		private bool logNow() 
		{
			if(loggingTimeTrack >= loggingTimeInterval) 
				return true;
			else return false;

		}

	
		/// <summary>
		/// Gets the error message for the application (Does not translate UE9 errorcodes). 
		/// </summary>
		/// <param name="err">The error number.</param>
		/// <returns>The error in string form.</returns>
		public string getError(int err)
		{
			switch(err)
			{
				case 0: return "No error";
				case -1: return "Error";
				case -2: return "Error : Could not find device";
				case -3: return "Error : Problem Communicating with Device";
				case -4: return "Error : Could not close USB device";
				
				case -10: return "Error : received wrong command bytes";
				case -11: return "Error : bad IP address";
				case -12: return "Error : received bad checksum";
				case -13: return "Error : received buffer has wrong IOType";
				case -14: return "Error : send failed";
				case -15: return "Error : receive failed";
				case -16: return "Error : received bad checksum16";
				case -17: return "Error : received bad checksum8";
				case -18: return "Errorcode : " + ue9.errorcode;
 				
				case -50: return "Error : binaryToCalibratedAnalogVoltage error";
				case -51: return "Error : binaryToCalibratedAnalogTemperature error";
				case -52: return "Error : analogToCalibratedBinaryVoltage error";
				case -53: return "Error : binaryToUncalibratedAnalogVoltage error";
				case -54: return "Error : getCalibrationInfo write failed";
				case -55: return "Error : getCalibrationInfo read failed";
				case -56: return "Error : getCalibrationInfo error";
	
				default: return "Unknown error";
			}
		}

		private void updateErrorBox(object sender, System.EventArgs e)
		{
			errorBox.Text = error;
		}

		private void updateAINLabels(object sender, System.EventArgs e)
		{
			ain0lbl.Text = string.Format("{0:f3}", ain0);
			ain1lbl.Text = string.Format("{0:f3}", ain1);
			ain2lbl.Text = string.Format("{0:f3}", ain2);
			ain3lbl.Text = string.Format("{0:f3}", ain3);
		}

		private void updateFIOStateCB(object sender, System.EventArgs e)
		{
			fio2StateCB.Checked = fio2State;
			fio3StateCB.Checked = fio3State;		
		}

		private void updateCount0Label(object sender, System.EventArgs e)
		{
			count0lbl.Text = getCounter0Value().ToString();
		}

		private void dac0Box_Validating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			double dac0Conv = 0;
			try
			{
				if((dac0Conv = Convert.ToDouble(dac0Box.Text)) != dac0)
				{
					if(dac0Conv > 5.0 || dac0Conv < 0.0)
					{
						dac0Box.Text = string.Format("{0:f3}", dac0);
					}
					else
					{
						dac0 = dac0Conv;
						dac0Box.Text = string.Format("{0:f3}", dac0);
					}
				}
			}
			catch
			{
				dac0Box.Text = string.Format("{0:f3}", dac0);
			}
			
			updateFIODAC = true;
		}
		
		private void focusClick(object sender, System.EventArgs e)
		{
			this.Focus();
		}

		private void ue9Logging_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			if(exitApp == false)
			{
				e.Cancel = true;
				exitApp = true;
			}
			else
				e.Cancel = false;
		}

		private void fioDirCB_Click(object sender, System.EventArgs e)
		{
			updateFIODAC = true;
		}

		private void fio2StateCB_Click(object sender, System.EventArgs e)
		{
			
			if(fio2StateCB.Checked == true)
				fio2State = true;
			else
				fio2State = false;
			updateFIODAC = true;
		}

		private void fio3StateCB_Click(object sender, System.EventArgs e)
		{
			if(fio3StateCB.Checked == true)
				fio3State = true;
			else
				fio3State = false;
			updateFIODAC = true;
		}

		private void intervalBox_Validating(object sender, System.ComponentModel.CancelEventArgs e)
		{
			try
			{
				double dIntervalConv = System.Math.Round((Convert.ToDouble(intervalBox.Text)), 2);
				Int32 intervalConv = Convert.ToInt32(dIntervalConv*1000);
				if(intervalConv < 0)
					throw new Exception("Error: Interval value must be zero or greater");

				if(intervalConv > 100000)
					throw new Exception("Error: Interval value must be 1000.00 or less");

				loggingTimeInterval = intervalConv;
			}
			catch(Exception ex) 
			{
				error = "Error: " + ex.Message;
				this.Invoke(new EventHandler(updateErrorBox));
			}
			
			intervalBox.Text = string.Format("{0:f2}",((double)loggingTimeInterval/1000.0));
		}

		private void startButton_Click(object sender, System.EventArgs e)
		{
			try 
			{
				if(logging == true)
				{
					logging = false;

					Thread.Sleep(backgroundTimeInterval +  200);
					try 
					{
						sWriter.Flush();
						sWriter.Close();
					}
					catch {}

					startButton.Text = "Start Logging";
					intervalBox.Enabled = true;
					intervalBox.ReadOnly = false;
				}
				else
				{
					string filePath = @Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName)+"\\"; //System.IO.Directory.GetCurrentDirectory();
					string fileName = "";
					uint count = 1;
					bool loop = true;

					//In loop to create new file dataX.txt in current directory.
					//Existing files will not be appended to or overwritten.
					while(loop == true) 
					{
						fileName = "data"+count+".txt";
						if(File.Exists(filePath+fileName) == false) 
						{
							sWriter = File.CreateText(filePath+fileName);
							loop = false;
						}
						count++;
					}

					DateTime date = DateTime.Now;
					sWriter.WriteLine("Date Created: " + date.ToShortDateString() + " " + date.Hour + ":" + date.Minute + ":" + date.Second);
					sWriter.WriteLine("TimeStamp(ms);AIN0;AIN1;AIN2;AIN3;FIO2Dir;FIO2State;FIO3Dir;FIO3State;Counter0");
					loggingTimeTrack = 0;
					
					startButton.Text = "Stop Logging";
					intervalBox.Enabled = false;
					intervalBox.ReadOnly = true;
					tickCountOverlap = 0;
					resetCounter = true;
					updateFIODAC = true;
					logging = true;
					firstLog = true;
				}
			}
			catch(Exception ex)
			{
				try 
				{
					sWriter.Flush();
					sWriter.Close();
				}
				catch{}

				logging = false;
				startButton.Text = "Start Logging";
				intervalBox.Enabled = true;
				intervalBox.ReadOnly = false;

				error += "Error: " + ex.Message;
				this.Invoke(new EventHandler(updateErrorBox));
			}
		}

		private void intervalBox_GotFocus(object sender, System.EventArgs e)
		{
			intervalBox.BackColor = System.Drawing.Color.FromArgb(0xFFFFA0);
		}

		private void intervalBox_LostFocus(object sender, System.EventArgs e)
		{
			intervalBox.BackColor = System.Drawing.Color.White;
		}

		private void dac0Box_GotFocus(object sender, System.EventArgs e)
		{
			dac0Box.BackColor = System.Drawing.Color.FromArgb(0xFFFFA0);
		}

		private void dac0Box_LostFocus(object sender, System.EventArgs e)
		{
			dac0Box.BackColor = System.Drawing.Color.White;
		}

		private void hzCB_CheckStateChanged(object sender, System.EventArgs e)
		{
			resetCounter = true;
			updateFIODAC = true;
		}
	}
}
