#include "lks32mc09x_wake.h"

/**
 * @brief 清除休眠事件记录
 */
void WAKE_EVTCLRSleep(void)
{
    // 清除深度休眠记录
    AON0->EVT_RCD &= ~BIT13;
}

/**
 * @brief 进入低功耗模式，必须定义WAKE_IRQHandler函数，WAKE_IRQHandler内可以不做任何操作
 */
void WAKE_FallSleep(void)
{
    int irqstate;
    uint16_t sys_reg_0;
    uint16_t sys_reg_1;
    uint16_t sys_reg_2;
    uint16_t sys_reg_3;
    uint16_t sys_reg_4;
    uint16_t sys_reg_5;
    uint16_t sys_reg_7;
    uint32_t sys_clk_fen;
    uint32_t sys_clk_cfg;
    uint32_t nvic_state;        // 各个使能的状态
    irqstate = __get_PRIMASK(); // 保存全局中断状态
    __disable_irq();            // 关闭全局中断

    SYS_WR_PROTECT = 0x7a83; /*开启寄存器写使能*/
    sys_reg_0      = SYS_AFE_REG0;
    sys_reg_1      = SYS_AFE_REG1;
    sys_reg_2      = SYS_AFE_REG2;
    sys_reg_3      = SYS_AFE_REG3;
    sys_reg_4      = SYS_AFE_REG4;
    sys_reg_5      = SYS_AFE_REG5;
    sys_reg_7      = SYS_AFE_REG7;
    sys_clk_fen    = SYS_CLK_FEN;
    sys_clk_cfg    = SYS_CLK_CFG;
    SYS_AFE_REG0   = 0;
    SYS_AFE_REG1   = BIT11 | BIT10; // 关闭BGP和RCH
    SYS_AFE_REG2   = 0;
    SYS_AFE_REG3   = 0;
    SYS_AFE_REG4   = 0;
    SYS_AFE_REG5   = (sys_reg_5 & (BIT8 | BIT9)); // 保持复位电压阈值不变
    SYS_AFE_REG7   = 0;
    SYS_CLK_FEN    = 0;
    SYS_CLK_CFG    = 0x0;
    {
        int cnt;
        for (cnt = 0; cnt < 4000; cnt++)
        {
            __NOP();
        }
    }
    SYS_WR_PROTECT = 0x0;

    nvic_state    = NVIC->ICER[0];
    NVIC->ICER[0] = 0xffffffff;     // 关闭所有中断
    NVIC_EnableIRQ(WAKE_IRQn);      /* 使能WAKE中断 */
    NVIC_SetPriority(WAKE_IRQn, 0); /* 配置WAKE中断优先级 */
    IWDG_PSW = 0xA6B4;
    IWDG_CLR = 0x798D;
    SCB->SCR |= (1UL << 2);
    __enable_irq();
    __WFI(); // 使用WFI指令进入休眠模式

    // 休眠后程序会停在这里，唤醒后会执行WAKE_IRQHandler中断，随后从这里继续执行
    __disable_irq();
    SYS_WR_PROTECT = 0x7a83; /*开启寄存器写使能*/
    SYS_AFE_REG0   = sys_reg_0;
    SYS_AFE_REG1   = sys_reg_1;
    SYS_AFE_REG2   = sys_reg_2;
    SYS_AFE_REG3   = sys_reg_3;
    SYS_AFE_REG4   = sys_reg_4;
    SYS_AFE_REG5   = sys_reg_5;
    SYS_AFE_REG7   = sys_reg_7;
    SYS_CLK_FEN    = sys_clk_fen;
    {
        int cnt;
        for (cnt = 0; cnt < 4000; cnt++)
        {
            __NOP();
        }
    }
    SYS_CLK_CFG = sys_clk_cfg;
    {
        int cnt;
        for (cnt = 0; cnt < 4000; cnt++)
        {
            __NOP();
        }
    }
    SYS_WR_PROTECT = 0x0;
    __set_PRIMASK(irqstate); // 还原中断状态
    NVIC->ISER[0] = nvic_state;
}

/**
 * @brief 设置唤醒间隔时间
 * @param rth 唤醒复位阈值，由于计数器计数阈值是从复位阈值开始计数的，所有唤醒阈值必须大于复位阈值
 * @param wth 唤醒阈值
 * @param ena 使能标志
 */
void WAKE_SetWakeInterval(uint32_t rth, uint32_t wth, uint8_t ena)
{
    if (ena)
    {
        int32_t val;
        IWDG0->CFG |= BIT4;
        IWDG0->PSW = PSW_IWDG_PRE;
        IWDG0->RTH = rth; // 设置复位阈值
        val        = rth - wth;
        if (val < 0x100)
        {
            val = 0x100;
        }
        else
        {
            __NOP();
        }
        IWDG0->WTH = val; // 设置唤醒阈值
    }
    else
    {
        IWDG0->CFG &= ~BIT4;
    }
}

/**
 * @brief 设置唤醒IO
 * @param wakeIO 唤醒IO选择，必须打开对应的gpio输入使能（GPIO设置为输入模式），可以复用成任何模式
 * @param trigLevel 触发电平
 * @param flt 滤波使能
 * @param ena 使能标志
 */
void WAKE_SetWakeIO(uint32_t WAKE_IO_x, WAKE_TRIG_x trigLevel, uint32_t flt, uint8_t ena)
{
    if (ena)
    {
        AON_IO_WAKE_EN |= WAKE_IO_x;
        // 使能IO唤醒
        AON0->IO_WAKE_EN |= WAKE_IO_x;

        // 设置触发电平
        if (trigLevel == WAKE_TRIG_HIGH)
        {
            AON0->IO_WAKE_POL |= WAKE_IO_x;
        }
        else
        {
            AON0->IO_WAKE_POL &= ~WAKE_IO_x;
        }

        // 设置滤波使能
        if (flt == WAKE_FLT_EN)
        {
            AON0->PWR_CFG |= BIT1;
        }
        else
        {
            AON0->PWR_CFG &= ~BIT1;
        }
    }
    else
    {
        // 禁用IO唤醒
        AON0->IO_WAKE_EN &= ~WAKE_IO_x;
    }
}
