//----------------------------------------------------
/**
	\file		ctk/hw/ads131e08.h
	\ingroup	hardware
	\ingroup	all

	\brief		Ovladac obvodu ADS131E08
				<<< ALL >>>

	\author		ConTeK s.r.o., Stanek Jan
	\version	01.10
	\date		19.04.2013
*/
//----------------------------------------------------
#ifndef _ADS131E08_H_
#define _ADS131E08_H_		//!< Definice pritomnosti knihovny

#include <hwsubmdl.h>
#include <spi.h>
#include <ctktypes.h>
#include <iolib.h>
#include "stmachine.h"

//----------------------------------------------------
//!	\name	ADS IO Channel definition
//@{
#define ADS_DINP_COUNT		8	//!< Pocet dig. vstupu 4 + 4 rezerva  
#define ADS_DOUTP_COUNT 	8	//!< Pocet dig. vystupu 4 + 4 rezerva
#define ADS_AINP_COUNT	 	8	//!< Pocet analogovych vstupu
#define ADS_AOUTP_COUNT 	0	//!< Pocet analogovych vystupu

#define _AD_AI_CH1		0		//!< AInp CH1 addr offset
#define _AD_AI_CH2		1		//!< AInp CH2 addr offset
#define _AD_AI_CH3		2		//!< AInp CH3 addr offset
#define _AD_AI_CH4		3		//!< AInp CH4 addr offset
#define _AD_AI_CH5		4		//!< AInp CH5 addr offset
#define _AD_AI_CH6		5		//!< AInp CH6 addr offset
#define _AD_AI_CH7		6		//!< AInp CH7 addr offset
#define _AD_AI_CH8		7		//!< AInp CH8 addr offset

#define _AD_DIO_1		0		//!< DIO CH1 addr offset
#define _AD_DIO_2		1		//!< DIO CH2 addr offset
#define _AD_DIO_3		2		//!< DIO CH3 addr offset
#define _AD_DIO_4		3		//!< DIO CH4 addr offset
//@}

//----------------------------------------------------
//!	\name	ADS memory map
//@{
//device
#define ADS_REG_ADR_ID			0x00
//global settings
#define ADS_REG_ADR_CONFIG1		0x01
#define ADS_REG_ADR_CONFIG2		0x02
#define ADS_REG_ADR_CONFIG3		0x03
#define ADS_REG_ADR_FAULT		0x04
//channel-specific settings
#define ADS_REG_CHANNEL_OFFSET	0x05
 #define	ADS_ADR_CH1SET		0
 #define	ADS_ADR_CH2SET		1
 #define	ADS_ADR_CH3SET		2
 #define	ADS_ADR_CH4SET		3
 #define	ADS_ADR_CH5SET		4
 #define	ADS_ADR_CH6SET		5
 #define	ADS_ADR_CH7SET		6
 #define	ADS_ADR_CH8SET		7
//fault detect
#define	ADS_REG_ADR_FAULT_STATP		0x12	//18
#define ADS_REG_ADR_FAULT_STATN		0x13	//19
//gpio
#define	ADS_REG_ADR_GPIO	0x14	//20
//@}


//----------------------------------------------------
//!	\name	ADS SPI commands
//@{
//system
#define ADS_CMD_WAKEUP		0x02	//!< Wake-up from standby mode
#define ADS_CMD_STANDBY		0x04	//!< Enter standby mode
#define ADS_CMD_RESET		0x06	//!< Reset the device
#define ADS_CMD_START		0x08	//!< Start or restart (synchronize) conversions
#define ADS_CMD_STOP		0x0A	//!< Stop conversion
#define ADS_CMD_OFFSETCAL	0x1A	//!< Channel offset calibration

//data read
#define ADS_CMD_RDATAC	0x10	//!< Enable Read Data Continuous mode
#define ADS_CMD_SDATAC	0x11	//!< Stop Read Data Continuous mode
#define ADS_CMD_RDATA	0x12	//!< Read data by command

