/** @file testapci1696.c
 
   This software 
   - scans the /proc/sys/apci1696/ directory 
   - run a serie of test on each detected boards
  
   @par CREATION  
   @author Krauth Julien
   @date   13.06.05
   
   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim   
   
   @par COMPILER
   @verbatim
   Compiler	: gcc
   Version	: gcc (GCC) 3.3.6 (Debian 1:3.3.6-5)   
   kernel	: 2.4.26
   @endverbatim  
   
   @par UPDATES
   @verbatim
   Date			:
   Author		: 
   Description	: 
   @endverbatim    
    
   @par LICENCE
   @verbatim
   Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
        
        ADDI-DATA GmbH 
        Dieselstrasse 3 
        D-77833 Ottersweier 
        Tel: +19(0)7223/9493-0 
        Fax: +49(0)7223/9493-92 
        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 <sys/sysmacros.h> /* major() minor() */

#include <signal.h> /* For signal */
#include <assert.h>
#include <apci1696.h>
#include <assert.h>


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

/** Move the consol cursor on the specified point.
 * 
 * @param x	Horizontal position of the cursor.
 * @param y	Vertical position of the cursor.
 * 
 * retval 0 No error.
 */
int gotoxy(int x, int y) 
{
	char essq[100];       // String variable to hold the escape sequence
	char xstr[100];       // Strings to hold the x and y coordinates
	char ystr[100];       // Escape sequences must be built with characters
	
	// Convert the screen coordinates to strings
	sprintf(xstr, "%d", x);
	sprintf(ystr, "%d", y);
	
	// Build the escape sequence (vertical move)
	essq[0] = '\0';
	strcat(essq, "\033[");
	strcat(essq, ystr);
	
	// Described in man terminfo as vpa=\\E[%p1%dd
	// Vertical position absolute
	strcat(essq, "d");
	
	// Horizontal move
	// Horizontal position absolute
	strcat(essq, "\033[");
	strcat(essq, xstr);
	
	// Described in man terminfo as hpa=\\E[%p1%dG
	strcat(essq, "G");
	
	// Execute the escape sequence
	// This will move the cursor to x, y
	printf("%s", essq);
	
	return 0;
}

//------------------------------------------------------------------------------
void output_port_state(unsigned char PortsStates[APCI1696_PORT_NUMBER],int clear)
{
	int i;
    for (i=0; i<APCI1696_PORT_NUMBER; i++)
    {
    	int j;
    	for(j=0; j<8;j++)
    	{
    		printf("%d", ((PortsStates [(APCI1696_PORT0+i)] >> j) & 0x1) ); 
    	}
	}
	if (clear)
	{
	    for (i=0; i<APCI1696_PORT_NUMBER; i++)
	    {
	    	int j;
	    	for(j=0; j<8;j++)
	    	{
	    		printf("\b");
	    	}
	    }
	}	
	else
		printf("\n");
}

//------------------------------------------------------------------------------
/** Filter the "." and ".." entries in the struct dirent ** area set up by the scandir() function (utility function).*/
int
get_real_dir_entry (const struct dirent * ent)
{
        if (! strcmp(ent->d_name,"."))
                return 0;
        if (! strcmp(ent->d_name,".."))
                return 0;
                                
        return 1;
}

