/**************************************************************************//**
 * @file     pan_adc.c
 * @version  V1.00
 * $Revision:  2$
 * $Date: 16/02/25 15:53 $
 * @brief    Panchip series ADC driver source file
 *
 * @note
 * Copyright (C) 2025 Panchip Technology Corp. All rights reserved.
*****************************************************************************/
#include "pan271x.h"
#include "pan_adc.h"
#include "pan_sys.h"
#include "math.h"

/** @addtogroup Panchip_Device_Driver Panchip Device Driver
  @{
*/

/** @addtogroup Panchip_ADC_Driver ADC Driver
  @{
*/


/** @addtogroup Panchip_ADC_EXPORTED_FUNCTIONS ADC Exported Functions
  @{
*/

uint32_t global_calc_vbat_mv = 3300;

/**
  * @brief Init ADC config parameters
  * @param[in] ADCx     Base address of ADC module
  * @param[in] buf_en   Enable ADC buffer or not
  * @return None
  */
bool ADC_Init(ADC_T *ADCx, bool buf_en)
{
//	ADCx->ADC_CTL2 |= ADC_CTL2_BUFFER_EN_Msk;
	uint32_t adc_ctl2, adc_temp;
	adc_ctl2 = ADCx->ADC_CTL2;
	adc_temp = ADCx->ADC_TEMP;
//	/* ctlr2 reg */
	adc_ctl2 = (adc_ctl2 & ~(0x7u << 29)) | (0x4u << 29); //bit cycle  3bit
	adc_ctl2 = (adc_ctl2 & ~(0x3u << 27)) | (0x2u << 27); //buffer  chop 2bit
	adc_ctl2 = (adc_ctl2 & ~(0x3u << 11)) | (0x2u << 11); //clk   2bit
	adc_ctl2 = (adc_ctl2 & ~(0x1u << 26)) | (0x1u << 26); //buffer en   1bit
	adc_ctl2 = (adc_ctl2 & ~(0x3fu << 18)) | (0x20u << 18); //vbg trim
	adc_ctl2 = (adc_ctl2 & ~(0x3u << 16)) | (0x0u << 16); //chen   2bit
//	adc_ctl2 = (adc_ctl2 & ~(0x7u << 13)) | (0x1u << 13); //clk_div 3bit, set 1
	
	adc_temp = (adc_temp & ~(0x1u << 31)) | (0x0u << 31); //adc cal cmp en	 1bit
	adc_temp = (adc_temp & ~(0x1u << 30)) | (0x0u << 30); //adc cal cap en    1bit
	adc_temp = (adc_temp & ~(0x7u << 27)) | (0x0u << 27); //adc cal cap sel
	adc_temp = (adc_temp & ~(0x1u << 26)) | (0x0u << 26); //adc cal cap side sel
	adc_temp = (adc_temp & ~(0x3u << 24)) | (0x2u << 24); //adc cal cmp vos
	adc_temp = (adc_temp & ~(0xfu << 20)) | (0x0u << 20); //adc cal cmp vos

	adc_temp = (adc_temp & ~(0x1u << 18)) | (0x0u << 18); //adc vrefp byp en	
	adc_temp = (adc_temp & ~(0x1u << 17)) | (0x1u << 17); //adc vbg en
	adc_temp = (adc_temp & ~(0x1u << 16)) | (0x0u << 16); //diff mode en

	adc_temp = (adc_temp & ~(0x7u << 13)) | (0x0u << 13); //adc pga gain
	adc_temp = (adc_temp & ~(0x1u << 12)) | (0x1u << 12); //GPADC_VBOOST_BYP_EN
	adc_temp = (adc_temp & ~(0x3u << 1)) | (0x0u << 1); //GPADC_VBOOST_TRIM<1:0>
	adc_temp = (adc_temp & ~(0x1u << 0)) | (0x0u << 0); //GPADC_VREF_TEST_EN
	ADCx->ADC_CTL2 = adc_ctl2;     
	ADCx->ADC_TEMP = adc_temp;

    return true;
}

/**
  * @brief Prepare ADC VBG fitting curve paramters due to SoC VBAT level
  * @param[in] ADCx Base address of ADC module
  * @return None
  */
