#include "lks32mc09x_adc.h"
#include "lks32mc09x_sys.h"
#include "lks32mc09x_trim.h"
#include "lks32mc09x_user_manual.h"

/**
 * @brief 使能ADC模块
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 */
void ADC_Enable(ADC_TypeDef *ADCx)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    // 使能ADC模块时钟
    if ((ADCx == ADC0) || (ADCx == ADC1))
    {
        REG_SET(SYS0->AFE_REG7, SYS_AFE_REG7_SHAPDN_BIT | SYS_AFE_REG7_ADCPDN_BIT);
    }
    REG_WRITE(SYS0->PROTECT, 0);
}

/**
 * @brief 禁用ADC模块
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 */
void ADC_Disable(ADC_TypeDef *ADCx)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    // 关闭ADC模块时钟
    if ((ADCx == ADC0) || (ADCx == ADC1))
    {
        REG_RESET(SYS0->AFE_REG7, SYS_AFE_REG7_SHAPDN_BIT | SYS_AFE_REG7_ADCPDN_BIT);
    }
    REG_WRITE(SYS0->PROTECT, 0);
}

/**
 * @brief 复位ADC模块
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 */
void ADC_Reset(ADC_TypeDef *ADCx)
{
    if (ADCx == ADC0)
    {
        SYS_SoftResetModule(SYS_MODULE_ADC0);
    }
    else if (ADCx == ADC1)
    {
        SYS_SoftResetModule(SYS_MODULE_ADC1);
    }
    else
    {
        __NOP();
    }
}

/**
 * @brief 初始化ADC模块
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 * @param ADC_InitStruct: 指向ADC初始化结构体的指针
 */
void ADC_Init(ADC_TypeDef *ADCx, ADC_InitTypeDef *ADC_InitStruct)
{
    ADC_Enable(ADCx);
    SYS_ModuleClockCmd(SYS_MODULE_ADC0, 1);
    SYS_ModuleClockCmd(SYS_MODULE_ADC1, 1);

    if (ADC_InitStruct->S2 == 0)
    {
        ADC_InitStruct->NSMP = DISABLE; // 当第二段采样次数为0时，不允许配置第二段使能
    }

    // 解锁SYS寄存器
    REG_WRITE(SYS0->PROTECT, 0x7a83);

    // 配置ADC初始化结构体中的各个成员
    REG_WRITE(ADCx->IE, ADC_InitStruct->IE | ADC_InitStruct->RE);

    // 计算并一次性配置CFG寄存器
    REG_WRITE(ADCx->CFG, ((ADC_InitStruct->NSMP << 12) |
                          (1 << 11) | // 初始化时复位adc状态机
                          (ADC_InitStruct->DATA_ALIGN << 10) |
                          (ADC_InitStruct->IDLE_PRI << 9) |
                          (ADC_InitStruct->CSMP << 8) |
                          (ADC_InitStruct->TCNT << 4) |
                          (ADC_InitStruct->TROVS << 3) |
                          (ADC_InitStruct->OVSR << 0)));

    REG_WRITE(ADCx->TRIG, ADC_InitStruct->TRIG);

    // 配置CHNT寄存器
    REG_WRITE(ADCx->CHNT, (REG_READ(ADCx->CHNT) & ~((0x0F << 0) | (0x0F << 4) | (0x0F << 8))) |
                              ((ADC_InitStruct->S1 << 0) |
                               (ADC_InitStruct->S2 << 4) |
                               (ADC_InitStruct->IS1 << 8)));

    // 配置GAIN寄存器
    REG_WRITE_BIT(ADCx->GAIN, 1 << 0, ADC_InitStruct->GAIN << 0);

    REG_WRITE(ADCx->LTH, ADC_InitStruct->LTH);
    REG_WRITE(ADCx->HTH, ADC_InitStruct->HTH);
    REG_WRITE(ADCx->GEN, ADC_InitStruct->GEN);
    if (ADCx == ADC0)
    {
        REG_WRITE(ADCx->AMC0, TRIM_Read(NVR_ADDR_ADC_0_AMC0));
        REG_WRITE(ADCx->DC0, TRIM_Read(NVR_ADDR_ADC_0_DC0));
        REG_WRITE(ADCx->AMC1, TRIM_Read(NVR_ADDR_ADC_0_AMC1));
        REG_WRITE(ADCx->DC1, TRIM_Read(NVR_ADDR_ADC_0_DC1));
    }
    else if (ADCx == ADC1)
    {
        REG_WRITE(ADCx->AMC0, TRIM_Read(NVR_ADDR_ADC_1_AMC0));
        REG_WRITE(ADCx->DC0, TRIM_Read(NVR_ADDR_ADC_1_DC0));
        REG_WRITE(ADCx->AMC1, TRIM_Read(NVR_ADDR_ADC_1_AMC1));
        REG_WRITE(ADCx->DC1, TRIM_Read(NVR_ADDR_ADC_1_DC1));
    }
    else
    {
        __NOP();
    }
}

