#include "lks32mc09x_sys.h"
#include "lks32mc09x_user_manual.h"

/**
 * @brief 数字模块时钟使能
 * @param nModule 模块编号
 * @param state 使能或禁用状态
 */
void SYS_ModuleClockCmd(uint32_t nModule, uint8_t state)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    if (state)
    {
        REG_SET(SYS0->CLK_FEN, nModule);
    }
    else
    {
        REG_RESET(SYS0->CLK_FEN, nModule);
    }
    REG_WRITE(SYS0->PROTECT, 0);
}

/**
 * @brief 软复位模块
 * @param nModule 模块编号
 */
void SYS_SoftResetModule(uint32_t nModule)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    REG_SET(SYS0->SFT_RST, nModule);
    REG_RESET(SYS0->SFT_RST, nModule); // 触发复位后需清除复位位
    REG_WRITE(SYS0->PROTECT, 0);
}

/**
 * @brief 软复位所有模块
 */
void SYS_SoftReset_all(void)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    REG_WRITE(SYS0->SFT_RST, 0xFFFFFFFF);
    REG_WRITE(SYS0->SFT_RST, 0x00000000); // 触发复位后需清除所有复位位
    REG_WRITE(SYS0->PROTECT, 0);
}

/**
 * @brief 选择系统时钟
 * @param SYS_MCLK_x 时钟源选择
 * @see 使用外部晶振时，除了晶振使能外，还需要配置
 * SYS_AFE_REG1_XTAL_FLT_BIT  [9] 晶振低通滤波关闭 1:关闭 0:打开
 * SYS_AFE_REG1_XTAL_SCHT_BIT [4] 晶振选择反相器或者施密特 1:反相器 0:施密特
 * SYS_AFE_REG2_XTAL_RSEL_BIT [8] 晶体起振电路电阻调节 0:P端电阻维持原值 1: P端电阻增加一倍
 */
void SYS_MclkChoice(uint32_t SYS_MCLK_x)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    if (SYS_MCLK_x & 0x8000) // 使用外部晶振
    {
        REG_SET(SYS_AFE_REG5, BIT4);
    }
    else
    {
        REG_RESET(SYS_AFE_REG5, BIT4);
    }
    REG_WRITE_BIT(SYS0->CLK_CFG, 0x3ff, SYS_MCLK_x);
    {
        int cnt;
        for (cnt = 0; cnt < 4000; cnt++)
        {
            __NOP();
        }
    }
    REG_WRITE(SYS0->PROTECT, 0);
}

/**
 * @brief UART时钟分频
 * @param div 分频系数
 */
void SYS_UartClkDiv(uint16_t div)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    REG_WRITE(SYS0->CLK_DIV2, div);
    REG_WRITE(SYS0->PROTECT, 0);
}

/**
 * @brief I2C时钟分频
 * @param div 分频系数
 */
void SYS_I2CClkDiv(uint16_t div)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    REG_WRITE(SYS0->CLK_DIV0, div);
    REG_WRITE(SYS0->PROTECT, 0);
}

/**
 * @brief SPI时钟分频
 * @param div 分频系数
 */
void SYS_SPIClkDiv(uint16_t div)
{
    // 保留接口，09x的SPI时钟只需要配置模块本身的分频即可
    if (div != 0)
    {
        __NOP();
    }
}

/**
 * @brief 获取当前MCU时钟
 * @return 当前MCU时钟频率
 */