void ADC_PrepareVbgCalibData(ADC_T *ADCx)
{
//    // NOTE1: We assume ADC is already initialized!
//    // NOTE2: We assume ADC input range is already specified!

//    uint32_t chen_bkp = 0;
//    uint32_t sample_code = 0;

//    if (m_adc_opt.ft_version < 3) {
//        // Only use in the SoC which ft_verison >= 3
//        return;
//    }

//    if (ADCx->CTL2 & ADC_SEL_VREF_Msk) {
//        // Only use when the ADC reference is 1.2v VBG
//        return;
//    }

//    if (ADCx->CHEN) {
//        chen_bkp = ADCx->CHEN;
//    }
//    // Enable channel 10 (internal channel connected to vbat/4)
//    ADC_Open(ADCx, ADC_CHEN_CH10_VDD_4_Msk);

//    // Power on ADC
//    ADC_PowerOn(ADCx);

//    // Delay a while to wait adc stable
//    if (m_adc_opt.chip_info >= 0x20) {
//        SYS_delay_10nop(500); // Delay 100us+
//    } else {
//        SYS_delay_10nop(10000); // Delay 3ms+
//    }

//    for (size_t i = 0; i < 8; i++) {
//        /* Start sampling */
//        ADC_StartConvert(ADC);
//        /* Wait for sampling done */
//        while (!ADC_IsDataValid(ADC)) {}
//        /* Process sampling result data */
//        sample_code += ADC_GetConversionData(ADC);
//        // Delay 200us+ to wait adc stable
//        if (m_adc_opt.chip_info < 0x20) {
//            SYS_delay_10nop(1000);
//        }
//    }
//    sample_code /= 8;

//    // Power down ADC
//    ADC_PowerDown(ADC);

//    if (chen_bkp) {
//        ADCx->CHEN = chen_bkp;
//    }

//    global_calc_vbat_mv = ((uint32_t)(m_adc_opt.adc_vbat_k / 10000.0 * sample_code + m_adc_opt.adc_vbat_b / 100.0));;
}


/**
  * @brief Convert adc code to voltage in uV
  * @param[in] ADCx Base address of ADC module
  * @param[in] adc_code Code sampled by ADC module
  * @return ADC sample voltage output in mV
  */
//float ADC_OutputVoltage(ADC_T *ADCx, uint32_t adc_code)
//{
//    float voltage_mv = 0;

//    if (ADCx->CTL2 & ADC_SEL_VREF_Msk)  // Ref src is Vbat
//    {
//        voltage_mv = m_adc_opt.adc_vdd_k / 10000.0 * adc_code + m_adc_opt.adc_vdd_b; // code to code
//        voltage_mv = voltage_mv * global_calc_vbat_mv / 4096;
//    }
//    else    // Ref src is ADC VBG (1.2v)
//    {
//        if (m_adc_opt.ft_version >= 3)
//        {
//            uint32_t calc_vbat_mv = global_calc_vbat_mv;
//            uint32_t vol_list[] = {1800, 2100, 2400, 2700, 3000, 3300, 3600};
//            float V1, V2;
//            float A;
//            uint8_t vol_index = 0;
//            for (uint8_t i = 0; i < 7; i++)
//            {
//                if (calc_vbat_mv <= vol_list[0])
//                {
//                    voltage_mv = (float)m_adc_opt.adc_vbg_kb[0].adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_kb[0].adc_vbg_b / 100.0;
//                    break;
//                }
//                else if (calc_vbat_mv >= vol_list[6])
//                {
//                    voltage_mv = (float)m_adc_opt.adc_vbg_kb[6].adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_kb[6].adc_vbg_b / 100.0;
//                    break;
//                }

//                if (calc_vbat_mv < vol_list[i])
//                {
//                    vol_index = i;
//                    V1 = (float)m_adc_opt.adc_vbg_kb[vol_index - 1].adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_kb[vol_index - 1].adc_vbg_b / 100.0;
//                    V2 = (float)m_adc_opt.adc_vbg_kb[vol_index].adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_kb[vol_index].adc_vbg_b / 100.0;
//                    A = (float)(calc_vbat_mv - vol_list[vol_index - 1]) / 300;
//                    voltage_mv = A * V2 + (1 - A) * V1;
//                    break;
//                }
//            }
//        }
//        else
//        {
//            voltage_mv = m_adc_opt.adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_b / 100.0;
//        }
//    }

