/******************************************************************************
文 件 名：CLOCK.c
功能描述：时钟系统初始化库文件
作    者：张暄
版    本：V1.0
日    期：2016.11.2
******************************************************************************/

#include "CRG.h"
#include "System_Status_Monitor.h"
#include "PowerManagement.h"   
#include "fuelconfig.h"

volatile uint8_t          CRGStopMode;
volatile RTITimingStruct  RealTimeClock;

uint8_t TimerCntFlag;
uint8_t Motortime;

extern uint8_t  DiagnosticFlag;

extern void Data_Mileage_Rolling_Counter_Update_ISR(void);
extern void Data_Fuel_Consumption_Count_ISR(void);

/******************************************************************************
函数名：WDT_Init
功  能：看门狗初始化
参  数：无
返回值：无
******************************************************************************/
void WDT_Init(void)
{
  //配置看门狗
  wdt_reset();
  COPCTL     = WDT_PERIOD;    //配置看门狗定时周期
  // PLLCTL_PCE = 1;            //看门狗在Pseudo Stop模式下持续运行
}

/******************************************************************************
函数名：Clock_Init
功  能：时钟系统初始化
参  数：无
返回值：无
******************************************************************************/
void Clock_Init(void)
{
  uint32_t  REFCLK;
  uint32_t  VCOCLK;

  uint8_t   REFDIVVal;
  uint8_t   SYNDIVVal;
  uint8_t   POSTDIVVal;

  uint8_t   Result;                                                                                                            ;

  //使用OSCCLK作为系统时钟
  CLKSEL = 0x00;

  //计算时钟配置寄存器值
  Result = 0;
  REFDIVVal = 0;
  while ((REFDIVVal < 64) && (Result == 0))
  {
    /*===================================================
                              fOSC
                   fREF = --------------
                           (REFDIV + 1)
    ===================================================*/
    REFCLK = OSCCLK / (REFDIVVal + 1);

    if ((REFCLK >= REFCLK_MIN) && (REFCLK <= REFCLK_MAX))
    {
      SYNDIVVal = 0;
      while ((SYNDIVVal < 64) && (Result == 0))
      {
        /*========================================================
                           (SYNDIV + 1)
        fVCO = 2 x fOSC x -------------- = 2 x fREF x (SYNDIV + 1)
                           (REFDIV + 1)
        ========================================================*/
        VCOCLK = REFCLK * 2 * (SYNDIVVal + 1);

        if ((VCOCLK >= VCOCLK_MIN) && (VCOCLK <= VCOCLK_MAX) && (VCOCLK >= BUSCLK))
        {
          POSTDIVVal = 0;
          while ((POSTDIVVal < 32) && (Result == 0))
          {
            if (POSTDIVVal == 0)
            {
              /*========================================================
              当POSTDIV为0时,fPLL等于fVCO
                                                  fPLL     fVCO
                      fPLL = fVCO         fBUS = ------ = ------
                                                    2        2
              ========================================================*/
              if (VCOCLK / 2 == BUSCLK)
                Result = 1;
              else
                POSTDIVVal++;
            }
            else
            {
              /*========================================================
              当POSTDIV不为0时
                          fVCO                    fPLL        fVCO
               fPLL = -------------       fBUS = ------ = -------------
                       2 x POSTDIV                  2      4 x POSTDIV
              ========================================================*/
              if (VCOCLK / (4 * POSTDIVVal) == BUSCLK)
                Result = 1;
              else
                POSTDIVVal++;
            }
          }
        }

        if (Result == 0)
          SYNDIVVal++;
      }
    }

    if (Result == 0)
      REFDIVVal++;
  }

  while (Result == 0);         //无法生成所需的BUSCLK,在这里停机

  //设置时钟配置寄存器
  PLLCTL_SCME = 0;
  PLLCTL_CME  = 1;

  if (VCOCLK <= 48000000)
    SYNR =        SYNDIVVal;
  else if (VCOCLK <= 80000000)
    SYNR = 0x40 | SYNDIVVal;
  else
    SYNR = 0xC0 | SYNDIVVal;

  if (REFCLK <= 2000000)
    REFDV =        REFDIVVal;
  else if (REFCLK <= 6000000)
    REFDV = 0x40 | REFDIVVal;
  else if (REFCLK <= 12000000)
    REFDV = 0x80 | REFDIVVal;
  else
    REFDV = 0xC0 | REFDIVVal;

  POSTDIV = POSTDIVVal;

  while (!CRGFLG_LOCK);        //等待 fVCO 输出稳定

  while (!FSTAT_CCIF);         /* wait for FTM reset to complete */

  if (FCLKDIV == 0)
    FCLKDIV = 0x07;            //FCLK=OSCCLK/7=8M/7=1.1238MHZ

  //FPROT = 0x9C;	               // Protect 0x7F_C000 to 0x7F_FFFF (pages FD and FF)
  DFPROT = 0xFF;               /* Disable any protection set on DFlash */

  CLKSEL_PLLSEL = 1;           //选择PLLCLK作为系统时钟
#if CRG_USE_PSEUDO_STOP_MODE
  CLKSEL_PSTP = 1;             //Oscillator在Stop模式下持续运行(Pseudo Stop)
#else
  CLKSEL_PSTP = 0;             //Oscillator在Stop模式下停止运行(Full Stop)
#endif
  CRG_STOP_MODE = 0;           //系统正常运行,不在停机模式
}

/******************************************************************************
函数名：Enter_Stop_Mode
功  能：进入停机模式
参  数：无
返回值：无
******************************************************************************/
void Enter_Stop_Mode(void)
{
  CRG_STOP_MODE = 1;           //进入停机模式
  asm ANDCC #0x7F;
  asm STOP;
}

