 /* @file apci3120-kapi.h
  *
  * @brief Define the public Kernel API for the apci3120 ADDI-DATA board.
  *
  *
  */

/** @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 library is free software; you can redistribute it and/or modify it under
 the terms of the GNU Lesser General Public License as published by the
 Free Software Foundation; either version 2.1 of the License,
 or (at your option) any later version.

 This library 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 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this library; if not, write to the Free Software Foundation,
 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA


 You also shoud find the complete LGPL in the LGPL.txt file accompanying
 this source code.

 @endverbatim
**/

#ifndef __APCI3120_KAPI_H__
#define __APCI3120_KAPI_H__

#include "apci.h"

#ifndef __KERNEL__
#error This header is intended for use in kernel context only
#endif

//------------------------------------------------------------------------------
/** Initialize the analog input value.
 *
 * @param [in] 	pdev			: The device to initialize.
 * @param [in]	b_ChannelNumber	: The analog input channel.
 * @param [in]	b_Gain			: Gain factor of the analog input: <br>
 *									- APCI3120_1_GAIN : Gain =  1 <br>
 *									- APCI3120_2_GAIN : Gain =  2 <br>
 *									- APCI3120_5_GAIN : Gain =  5 <br>
 *									- APCI3120_10_GAIN: Gain = 10
 * @param [in]	b_Polarity		: Polarity of the analog input: <br>
 *									- APCI3120_UNIPOLAR:  0V - +10V <br>
 *									- APCI3120_BIPOLAR: -10V - +10V
 * @param [in]	ui_ConvertTiming: The convert timing of the analog input: <br>
 *									from 10us up to 32767us
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Number of the analog input is wrong.
 * @retval 3: The selected gain is wrong.
 * @retval 4: The selected input voltage range is wrong.
 * @retval 5: The selected conversion time is wrong.
 * @retval 6: A wrong parameter has been passed for <br>
 *			  b_InterruptFlag or the user interrupt routine has <br>
 *			  not been installed.
 */
extern int i_APCI3120_InitAnalogInput (struct pci_dev *pdev,
								uint8_t b_ChannelNumber,
                                uint8_t b_Gain,
                                uint8_t b_Polarity,
								uint32_t ui_ConvertTiming,
								uint8_t b_InterruptFlag);

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

/** Start the analog input conversion.
 *
 * @param [in] 	pdev			: The device to initialize.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
extern int i_APCI3120_StartAnalogInput (struct pci_dev *pdev);

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

/** Read the analog input conversion bit.
 *
 * Test the endo of conversion.
 *
 * @param [in] 	pdev			: The device to initialize.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The EOC flag is not set.
 */
extern int i_APCI3120_ReadAnalogInputBit (struct pci_dev *pdev);

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

/** Read the analog input value.
 *
 * @param [in] 	pdev			: The device to initialize.
 * @param [out]	ui_ReadValue	: The analog input value.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
extern int i_APCI3120_ReadAnalogInputValue (struct pci_dev *pdev, uint32_t *ui_ReadValue);

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

/** Read more analog input.
 *
 * @param [in] 	pdev				: The device to initialize.
 * @param [in]	b_SequenzArraySize		: Size of the sequence array (1 to 16 elements).
 * @param [in]	pb_ChannelArray			: Channels to read (array size = b_SequenzArraySize).
 * @param [in]	pb_GainArray			: Gain selection array.
 * @param [in]	pb_PolarityArray		: Selection of the input.
 * @param [in]	ui_ConvertTiming		: Selection of the conversion time from 10 to 32767 us.
 * @param [in]	b_InterruptFlag			: This parameter has to be 0 or PCI3120_DISABLE.<br>
 * 																The interrupt is not implemeted!
 *
 * @param [out]	pui_AnalogInputValueArray	: Read values.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The size of the sequence table is wrong.
 * @retval 3: Wrong parameter found in table "pb_ChannelArray".
 * @retval 4: Wrong parameter found in table "pb_GainArray".
 * @retval 5: Wrong parameter found in table "pb_PolarityArray".
 * @retval 6: The selected conversion time is wrong.
 * @retval 7: A wrong parameter has been passed for b_InterruptFlag.
 * @retval 8: Time out.
 *
 * @warning This function must not be called while the board is locked
 */
