/** @file sample_endat_01.c
*
* @author El Bakali Laaziz
*
* Windows original Sample : ReadSensorMemory
*
*i_APCI1711_EndatResetErrorBits
*i_APCI1711_EndatInitialiseSensor
*i_APCI1711_EndatSelectMemoryArea
*i_APCI1711_EndatSensorSendParameter
*i_APCI1711_EndatSensorSendPositionAndRecvMemArea
*i_APCI1711_EndatSelectMemoryArea
*/

/** @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_endat";


static int sample_endat_kernel (struct pci_dev *pdev)
{
    int i_ReturnValue = 0;
    int i=0;

    //Value fixed by the user
    uint8_t moduleIndex = 0;
    uint8_t sensorIndex = 0;
    uint32_t frequency = 1000;

    /**
    *        "Address mrsCode that you want to use \n"
    *        "Encoder manufacturer :\n"
    *        "0xA1:    first part (address area: 0x4 - 0xF)\n"
    *        "0xA3:    second part (address area: 0x0 - 0xF)\n"
    *        "0xA5:    third part (address area: 0x0 - 0xF)\n"
    *        "0xA7:    Operating parameters (address area: 0x0 - 0xF)\n"
    *        "Parameters of the OEM :\n"
    *        "0xA9:    first part (address area: depending on the sensor)\n"
    *        "0xAB:    second part (address area: depending on the sensor)\n"
    *        "0xAD:    third part (address area: depending on the sensor)\n"
    *        "0xAF:    fourth part (address area: depending on the sensor)\n"
    *        "Compensation values of the encoder manufacturer :\n"
    *        "0xB1:    first part (address area: depending on the sensor)\n"
    *        "0xB3:    second part (address area: depending on the sensor)\n"
    *        "0xB5:    third part (address area: depending on the sensor)\n"
    *        "0xB7:    fourth part (address area: depending on the sensor)\n"
    *        "Other addresses :\n"
    *        "0xB9:    Operating status (address area: 0x0 - 0x3)\n"
    *        "For Endat 2.2"
    *        "0xBD:    Parameters of the encoder manufacturer for EnDat 2.2\n"
    *        "0xBF:    Parameters of the section 2 memory area\n"
    *        "0xBB:    Operating parameters 2\n"
    */
    uint32_t mrsCode = 0xA1;

    // Word you want to read value between  0 and 0x1000, fixed by the user
    uint32_t word = 0x0001;

    uint32_t readValue = 0;
    uint32_t param = 0;
    uint8_t endatVersion = 0;
    uint8_t allowEndat22 = 0;


    /* reset the error bits */
    i_ReturnValue = i_APCI1711_EndatResetErrorBits(pdev,moduleIndex,sensorIndex);
    if (i_ReturnValue != 0)
    {
        printk("i_APCI1711_EndatResetErrorBits, error : %d \n", i_ReturnValue);
        return 1;
    }
    printk("i_APCI1711_EndatResetErrorBits: ok. \n");


    /* initialise the EnDat sensor */
    i_ReturnValue = i_APCI1711_EndatInitialiseSensor(pdev,moduleIndex,sensorIndex,frequency);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatInitialiseSensor, error : %d \n", i_ReturnValue);
        return 1;
    }
    printk("i_APCI1711_EndatInitialiseSensor: ok. \n");


    /* get the encoder version type */
    i_ReturnValue = i_APCI1711_EndatSelectMemoryArea(pdev, moduleIndex, sensorIndex, 0xA1);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSelectMemoryArea, error : %d \n", i_ReturnValue);
        return 1;
    }

    /* read the address and get the parameter */
    i_ReturnValue = i_APCI1711_EndatSensorSendParameter(pdev,moduleIndex,sensorIndex,0xA1,8,&readValue);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSensorSendParameter, error : %d \n", i_ReturnValue);
        return 1;
    }

    endatVersion = (readValue & 0x3);

    printk("EnDat 2.%u sensor\n", (readValue & 0x3));

    /* get if the encoder allow to use EnDat 2.2 commands */
    i_ReturnValue = i_APCI1711_EndatSelectMemoryArea(pdev, moduleIndex, sensorIndex, 0xA5);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSelectMemoryArea, error : %d \n", i_ReturnValue);
        return 1;
    }

    /* read the address and get the parameter */
    i_ReturnValue = i_APCI1711_EndatSensorSendParameter(pdev,moduleIndex,sensorIndex,0xA5,5,&readValue);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSensorSendParameter, error : %d \n", i_ReturnValue);
        return 1;

    }
    allowEndat22 = (readValue & 0x1);

    if(allowEndat22)
    {
        printk("sensor allow EnDat 2.2 commands");
    }
    else
    {
        printk ("sensor doesn't allow EnDat 2.2 commands");
    }
    for (i=0;i<100;i++)
    {

        if(allowEndat22)
        {
            /* select the corresponding memory area */
            i_ReturnValue = i_APCI1711_EndatSensorSendPositionAndRecvMemArea(pdev,moduleIndex,sensorIndex,mrsCode);
            if ( i_ReturnValue != 0 )
            {
                if (i_ReturnValue == 20)
                {

                }
                printk("i_APCI1711_EndatSensorSendPositionAndRecvMemArea, error : %d \n", i_ReturnValue);
                return 1;
            }
            printk("i_APCI1711_EndatSensorSendPositionAndRecvMemArea (%x): ok. \n", mrsCode);

        }
        else
        {
            /* get the encoder version type */
            i_ReturnValue = i_APCI1711_EndatSelectMemoryArea(pdev,moduleIndex,sensorIndex,mrsCode);
            if ( i_ReturnValue != 0 )
            {
                if (i_ReturnValue == 20)
                {

                }
                printk("i_APCI1711_EndatSelectMemoryArea, error : %d \n", i_ReturnValue);
                return 1;
            }
        }

        /* select the corresponding memory area */
        i_ReturnValue = i_APCI1711_EndatSensorSendPositionAndRecvMemArea(pdev,moduleIndex,sensorIndex,mrsCode);
        if ( i_ReturnValue != 0 )
        {
            if (i_ReturnValue == 20)
            {

            }
            printk("i_APCI1711_EndatSensorSendPositionAndRecvMemArea, error : %d \n", i_ReturnValue);
            return 1;
        }
        printk("i_PCIe1711_EndatSelectMemoryArea (%x): ok. \n", mrsCode);


        /* read the address and get the parameter */
        i_ReturnValue = i_APCI1711_EndatSensorSendParameter(pdev,moduleIndex,sensorIndex,mrsCode,word,&param);
        if ( i_ReturnValue != 0 )
        {
            printk("i_PCIe1711_EndatSensorSendParameter, error : %d \n", i_ReturnValue);
            return 1;
        }
        printk("i_PCIe1711_EndatSensorSendParameter : \n"
            "\tmrscode :0x%x\n"
            "\tword %d \n"
            "\tvalue : 0x%x): ok. \n", mrsCode,  word, param);

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

    }

    return 0;


}


/** 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_endat_kernel (pdev);

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

}
//------------------------------------------------------------------------------
module_exit(apci1710Sample_exit);
module_init(apci1710Sample_init);