/******************************************************************************
函数名：RTI_Init
功  能：初始化RTI
参  数：无
返回值：无
******************************************************************************/
void RTI_Init(void)
{
  RealTimeClock.RollingCounter = 0;
  RealTimeClock.BackupCounter  = 0;
  RealTimeClock.Year           = RTC_DEFAULT_YEAR;
  RealTimeClock.BackupYear     = RTC_DEFAULT_YEAR;
  RealTimeClock.Month          = RTC_DEFAULT_MONTH;
  RealTimeClock.Date           = RTC_DEFAULT_DATE;
  RealTimeClock.Hour           = RTC_DEFAULT_HOUR;
  RealTimeClock.Minute         = RTC_DEFAULT_MINUTE;
  RealTimeClock.Second         = RTC_DEFAULT_SECOND;
  RealTimeClock.LeapYear       = Determine_Leap_Year(RealTimeClock.Year);

  PLLCTL_PRE  = 1;             //1 RTI continues running during Pseudo Stop Mode.
  //Real Time 时钟频率设置
  RTICTL      = 0xDF;          //Real Time = 8M / 800000 = 10HZ  (100MS)
  CRGINT_RTIE = 1;	           //开Real Time 中断
}

/******************************************************************************
函数名：RTI_Timing_Service
功  能：RTI实时计时服务
参  数：无
返回值：无
*******************************************************************************
注  意：该服务函数必须每100ms被调用一次
******************************************************************************/
void RTI_Timing_Service(void)
{
  uint16_t  Counter;
  uint16_t  SecInc;

  if (RealTimeClock.Year != RealTimeClock.BackupYear) //曾经修改过年
  {
    RealTimeClock.LeapYear = Determine_Leap_Year(RealTimeClock.Year);
    RealTimeClock.BackupYear = RealTimeClock.Year;
  }

  Counter = RealTimeClock.RollingCounter;

  if (Counter - RealTimeClock.BackupCounter >= 10)
  {
    SecInc = (Counter - RealTimeClock.BackupCounter) / 10;
    RealTimeClock.BackupCounter += SecInc * 10;

    RealTimeClock.Second += (uint8_t)(SecInc % 60);
    RealTimeClock.Minute += (uint8_t)(SecInc / 60);

    if (RealTimeClock.Second >= 60)
    {
      RealTimeClock.Minute += RealTimeClock.Second / 60;
      RealTimeClock.Second  = RealTimeClock.Second % 60;
    }

    if (RealTimeClock.Minute >= 60)
    {
      RealTimeClock.Hour   += RealTimeClock.Minute / 60;
      RealTimeClock.Minute  = RealTimeClock.Minute % 60;
    }

    if (RealTimeClock.Hour >= 24)
    {
      RealTimeClock.Date += RealTimeClock.Hour / 24;
      RealTimeClock.Hour  = RealTimeClock.Hour % 24;
    }

    switch (RealTimeClock.Month)
    {
      case 1  :
      case 3  :
      case 5  :
      case 7  :
      case 8  :
      case 10 :
      case 12 :
        if (RealTimeClock.Date > 31)
        {
          RealTimeClock.Date = 1;
          RealTimeClock.Month++;
        }
        break;

      case 4  :
      case 6  :
      case 9  :
      case 11 :
        if (RealTimeClock.Date > 30)
        {
          RealTimeClock.Date = 1;
          RealTimeClock.Month++;
        }
        break;

      case 2  :
        if (RealTimeClock.LeapYear)
        {
          if (RealTimeClock.Date > 29)
          {
            RealTimeClock.Date = 1;
            RealTimeClock.Month++;
          }
        }
        else
        {
          if (RealTimeClock.Date > 28)
          {
            RealTimeClock.Date = 1;
            RealTimeClock.Month++;
          }
        }
        break;
    }

    if (RealTimeClock.Month > 12)
    {
      RealTimeClock.Month =1;
      RealTimeClock.Year++;
      RealTimeClock.LeapYear = Determine_Leap_Year(RealTimeClock.Year);
      RealTimeClock.BackupYear = RealTimeClock.Year;
    }
  }
}

/******************************************************************************
函数名：Determine_Leap_Year
功  能：闰年检测
参  数：Year：年
返回值：1 - 是闰年 0 -不是闰年
******************************************************************************/
uint8_t Determine_Leap_Year(uint16_t Year)
{
  if (Year % 4 == 0)
  {
    if (Year % 100 != 0)
      return 1;
    else if (Year % 400 == 0)
      return 1;
  }

  return 0;
}

uint8_t Timer5sFlag;

extern uint8_t DiagnosticReceived;

#pragma CODE_SEG __NEAR_SEG NON_BANKED
/******************************************************************************
函数名：RTI_ISR
功  能：RTI中断服务函数
        RTI每100ms发生中断后,其滚动计数器会自动加1
        RTI中断还可以将处理器从睡眠中唤醒
参  数：无
返回值：无    2017年5月27日16:47:20
******************************************************************************/

void interrupt RTI_ISR(void)
{
  uint8_t i;
  RealTimeClock.RollingCounter++;
    
  if (SYS_IGN_ON_DISP_MODE) 
  {
  }
  else
  {
    SetPowerSt(0);
    for (i=0; i<10; i++)
    	AFCTimerCall();	
    FuelFSM();	
  }
 
  S3_ServerCNT();
  TIME_100MS = 1;  
  if (DiagnosticReceived != 0)
    DiagnosticReceived--;
  Data_Mileage_Rolling_Counter_Update_ISR();

  CRGFLG_RTIF = 1;             //通过写1清0中断标
}
#pragma CODE_SEG DEFAULT