extern int   i_APCI3120_ReadMoreAnalogInputs     (struct pci_dev *pdev,
					   	uint8_t    b_SequenzArraySize,
					   	uint8_t *  pb_ChannelArray,
					   	uint8_t * pb_GainArray,
					   	uint8_t *  pb_PolarityArray,
					   	uint32_t    ui_ConvertTiming,
					   	uint8_t b_InterruptFlag,
					   	uint32_t * pui_AnalogInputValueArray);

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

/** Initialize the analog output value.
 *
 * @param [in] 	pdev			: The device to initialize.
 * @param [in]	b_ChannelNumber	: The analog output channel.
 * @param [in]	b_Polarity		: Polarity of the analog input: <br>
 *									- APCI3120_UNIPOLAR:  0V - +10V <br>
 *									- APCI3120_BIPOLAR: -10V - +10V
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Number of the analog output is wrong.
 * @retval 3: The selected output voltage range is wrong.
 */
extern int i_APCI3120_InitAnalogOutput (struct pci_dev *pdev,
										uint8_t b_ChannelNumber,
                                		uint8_t b_Polarity);

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

/** Write a value on a output channel.
 *
 * @param [in] 	pdev			: The device to initialize.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Wrong output value for the output channel.
 */
extern int i_APCI3120_Write1AnalogOutput (	struct pci_dev *pdev,
											uint8_t b_ChannelNumber,
											uint32_t ui_ValueToWrite);

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

/** Read the analog output conversion bit.
 *
 * Test the end of conversion.
 *
 * @param [in] 	pdev			: The device to initialize.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The ready bit flag is not set.
 */
extern int i_APCI3120_ReadAnalogOutputBit (struct pci_dev *pdev);

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

/** Write more analog outputs.
 *
 * @param [in] 	pdev					: The device to initialize.
 * @param [in] 	pui_ValueToWriteArray	: Value to write on each output.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Wrong output value for the output channel.
 */
extern int i_APCI3120_WriteMoreAnalogOutput (	struct pci_dev *pdev,
						uint32_t *pui_ValueToWriteArray);

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

/** Initialize read more analog input.
 *
 * @param [in] pdev                 : The device to initialize.
 * @param [in] b_SequenzArraySize   : Size of the sequence array (1 to 16 elements).
 * @param [in] pb_ChannelArray      : Channels to read (array size = b_SequenzArraySize).
 * @param [in] pb_GainArray         : Gain selection array.
 * @param [in] pb_PolarityArray     : Selection of the input.
 * @param [in] ui_ConvertTiming     : Selection of the conversion time from 10 to 32767 us.
 * @param [in] b_InterruptFlag      : This parameter has to be 0 or PCI3120_DISABLE.<br>
 * 																The interrupt is not implemeted!
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The size of the sequence table is wrong.
 * @retval 3: Wrong parameter found in table "pb_ChannelArray".
 * @retval 4: Wrong parameter found in table "pb_GainArray".
 * @retval 5: Wrong parameter found in table "pb_PolarityArray".
 * @retval 6: The selected conversion time is wrong.
 * @retval 7: A wrong parameter has been passed for b_InterruptFlag.
 * @retval 8: Time out.
 */
int i_APCI3120_InitReadMoreAnalogInput (struct pci_dev *pdev,
                                       uint8_t b_SequenzArraySize,
                                       uint8_t *  pb_ChannelArray,
                                       uint8_t * pb_GainArray,
                                       uint8_t *  pb_PolarityArray,
                                       uint32_t ui_ConvertTiming,
                                       uint8_t b_InterruptFlag);

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

/** Start read more analog input.
 *
 * @param [in]    pdev                 : The device to initialize.
 * @param [in]    b_SequenzArraySize   : Size of the sequence array (1 to 16 elements).
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The size of the sequence table is wrong.
 */
