/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
/*
 * ac_bridge.c
 *
 *  Created on: May 27, 2015
 *      Author: a0282860
 */

#include "ac_bridge.h" 									// All other required source files are declared here

//Values used by "g_excitationStatus"
#define EXC_OFF 		0x00
#define EXC_POS 		0x01
#define EXC_NEG 		0x02

#define NumContReadings 16


//File global variables
static char g_excitationStatus	= EXC_OFF;				//Indicates bridge excitation polarity
static char output_mode				= 0;				//Controls output data formatting

//Internal inline function prototypes (not declared in "control.h")
static inline void show_AppMenu(void);
static inline void LoadInitRegSettings(void);
static inline void run_ReadPosCont(void);
static inline void run_ReadChopCont(void);
static inline double get_reference(uint8_t print_output);
static inline double get_temperature(void);
static inline void set_excitation(uint8_t excitation_target);


void run_demo(char c)
{
	int16_t option = (int16_t) c - 48;	//Convert character "c" to a (0 through 9) integer "option"

	if (NULL == c)
		show_AppMenu();					//show application menu

	else if (0 == option)
		LoadInitRegSettings();			//configure register settings

	else if (1 == option)
	{
		get_reference(1);		//read reference voltage and store it for later use
		get_temperature();				//read int temp sensor
	}

	else if (2 == option)				//read pos input 16 times - compute noise
		run_ReadPosCont();

	else if (3 == option)				//read chopped input 16 times - compute noise
		run_ReadChopCont();

	else if (4 == option)
	{
		output_mode = 1;

		get_reference(1);		//read reference voltage and store it for later use
		get_temperature();
		run_ReadPosCont();
		__delay_cycles(SYSFREQ);
		run_ReadChopCont();

		output_mode = 0;
	}

	else
		printError();					//invalid option
}


static inline void show_AppMenu(void)
{
#ifdef CONSOLE_OUTPUT
	strcpy(outString,"\r\nSelect Operation:\r\n");
	print2Console(outString);
	strcpy(outString,"\tz0) Load Initial Register Settings\r\n");
	print2Console(outString);
	strcpy(outString,"\tz1) Read Supply & Reference\r\n");
	print2Console(outString);
	strcpy(outString,"\tz2) Read Bridge (dc excitation)\r\n");
	print2Console(outString);
	strcpy(outString,"\tz3) Read Bridge (ac excitation)\r\n");
	print2Console(outString);
	strcpy(outString,"\tz9) TIPD188 Data Collection Mode\r\n");
	print2Console(outString);
#endif
}