//register read
#define ADS_CMD_RREG	0x20	//!< Read n nnnn registers starting at address r rrrr
#define ADS_CMD_WREG	0x40	//!< Write n nnnn registers starting at address r rrrr
//@}


//----------------------------------------------------
//!	\name	ADS conversion constants definition
//@{
#define VREF_16_POS		0x7FFF		//!< 16 bit resolution VREF+ constant
#define VREF_16_NEG		0x8000		//!< 16 bit resolution VREF- constant
#define VREF_24_POS		0x7FFFFF	//!< 24 bit resolution VREF+ constant
#define VREF_24_NEG		0x800000	//!< 24 bit resolution VREF- constant
//@}

//----------------------------------------------------
/**
	\brief	Funkce prepocita vstupni hodnotu na procenta reference
	\note	Pouziti pro rozliseni 16bitu
	\param	_aInpVal	Hodnota ctena z prevodniku
	\return Hodnota v rozsahu <-1,1>, ktera odpovida <-VREF,+VREF>
*/
//----------------------------------------------------
inline percent_t Ads131GetPercentValue16(uint16_t _aInpVal)
{
	float_t retval = (float_t)((int16_t)_aInpVal);
	return retval/VREF_16_POS;
}

//----------------------------------------------------
/**
	\brief	Funkce prepocita vstupni hodnotu na procenta reference
	\note	Pouziti pro rozliseni 24bitu
	\param	_aInpVal	Hodnota ctena z prevodniku
	\return Hodnota v rozsahu <-1,1>, ktera odpovida <-VREF,+VREF>
*/
//----------------------------------------------------
inline percent_t Ads131GetPercentValue24(uint32_t _aInpVal)
{
	if(_aInpVal > VREF_24_NEG)
	{
		//zaporne cislo, doplnime prazdna mista jednickami
		_aInpVal |= 0xFF000000;
	}
	float_t retval = (float_t)((int32_t)_aInpVal);
	return retval/VREF_24_POS;
}

//----------------------------------------------------
//!	\name	Konstanty pro konfiguraci prevodniku
//@{
typedef enum _ADS_CFG1_DR{		//!<	Nastaveni datarate a rozliseni
	DATARATE_64K	= 0,		//!<	64Ks , 16 bit
	DATARATE_32K	= 1,		//!<	32Ks , 16 bit, default
	DATARATE_16K	= 2,		//!<	16Ks , 24 bit
	DATARATE_8K		= 3,		//!<	 8Ks , 24 bit
	DATARATE_4K		= 4,		//!<	 4Ks , 24 bit
	DATARATE_2K		= 5,		//!<	 2Ks , 24 bit
	DATARATE_1K		= 6			//!<	 1Ks , 24 bit
}ADS_CFG1_DR;

typedef enum _ADS_CFG1_CLKOUT{	//!< Pripojeni hodin na vystupni pin CLK
	CLKOUT_DISABLE	= 0,		//!< Vnitrni oscilator nevyveden
	CLKOUT_ENABLE	= 1			//!< Vnitrni oscilator vyveden pokud pin CLKSEL = 1
}ADS_CFG1_CLKOUT;

typedef enum _ADS_CFG1_MODE{	//!< Volba spi rezimu
	SPI_MODE_DAISY		= 0,	//!< Spi v rezimu "Daisy-chain"
	SPI_MODE_READ_BACK	= 1		//!< Spi v standardnim rezimu
}ADS_CFG1_MODE;

typedef enum _ADS_CFG2_FREQ{	//!< Frekvence vnitrniho testovaciho signalu
	TEST_FREQ_DIV21	= 0,		//!< fclk/2^21
	TEST_FREQ_DIV20	= 1,		//!< fclk/2^20
	TEST_FREQ_DC	= 3,		//!< At DC
}ADS_CFG2_FREQ;

typedef enum _ADS_CFG2_AMP{		//!< Amplituda vnitrniho testovaciho signalu
	TEST_AMP_MUL1 = 0,			//!< Default
	TEST_AMP_MUL2 = 1			//!< Default x2
}ADS_CFG2_AMP;

