/*******************************************************************************
* LowPower Library
* Version: 1.00
* Date: 09-05-2024
* Author: cuij
* Company: megawin Technology Co., Ltd.
* Website: www.megawin.com
*
* This is a lightweight low power library for Arduino.
*
* Unported License.
*
* Revision  Description
* ========  ===========
* 1.00      Initial public release.
*******************************************************************************/
#include "sleep.h"
#include "wdt.h"
#include "LowPower.h"
#include "MG32x02z_RTC_MID.h"


LowPowerClass LowPower;

static void STOP_EnableRST()
{

    //特定时候需要屏蔽系统的一些复位源
    UnProtectModuleReg(RSTprotect);
    RST_CRstSource_Config(RST_SW_CE, ENABLE);
    RST_CRstSource_Config(RST_CPU_CE, ENABLE);
    RST_CRstSource_Config(RST_BOD0_CE, ENABLE);
    RST_CRstSource_Config(RST_BOD1_CE, ENABLE);
    RST_CRstSource_Config(RST_BOD2_CE, ENABLE);

    RST_CRstSource_Config(RST_LPM_CE, ENABLE);
    RST_CRstSource_Config(RST_CSC_CE, ENABLE);
    RST_CRstSource_Config(RST_MEM_CE, ENABLE);
    //不使能IWDT复位
    //RST_CRstSource_Config(RST_IWDT_CE, ENABLE);
    RST_CRstSource_Config(RST_WWDT_CE, ENABLE);
    RST_CRstSource_Config(RST_ADC_CE, ENABLE);
    RST_CRstSource_Config(RST_CMP0_CE, ENABLE);
    RST_CRstSource_Config(RST_CMP1_CE, ENABLE);

    RST_WRstSource_Config ( RST_SW_WE, ENABLE);
    RST_WRstSource_Config ( RST_CPU_WE, ENABLE);
    RST_WRstSource_Config ( RST_BOD0_WE, ENABLE);
    RST_WRstSource_Config ( RST_BOD1_WE, ENABLE);
    RST_WRstSource_Config ( RST_BOD2_WE, ENABLE);
    RST_WRstSource_Config ( RST_LPM_WE, ENABLE);
    RST_WRstSource_Config ( RST_CSC_WE, ENABLE);
    RST_WRstSource_Config ( RST_MEM_WE, ENABLE);
    //不使能IWDT复位
    //RST_WRstSource_Config ( RST_IWDT_WE, ENABLE);
    RST_WRstSource_Config ( RST_WWDT_WE, ENABLE);
    RST_WRstSource_Config ( RST_ADC_WE, ENABLE);
    RST_WRstSource_Config ( RST_CMP0_WE, ENABLE);
    RST_WRstSource_Config ( RST_CMP1_WE, ENABLE);
    ProtectModuleReg(RSTprotect);

}

static void STOP_DisableRST()
{
    //特定时候需要屏蔽系统的一些复位源
    UnProtectModuleReg(RSTprotect);
    RST_CRstSource_Config(RST_SW_CE, DISABLE);
    RST_CRstSource_Config(RST_CPU_CE, DISABLE);
    RST_CRstSource_Config(RST_BOD0_CE, DISABLE);
    RST_CRstSource_Config(RST_BOD1_CE, DISABLE);
    RST_CRstSource_Config(RST_BOD2_CE, DISABLE);
    RST_CRstSource_Config(RST_LPM_CE, DISABLE);
    RST_CRstSource_Config(RST_CSC_CE, DISABLE);
    RST_CRstSource_Config(RST_MEM_CE, DISABLE);
    RST_CRstSource_Config(RST_IWDT_CE, DISABLE);
    RST_CRstSource_Config(RST_WWDT_CE, DISABLE);
    RST_CRstSource_Config(RST_ADC_CE, DISABLE);
    RST_CRstSource_Config(RST_CMP0_CE, DISABLE);
    RST_CRstSource_Config(RST_CMP1_CE, DISABLE);

    RST_WRstSource_Config ( RST_SW_WE, DISABLE);
    RST_WRstSource_Config ( RST_CPU_WE, DISABLE);
    RST_WRstSource_Config ( RST_BOD0_WE, DISABLE);
    RST_WRstSource_Config ( RST_BOD1_WE, DISABLE);
    RST_WRstSource_Config ( RST_BOD2_WE, DISABLE);
    RST_WRstSource_Config ( RST_LPM_WE, DISABLE);
    RST_WRstSource_Config ( RST_CSC_WE, DISABLE);
    RST_WRstSource_Config ( RST_MEM_WE, DISABLE);
    RST_WRstSource_Config ( RST_IWDT_WE, DISABLE);
    RST_WRstSource_Config ( RST_WWDT_WE, DISABLE);
    RST_WRstSource_Config ( RST_ADC_WE, DISABLE);
    RST_WRstSource_Config ( RST_CMP0_WE, DISABLE);
    RST_WRstSource_Config ( RST_CMP1_WE, DISABLE);
    ProtectModuleReg(RSTprotect);
}