static inline void LoadInitRegSettings(void)
{
	uint8_t AdcRegData[ADS126x_NUM_REG];							//Stores the register read values
	uint8_t WriteRegData[ADS126x_NUM_REG];							//Stores the register write values

	ADS126xReadRegister(ID, ADS126x_NUM_REG, AdcRegData);			//Read ALL registers

	/* Configure Register Settings */
	WriteRegData[ID] = AdcRegData[ID];								//ID
	WriteRegData[POWER] = INTREF;									//POWER (RESET = 0, INTREF = 1)
	WriteRegData[INTERFACE] = STATUS | CRC_ON;						//INTERFACE
	WriteRegData[MODE0] = DELAY_278us;								//MODE0 (Set DELAY)
	WriteRegData[MODE1] = (AdcRegData[MODE1] & FILTER_MASK);		//MODE1
	WriteRegData[MODE2] = (AdcRegData[MODE2] & ~BYPASS) | GAIN_32;	//MODE2 (BYPASS = 0, GAIN = 32 V/V)
	WriteRegData[INPMUX] = MUXP_AIN1 | MUXN_AIN2;					//INPMUX (AINP = AIN1, AINN = AIN2)
	WriteRegData[OFCAL0] = OFCAL0_DEFAULT_VALUE;					//OFCAL0 (reset to default)
	WriteRegData[OFCAL1] = OFCAL1_DEFAULT_VALUE;					//OFCAL1 (reset to default)
	WriteRegData[OFCAL2] = OFCAL2_DEFAULT_VALUE;					//OFCAL2 (reset to default)
	WriteRegData[FSCAL0] = FSCAL0_DEFAULT_VALUE;					//FSCAL0 (reset to default)
	WriteRegData[FSCAL1] = FSCAL1_DEFAULT_VALUE;					//FSCAL1 (reset to default)
	WriteRegData[FSCAL2] = FSCAL2_DEFAULT_VALUE;					//FSCAL2 (reset to default)
	WriteRegData[IDACMUX] = MUX2_NO_CONM | MUX1_AINCOM;				//IDACMUX (IDAC1MUX = AINCOM)
	WriteRegData[IDACMAG] = MAG2_OFF | MAG1_500uA;					//IDACMAG (IDAC1MAG = 500 uA)
	WriteRegData[REFMUX] = RMUXP_AIN0 | RMUXN_AIN3;					//REFMUX (REFP = AIN0, REFN = AIN3)
	WriteRegData[TDACP] = TDACP_DEFAULT_VALUE;						//TDACP (reset to default)
	WriteRegData[TDACN] = TDACN_DEFAULT_VALUE;						//TDACN (reset to default)
	WriteRegData[GPIOCON] = CON6_AIN09 | CON5_AIN08;				//GPIOCON (Enable GPIOs on AIN8 & AIN9)
	WriteRegData[GPIODIR] = GPIOCON_DEFAULT_VALUE;					//GPIODIR (reset to default)
	WriteRegData[GPIODAT] = DAT5_AIN08;								//GPIODAT (Biases bridge with + polarity)
#ifdef ADS1263
	WriteRegData[ADC2CFG] = ADC2CFG_DEFAULT_VALUE;					//ADC2CFG (reset to default)
	WriteRegData[ADC2MUX] = ADC2MUX_DEFAULT_VALUE;					//ADC2MUX (reset to default)
	WriteRegData[ADC2OFC0] = ADC2OFC0_DEFAULT_VALUE;				//ADC2OFC0 (reset to default)
	WriteRegData[ADC2OFC1] = ADC2OFC1_DEFAULT_VALUE;				//ADC2OFC1 (reset to default)
	WriteRegData[ADC2FSC0] = ADC2FSC0_DEFAULT_VALUE;				//ADC2FSC0 (reset to default)
	WriteRegData[ADC2FSC1] = ADC2FSC1_DEFAULT_VALUE;				//ADC2FSC1 (reset to default)
#endif

	ADS126xWriteRegister(ID, ADS126x_NUM_REG, &WriteRegData[0]);	//Write ALL registers

#ifdef CONSOLE_OUTPUT
	show_parms('0');		//read back registers and output to console
#endif
}


static inline void run_ReadPosCont(void)
{
	int32_t AdcOutput[NumContReadings];

	if (EXC_POS != g_excitationStatus)		//Configure Bridge Polarity
	{
		set_excitation(EXC_OFF);
		set_excitation(EXC_POS);
	}

#ifdef CONSOLE_OUTPUT

	strcpy(outString,"SINGLE,");
	print2Console(outString);

#endif

	//Collect 16x data conversions
	set_adc_START(1);
	for(int i = 0; i < NumContReadings; ++i)
	{
		WaitForDRDY();
		AdcOutput[i] = ADS126xReadData(6, 1);
	}
	set_adc_START(0);

#ifdef CONSOLE_OUTPUT

	for(int i = 0; i < NumContReadings; ++i)
	{
			hex2asc(&AdcOutput[i],8,2,tempString,1);
			strcpy(outString, tempString);
			strcat(outString, ",");
			print2Console(outString);
	}

#endif
}



static inline void run_ReadChopCont(void)
{
	int32_t AdcChopOutputP[NumContReadings];
	int32_t AdcChopOutputN[NumContReadings];

	if (EXC_POS != g_excitationStatus)		//Configure "+" Bridge Polarity
	{
		set_excitation(EXC_OFF);
		set_excitation(EXC_POS);
	}

	__delay_cycles(Delay100ms);

#ifdef CONSOLE_OUTPUT

	strcpy(outString,"DOUBLE(+),");
	print2Console(outString);
	PressANYkeytoContinue(0);

#endif

	//Collect 16x data conversions and calculate average
	set_adc_START(1);
	for(int i = 0; i < NumContReadings; ++i)
	{
		WaitForDRDY();
		AdcChopOutputP[i] = ADS126xReadData(6, 1);
	}
	set_adc_START(0);

#ifdef CONSOLE_OUTPUT

	for(int i = 0; i < NumContReadings; ++i)
	{
		hex2asc(&AdcChopOutputP[i],8,2,tempString,1);
		strcpy(outString, tempString);
		strcat(outString, ",");
		print2Console(outString);
	}

#endif

	//Configure "-" Bridge Polarity
	set_excitation(EXC_OFF);
	set_excitation(EXC_NEG);

	__delay_cycles(Delay100ms);

#ifdef CONSOLE_OUTPUT

	strcpy(outString,"DOUBLE(-),");
	print2Console(outString);
	PressANYkeytoContinue(0);

#endif

	//Collect 16x data conversions and calculate average
	set_adc_START(1);
	for(int i = 0; i < NumContReadings; ++i)
	{
		WaitForDRDY();
		AdcChopOutputN[i] = ADS126xReadData(6, 1);
	}
	set_adc_START(0);

#ifdef CONSOLE_OUTPUT

	for(int i = 0; i < NumContReadings; ++i)
	{
		hex2asc(&AdcChopOutputN[i],8,2,tempString,1);
		strcpy(outString, tempString);
		strcat(outString, ",");
		print2Console(outString);
	}

#endif
}


