#ifndef _ADC_H__
#define _ADC_H__
#include "bsp/bsp.h"
#include "os/os_types.h"

float adc_vref_compesion(void);
float adc_5vref_compesion(void);

/*
inserted ADC 由timer0 ch3触发，
注意：adc所有外部触发都是下降沿触发 
*/
#define ISQ0_OFFSET 0
#define ISQ1_OFFSET 5
#define ISQ2_OFFSET 10
#define ISQ3_OFFSET 15
#define IL_OFFSET   20

#define ADC_SAMPLE_TIME ADC_SAMPLETIME_13POINT5
#ifdef CONFIG_SENSORLESS_TOW_SAMPLES
#define ADC_TRIGGER_PHASE ADC0_1_EXTTRIG_INSERTED_T0_TRGO
#else
#define ADC_TRIGGER_PHASE ADC0_1_EXTTRIG_INSERTED_T0_CH3
#endif
#define ADC_TRIGGER_PHASE2 ADC0_1_EXTTRIG_INSERTED_T1_CH0
#define ADC_TRIGGER_NONE  ADC0_1_2_EXTTRIG_INSERTED_NONE
#define ADC_TRIGGER_VBUS ADC0_1_EXTTRIG_INSERTED_T1_CH0

#define PHASE_AB 0
#define PHASE_AC 1
#define PHASE_BC 2

#define ADC_RANK_CHANNEL(c)  ((c)<<ISQ3_OFFSET | (0)<<IL_OFFSET) 
#define ADC_INS_RANK_4_CHANS(c1,c2,c3,c4) (((c1)<<ISQ0_OFFSET) | ((c2)<<ISQ1_OFFSET) | ((c3)<<ISQ2_OFFSET) | ((c4)<<ISQ3_OFFSET) | ((3)<<IL_OFFSET))
#define INJ_CHAN_NUM 1

#ifndef HIGH_SIDE_CURRENT_SENSOR
static u32 adc0_rank_channels[3] = {
	ADC_RANK_CHANNEL(U_PHASE_I_CHAN),//0, A, AB	
	ADC_RANK_CHANNEL(U_PHASE_I_CHAN),//1, A, AC
	ADC_RANK_CHANNEL(V_PHASE_I_CHAN),//2, B, BC

};
static u32 adc1_rank_channels[3] = {
	ADC_RANK_CHANNEL(V_PHASE_I_CHAN),//0, B
	ADC_RANK_CHANNEL(W_PHASE_I_CHAN),//1, C
	ADC_RANK_CHANNEL(W_PHASE_I_CHAN),//2, C
};


static u32 volatile * adc_phase_reg1[3] = {
	&ADC_IDATA0(ADC0),//0, A
	&ADC_IDATA0(ADC0),//1, A
	&ADC_IDATA0(ADC0),//2, B
};
static u32 volatile * adc_phase_reg2[3] = {
	&ADC_IDATA0(ADC1),//0, B
	&ADC_IDATA0(ADC1),//1, C
	&ADC_IDATA0(ADC1),//2, C
};
#endif

#define v_calc(sum, v, min, max) \
	do { \
		if (v > max) { \
			max = v; \
		} \
		if (v < min) { \
			min = v; \
		}\
		sum += v; \
	}while(0);

static void __inline adc_phase_current_read(u8 phases, s32 *pv1, s32 *pv2) {
#ifdef HIGH_SIDE_CURRENT_SENSOR
#if (INJ_CHAN_NUM==4)
	u16 min, max;
	u16 sum = 0;
	u16 v1 = ADC_IDATA0(ADC0);
	u16 v2 = ADC_IDATA1(ADC1);
	u16 v3 = ADC_IDATA2(ADC0);
	u16 v4 = ADC_IDATA3(ADC1);
	min = max = v1;
	sum += v1;
	v_calc(sum, v2, min, max);
	v_calc(sum, v3, min, max);
	v_calc(sum, v4, min, max);
	*pv1 = (s32) ((sum-min-max)/2.0f * adc_5vref_compesion());

	sum = 0;
	v1 = ADC_IDATA0(ADC1);
	v2 = ADC_IDATA1(ADC0);
	v3 = ADC_IDATA2(ADC1);
	v4 = ADC_IDATA3(ADC0);
	min = max = v1;
	sum += v1;
	v_calc(sum, v2, min, max);
	v_calc(sum, v3, min, max);
	v_calc(sum, v4, min, max);
	*pv2 = (s32) ((sum-min-max)/2.0f * adc_5vref_compesion());

#else
	*pv1 = (s32)((float)ADC_IDATA0(ADC0) * adc_5vref_compesion());
	*pv2 = (s32)((float)ADC_IDATA0(ADC1) * adc_5vref_compesion());
#endif
#else
	*pv1 = (s32)(*adc_phase_reg1[phases]) ;
	*pv2 = (s32)(*adc_phase_reg2[phases]) ;
#endif
}