void LowPowerClass::idle( period_t period)
{
    powerDown(period);
}


void LowPowerClass::standby( period_t period)
{
    powerStandby(period);
}


void LowPowerClass::longPowerDown(uint32_t sleepTime)
{
    do {
        if (sleepTime >= 8192)
        {
            powerDown(SLEEP_8S);
            sleepTime -= 8192;
        }
        else if (sleepTime >= 4096)
        {
            powerDown(SLEEP_4S );
            sleepTime -= 4096;
        }
        else if (sleepTime >= 2048)
        {
            powerDown(SLEEP_2S );
            sleepTime -= 2048;
        }
        else if (sleepTime >= 1024)
        {
            powerDown(SLEEP_1S);
            sleepTime -= 1024;
        }
        else if (sleepTime >= 512)
        {
            powerDown(SLEEP_500MS );
            sleepTime -= 512;
        }
        else if (sleepTime >= 256)
        {
            powerDown(SLEEP_250MS );
            sleepTime -= 256;
        }
        else if (sleepTime >= 128)
        {
            powerDown(SLEEP_120MS );
            sleepTime -= 128;
        }
        else if (sleepTime >= 64)
        {
            powerDown(SLEEP_60MS );
            sleepTime -= 64;
        }
        else if (sleepTime >= 32)
        {
            powerDown(SLEEP_30MS );
            sleepTime -= 32;
        }
        else if (sleepTime >= 16)
        {
            powerDown(SLEEP_15MS);
            sleepTime -= 16;
        }
        else
        {
            wdt_reset();
            delay(sleepTime);
            wdt_reset();
            sleepTime = 0;
        }
    } while(sleepTime);
}


void LowPowerClass::sleep(uint32_t sleepTime)
{
    longPowerDown(sleepTime);
}



void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod, usb_t usb, rtc_t rtc)
{
    STOP_DisableRST();
    wdt_reset();

    if(adc == ADC_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_CMP0, DISABLE);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_CMP1, DISABLE);
        ProtectModuleReg(PWprotect);

        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_CMP0, DISABLE);    
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_CMP1, DISABLE);    
        ProtectModuleReg(PWprotect); 

        analogReadDeinit();
    }

    if(bod ==BOD_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_BOD0, DISABLE);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_BOD1, DISABLE);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_BOD2, DISABLE);
        ProtectModuleReg(PWprotect);

        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_BOD0, DISABLE);    
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_BOD1, DISABLE);   
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_BOD2, DISABLE);   
        ProtectModuleReg(PWprotect);   
    }

    if(usb ==USB_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_USB, DISABLE);
        ProtectModuleReg(PWprotect);

        USB_LVRModeInSTOP_Select( USB_STOP_LVR_DISABLE);
        
        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_USB, DISABLE); 
        ProtectModuleReg(PWprotect);    
    }

    if(rtc==RTC_OFF)
    {
        UnProtectModuleReg(CSCprotect); 
        CSC_PeriphOnModeClock_Config(CSC_ON_RTC, DISABLE);
        CSC_PeriphSTOPModeClock_Config(CSC_STP_RTC, DISABLE);
        ProtectModuleReg(CSCprotect);  

        RTC_HandleTypeDef  mRTC;
        mRTC.Instance = RTC;
        __DRV_RTC_DISABLE( &mRTC );
        
        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_RTC, DISABLE); 
        ProtectModuleReg(PWprotect);                                  // protect PW module
    }

    //模拟输出关闭
    analogOutputDeinit();

    //关闭POR
    UnProtectModuleReg(PWprotect);
    PW_PeriphSTOPModeContinuous_Config(PW_STPPO_POR, DISABLE);
    ProtectModuleReg(PWprotect);
    
    UnProtectModuleReg(PWprotect);                                // Unprotect PW module
    PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_I2C0, DISABLE);
    PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_I2C1, DISABLE);
    ProtectModuleReg(PWprotect);    
    

    //可选关闭IWDT，如果关闭，这里是不打开的。
    wdt_disableRST();
	if (period != SLEEP_FOREVER)
	{
		wdt_enable(period);
		wdt_reset();
	}
	else 
    {
        wdt_disable();
        UnProtectModuleReg(CSCprotect); 
        CSC_PeriphOnModeClock_Config(CSC_ON_IWDT, DISABLE);
        CSC_PeriphSTOPModeClock_Config(CSC_STP_IWDT, DISABLE);
        ProtectModuleReg(CSCprotect);
        
        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_IWDT, DISABLE);        // IWDT Wake Up Set
        ProtectModuleReg(PWprotect);                                  // protect PW module
    }

//关闭uart iO，设置为输入节省能源。
#if defined(HWSERIAL0)
    Serial.end();
#endif

#if defined(HWSERIAL1)
    Serial1.end();