//    return voltage_mv;
//}

/**
  * @brief get caliration params relatd adc ft process
  * @param[in] ADC_OPT_T    hold adc ft parameters
  * @return NULL
  */
void ADC_SetCalirationParams(OTP_STRUCT_T *opt)
{

}

/**
  * @brief Measure SoC Temperature More Fast using the ADC internal Channel 9
  * @param[in] ADCx Base address of ADC module
  * @return ADC measured temperature in Celsius
  */
//float ADC_MeasureSocTemperatureFast(ADC_T *ADCx)
//{
//    uint32_t temp_code = 0;
//    float temp_param_k = (m_adc_opt.chip_info >= 0x20) ? (m_adc_opt.ft_version >= 6 ? m_adc_opt.adc_temp_k : 0.35) : -0.69; // t = k * (v - vFT) + tFT
//    float voltage = 0;
//    uint16_t temp_code_arr[128];

//    // Check if current chip support this API
//    if (m_adc_opt.chip_info < 0x20) {
//        return -1.0f;
//    }

//    // Enable ADC channel 9
//    ADC_Open(ADCx, ADC_CHEN_CH9_TMP_Msk);

//    // Change ADC Ref to ADC-VBG (1.2v) if is not
//    if (ADCx->CTL2 & ADC_SEL_VREF_Msk) {
//        ADC_SelInputRange(ADCx, ADC_INPUTRANGE_LOW);
//    }

//    // Prepare ADC vbg calib paramter due to currnet soc vbat after setting input range to the 0~1.2v ref
//    ADC_PrepareVbgCalibData(ADCx);

//    // Power on ADC
//    ADC_PowerOn(ADCx);

//    // Delay a while to wait adc stable
//    SYS_delay_10nop(500); // Delay 100us+

//    // Start sampling
//    for (int i = 0; i < 128; i++) {
//        ADC_StartConvert(ADCx);
//        // Wait for sampling done
//        while (!ADC_IsDataValid(ADCx)) {
//        }
//        // Process sampling result data
//        temp_code_arr[i] = ADC_GetConversionData(ADCx);
//    }

//    // Power down ADC
//    ADC_PowerDown(ADCx);

//    // Filter out largest 8 and smallest 8 data and calculate average value
//    bubble_sort_uint16(temp_code_arr, 128);
//    for (int i = 8; i < 120; i++) {
//        temp_code += temp_code_arr[i];
//    }
//    temp_code /= 112;

//    // Calculate voltage of temp sensor
//    voltage = ADC_OutputVoltage(ADCx, temp_code);

//    // Calculate and return current temp by formula: t = k * (v - vFT) + tFT - tDelta
//    return temp_param_k * (voltage - (double)m_adc_opt.adc_temp_volt / 10.0) + (double)m_adc_opt.current_temp_value / 100.0
//        - (m_adc_opt.ft_version >= 5 ? ((double)m_adc_opt.adc_vbat_dtemp_k / 10000000.0 * global_calc_vbat_mv + (double)m_adc_opt.adc_vbat_dtemp_b / 1000.0) : 0);
//}

/**
  * @brief Measure SoC VBAT using the ADC internal Channel 10
  * @param[in] ADCx Base address of ADC module
  * @return ADC measured VBAT voltage in mV
  */
//uint16_t ADC_MeasureSocVbat(ADC_T *ADCx)
//{
//    uint32_t u32TempReg = 0;
//    float voltage = 0;
//    float temp_voltage_arr[32];

//    // Enable channel 10 (internal channel connected to vbat/4)
//    ADC_Open(ADCx, ADC_CHEN_CH10_VDD_4_Msk);

//    // Change ADC Ref to ADC-VBG (1.2v) if is not
//    if (ADCx->CTL2 & ADC_SEL_VREF_Msk) {
//        ADC_SelInputRange(ADCx, ADC_INPUTRANGE_LOW);
//    }

