/** @file tempconvert.c

@brief TODO


@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() */
#include <limits.h>
#include <apci3200.h>
#include "convert.h"
#include "findboards.h"
#include "input.h"
#include "errorlib.h"
#include "errormsg.h"

const char *PROGNAME;

/*
 * @param [in]	w_AcquisitionType		Define the acquisition type.<br>
 * 										When not scan mode use APCI3200_OTHER,<br>
 * 										else APCI3200_SCAN.
 * @param [in]	b_InputType				Type of the input (sensor):<br>
 * 										- ADDIDATA_THERMOCOUPLE<br>
 * 										- ADDIDATA_RTD
 * @param [in]	b_TypePrecision			Type of the thermocouple.
 *										Type of Thermocouple:<br>
 *										- ADDIDATA_THERMOCOUPLE_TYPE_B<br>
 *										- ADDIDATA_THERMOCOUPLE_TYPE_E<br>
 *										- ADDIDATA_THERMOCOUPLE_TYPE_J<br>
 *										- ADDIDATA_THERMOCOUPLE_TYPE_K<br>
 *										- ADDIDATA_THERMOCOUPLE_TYPE_N<br>
 *										- ADDIDATA_THERMOCOUPLE_TYPE_R<br>
 *										- ADDIDATA_THERMOCOUPLE_TYPE_S<br>
 *										- ADDIDATA_THERMOCOUPLE_TYPE_T
 * @param [in]	w_InputTypeValue		With thermocouple put 0. With RTD the RTD value.
 * @param [in]	b_PolaritySelected		Connection polarity:<br>
 *										- APCI3200_POLARITY_UNIPOLAR (0 to 2.5 V)<br>
 *										- APCI3200_POLARITY_BIPOLAR (-2.5 to 2.5 V)
 * @param [in]	w_GainSelected			The gain to use:<br>
 *										- APCI3200_GAIN_1<br>
 *										- APCI3200_GAIN_2<br>
 *										- APCI3200_GAIN_4<br>
 *										- APCI3200_GAIN_8<br>
 *										- APCI3200_GAIN_16<br>
 *										- APCI3200_GAIN_32<br>
 *										- APCI3200_GAIN_128
 * @param [in]	d_GainFactorValue		The gain factor that is returned by<br>
 * 										do_CMD_APCI3200_ReadChannelCalibrationValue.
 * 										This value has to be divided per / 1000000.0.
 * @param [in]	d_CurrentSourceValue	The channel current source value that is returned by<br>
 *										do_CMD_APCI3200_ReadChannelCalibrationValue<br>
 *										This value has be divided per / 1000000000.0.
 * @param [in]	d_CurrentSourceCJCValue	The CJC  current source value that is returned by<br>
 *										do_CMD_APCI3200_ReadChannelCalibrationValue<br>
 *										This value has be divided per / 1000000000.0.
 * @param [in]	pdw_DigitalValue		A pointer of an array that will contain:<br>
 *										pdw_DigitalValue [0] The channel value returned by do_CMD_APCI3200_Read1AnalogInputChannel.<br>
 *										pdw_DigitalValue [1] The CJC value returned by do_CMD_APCI3200_ReadCJCValue.<br>
 *										pdw_DigitalValue [2] The channel offset value returned by do_MD_APCI3200_ReadCalibrationOffsetValue.<br>
 *										pdw_DigitalValue [3] The channel gain value returned by do_CMD_APCI3200_ReadCalibrationGainValue.<br>
 *										pdw_DigitalValue [4] The CJC offset value returned by do_CMD_APCI3200_ReadCJCCalibrationOffsetValue.<br>
 *										pdw_DigitalValue [5] The CJC gain value returned by do_CMD_APCI3200_ReadCJCCalibrationGainValue.
 * @param [in]	pd_RealValue			Is a pointer on the temperature value in degree Celsius.
 * @param [in]	d_ReferenceVoltage		Reference voltage as provided by CMD_APCI3200_ReadReferenceVoltage, but converted in Volt (1.25 or 2.5)
 */