#endif

#if defined(HWSERIAL2)
    Serial2.end();
#endif

#if defined(URT3)&defined(HWSERIAL3)
    Serial3.end();
#endif

#if defined(HWSERIAL4)
    Serial4.end();
#endif

#if defined(HWSERIAL5)
    Serial5.end();
#endif

#if defined(HWSERIAL6)
    Serial6.end();
#endif

#if defined(HWSERIAL7)
    Serial7.end();
#endif

    sleep_enable();
    //MID_SuspendTick(); 
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    STOP_WFI();
    wdt_reset();
    //MID_InitTick(TICK_INT_PRIORITY); 
    sleep_disable();


#if defined(HWSERIAL0)
    Serial.begin();
#endif

#if defined(HWSERIAL1)
    Serial1.begin(  );
#endif

#if defined(HWSERIAL2)
    Serial2.begin(  );
#endif

#if defined(URT3)&defined(HWSERIAL3)
    Serial3.begin(  );
#endif

#if defined(HWSERIAL4)
    Serial4.begin(  );
#endif

#if defined(HWSERIAL5)
    Serial5.begin(  );
#endif

#if defined(HWSERIAL6)
    Serial6.begin(  );
#endif

#if defined(HWSERIAL7)
    Serial7.begin(  );
#endif

    UnProtectModuleReg(PWprotect);                                // Unprotect PW module
    PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_I2C0, ENABLE);
    PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_I2C1, ENABLE);
    ProtectModuleReg(PWprotect);    

    UnProtectModuleReg(PWprotect);
    PW_PeriphSTOPModeContinuous_Config(PW_STPPO_POR, ENABLE);
    ProtectModuleReg(PWprotect);

    analogOutputInit();

    //完成以后恢复
    if(adc == ADC_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_CMP0, ENABLE);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_CMP1, ENABLE);
        ProtectModuleReg(PWprotect);

        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_CMP0, ENABLE);    
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_CMP1, ENABLE);    
        ProtectModuleReg(PWprotect); 

        analogReadInit();
    }

    if(bod ==BOD_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_BOD0, ENABLE);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_BOD1, ENABLE);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_BOD2, ENABLE);
        ProtectModuleReg(PWprotect);

        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_BOD0, ENABLE);    
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_BOD1, ENABLE);   
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_BOD2, ENABLE);   
        ProtectModuleReg(PWprotect);   
    }

    if(usb ==USB_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_USB, ENABLE);
        ProtectModuleReg(PWprotect);
        USB_LVRModeInSTOP_Select( USB_STOP_LVR_ENABLE);
        
        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_USB, ENABLE); 
        ProtectModuleReg(PWprotect);   
    }
    
    if(rtc==RTC_OFF)
    {
        UnProtectModuleReg(CSCprotect); 
        CSC_PeriphOnModeClock_Config(CSC_ON_RTC, ENABLE);
        CSC_PeriphSTOPModeClock_Config(CSC_STP_RTC, ENABLE);
        ProtectModuleReg(CSCprotect);  

        RTC_HandleTypeDef  mRTC;
        mRTC.Instance = RTC;
        __DRV_RTC_ENABLE( &mRTC );
        
        UnProtectModuleReg(PWprotect);                                // Unprotect PW module
        PW_PeriphSTOPModeWakeUp_Config(PW_WKSTP_RTC, ENABLE); 
        ProtectModuleReg(PWprotect);                                  // protect PW module
    }

    wdt_reset();
    STOP_EnableRST();
}


void LowPowerClass::powerStandby(period_t period, adc_t adc, usb_t usb)
{
    
    if(adc == ADC_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSLEEPModeContinuous_Config(PW_SLPPO_CMP0, DISABLE);
        PW_PeriphSLEEPModeContinuous_Config(PW_SLPPO_CMP1, DISABLE);
        ProtectModuleReg(PWprotect);
    }
    
    if(usb ==USB_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSLEEPModeContinuous_Config(PW_SLPPO_USB, DISABLE);
        ProtectModuleReg(PWprotect);
    }

    wdt_disableRST();
	if (period != SLEEP_FOREVER)
	{
        wdt_enable(period);
        wdt_reset();
	}


    sleep_enable();
    MID_SuspendTick(); 
    SLEEP_WFI(); 
    wdt_reset();
    MID_InitTick(TICK_INT_PRIORITY); 
    sleep_disable();
    

    
    if(adc == ADC_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_CMP0, ENABLE);
        PW_PeriphSTOPModeContinuous_Config(PW_STPPO_CMP1, ENABLE);
        ProtectModuleReg(PWprotect);
    }

    if(usb ==USB_OFF)
    {
        UnProtectModuleReg(PWprotect);
        PW_PeriphSLEEPModeContinuous_Config(PW_SLPPO_USB, ENABLE);
        ProtectModuleReg(PWprotect);
    }
    wdt_reset();

}






