/** @file sample_xpci3009.c
 
   This demonstarte how to use compare logic in user mode.
 
   @par CREATION  
   @author Krauth Julien
   @date   30.05.06
   
   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim   
   
   @par LICENCE
   @verbatim
    Copyright (C) 2009  ADDI-DATA GmbH for the source code of this module.
        
    ADDI-DATA GmbH
    Airpark Business Center
    Airport Boulevard B210
    77836 Rheinm�nster
    Germany
    Tel: +49(0)7229/1847-0
    Fax: +49(0)7229/1847-200
    http://www.addi-data-com
    info@addi-data.com
        
   This program is free software; you can redistribute it and/or modify it under 
   the terms of the GNU General Public License as published by the Free Software 
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, 
   but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
   or FITNESS FOR A PARTICULAR PURPOSE. 
   See the GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along with 
   this program; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

   You shoud also find the complete GPL in the COPYING file 
   accompanying this source code.
   @endverbatim   
 */ 

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <signal.h>
#include <sys/sysmacros.h> /* major() minor() */

#include <xpci3009.h>
#include "findboards.h"

static uint8_t gb_CompareInterrupt; /* Interrupt flag */
static int gi_fd; /* Global file handle on the board to use */

void v_xpci3009_Signal (int dummy)
{
	uint32_t ul_ArgArray[3];
	int i_ReturnValue = 0;
	
		i_ReturnValue = ioctl (gi_fd,CMD_XPCI3009_TestModuleInterrupt, ul_ArgArray);
			
		if (i_ReturnValue < 0) {
			perror("ioctl");
		}
		else
			{
			printf ("\nAn interrupt occured:");
			printf ("\nModule = %i", ul_ArgArray[0]);		
			printf ("\nInterrupt mask = %u", ul_ArgArray[1]);			
			}
			
		i_ReturnValue = ioctl (gi_fd,CMD_XPCI3009_SetDigitalChlOn, (uint8_t)ul_ArgArray[0]);
		
		/* Test the return value */
		switch (i_ReturnValue)
			{
			case 0:
			printf ("\nCMD_XPCI3009_SetDigitalChlOn OK");
			break;

			case 1:
			printf ("\nCMD_XPCI3009_SetDigitalChlOn error");
			printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
			break;

			case 2:
			printf ("\nCMD_XPCI3009_SetDigitalChlOn error");
			printf ("\nError = %d. The selected module number parameter is wrong", i_ReturnValue);
			break;

			case 3:
			printf ("\nCMD_XPCI3009_SetDigitalChlOn error");
			printf ("\nError = %d. Counter not initialised see function CMD_XPCI3009_InitCounter", i_ReturnValue);
			break;

			default:
			printf ("\nCMD_XPCI3009_SetDigitalChlOn error");
			printf ("\nError = %d.", i_ReturnValue);
			perror("\nioctl");					
			break;
			} // switch (i_ReturnValue)	
			
		gb_CompareInterrupt = 1;			
				
}

//--------------------------------------------------------------------------------