struct config_t
{
	unsigned int w_AcquisitionType;
	unsigned char b_InputType;
	unsigned char b_TypePrecision;
	unsigned int w_InputTypeValue;
	unsigned char b_PolaritySelected;
	unsigned int w_GainSelected;
	double d_GainFactorValue;
	double d_CurrentSourceValue;
	double d_CurrentSourceCJCValue;
	unsigned long pdw_DigitalValue[6];
	double d_ReferenceVoltage;
};
//--------------------------------------------------------------------------------
void help(void)
{
	printf("apci3200convert PARAMETERS\n");
	printf("where PARAMETERS are:\n");
	printf("[string] AcquisitionType = OTHER | SCAN\n");
	printf("[string] InputType = THERMOCOUPLE | RTD\n");
	printf("[string] b_TypePrecision| InputType == THERMOCOUPLE = B | E | J | N | R | S | T\n");
	printf("         b_TypePrecision| InputType == RTD = PT | Ni\n");
	printf("[uint8]  InputTypeValue | InputType == THERMOCOUPLE = 0\n");
	printf("         InputTypeValue | InputType == RTD = 100 | 1000\n");
	printf("[string] PolaritySelected = UNIPOLAR | BIPOLAR\n");
	printf("[string] GainSelected = 1 | 2 | 4 | 8 | 16 | 32 | 128\n");
	printf("[uint32] GainFactor (returned by ReadChannelCalibrationValue())\n");
	printf("[uint32] CurrentSourceValue (returned by ReadChannelCalibrationValue())\n");
	printf("[uint32] CurrentSourceCJCValue (returned by ReadChannelCalibrationValue())\n");
	printf("[uint32] AnalogInputChannel (returned by Read1AnalogInputChannel())\n");
	printf("[uint32] CJCValue (returned by ReadCJCValue())");
	printf("[uint32] CalibrationOffset (returned by ReadCalibrationOffsetValue())\n");
	printf("[uint32] CalibrationGain (returned by ReadCalibrationGainValue())\n");
	printf("[uint32] CJCCalibrationOffset (returned by ReadCJCCalibrationOffsetValue())\n");
	printf("[uint32] CJCCalibrationGain (returned by ReadCJCCalibrationGainValue())\n");
	printf("[uint32] d_ReferenceVoltage (returned by ReadReferenceVoltage())\n");
}
//--------------------------------------------------------------------------------
void ABORTPARSE(unsigned int which, const char* what,const char* why)
{
	fprintf(stderr,"argument %d: parse error: %s: %s\n",which-1, what, why);
	abort();
}
//--------------------------------------------------------------------------------
unsigned long parse_longinteger(unsigned int which, const char* what, const char *str, unsigned long min, unsigned long max)
{
	char buff[10];
	char * endptr = NULL;
	int val;

	errno=0;
	val = strtol(buff, &endptr, 10);
	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) { ABORTPARSE(which, what, strerror(errno)); }
	if (endptr == buff) { ABORTPARSE(which, what, "is not a digit"); }
	if ( (val >= min) && (val <= max) ) return val;
	ABORTPARSE(which, what, "value out of range");
	return val;
}
//--------------------------------------------------------------------------------
unsigned char parse_char(unsigned int which, const char* what, const char *str)
{
	return parse_longinteger(which, what, str, 0x0, 0xFF);
}
//--------------------------------------------------------------------------------
unsigned char parse_uint32(unsigned int which, const char* what, const char *str)
{
	return parse_longinteger(which, what, str, 0x0, 0xFFFFFFFF);
}
//--------------------------------------------------------------------------------
const char *UNKNOWNARG="unknown argument";
//--------------------------------------------------------------------------------
/* OTHER | SCAN */
void parse_w_AcquisitionType(int arg, char* argv, struct config_t *config)
{
	if( !strcmp(argv,"OTHER") )
	{
		config->w_AcquisitionType=APCI3200_OTHER;
		return;
	}
	if( !strcmp(argv,"SCAN") )
	{
		config->w_AcquisitionType=APCI3200_SCAN;
		return;
	}
	ABORTPARSE(arg,"AcquisitionType",UNKNOWNARG);
}
//--------------------------------------------------------------------------------
/* THERMOCOUPLE | RTD */
void parse_b_InputType(int arg, char* argv, struct config_t *config)
{
	if( !strcmp(argv,"THERMOCOUPLE") )
	{
		config->b_InputType=ADDIDATA_THERMOCOUPLE;
		return;
	}
	if( !strcmp(argv,"RTD") )
	{
		config->b_InputType=ADDIDATA_RTD;
		return;
	}
	ABORTPARSE(arg,"InputType",UNKNOWNARG);
}
//--------------------------------------------------------------------------------
/* B | E | J | N | R | S | T */
void parse_b_TypePrecision_Thermocouple(int arg, char* argv, struct config_t *config)
{
	if( !strcmp(argv,"B") )
	{
		config->b_TypePrecision=ADDIDATA_THERMOCOUPLE_TYPE_B;
		return;
	}
	if( !strcmp(argv,"E") )
	{
		config->b_TypePrecision=ADDIDATA_THERMOCOUPLE_TYPE_E;
		return;
	}
	if( !strcmp(argv,"J") )
	{
		config->b_TypePrecision=ADDIDATA_THERMOCOUPLE_TYPE_J;
		return;
	}
	if( !strcmp(argv,"K") )
	{
		config->b_TypePrecision=ADDIDATA_THERMOCOUPLE_TYPE_K;
		return;
	}
	if( !strcmp(argv,"N") )
	{
		config->b_TypePrecision=ADDIDATA_THERMOCOUPLE_TYPE_N;
		return;
	}
	if( !strcmp(argv,"R") )
	{
		config->b_TypePrecision=ADDIDATA_THERMOCOUPLE_TYPE_R;
		return;
	}
	if( !strcmp(argv,"S") )
	{
		config->b_TypePrecision=ADDIDATA_THERMOCOUPLE_TYPE_S;
		return;
	}
	if( !strcmp(argv,"T") )
	{
		config->b_TypePrecision=ADDIDATA_THERMOCOUPLE_TYPE_T;
		return;
	}
	ABORTPARSE(arg,"TypePrecision",UNKNOWNARG);
}
//--------------------------------------------------------------------------------
/* PT | Ni */
void parse_b_TypePrecision_RTD(int arg, char* argv, struct config_t *config)
{
	if( !strcmp(argv,"PT") )
	{
		config->b_TypePrecision=ADDIDATA_RTD_TYPE_PT;
		return;
	}
	if( !strcmp(argv,"Ni") )
	{
		config->b_TypePrecision=ADDIDATA_RTD_TYPE_Ni;
		return;
	}
	ABORTPARSE(arg,"TypePrecision",UNKNOWNARG);
}
//--------------------------------------------------------------------------------
void parse_b_TypePrecision(int arg, char* argv, struct config_t *config)
{
	switch(config->b_InputType)
	{
		case ADDIDATA_THERMOCOUPLE:
			parse_b_TypePrecision_Thermocouple(arg, argv, config);
			return;
		case ADDIDATA_RTD:
			parse_b_TypePrecision_RTD(arg, argv, config);
			return;
		default:
			ABORTPARSE(arg,"InputType",UNKNOWNARG);
	}
}
//--------------------------------------------------------------------------------
/* unsigned int With thermocouple put 0. With RTD the RTD value. */
void parse_w_InputTypeValue(int arg, char* argv, struct config_t *config)
{

	config->w_InputTypeValue = parse_longinteger(arg,"InputTypeValue",argv,0x0,0xFFFFFFFF);
	if((config->b_InputType==ADDIDATA_THERMOCOUPLE) && (config->w_InputTypeValue!=0)) ABORTPARSE(arg, "InputTypeValue", "InputTypeValue must be 0 for thermocouple");
	switch(config->w_InputTypeValue)
	{
		case 100:
		case 1000:
			break;
		default:
			ABORTPARSE(arg, "InputTypeValue", "InputTypeValue must be 100 or 1000 for RTD");
	}
}
//--------------------------------------------------------------------------------
/* @param [in]	b_PolaritySelected		Connection polarity:<br>
*										- APCI3200_POLARITY_UNIPOLAR (0 to 2.5 V)<br>
*										- APCI3200_POLARITY_BIPOLAR (-2.5 to 2.5 V)
*/
void parse_b_PolaritySelected(int arg, char* argv, struct config_t *config)
{
	if( !strcmp(argv,"UNIPOLAR") )
	{
		config->b_PolaritySelected=APCI3200_POLARITY_UNIPOLAR;
		return;
	}
	if( !strcmp(argv,"BIPOLAR") )
	{
		config->b_PolaritySelected=APCI3200_POLARITY_BIPOLAR;
		return;
	}
	ABORTPARSE(arg,"PolaritySelected",UNKNOWNARG);
}
//--------------------------------------------------------------------------------
/*  * @param [in]	w_GainSelected			The gain to use:<br>
 *										- APCI3200_GAIN_1<br>
 *										- APCI3200_GAIN_2<br>
 *										- APCI3200_GAIN_4<br>
 *										- APCI3200_GAIN_8<br>
 *										- APCI3200_GAIN_16<br>
 *										- APCI3200_GAIN_32<br>
 *										- APCI3200_GAIN_128
 *										- */
