/*
 * TLGB_Diginout.c
 *
 *  Created on: 11/dic/2015
 *      Author: gozzini.davide
 */

//==============================================================================
// Include files

#include "string.h"
#include "stdlib.h"

#include "drivers/AD7193.h"
#include "drivers/my_interrupt.h"
#include "drivers/my_debug.h"

#include "TLGB/TLGB_BinSearch.h"
#include "TLGB/TLGB_Diginout.h"
#include "TLGB/TLGB_flash.h"

//==============================================================================
// Constants

//==============================================================================
// Types

//==============================================================================
// Static global variables

//==============================================================================
// Static functions

//==============================================================================
// Global variables

S_out out[3] = {0};
S_in in[3] = {0};
S_ValoriIstantanei ValoriIstantanei = {0};
S_IngressiDigitali IngressiDigitali = {0};
S_UsciteDigitali UsciteDigitali = {0};

S_in in_forzati[3] = {0};
S_out out_forzati[3] = {0};

S_in in_visualizzati[3] = {0};

//==============================================================================
// Global functions

void init_ev(void)
{
	memset(&out[0], 0, sizeof(S_out));
	memset(&out[1], 0, sizeof(S_out));
	memset(&out[2], 0, sizeof(S_out));

	Write_Output_Module(1, &out[0]);
	Write_Output_Module(2, &out[1]);
	Write_Output_Module(3, &out[2]);
	return;
}

void leggi_analogiche(void)
{
	if((AD_data_ready[0] == 1) && AD7193_Is_continuous_read())
	{
		//UsciteDigitali.Movimento1Lavoro[0] ^= 1; // usata per analizzare frequenza con oscilloscopio
		//scrivi_uscite();

		AD_data_ready[0] = 0;
		if(AcquisitionManage.AcquisitionMode == Single_ended)
		{
			ValoriIstantanei.ErroreAnalogica[0] = ChannelValues.SingleEndedValue1Err;
			ValoriIstantanei.TensioneAnalogica[0] = ChannelValues.SingleEndedValue1_Tensione;
			ValoriIstantanei.GrandezzaAnalogica[0] = ChannelValues.SingleEndedValue1_Grandezza;
		}
		else
		{
			ValoriIstantanei.ErroreAnalogica[0] = ChannelValues.DifferentialValue1Err;
			ValoriIstantanei.TensioneAnalogica[0] = ChannelValues.DifferentialValue1_Tensione;
			ValoriIstantanei.GrandezzaAnalogica[0] = ChannelValues.DifferentialValue1_Grandezza;
		}
	}

	if((AD_data_ready[1] == 1) && AD7193_Is_continuous_read())
	{
		AD_data_ready[1] = 0;
		if(AcquisitionManage.AcquisitionMode == Single_ended)
		{
			ValoriIstantanei.ErroreAnalogica[1] = ChannelValues.SingleEndedValue2Err;
			ValoriIstantanei.TensioneAnalogica[1] = ChannelValues.SingleEndedValue2_Tensione;
			ValoriIstantanei.GrandezzaAnalogica[1] = ChannelValues.SingleEndedValue2_Grandezza;
		}
		else
		{
			ValoriIstantanei.ErroreAnalogica[1] = ChannelValues.DifferentialValue2Err;
			ValoriIstantanei.TensioneAnalogica[1] = ChannelValues.DifferentialValue2_Tensione;
			ValoriIstantanei.GrandezzaAnalogica[1] = ChannelValues.DifferentialValue2_Grandezza;
		}
	}

	if((AD_data_ready[2] == 1) && AD7193_Is_continuous_read())
	{
		AD_data_ready[2] = 0;
		if(AcquisitionManage.AcquisitionMode == Single_ended)
		{
			ValoriIstantanei.ErroreAnalogica[2] = ChannelValues.SingleEndedValue3Err;
			ValoriIstantanei.TensioneAnalogica[2] = ChannelValues.SingleEndedValue3_Tensione;
			ValoriIstantanei.GrandezzaAnalogica[2] = ChannelValues.SingleEndedValue3_Grandezza;
		}
		else
		{
			ValoriIstantanei.ErroreAnalogica[2] = ChannelValues.DifferentialValue3Err;
			ValoriIstantanei.TensioneAnalogica[2] = ChannelValues.DifferentialValue3_Tensione;
			ValoriIstantanei.GrandezzaAnalogica[2] = ChannelValues.DifferentialValue3_Grandezza;
		}
	}

	if((AD_data_ready[3] == 1) && AD7193_Is_continuous_read())
	{
		AD_data_ready[3] = 0;
		if(AcquisitionManage.AcquisitionMode == Single_ended)
		{
			ValoriIstantanei.ErroreAnalogica[3] = ChannelValues.SingleEndedValue4Err;
			ValoriIstantanei.TensioneAnalogica[3] = ChannelValues.SingleEndedValue4_Tensione;
			ValoriIstantanei.GrandezzaAnalogica[3] = ChannelValues.SingleEndedValue4_Grandezza;
		}
		else
		{
			ValoriIstantanei.ErroreAnalogica[3] = ChannelValues.DifferentialValue4Err;
			ValoriIstantanei.TensioneAnalogica[3] = ChannelValues.DifferentialValue4_Tensione;
			ValoriIstantanei.GrandezzaAnalogica[3] = ChannelValues.DifferentialValue4_Grandezza;
		}
	}
	return;
}