void sample (int fd)
{
	uint8_t b_ModuleNbr = 0;
	int i_ReturnValue = 0;
	uint32_t ul_CounterValue = 0;
	uint8_t i = 0;
	uint8_t b_ArgArray[6];
	uint32_t ui_ArgArray[2];
	int oflags = 0;
		
		gi_fd = fd;
		gb_CompareInterrupt = 0;

		/* Initialise the incremental counter */
		b_ArgArray[0] = b_ModuleNbr;			// The module to use (0 to 3).
		b_ArgArray[1] = XPCI3009_32BIT_COUNTER;	// Selection form counter range.
		b_ArgArray[2] = XPCI3009_SIMPLE_MODE;	// First counter operating mode.
		b_ArgArray[3] = XPCI3009_HYSTERESIS_ON;	// First counter option.
		b_ArgArray[4] = XPCI3009_SIMPLE_MODE;	// Second counter operating mode.
		b_ArgArray[5] = XPCI3009_HYSTERESIS_ON;	// Second counter option.
	   	   	   	   
		i_ReturnValue = ioctl (fd,CMD_XPCI3009_InitCounter, b_ArgArray);

		/* Test the return value */
		switch (i_ReturnValue)
			{
			case 0:
			printf ("\nCMD_XPCI3009_InitCounter OK");

			/* Install the user interrupt routine */
			i_ReturnValue = ioctl (fd,CMD_XPCI3009_SetBoardIntRoutine);

			/* Test the return value */
			switch (i_ReturnValue)
				{
				case 0:
				printf ("\nCMD_XPCI3009_SetBoardIntRoutine OK");
				
				/* request asynchronous SIGIO */
				printf("\nrequest asynchronous SIGIO");
				
				if (signal(SIGIO, &v_xpci3009_Signal) == SIG_ERR)
					{
					perror("signal");
					}
					
				if (fcntl(fd, F_SETOWN, getpid()) == -1)
				{
				perror("fcntl");
				}

				oflags = fcntl(fd, F_GETFL);
				if ( fcntl(fd, F_SETFL, oflags | FASYNC) == -1)
					{
					perror("fcntl");
					}

				/* Clear the counter */
				i_ReturnValue = ioctl (fd,CMD_XPCI3009_ClearCounterValue, b_ModuleNbr);

				/* Test the return value */
				switch (i_ReturnValue)
					{
					case 0:
					printf ("\nCMD_XPCI3009_ClearCounterValue OK");
					break;

					case 1:
					printf ("\nCMD_XPCI3009_ClearCounterValue error");
					printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
					break;

					case 2:
					printf ("\nCMD_XPCI3009_ClearCounterValue error");
					printf ("\nError = %d. The selected module number parameter is wrong", i_ReturnValue);
					break;

					case 3:
					printf ("\nCMD_XPCI3009_ClearCounterValue error");
					printf ("\nError = %d. Counter not initialised", i_ReturnValue);
					break;

					default:
					printf ("\nCMD_XPCI3009_ClearCounterValue error");
					printf ("\nError = %d.", i_ReturnValue);
					perror("\nioctl");					
					break;
					} // switch (i_ReturnValue)

				/* Initialise the compare logic */
				ui_ArgArray[0] = b_ModuleNbr;	// The module to use (0 to 3).
				ui_ArgArray[1] = 1000;			// 32-Bit compare value.
				
				i_ReturnValue = ioctl (fd,CMD_XPCI3009_InitCompareLogic, ui_ArgArray);

				/* Test the return value */
				switch (i_ReturnValue)
					{
					case 0:
					printf ("\nCMD_XPCI3009_InitCompareLogic OK");
					break;

					case 1:
					printf ("\nCMD_XPCI3009_InitCompareLogic error");
					printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
					break;

					case 2:
					printf ("\nCMD_XPCI3009_InitCompareLogic error");
					printf ("\nError = %d. No counter module found", i_ReturnValue);
					break;

					case 3:
					printf ("\nCMD_XPCI3009_InitCompareLogic error");
					printf ("\nError = %d. Counter not initialised", i_ReturnValue);
					break;

					default:
					printf ("\nCMD_XPCI3009_InitCompareLogic error");
					printf ("\nError = %d.", i_ReturnValue);
					perror("\nioctl");						
					break;
					} // switch (i_ReturnValue)

				/* Enable the compare logic */
				i_ReturnValue = ioctl (fd,CMD_XPCI3009_EnableCompareLogic, b_ModuleNbr);

				/* Test the return value */
				switch (i_ReturnValue)
					{
					case 0:
					printf ("\nCMD_XPCI3009_EnableCompareLogic OK");
					break;

					case 1:
					printf ("\nCMD_XPCI3009_EnableCompareLogic error");
					printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
					break;

					case 2:
					printf ("\nCMD_XPCI3009_EnableCompareLogic error");
					printf ("\nError = %d. No counter module found", i_ReturnValue);
					break;

					case 3:
					printf ("\nCMD_XPCI3009_EnableCompareLogic error");
					printf ("\nError = %d. Counter not initialised", i_ReturnValue);
					break;

					case 4:
					printf ("\nCMD_XPCI3009_EnableCompareLogic error");
					printf ("\nError = %d. Compare logic not initialised", i_ReturnValue);
					break;

					case 5:
					printf ("\nCMD_XPCI3009_EnableCompareLogic error");
					printf ("\nError = %d. Interrupt function not initialised", i_ReturnValue);
					perror("\nioctl");						
					break;
					} // switch (i_ReturnValue)

				printf ("\n\n");

				do
					{
					/* Read the 32-Bit counter */
					ul_CounterValue = b_ModuleNbr; /* Pass the module number (0 to 3) */
					
					i_ReturnValue = ioctl (fd,CMD_XPCI3009_Read32BitCounterValue, &ul_CounterValue);

					/* Test the return value */
					switch (i_ReturnValue)
						{
						case 0:
						break;

						case 1:
						printf ("\nCMD_Read32BitCounterValue for the first counter error");
						printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
						break;

						case 2:
						printf ("\nCMD_Read32BitCounterValue for the first counter error");
						printf ("\nError = %d. No counter module found", i_ReturnValue);
						break;

						case 3:
						printf ("\nCMD_Read32BitCounterValue for the first counter error");
						printf ("\nError = %d. Counter not initialised", i_ReturnValue);
						break;

						default:
						printf ("\nCMD_Read32BitCounterValue for the first counter error");
						printf ("\nError = %d.", i_ReturnValue);
						perror("\nioctl");							
						break;
						} // switch (i_ReturnValue)

					/* 
					 * Wait the interrupt signal.
					 * Print the 32-Bit counter value. 
					 */	      
					if (gb_CompareInterrupt) {
						
						i_ReturnValue = ioctl (gi_fd,CMD_XPCI3009_SetDigitalChlOff, b_ModuleNbr);
								
						/* Test the return value */
						switch (i_ReturnValue)
							{
							case 0:
							printf ("\nCMD_XPCI3009_SetDigitalChlOff OK");
							break;
				
							case 1:
							printf ("\nCMD_XPCI3009_SetDigitalChlOff error");
							printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
							break;
				
							case 2:
							printf ("\nCMD_XPCI3009_SetDigitalChlOff error");
							printf ("\nError = %d. The selected module number parameter is wrong", i_ReturnValue);
							break;
				
							case 3:
							printf ("\nCMD_XPCI3009_SetDigitalChlOff error");
							printf ("\nError = %d. Counter not initialised see function CMD_XPCI3009_InitCounter", i_ReturnValue);
							break;
				
							default:
							printf ("\nCMD_XPCI3009_SetDigitalChlOff error");
							printf ("\nError = %d.", i_ReturnValue);
							perror("\nioctl");					
							break;
							} // switch (i_ReturnValue)	
									
						gb_CompareInterrupt = 0;
					}
					else
						printf ("\nCounter value from module %d  = %u", b_ModuleNbr, ul_CounterValue);
						
					sleep (1);
					}
				while (i++ < 10);			   		

				/* Disable the compare logic */
				i_ReturnValue = ioctl (fd,CMD_XPCI3009_DisableCompareLogic, b_ModuleNbr);

				/* Test the return value */

				switch (i_ReturnValue)
					{
					case 0:
					printf ("\nCMD_DisableCompareLogic OK");
					break;

					case 1:
					printf ("\nCMD_DisableCompareLogic error");
					printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
					break;

					case 2:
					printf ("\nCMD_DisableCompareLogic error");
					printf ("\nError = %d. No counter module found", i_ReturnValue);
					break;

					case 3:
					printf ("\nCMD_DisableCompareLogic error");
					printf ("\nError = %d. Counter not initialised", i_ReturnValue);
					break;

					case 4:
					printf ("\nCMD_DisableCompareLogic error");
					printf ("\nError = %d. Compare logic not initialised", i_ReturnValue);
					break;
					
					default:
					printf ("\nCMD_DisableCompareLogic error");
					printf ("\nError = %d.", i_ReturnValue);
					perror("\nioctl");							
					break;					
					} // switch (i_ReturnValue)

				/* Reset the board interrupt routine */
				i_ReturnValue = ioctl (fd,CMD_XPCI3009_ResetBoardIntRoutine);

				/* Test the return value */
				switch (i_ReturnValue)
					{
					case 0:
					printf ("\nCMD_ResetBoardIntRoutine OK\n\n");
					break;

					case 1:
					printf ("\nCMD_ResetBoardIntRoutine error");
					printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
					break;

					case 2:
					printf ("\nCMD_ResetBoardIntRoutine error");
					printf ("\nError = %d. No Interrupt function initialised", i_ReturnValue);
					break;

					default:
					printf ("\nCMD_ResetBoardIntRoutine error");
					printf ("\nError = %d.", i_ReturnValue);
					perror("\nioctl");					
					break;
					} // switch (i_ReturnValue)
				break;

				case 1:
				printf ("\nCMD_XPCI3009_SetBoardIntRoutine error");
				printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
				break;

				case 2:
				printf ("\nCMD_XPCI3009_SetBoardIntRoutine error");
				printf ("\nError = %d. Interrupt already installed", i_ReturnValue);
				break;

				default:
				printf ("\nCMD_XPCI3009_SetBoardIntRoutine error");
				printf ("\nError = %d.", i_ReturnValue);
				perror("\nioctl");				
				break;
				} // switch (i_ReturnValue)
			break;

			case 1:
			printf ("\nCMD_XPCI3009_InitCounter error");
			printf ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
			break;

			case 2:
			printf ("\nCMD_XPCI3009_InitCounter error");
			printf ("\nError = %d. The module is not a counter module", i_ReturnValue);
			break;

			case 3:
			printf ("\nCMD_XPCI3009_InitCounter error");
			printf ("\nError = %d. The selected counter range is wrong", i_ReturnValue);
			break;

			case 4:
			printf ("\nCMD_XPCI3009_InitCounter error");
			printf ("\nError = %d. The selected first counter operating mode is wrong", i_ReturnValue);
			break;

			case 5:
			printf ("\nCMD_XPCI3009_InitCounter error");
			printf ("\nError = %d. The selected first counter operating option is wrong", i_ReturnValue);
			break;

			case 6:
			printf ("\nCMD_XPCI3009_InitCounter error");
			printf ("\nError = %d. The selected second counter operating mode is wrong", i_ReturnValue);
			break;

			case 7:
			printf ("\nCMD_XPCI3009_InitCounter error");
			printf ("\nError = %d. The selected second counter operating option is wrong", i_ReturnValue);
			break;

			default:
			printf ("\nCMD_XPCI3009_InitCounter error");
			printf ("\nError = %d", i_ReturnValue);
			perror("\nioctl");			
			break;
			} // switch (i_ReturnValue)

			printf ("\nProgram concluded.");
}

//--------------------------------------------------------------------------------

int main(int argc, char** argv)
{

	int * xpci3009_card_fd;
	unsigned int xpci3009_card_number = 0;
	{
		xpci3009_card_number = apci_find_boards("xpci3009", &xpci3009_card_fd);
		printf("total: %d cards\n",xpci3009_card_number);
	}	
	
	{
		int i;
		for (i=0;i< xpci3009_card_number; i++)
		{
			printf("\n+++++++++++++++++++++++++++++++++++++\nrunning test on device of minor number %d\n+++++++++++++++++++++++++++++++++++++\n\n\n",i);

			/* Compare logic sample */
			sample (xpci3009_card_fd[i]);
		}
	}

	

	return 0;
}
//--------------------------------------------------------------------------------