//--------------------------------------------------------------------------------
/** this function look up for cards in the /proc/sys/apci1696/ directory 
* @param cards A pointer to the card area to fill
* @return The number of cards detected (may be zero if nor cards found).
*/
int apci1696_find_cards(int ** cards)
{
	
	struct dirent **eps;
	int cnt = 0; // number of card found
    char APCI_SPECIAL_FILE_DIR[255]={0};
    char proc_path_template[255]={0};

    /* search which node is available */
    {
            struct stat file_stat;
            const char PROC_PATH[]="/proc/sys/apci1696";
            const char DEV_PATH[]="/dev/apci1696/";

            if (stat(PROC_PATH,&file_stat) == 0)
            {
                    /* Kernel 2.4 */
                    strncpy(APCI_SPECIAL_FILE_DIR, PROC_PATH, strlen(PROC_PATH));
                    strncpy(proc_path_template, "%s%s/ctrl", 9);
            }
            else if (stat(DEV_PATH,&file_stat) == 0)
            {
                    /* Kernel 2.6 */
                    strncpy(APCI_SPECIAL_FILE_DIR, DEV_PATH, strlen(DEV_PATH));
                    strncpy(proc_path_template, "%s%s", 4);
            }
            else
            {
                    perror("fstat");
                    exit(1);
            }
    }

	/* scan directory for card entry */
	if ( (cnt = scandir (APCI_SPECIAL_FILE_DIR, &eps, get_real_dir_entry , alphasort)) == -1 )
	{
		perror("scandir");
		return 0;
	}	
	
	if (cnt == 0) return 0;
	
	/* allocate cards area */
	if ( ! ( (*cards) = malloc( cnt * sizeof(int) ) ) )
	{
		perror("malloc");
		free(eps);
		return 0;
	}
	
	/* for each card entry, open it and store file descriptor in cards[] */
	{
		int i;
		for (i=0; i< cnt; i++)
		{
			int fd;
			char name[100];
			
			snprintf(name,sizeof(name),proc_path_template,APCI_SPECIAL_FILE_DIR,eps[i]->d_name);
			
			if ( ( fd = open(name, O_RDWR)) == -1 )
			{
				perror("open");
				exit(1);
			}			
									
			{
				struct stat file_stat;
				if ( fstat(fd,&file_stat) )
				{
					perror("fstat");
					exit(1);
				}			
				if (!S_ISCHR(file_stat.st_mode)) 
				{
					/* should never happen !*/
					printf("file %d is not a character device\n",i);
					exit(1);
				}
				printf("%s, major:%d minor:%d \n",name, major(file_stat.st_rdev),minor(file_stat.st_rdev));
			
				(*cards)[minor(file_stat.st_rdev)] = fd;
			} 
			/* index device file descriptor by the minor number */
			
		}	
	}
		
	return cnt;
	
	
}
//--------------------------------------------------------------------------------
void apci1696_run_test(int fd)
{
	printf("=> CMD_APCI1696_CheckAndGetPCISlotNumber\n");
	{	
		// deprecated (the number of boards is now unlimited and the OS gives actually these information)
		int nb = 0;
		char b_SlotArray[CONFIG_APCI1696_MAX_BOARD_NBR+1];
		if ( (nb = ioctl(fd,CMD_APCI1696_CheckAndGetPCISlotNumber,b_SlotArray)) == 0 )
		{
			printf("no boards found\n"); 
			exit(1);
		}	
		printf("The driver advertise %d board\n", nb);
		
		{
			int i;
			for (i=0; i< nb; i++)
	   			printf ("\t%d: Slot Number                       : %d\n", i, b_SlotArray[i]);		
		}
		
	}

	printf("=> CMD_APCI1696_SetBoardInformation\n");
	{
		//this command do nothing
		if ( ioctl (fd,CMD_APCI1696_SetBoardInformation,0) == -1)
		{
			perror("ioctl");
			exit(1);
		}	
	}
	printf("=> CMD_APCI1696_GetHardwareInformation\n");
	{
		// deprecated (the OS gives actually these information)
		str_BaseInformations s_BaseInformations;
		if ( ioctl (fd,CMD_APCI1696_GetHardwareInformation,&s_BaseInformations) == -1)
		{
			perror("ioctl");
			exit(1);
		}			

   		printf("\tBAR 0 : %d\n",  s_BaseInformations.ui_BaseAddress[0] ); 
		printf("\tBAR 1 : %d\n",  s_BaseInformations.ui_BaseAddress[1] ); 
		printf("\tBAR 2 : %d\n",  s_BaseInformations.ui_BaseAddress[2] ); 
		printf("\tBAR 3 : %d\n",  s_BaseInformations.ui_BaseAddress[3] ); 
		printf("\tBAR 5 : %d\n",  s_BaseInformations.ui_BaseAddress[4] ); 
   		printf("\tinterrupt nb: %d\n", s_BaseInformations.b_Interrupt);
   		printf("\tslot number: %d\n", s_BaseInformations.b_SlotNumber);
		
		
	}

}

