/*
******************************************************************************************************
 @Module        	MAIN
 @Filename     	main.c
 @Project        	SEM-3000
-----------------------------------------------------------------------------------------------------
 @Controller     	Si1010

 @Compiler      	Keil 8.12

 @ Frequency   	Using Internal clock 24.5MHz

 @Codegenerator 	0.1

 @Description   

------------------------------------------------------------------------------------------------------
 @Date          		2013-07-05 11:00:00

******************************************************************************************************
*/


#define _ADC_C_

/*
********************************************************************************************************
									 @Project Includes
********************************************************************************************************
*/

#include "PROJECT_INCLUDES.H"

void  (*pADC0_Intertupt_Service__BATT_Monitor)(void);	//ADC0 interrupt service function
///void  (*pADC0_Intertupt_Service__ADAPTER_Monitor)(void);	//ADC0 interrupt service function

void  (*pADC0_Intertupt_Service__CT1_Eng_Monitor)(void);	//ADC0 interrupt service function
void  (*pADC0_Intertupt_Service__CT2_Eng_Monitor)(void);	//ADC0 interrupt service function
void  (*pADC0_Intertupt_Service__CT3_Eng_Monitor)(void);	//ADC0 interrupt service function

void  (*pADC0_Intertupt_Service__CT_DECT_Monitor)(void);	//ADC0 interrupt service function

/*
*********************************************************************************************************
*                                        			ADC0	Intertupt Service  Routine 모음 
*
* Description:    ADC Intertupt Service  Routine

* Arguments  :   Intertupt Service function Pointer
*                    
*
* Returns    :     NONE  

*********************************************************************************************************
*/

void BATT_Monitor_Intertupt_Service_Init (void (*a_pInterrupt_Service)())
{
	pADC0_Intertupt_Service__BATT_Monitor=a_pInterrupt_Service;
}

///void ADAPTER_Monitor_Intertupt_Service_Init (void (*a_pInterrupt_Service)())
///{
///	pADC0_Intertupt_Service__ADAPTER_Monitor=a_pInterrupt_Service;
///}

void CT1_Monitor_Intertupt_Service_Init (void (*a_pInterrupt_Service)())
{
	pADC0_Intertupt_Service__CT1_Eng_Monitor=a_pInterrupt_Service;
}

void CT2_Monitor_Intertupt_Service_Init (void (*a_pInterrupt_Service)())
{
	pADC0_Intertupt_Service__CT2_Eng_Monitor=a_pInterrupt_Service;
}

void CT3_Monitor_Intertupt_Service_Init (void (*a_pInterrupt_Service)())
{
	pADC0_Intertupt_Service__CT3_Eng_Monitor=a_pInterrupt_Service;
}

void CT_DECT_Monitor_Intertupt_Service_Init (void (*a_pInterrupt_Service)())
{
	pADC0_Intertupt_Service__CT_DECT_Monitor=a_pInterrupt_Service;

}


/*
*********************************************************************************************************
 									@ADC0 Intertupt_Service Function
*********************************************************************************************************
*/

//const U8 Adc_Channel_Buff[ADC_CHANNEL_NUM]={ BATT_INDICATOR, Sel_Temperature_Sensor} ;
//const U8 Adc_Channel_Buff[ADC_CHANNEL_NUM]={BATT_INDICATOR, ADC_MUX_CT_DECT, ADC_MUX_CT_1 , ADC_MUX_CT_2, ADC_MUX_CT_3, ADAPTER_DETECT} ;
const U8 Adc_Channel_Buff[ADC_CHANNEL_NUM]={ADC_MUX_CT_DECT, ADC_MUX_CT_1 , ADC_MUX_CT_2, ADC_MUX_CT_3} ;

//============================================
#define ADC_PORT_MSK 0x78       // 2.3 2.4   2.5   2.6   
#define SET_ANALOG_PORT  P2 |=ADC_PORT_MSK; 

#define	ADC0_Select_Reference(Ref) { REF0CN= (REF0CN& ~REF_MSK)|Ref; }
//----------------------------------------------
#define	ADC0_Enale()				Set_Bit(ADC0CN, ADC0_EN); 
#define	ADC0_Burst_Mode_Enable()	Set_Bit(ADC0CN, BURST_MODE_EN);  

#define	ADC0_Select_Start_Mode(Mode){ ADC0CN= (ADC0CN&~Sel_Bit_Msk)|Mode; }