int i_APCI3120_StartReadMoreAnalogInput (struct pci_dev *pdev, uint8_t b_SequenzArraySize);

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

/** Test end of conversion of read more analog input.
 *
 * @param [in]    pdev  : The device to initialize.
 *
 * @retval 0: No error (Conversion is not running).
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Conversion is running.
 */
int i_APCI3120_TestEndOfReadMoreConversion (struct pci_dev *pdev);

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

/** Start read more analog input.
 *
 * @param [in]    pdev                 : The device to initialize.
 * @param [in]    b_SequenzArraySize   : Size of the sequence array (1 to 16 elements).
 * @param [out]   pui_Values           : Read values.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The size of the sequence table is wrong.
 */
int i_APCI3120_ReadMoreValues (struct pci_dev *pdev, uint8_t b_SequenzArraySize, uint32_t * pui_Values);

//------------------------------------------------------------------------------
/** find a apci3120 device of a given index in the system PCI device list.
 * @param index The index (minor number) to lookup
 * @return A pointer to the device or NULL
 *
 * This function is used to map a minor number to an actual device.
 */
extern struct pci_dev * apci3120_lookup_board_by_index(unsigned int index);
//----------------------------------------------------------------------------

/** return a pointer to the lock protecting the board */
extern spinlock_t * APCI3120_get_lock(struct pci_dev *pdev);

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

/** lock the board using spin_lock_irqsave(), disabling local software and hardware interrupts
 * @param[in] pdev The device to acquire.
 * @param[out] flags interuption flag used with unlock()
 *
 * This function is to be used before calling any kAPI function; BUT not in user interrupt handler where the board is already acquired.
 *
 * @warning lock aren't reentrant, that means that you can not nest call to lock()
 *
 */
static inline void APCI3120_lock(struct pci_dev *pdev, unsigned long * flags)
{
        spin_lock_irqsave(APCI3120_get_lock(pdev), *flags);
}

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

/** unlock the board using spin_lock_irqrestore()
 * @param[in] pdev The device to acquire.
 * @param[out] flags interuption flag initialised by lock()
 *
 * This function is to be used before calling any kAPI function; BUT not in user interrupt handler where the board is already acquired.
 *
 *
 *
 */
static inline void APCI3120_unlock(struct pci_dev *pdev, unsigned long flags)
{
        spin_unlock_irqrestore(APCI3120_get_lock(pdev), flags);
}

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

/** Read 4 digital input.
 *
 * @param [in] pdev                 : The device to manage.
 * @param [out] b_DigitalInputValue : Digital input value.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
int i_APCI3120_Read4DigitalInput (struct pci_dev *pdev, uint8_t *b_DigitalInputValue);

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

/** Set digital output memory on.
 *
 * When output memory is setting on. Output state is holding, and <br>
 * the new output(s) is(are) set or reset.
 *
 * @param [in] pdev                 : The device to manage.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
int i_APCI3120_SetOutputMemoryOn (struct pci_dev *pdev);

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

/** Set digital output memory off.
 *
 * @param [in] pdev                 : The device to manage.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
int i_APCI3120_SetOutputMemoryOff (struct pci_dev *pdev);

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

/** Set 4 digital output on.
 *
 * @param [in] pdev                 : The device to manage.
 * @param [in] b_DigitalOutputValue : Digital output value.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The digital output value is wrong.
 */
int i_APCI3120_Set4DigitalOutputOn (struct pci_dev *pdev, uint8_t b_DigitalOutputValue);

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

/** Set 4 digital output off.
 *
 * Can only be used when i_APCI3120_SetOutputMemoryOn has been called.
 *
 * @param [in] pdev                 : The device to manage.
 * @param [in] b_DigitalOutputValue : Digital output value.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The digital output value is wrong.
 * @retval 3: Output memory is not activated (please use i_APCI3120_SetOutputMemoryOn).
 */
int i_APCI3120_Set4DigitalOutputOff (struct pci_dev *pdev, uint8_t b_DigitalOutputValue);

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