//------------------------------------------------------------------------------
const char * direction_to_str(int val)
{
	switch(val)
	{
		case 0:
			return "input";
		case 1:
			return "output";
		default:
			return "unknown";
	}
}
//------------------------------------------------------------------------------

/** Test APCI-1696 initialization.
 * 
 * @param [in]	fd	File descriptor of the borad to use.
 * 
 * @retval 0	No error.
 * @retval 1	Error.
 */
int apci1696_test_initialization (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char UserPortsSetting[APCI1696_PORT_NUMBER]; /**< Ports initialization type:<br>
                                       - 0: Input direction<br>
                                       - 1: Output direction*/   
	struct DigitalPortsArg_t DigitalPort;
	memset (UserPortsSetting, 0, sizeof (UserPortsSetting) );   
   
	/* Set the configuration of all ports */
	{
		int i;
	    for (i=0; i<APCI1696_PORT_NUMBER; i++)      
	    {
	    	int ok = 0;
	    	while(!ok)
			{   
				int val = 0;
				printf ("Select the configuration for port %i (0:Input / 1:Output)>", (APCI1696_PORT0+i));
				if ( 1 != scanf ("%i", &val) )
				{
					printf("incorrect input\n");
		        	exit(1);
				}
				switch(val)
				{
					case 0:
					case 1:
						ok=1;
						break;					
					default:
						printf("\n%d: incorrect input: must be 0 or 1\n",val);
						continue;
				}
				UserPortsSetting [APCI1696_PORT0+i] = val;
				printf("%s\n",direction_to_str(UserPortsSetting [APCI1696_PORT0+i]));
			}
		}
	}
	if ( ioctl (fd,CMD_APCI1696_InitAllDigitalPorts,UserPortsSetting) )
	{
		perror("ioctl");
		exit(1);
	}	
      
	printf ("CMD_APCI1696_InitAllDigitalPorts: OK\n");
	printf ("\n");
            
	/* compare with given value */
	{
		unsigned char ReadPortsSetting[APCI1696_PORT_NUMBER];
		/* Set the port setting variable to 0 */
		memset (ReadPortsSetting, 0, sizeof (ReadPortsSetting) );
	      
		/* Get all ports actual setting */
	    if ( ioctl (fd,CMD_APCI1696_GetAllDigitalPortsSetting,ReadPortsSetting) < 0 )
	    {
	    	perror("ioctl");
	        exit(1);
		}	
		
		{
			int i;
			for (i=0; i<APCI1696_PORT_NUMBER; i++)
			{
				if ( ReadPortsSetting[i] != UserPortsSetting[i] )
				{
					printf("set and values from driver are not the same\n: %d != %d\n",ReadPortsSetting[i],UserPortsSetting[i]);
				}
			}     
		}
		printf ("CMD_APCI1696_GetAllDigitalPortsSetting: OK\n"); 
	    printf ("\n");
	}
	/* Change the setting of one port */      
    do
    {         	
        printf ("Select the port to configure (0 - %d), this function initialize 1 port)>",APCI1696_PORT_NUMBER-1);
		if ( 1 != scanf ("%i", (int*)&DigitalPort.Port) )
        {
        	printf("incorrect input\n");
        	exit(1);
        }
    }
	while ( (DigitalPort.Port > (APCI1696_PORT_NUMBER-1) ) );
	printf("%d\n",DigitalPort.Port);
    do
    {         	
    	printf ("Select the configuration for port %i (0:Input / 1:Output)>", DigitalPort.Port);
        if ( 1 != scanf ("%i", (int*)&DigitalPort.Value) )
        {
        	printf("incorrect input\n");
        	exit(1);
        }
	}
    while ( (DigitalPort.Value != 0) && (DigitalPort.Value != 1) );         
	printf("%s\n",direction_to_str(DigitalPort.Value));
      
	if ( ioctl (fd,CMD_APCI1696_InitDigitalPort,&DigitalPort) < 0 )
    {
    	perror("ioctl");
		exit(1);
	}
         
    printf ("CMD_APCI1696_InitDigitalPort: OK\n");               
    printf ("\n");

    /* Get all ports actual setting */
    {
    	int i;
	    for (i=0; i<APCI1696_PORT_NUMBER; i++)
	    {
	        DigitalPort.Port = (APCI1696_PORT0+i);
	        DigitalPort.Value = 0;
	         	
	        if ( ioctl (fd,CMD_APCI1696_GetDigitalPortSetting,&DigitalPort) < 0 )
			{
		        perror("ioctl");
		        exit(1);
	    	}	
	          
	        printf ("Port %i is as digital %s\n", (APCI1696_PORT0+i), (DigitalPort.Value == APCI1696_PORT_INPUT_DIRECTION)?"input": "output");     
		}
    }
    printf ("CMD_APCI1696_GetDigitalPortSetting: OK\n"); 
    printf ("\n");      

    return 0;
}

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