////    if (m_adc_opt.chip_info < 0x20) {
////        // Prepare ADC vbg calib paramter due to currnet soc vbat after setting input range to the 0~1.2v ref
////        ADC_PrepareVbgCalibData(ADCx);
////    }

//    // Power on ADC
//    ADC_PowerOn(ADCx);

//    // Delay a while to wait adc stable
//    if (m_adc_opt.chip_info >= 0x20) {
//        SYS_delay_10nop(500); // Delay 100us+
//    } else {
//        SYS_delay_10nop(50000); // Delay 15ms+
//    }

//    // Start sampling
//    for (int i = 0; i < 32; i++) {
//        ADC_StartConvert(ADCx);
//        // Wait for sampling done
//        while (!ADC_IsDataValid(ADCx)) {
//        }
//        // Process sampling result data
//        u32TempReg = ADC_GetConversionData(ADCx);
//        if (m_adc_opt.ft_version >= 3) {
//            temp_voltage_arr[i] = ((float)(m_adc_opt.adc_vbat_k / 10000.0 * u32TempReg + m_adc_opt.adc_vbat_b / 100.0));
//        } else {
//            temp_voltage_arr[i] = ADC_OutputVoltage(ADCx, u32TempReg);
//        }
//    }

//    // Power down ADC
//    ADC_PowerDown(ADCx);

//    // Filter out largest 8 and smallest 8 data and calculate average value
//    bubble_sort_float(temp_voltage_arr, 32);
//    for (int i = 8; i < 24; i++) {
//        voltage += temp_voltage_arr[i];
//    }
//    voltage /= 16;

//    if (m_adc_opt.ft_version < 3) {
//        voltage = (uint16_t)(4 * voltage + 0.5); // Rounding off
//    }

//    return voltage;
//}


void ADC_SetWeightRatio(ADC_T *ADCx, ADC_WEIGHT_OPT_T WeightOpt)
{
	ADCx->ADC_WDR1 = WeightOpt.weight_difference_1_t.weight_difference_1;
	ADCx->ADC_WDR2 = WeightOpt.weight_difference_2_t.weight_difference_2;
	ADCx->ADC_WDR3 = WeightOpt.weight_difference_3_t.weight_difference_3;
	ADCx->ADC_WDR4 = WeightOpt.weight_difference_4_t.weight_difference_4;
	ADCx->ADC_WDR5 = WeightOpt.weight_difference_5_t.weight_difference_5;
}

void ADC_VrefVoltageSelect(ADC_T *ADCx, uint32_t Vref)
{
	if (ADC_VREF_VOL_SEL_VBG == Vref) {
		ADCx->ADC_TEMP |= ADC_TEMP_GPADC_VREFP_VBG_EN_Msk;
	} else if (ADC_VREF_VOL_SEL_VBAT == Vref) {
		ADCx->ADC_TEMP &= ~ADC_TEMP_GPADC_VREFP_VBG_EN_Msk;
		ADCx->ADC_TEMP |= ADC_TEMP_GPADC_VREFP_BYP_EN_Msk;
	} else {
		ADCx->ADC_TEMP &= ~ADC_TEMP_GPADC_VREFP_BYP_EN_Msk;
		ADCx->ADC_TEMP &= ~ADC_TEMP_GPADC_VREFP_VBG_EN_Msk;
	}
}

void ADC_ReadFifo(ADC_T *ADCx, uint16_t *Data)
{
	while (false == ADC_StatusFlag(ADC, ADC_STATUS_FIFO_EMPTY_FALG_Msk)) {
		*Data = ADC_GetConversionData(ADC);
		Data++;
	}
}


bool ADC_IsIntOccurred(ADC_T *ADCx,uint32_t IntFlag, uint32_t IntMask)
{
	if (ADC_StatusFlag(ADCx, IntFlag) && ADC_IsIntEnabled(ADCx, IntMask)) {
		return true;
	} else {
		return false;
	}
}

/*@}*/ /* end of group Panchip_ADC_EXPORTED_FUNCTIONS */

/*@}*/ /* end of group Panchip_ADC_Driver */

/*@}*/ /* end of group Panchip_Device_Driver */

/*** (C) COPYRIGHT 2016 Panchip Technology Corp. ***/