uint32_t SYS_ReadMcuClk(void)
{
    uint32_t clk    = 96000000;
    uint32_t clkdiv = (SYS_CLK_CFG & SYS_CLK_CFG_CLK_DIV_MASK) >> SYS_CLK_CFG_CLK_DIV_POS;
    uint32_t clksel = (SYS_CLK_CFG & SYS_CLK_CFG_CLK_SEL_MASK) >> SYS_CLK_CFG_CLK_SEL_POS;
    switch (clksel) //  0: HRC 1: PLL 2: LRC
    {
        case 0: // HRC
            clk = 8000000;
            break;
        case 1: // PLL
            switch (clkdiv)
            {
                case 0xff: // 96M
                    clk = 96000000;
                    break;
                case 0x55: // 48M
                    clk = 48000000;
                    break;
                case 0x11: // 24M
                    clk = 24000000;
                    break;
                case 0x01: // 12M
                    clk = 12000000;
                    break;
                case 0x00: // 12M
                    clk = 12000000;
                    break;
                default: // 逐位计算
                    clk = 0;
                    for (int i = 0; i < 8; i++)
                    {
                        if (clkdiv & (1 << i))
                        {
                            clk += 12000000;
                        }
                        else
                        {
                            __NOP();
                        }
                    }
                    break;
            }
            break;
        case 2: // LRC
            clk = 32000;
            break;
        default:
            break;
    }
    return clk;
}

/**
 * @brief 掉电检测配置
 * @param SYS_PVDSEL_x 掉电检测配置值，可选：
 * - SYS_PVDSEL_4_0V    4.0V
 * - SYS_PVDSEL_3_74V   3.74V
 * - SYS_PVDSEL_3_49V   3.49V
 * - SYS_PVDSEL_2_8V    2.8V
 * - SYS_PVDSEL_DAC     DAC (这里使用的是DAC0)
 * - SYS_PVDSEL_OFF     OFF
 */
void SYS_SetPowerFailureDetection(uint32_t SYS_PVDSEL_x)
{
    REG_WRITE(SYS0->PROTECT, 0x7a83);
    REG_WRITE_BIT(SYS0->AFE_REG5, SYS_AFE_REG5_RSTSEL_MASK, SYS_AFE_REG5_RSTSEL(1));
    REG_WRITE_BIT(SYS0->AFE_REG0, (SYS_AFE_REG0_PVDSEL_MASK | SYS_AFE_REG0_PD_PDT_BIT | SYS_AFE_REG0_VSR_PDT_BIT), SYS_PVDSEL_x);
    REG_WRITE(SYS0->PROTECT, 0);
}
/**
 * @brief 等待电源就绪
 * @param SYS_PVDSEL_x 电源电压检测阈值配置，可选：
 * - SYS_PVDSEL_4_0V    4.0V
 * - SYS_PVDSEL_3_74V   3.74V
 * - SYS_PVDSEL_3_49V   3.49V
 * - SYS_PVDSEL_2_8V    2.8V
 * 注意：SYS_PVDSEL_DAC暂不支持
 * @note 使用前确保已配置PWRDN中断（如需要）
 * @code
void SystemInit()
{
    SYS_WaitPowerReady(SYS_PVDSEL_4_0V); // 等待电源就绪
    NVIC_SetPriority(PWRDN_IRQn, 0);     // 掉电检测中断优先级配置
    NVIC_EnableIRQ(PWRDN_IRQn);          // 使能掉电检测中断
    // 其他初始化代码
}
void PWRDN_IRQHandler(void) {
    __disable_irq();
    SYS_ResetPeripheral();
    NVIC_SystemReset();
}
 * @endcode
 */
void SYS_WaitPowerReady(uint32_t SYS_PVDSEL_x)
{
    // 通常SYS_WaitPowerReady执行时全局中断处于关闭状态。
    // 为了确保兼容性，这里使用原子锁进行处理。
    uint32_t flg = __get_PRIMASK();
    __disable_irq();
    // 设置掉电检测电压
    SYS_SetPowerFailureDetection(SYS_PVDSEL_x);
    // 等待电源就绪
    while (REG_READ_BIT(SYS0->AFE_DBG, SYS_AFE_DBG_PWR_WEAK_BIT))
    {
        __NOP();
    }
    // 电源就绪后清除中断标志位，上电过程中一定会触发一次掉电中断
    NVIC_ClearPendingIRQ(PWRDN_IRQn);
    __set_PRIMASK(flg); // 还原中断状态
}