void parse_w_GainSelected(int arg, char* argv, struct config_t *config)
{
	if( !strcmp(argv,"1") )
	{
		config->w_GainSelected=APCI3200_GAIN_1;
		return;
	}
	if( !strcmp(argv,"2") )
	{
		config->w_GainSelected=APCI3200_GAIN_2;
		return;
	}
	if( !strcmp(argv,"4") )
	{
		config->w_GainSelected=APCI3200_GAIN_4;
		return;
	}
	if( !strcmp(argv,"8") )
	{
		config->w_GainSelected=APCI3200_GAIN_8;
		return;
	}
	if( !strcmp(argv,"16") )
	{
		config->w_GainSelected=APCI3200_GAIN_16;
		return;
	}
	if( !strcmp(argv,"32") )
	{
		config->w_GainSelected=APCI3200_GAIN_32;
		return;
	}
	if( !strcmp(argv,"128") )
	{
		config->w_GainSelected=APCI3200_GAIN_128;
		return;
	}
	ABORTPARSE(arg,"GainSelected",UNKNOWNARG);
}
//--------------------------------------------------------------------------------
/*The gain factor that is returned by do_CMD_APCI3200_ReadChannelCalibrationValue.*/
void parse_d_GainFactorValue(int arg, char* argv, struct config_t *config)
{
	config->d_GainFactorValue = (double) parse_uint32(arg, "GainFactorValue", argv);
}
//--------------------------------------------------------------------------------
/*The channel current source value that is returned by<br>
 *										do_CMD_APCI3200_ReadChannelCalibrationValue<br>
 *										This value has be divided per / 1000000000.0.
 */
