//=================================================================================================
//
// Company:       Paul Scherrer Institut
//                5232 Villigen PSI
//                Switzerland
//
//-------------------------------------------------------------------------------------------------
//
// Project:       Peltier Controller V2
// Author:        Noah Piqué (noah.pique@psi.ch)
//
//-------------------------------------------------------------------------------------------------
//
// Module:        ADC-Driver
// Filename:      ADCD_AdcDriver.c
// Date:          Handled by Subversion (version control system)
// Revision:      Handled by Subversion (version control system)
// History:       Handled by Subversion (version control system)
//
//-------------------------------------------------------------------------------------------------
//
// Description:   This source file contains all functions dealing with the internal ADC-Driver
//
//=================================================================================================



//=================================================================================================
// Section:       INCLUDES
// Description:   List of required include files.
//=================================================================================================

#include "../PDEF_ProjectDefinitions.h"
#include "ADCD_AdcDriver.h"

// Drivers
#include "SPID_SpiDriver.h"
#include "DIPO_DigitalPorts.h"
//#include "EXTI_ExtiHandler.h"

// Application
//#include "../Application/ELOG_ErrorLogger.h"

// Toolbox 
#include "../Toolbox/UTIL_Utility.h"

// CMSIS OS
#include "cmsis_os2.h"

//=================================================================================================
// Section:       DEFINITIONS
// Description:   Definition of local constants (visible by this module only).
//=================================================================================================

// define commands
#define CMD_READ      				(0<<7)
#define CMD_WRITE     				(1<<7)

// define register
#define REG_CONFIG    				0x00
#define REG_RTD_MSB   				0x01
#define REG_RTD_LSB    				0x02
#define REG_HIGH_FAULT_MSB  		0x03
#define REG_HIGH_FAULT_LSB  		0x04
#define REG_LOW_FAULT_MSB   		0x05
#define REG_LOW_FAULT_LSB   		0x06
#define REG_FAULT_STATUS    		0x07

#define CONFIG_VBIAS_ON 			(1<<7)
#define CONFIG_VBIAS_OFF 			(0<<7)
#define CONFIG_MODE_AUTO 			(1<<6)
#define CONFIG_MODE_OFF 			(0<<6)
#define CONFIG_1SHOT 				(1<<5)
#define CONFIG_3WIRE 				(1<<4)
#define CONFIG_24WIRE 				(0<<4)
#define CONFIG_FAULTCYCLE_NO 		(0<<2)
#define CONFIG_FAULTCYCLE_AUTO 		(1<<2)
#define CONFIG_FAULTCYCLE_MANUAL1 	(2<<2)
#define CONFIG_FAULTCYCLE_MANUAL2 	(3<<2)
#define CONFIG_FAULTSTATCLEAR 		(1<<1)
#define CONFIG_FILT50HZ 			(1<<0)
#define CONFIG_FILT60HZ 			(0<<0)

#define FAULT_HIGHTHRESH 			0x80
#define FAULT_LOWTHRESH 			0x40
#define FAULT_REFINLOW 				0x20
#define FAULT_REFINHIGH 			0x10
#define FAULT_RTDINLOW 				0x08
#define FAULT_OVUV 					0x04

#define CONFIG	(U8)(CONFIG_VBIAS_ON | CONFIG_MODE_OFF | CONFIG_24WIRE | CONFIG_FILT60HZ) // enable Vbias; autoconvert off; 4-wire; 60Hz;

#define EVENT_ENABLE                ((U32)(1<<0))
#define EVENT_DISABLE               ((U32)(1<<1))
#define EVENT_INVERT                ((U32)(1<<2))
#define EVENT_EXT_SYNC_ENABLE       ((U32)(1<<3))
#define EVENT_NEW_SET_VALUE         ((U32)(1<<4))
#define EVENT_NEW_MODE              ((U32)(1<<5))
#define EVENT_DAC_START             ((U32)(1<<6))
#define EVENT_DAC_STOP              ((U32)(1<<7))
#define EVENT_ADC_DATA_READY        ((U32)(1<<8))
#define EVENT_RESET_DATA_COUNTER    ((U32)(1<<9)) 

#define EVENT_FLAGS_ALL             ( EVENT_ENABLE | EVENT_DISABLE | EVENT_INVERT | \
                                      EVENT_EXT_SYNC_ENABLE | EVENT_NEW_SET_VALUE | EVENT_NEW_MODE | \
                                      EVENT_DAC_START | EVENT_DAC_STOP | EVENT_ADC_DATA_READY | \
                                      EVENT_RESET_DATA_COUNTER )


//=================================================================================================
// Section:       MACROS
// Description:   Definition of local macros (visible by this module only).
//=================================================================================================



//=================================================================================================
// Section:       ENUMERATIONS
// Description:   Definition of local enumerations (visible by this module only).
//=================================================================================================



//=================================================================================================
// Section:       STRUCTURES
// Description:   Definition of local Structures (visible by this module only).
//=================================================================================================
 

