/** @file ktestapci1648.c
 
   This software demonstrates how to call apci1648.o functions in a kernel
   module.
   
   
   @warning The method to access on kernel mode to functions with apci1648_do_ioctl_kernel is
   deprecated and will be replaced with exported functions.
   Please before to use apci1648_do_ioctl_kernel ask ADDI-DATA!!
  
   @par CREATION  
   @author Krauth Julien
   @date   15.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 <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
	#include <linux/config.h>
#else
	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
		#include <linux/autoconf.h>
	#else
		#include <generated/autoconf.h>
	#endif
#endif

#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/init.h>

#include <apci1648.h>
#include <apci1648-kapi.h> // for apci1648_lookup_board_by_index
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>");
MODULE_DESCRIPTION("APCI-1648 Kernel sample.");

/**@def EXPORT_NO_SYMBOLS
 * Function in this file are not exported.
 */
EXPORT_NO_SYMBOLS;

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

/** Test APCI-1648 digital input.
 * 
 * @param [in]	fd	File descriptor of the borad to use.
 * 
 * @retval 0	No error.
 * @retval 1	Error.
 */
static int apci1648_test_digital_input (struct pci_dev * pdev)
{
	unsigned char PortsSetting[6]; /**< Ports initialization type:<br>
                                       - 0: Input direction<br>
                                       - 1: Output direction*/
	unsigned char PortsStates[6];
	int i=0;
            
      /* Set port variable to 0 */
    memset (PortsSetting, APCI1648_PORT_INPUT_DIRECTION, sizeof (PortsSetting) );
    memset (PortsStates, 0, (sizeof (unsigned char) * 6));
      
      
	/* Set all ports as input */
	if (APCI1648_InitAllDigitalPorts(pdev,PortsSetting) )
	{
    	printk("APCI1648_InitAllDigitalPorts failed\n");
        return(1);
    }
	/* Read all digital input state */
	if ( APCI1648_ReadAllDigitalInputs(pdev, PortsStates) )
	{
		printk("APCI1648_ReadAllDigitalInputs failed\n");
		return(1);
	}
          
	printk ("\n        +-------------------------------+");
    printk ("\n        | DIGITAL INPUTS STATES         |");
    printk ("\n+-------+---+---+---+---+---+---+---+---+-----+");
    printk ("\n| PORT  | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | Hex |");
				
    for (i=0; i<APCI1648_PORT_NUMBER; i++)
    {
		printk ("\n+-------+---+---+---+---+---+---+---+---+-----+");              
		printk ("\n| %3d   |%3s|%3s|%3s|%3s|%3s|%3s|%3s|%3s| %3x |", (APCI1648_PORT0+i),
					(PortsStates [(APCI1648_PORT0+i)] & 128)?"ON":"OFF",
				    (PortsStates [(APCI1648_PORT0+i)] & 64)?"ON":"OFF",
				    (PortsStates [(APCI1648_PORT0+i)] & 32)?"ON":"OFF",
				    (PortsStates [(APCI1648_PORT0+i)] & 16)?"ON":"OFF",
				    (PortsStates [(APCI1648_PORT0+i)] & 8)?"ON":"OFF",
				    (PortsStates [(APCI1648_PORT0+i)] & 4)?"ON":"OFF",
				    (PortsStates [(APCI1648_PORT0+i)] & 2)?"ON":"OFF",
				    (PortsStates [(APCI1648_PORT0+i)] & 1)?"ON":"OFF",
				    PortsStates [(APCI1648_PORT0+i)]);             	 
    }
    printk ("\n+---------------------------------------------+"); 
    printk ("\n");            
	printk ("APCI1648_ReadAllDigitalInputs: OK\n"); 
    printk ("\n");      
         
      return 0;
}

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

/** Test APCI-1648 digital output.
 * 
 * @param [in]	fd	File descriptor of the borad to use.
 * 
 * @retval 0	No error.
 * @retval 1	Error.
 */