typedef enum _ADS_CFG2_SRC{		//!< Volba zdroje pro testovaci signal
	TEST_SRC_EXTERNAL = 0,		//!< Test signal z externiho zdroje
	TEST_SRC_INTERNAL = 1		//!< Test signal generovan interne
}ADS_CFG2_SRC;

typedef enum _ADS_CFG3_AMPREF{	//!< Volba propojeni neinvertujiciho vstupu OPAMP
	OPAMP_REF_EXT_PIN		= 0,//!< Vstup pripojen na OPAMPP pin
	OPAMP_REF_INT_SUPPLY	= 1	//!< Vstup pripojen k vnitrni referenci (AVDD + AVSS)/2
}ADS_CFG3_AMPREF;

typedef enum _ADS_CFG3_AMPEN{	//!< Povoleni vnitrniho OPAMP
	OPAMP_DISABLE	= 0,		//!< Napajeni OPAMP vypnuto
	OPAMP_ENABLE	= 1			//!< Napajeni OPAMP zapnuto
}ADS_CFG3_AMPEN;

typedef enum _ADS_CFG3_BUFEN{	//!< Povoleni vnitrni napetove reference
	VREF_INTERNAL_DISABLE	= 0,//!< Napetova reference rizena externim pinem
	VREF_INTERNAL_ENABLE	= 1	//!< Externi pin rizen vnitrni referenci
}ADS_CFG3_BUFEN;

typedef enum _ADS_CFG3_VREFP{	//!< Volba referencniho napeti prevodniku
	VREFP_2V4 = 0,				//!< Referencni napeti 2.4V
	VREFP_4V  = 1				//!< Referencni napeti 4V, pouze pro 5V napajeni
}ADS_CFG3_VREFP;

typedef enum _ADS_FAULT_TH{		//!< Nastaveni limitu pro hlaseni chyby
	FAULT_TH_05 = 0,			//!<  5%   od dosazeni VREF+-
	FAULT_TH_07 = 1,			//!<  7,5% od dosazeni VREF+-
	FAULT_TH_10 = 2,			//!< 10%   od dosazeni VREF+-
	FAULT_TH_12 = 3,			//!< 12,5% od dosazeni VREF+-
	FAULT_TH_15 = 4,			//!< 15%   od dosazeni VREF+-
	FAULT_TH_20 = 5,			//!< 20%   od dosazeni VREF+-
	FAULT_TH_25 = 6,			//!< 25%   od dosazeni VREF+-
	FAULT_TH_30 = 7,			//!< 30%   od dosazeni VREF+-
}ADS_FAULT_TH;

typedef enum _ADS_CH_MUX{		//!< Vyber vstupniho signalu pro dany kanal
	CH_MUX_NORMAL	= 0,		//!< Vstupni signal (Normal operation)
	CH_MUX_SHORTED	= 1,		//!< Vstup nakratko (mereni offsetu & sumu)
	CH_MUX_MVDD		= 3,		//!< Napajeci napeti
	CH_MUX_TEMP		= 4,		//!< Teplotni sensor
	CH_MUX_TEST		= 5			//!< Testovaci signal
}ADS_CH_MUX;

typedef enum _ADS_CH_GAIN{		//!< Nastaveni vnitrniho zesileni pro dany kanal
	CH_GAIN_1  = 1,				//!< Gain = 1
	CH_GAIN_2  = 2,				//!< Gain = 2
	CH_GAIN_4  = 4,				//!< Gain = 4
	CH_GAIN_8  = 5,				//!< Gain = 8
	CH_GAIN_12 = 6				//!< Gain = 12
}ADS_CH_GAIN;

typedef enum _ADS_CH_CMD{		//!< Povoleni prevodu pro dany kanal
	CH_PWR_ENABLE	= 0,		//!< Prevod povolen, kanal aktivni
	CH_PWR_DISABLE	= 1			//!< Prevod zakazan
}ADS_CH_CMD;
//@}


//----------------------------------------------------
//!	\name	Konstanty ID
//@{
#define ADS_ID_FAMILY_E08	(0x06 << 5)	//!< Family ID
#define ADS_ID_FAMILY_MASK	(0x07 << 5)