#define ADC_CT1_PORT_DIGITAL_MODE 			P2MDIN	  &=~P26_ADC_CT1;
#define ADC_CT1_PORT_PUSH_PULL_OUT_MODE 	P2MDOUT  &=~P26_ADC_CT1;
#define ADC_CT2_PORT_DIGITAL_MODE 			P2MDIN	  &=~P25_ADC_CT2;
#define ADC_CT2_PORT_PUSH_PULL_OUT_MODE 	P2MDOUT  &=~P25_ADC_CT2;
#define ADC_CT3_PORT_DIGITAL_MODE 			P2MDIN	  &=~P24_ADC_CT3;
#define ADC_CT3_PORT_PUSH_PULL_OUT_MODE 	P2MDOUT  &=~P24_ADC_CT3;
#define ADC_CT_DECT_PORT_DIGITAL_MODE 			P2MDIN	  &=~P23_ADC_CT_DECT;
#define ADC_CT_DECT_PORT_PUSH_PULL_OUT_MODE 	P2MDOUT  &=~P23_ADC_CT_DECT;

//#define ADC_PORT_MSK 0x1f
//#define SET_ANALOG_PORT  P2 |=ADC_PORT_MSK; 

#define RL_ENABLE_PORT_DIGITAL_MODE 			P2MDIN	  |=P22_RL_ENABLE;
#define RL_ENABLE_PORT_PUSH_PULL_OUT_MODE 	P2MDOUT  |=P22_RL_ENABLE;

//------------------------------------------------------------------------------
#define   ADC0_Accumulator_Configuration(Config){  ADC0AC=0; ADC0AC =Config; }
//=============================================
volatile  U8 idata  Adc_Channel;
#if 0
//---------------------------------------------------------------
//		ADC0CN
//---------------------------------------------------------------
#define	ADC0_EN			 	 7
#define	BURST_MODE_EN 	 	 6	
#define	ADC0_INT_FLAG			 5
#define	ADC0_BUSY				 4
#define	ADC0_WINDOE_INT_FLAG	 3

#define  Sel_Bit_Msk 0x07	

#define  STRAR_AD0_BUSY_SET	0x00
#define  STRAR_TIMER_0			0x01
#define  STRAR_TIMER_2			0x02
#define  STRAR_TIMER_3			0x03
#define  STRAR_P0_6__RISING_EDGE 	0x04

//---------------------------------------------------------------
//		ADC0AC
//---------------------------------------------------------------


#define ADC0_ACC_EN            6

#define No_shifting  		0x00
#define Shift_right_1_bit	0x08
#define Shift_right_2_bit	0x10
#define Shift_right_3_bit	0x18

#define 	Accumulate_1	0x00
#define 	Accumulate_4	0x01
#define 	Accumulate_8	0x02
#define 	Accumulate_16	0x03
#define 	Accumulate_32	0x04
#define 	Accumulate_64	0x05
#endif

#define	ADC_TIMEOUT_PERIOD  500  // 1000ms
#define	ADC_PORT_CLR 0x1
///#define	SET_ANALOG_PORT  P2 |=ADC_PORT_CLR;
//#define	ADC0_Enale()				Set_Bit(ADC0CN, ADC0_EN); 
//#define	ADC0_Burst_Mode_Enable()	Set_Bit(ADC0CN, BURST_MODE_EN);  

//volatile U8 idata ADC_Timeout_Chk_Timer;

//-----------------------------------------------------------------------------
// Temperature Sensor Calibration PARAMETERS
//-----------------------------------------------------------------------------
#define AMB_TEMP           			23        // Ambient Calibration Temperature (degC)	26 -> 16 -> 22
#define TEMP_SENSOR_GAIN   		1650    // Temp Sensor Gain in (uV / degC)
#define PGA_GAIN           			2         // PGA gain setting		//1 -> 2
#define VREF               			3000///1650    // ADC Voltage Reference (mV)


//////////////////////////////////////////// 

#define  ONE_CALIBRATION_TEMPERAT_SENSOR   0xFFFF

///unsigned int code   TEMP_OFFSET=ONE_CALIBRATION_TEMPERAT_SENSOR;       //  The temperat. sensor offset value will be set on the first run.  It must be initialized to 0xff's


unsigned long time_remainder;           // remainder after compens. of sec.
unsigned long ppm_remainder;
unsigned long idata accumulative;       // real ppm acumulator
unsigned char Seconds;

void FLASH_Write (char *dest, char *src, unsigned num) // code memory write 
{
	unsigned char idata i;                    // loop counter
	char xdata *pwrite;                      // FLASH write pointer
	char idata the_data;                    // holds data to write to FLASH

	pwrite = (char *) dest;                  // set target address in FLASH

	for (i = 0; i < num; i++) {
		  the_data = *src++;                    // read data byte
		  FLKEY = 0xa5;                         // Key sequence #1
		  FLKEY = 0xf1;                         // Key sequence #2
		  PSCTL = 0x01;                         // PSWE = 1; MOVX writes target FLASH
		  RSTSRC = 0x06;                        // force MCD and VDDmon enable
		  *pwrite = the_data;                   // write the data
		  PSCTL = 0x00;                         // PSWE = 0; MOVX writes target XRAM
		  pwrite++;                             // advance write pointer
	}
}