static int apci1648_test_digital_output (struct pci_dev * pdev)
{
	unsigned char PortsSetting[6]; /**< Ports initialization type:<br>
                                       - 0: Input direction<br>
                                       - 1: Output direction*/
	unsigned char PortsStates[6];
	int i=0;
            
	/* Set port variable to 0 */
    memset (PortsSetting, APCI1648_PORT_OUTPUT_DIRECTION, (sizeof (unsigned char) * 6));
    memset (PortsStates, 0, (sizeof (unsigned char) * 6));
      
    /* Set all ports as output */
    if ( APCI1648_InitAllDigitalPorts(pdev, PortsSetting) )
    {
    	printk("APCI1648_InitAllDigitalPorts failed\n");
    	return 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 ( APCI1648_SetDigitalOutputMemoryOn(pdev) )
    {
		printk("APCI1648_SetDigitalOutputMemoryOn failed\n");
		return 1;
    }

	printk ("CMD_APCI1648_SetDigitalOutputMemoryOn: OK\n"); 
    printk ("\n");         
    printk ("\n");         

    /* Set all digital output state on */
    for (i=0; i<APCI1648_PORT_NUMBER; i++)
    {      
    	printk ("Value %i to write on port %i\n", i, (APCI1648_PORT0+i));
        PortsStates [(APCI1648_PORT0+i)] = i;
	}
    
    if ( APCI1648_SetAllDigitalOutputsOn(pdev, PortsStates) )
    {
    	printk("APCI1648_SetAllDigitalOutputsOn failed\n");
    	return 1;
    }

	printk ("APCI1648_SetAllDigitalOutputsOn: OK\n"); 
    printk ("\n");   
    
    if ( APCI1648_GetAllDigitalOutputsStates(pdev, PortsStates) )
    {
    	printk("APCI1648_GetAllDigitalOutputsStates failed\n");
    	return 1;
    }

	printk ("APCI1648_GetAllDigitalOutputsStates: OK\n"); 
    printk ("\n");   
              
    printk ("\n        +-------------------------------+");
    printk ("\n        | DIGITAL OUTPUTS STATES        |");
    printk ("\n+-------+---+---+---+---+---+---+---+---+-----+");
   	printk ("\n| PORT  | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | Hex |");
				
    for (i=0; i<APCI1648_PORT_NUMBER; i++)
    {
		printk ("\n+-------+---+---+---+---+---+---+---+---+-----+");              
		printk ("\n| %3d   |%3s|%3s|%3s|%3s|%3s|%3s|%3s|%3s| %3x |", (APCI1648_PORT0+i),
				     (PortsStates [(APCI1648_PORT0+i)] & 128)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 64)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 32)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 16)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 8)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 4)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 2)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 1)?"ON":"OFF",
				     PortsStates [(APCI1648_PORT0+i)]);             	 
	}
    printk ("\n+---------------------------------------------+"); 

    printk ("\n");   
    printk ("\n");            
      
    /* Set all digital output state off */
    for (i=0; i<APCI1648_PORT_NUMBER; i++)
    {
         printk ("Value %i to write on port %i\n", i, (APCI1648_PORT0+i));
         PortsStates [(APCI1648_PORT0+i)] = i;
	}
    
    if ( APCI1648_SetAllDigitalOutputsOff(pdev, PortsStates) )
    {
    	printk("APCI1648_SetAllDigitalOutputsOff failed\n");
    	return 1;
    }	 

	printk ("APCI1648_SetAllDigitalOutputsOff: OK\n"); 
    printk ("\n");            
    
    if ( APCI1648_GetAllDigitalOutputsStates(pdev, PortsStates) )
    {
    	printk("APCI1648_GetAllDigitalOutputsStates failed\n");
    	return 1;
    }

	printk ("APCI1648_GetAllDigitalOutputsStates: OK\n"); 
    printk ("\n");   
              
    printk ("\n        +-------------------------------+");
    printk ("\n        | DIGITAL OUTPUTS STATES        |");
    printk ("\n+-------+---+---+---+---+---+---+---+---+-----+");
   	printk ("\n| PORT  | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | Hex |");
				
    for (i=0; i<APCI1648_PORT_NUMBER; i++)
	{
		printk ("\n+-------+---+---+---+---+---+---+---+---+-----+");              
		printk ("\n| %3d   |%3s|%3s|%3s|%3s|%3s|%3s|%3s|%3s| %3x |", (APCI1648_PORT0+i),
				     (PortsStates [(APCI1648_PORT0+i)] & 128)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 64)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 32)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 16)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 8)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 4)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 2)?"ON":"OFF",
				     (PortsStates [(APCI1648_PORT0+i)] & 1)?"ON":"OFF",
				     PortsStates [(APCI1648_PORT0+i)]);             	 
	}
    printk ("\n+---------------------------------------------+"); 

    printk ("\n");   
    printk ("\n");  

    printk ("\n");       
    
    if ( APCI1648_SetDigitalOutputMemoryOff(pdev) )
    {
    	printk("APCI1648_SetDigitalOutputMemoryOff failed\n");
    	return 1;
    }
     
    printk ("APCI1648_SetDigitalOutputMemoryOff: OK\n"); 
    printk ("\n");         

    return 0;
}


//------------------------------------------------------------------------------
/** Called when module loads. */
static int __init APCI1648_sample_init(void)
{		
	struct pci_dev * pdev;
	int index = 0;

	/* Get a pointer on the first APCI-1648.
	* 0 is here to indicate the first board.
	* It is the board minor number.
	*/
	pdev = apci1648_lookup_board_by_index(index);
         
	printk("\n\nRunning digital input test on device of minor number %d\n\n\n\n",index);
	apci1648_test_digital_input (pdev);
            
	printk("\n\nRunning digital output test on device of minor number %d\n\n\n\n",index);			
	apci1648_test_digital_output (pdev);
	
	return 0;
}
//------------------------------------------------------------------------------	     
/** Called when module is unloaded. */
static void __exit APCI1648_sample_exit(void)
{

}
//------------------------------------------------------------------------------
module_exit(APCI1648_sample_exit);
module_init(APCI1648_sample_init);