/**
 * @brief 将ADC初始化结构体置为默认值
 * @param ADC_InitStruct: 指向ADC初始化结构体的指针
 */
void ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct)
{
    uint32_t i;
    for (i = 0; i < sizeof(ADC_InitTypeDef); i++)
    {
        ((uint8_t *)ADC_InitStruct)[i] = 0;
    }
}

/**
 * @brief 获取ADC中断标志位状态
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 * @param INT_flag: 中断标志位，可以是ADC_IF_ISF等
 * @return 中断标志位状态
 */
uint16_t ADC_GetIRQFlag(ADC_TypeDef *ADCx, uint16_t INT_flag)
{
    return REG_READ_BIT(ADCx->IF, INT_flag) ? 1 : 0;
}

/**
 * @brief 清除ADC中断标志位
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 * @param INT_flag: 中断标志位，可以是ADC_IF_ISF等
 */
void ADC_ClearIRQFlag(ADC_TypeDef *ADCx, uint16_t INT_flag)
{
    REG_WRITE(ADCx->IF, INT_flag);
}

/**
 * @brief 设置ADC通道的增益
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 * @param DAT_x: 数据寄存器序号，如ADC_DAT_0表示第0次采样结果
 * @param gainx: 增益选择，如ADC_GAIN_3V6
 */
void ADC_SetGain(ADC_TypeDef *ADCx, ADC_DAT_x DAT_x, ADC_GAIN_x gainx)
{
    REG_WRITE_BIT(ADCx->GAIN, 1 << DAT_x, gainx << DAT_x);
}

/**
 * @brief 获取ADC通道的转换值
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 * @param DATNum: 数据寄存器序号，如ADC_DAT_0
 * @return 转换值
 */
s16 ADC_GetConversionValue(ADC_TypeDef *ADCx, ADC_DAT_x DATNum)
{
    int32_t adc_dat = ADC_GetConversionValueS32(ADCx, DATNum);
    // adc_dat不会小于-32767，这里不做判断
    if (adc_dat > 32767)
    {
        adc_dat = 32767;
    }
    return adc_dat;
}

/**
 * @brief 获取ADC通道的转换值(按int32返回，采样通道4、5、6、7时，返回值大于32767)
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 * @param DATNum: 数据寄存器序号，如ADC_DAT_0
 * @return 转换值
 */
int32_t ADC_GetConversionValueS32(ADC_TypeDef *ADCx, ADC_DAT_x DATNum)
{

    int32_t adc_dat  = 0;
    uint16_t adc_chn = 0;
    switch (DATNum)
    {
        case ADC_DAT_0:
            adc_dat = REG_READ(ADCx->DAT0);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN0, ADC0_CHN0_PDS0);
            break;
        case ADC_DAT_1:
            adc_dat = REG_READ(ADCx->DAT1);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN0, ADC0_CHN0_PDS1);
            break;
        case ADC_DAT_2:
            adc_dat = REG_READ(ADCx->DAT2);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN0, ADC0_CHN0_PDS2);
            break;
        case ADC_DAT_3:
            adc_dat = REG_READ(ADCx->DAT3);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN0, ADC0_CHN0_PDS3);
            break;
        case ADC_DAT_4:
            adc_dat = REG_READ(ADCx->DAT4);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN1, ADC0_CHN1_PDS4);
            break;
        case ADC_DAT_5:
            adc_dat = REG_READ(ADCx->DAT5);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN1, ADC0_CHN1_PDS5);
            break;
        case ADC_DAT_6:
            adc_dat = REG_READ(ADCx->DAT6);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN1, ADC0_CHN1_PDS6);
            break;
        case ADC_DAT_7:
            adc_dat = REG_READ(ADCx->DAT7);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN1, ADC0_CHN1_PDS7);
            break;
        case ADC_DAT_8:
            adc_dat = REG_READ(ADCx->DAT8);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN2, ADC0_CHN2_PDS8);
            break;
        case ADC_DAT_9:
            adc_dat = REG_READ(ADCx->DAT9);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN2, ADC0_CHN2_PDS9);
            break;
        case ADC_DAT_10:
            adc_dat = REG_READ(ADCx->DAT10);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN2, ADC0_CHN2_PDS10);
            break;
        case ADC_DAT_11:
            adc_dat = REG_READ(ADCx->DAT11);
            adc_chn = REG_READ_BIT_POS_MASK(ADCx->CHN2, ADC0_CHN2_PDS11);
            break;
        default:
            adc_dat = 0;
            break;
    }
    // 先按照int16处理一下
    adc_dat = (int16_t)(adc_dat & 0xffff);
    // ADC0/1采样公共通道4/5/6/7时，负端电压为2.4V，实际允许的输入电压范围是
    // 仅内部基准有效
    if ((adc_chn == 4) || (adc_chn == 5) || (adc_chn == 6) || (adc_chn == 7))
    {
        int32_t dat = adc_dat;
        // 使用外部基准时需要手动处理
        if (REG_READ_BIT(SYS_AFE_REG4, SYS_AFE_REG4_REF2VDD_BIT) == 0)
        {
            if (REG_READ_BIT(ADC0_CFG, ADC0_CFG_DATA_ALIGN_BIT) == 0)
            { // 左对齐
                dat     = dat + 0x5550;
                adc_dat = dat;
            }
            else
            { // 右对齐
                dat     = dat + 0x555;
                adc_dat = dat;
            }
        }
    }
    return adc_dat;
}
/**
 * @brief 执行软件触发ADC采样，采样次数取决于ADC_InitTypeDef里的S1的配置
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 */
void ADC_SoftTrig(ADC_TypeDef *ADCx)
{
    // 写入软件触发值
    REG_WRITE(ADCx->SWT, 0x5AA5);
}

