/** @file temperature-open-line-diagnostic.c

@brief Demonstrate how to test if a line is open.


@par LICENCE
@verbatim
Copyright (C) 009  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 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 <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <sys/sysmacros.h> /* major() minor() */
#define NDEBUG
#include <assert.h>
#include <apci3200.h>
#include "findboards.h"
#include "input.h"
#include "errorlib.h"
#include "errormsg.h"
#include "libapci3200sample.h"
#include <signal.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <math.h>

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

/* Use to stop properly the sample */
static int Stop;

void quit_sample (int dummy)
{
	Stop = 1;
}

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

double CalculateVoltage(int Value, int CalibrationOffset, int CalibrationGain, int PGAGain, double RefVoltage, double GainFactor)
{
	printf ("%f %i %i %i %i %i %f ", RefVoltage, Value, CalibrationOffset, CalibrationGain, CalibrationOffset, PGAGain, GainFactor);
	return (RefVoltage * (double)(Value - CalibrationOffset)) / ((double)(CalibrationGain - CalibrationOffset) * (pow(2, PGAGain) * GainFactor));
}

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

/** This function demonstrate how to test if the line is open.
 *
 * @param[in] fd				: File descriptor of the board to use.
 * @param[in] channel			: Channel to test (0 - 15 single and 0 - 7 differential on a board with 4 ADC).
 * @param[in] sign				: Sign to test the channel:
 * 						  			0: > (if (measured voltage > voltage))
 * 						  			1: < (if (measured voltage < voltage))
 * @param[in] voltage			: Voltage value to be compared with the measured voltage.
 * @param[in] polarity			: Polarity APCI3200_POLARITY_BIPOLAR or APCI3200_POLARITY_UNIPOLAR.
 * @param[in] connectionType	: Polarity APCI3200_CONNECTION_TYPE_DIFFERENTIAL or APCI3200_CONNECTION_TYPE_SINGLE.
 *
 * @retval -1	: Error.
 * @retval 0	: Line is not open.
 * @retval 1	: Line is open.
 */