void parse_d_CurrentSourceValue(int arg, char* argv, struct config_t *config)
{
	config->d_GainFactorValue = (double) parse_uint32(arg, "GainFactorValue", argv);
}
//--------------------------------------------------------------------------------
/*d_CurrentSourceCJCValue	The CJC  current source value that is returned by<br>
 *										do_CMD_APCI3200_ReadChannelCalibrationValue<br>
 *										This value has be divided per / 1000000000.0.
 */
void parse_d_CurrentSourceCJCValue(int arg, char* argv, struct config_t *config)
{
	config->d_CurrentSourceCJCValue = (double) parse_uint32(arg, "CurrentSourceCJCValue", argv);
}
//--------------------------------------------------------------------------------
//The channel value returned by do_CMD_APCI3200_Read1AnalogInputChannel.<br>
void parse_pdw_DigitalValue0(int arg, char* argv, struct config_t *config)
{
	config->pdw_DigitalValue[0] = parse_uint32(arg, "DigitalValue0", argv);
}
//--------------------------------------------------------------------------------
//The CJC value returned by do_CMD_APCI3200_ReadCJCValue.<br>

void parse_pdw_DigitalValue1(int arg, char* argv, struct config_t *config)
{
	config->pdw_DigitalValue[1] = parse_uint32(arg, "DigitalValue1", argv);
}
//--------------------------------------------------------------------------------
//The channel offset value returned by do_MD_APCI3200_ReadCalibrationOffsetValue.<br>

void parse_pdw_DigitalValue2(int arg, char* argv, struct config_t *config)
{
	config->pdw_DigitalValue[2] = parse_uint32(arg, "DigitalValue2", argv);
}
//--------------------------------------------------------------------------------
//The channel gain value returned by do_CMD_APCI3200_ReadCalibrationGainValue.<br>