/** Initialize the timer or watchdog functionality.
 *
 * @param [in] 	pdev			: The device to initialize.
 * @param [in]	b_TimerMode		: APCI3120_TIMER or APCI3120_WATCHDOG.
 * @param [in]	l_DelayValue	: Timer / Watchdog delay from 70 us to 4587400 us.
 * @param [in]	b_InterruptFlag	: This parameter has to be 0 or PCI3120_DISABLE.<br>
 * 								  The interrupt is not implemeted!
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Timer mode error.
 * @retval 3: The user interrupt routine is not installed.
 * @retval 4: The interrupt parameter is wrong.
 * @retval 5: The time interval selected for timer is wrong.
 */
int i_APCI3120_InitTimerWatchdog (struct pci_dev *pdev,
								  uint8_t b_TimerMode,
								  uint32_t ul_DelayTime,
								  uint8_t b_InterruptFlag);

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

/** Start the timer or watchdog functionality.
 *
 * @param [in] 	pdev			: The device to initialize.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Timer or watchdog not initialized.
 */
int i_APCI3120_StartTimerWatchdog (struct pci_dev *pdev);

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

/** Stop the timer or watchdog functionality.
 *
 * @param [in] 	pdev			: The device to initialize.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Timer or watchdog not initialized.
 * @retval 3: Timer or watchdog has not been started.
 */
int i_APCI3120_StopTimerWatchdog (struct pci_dev *pdev);

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

/** Read the timer value.
 *
 * @param [in] 	pdev			: The device to initialize.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Timer not initialized.
 * @retval 3: Watchdog was initialized, not a timer.
 */
int i_APCI3120_ReadTimer (struct pci_dev *pdev,
                          uint32_t *pl_ReadValue);

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

/** Read the watchdog status.
 *
 * @param [in] 	pdev				: The device to initialize.
 *
 * @param [out] pb_watchdogStatus	: 0: Watchdog has not run down<br>
 *                                    1: Watchdog has run down
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Watchdog not initialized.
 * @retval 3: Timer was initialized, not a Watchdog.
 */
int i_APCI3120_ReadWatchdogStatus (struct pci_dev *pdev,
								   uint8_t *pb_watchdogStatus);

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