int i_APCI3200_TestTemperatureChannelConnection (int fd, int channel, unsigned char sign, double voltage, int polarity, int connectionType)
{
	unsigned long Value = 0;
	unsigned long Offset = 0;
	unsigned long Gain = 0;
	double ReferenceVoltage = 0.0;
	double CJCCurrentSource	= 0.0;
	double ChannelGainFactor = 0.0;
	double ChannelCurrentSource	= 0.0;
	double MeasuredVoltage = 0.0;
	int index = channel;

	if ((sign != 0) && (sign != 1))
		return -1;

	/* As not all function of the driver are managing single / differential connections automatically,
	 * in differential mode, the channel number has to be computed.
	 */
	if (connectionType == APCI3200_CONNECTION_TYPE_DIFFERENTIAL)
	{
		if (index%2)
		{
			channel = (index * 2)-1;
		}
		else
			channel = (index * 2);
	}
	else
	{
		channel = index;
	}

	/* Initialize the channel */
	{
		struct InitAnalogInputChannel_t ChannelInit;

		ChannelInit.b_PolaritySelected	= polarity;
		ChannelInit.b_DiffSingSelected	= connectionType;
		ChannelInit.w_GainSelected		= APCI3200_GAIN_1;
		ChannelInit.b_Channel			= channel;

		if ( call_ioctl (fd,CMD_APCI3200_InitAnalogInputChannel, &ChannelInit))
			return -1;
	}

	/* Set the converting time */
	{
		struct SetConvertingTime_t ConvertingTime;

		ConvertingTime.b_Channel			= channel;
		ConvertingTime.dw_TimerReloadValue	= APCI3200_FREQUENCE_20_HZ;
		ConvertingTime.b_ConvertingTimeUnit	= APCI3200_UNIT_HZ;

		if (call_ioctl (fd,CMD_APCI3200_SetConvertingTime, &ConvertingTime))
		  return -1;
	}

	/* Select the diagnostic open connection mode */
	{
		unsigned char value[2] = {0, 0};
		value[0] = APCI3200_DIAGNOSTIC_OPEN_CONNECTION;
		value[1] = channel;

		if (call_ioctl (fd,CMD_APCI3200_SetDiagnosticMode, value))
			return -1;
	}

	/* Read the channel value */
	Value = channel;
	if ( call_ioctl (fd,CMD_APCI3200_Read1AnalogInputChannelFast, &Value))
		return -1;

	Offset = channel;
	if ( call_ioctl (fd,CMD_APCI3200_ReadCalibrationOffsetValueFast, &Offset))
		return -1;

	Gain = channel;
	if ( call_ioctl (fd,CMD_APCI3200_ReadCalibrationGainValueFast, &Gain))
		return -1;

	/* Select the diagnostic to none mode */
	{
		unsigned char value[2] = {0, 0};
		value[0] = APCI3200_DIAGNOSTIC_NONE;
		value[1] = channel;

		if (call_ioctl (fd,CMD_APCI3200_SetDiagnosticMode, value))
			return -1;
	}

    /* CMD_APCI3200_ReadChannelCalibrationValue is managing single / differential mode that's why it is necessary to
     * give the channel index for differential connections: index
     */
	{
		struct ReadCalibrationValue_t ReadCalibrationValue;

		ReadCalibrationValue.b_Channel					= index;
		ReadCalibrationValue.w_ConnectionType			= connectionType;
		ReadCalibrationValue.w_Gain						= APCI3200_GAIN_1;
		ReadCalibrationValue.dw_CJCCurrentSource 		= 0;
		ReadCalibrationValue.dw_ChannelCurrentSource	= 0;
		ReadCalibrationValue.dw_ChannelGainFactor		= 0;

		if ( call_ioctl (fd,CMD_APCI3200_ReadChannelCalibrationValue, &ReadCalibrationValue))
			return -1;

		CJCCurrentSource		= ((double) ReadCalibrationValue.dw_CJCCurrentSource / 1000000000.0);
		ChannelGainFactor		= ((double) ReadCalibrationValue.dw_ChannelGainFactor / 1000000.0);
		ChannelCurrentSource	= ((double) ReadCalibrationValue.dw_ChannelCurrentSource / 1000000000.0);
	}

	{
		struct ReadReferenceVoltage_t ReadReferenceVoltage;

		ReadReferenceVoltage.b_Channel = channel;

		if ( call_ioctl (fd,CMD_APCI3200_ReadReferenceVoltage, &ReadReferenceVoltage))
			return -1;

		ReferenceVoltage = ((double) ReadReferenceVoltage.dw_ReferenceVoltage / 1000.0);
	}

	MeasuredVoltage = CalculateVoltage (Value, Offset, Gain, APCI3200_GAIN_1, ReferenceVoltage, ChannelGainFactor);

	if (voltage > ReferenceVoltage)
	{
		voltage = voltage / 2.0;
	}

	printf ("%f %c %f ", (float)MeasuredVoltage, sign>0?'<':'>', voltage);
	if (sign == 0)
	{
		if (MeasuredVoltage > voltage)
			return 1;
	}
	else
	{
		if (MeasuredVoltage < voltage)
			return 1;
	}

	return 0;
}

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

int main(int argc, char** argv)
{
	int * apci3200_card_fd;
	unsigned int apci3200_card_number = 0;
	int channel = 0;
	unsigned char sign = 0;
	double voltage = 0.0;
	int polarity = APCI3200_POLARITY_UNIPOLAR;
	int connection = APCI3200_CONNECTION_TYPE_SINGLE;
	int i = 0;

	{
		apci3200_card_number = apci3200_find_cards(&apci3200_card_fd);

		printf("total: %d cards\n",apci3200_card_number);
	}

	{
		int index;
		switch(apci3200_card_number)
		{
		case 1:
			index = 0;
			break;
		case 0:
			exit(0);
		default:
			printf("board>");
			index = get_integer(0,apci3200_card_number-1);
		}

		Stop = 0;
		signal(SIGQUIT, quit_sample);

		printf("Test open connection on channel ");
		channel = get_integer(0,15);

		sign = 0, voltage = 2, polarity = APCI3200_POLARITY_BIPOLAR, connection = APCI3200_CONNECTION_TYPE_DIFFERENTIAL;
		for (i=0; i<=channel; i++)
			printf ("Channel %i connection is %s\n", i, (i_APCI3200_TestTemperatureChannelConnection (apci3200_card_fd[index], i, sign, voltage, polarity, connection) == 1)?"open":"closed");

	}
	return 0;
}
//--------------------------------------------------------------------------------
