/****************************************************************************
**                   
****************************************************************************
**                    2007 Tell Engineering, Inc.		    
**                          Minneapolis, MN
**                       
**
**                            763-226-6531
**                            763-786-6400
**                            651-636-4211 Fax
**                         www.TellEngineering.com
**                        Larry@TellEngineering.com
****************************************************************************
**   This program is not copyrighted and is in the public domain.
**
**   This program is not warranted in any way. 
****************************************************************************
**                                                                               
//*                                                                                
//* FILENAME : usbApiDemo.c                                                              
//*                                                                                
//* Demo application for usbHidAPI.DLL
//*
//* Author:  Larry Tell, Tell Engineering, 763-226-6531
//*                                        763-786-6400
//*                                        651-636-4211 Fax
//*                                        Larry@TellEngineering.com
//*
//* DESCRIPTION:                                                                   
//*    CVI C source code 
//*                                                                                
//*                                                                                
//*---------------------------------------------------------------------------     
//* RELEASE/REVISION HISTORY:                                                              
//*                                                                                
//*        Revision        Date     	Programmer     	Reason for Change                            
//*        ---------       -----    	-----------   	-----------------                            
//*/
#define VERSION	1.0  	//9/12/07		L. Tell			Started file
//*
//*
//**********************************************************************************
//******************  E N D   O F   H E A D E R  ***********************************
//**********************************************************************************/
/** Function List
***
** main
**
**
************************************************************************************/


/////// MACROS //////////////////////////////////////////////////////////////////
#ifndef TRUE
#define TRUE 	1
#endif

#ifndef FALSE
#define FALSE 	0
#endif

#define MAX_DEVICES		10
	

/////// Includes //////////////////////////////////////////////////////////////////
#include <userint.h>
#include <cviauto.h>
#include "asynctmr.h"
#include <utility.h>
#include <ansi_c.h>
#include "usbHidApi_2A.h"
#include <formatio.h>
#include "usbApiDemo.h"


/////// Variables /////////////////////////////////////////////////////////////////
int mainPnlHdl;
int aboutPnlHdl;
int listPnlHdl;

int rcvTimer, repeatTimer;
int repeatCmd;
int open = 0;

double repeatRate;


/////// Prototypes ////////////////////////////////////////////////////////////////
int CVICALLBACK receivePLCmsg (int panel, int control, int event,
        void *callbackData, int eventData1, int eventData2);
int CVICALLBACK repeatPLCmsg (int panel, int control, int event,
        void *callbackData, int eventData1, int eventData2);
int writeDevice(char *outString);


/******************************************************************************
*	main function
*	
*******************************************************************************/

void main(void)
{

	char tempchar[500], tempchar2[500];
	int i, status;
	int panelWidth, panelHeight;
	
	if (InitCVIRTE (0, 0, 0) == 0)	// Needed if linking in external compiler; harmless otherwise 
		return;	// out of memory 
	
	// Load all panels
	mainPnlHdl = LoadPanel (0, "usbApiDemo.uir", DEMO); 
	aboutPnlHdl = LoadPanel (0, "usbApiDemo.uir", ABOUT); 
	listPnlHdl = LoadPanel (0, "usbApiDemo.uir", LIST); 
	
	// Display the version of the program and library on the about panel and main panel.
	GetLibVersion(tempchar2);
	sprintf (tempchar, "usbHidApi Library version: %s", tempchar2);
	SetCtrlVal (aboutPnlHdl, ABOUT_LIBVER, tempchar);
	SetCtrlVal (mainPnlHdl, DEMO_LIBVER, tempchar);

	sprintf (tempchar, "Program version: %.2f", VERSION);
	SetCtrlVal (aboutPnlHdl, ABOUT_PROGVER, tempchar);
	SetCtrlVal (mainPnlHdl, DEMO_PROGVER, tempchar);

	// Display the about panel for a few seconds.
	DisplayPanel (aboutPnlHdl);
	Delay (5.0);

	// Display the list of devices, "Push" the Refresh button to fill the list.
	DisplayPanel (listPnlHdl);
	listButtons (listPnlHdl, LIST_REFRESH, EVENT_COMMIT, 0, 0, 0);

	// Create a timer to scan for received messages.
	rcvTimer = NewAsyncTimer (0.1, -1, 1, receivePLCmsg, 0);
	
	// Create a Repeat Transmit message timer, initially disabled.
	repeatTimer = NewAsyncTimer (0.1, -1, 0, repeatPLCmsg, 0);
	
	RunUserInterface ();       

}