/**
 * @brief 复位所有外设到默认状态（芯片上电后的状态）
 * @warning 不复位的寄存器有：
 *              复位事件记录寄存器
 *              后备存储器
 *              ram
 *              校准寄存器（仅限于上电会自动加载的校准寄存器）
 *              只读的寄存器
 *              部分flash寄存器（如FLASH->WDATA等，写入操作无意义）
 *              所有内核的寄存器
 */
void SYS_ResetPeripheral(void)
{
    SYS_ResetIO();
    SYS_ResetPeripheralInternal();
}
/**
 * @brief 复位所有内部外设为默认值(除io的所有模块)
 * @warning 不复位的寄存器有：
 *              复位事件记录寄存器
 *              后备存储器
 *              ram
 *              校准寄存器（仅限于上电会自动加载的校准寄存器）
 *              只读的寄存器
 *              部分flash寄存器（如FLASH->WDATA等，写入操作无意义）
 *              所有内核的寄存器
 */
void SYS_ResetPeripheralInternal(void)
{
    uint32_t flg = __get_PRIMASK();
    __disable_irq();
    SYS->PROTECT      = 0x7a83;
    SYS->SFT_RST      = (0xffffffff & ~BIT11); // 复位除GPIO之外的所有模块
    SYS->SFT_RST      = 0;
    SYS->AFE_REG0     = 0;
    SYS->AFE_REG1     = 0;
    SYS->AFE_REG2     = 0;
    SYS->AFE_REG3     = 0;
    SYS->AFE_REG4     = 0;
    SYS->AFE_REG5     = 0;
    SYS->AFE_REG7     = 0;
    SYS->AFE_DAC_CTRL = 0;
    SYS->AFE_DAC0     = 0;
    SYS->AFE_DAC1     = 0;

    SYS->CLK_CFG = 0;
    {
        int cnt;
        for (cnt = 0; cnt < 4000; cnt++)
        {
            __NOP();
        }
    }
    SYS->IO_CFG   = 0;
    SYS->DBG_CFG  = 0;
    SYS->CLK_DIV0 = 0;
    SYS->CLK_DIV1 = 0;
    SYS->CLK_DIV2 = 0;
    SYS->CLK_FEN  = 0;
    SYS->RAM_LOCK = 0;
    SYS->SFT_RST  = 0;
    SYS->FLSE     = 0;
    SYS->FLSP     = 0;
    SYS->PROTECT  = 0;

    FLASH->CFG   = 0xe0;
    FLASH->ADDR  = 0;
    FLASH->NADDR = 0;
    FLASH->NKEY  = 0;
    {
        uint32_t reg = FLASH->PROTECT; // 更新falsh状态
        if (reg != 0)
        {
            __NOP();
        }
    }
    __set_PRIMASK(flg);
}
/**
 * @brief 复位所有IO为默认值（gpio以及部分和io有关的sys寄存器）
 */
void SYS_ResetIO(void)
{
    uint32_t flg = __get_PRIMASK();
    __disable_irq();
    SYS_WR_PROTECT = 0x7a83;
    SYS_SFT_RST    = BIT11; // 复位GPIO，GPIO0 GPIO1 GPIO2三个模块的所有寄存器
    SYS_SFT_RST    = 0;
    SYS_AFE_REG1 &= ~BIT8;                                           // 关闭LDO输出到P0.0
    SYS_AFE_REG2 &= ~(BIT15 | BIT14 | BIT13 | BIT11 | BIT10 | 0xff); // 关闭dac、vref、vbgp、opa输出到P0.0
    SYS_IO_CFG     = 0;                                              // 恢复SWD&RST为默认状态
    SYS_WR_PROTECT = 0;
    __set_PRIMASK(flg);
}
