/** @file sample_pwm_01.c
*
* @author 
    Read 1 PWM status.
    PWM initialisation :
      - The period start witch a low level
      - The PWM is stopped directly after
        the 'i_APCI1710_DisablePWM' and break
        the last period
      - The output signal keep the level
        after the 'i_APCI1710_DisablePWM'
      - Extern gate disable
      - Interrupt disable
*/

/** @par LICENCE
* @verbatim
    Copyright (C) 2016  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_pwm";

// update here

uint8_t moduleIndex = 0;                 // selected module of the card+
uint8_t  b_SelectedPWM = 0;        // PWM in Module can be 0 or 1
struct pci_dev *pdev;                   // board handle

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

            uint8_t  b_ClockSelection = 2;                         // Clock selection
            /*
            * Get clock selection. '0' for 30 MHz
            '1' for 33 MHz 
            '2' for 40 MHz
            */
            uint8_t  b_SelectedPWM = 0;                            // PWM in Module can be 0 or 1
            uint8_t  b_TimingUnit = 2;                             // Timing unity selection
            unsigned long irqstate;                               // Spin lock
            /*
            * timing unity. '0' for ns
            '1' for us
            '2' for ms
            '3' for s
            '4' for mn
            */
            uint32_t ul_LowTiming = 5;                            // Low timing - 5 milli-seconds
            uint32_t ul_HighTiming = 5;                          // High timing - 5 milli-seconds
            uint8_t  b_PWMOutputStatus;                            // Output level
            uint8_t  b_ExternGateStatus;                   // Extern gate status

        


            /***********************/
            /* Get Clock selection */
            /***********************/

            if (b_ClockSelection == '0')
            {
                b_ClockSelection = APCI1710_30MHZ;
            }
            else
            {
                if (b_ClockSelection == '1')
                {
                    b_ClockSelection = APCI1710_33MHZ;
                }
                else
                {
                    b_ClockSelection = APCI1710_40MHZ;
                }
            }

       printk ("\n Start of the sample");
       /**********************/
       /* Initialise the PWM */
       /**********************/
            /* Lock the function to avoid parallel configurations */
            apci1710_lock(pdev,&irqstate);

            
            i_ReturnValue = i_APCI1710_InitPWM(pdev,moduleIndex,b_SelectedPWM, b_ClockSelection, b_TimingUnit, ul_LowTiming, ul_HighTiming);
            
            /* Unlock the function so that other applications can call it */
            apci1710_unlock(pdev,irqstate);
           /*************************/
       /* Test the return value */
       /*************************/

       switch (i_ReturnValue)
          {
          case 0 :
           printk ("\ni_APCI1710_InitPWM OK");
                   
                   /* Lock the function to avoid parallel configurations */
                    apci1710_lock(pdev,&irqstate);

           i_ReturnValue = i_APCI1710_EnablePWM (pdev,
                             moduleIndex,
                             b_SelectedPWM,
                             0,
                             0,
                             0,
                             0,
                             APCI1710_DISABLE);
                   
                  /* Unlock the function so that other applications can call it */
                    apci1710_unlock(pdev,irqstate);

           /*************************/
           /* Test the return value */
           /*************************/

           switch (i_ReturnValue)
              {
              case 0:
               printk ("\n");

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

                  i_ReturnValue = i_APCI1710_GetPWMStatus (pdev,
                                       moduleIndex,
                                       b_SelectedPWM,
                                       &b_PWMOutputStatus,
                                       &b_ExternGateStatus);
                              
                            /* Unlock the function so that other applications can call it */
                                apci1710_unlock(pdev,irqstate);

                  /*************************/
                  /* Test the return value */
                  /*************************/

                  switch (i_ReturnValue)
                 {
                 case 0:
                      if (b_PWMOutputStatus)
                     {
                     printk ("\rThe output signal is high. Extern gate level = %d", b_ExternGateStatus);
                     }
                      else
                                         {
                     printk ("\rThe output signal is low . Extern gate level = %d ", b_ExternGateStatus);
                     }
                      break;

                 case -1:
                      printk ("\ni_APCI1710_GetPWMStatus error");
                      printk ("\nError = %d. The handle parameter of the board is wrong.", i_ReturnValue);
                      break;

                 case -2:
                      printk ("\ni_APCI1710_GetPWMStatus error");
                      printk ("\nError = %d. Module selection wrong.", i_ReturnValue);
                      break;

                 case -3:
                      printk ("\ni_APCI1710_GetPWMStatus error");
                      printk ("\nError = %d. The module is not a PWM module.", i_ReturnValue);
                      break;

                 case -4:
                      printk ("\ni_APCI1710_GetPWMStatus error");
                      printk ("\nError = %d. PWM selection is wrong.", i_ReturnValue);
                      break;

                 case -5:
                      printk ("\ni_APCI1710_GetPWMStatus error");
                      printk ("\nError = %d. PWM not initialised.", i_ReturnValue);
                      break;

                 case -6:
                      printk ("\ni_APCI1710_GetPWMStatus error");
                      printk ("\nError = %d. PWM not enabled.", i_ReturnValue);
                      break;

                 default:
                      printk ("\ni_APCI1710_GetPWMStatus error");
                      printk ("\nError = %d.", i_ReturnValue);
                      break;
                 }
     
        
 
               break;
                           
                           // Case error for Enable PWM function

              case -1:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. The handle parameter of the board is wrong.", i_ReturnValue);
               break;

              case -2:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. Module selection wrong.", i_ReturnValue);
               break;

              case -3:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. The module is not a PWM module.", i_ReturnValue);
               break;

              case -4:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. PWM selection is wrong.", i_ReturnValue);
               break;

              case -5:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. PWM not initialised.", i_ReturnValue);
               break;

              case -6:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. PWM start level selection is wrong.", i_ReturnValue);
               break;

              case -7:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. PWM stop mode selection is wrong.", i_ReturnValue);
               break;

              case -8:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. PWM stop level selection is wrong.", i_ReturnValue);
               break;

              case -9:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. Extern gate signal selection is wrong.", i_ReturnValue);
               break;

              case -10:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. Interrupt parameter is wrong.", i_ReturnValue);
               break;

              case -11:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d. Interrupt function not initialized.", i_ReturnValue);
               break;

              default:
               printk ("\ni_APCI1710_EnablePWM error");
               printk ("\nError = %d.", i_ReturnValue);
               break;
              }
              
                  break;    
                   // Case error for Initialize PWM function
                   
          case -1:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. The handle parameter of the board is wrong.", i_ReturnValue);
           break;

          case -2:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. Module selection wrong.", i_ReturnValue);
           break;

          case -3:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. The module is not a PWM module.", i_ReturnValue);
           break;

          case -4:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. PWM selection is wrong.", i_ReturnValue);
           break;

          case -5:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. The selected input clock is wrong.", i_ReturnValue);
           break;

          case -6:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. Timing Unit selection is wrong.", i_ReturnValue);
           break;

          case -7:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. Low base timing selection is wrong.", i_ReturnValue);
           break;

          case -8:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. High base timing selection is wrong.", i_ReturnValue);
           break;

          case -9:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d. You can not used the 40MHz clock selection with this board.", i_ReturnValue);
           break;

          default:
           printk ("\ni_APCI1710_InitPWM error");
           printk ("\nError = %d.", i_ReturnValue);
           break;
          }