#define ADS_CH_CNT_4		0x00		//!< Zarizeni obsahuje 4 AD kanaly
#define ADS_CH_CNT_6		0x01		//!< Zarizeni obsahuje 6 AD kanalu
#define ADS_CH_CNT_8		0x02		//!< Zarizeni obsahuje 8 AD kanalu
#define ADS_CH_CNT_MASK		0x03
//@}

//----------------------------------------------------
//!	\name	Obsah konfiguracnich a stavovych registru
//@{
#define ADS_CFG1_BASE	0x90			//!< Nuceny stav nepouzitych bitu
typedef struct _ADS_CFG1_REG			//!< Obsah registru CONFIG1
{
	ADS_CFG1_DR		data_rate	:3;		//!< Vzorkovaci kmitocet
	uint8_t						:2;
	ADS_CFG1_CLKOUT	clk_en		:1;		//!< Oscillator clk output enable
	ADS_CFG1_MODE	daisy_in	:1;		//!< Daisy-chain mode / Multiple read-back mode
	uint8_t						:1;
} __attribute__((packed)) ADS_CFG1_REG;

#define ADS_CFG2_BASE	0xE0			//!< Nuceny stav nepouzitych bitu
typedef struct _ADS_CFG2_REG			//!< Obsah registru CONFIG2
{
	ADS_CFG2_FREQ	frequency	:2;		//!< Frekvence testovaciho signalu
	ADS_CFG2_AMP	amplitude	:1;		//!< Amplituda testovaciho signalu
	uint8_t						:1;
	ADS_CFG2_SRC	source		:1;		//!< Zdroj testovaciho signalu int/ext
	uint8_t 					:3;
} __attribute__((packed)) ADS_CFG2_REG;

#define ADS_CFG3_BASE	0x40			//!< Nuceny stav nepouzitych bitu
typedef struct _ADS_CFG3_REG			//!< Obsah registru CONFIG3
{
	uint8_t						:2;
	ADS_CFG3_AMPEN	pdb_opamp	:1;		//!< Povoleni napajeni pro OPAMP
	ADS_CFG3_AMPREF	opamp_ref	:1;		//!< Volba zapojeni vstupu OPAMP
	uint8_t						:1;
	ADS_CFG3_VREFP	vref_4V		:1;		//!< Volba napetove reference, 4V pouze s 5V napajenim
	uint8_t						:1;
	ADS_CFG3_BUFEN	pdb_refbuf	:1;		//!< Povoleni vnitrni napetove reference
} __attribute__((packed)) ADS_CFG3_REG;

typedef struct _ADS_FAULT_REG			//!< Obsah konfiguracniho registru chyb
{
	uint8_t						:5;
	ADS_FAULT_TH	comp_TH		:3;		//!< Nastaveni prahovych napeti pro hlaseni chyb
} __attribute__((packed)) ADS_FAULT_REG;

typedef struct _ADS_CHN_REG				//!< Obsah konfiguracniho registru pro AD kanal
{
	ADS_CH_MUX	MUX			:3;			//!< Vyber zdroje signalu
	uint8_t					:1;
	ADS_CH_GAIN	gain		:3;			//!< Nastaveni zesileni
	ADS_CH_CMD	powerDown	:1;			//!< Povoleni napajeciho napeti
} __attribute__((packed)) ADS_CHN_REG;

typedef struct _ADS_FAULT_STAT_REG		//!< Registr hlaseni chyb
{
	uint8_t		input1	:1;				//!< Prekrocen limit napeti na kanalu 1
	uint8_t		input2	:1;				//!< Prekrocen limit napeti na kanalu 2
	uint8_t		input3	:1;				//!< Prekrocen limit napeti na kanalu 3
	uint8_t		input4	:1;				//!< Prekrocen limit napeti na kanalu 4
	uint8_t		input5	:1;				//!< Prekrocen limit napeti na kanalu 5
	uint8_t		input6	:1;				//!< Prekrocen limit napeti na kanalu 6
	uint8_t		input7	:1;				//!< Prekrocen limit napeti na kanalu 7
	uint8_t 	input8	:1;				//!< Prekrocen limit napeti na kanalu 8
} __attribute__((packed)) ADS_FAULT_STAT_REG;