/** Initialize a sequence acquisition
 *
 * @param [in]	pdev				: The device to initialize
 * @param [in]	sequence_array_size	: The number of channels in the sequence
 * @param [in]	sequence			: An array containing the id of the channel that will be acquired during the sequence
 * @param [in]	gain				: An array containing the gain of the channels
 * @param [in]	polarity			: An array containing the polarity of the channels
 * @param [in]	sequence_data		: A pointer to a structure containing usefull data for the sequence acquisition. The structure is described in the file apci3120.h
 * Description of the structure apci3120_sequence_acquisition_data
 *					uint8_t acquisition_mode		: Two conversion cycles are possible:
															- APCI3120_SIMPLE_MODUS:
																A conversion occurs every acquisition_timing (time interval)
															- APCI3120_DELAY_MODUS:
																The both times are used in this mode:
																	ui_AcquisitionTiming and l_DelayTiming.
																Conversions occur every ui_AcquisitionTiming (time interval) until all the analog inputs have been acquired
																(determined by b_SequenzArraySize)
																Step 1.
																	Afterwards there is a waiting time of l_DelayTiming.
																Step 2
																	The two steps are repeated
					uint8_t extern_trigger			: APCI3120_ENABLE or APCI3120_DISABLE
					uint32_t acquisition_timing		: Time in us between two conversions of successive input.
														If APCI_DMA_USED: from 7 us to 45874 us
														If APCI3120_NOT_DMA_USED: from 1500 us to 45874 us
					uint64_t delay_timing			: Waiting time in us between two conversion cycles. From 70us to 4587400 (Only have a meaning if use : APCI3120_DELAY_MODUS)
					uint32_t number_of_acquisition	: How many acquisitions have to happened (1 to 32767) before an interrupt occurs
					uint8_t dma_mode				: Determine is DMA is used or not.
														If APCI3120_DMA_USED: all the conversion values are saved and returned to the user. An interrupt is generated when
														the conversions (set by number_of_acquisition) are completed
														If APCI3120_DMA_NOT_USED: An interrupt is generated at the end of each conversion and the analog value is returned
														to the user thanks to the interrupt routine
														For the moment this option must be set to APCI3120_DMA_USED !!!!!
					uint8_t acquisition_cycle		: Type of DMA conversion
														If APCI3120_CONTINUOUS: An interrupt is generated each time a DMA conversion cycle is completed .A new DMA conversion cycle is started
														If APCI3120_SINGLE: The DMA conversion cycle is only carried out once: i.e.you receive one single interrupt at the end of the
														first DMA conversion cycle.
														For the moment this option must be set to APCI3120_CONTINUOUS !!!!!
  | Return Value      :  0  : No error                                         |
  |                      1  : The handle parameter of the board is wrong       |
  |                      2  : The user interrupt routine is not installed.     |
  |                           See function "i_APCI3120_SetBoardIntRoutine"     |
  |                      3  : The size of the sequence table is wrong          |
  |                      4  : Wrong parameter found in table "pb_ChannelArray" |
  |                      5  : Wrong parameter found in table "pb_GainArray"    |
  |                      6  : Wrong parameter found in table "pb_PolarityArray"|
  |                      7  : The waiting time between two conversion cycles is|
  |                           too high                                         |
  |                      8  : The selected time for ui_AcquisitionTiming or    |
  |                           l_DelayTiming is wrong                           |
  |                      9  : The parameter b_DMAUsed is wrong                 |
  |                      10 : The parametered running time of the DMA          |
  |                           conversion cycle is wrong                        |
  |                           (APCI3120_CONTINUOUS or APCI3120_SINGLE)         |
  |                      11 : The parametered conversion cycle is wrong        |
  |                           (APCI3120_SIMPLE_MODUS or APCI3120_DELAY_MODUS   |
  |                      12: Not enough memory available.                      |
  |                      13: Extern Trigger is wrong                           |
  |                      14: ul_NumberOfAcquisition is wrong                   |
  |                      16: The Delay time is too small.                      |
 */
int i_APCI3120_InitAnalogInputSequenceAcquisition (	struct pci_dev *pdev,
													//uint8_t sequence_array_size,
													//uint8_t* sequence,
													//uint8_t* gain,
													//uint8_t* polarity,
													struct apci3120_sequence_acquisition_data *sequence_data);

/*
 * Starts the cyclic conversion. It has been previously initialized with function "i_APCI3120_InitAnalogInputAcquisition".
  | Return Value      :  0: No error                                           |
  |                      1: The handle parameter of the board is wrong         |
  |                      2: The cyclic conversion has not been initialized.    |
  |                         "i_APCI3120_InitAnalogInputAcquisition"            |
  |                      3: Interrupt routine has not been installed.          |
  |                      4: There was still a running acquisition              |
 */
int i_APCI3120_StartAnalogInputSequenceAcquisition (	struct pci_dev *pdev);

/*
  +----------------------------------------------------------------------------+
  | Function's Name   : _INT_ i_APCI3120_StopAnalogInputAcquisition            |
  |                               (BYTE_    b_BoardHandle)                     |
  +----------------------------------------------------------------------------+
  | Task              : Stops the cyclic conversion . It has been started      |
  |                     previously with function                               |
  |                     "i_APCI3120_StartAnalogInputAcquisition".              |
  +----------------------------------------------------------------------------+
  | Input Parameters  : BYTE      b_BoardHandle     : Handle of board APCI3120 |
  +----------------------------------------------------------------------------+
  | Return Value      :  0: No error                                           |
  |                     -1: The handle parameter of the board is wrong         |
  |                     -2: The cyclic conversion has not been started.        |
  |                         "i_APCI3120_StartAnalogInputAcquisition"           |
  +----------------------------------------------------------------------------+
*/
int i_APCI3120_StopSequenceAcquisition ( struct pci_dev *pdev);

#endif // __APCI3120_KAPI_H__