/**
 * @brief 执行软件触发ADC空闲采样
 * @param ADCx: ADC模块指针，指向ADC0
 */
void ADC_SoftIdleTrig(ADC_TypeDef *ADCx)
{
    // 写入软件触发值
    REG_WRITE(ADCx->SWT, 0xf00f);
}

/**
 * @brief 设置第每次的采样通道，例如ADC_SetChn(ADC0,ADC_DAT_0,ADC_CHN_0),把adc第一次采样的通道设置为通道0
 * @param ADCx: ADC模块指针，指向ADC0或ADC1
 * @param datx: 数据寄存器序号，如ADC_DAT_0
 * @param chnx: ADC采样通道序号枚举定义，如ADC_CHN_0
 */
void ADC_SetChn(ADC_TypeDef *ADCx, ADC_DAT_x datx, ADC_CHN_x chnx)
{
    uint8_t n = (datx & 0x3) * 4;
    switch (datx)
    {
        case ADC_DAT_0:
            REG_WRITE(ADCx->CHN0, (REG_READ(ADCx->CHN0) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_1:
            REG_WRITE(ADCx->CHN0, (REG_READ(ADCx->CHN0) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_2:
            REG_WRITE(ADCx->CHN0, (REG_READ(ADCx->CHN0) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_3:
            REG_WRITE(ADCx->CHN0, (REG_READ(ADCx->CHN0) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_4:
            REG_WRITE(ADCx->CHN1, (REG_READ(ADCx->CHN1) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_5:
            REG_WRITE(ADCx->CHN1, (REG_READ(ADCx->CHN1) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_6:
            REG_WRITE(ADCx->CHN1, (REG_READ(ADCx->CHN1) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_7:
            REG_WRITE(ADCx->CHN1, (REG_READ(ADCx->CHN1) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_8:
            REG_WRITE(ADCx->CHN2, (REG_READ(ADCx->CHN2) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_9:
            REG_WRITE(ADCx->CHN2, (REG_READ(ADCx->CHN2) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_10:
            REG_WRITE(ADCx->CHN2, (REG_READ(ADCx->CHN2) & (~(0xf << n))) | (chnx << n));
            break;
        case ADC_DAT_11:
            REG_WRITE(ADCx->CHN2, (REG_READ(ADCx->CHN2) & (~(0xf << n))) | (chnx << n));
            break;
    }
}

/**
 * @brief 设置ADC基准电压
 * @param ADCx ADC模块指针,注意：adc0和adc1共用同一个基准电压
 * @param rangex 基准选择
 */
void ADC_SetRange(ADC_TypeDef *ADCx, ADC_RANGE_x rangex)
{
    if ((ADCx == ADC0) || (ADCx == ADC1))
    {
        REG_WRITE(SYS_WR_PROTECT, 0x7a83);
        switch (rangex)
        {
            case ADC_RANGE_3_3: ///< 3.3V基准
                REG_SET(SYS_AFE_REG0, BIT15);
                REG_RESET(SYS_AFE_REG4, BIT4);
                break;
            case ADC_RANGE_EXTERNAL: ///< 外部基准
                REG_RESET(SYS_AFE_REG0, BIT15);
                REG_SET(SYS_AFE_REG4, BIT4);
                break;
            default:            // 默认配置为3.6V基准
            case ADC_RANGE_3_6: ///< 3.6V基准
                REG_RESET(SYS_AFE_REG0, BIT15);
                REG_RESET(SYS_AFE_REG4, BIT4);
                break;
        }
        REG_WRITE(SYS_WR_PROTECT, 0);
    }
}
