/** @file sample_endat_01.c
*
* @author El Bakali Laaziz
*  Get Operating Status
*  i_APCI1711_EndatResetErrorBits
*  i_APCI1711_EndatInitialiseSensor
*  i_APCI1711_EndatSelectMemoryArea
*  i_APCI1711_EndatSensorSendParameter
*  i_APCI1711_EndatSensorReceiveParameter
*  i_APCI1711_EndatGetErrorSources
*/

/** @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 Rheinmuenster
    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;
    uint8_t moduleIndex = 0;
    uint8_t sensorIndex = 0;
    uint32_t frequency = 1000;
    uint8_t errorSrc1 = 0;
    uint8_t errorSrc2 = 0;
    uint8_t errorSrc3 = 0;
    uint8_t errorSrc4 = 0;
    uint8_t errorSrc7 = 0;
    uint8_t errorSrc8 = 0;
    uint8_t errorSrc9 = 0;
    uint8_t errorSrc10 = 0;
    uint8_t errorSrc11 = 0;
    uint8_t errorSrc12 = 0;
    uint8_t errorSrc13 = 0;
    uint32_t param = 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 ("%s %i\n", __FUNCTION__, __LINE__);

    /* 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 ("%s %i\n", __FUNCTION__, __LINE__);

    /**
    * select the memory area 0xB9
    * indeed, in the EnDat documentation, you can see that the memory area 0xB9 contains information
    * concerning the operating status
    */
    i_ReturnValue = i_APCI1711_EndatSelectMemoryArea(pdev,moduleIndex,sensorIndex,0xB9);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSelectMemoryArea, error : %d \n",i_ReturnValue);
        return 1;
    }
    printk ("%s %i\n", __FUNCTION__, __LINE__);


    /* read the word 0 (error message) - MRS-Code (0xB9) stay the same */
    i_ReturnValue = i_APCI1711_EndatSensorSendParameter(pdev,moduleIndex,sensorIndex,0xB9,0x0,&param);
    if ( i_ReturnValue != 0 )
    {
        printk("i_PCIe1711_EndatSensorSendParameter, error : %d \n", i_ReturnValue);
        return 1;
    }


    printk("i_PCIe1711_EndatSensorSendParameter (0xB9 - 0x0 ): ok. \n");
    printk("Error message (read in the sensor's register) : 0x%x \n", param);

    if ( (param & 1) == 1 )
    {
        printk("\tLight source: Failure.\n");
    }
    if ( ((param >> 1) & 1) == 1 )
    {
        printk("\tSignal amplitude: Faulty.\n");
    }
    if ( ((param >> 2) & 1) == 1 )
    {
        printk("\tPosition: Faulty.\n");
    }
    if ( ((param >> 3) & 1) == 1 )
    {
        printk("\tOvervoltage: Yes.\n");
    }
    if ( ((param >> 4) & 1) == 1 )
    {
        printk("\tUndervoltage: Undervoltage supply.\n");
    }
    if ( ((param >> 5) & 1) == 1 )
    {
        printk("\tOvercurrent: Yes.\n");
    }
    if ( ((param >> 6) & 1) == 1 )
    {
        printk("\tBattery: Change required.\n");
    }


    /* reset the error bits of the operating status */
    i_ReturnValue = i_APCI1711_EndatSensorReceiveParameter(pdev, moduleIndex,sensorIndex,0xB9,0x0,0x0);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSensorReceiveParameter, error : %d \n", i_ReturnValue);
        return 1;
    }

    printk ("%s %i\n", __FUNCTION__, __LINE__);

    /* read the word 1 (warnings) - MRS-Code (0xB9) stay the same */
    i_ReturnValue = i_APCI1711_EndatSensorSendParameter(pdev, moduleIndex,sensorIndex,0xB9,0x1, &param);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSensorSendParameter, error : %d \n", i_ReturnValue);
        return 1;

    }
    printk("i_APCI1711_EndatSensorSendParameter (0xB9 - 0x1 ): ok. \n");

    printk("Warnings (read in the sensor's register) : 0x%x \n", param);

    if ( (param & 1) == 1 )
    {
        printk("\tFrequency collision: Yes.\n");
    }
    if ( ((param >> 1) & 1) == 1 )
    {
        printk("\tTemperature exceeded: Yes.\n");
    }
    if ( ((param >> 2) & 1) == 1 )
    {
        printk("\tLight source control reserve: Reached.\n");
    }
    if ( ((param >> 3) & 1) == 1 )
    {
        printk("\tBattery charge: Too low.\n");
    }
    if ( ((param >> 4) & 1) == 1 )
    {
        printk("\tReference points: Not reached.\n");
    }
    if ( ((param >> 5) & 1) == 1 )
    {
        printk("\tCyclic mode: Acyclic.\n");
    }
    if ( ((param >> 6) & 1) == 1 )
    {
        printk("\tLimit position: Reached.\n");
    }
    if ( ((param >> 7) & 1) == 1 )
    {
        printk("\tReadiness: None.\n");
    }
    if ( ((param >> 8) & 1) == 1 )
    {
        printk("\tDiagnostics: Below threshold value.\n");
    }

    /* reset the warnings bits of the operating status */
    i_ReturnValue = i_APCI1711_EndatSensorReceiveParameter(pdev,moduleIndex,sensorIndex,0xB9,0x1,0x0);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSensorReceiveParameter, error : %d \n", i_ReturnValue);
        return 1;
    }
    printk("i_APCI1711_EndatSensorReceiveParameter (0xB9 - 0x1 ): ok. \n");


    printk("\n*********************************************************\n");
    /* read the word 2 (write-protected status) - MRS-Code (0xB9) stay the same */
    i_ReturnValue = i_APCI1711_EndatSensorSendParameter(pdev, moduleIndex,sensorIndex,0xB9,0x2,&param);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSensorSendParameter, error : %d \n", i_ReturnValue);
        return 1;
    }

    printk("i_APCI1711_EndatSensorSendParameter (0xB9 - 0x2 ): ok. \n");

    printk("Write-protected status (read in the sensor's register) : 0x%x \n", param);

    if ( (param & 1) == 1 )
    {
        printk("\tEncoder manufacturer: Protection activated.\n");
    }
    if ( ((param >> 1) & 1) == 1 )
    {
        printk("\tOperating parameters: Protection activated.\n");
    }
    if ( ((param >> 2) & 1) == 1 )
    {
        printk("\tOEM: Protection activated.\n");
    }
    if ( ((param >> 3) & 1) == 1 )
    {
        printk("\tCompensation values, MRS code 10110111: Protection activated.\n");
    }
    if ( ((param >> 4) & 1) == 1 )
    {
        printk("\tCompensation values, MRS code 10110101: Protection activated.\n");
    }
    if ( ((param >> 5) & 1) == 1 )
    {
        printk("\tCompensation values, MRS code 10110011: Protection activated.\n");
    }
    if ( ((param >> 6) & 1) == 1 )
    {
        printk("\tSection 2 memory area block 0: Protection activated.\n");
    }
    if ( ((param >> 7) & 1) == 1 )
    {
        printk("\tSection 2 memory area block 1: Protection activated.\n");
    }
    if ( ((param >> 8) & 1) == 1 )
    {
        printk("\tSection 2 memory area block 2: Protection activated.\n");
    }
    if ( ((param >> 9) & 1) == 1 )
    {
        printk("\tSection 2 memory area block 3 to n: Protection activated.\n");
    }


    printk("\n*********************************************************\n");
    /* read the word 3 (initializing the Functions) - MRS-Code (0xB9) stay the same */
    i_ReturnValue = i_APCI1711_EndatSensorSendParameter(pdev, moduleIndex,sensorIndex,0xB9,0x3,&param);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatSensorSendParameter, error : %d \n", i_ReturnValue);
        return 1;
    }
    printk("i_APCI1711_EndatSensorSendParameter (0xB9 - 0x3 ): ok. \n");
    printk("Initializing the Functions (read in the sensor's register) : 0x%x \n", param);

    if ( (param & 1) == 1 )
    {
        printk("\tRecovery time tm: 1.25us < tm < 3.75us.\n");
    }
    else
    {
        printk("\tRecovery time tm: 10us < tm < 30us.\n");
    }
    if ( ((param >> 2) & 1) == 1 )
    {
        printk("\tReference pulse initialization: Activated.\n");
    }
    else
    {
        printk("\tReference pulse initialization: Deactivated.\n");
    }
    if ( ((param >> 4) & 1) == 1 )
    {
        printk("\tOversampling: Activated.\n");
    }
    else
    {
        printk("\tOversampling: Deactivated.\n");
    }
    if ( ((param >> 6) & 1) == 1 )
    {
        printk("\tEnDat 2.2 cyclic operation: Activated.\n");
    }
    else
    {
        printk("\tEnDat 2.2 cyclic operation: Deactivated.\n");
    }
    if ( ((param >> 8) & 1) == 1 )
    {
        printk("\tMultiturn overflow error message: Activated.\n");
    }
    else
    {
        printk("\tMultiturn overflow error message: Deactivated.\n");
    }
    if ( ((param >> 9) & 1) == 1 )
    {
        printk("\tMultiturn overflow latch: Activated.\n");
    }
    else
    {
        printk("\tMultiturn overflow latch: Deactivated.\n");
    }
    if ( ((param >> 10) & 1) == 1 )
    {
        printk("\tMultiturn error messages: Activated.\n");
    }
    else
    {
        printk("\tMultiturn error messages: Deactivated.\n");
    }
    if ( ((param >> 11) & 1) == 1 )
    {
        printk("\tMultiturn counter reset: Activated.\n");
    }
    else
    {
        printk("\tMultiturn counter reset: Deactivated.\n");
    }
    if ( ((param >> 13) & 1) == 1 )
    {
        printk("\tDiagnostics reset: Activated.\n");
    }
    else
    {
        printk("\tDiagnostics reset: Deactivated.\n");
    }

    printk("\n*********************************************************\n");
    /* get the errors */
    i_ReturnValue = i_APCI1711_EndatGetErrorSources(pdev,moduleIndex,sensorIndex,&errorSrc1,&errorSrc2,&errorSrc3,&errorSrc4,
                                                    &errorSrc7,&errorSrc8,&errorSrc9,&errorSrc10, &errorSrc11,&errorSrc12,
                                                    &errorSrc13);
    if ( i_ReturnValue != 0 )
    {
        printk("i_APCI1711_EndatGetErrorSources, error : %d \n", i_ReturnValue);
        return 1;
    }
    printk("i_APCI1711_EndatGetErrorSources: ok. \n");

    /* dump the errors */
    printk("error source 1: \t %d\n", (int) errorSrc1);
    printk("error source 2: \t %d\n", (int) errorSrc2);
    printk("error source 3: \t %d\n", (int) errorSrc3);
    printk("error source 4: \t %d\n", (int) errorSrc4);
    printk("error source 7: \t %d\n", (int) errorSrc7);
    printk("error source 8: \t %d\n", (int) errorSrc8);
    printk("error source 9: \t %d\n", (int) errorSrc9);
    printk("error source 10: \t %d\n", (int) errorSrc10);
    printk("error source 11: \t %d\n", (int) errorSrc11);
    printk("error source 12: \t %d\n", (int) errorSrc12);
    printk("error source 13: \t %d\n", (int) errorSrc13);

    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;
    }

    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);