static inline double get_reference(uint8_t print_output)
{
	uint8_t WriteRegData;					//Stores the register write values
	uint8_t AdcRegData[ADS126x_NUM_REG];	//Stores the register read values
	int32_t AdcOutput = 0;
	const uint8_t Gain = 1;

	double VoltageReading;
	const double IntRefVolt = 2.49906;
	static double SupplyRefVolt = 5;
	static double ExtRefVolt = 5;

	//Read ALL registers
	ADS126xReadRegister(ID, ADS126x_NUM_REG, AdcRegData);

	//MODE0 (CHOP OFF)
	WriteRegData = (AdcRegData[MODE0] & DELAY_MASK);
	ADS126xWriteRegister(MODE0, 1, &WriteRegData);

	//MODE2 (BYPASS OFF, GAIN = 1 V/V)
	WriteRegData = (AdcRegData[MODE2] & DR_MASK);
	ADS126xWriteRegister(MODE2, 1, &WriteRegData);

	//Reset OFCAL coefficients
	WriteRegData = 0x00;
	ADS126xWriteRegister(OFCAL2, 1, &WriteRegData);		//OFCAL2 = 0x00
	WriteRegData = 0x00;
	ADS126xWriteRegister(OFCAL1, 1, &WriteRegData);		//OFCAL1 = 0x00
	WriteRegData = 0x00;
	ADS126xWriteRegister(OFCAL0, 1, &WriteRegData);		//OFCAL0 = 0x00

	//Reset FSCAL coefficients
	WriteRegData = 0x40;
	ADS126xWriteRegister(FSCAL2, 1, &WriteRegData);		//FSCAL2 = 0x40
	WriteRegData = 0x00;
	ADS126xWriteRegister(FSCAL1, 1, &WriteRegData);		//FSCAL1 = 0x00
	WriteRegData = 0x00;
	ADS126xWriteRegister(FSCAL0, 1, &WriteRegData);		//FSCAL0 = 0x00

	//INPMUX (AINP = AIN0, AINN = AIN3)
	WriteRegData = MUXP_AVDD | MUXN_AVSS;
	ADS126xWriteRegister(INPMUX, 1, &WriteRegData);

	//REFMUX
	WriteRegData = RMUXP_INTP | RMUXN_INTN;
	ADS126xWriteRegister(REFMUX, 1, &WriteRegData);

	//Read one conversion
	set_adc_START(1);
	WaitForDRDY();
	set_adc_START(0);
	AdcOutput = ADS126xReadData(6, 1);

	VoltageReading = (double) AdcOutput * IntRefVolt / ((double) Gain * exp2(29)); //2^29 to account for 1/4 supply & 1/2 FSR
	SupplyRefVolt = VoltageReading; //VREF = previous supply reading

#ifdef CONSOLE_OUTPUT
	if(output_mode)
	{
		sprintf(tempString, "\r\n%f,", VoltageReading);
		strcpy(outString, tempString);
		print2Console(outString);
	}

	else if(print_output)
	{
		strcpy(outString, "Supply Reading = 0x");
		hex2asc(&AdcOutput, 8, 2, tempString,1);
		strcat(outString, tempString);
		sprintf(tempString, " = %f V\r\n", VoltageReading);
		strcat(outString, tempString);
		print2Console(outString);
	}
#endif

	//INPMUX (AINP = AIN0, AINN = AIN3)
	WriteRegData = MUXP_AIN0 | MUXN_AIN3;
	ADS126xWriteRegister(INPMUX, 1, &WriteRegData);

	//REFMUX
	WriteRegData = RMUXP_AVDD | RMUXN_AVSS;
	ADS126xWriteRegister(REFMUX, 1, &WriteRegData);

	//Read one conversion
	set_adc_START(1);
	WaitForDRDY();
	set_adc_START(0);
	AdcOutput = ADS126xReadData(6, 1);

	VoltageReading = (double) AdcOutput * SupplyRefVolt / ((double) Gain * exp2(31));


	ExtRefVolt = VoltageReading; //VREF = Ext IntRefVolt, for bridge readings

#ifdef CONSOLE_OUTPUT
	if(!output_mode)
	{

		if(print_output)
		{
			strcpy(outString, "Reference Reading = 0x");
			hex2asc(&AdcOutput, 8, 2, tempString,1);
			strcat(outString, tempString);
			sprintf(tempString, " = %f V\r\n", VoltageReading);
			strcat(outString, tempString);
			print2Console(outString);
		}
	}
#endif

	//Restore Register Settings
	ADS126xWriteRegister(OFCAL0, 1, &AdcRegData[OFCAL0]);
	ADS126xWriteRegister(OFCAL1, 1, &AdcRegData[OFCAL1]);
	ADS126xWriteRegister(OFCAL2, 1, &AdcRegData[OFCAL2]);
	ADS126xWriteRegister(FSCAL0, 1, &AdcRegData[FSCAL0]);
	ADS126xWriteRegister(FSCAL1, 1, &AdcRegData[FSCAL1]);
	ADS126xWriteRegister(FSCAL2, 1, &AdcRegData[FSCAL2]);
	ADS126xWriteRegister(INPMUX, 1, &AdcRegData[INPMUX]);
	ADS126xWriteRegister(REFMUX, 1, &AdcRegData[REFMUX]);
	ADS126xWriteRegister(MODE2,  1, &AdcRegData[MODE2]) ;
	ADS126xWriteRegister(MODE0,  1, &AdcRegData[MODE0]) ;

	return ExtRefVolt;
}