void scrivi_uscite(void)
{
	out[0].out1 = UsciteDigitali.EvRiempimentoPezzoOn[0] ||  out_forzati[0].out1;
	out[0].out2 = UsciteDigitali.EvRiempimentoPezzoOff[0] ||  out_forzati[0].out2;
	out[0].out3 = UsciteDigitali.scorta_3 ||  out_forzati[0].out3;
	out[0].out4 = UsciteDigitali.scorta_4 ||  out_forzati[0].out4;
	out[0].out5 = UsciteDigitali.EvRiempimentoSerbatoioOn[0] ||  out_forzati[0].out5;
	out[0].out6 = UsciteDigitali.EvRiempimentoSerbatoioOff[0] ||  out_forzati[0].out6;
	out[0].out7 = UsciteDigitali.Buono[0] ||  out_forzati[0].out7;
	out[0].out8 = UsciteDigitali.Scarto[0] ||  out_forzati[0].out8;
	out[0].out9 = UsciteDigitali.Anomalia[0] ||  out_forzati[0].out9;
	out[0].out10 = UsciteDigitali.StrumentoPronto ||  out_forzati[0].out10;
	out[0].out11 = UsciteDigitali.CicloInCorso[0] ||  out_forzati[0].out11;
	out[0].out12 = UsciteDigitali.scorta_12 ||  out_forzati[0].out12;
    Write_Output_Module(1, &out[0]);

	out[1].out1 = UsciteDigitali.scorta_13 ||  out_forzati[1].out1;
	out[1].out2 = UsciteDigitali.scorta_14 ||  out_forzati[1].out2;
	out[1].out3 = UsciteDigitali.scorta_15 ||  out_forzati[1].out3;
	out[1].out4 = UsciteDigitali.scorta_16 ||  out_forzati[1].out4;
	out[1].out5 = UsciteDigitali.scorta_17 ||  out_forzati[1].out5;
	out[1].out6 = UsciteDigitali.scorta_18 ||  out_forzati[1].out6;
	out[1].out7 = UsciteDigitali.scorta_19 ||  out_forzati[1].out7;
	out[1].out8 = UsciteDigitali.scorta_20 ||  out_forzati[1].out8;
	out[1].out9 = UsciteDigitali.scorta_21 ||  out_forzati[1].out9;
	out[1].out10 = UsciteDigitali.scorta_22 ||  out_forzati[1].out10;
	out[1].out11 = UsciteDigitali.scorta_23 ||  out_forzati[1].out11;
	out[1].out12 = UsciteDigitali.scorta_24 ||  out_forzati[1].out12;
    Write_Output_Module(2, &out[1]);

	out[2].out1 = UsciteDigitali.scorta_25 ||  out_forzati[2].out1;
	out[2].out2 = UsciteDigitali.scorta_26 ||  out_forzati[2].out2;
	out[2].out3 = UsciteDigitali.scorta_27 ||  out_forzati[2].out3;
	out[2].out4 = UsciteDigitali.scorta_28 ||  out_forzati[2].out4;
	out[2].out5 = UsciteDigitali.scorta_29 ||  out_forzati[2].out5;
	out[2].out6 = UsciteDigitali.scorta_30 ||  out_forzati[2].out6;
	out[2].out7 = UsciteDigitali.scorta_31 ||  out_forzati[2].out7;
	out[2].out8 = UsciteDigitali.scorta_32 ||  out_forzati[2].out8;
	out[2].out9 = UsciteDigitali.scorta_33 ||  out_forzati[2].out9;
	out[2].out10 = UsciteDigitali.scorta_34 ||  out_forzati[2].out10;
	out[2].out11 = UsciteDigitali.scorta_35 ||  out_forzati[2].out11;
	out[2].out12 = UsciteDigitali.scorta_36 ||  out_forzati[2].out12;
    Write_Output_Module(3, &out[2]);

	return;
}