/** Test APCI-1696 digital input.
 * 
 * @param [in]	fd	File descriptor of the borad to use.
 * 
 * @retval 0	No error.
 * @retval 1	Error.
 */
int apci1696_test_digital_input (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsSetting[APCI1696_PORT_NUMBER]; /**< Ports initialization type:<br>
                                       - 0: Input direction<br>
                                       - 1: Output direction*/
	unsigned char PortsStates[APCI1696_PORT_NUMBER];
            
  	/* Set port variable to 0 */
	memset (PortsSetting, APCI1696_PORT_INPUT_DIRECTION, sizeof (PortsSetting) );
	memset (PortsStates, 0, sizeof (PortsStates) );
  
  
	/* Set all ports as input */
	if ( ioctl (fd,CMD_APCI1696_InitAllDigitalPorts,PortsSetting) < 0 )
    {
    	perror("ioctl");
		exit(1);
	}      
  
	int quit = 0;
	
	void on_sig(int sig)
	{
		quit = 1;
	}
	
	signal(SIGINT,on_sig);  
	printf ("ctrl + C for the next test\n");       
	while (!quit)
    {
    	/* Read all digital input state */
     	if ( ioctl (fd,CMD_APCI1696_ReadAllDigitalInputs,PortsStates) < 0 )
        {
        	perror("ioctl");
        	exit(1);
        }	      
                  
		output_port_state(PortsStates,1);      
	}
	printf ("CMD_APCI1696_ReadAllDigitalInputs: OK\n");
    signal(SIGINT,NULL);
	return 0;
}

//------------------------------------------------------------------------------
/* all ports as output
 * DigitalOutputMemory is Off
 * all outputs as 0
 */
int apci1696_test_digital_output_reset (int fd)
{
	unsigned char PortsSetting[APCI1696_PORT_NUMBER];
    memset (PortsSetting, APCI1696_PORT_OUTPUT_DIRECTION, sizeof (PortsSetting));
    /* Set all ports as output */
    assert( ioctl (fd,CMD_APCI1696_InitAllDigitalPorts,PortsSetting) == 0 );

    /* clear all output */
    {
    	assert( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOff,NULL) == 0 );
		unsigned char tmp[APCI1696_PORT_NUMBER];
		memset (tmp, 0, sizeof (tmp));
		assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,tmp) == 0);
    }
    return 0;	
}