static void __inline adc_current_sample_config(u8 phases) {
#ifdef HIGH_SIDE_CURRENT_SENSOR
#if (INJ_CHAN_NUM==4)
	//ADC_ISQ(ADC0) = ADC_INS_RANK_4_CHANS(V_PHASE_I_CHAN, W_PHASE_I_CHAN, V_PHASE_I_CHAN, W_PHASE_I_CHAN);
	//ADC_ISQ(ADC1) = ADC_INS_RANK_4_CHANS(W_PHASE_I_CHAN, V_PHASE_I_CHAN, W_PHASE_I_CHAN, V_PHASE_I_CHAN);
#else
	ADC_ISQ(ADC0) = ADC_RANK_CHANNEL(V_PHASE_I_CHAN);
	ADC_ISQ(ADC1) = ADC_RANK_CHANNEL(W_PHASE_I_CHAN);
#endif
#else
	ADC_ISQ(ADC0) = adc0_rank_channels[phases];
	ADC_ISQ(ADC1) = adc1_rank_channels[phases];
#endif
}

static void __inline adc_disable_ext_trigger(void) {   
	ADC_CTL1(ADC0) &= ~ADC_CTL1_ETEIC;
}

static void __inline adc_enable_ext_trigger(void) {	
	ADC_CTL1(ADC0) |= ADC_CTL1_ETEIC;
}

/* insert len fixed to 2(IL=1), ISQ2 >> ISQ3*/
static __inline__ void adc_update_insert_sample_rank(u32 adc, u8 channel) {
    ADC_ISQ(adc) = ADC_RANK_CHANNEL(channel);
}

static __inline__ void adc_update_insert_sample_time(u32 adc, uint8_t adc_channel , uint32_t sample_time)
{
    uint32_t sampt;
    /* ADC sampling time config */  
    if(adc_channel < 10U){
        sampt = ADC_SAMPT1(adc);
        sampt &= ~((u32)(ADC_SAMPTX_SPTN << (3U*adc_channel)));
        sampt |= (u32) sample_time << (3U*adc_channel);
        ADC_SAMPT1(adc) = sampt;
    }else if(adc_channel < 18U){
        sampt = ADC_SAMPT0(adc);
        sampt &= ~((u32)(ADC_SAMPTX_SPTN << (3U*(adc_channel-10U))));
        sampt |= ((u32)sample_time << (3U*(adc_channel-10U)));
        ADC_SAMPT0(adc) = sampt;
    }
}

static __inline__ bool adc_eoic_interrupt(void)
{
	if (ADC_STAT(ADC0) & ADC_STAT_EOIC){
		return true;
	}
	return false;
}

static __inline__ void adc_clear_irq_flags(void) {
	ADC_STAT(ADC0) &= ~((u32) ADC_INT_FLAG_EOIC);
	ADC_STAT(ADC1) &= ~((u32) ADC_INT_FLAG_EOIC);
}


static __inline void adc_update_ext_trigger(u32 trigger) {
	adc_external_trigger_source_config(ADC0, ADC_INSERTED_CHANNEL, trigger);
}

void adc_init(void);
s32 adc_sample_regular_channel(int chan, int times);
void adc_start_convert(void);
void adc_stop_convert(void);
u16 adc_get_vbus(void);
u16 adc_get_acc(void);
u16 adc_get_throttle(void);
void adc_get_uvw_phaseV(u16 *uvw);
u16 adc_get_mos_temp(void);
u16 adc_get_motor_temp(void);
u16 adc_get_ibus(void);
u16 adc_get_vref(void);
void adc_set_vref_calc(float v);
void adc_vref_filter(void);
u16 adc_get_5v_ref(void);
void adc_set_5vref_calc(float v);
u16 adc_get_throttle2(void);
u16 adc_get_thro_5v(void);
u16 adc_get_thro2_5v(void);

#endif /* _ADC_H__ */