void leggi_ingressi(void)
{
	// non devo fare il read perche' gli ingressi sono in interrupt

	//Read_Input_Module(1, &in[0]);
	IngressiDigitali.InizioProva[0] = in[0].in1 || in_forzati[0].in1;
	IngressiDigitali.StopCiclo[0] = in[0].in2 || in_forzati[0].in2;
	IngressiDigitali.scorta_3 = in[0].in3 || in_forzati[0].in3;
	IngressiDigitali.scorta_4 = in[0].in4 || in_forzati[0].in4;

	//Read_Input_Module(2, &in[1]);
	IngressiDigitali.scorta_5 = in[1].in1 || in_forzati[1].in1;
	IngressiDigitali.scorta_6 = in[1].in2 || in_forzati[1].in2;
	IngressiDigitali.scorta_7 = in[1].in3 || in_forzati[1].in3;
	IngressiDigitali.scorta_8 = in[1].in4 || in_forzati[1].in4;

	//Read_Input_Module(3, &in[2]);
	IngressiDigitali.scorta_9 = in[2].in1 || in_forzati[2].in1;
	IngressiDigitali.scorta_10 = in[2].in2 || in_forzati[2].in2;
	IngressiDigitali.scorta_11 = in[2].in3 || in_forzati[2].in3;
	IngressiDigitali.scorta_12 = in[2].in4 || in_forzati[2].in4;

	in_visualizzati[0].in1 = in[0].in1 || in_forzati[0].in1;
	in_visualizzati[0].in2 = in[0].in2 || in_forzati[0].in2;
	in_visualizzati[0].in3 = in[0].in3 || in_forzati[0].in3;
	in_visualizzati[0].in4 = in[0].in4 || in_forzati[0].in4;
	in_visualizzati[1].in1 = in[1].in1 || in_forzati[1].in1;
	in_visualizzati[1].in2 = in[1].in2 || in_forzati[1].in2;
	in_visualizzati[1].in3 = in[1].in3 || in_forzati[1].in3;
	in_visualizzati[1].in4 = in[1].in4 || in_forzati[1].in4;
	in_visualizzati[2].in1 = in[2].in1 || in_forzati[2].in1;
	in_visualizzati[2].in2 = in[2].in2 || in_forzati[2].in2;
	in_visualizzati[2].in3 = in[2].in3 || in_forzati[2].in3;
	in_visualizzati[2].in4 = in[2].in4 || in_forzati[2].in4;
	return;
}


void ricava_npunti_min_max_ingressi(int can)
{
	int j = {0};
	float ch_min = {0};
	float ch_max = {0};

	adc.Linearizzazione[can].NPuntiAttivi = 1;
	ch_min = adc.Linearizzazione[can].Grandezza[0];
	ch_max = adc.Linearizzazione[can].Grandezza[0];

	for(j = 1; j < sizeof(adc.Linearizzazione[can].Tensione)/sizeof(adc.Linearizzazione[can].Tensione[0]); j++)
	{
		if(adc.Linearizzazione[can].Tensione[j] <= adc.Linearizzazione[can].Tensione[j - 1])
		{
			break;
		}
		else
		{
			adc.Linearizzazione[can].NPuntiAttivi++;

			if(ch_max < adc.Linearizzazione[can].Grandezza[j])
			{
				ch_max = adc.Linearizzazione[can].Grandezza[j];
			}

			if(ch_min > adc.Linearizzazione[can].Grandezza[j])
			{
				ch_min = adc.Linearizzazione[can].Grandezza[j];
			}
		}
	}
	return;
}



/// HIFN Linearizza secondo la tabella inserita i canali analogici.
/// HIFN UTILIZZA LA STRUTTURA GLOBALE trusc[32].
/// HIFN che contiene i valori delle tabelle di conversione,
/// HIFN disposti a coppie: tensione, valore corrispondente
/// HIRET Document return value here.
/// HIRET You may use multiple lines for documentation.
/// HIPAR tensione/tensione letta dal trasduttore quindi num*10/fsnum se disponibile in numeri.
/// HIPAR can/sceglie la tabella del canale corrispondente.
float linearizza_ingressi(float tensione, int can)
{
	int intervallo = {0};
	double x1 = adc.Linearizzazione[can].Tensione[intervallo];
	double x2 = adc.Linearizzazione[can].Tensione[intervallo + 1];
	double y1 = adc.Linearizzazione[can].Grandezza[intervallo];
	double y2 = adc.Linearizzazione[can].Grandezza[intervallo + 1];
	double m  = 0;

	if(x2 == x1) // canale non usato
	{
		return 0.0;
	}
	else // ricava l'intervallo nel quale si trova il valore da convertire
	{
		intervallo = BinSearch (adc.Linearizzazione[can].Tensione, adc.Linearizzazione[can].NPuntiAttivi, sizeof(adc.Linearizzazione[can].Tensione[0]), &tensione, FloatCompare);
	}

	if(intervallo >= 0) // se ho trovato il valore nel punto preciso
	{
		return adc.Linearizzazione[can].Grandezza[intervallo];
	}

	intervallo = abs(intervallo);

	if(intervallo == 1) // se ho trovato che e' il primo negativo
	{
	}
	else if(intervallo > adc.Linearizzazione[can].NPuntiAttivi) // se ho trovato che e' oltre il limite
	{
		intervallo--;
		intervallo--;
	}
	else // se invece ho trovato dove va posizionato
	{
		intervallo--;
	}

	x1 = adc.Linearizzazione[can].Tensione[intervallo - 1];	// tensione
	x2 = adc.Linearizzazione[can].Tensione[intervallo];		// tensione
	y1 = adc.Linearizzazione[can].Grandezza[intervallo - 1];	// grandezza fisica
	y2 = adc.Linearizzazione[can].Grandezza[intervallo];		// grandezza fisica

	// equazione della retta per due punti
	// m = (y2 - y1)/(x2 - x1)
	// y2 = m(x2 - x1) + y1
	m = (y2 - y1) / (x2 - x1);
	return (m * (tensione - x1) + y1);
}