//-----------------------------------------------------------------------------
// ADC0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Initialize the ADC to use the temperature sensor.
//	if(time_mSecTimeExpired(ADC_Timeout_Chk_Timer) == TIMER_EXPIRED ){ 
//   timer_mSecTimerSet(ADC_Timeout_Chk_Timer, ADC_TIMEOUT_PERIOD); 	// Set Time out priode
//-----------------------------------------------------------------------------
extern void phyWrite (U8 reg, U8 value);

//#define	ADC0_Accumulator_Configuration(Config){  ADC0AC=0; ADC0AC =Config; }
//#define	ADC0_Select_Start_Mode(Mode){ ADC0CN= (ADC0CN&~Sel_Bit_Msk)|Mode; }
#define	ADC0MX_GND 0x1F

void ADC0_Init (void)
{
	#if 0
	time_remainder = 0;           // remainder after compens. of sec.
	ppm_remainder = 0;
	accumulative = 0;       // real ppm acumulator
	Seconds = 0;

	temperature = 0 ;                  
 
  	///ADC_Timeout_Chk_Timer= timer_mSecHandleAssign();

	phyWrite(0x12, 0x3F);	//60 -> 30 -> 20 
	phyWrite(0x13, 0x70);	//
	
   	VDM0CN |=0x80 ;  					// VDD_MCU/DC+ Supply Monitor Enable..              
										
  	REF0CN = 0x1c;      					//Vref =  internal 1.65    Temp. Sensor ON
  	
	P2SKIP    = 0x81;
		
	ADC0_Burst_Mode_Enable();
	
	ADC0MX = ADC0MX_GND;
		
   	ADC0MX = Sel_Temperature_Sensor;   	// AMUX0 Selects Temp. Sensor  											   
	 
   	ADC0CF = ((SYSCLK/5000000)-1) << 3;   // ADC conversion clock --> 5.0MHz
   	ADC0CF |= 0x01;                     			// Gain = 1
	 	
   	///ADC0CN = 0x80;                      			// ADC ON,   AD0BUSY=1 Writing  Conversion Start

	ADC0_Accumulator_Configuration(Shift_right_2_bit|Accumulate_16);
	
   	EIE1 &= ~0x08;                       			// disable ADC0 conversion complete int.

   	///if(TEMP_OFFSET == ONE_CALIBRATION_TEMPERAT_SENSOR) calibrate();   // Measure the temperature, calculate the 0 DEG C offset value
	 
   	///temperature = get_temp();  // 온도 값 초기화 
	 
	///timer_mSecTimerDelete(ADC_Timeout_Chk_Timer);
	
  	///ADC_Timeout_Chk_Timer= timer_mSecHandleAssign();
	#else
	SET_ANALOG_PORT;

	RL_ENABLE_PORT_DIGITAL_MODE;                // ADC 오차 교정을 위한  병렬 저항  선택 포트 
	RL_ENABLE_PORT_PUSH_PULL_OUT_MODE;

	ADC_RL_ENABLE=ON;  //  병렬 저항  을 선택 하지 않는다 

    ADC0CN = 0xEB;///0xCB;

	P2SKIP=ADC_PORT_MSK;

	//ADC0_Burst_Mode_Enable();
	
	//ADC0_Select_Start_Mode(STRAR_AD0_BUSY_SET);  // AD0_BUSY bit 에 1을 write 하면  ADC 는 시작 된다 
	//ADC0_Select_Start_Mode(STRAR_TIMER_3);  // AD0_BUSY bit 에 1을 write 하면  ADC 는 시작 된다 

  	ADC0_Select_Reference( P0_0_VREF); 
	
	ADC0MX =ADC_MUX_CT_DECT   ;  //ADC_MUX_CT_1 	BATT_INDICATOR									   
	 
   	///ADC0CF = ((SYSCLK/5000000)-1) << 3;   // ADC conversion clock --> 5.0MHz
   	ADC0CF = ((SYSCLK/1500000))<<3;     // Set SAR clock to 8.3MHz   8300000
   	ADC0CF |= 0x01;                     			// Gain = 1
	 	
	ADC0_Accumulator_Configuration(Shift_right_2_bit|Accumulate_16);
	
 	INTERRUPT_DISABLE_ADC_0();	   

  	//ADC_Timeout_Chk_Timer= timer_mSecHandleAssign();
	
	#endif
}