//=================================================================================================
// Section:       LOCAL CONSTANTS
// Description:   Definition of local constants (visible by this module only).
//=================================================================================================

LOCAL CONST osMutexAttr_t m_stMutexAttr =
{
  "ADCD_Mutex",                             // human readable mutex name
  osMutexRecursive | osMutexPrioInherit,    // attr_bits
  NULL,                                     // memory for control block   
  0U                                        // size for control block
};

// Data Ready Pin
//LOCAL CONST GPIO_TypeDef* m_pstDataReadyPort = GPIOD;
//LOCAL CONST U16           m_u16DataReadyPin = GPIO_PIN_8;

//=================================================================================================
// Section:       LOCAL VARIABLES
// Description:   Definition of local variables (visible by this module only).
//=================================================================================================

LOCAL U8 m_au8RxData[8];
LOCAL U8 m_au8TxData[8];
LOCAL osMutexId_t m_pstMutexID = NULL;

LOCAL SPID_StHandle m_stSPIHandle = 
{
  SPID_eADC,              	// enSPI;
  0xFF,           			// enCS (0xFF = hardware chip select)
  m_au8TxData,            	// pu8TxBuf;
  m_au8RxData,            	// pu8RxBuf;
  0,                      	// u16TransferSize;
};


//=================================================================================================
// Section:       LOCAL FUNCTIONS (PROTOTYPES)
// Description:   Definition of local functions (visible by this module only).
//=================================================================================================

PRIVATE BOOL boWriteReg( U8 u8Register, U16 u16Data, BOOL boIs16bit );
PRIVATE BOOL boReadReg( U8 u8Register, PU16 pu16Data, BOOL boIs16bit );

//=================================================================================================
// Section:       EXTERNAL FUNCTIONS
// Description:   Definition of external (global) functions.
//=================================================================================================



//=================================================================================================
// Section:       EXTERNAL VARIABLES
// Description:   Definition of external (global) variables.
//=================================================================================================


//=================================================================================================
// Section:       GLOBAL FUNCTIONS
// Description:   Definition (implementation) of global functions.
//=================================================================================================

//-------------------------------------------------------------------------------------------------
// Function:      ADCD_boInitializeModule
// Description:   Initializes the ADC module
// Parameters:    None
// Returns:       BOOL  TRUE, if initializaiton sucessful, otherwise FALSE
//                                          
//-------------------------------------------------------------------------------------------------
BOOL ADCD_boInitializeModule( VOID )
{
  BOOL boOK = TRUE;
  
  boOK &= ( ( m_pstMutexID = osMutexNew( &m_stMutexAttr ) ) == NULL ) ? FALSE : TRUE;
	
	osMutexAcquire( m_pstMutexID, osWaitForever );
	
	// Conifg ADC Cold
	DIPO_vSetOutput( DIPO_eCS_C );
	boOK &= boWriteReg( REG_CONFIG, (U16) CONFIG | CONFIG_FAULTSTATCLEAR, FALSE );
	DIPO_vResetOutput( DIPO_eCS_C );

	DIPO_vSetOutput( DIPO_eCS_C );
	boOK &= boWriteReg( REG_HIGH_FAULT_MSB, (U16)0x5b12 , TRUE );
	DIPO_vResetOutput( DIPO_eCS_C );

	DIPO_vSetOutput( DIPO_eCS_C );
	boOK &= boWriteReg( REG_LOW_FAULT_MSB, (U16)0x2690 , TRUE );
	DIPO_vResetOutput( DIPO_eCS_C );

	// Config ADC Hot	
	DIPO_vSetOutput( DIPO_eCS_H );
	boOK &= boWriteReg( REG_CONFIG, (U16) CONFIG | CONFIG_FAULTSTATCLEAR, FALSE );
	DIPO_vResetOutput( DIPO_eCS_H );

	DIPO_vSetOutput( DIPO_eCS_H );
	boOK &= boWriteReg( REG_HIGH_FAULT_MSB, (U16)0x5b12 , TRUE );
	DIPO_vResetOutput( DIPO_eCS_H );

	DIPO_vSetOutput( DIPO_eCS_H );
	boOK &= boWriteReg( REG_LOW_FAULT_MSB, (U16)0x2690 , TRUE );
	DIPO_vResetOutput( DIPO_eCS_H );
	
	osMutexRelease( m_pstMutexID );
  
  return( boOK );
}