//------------------------------------------------------------------------------
// __shouldbe = unsigned char [APCI1696_PORT_NUMBER]
#define apci1696_read_and_compare(__fd, __shouldbe) \
{ \
	unsigned char ReadStates[APCI1696_PORT_NUMBER]; \
    memset (ReadStates, 0, sizeof(ReadStates) ); \
    assert( ioctl (__fd,CMD_APCI1696_GetAllDigitalOutputsStates,ReadStates) == 0 ); \
	output_port_state(ReadStates,0); \
	{ \
		int i; \
		for (i=0; i<APCI1696_PORT_NUMBER; i++) \
			if (ReadStates[i]!=__shouldbe[i]) \
			{ \
				printf("%s:%d: ReadStates[%d]=%X != shouldbe[%d]=%X",__FUNCTION__,__LINE__,i,ReadStates[i],i,__shouldbe[i]); \
				exit(1); \
			} \
	} \
}

//------------------------------------------------------------------------------
/* 
 * outputmemory == 0 -> off ; outputmemory == 0 -> on 
 * all I/O as output
 * all outputs as 0
 * read output
 */
int apci1696_test_digital_output_auto (int fd, unsigned char PortsStates[APCI1696_PORT_NUMBER], int outputmemory)
{ 

      
	apci1696_test_digital_output_reset(fd);
    
    /* Set the digital output memory off.<br> 
     * When digital output memory is activated,<br>
     * the previous output state is hold when one<br>
     * or more output states are set. 
     */
    if ( outputmemory )
	{
	    if ( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOn,NULL) < 0 )
	    {
	    	perror("ioctl");
			exit(1);
		}
		printf ("CMD_APCI1696_SetDigitalOutputMemoryOn: OK\n");
	}
	else
	{
	    if ( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOff,NULL) < 0 )
	    {
	    	perror("ioctl");
			exit(1);
		}
		printf ("CMD_APCI1696_SetDigitalOutputMemoryOff: OK\n");
	}
     
    printf ("\n");         
    printf ("\n");         
		
    if ( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) < 0 )
    {
    	perror("ioctl");
		exit(1);
	}	 
      
    printf ("CMD_APCI1696_SetAllDigitalOutputsOn: OK\n"); 
    printf ("\n");   
	apci1696_read_and_compare(fd,PortsStates);
    printf ("\n");     
      
    return 0;
}
/* 
 * outputmemory off
 * all I/O as output
 * all outputs as 0
 * read output
 */
int apci1696_test_digital_output_1 (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsStates[APCI1696_PORT_NUMBER] =
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	};
		
	assert(apci1696_test_digital_output_auto (fd, PortsStates,0)==0);
	return 0;
}

/* 
 * outputmemory off
 * all I/O as output
 * all outputs as 0xFF
 * read output
 */
int apci1696_test_digital_output_2 (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsStates[APCI1696_PORT_NUMBER] =
	{
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF
	};
	
	assert(apci1696_test_digital_output_auto (fd, PortsStates,0)==0);
	return 0;
}

/* 
 * outputmemory off
 * all I/O as output
 * all outputs as 0x0F
 * read output
 */
int apci1696_test_digital_output_3 (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsStates[APCI1696_PORT_NUMBER] =
	{
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F
	};
	
	assert(apci1696_test_digital_output_auto (fd, PortsStates,0)==0);
	return 0;
}

/* 
 * outputmemory on
 * all I/O as output
 * all outputs as 0x00
 * read output
 */
int apci1696_test_digital_output_4 (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsStates[APCI1696_PORT_NUMBER] =
	{
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00,
		0x00
	};
	
	assert(apci1696_test_digital_output_auto (fd, PortsStates,1)==0);
	return 0;
}
/* 
 * outputmemory on
 * all I/O as output
 * all outputs as 0xFF
 * read output
 */
int apci1696_test_digital_output_5 (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsStates[APCI1696_PORT_NUMBER] =
	{
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF
	};
	
	assert(apci1696_test_digital_output_auto (fd, PortsStates,1)==0);
	return 0;
}
/* 
 * outputmemory on
 * all I/O as output
 * all outputs as 0x0F
 * read output
 */