void parse_pdw_DigitalValue3(int arg, char* argv, struct config_t *config)
{
	config->pdw_DigitalValue[3] = parse_uint32(arg, "DigitalValue3", argv);
}
//--------------------------------------------------------------------------------
//The CJC offset value returned by do_CMD_APCI3200_ReadCJCCalibrationOffsetValue.<br>
void parse_pdw_DigitalValue4(int arg, char* argv, struct config_t *config)
{
	config->pdw_DigitalValue[4] = parse_uint32(arg, "DigitalValue4", argv);
}
//--------------------------------------------------------------------------------
//The CJC gain value returned by do_CMD_APCI3200_ReadCJCCalib
void parse_pdw_DigitalValue5(int arg, char* argv, struct config_t *config)
{
	config->pdw_DigitalValue[5] = parse_uint32(arg, "DigitalValue5", argv);
}
//--------------------------------------------------------------------------------
//Reference voltage as provided by CMD_APCI3200_ReadReferenceVoltage, but converted in Volt (1.25 or 2.5)
void parse_d_ReferenceVoltage(int arg, char* argv, struct config_t *config)
{
	config->d_ReferenceVoltage = (double) parse_uint32(arg, "ReferenceVoltage", argv);
}
//--------------------------------------------------------------------------------
#define NEXTARG (argc++)
//--------------------------------------------------------------------------------
int parse_arg(int argc, char** argv, struct config_t *config)
{
	if(argc==1)
	{
		help();
		exit(0);
	}
	if(argc!=17)
	{
		fprintf(stderr,"%s: not enough argument\n", PROGNAME);
		abort();
	}

	//--------------------------------------------------------------------------------
	NEXTARG;
	parse_w_AcquisitionType(argc,argv[argc],config);
	NEXTARG;
	parse_b_InputType(argc, argv[argc], config);
	NEXTARG;
	parse_b_TypePrecision(argc, argv[argc], config);
	NEXTARG;
	parse_w_InputTypeValue(argc, argv[argc],config);
	NEXTARG;
	parse_b_PolaritySelected(argc, argv[argc], config);
	NEXTARG;
	parse_w_GainSelected(argc, argv[argc], config);
	NEXTARG;
	parse_d_GainFactorValue(argc, argv[argc], config);
	NEXTARG;
	parse_d_CurrentSourceValue(argc, argv[argc], config);
	NEXTARG;
	parse_d_CurrentSourceCJCValue(argc, argv[argc], config);
	NEXTARG;
	parse_pdw_DigitalValue0(argc, argv[argc], config);
	NEXTARG;
	parse_pdw_DigitalValue1(argc, argv[argc], config);
	NEXTARG;
	parse_pdw_DigitalValue2(argc, argv[argc], config);
	NEXTARG;
	parse_pdw_DigitalValue3(argc, argv[argc], config);
	NEXTARG;
	parse_pdw_DigitalValue4(argc, argv[argc], config);
	NEXTARG;
	parse_pdw_DigitalValue5(argc, argv[argc], config);
	NEXTARG;
	parse_d_ReferenceVoltage(argc, argv[argc], config);


	return 0;
}
//--------------------------------------------------------------------------------
int main(int argc, char** argv)
{
	struct config_t config;
	double pd_RealValue = 0;

	memset(&config,0,sizeof(struct config_t));
	PROGNAME=argv[0];

	if ( parse_arg(argc, argv, &config) )
	{
		help();
		exit(1);
	}
	if( i_ADDIDATA_ConvertDigitalToRealTemperatureValueWithCorrectionParameters (
			config.w_AcquisitionType,
			config.b_InputType,
			config.b_TypePrecision,
			config.w_InputTypeValue,
			config.b_PolaritySelected,
			config.w_GainSelected,
			config.d_GainFactorValue / 1000000.0,
			config.d_CurrentSourceValue / 1000000000.0,
			config.d_CurrentSourceCJCValue / 1000000000.0,
			config.pdw_DigitalValue,
			&pd_RealValue,
			config.d_ReferenceVoltage / 1000.0
	) )
		exit(1);
	printf("%f\n",pd_RealValue);
	return 0;
}
//--------------------------------------------------------------------------------
