/** @file sample_ssi_03.c
*
* @author Krauth Julien
*
* Initialize and read all SSI values:
* - i_APCI1710_InitSSI
* - i_APCI1710_ReadAllSSIValue
*/

/** @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 shoud 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/spinlock.h>
#include <linux/ioctl.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pci.h> // struct pci_dev
#include <asm/io.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)
    #include <asm/system.h>
#endif
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/sched.h>

#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/proc_fs.h>

#include <apci1710.h>
#include <apci1710-kapi.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>");
MODULE_DESCRIPTION("APCI-1710");

EXPORT_NO_SYMBOLS;

static const char modulename[] = "sample_ssi";


static int sample_ssi_kernel (struct pci_dev *pdev)
{ 

    int i_ReturnValue = 0;
    int i = 0;
    unsigned long irqstate;

    uint8_t b_ModulNbr = 0; /* The first module */
    uint8_t b_SSIProfile = 25;
    uint8_t b_PositionTurnLength = 12;
    uint8_t b_TurnCptLength = 12;
    uint8_t b_PCIInputClock = APCI1710_33MHZ;
    uint32_t ul_SSIOutputClock = 150000;
    uint8_t b_SSICountingMode = APCI1710_BINARY_MODE;
    uint32_t ul_Position[3];
    uint32_t ul_TurnCpt[3];

    /* Lock the function to avoid parallel configurations */
    apci1710_lock(pdev,&irqstate);

    i_ReturnValue = i_APCI1710_InitSSI (pdev,
                                                    b_ModulNbr,
                                                    b_SSIProfile,
                                                    b_PositionTurnLength,
                                                    b_TurnCptLength,
                                                    b_PCIInputClock,
                                                    ul_SSIOutputClock,
                                                    b_SSICountingMode);

    /* Unlock the function so that other applications can call it */
    apci1710_unlock(pdev,irqstate);

    switch (i_ReturnValue)
    {
        case 0:
        printk ("\ni_APCI1710_InitSSI OK");
        break;

        case 1:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
        break;
        
        case 2:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The module parameter is wrong", i_ReturnValue);
        break;
        
        case 3:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The module is not a SSI module", i_ReturnValue);
        break;
        
        case 4:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The selected SSI profile length is wrong", i_ReturnValue);
        break;
        
        case 5:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The selected SSI position data length is wrong", i_ReturnValue);
        break;
        
        case 6:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The selected SSI turn counter data length is wrong", i_ReturnValue);
        break;
        
        case 7:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The selected PCI input clock is wrong", i_ReturnValue);
        break;
        
        case 8:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The selected SSI output clock is wrong", i_ReturnValue);
        break;
        
        case 9:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d. The selected SSI counting mode parameter is wrong", i_ReturnValue);
        break;
        
        default:
        printk ("\ni_APCI1710_InitSSI error");
        printk ("\nError = %d.", i_ReturnValue);
        break;
    }

    if (!i_ReturnValue)
    {
        for (i=0; i<100; i++)
        {
            i_ReturnValue = i_APCI1710_ReadAllSSIValue  (pdev,
                                                                        b_ModulNbr,
                                                                        ul_Position,
                                                                        ul_TurnCpt);
            
            switch (i_ReturnValue)
            {
            case 0 :
                printk ("\ni_APCI1710_ReadAllSSIValue OK");
                printk ("\nCounter 0 value = %u Counter 0 position = %u", ul_Position [0] , ul_TurnCpt [0]);
                printk ("\nCounter 1 value = %u Counter 1 position = %u", ul_Position [1] , ul_TurnCpt [1]);
                printk ("\nCounter 2 value = %u Counter 2 position = %u", ul_Position [2] , ul_TurnCpt [2]);
                break;
            
            case 1:
                printk ("\ni_APCI1710_ReadAllSSIValue error");
                printk ("\nError = %d. The handle parameter of the board is wrong", i_ReturnValue);
                break;
            
            case 2:
                printk ("\ni_APCI1710_ReadAllSSIValue error");
                printk ("\nError = %d. The module parameter is wrong", i_ReturnValue);
                break;
            
            case 3:
                printk ("\ni_APCI1710_ReadAllSSIValue error");
                printk ("\nError = %d. The module is not a SSI module", i_ReturnValue);
                break;
            
            case 4:
                printk ("\ni_APCI1710_ReadAllSSIValue error");
                printk ("\nError = %d. SSI not initialised", i_ReturnValue);
                break;
            
            default:
                printk ("\ni_APCI1710_ReadAllSSIValue error");
                printk ("\nError = %d.", i_ReturnValue);
                break;
            }
        }
    }
    
    return (i_ReturnValue);
}


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

    printk("%s: looking for board %u\n",modulename,board_index);
    pdev=apci1710_lookup_board_by_index(0);
    if( !pdev )
    {
        printk("%s: board %u not found\n",modulename,board_index);
        return -ENODEV;
    }
    printk("%s: beginning test\n",modulename);
        sample_ssi_kernel (pdev);

    return 0;
}
//-------------------------------------------------------------------
/** Called when module is unloaded. */
static void __exit apci1710Sample_exit(void)
{
 
    
}
//------------------------------------------------------------------------------
module_exit(apci1710Sample_exit);
module_init(apci1710Sample_init);
