/** @file temperature.c

@brief another example, this time reading temperature in differential modus and SCAN


@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 <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 "convert.h"
#include "findboards.h"
#include "input.h"
#include "errorlib.h"
#include "errormsg.h"
#include "libapci3200sample.h"

//--------------------------------------------------------------------------------
int verbose=0;
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_InitAnalogInputChannel(int fd, int ch, struct acquisition_t *acquisition)
{
	acquisition->ChannelInit.b_Channel = ch;
	acquisition->ChannelInit.b_PolaritySelected = apci3200_ask_polarity();

	if(acquisition->ChannelInit.b_PolaritySelected==APCI3200_POLARITY_BIPOLAR)
		acquisition->ChannelInit.w_GainSelected = APCI3200_GAIN_1;
	else
		acquisition->ChannelInit.w_GainSelected = apci3200_ask_gain();

	// On one module the connection type has to be the same.
	// One module can have 4 single channels or 2 differential
	// channels.

	// If you chose to use one channel in differential,
	// you have to use all channels from this module in
	// differential mode!

	acquisition->ChannelInit.b_DiffSingSelected = apci3200_ask_connection_type();

	if(verbose) printf("=> CMD_APCI3200_InitAnalogInputChannel on input %i\n", acquisition->ChannelInit.b_Channel);
	if ( call_ioctl (fd,CMD_APCI3200_InitAnalogInputChannel, &(acquisition->ChannelInit)))
		return -1;
	return 0;
}
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_Read1AnalogInputChannel(int fd, int ch,  struct acquisition_t *acquisition)
{
	struct Read1AnalogInputChannel_t read;

	read.b_Channel = ch;
	read.dw_TimerReloadValue = acquisition->Frequency;
	read.b_ConvertingTimeUnit = APCI3200_UNIT_HZ;
	read.dw_ChannelValue = 0;		// will be the channel value

	if(verbose) printf("=> CMD_APCI3200_Read1AnalogInputChannel on input %i\n", read.b_Channel);
	{
		if ( call_ioctl (fd,CMD_APCI3200_Read1AnalogInputChannel, &read))
			return -1;

		printf("\nAnalog input %i value = %lu\n", read.b_Channel, read.dw_ChannelValue);
		acquisition->dw_ChannelValue = read.dw_ChannelValue;
	}
	return 0;
}
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_ReadReferenceVoltage(int fd, int ch, struct acquisition_t *acquisition)
{
	struct ReadReferenceVoltage_t read;

	read.b_Channel = ch;

	if(verbose) printf("=> CMD_APCI3200_ReadReferenceVoltage on input %i\n", read.b_Channel);
	{
		if ( call_ioctl (fd,CMD_APCI3200_ReadReferenceVoltage, &read))
			return -1;

		printf("Analog input %i value has reference voltage %u %s\n", read.b_Channel, read.dw_ReferenceVoltage, apci3200_unit2symb(read.Unit));
		acquisition->dw_ReferenceVoltage = read.dw_ReferenceVoltage;
	}
	return 0;
}
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_ReadCJCValue(int fd, struct acquisition_t *acquisition)
{
	struct Read1CJCInputChannel_t read;

	read.dw_TimerReloadValue = acquisition->Frequency;
	read.b_ConvertingTimeUnit = APCI3200_UNIT_HZ;
	read.dw_ChannelValue = 0;		// will be the channel value

	if(verbose) printf("=> CMD_APCI3200_ReadCJCValue\n");
	{
		if ( call_ioctl (fd,CMD_APCI3200_ReadCJCValue, &read))
			return -1;

		printf("CJC input value = %lu \n", read.dw_ChannelValue);
		acquisition->dw_CJCValue = read.dw_ChannelValue;
	}
	return 0;
}
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_ReadCalibrationGainValue(int fd, int ch, struct acquisition_t *acquisition)
{
	struct Read1AnalogInputChannel_t read;

	read.b_Channel = ch;
	read.dw_TimerReloadValue = acquisition->Frequency;
	read.b_ConvertingTimeUnit = APCI3200_UNIT_HZ;
	read.dw_ChannelValue = 0;		// will be the channel value

	if(verbose) printf("=> CMD_APCI3200_ReadCalibrationGainValue on input %i\n", read.b_Channel);
	{
		if ( call_ioctl (fd,CMD_APCI3200_ReadCalibrationGainValue, &read))
			return -1;

		printf("Analog input gain %i value = %lu\n", read.b_Channel, read.dw_ChannelValue);
		acquisition->dw_ChannelGainValue = read.dw_ChannelValue;
	}
	return 0;
}
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_ReadCalibrationOffsetValue(int fd, int ch, struct acquisition_t *acquisition)
{
	struct Read1AnalogInputChannel_t read;

	read.b_Channel = ch;
	read.dw_TimerReloadValue = acquisition->Frequency;
	read.b_ConvertingTimeUnit = APCI3200_UNIT_HZ;
	read.dw_ChannelValue = 0;		// will be the channel value

	if(verbose) printf("=> CMD_APCI3200_ReadCalibrationOffsetValue on input %i\n", read.b_Channel);
	{
		if ( call_ioctl (fd,CMD_APCI3200_ReadCalibrationOffsetValue, &read))
			return -1;

		printf("Analog input offset %i value = %lu \n", read.b_Channel, read.dw_ChannelValue);
		acquisition->dw_ChannelOffsetValue = read.dw_ChannelValue;
	}
	return 0;
}
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_ReadCJCCalibrationGainValue(int fd, struct acquisition_t *acquisition)
{
	struct Read1CJCInputChannel_t read;

	read.dw_TimerReloadValue = acquisition->Frequency;
	read.b_ConvertingTimeUnit = APCI3200_UNIT_HZ;
	read.dw_ChannelValue = 0;		// will be the channel value

	if(verbose) printf("=> CMD_APCI3200_ReadCJCCalibrationGainValue\n");
	{
		if ( call_ioctl (fd,CMD_APCI3200_ReadCJCCalibrationGainValue, &read))
			return -1;

		printf("CJC gain input value = %lu \n", read.dw_ChannelValue);
		acquisition->dw_CJCGainValue = read.dw_ChannelValue;
	}
	return 0;
}
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_ReadCJCCalibrationOffsetValue(int fd, struct acquisition_t *acquisition)
{
	struct Read1CJCInputChannel_t read;

	read.dw_TimerReloadValue = acquisition->Frequency;
	read.b_ConvertingTimeUnit = APCI3200_UNIT_HZ;
	read.dw_ChannelValue = 0;		// will be the channel value

	if(verbose) printf("=> CMD_APCI3200_ReadCJCCalibrationOffsetValue\n");
	{
		if ( call_ioctl (fd,CMD_APCI3200_ReadCJCCalibrationOffsetValue, &read))
			return -1;

		printf("CJC offset input value = %lu \n", read.dw_ChannelValue);
		acquisition->dw_CJCOffsetValue = read.dw_ChannelValue;
	}
	return 0;
}
//--------------------------------------------------------------------------------
int call_CMD_APCI3200_ReadChannelCalibrationValue(int fd, int ch, struct acquisition_t *acquisition)
{
	struct ReadCalibrationValue_t read;

	read.b_Channel = ch;
	read.w_ConnectionType = acquisition->ChannelInit.b_DiffSingSelected;
	read.w_Gain = acquisition->ChannelInit.w_GainSelected;

	// Following variables are used to get driver values
	read.dw_CJCCurrentSource = 0;
	read.dw_ChannelCurrentSource = 0;
	read.dw_ChannelGainFactor = 0;

	if(verbose) printf("=> CMD_APCI3200_ReadChannelCalibrationValue on channel %i\n", read.b_Channel);
	{
		if ( call_ioctl (fd,CMD_APCI3200_ReadChannelCalibrationValue, &read))
			return -1;

		printf("Calibration values on channel %i\n", read.b_Channel);
		printf("CJC current source = %lu\n", read.dw_CJCCurrentSource);
		printf("Channel current source = %lu\n", read.dw_ChannelCurrentSource);
		printf("Channel gain factor = %lu\n", read.dw_ChannelGainFactor);

		acquisition->dw_CJCCurrentSource = read.dw_CJCCurrentSource;
		acquisition->dw_ChannelGainFactor = read.dw_ChannelGainFactor;
		acquisition->dw_ChannelCurrentSource = read.dw_ChannelCurrentSource;
	}
	return 0;
}
//--------------------------------------------------------------------------------
int apci3200_test_read_1_temperature(int fd, int ch)
{
	struct acquisition_t acquisition;

	apci3200_ask_sensortype(ch, &acquisition);
	acquisition.Frequency = apci3200_ask_frequency();

	if(call_CMD_APCI3200_InitAnalogInputChannel(fd, ch, &acquisition))
		return -1;

	// Read 1 analog input channel.
	if( call_CMD_APCI3200_Read1AnalogInputChannel(fd, ch, &acquisition) )
		return -1;

	// If the sensor type is a thermocouple, CJC values have to be read.
	if(acquisition.SensorClass== ADDIDATA_THERMOCOUPLE)
		if( call_CMD_APCI3200_ReadCJCValue(fd, &acquisition) )
			return -1;

	// Read the calibration gain
	if( call_CMD_APCI3200_ReadCalibrationGainValue(fd, ch, &acquisition) )
		return -1;

	// Read the calibration offset
	if( call_CMD_APCI3200_ReadCalibrationOffsetValue(fd, ch, &acquisition) )
		return -1;

	// If the sensor type is a thermocouple, CJC values have to be read.

	if( call_CMD_APCI3200_ReadCJCCalibrationGainValue(fd, &acquisition) )
		return -1;

	// If the sensor type is a thermocouple, CJC values have to be read.
	if( call_CMD_APCI3200_ReadCJCCalibrationOffsetValue(fd, &acquisition) )
		return -1;

	if(call_CMD_APCI3200_ReadChannelCalibrationValue(fd, ch, &acquisition))
		return -1;

	if( call_CMD_APCI3200_ReadReferenceVoltage(fd, ch, &acquisition) )
		return -1;
	{ printf("sensor: "); apci3200_dump_sensor(&acquisition); };
	// Convert in temperature value
	{
		double d_RealValue = 0.0;
		int i_ReturnValue = 0;
		unsigned long pdw_DigitalValue [6];

		pdw_DigitalValue [0] = acquisition.dw_ChannelValue;

		if(acquisition.SensorClass== ADDIDATA_THERMOCOUPLE)
		{
			pdw_DigitalValue [1] = acquisition.dw_CJCValue;
			pdw_DigitalValue [2] = acquisition.dw_ChannelOffsetValue;
			pdw_DigitalValue [3] = acquisition.dw_ChannelGainValue;
			pdw_DigitalValue [4] = acquisition.dw_CJCOffsetValue;
			pdw_DigitalValue [5] = acquisition.dw_CJCGainValue;
		}

		if(acquisition.SensorClass== ADDIDATA_RTD)
		{
			pdw_DigitalValue [1] = acquisition.dw_ChannelOffsetValue;
			pdw_DigitalValue [2] = acquisition.dw_ChannelGainValue;
		}

		// This function is as example.
		// It show how to convert the APCI-3200 digital value
		// in C.
		i_ReturnValue = i_ADDIDATA_ConvertDigitalToRealTemperatureValueWithCorrectionParameters (
				APCI3200_OTHER, /* acquisition type */
				acquisition.SensorClass,
				acquisition.SensorType,
				acquisition.RTDValue,
				acquisition.ChannelInit.b_PolaritySelected,
				acquisition.ChannelInit.w_GainSelected,
				( (double) acquisition.dw_ChannelGainFactor / 1000000.0),
				( (double) acquisition.dw_ChannelCurrentSource / 1000000000.0),
				( (double) acquisition.dw_CJCCurrentSource / 1000000000.0),
				pdw_DigitalValue,
				&d_RealValue,
				( (float) acquisition.dw_ReferenceVoltage/1000.0)
		);

		if (i_ReturnValue != 0)
		{
			printf ("i_ADDIDATA_ConvertDigitalToRealTemperatureValueWithCorrectionParameters error =%i\n", i_ReturnValue);
			exit(1);
		}

		printf ("ch%i Temperature value = %f\n", ch, d_RealValue);
	}
	return 0;
}

//--------------------------------------------------------------------------------
int run_test(int fd)
{
	int channel;

	printf("channel number>");
	channel = get_integer(0,15);

	return apci3200_test_read_1_temperature(fd, channel);
}
//--------------------------------------------------------------------------------
int main(int argc, char** argv)
{
	int * apci3200_card_fd;

	unsigned int apci3200_card_number = 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);
		}
		return run_test(apci3200_card_fd[index]);
	}
	return 0;
}
//--------------------------------------------------------------------------------