/******************************************************************************
*	menu
*
*	CALLBACK from menu items on main display
*
*******************************************************************************/
void CVICALLBACK menu (int menuBar, int menuItem, void *callbackData,
		int panel)
{
	char tempChar[500];
	
	
	switch (menuItem)
	{
		case MENU_HELP_ABOUT:

			DisplayPanel (aboutPnlHdl);
	
			
			break;
		case MENU_EXIT:
			
			QuitUserInterface (0);
			
			break;
			
		default:
			
			break;
	}
	
	
	
	return;
	

		
}

/******************************************************************************
*	buttons
*	CALLBACK from controls on main display
*******************************************************************************/
int CVICALLBACK buttons (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
	char stringToSend[100];
	char tempChar[100];
	
	if (event == EVENT_COMMIT)
	{
		switch (control)
		{
			case DEMO_SEND:
				GetCtrlVal (panel, DEMO_XMIT, tempChar);
				GetCtrlVal (panel, DEMO_TID, stringToSend);
				strcat (stringToSend, " ");
				strcat (stringToSend, tempChar);
				writeDevice(stringToSend);
				break;
			case DEMO_SELECT:
				if (open)
				{
					CloseRead();
					CloseWrite();
				}
				DisplayPanel (listPnlHdl);
				listButtons (listPnlHdl, LIST_REFRESH, EVENT_COMMIT, 0, 0, 0);
				
				break;
			case DEMO_CLRRCV:

				DeleteTextBoxLines (mainPnlHdl, DEMO_RCVMSGS, 0, -1);
				
				break;
				
			case DEMO_MORE:
				menu (0, MENU_HELP_ABOUT, 0, 0);

				break;
			case DEMO_RPT:
				GetCtrlVal (panel, DEMO_RPT, &repeatCmd);

				if (!repeatCmd)
				{
					SetAsyncTimerAttribute (repeatTimer, ASYNC_ATTR_ENABLED, FALSE);
					SetCtrlAttribute (panel, DEMO_RATE, ATTR_DIMMED, 1);
					break;
				}

				SetCtrlAttribute (panel, DEMO_RATE, ATTR_DIMMED, 0);
				SetAsyncTimerAttribute (repeatTimer, ASYNC_ATTR_ENABLED, TRUE);
				
				// intentionally no break;
			case DEMO_RATE:
				GetCtrlVal (panel, DEMO_RATE, &repeatRate);
				SetAsyncTimerAttribute (repeatTimer, ASYNC_ATTR_INTERVAL, repeatRate);
				
				
				break;
			case DEMO_EXIT:
				menu (0, MENU_EXIT, 0, 0);

				break;
		}
	}
	return 0;
}

/******************************************************************************
*	listButtons
*	CALLBACK from controls on list display
*******************************************************************************/

