/** @file analog_in-kapi.c

   Contains functions that enable to read the analog input

   @par CREATION
   @author Rose Jordan
   @date   20.09.2010

   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim

   @par LICENCE
   @verbatim
   Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.

        ADDI-DATA GmbH
        Dieselstrasse 3
        D-77833 Ottersweier
        Tel: +19(0)7223/9493-0
        Fax: +49(0)7223/9493-92
        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 should have received a copy of the GNU General Public License along with
   this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

   You shoud also find the complete GPL in the COPYING file
   accompanying this source code.
   @endverbatim
 */

#include "apci3701-private.h"

EXPORT_SYMBOL(i_APCI3701_read_1_analog_channel);

/*
 * This function enables to read the value of one channel, and return the value
 *
 * Returns:
 * 		-1: an acquisition was still started
 * 		-2: the channel given in parameter is too high
 */
int i_APCI3701_read_1_analog_channel( struct pci_dev *pdev, BYTE channel, uint32_t* value )
{
	DWORD dw_eos = 0;
	DWORD dw_chan_value = 0;

	/*
	 * Test if an acquisition is still loaded or not
	 */
	if ( APCI3701_ACQUISITION_STARTED(pdev) )
		return -1;

	/*
	 * Test the channel given in parameter
	 */
	if (channel >= APCI3701_PRIVDATA(pdev)->b_NumberOfAnalogInput)
		return -2;

	// Set in sequence selection
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_INDEX, (uint32_t) 0x100 );

	// Write the channel number
	OUTPDW_MEM( GET_MEM_BAR3(pdev), 0, (uint32_t) (channel & 0xFFFFFFFFUL) );

	// Sequence index to 0
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_INDEX, (uint32_t) 0x0 );

	// Clear sequence index and start bit
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, (uint32_t) 0x0 );

	// Clear sequence counter
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_COUNTER_M, (uint32_t) 0x0 );

	// Clear the FIFO
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_REG_CLEAR_INDEX, (uint32_t) (0x1 << 16) );

	// Start the conversion
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, (uint32_t) (0x1 << 19) );

	// Read the EOS bit
	INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_REG_ANALOG_INPUT_EOS_STATUS, &dw_eos);

	do
	{
		INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_REG_ANALOG_INPUT_EOS_STATUS, &dw_eos);
	}
	while(dw_eos != 1);

	// Read the channel value
	// Remember that we are in sequence mode, so the value are stored here
	INPDW_MEM( GET_MEM_BAR3(pdev), (APCI3701_REG_AUTOREFRESH_VALUES_BASE + (channel * 4)), &dw_chan_value );
	dw_chan_value = (uint32_t)(dw_chan_value & 0xFFFF);

	// Returns it
	*value = dw_chan_value;

	return 0;
}