int apci1696_test_digital_output_6 (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsStates[APCI1696_PORT_NUMBER] =
	{
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F,
		0x0F
	};
	
	assert(apci1696_test_digital_output_auto (fd, PortsStates,1)==0);
	return 0;
}
/* 
 * outputmemory off
 * all I/O as output
 * all outputs as "random"
 * read output
 */
int apci1696_test_digital_output_7 (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsStates[APCI1696_PORT_NUMBER];	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=random();
		}
	}

	assert(apci1696_test_digital_output_auto (fd, PortsStates,0)==0);
	return 0;
}

/* 
 * outputmemory on
 * all I/O as output
 * all outputs as "random"
 * read output
 */
int apci1696_test_digital_output_8 (int fd)
{
	printf("%s\n",__FUNCTION__);
	unsigned char PortsStates[APCI1696_PORT_NUMBER];	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=random();
		}
	}

	assert(apci1696_test_digital_output_auto (fd, PortsStates,1)==0);
	return 0;
}
/* test CMD_APCI1696_SetAllDigitalOutputsOn
 * outputmemory on
 * all I/O as output
 * first output as 0x0F 
 * then output as 0xF0
 * should be 0xFF
 */
int apci1696_test_digital_output_9 (int fd)
{
	apci1696_test_digital_output_reset(fd);
	assert( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOn,NULL) == 0 );

	unsigned char PortsStates[APCI1696_PORT_NUMBER];	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x0F;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xF0;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xFF;
		}
	}
	apci1696_read_and_compare(fd,PortsStates);
	return 0;
}
/* test CMD_APCI1696_SetAllDigitalOutputsOn
 * outputmemory on
 * all I/O as output
 * first output as 0x0F
 * then output as 0x0F
 * should be 0x0F
 */
int apci1696_test_digital_output_10 (int fd)
{
	apci1696_test_digital_output_reset(fd);
	assert( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOn,NULL) == 0 );

	unsigned char PortsStates[APCI1696_PORT_NUMBER];	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x0F;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x0F;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x0F;
		}
	}
	apci1696_read_and_compare(fd,PortsStates);
	return 0;
}
/* test CMD_APCI1696_SetAllDigitalOutputsOn
 * outputmemory on
 * all I/O as output
 * first output as 0xFF
 * then output as 0x00
 * should be 0xFF
 */
int apci1696_test_digital_output_11 (int fd)
{
	apci1696_test_digital_output_reset(fd);
	assert( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOn,NULL) == 0 );

	unsigned char PortsStates[APCI1696_PORT_NUMBER];	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xFF;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x00;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xFF;
		}
	}
	apci1696_read_and_compare(fd,PortsStates);
	return 0;
}
/* test CMD_APCI1696_SetAllDigitalOutputsOff
 * outputmemory on
 * all I/O as output
 * first output as 0xFF
 * then output as 0x00
 * should be 0xFF
 */
int apci1696_test_digital_output_12 (int fd)
{
	apci1696_test_digital_output_reset(fd);
	assert( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOn,NULL) == 0 );

	unsigned char PortsStates[APCI1696_PORT_NUMBER];	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xFF;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x00;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOff,PortsStates) == 0 );
	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xFF;
		}
	}
	apci1696_read_and_compare(fd,PortsStates);
	return 0;
}
/* test CMD_APCI1696_SetAllDigitalOutputsOff
 * outputmemory on
 * all I/O as output
 * first output as 0xFF
 * then output as 0xFF
 * should be 0x00
 */
int apci1696_test_digital_output_14 (int fd)
{
	apci1696_test_digital_output_reset(fd);
	assert( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOn,NULL) == 0 );

	unsigned char PortsStates[APCI1696_PORT_NUMBER];	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xFF;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xFF;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOff,PortsStates) == 0 );
	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x0;
		}
	}
	apci1696_read_and_compare(fd,PortsStates);
	return 0;
}
/* test CMD_APCI1696_SetAllDigitalOutputsOff
 * outputmemory on
 * all I/O as output
 * first output as 0x0F
 * then output as 0xF0
 * should be 0x0F
 */