int CVICALLBACK listButtons (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
	int i, status;
	static mdeviceList2 pList[MAX_DEVICES];
	static unsigned int selectedDevice, numDevices = 0;
	static char VendorID[MAX_DEVICES][50], MfgrName[MAX_DEVICES][50], SerialNumber[MAX_DEVICES][50];
	char tempChar[500];
	Point cell;
	
	if (event == EVENT_COMMIT)
	{
		switch (control)
		{
			case LIST_OPEN:
				
				// Get the cell the user selected.  We just need the row.
				GetActiveTableCell (panel, LIST_TABLE, &cell);
				
				// The pList array is zero based, the table is one based.
				selectedDevice = cell.y - 1;
				
				// sanity check
				if (selectedDevice >= numDevices)
					return -1;
				
				// call the "Open" function in subHidApi to connect to the device
				open = Open (pList[selectedDevice].VendorID,	  	  // Vendor ID to search     (0xffff if unused)
			             pList[selectedDevice].ProductID,	  // Product ID to search    (0xffff if unused)
			             0, // Manufacturer            (NULL if unused)
			             0,	  // Serial number to search (0xffff if unused)
			             0,	  // Device name to search   (NULL if unused)
			             1);		  // Set TRUE for non-blocking read requests.
				

				// Update the display with the new device information
				SetCtrlVal (mainPnlHdl, DEMO_VID, pList[selectedDevice].VendorID);
				SetCtrlVal (mainPnlHdl, DEMO_PID, pList[selectedDevice].ProductID);
	
				if (strlen(pList[selectedDevice].DeviceName) > 0)
					SetCtrlVal (mainPnlHdl, DEMO_DNAME, pList[selectedDevice].DeviceName);
				else 
					SetCtrlVal (mainPnlHdl, DEMO_DNAME, "");
				
				if (strlen(pList[selectedDevice].SerialNumber) > 0)
					SetCtrlVal (mainPnlHdl, DEMO_SN, pList[selectedDevice].SerialNumber);
				else 
					SetCtrlVal (mainPnlHdl, DEMO_SN, "");
	
				SetCtrlVal (mainPnlHdl, DEMO_INLEN, pList[selectedDevice].InputReportLen);
				SetCtrlVal (mainPnlHdl, DEMO_OUTLEN, pList[selectedDevice].OutputReportLen);

				HidePanel (panel);
				DisplayPanel (mainPnlHdl);

				break;
			case LIST_REFRESH:
				
				// Clear the table 
				DeleteTableRows (panel, LIST_TABLE, 1, -1);
				
				for (i=0; i<MAX_DEVICES; i++)
				{
					pList[i].DeviceName = VendorID[i];
					pList[i].Manufacturer = MfgrName[i];
					pList[i].SerialNumber = SerialNumber[i];
				}
				
				// call the "GetList" function in subHidApi to fill the pList array with
					// information on all connected HID devices.
				numDevices = GetList( 0xFFFF, 
								0xFFFF, 
							   0, 
							   0, 
							   0, 
							   pList, 
							   MAX_DEVICES); 

				
				if (numDevices == MAX_DEVICES)
				{
					sprintf(tempChar, "Found %d devices which is maximum the program can handle.\nSome connected devices may have been missed.", numDevices, MAX_DEVICES);
					MessagePopup ("Device List", tempChar);
					
					numDevices = MAX_DEVICES;
				}
				// sanity check.  This should never happen since we asked for only MAX_DEVICES
				else if (numDevices > MAX_DEVICES)
				{
					sprintf(tempChar, "Found %d devices which exceeds the maximum (%d) the program can handle.", numDevices, MAX_DEVICES);
					MessagePopup ("Device List", tempChar);
					
					numDevices = MAX_DEVICES;
				}
				
				
				// Display the information in pList on the Table
				for (i=0; i<numDevices; i++)
				{
					InsertTableRows (panel, LIST_TABLE, -1, 1, VAL_USE_MASTER_CELL_TYPE);
					
					cell.x = 1;
					cell.y = i+1;
					SetTableCellVal (panel, LIST_TABLE, cell, pList[i].DeviceName);
					
					cell.x = 2;
					SetTableCellVal (panel, LIST_TABLE, cell, pList[i].Manufacturer);

					cell.x = 3;
					SetTableCellVal (panel, LIST_TABLE, cell, pList[i].VendorID);

					cell.x = 4;
					SetTableCellVal (panel, LIST_TABLE, cell, pList[i].ProductID);

					cell.x = 5;
					SetTableCellVal (panel, LIST_TABLE, cell, pList[i].SerialNumber);

					cell.x = 6;
					SetTableCellVal (panel, LIST_TABLE, cell, pList[i].InputReportLen);

					cell.x = 7;
					SetTableCellVal (panel, LIST_TABLE, cell, pList[i].OutputReportLen);
				}
				
				SetCtrlAttribute (panel, LIST_OPEN, ATTR_DIMMED, 0);
				

				break;
			case LIST_CLOSE:
				SetCtrlAttribute (panel, LIST_OPEN, ATTR_DIMMED, 1);

				menu (0, MENU_EXIT, 0, 0);


				break;
		}
	}
	return 0;
}


/******************************************************************************
*
*  PANEL CALLBACK SECTION
*
*******************************************************************************/