static inline double get_temperature(void)
{
	uint8_t WriteRegData;					//Stores the register write values
	uint8_t AdcRegData[ADS126x_NUM_REG];	//Stores the register read values
	int32_t AdcOutput = 0;
	const char deg_char[3] = {176,'C','\0'};

	double TempReading;

	//Read ALL registers
	ADS126xReadRegister(ID, ADS126x_NUM_REG, AdcRegData);

	//MODE0 (CHOP OFF)
	WriteRegData = (AdcRegData[MODE0] & DELAY_MASK);
	ADS126xWriteRegister(MODE0, 1, &WriteRegData);

	//MODE2 (BYPASS OFF, GAIN = 1 V/V)
	WriteRegData = (AdcRegData[MODE2] & DR_MASK);
	ADS126xWriteRegister(MODE2, 1, &WriteRegData);

	//Reset OFCAL coefficients
	WriteRegData = 0x00;
	ADS126xWriteRegister(OFCAL2, 1, &WriteRegData);		//OFCAL2 = 0x00
	WriteRegData = 0x00;
	ADS126xWriteRegister(OFCAL1, 1, &WriteRegData);		//OFCAL1 = 0x00
	WriteRegData = 0x00;
	ADS126xWriteRegister(OFCAL0, 1, &WriteRegData);		//OFCAL0 = 0x00

	//Reset FSCAL coefficients
	WriteRegData = 0x40;
	ADS126xWriteRegister(FSCAL2, 1, &WriteRegData);		//FSCAL2 = 0x40
	WriteRegData = 0x00;
	ADS126xWriteRegister(FSCAL1, 1, &WriteRegData);		//FSCAL1 = 0x00
	WriteRegData = 0x00;
	ADS126xWriteRegister(FSCAL0, 1, &WriteRegData);		//FSCAL0 = 0x00

	//INPMUX (AINP = Temp, AINN = Temp)
	WriteRegData = MUXP_TEMP | MUXN_TEMP;
	ADS126xWriteRegister(INPMUX, 1, &WriteRegData);

	//REFMUX
	WriteRegData = RMUXP_INTP | RMUXN_INTN;
	ADS126xWriteRegister(REFMUX, 1, &WriteRegData);

	//Read one conversion
	set_adc_START(1);
	WaitForDRDY();
	AdcOutput = ADS126xReadData(6, 1);
	set_adc_START(0);

	TempReading = (double) 25 + ((((double) AdcOutput * (double) 0.00116415321) - (double) 122400) / (double) 420);

#ifdef CONSOLE_OUTPUT
	if(output_mode)
	{
		sprintf(tempString, "%.2f,", TempReading);
		strcpy(outString, tempString);
		print2Console(outString);
	}
	else
	{
		strcpy(outString, "Temperature Reading = 0x");
		hex2asc(&AdcOutput, 8, 2, tempString,1);
		strcat(outString, tempString);
		sprintf(tempString, " = %.2f", TempReading);
		strcat(outString, tempString);
		strcat(outString, deg_char);
		strcat(outString, "\r\n");
		print2Console(outString);
	}
#endif

	//Restore Register Settings
	ADS126xWriteRegister(OFCAL0, 1, &AdcRegData[OFCAL0]);
	ADS126xWriteRegister(OFCAL1, 1, &AdcRegData[OFCAL1]);
	ADS126xWriteRegister(OFCAL2, 1, &AdcRegData[OFCAL2]);
	ADS126xWriteRegister(FSCAL0, 1, &AdcRegData[FSCAL0]);
	ADS126xWriteRegister(FSCAL1, 1, &AdcRegData[FSCAL1]);
	ADS126xWriteRegister(FSCAL2, 1, &AdcRegData[FSCAL2]);
	ADS126xWriteRegister(INPMUX, 1, &AdcRegData[INPMUX]);
	ADS126xWriteRegister(REFMUX, 1, &AdcRegData[REFMUX]);
	ADS126xWriteRegister(MODE2,  1, &AdcRegData[MODE2]) ;
	ADS126xWriteRegister(MODE0,  1, &AdcRegData[MODE0]) ;

	return TempReading;
}