int apci1696_test_digital_output_15 (int fd)
{
	apci1696_test_digital_output_reset(fd);
	assert( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOn,NULL) == 0 );

	unsigned char PortsStates[APCI1696_PORT_NUMBER];	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x0F;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) == 0 );
	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0xF0;
		}
	}
	assert( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOff,PortsStates) == 0 );
	
	{
		int i;
		for (i=0; i< APCI1696_PORT_NUMBER; i++)
		{
			PortsStates[i]=0x0F;
		}
	}
	apci1696_read_and_compare(fd,PortsStates);
	return 0;
}
//------------------------------------------------------------------------------

/** Test APCI-1696 digital output.
 * 
 * @param [in]	fd	File descriptor of the borad to use.
 * 
 * @retval 0	No error.
 * @retval 1	Error.
 */
int apci1696_test_digital_output (int fd)
{
	
	printf("%s\n",__FUNCTION__);
	
	unsigned char PortsSetting[APCI1696_PORT_NUMBER]; /**< Ports initialization type:<br>
                                       - 0: Input direction<br>
                                       - 1: Output direction*/
	unsigned char PortsStates[APCI1696_PORT_NUMBER];
            
	/* Set port variable to 0 */
    memset (PortsSetting, APCI1696_PORT_OUTPUT_DIRECTION, sizeof (PortsSetting));
    memset (PortsStates, 0, sizeof(PortsStates) );
      
    /* Set all ports as output */
    if ( ioctl (fd,CMD_APCI1696_InitAllDigitalPorts,PortsSetting) < 0 )
    {
    	perror("ioctl");
        exit(1);
	}            
      
    /* Set the digital output memory on.<br> 
     * When digital output memory is activated,<br>
     * the previous output state is hold when one<br>
     * or more output states are set. 
     */      
    if ( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOn,NULL) < 0 )
    {
    	perror("ioctl");
		exit(1);
	}	     
         
    printf ("CMD_APCI1696_SetDigitalOutputMemoryOn: OK\n"); 
    printf ("\n");         
    printf ("\n");         

   {
    	int i;
	    for (i=0; i<APCI1696_PORT_NUMBER; i++)
	    {      
	    	int ok = 0;
			int val = -1;
	    	while(!ok)
	    	{

		    	printf ("Give the value (0 - 255) to write on port %i>", (APCI1696_PORT0+i));
		        if ( scanf ("%i", &val) != 1 )
		        {
		        	printf("incorrect input\n");
		        	exit(1);
		        }
				switch(val)
				{
					case 0 ... 255:
						ok = 1;
						break;
					default:
						printf("incorrect input: %d\n",val);
						break;
				}
	    	}
			printf( "%d\n", PortsStates [(APCI1696_PORT0+i)] = val);
		}
    }		
		
    if ( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOn,PortsStates) < 0 )
    {
    	perror("ioctl");
		exit(1);
	}	 
      
    printf ("CMD_APCI1696_SetAllDigitalOutputsOn: OK\n"); 
    printf ("\n");   
      
    if ( ioctl (fd,CMD_APCI1696_GetAllDigitalOutputsStates,PortsStates) < 0 )
    {
    	perror("ioctl");
        exit(1);
	}	                

    printf ("CMD_APCI1696_GetAllDigitalOutputsStates: OK\n"); 
    printf ("\n");   

	output_port_state(PortsStates,0);	

    printf ("\n");            
      
    {
    	int i;
	    for (i=0; i<APCI1696_PORT_NUMBER; i++)
	    {      
	    	int ok = 0;
			int val = -1;
	    	while(!ok)
	    	{

		    	printf ("Give the value (0 - 255) to write on port %i>", (APCI1696_PORT0+i));
		        if ( scanf ("%i", &val) != 1 )
		        {
		        	printf("incorrect input\n");
		        	exit(1);
		        }
				switch(val)
				{
					case 0 ... 255:
						ok = 1;
						break;
					default:
						printf("incorrect input: %d\n",val);
						break;
				}
	    	}
			printf("%s\n",direction_to_str( (PortsStates [(APCI1696_PORT0+i)] = val) ) );
		}
    }		
    if ( ioctl (fd,CMD_APCI1696_SetAllDigitalOutputsOff,PortsStates) < 0 )
    {
    	perror("ioctl");
        exit(1);
	}	 

    printf ("CMD_APCI1696_SetAllDigitalOutputsOff: OK\n"); 
    printf ("\n");            
              
    if ( ioctl (fd,CMD_APCI1696_GetAllDigitalOutputsStates,PortsStates) < 0 )
    {
    	perror("ioctl");
        exit(1);
	}	                

    printf ("CMD_APCI1696_GetAllDigitalOutputsStates: OK\n"); 
    printf ("\n");   
	output_port_state(PortsStates,0);   
    printf ("\n");  

    printf ("\n");       
      
    /* Set the digital output memory off */
    if ( ioctl (fd,CMD_APCI1696_SetDigitalOutputMemoryOff,NULL) < 0 )
    {
    	perror("ioctl");
        exit(1);
	}	     
         
    printf ("CMD_APCI1696_SetDigitalOutputMemoryOff: OK\n"); 
    printf ("\n");         
    if ( ioctl (fd,CMD_APCI1696_GetAllDigitalOutputsStates,PortsStates) < 0 )
    {
    	perror("ioctl");
        exit(1);
	} 
    printf ("\n");   
	output_port_state(PortsStates,0);   
    printf ("\n");  
    return 0;
}

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