#define SAMPLING     10  //      38	//50 -> 1

#define ADC_TIMER_TICKS  500   // 5s -> 1s

void ADC(void){
#if 0
	U8   idata Battery_Level=0;	
   
	if(time_mSecTimeExpired(ADC_Timeout_Chk_Timer) == TIMER_EXPIRED ){

   			timer_mSecTimerSet(ADC_Timeout_Chk_Timer, ADC_TIMER_TICKS); 	// Set Time out priode

			calc_ppm();	
			compensate_RTC();
			

			Battery_Check_ADC0();

			Battery_Level=Battery_Level_Get();
			
			

	}
#endif

			Battery_Check_ADC0();
} 



/*
*********************************************************************************************************
*                                        				ADC_Set_Channel
*
* Description:    ADC를 Read 하기 전 Channel을 선택 한다 .
*
* Arguments  :   ADC_Channel:  ADC를 원하는 입력 채널 
*                    
*
* Returns    :     NONE   

*********************************************************************************************************
*/

void  ADC_Set_Channel(U8 ADC_Channel)
{
	ADC0MX =Adc_Channel_Buff[ADC_Channel];  // 

}

/*
*********************************************************************************************************
*                                        				ADC_Get_mV
*
* Description:    ADC를 값을 읽어서 전압으로 변환해서 반환 한다. ( 이 함수 이전에 ADC_Set_Channel() 을 통해 읽을 Channel이 선택 되어야 한다.
*
* Arguments  :   NONE
*                    
*
* Returns    :     ADC mV Value

*********************************************************************************************************
*/

U32  ADC_Get_mV(void)
{ 
	idata  volatile U32 result, adc;
//	idata  volatile float adc;
 
	result = ADC0;
#if 0	
	adc = (VREF / ADC_SAMPLING) * 100;

	result = (result * adc)/100;
#else
	adc = (VREF / ADC_SAMPLING);

	result = (result * adc);
#endif	

///printf("\n ADC_Get_mV = %ld", result);
	return ( result );
}


U32  ADC_Eng_Get_mV(void)
{ 
	idata  volatile U32 result, adc;
//	idata  volatile float adc;

	
	result = ADC0;
#if 0	
	adc = (VREF / ADC_SAMPLING) * 100;

	result = (result * adc)/100;
#else
	adc = (VREF / ADC_ENG_SAMPLING);

	result = (result * adc);
#endif	
	

	return ( result );
}



#define SAMPLING     10  //      38	//50 -> 1

U32  ADC_CT_Get_mV(void)
{ 

	idata  volatile U32 result, adc;
//	idata  volatile float adc;
	
	
	result = ADC0;
#if 0	
	adc = (VREF / ADC_SAMPLING) * 100;

	result = (result * adc)/100;
#else
	adc = (VREF / ADC_SAMPLING);

	result = (result * adc);
#endif	

	return ( result );
}

void Adc_Mux_Channel_Initialize (void)
{
	Adc_Channel=ADC_CT_DETECTER;
}

void Set_Adc_Mux_Channel_Count (U8 Mux_Count)
{
	Adc_Channel=Mux_Count;
}

INTERRUPT (ADC_ISR, INTERRUPT_ADC0_EOC)  //662us * 5
{
	idata  volatile U8 Buff;
	idata  volatile  U16 k;

	AD0INT = 0;                               // clear ADC0 conv. complete flag	
		
	Buff=Adc_Channel;

	Adc_Channel++;

	if(Adc_Channel==ADC_CT1)Adc_Channel=ADC_CT_DETECTER;
	
	else if(Adc_Channel>=ADC_CHANNEL_NUM)Adc_Channel=ADC_CT1;

	ADC_Set_Channel(Adc_Channel);     // 미리 ADC Mux 를  변경 한다  
	///printf("\n INTERRUPT~~~~~~~~~~~~~ Buff=%d   ", (U16)Buff);
	for(k=0; k<5; k++){}   // Mux 변경후 Delay 
    
	switch(Buff){
		
	 case ADC_CT_DETECTER:	(*pADC0_Intertupt_Service__CT_DECT_Monitor)(); 	break;
	 
	 case ADC_CT1:			(*pADC0_Intertupt_Service__CT1_Eng_Monitor)();	break;	
	 case ADC_CT2:			(*pADC0_Intertupt_Service__CT2_Eng_Monitor)();	break;
	 case ADC_CT3:			(*pADC0_Intertupt_Service__CT3_Eng_Monitor)();	break;
	 
	 default:                             Adc_Channel=ADC_CT1;
	 
	}

}