#ifdef CONSOLE_OUTPUT
	void set_exc(char p1, char p2)
	{
		char temp_str[2] = {p2, '\0'};
		char exponent = strtoul(temp_str, NULL, 16);

		if (NULL == p1)
		{
			strcpy(outString, "AC Excitation = ");
			switch(g_excitationStatus)
			{
			case (EXC_OFF):
				strcat(outString, "OFF\r\n");
				break;
			case (EXC_POS):
				strcat(outString, "Positive\r\n");
				break;
			case (EXC_NEG):
				strcat(outString, "Negative\r\n");
				break;
			}
			print2Console(outString);
		}
		else
		{
			switch (p1)
			{

				case '0':
					set_excitation(EXC_OFF);
					break;

				case '1':
					set_excitation(EXC_POS);
					break;

				case '2':
					set_excitation(EXC_NEG);
					break;

				default:
					printError();
					break;
			}
		}
	}
#endif

static inline void set_excitation(uint8_t excitation_target)
{
	uint8_t RegData = 0x00;

	switch(excitation_target)
	{

	case EXC_OFF:			//Turn OFF Bridge Excitation
		//GPIODAT
		RegData = 0x00;
		ADS126xWriteRegister(GPIODAT, 1, &RegData);

		g_excitationStatus = EXC_OFF;
		break;

	case EXC_POS:			//Turn On Bridge Excitation (+ Polarity)
		//GPIOCON
		ADS126xReadRegister(GPIOCON, 1, &RegData);
		RegData |= CON5_AIN08;
		ADS126xWriteRegister(GPIOCON, 1, &RegData);

		//GPIODAT
		RegData = DAT5_AIN08; //set bit 5, AIN08
		ADS126xWriteRegister(GPIODAT, 1, &RegData);

		//MODE0
		ADS126xReadRegister(MODE0, 1, &RegData);
		RegData &= ~REFREV;
		ADS126xWriteRegister(MODE0, 1, &RegData);

		g_excitationStatus = EXC_POS;
		break;

	case EXC_NEG:			//Turn On Bridge Excitation (- Polarity)
		//GPIOCON
		ADS126xReadRegister(GPIOCON, 1, &RegData);
		RegData |= CON6_AIN09;
		ADS126xWriteRegister(GPIOCON, 1, &RegData);

		//GPIODAT
		RegData = DAT6_AIN09; //set bit 6, AIN09
		ADS126xWriteRegister(GPIODAT, 1, &RegData);

		//MODE0
		ADS126xReadRegister(MODE0, 1, &RegData);
		RegData |= REFREV;
		ADS126xWriteRegister(MODE0, 1, &RegData);

		g_excitationStatus = EXC_NEG;
		break;

	default:
		printError();
		break;
	}
}