int main(int argc, char** argv)
{
    system("clear");
	int * apci1696_card_fd;
	unsigned int apci1696_card_number = 0;
	{
		apci1696_card_number = apci1696_find_cards(&apci1696_card_fd);
		if (!apci1696_card_number)
		{
			printf("! no APCI1696 board found\n");
			return 1;
		}
	}
	printf("total: %d cards\n",apci1696_card_number);
	{
		int i;
		for (i=0;i< apci1696_card_number; i++)
		{
			printf("\n\nRunning test on device of minor number %d\n\n\n\n",i);
			apci1696_run_test(apci1696_card_fd[i]);		

			apci1696_test_digital_output_1(apci1696_card_fd[i]);
			apci1696_test_digital_output_2(apci1696_card_fd[i]);
			apci1696_test_digital_output_3(apci1696_card_fd[i]);
			apci1696_test_digital_output_4(apci1696_card_fd[i]);
			apci1696_test_digital_output_5(apci1696_card_fd[i]);
			apci1696_test_digital_output_6(apci1696_card_fd[i]);
			apci1696_test_digital_output_7(apci1696_card_fd[i]);
			apci1696_test_digital_output_8(apci1696_card_fd[i]);
			apci1696_test_digital_output_9(apci1696_card_fd[i]);
			apci1696_test_digital_output_10(apci1696_card_fd[i]);
			apci1696_test_digital_output_11(apci1696_card_fd[i]);
			apci1696_test_digital_output_12(apci1696_card_fd[i]);
			apci1696_test_digital_output_14(apci1696_card_fd[i]);
			apci1696_test_digital_output_15(apci1696_card_fd[i]);
			
			printf("\n\nRunning initialization test on device of minor number %d\n\n\n\n",i);
			apci1696_test_initialization (apci1696_card_fd[i]);

			printf("\n\nRunning digital input test on device of minor number %d\n\n\n\n",i);
			apci1696_test_digital_input (apci1696_card_fd[i]);
            
			printf("\n\nRunning digital output test on device of minor number %d\n\n\n\n",i);			
			apci1696_test_digital_output (apci1696_card_fd[i]);
		}
	}


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