return i_ReturnValue;
}

        
/** Called when module loads. */
static int __init apci1710Sample_init(void)
{
    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_pwm_kernel(pdev);

    return 0;
}
//-------------------------------------------------------------------
/** Called when module is unloaded. */
static void __exit apci1710Sample_exit(void)
{
            int i_ReturnValue = 0;
                unsigned long irqstate;                               // Spin lock
                           /*******************/
               /* Disable the PWM */
               /*******************/

                            /* Lock the function to avoid parallel configurations */
                                apci1710_lock(pdev,&irqstate);
                                
               i_ReturnValue = i_APCI1710_DisablePWM (pdev,
                                  moduleIndex,
                                  b_SelectedPWM);
                           
                           /* Unlock the function so that other applications can call it */
                                apci1710_unlock(pdev,irqstate);

               /*************************/
               /* Test the return value */
               /*************************/

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

                  case -1:
                   printk ("\ni_APCI1710_DisablePWM error");
                   printk ("\nError = %d. The handle parameter of the board is wrong.", i_ReturnValue);
                   break;

                  case -2:
                   printk ("\ni_APCI1710_DisablePWM error");
                   printk ("\nError = %d. Module selection wrong.", i_ReturnValue);
                   break;

                  case -3:
                   printk ("\ni_APCI1710_DisablePWM error");
                   printk ("\nError = %d. The module is not a PWM module.", i_ReturnValue);
                   break;

                  case -4:
                   printk ("\ni_APCI1710_DisablePWM error");
                   printk ("\nError = %d. PWM selection is wrong.", i_ReturnValue);
                   break;

                  case -5:
                   printk ("\ni_APCI1710_DisablePWM error");
                   printk ("\nError = %d. PWM not initialised.", i_ReturnValue);
                   break;

                  case -6:
                   printk ("\ni_APCI1710_DisablePWM error");
                   printk ("\nError = %d. PWM not enabled.", i_ReturnValue);
                   break;

                  default:
                   printk ("\ni_APCI1710_DisablePWM error");
                   printk ("\nError = %d.", i_ReturnValue);
                   break;
                  }

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