//-------------------------------------------------------------------------------------------------
// Function:      ADCD_boReadData
// Description:   Reads the conversion data form the ADC
// Parameters:    PU8 pu8Error              error
// Returns:       DOUBLE                    conversion data
//-------------------------------------------------------------------------------------------------
BOOL ADCD_boReadData( ADCD_EnTemps eChannel, PU8 pu8Error, PU16 pu16Data )
{
	BOOL boOK       = TRUE;
	*pu8Error       = 0;      // reset error state
	U16 u16Data		= 0;
	
	DIPO_EnDigitalOutput CS = DIPO_eCS_H;
	
	if( eChannel == ADCD_eHot ) CS = DIPO_eCS_H;
	else if ( eChannel == ADCD_eCold ) CS = DIPO_eCS_C;

	osMutexAcquire( m_pstMutexID, osWaitForever );
	DIPO_vSetOutput( CS );
	boOK &= boWriteReg( REG_CONFIG, CONFIG | CONFIG_1SHOT , FALSE );
	DIPO_vResetOutput( CS );
	osMutexRelease( m_pstMutexID );
	
	osDelay(55);
	
	osMutexAcquire( m_pstMutexID, osWaitForever );
	DIPO_vSetOutput( CS );
	boOK &= boReadReg( REG_RTD_MSB, &u16Data, TRUE );
	DIPO_vResetOutput( CS );
	osMutexRelease( m_pstMutexID );
	
	if( !boOK )
	{
		*pu8Error |= ADCD_SPI_FAILURE;
		return 0;
	}
	
	if( ( u16Data & 0x00 ) == 0x01 )
	{
		*pu8Error |= ADCD_STATUS_DATA_ERROR;
		
		osMutexAcquire( m_pstMutexID, osWaitForever );

		DIPO_vSetOutput( CS );
		boOK &= boReadReg( REG_FAULT_STATUS, &u16Data, FALSE );
		DIPO_vResetOutput( CS );

		DIPO_vSetOutput( CS );
		boOK &= boWriteReg( REG_CONFIG, (U16) CONFIG | CONFIG_FAULTSTATCLEAR, FALSE );
		DIPO_vResetOutput( CS );

		DIPO_vSetOutput( CS );
		boOK &= boReadReg( REG_HIGH_FAULT_MSB, &u16Data, TRUE );
		DIPO_vResetOutput( CS );

		osMutexRelease( m_pstMutexID );

		*pu8Error |= u16Data & 0xFC;
		return 0;
	} 
	
	u16Data = u16Data >> 1;
	
	*pu16Data = u16Data;
	
	osMutexAcquire( m_pstMutexID, osWaitForever );
	DIPO_vSetOutput( CS );
	boOK &= boWriteReg( REG_CONFIG, CONFIG | CONFIG_FAULTCYCLE_AUTO , FALSE );
	DIPO_vResetOutput( CS );
	osMutexRelease( m_pstMutexID );

	return( boOK ); 
}

//=================================================================================================
// Section:       LOCAL FUNCTIONS
// Descriptionn:  Definition (implementation) of local functions.
//=================================================================================================


//-------------------------------------------------------------------------------------------------
// Function:      boWriteReg
// Description:   Writes to the regiser
// Parameters:    U8 u8Register
//                U16 u16Data
//								BOOL boIs16bit TRUE, if Data is 16bit, FALSE, if Data is 8bit
// Returns:       BOOL TRUE, if successful, otherwise FALSE                                   
//-------------------------------------------------------------------------------------------------
PRIVATE BOOL boWriteReg( U8 u8Register, U16 u16Data, BOOL boIs16bit )
{
  	BOOL boOK = TRUE;
  
	if( boIs16bit ){
		m_au8TxData[0] = CMD_WRITE | u8Register;
		m_au8TxData[1] = (U8)u16Data>>8;
		m_au8TxData[2] = (U8)u16Data;
		m_stSPIHandle.u16TransferSize = 3;
		boOK &= SPID_boSendReceive( &m_stSPIHandle );
	} else {
		m_au8TxData[0] = CMD_WRITE | u8Register;
		m_au8TxData[1] = (U8)u16Data;
		m_stSPIHandle.u16TransferSize = 2;
		boOK &= SPID_boSendReceive( &m_stSPIHandle );
	}
  
  	return( boOK );
}

//-------------------------------------------------------------------------------------------------
// Function:      boReadReg
// Description:   Reads the regiser
// Parameters:    U8 u8Register
//                PU16 pu16Data
//				  BOOL boIs16bit TRUE, if Data is 16bit, FALSE, if Data is 8bit
// Returns:       BOOL TRUE, if successful, otherwise FALSE                                   
//-------------------------------------------------------------------------------------------------
PRIVATE BOOL boReadReg( U8 u8Register, PU16 pu16Data, BOOL boIs16bit )
{
  BOOL boOK   = TRUE;
	
	if( boIs16bit ){
		m_au8TxData[0] = CMD_READ | u8Register;
		m_au8TxData[1] = 0;
		m_au8TxData[2] = 0;
		m_stSPIHandle.u16TransferSize = 3;
		
		boOK &= SPID_boSendReceive( &m_stSPIHandle );
		
		*pu16Data = ( (U16)m_au8RxData[1]<<8 ) | ( (U16)m_au8RxData[2]<<0 );
	} else {
		m_au8TxData[0] = CMD_READ | u8Register;
		m_au8TxData[1] = 0;
		m_stSPIHandle.u16TransferSize = 2;
		
		boOK &= SPID_boSendReceive( &m_stSPIHandle );
		
		*pu16Data = (U16)m_au8RxData[1];
	}

  return( boOK );
}