typedef struct _ADS_GPIO_REG			//!< Obsah registru obsluhy GPIO
{
	uint8_t		ctrl	:4;				//!< Konfigurace GPIO pinu
	uint8_t		data	:4;				//!< Logicka uroven GPIO pinu
} __attribute__((packed)) ADS__REG;
//@}



//----------------------------------------------------
/**
	\brief	Kontext obsluhy AD prevodniku ADS131
*/
//----------------------------------------------------
typedef struct _ADS131_CTX
{
	IODEVICE	Device;				//!< Rodic IO zarizeni
	bool_t		IO_ready;			//!< Priznak probehle inicializace

	ADS_CFG1_REG config;			//!< Nastavena rychlost a delka slova
	ADS_CFG2_REG test;				//!< Nastaveni testovaciho signalu
	ADS_CFG3_REG opAmp_ref;			//!< Nastaveni napetove reference a operacniho zesilovace

	uint8_t		deviceID;			//!< Pridelene cislo, identifikace na desce

	struct
	{
		ADS_FAULT_STAT_REG 	statP;	//!< Registr hlaseni chyb, prekroceni nastaveneho maxima
		ADS_FAULT_STAT_REG 	statN;	//!< Registr hlaseni chyb, prekroceni nastaveneho minima
		ADS_FAULT_TH	 treshold;	//!< Obsah konfiguracniho registru, nastaveni limit
	} __attribute__((packed)) fault;

	struct
	{
		uint8_t	dataOut;			//!< Hodnota vystupnich GPIO pinu
		uint8_t	dataIn;				//!< Logicka uroven GPIO pinu
		uint8_t	output_en;			//!< Nastaveni GPIO pinu jako vstup/vystup
	} gpio;

	struct
	{
		uint8_t		data[8*3 + 3];	//!< Pamet pro cteni SPI transakci (a zapis konfiguracniho bloku)
		uint8_t		chnCount;		//!< Pocet kanalu zarizeni (podle produktove rady 4,6 nebo 8)
		uint8_t		chnSize;		//!< Pocet bytu podle rozliseni prevodu (24bit/16bit)
		uint8_t		cmd[3];			//!< Prikaz zasilany po spi
		uint8_t		adsHWID;		//!< Identifikace produktove rady
	} spiExchange;

	STMACHINE		Stm;			//!< Stavovy automat obsluhy

	SPIDESC	*   	Spi;			//!< Kontext pouzivaneho spi
	uint8_t			SpiChannel;		//!< Kanal pouzivaneho SPI
	volatile bool_t SpiReady;		//!< Priznak volneho kanalu spi

	volatile bool_t	flRunning;		//!< Priznak inicializace

} ADS131_CTX;


#ifdef USEHW_ADS131_DAISY
//----------------------------------------------------
/**
	\brief	Nadrazena struktura pro komunikaci typu Daisy-chain
	\note	Neuvazuje se
	\todo
*/
//----------------------------------------------------
typedef struct _ADS131_DAISY_CTX
{
	ADS131_CTX	members[DAISY_CNT];	//!< Kontexty vsech prevodniku v retezu
	//TODO daisyChain
}ADS131_DAISY_CTX;

#endif

//----------------------------------------------------
/**
	\brief	Inicializace ovladace ADS
	\param	_ctx		Kontext ADS
	\param	_spi		Ovladac SPI, ke kteremu je ADS pripojen
	\param	_spiChannel	Kanal SPI
	\param	_devID		Pridelene SW identifikacni cislo
	\return TRUE		Pokud inicializace probehla uspesne
*/
//----------------------------------------------------
bool_t Ads131Initialize(ADS131_CTX * const _ctx, SPIDESC * const _spi, const uint8_t _spiChannel, const uint8_t _devNo);

#endif