/********************************
*	CALLBACK from the mainPanel
********************************/
int CVICALLBACK mainPanel (int panel, int event, void *callbackData,
		int eventData1, int eventData2)
{
	switch (event)
	{
		case EVENT_GOT_FOCUS:

			break;
		case EVENT_LOST_FOCUS:

			break;
		case EVENT_CLOSE:
			menu(0, MENU_EXIT, 0, 0);
			break;
	}
	return 0;
}

int CVICALLBACK aboutPanel (int panel, int event, void *callbackData,
		int eventData1, int eventData2)
{
	switch (event)
	{
		case EVENT_GOT_FOCUS:

			break;
		case EVENT_LOST_FOCUS:
		case EVENT_RIGHT_CLICK:
		case EVENT_LEFT_CLICK:
			// Hide the panel if the user clicks either mouse button
			HidePanel (panel);
		

			break;
		case EVENT_CLOSE:
		

			break;
	}
	return 0;
}
/******************************************************************************
*
*  END PANEL CALLBACK SECTION
*
*******************************************************************************/

/******************************************************************************
*
*  TIMER CALLBACK SECTION
*
*******************************************************************************/

/**************************************************
*	CALLBACK from the receivePLCmsg timer
*   Scan for and display any/all received messages. 
**************************************************/

int CVICALLBACK receivePLCmsg (int panel, int control, int event,
        void *callbackData, int eventData1, int eventData2)
{
#define MAX_RESPONSES		50
#define MAX_RESPONSE_BYTES	9
#define MAX_MSG_SIZE		100

	static unsigned char msg[MAX_MSG_SIZE];
	int i, j, numResp;
	int iret = 0;
	unsigned char inBuf[MAX_RESPONSES][MAX_RESPONSE_BYTES]; 
	unsigned char tempChar[100];
	

	if (open)
	{
		// Clear the input buffers	
		for (i=0; i<MAX_RESPONSES; i++)
		{
			for (j=0; j<MAX_RESPONSE_BYTES; j++)
			{
				inBuf[i][j] = 0;
			}
		}

		numResp = -1;
		iret = 1;
		while ((iret > 0) && (numResp < MAX_RESPONSES))
			iret = Read (inBuf[++numResp]);
	
		// if we received some response(s), display them on the Received message control
		if (numResp)
		{
			for (i=0; i<numResp; i++)
			{
				sprintf(tempChar, " %02X", inBuf[i][0]);
				SetCtrlVal (mainPnlHdl, DEMO_RID, tempChar);
				sprintf(tempChar, " %02X %02X %02X %02X %02X %02X %02X %02X\n", inBuf[i][1], inBuf[i][2], inBuf[i][3], inBuf[i][4], inBuf[i][5], inBuf[i][6], inBuf[i][7], inBuf[i][8]);
				SetCtrlVal (mainPnlHdl, DEMO_RCVMSGS, tempChar);
			}
		}
	}
		
	
	return 0;

}

/**************************************************
*	CALLBACK from the repeatPLCmsg timer
*   (Re-)Send the message in the Transmit control. 
**************************************************/
int CVICALLBACK repeatPLCmsg (int panel, int control, int event,
        void *callbackData, int eventData1, int eventData2)
{
	
	char stringToSend[100];
	char tempChar[100];

	GetCtrlVal (mainPnlHdl, DEMO_XMIT, tempChar);
	GetCtrlVal (mainPnlHdl, DEMO_TID, stringToSend);
	strcat (stringToSend, " ");
	strcat (stringToSend, tempChar);

	writeDevice(stringToSend);
	
	return 0;
}	

/******************************************************************************
*
*  END TIMER CALLBACK SECTION
*
*******************************************************************************/


/******************************************************************************
*
*  SUPPORT FUNCTION SECTION
*
*******************************************************************************/


/**************************************************
*	writeDevice
*   Send the message in the outString argument.
**************************************************/
int writeDevice(char *outString)
{
	int bytes_sent = 0;
	char outBuf[100];

	// 9 bytes max
	sscanf(outString, "%02X %02X %02X %02X %02X %02X %02X %02X %02X", (int *)&outBuf[0], (int *)&outBuf[1], (int *)&outBuf[2], (int *)&outBuf[3], (int *)&outBuf[4], (int *)&outBuf[5], (int *)&outBuf[6], (int *)&outBuf[7], (int *)&outBuf[8]);
	
	bytes_sent = Write(outBuf);

	return 0;
}	