void ricava_npunti_min_max_uscite(int can)
{
	int j = {0};
	float ch_min = {0};
	float ch_max = {0};

	adc.Linearizzazione[can].NPuntiAttivi = 1;
	ch_min = adc.Linearizzazione[can].Grandezza[0];
	ch_max = adc.Linearizzazione[can].Grandezza[0];

	for(j = 1; j < sizeof(adc.Linearizzazione[can].Grandezza)/sizeof(adc.Linearizzazione[can].Grandezza[0]); j++)
	{
		if(adc.Linearizzazione[can].Grandezza[j] <= adc.Linearizzazione[can].Grandezza[j - 1])
		{
			break;
		}
		else
		{
			adc.Linearizzazione[can].NPuntiAttivi++;

			if(ch_max < adc.Linearizzazione[can].Grandezza[j])
			{
				ch_max = adc.Linearizzazione[can].Grandezza[j];
			}

			if(ch_min > adc.Linearizzazione[can].Grandezza[j])
			{
				ch_min = adc.Linearizzazione[can].Grandezza[j];
			}
		}
	}
	return;
}


/// HIFN Linearizza secondo la tabella inserita i canali analogici.
/// HIFN UTILIZZA LA STRUTTURA GLOBALE trusc[32].
/// HIFN che contiene i valori delle tabelle di conversione,
/// HIFN disposti a coppie: tensione, valore corrispondente
/// HIRET Document return value here.
/// HIRET You may use multiple lines for documentation.
/// HIPAR tensione/tensione letta dal trasduttore quindi num*10/fsnum se disponibile in numeri.
/// HIPAR can/sceglie la tabella del canale corrispondente.
float linearizza_uscite(float grandezza, int can)
{
	int intervallo = {0};
	double x1 = adc.Linearizzazione[can].Grandezza[intervallo];
	double x2 = adc.Linearizzazione[can].Grandezza[intervallo + 1];
	double y1 = adc.Linearizzazione[can].Tensione[intervallo];
	double y2 = adc.Linearizzazione[can].Tensione[intervallo + 1];
	double m  = 0;

	if(x2 == x1) // canale non usato
	{
		return 0.0;
	}
	else // ricava l'intervallo nel quale si trova il valore da convertire
	{
		intervallo = BinSearch (adc.Linearizzazione[can].Grandezza, adc.Linearizzazione[can].NPuntiAttivi, sizeof(adc.Linearizzazione[can].Grandezza[0]), &grandezza, FloatCompare);
	}

	if(intervallo >= 0) // se ho trovato il valore nel punto preciso
	{
		return adc.Linearizzazione[can].Tensione[intervallo];
	}

	intervallo = abs(intervallo);

	if(intervallo == 1) // se ho trovato che e' il primo negativo
	{
	}
	else if(intervallo > adc.Linearizzazione[can].NPuntiAttivi) // se ho trovato che e' oltre il limite
	{
		intervallo--;
		intervallo--;
	}
	else // se invece ho trovato dove va posizionato
	{
		intervallo--;
	}

	x1 = adc.Linearizzazione[can].Grandezza[intervallo - 1];	// grandezza fisica
	x2 = adc.Linearizzazione[can].Grandezza[intervallo];		// grandezza fisica
	y1 = adc.Linearizzazione[can].Tensione[intervallo - 1];		// tensione
	y2 = adc.Linearizzazione[can].Tensione[intervallo];			// tensione

	// equazione della retta per due punti
	// m = (y2 - y1)/(x2 - x1)
	// y2 = m(x2 - x1) + y1
	m = (y2 - y1) / (x2 - x1);
	return (m * (grandezza - x1) + y1);
}
