/**************************************************************************//**
  * \file     Sys_Tick.c
  * \brief    System tick timer driver file
  * \details
  * \author   Zhang Xuan
  * \version  V1.0.0
  * \date     19-Jul-2018
  * \par      History:
  *           V1.0.0 Initial release
  * \par      Copyright:
  *           (c) Heilongjiang TYW Electronics co., LTD
******************************************************************************/

/* Includes ------------------------------------------------------------------*/

#include "Sys_Tick.h"

/* Private typedef -----------------------------------------------------------*/
typedef struct
{
    uint32_t  MainCnt;
    uint32_t  DstVal2ms;
    uint32_t  DstVal100ms;
} Sys_Tick_Timer_st_t;

/* Private define ------------------------------------------------------------*/
/** Key to unlock one access to a System Controller configuration register by writing to SYSC0_PROTKEYR/SYSC1_PROTKEYR register */
#define   SYS_SYSC_UNLOCK_KEY               0x5CACCE55UL

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
Sys_Tick_Timer_st_t   SysTickTimer;
volatile uint16_t     SysRollingCounter50us;
volatile uint16_t     SysRollingCounter2ms;

/* Private function prototypes -----------------------------------------------*/
static __irq __arm void Sys_Tick_Timer_ISR(void);

/* Private functions ---------------------------------------------------------*/


/**************************************************************************//**
  * \brief      Start tick timer
  * \retval     None
******************************************************************************/
void Sys_Tick_Timer_Start(void)
{
    SysTickTimer.MainCnt            = 0U;
    SysTickTimer.DstVal2ms          = 40U;
    SysTickTimer.DstVal100ms        = 2000U;

    SysRollingCounter50us           = 0U;
    SysRollingCounter2ms            = 0U;

#ifdef __DEBUG
    /* Set main source clock timer operation mode */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTCNTR         =   0x00000003UL;           /* MODE  = 1 */
    /* DBGEN = 1 */
#else
    /* Set main source clock timer operation mode */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTCNTR         =   0x00000001UL;           /* MODE  = 1 */
    /* DBGEN = 0 */
#endif

#if (CLK_MAIN_OSC_FREQ == 4000000UL)
    /* Set main SCT interrupt interval to 50us */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTCPR          =   0x00020032UL;           /* CMPR = 0x00320U          */
    /* PSCL = 2(divided by 4)   */
#elif (CLK_MAIN_OSC_FREQ == 8000000UL)
    /* Set main SCT interrupt interval to 50us */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTCPR          =   0x00030032UL;           /* CMPR = 0x00320U          */
    /* PSCL = 3(divided by 8)   */
#else
#error Unsupported main oscillator frequency
#endif

    /* trigger configuration capture */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTTRGR         =   0x00000001UL;           /* CGCPT = 1 */
    /* CSTOP = 0 */
    /* TCLR  = 0 */

    /* Wait while timer setting is applied */
    while (SYSC_MOCTSTR_BUSY) {}

    /* Register ISR */
    Interrupt_IRQ_ISR_Register(INTERRUPTS_IRQ_NUMBER_218, (uint32_t)Sys_Tick_Timer_ISR, 31U);

    /* Enable interrupt */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTINTER        =   0x00000001UL;           /* INTE = 1 */
}

/**************************************************************************//**
  * \brief      GPIO initialization for sleep mode
  * \retval     None
******************************************************************************/
void Sys_Tick_Timer_Stop(void)
{
    /* Stop main source clock timer */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTTRGR         =   0x00000007UL;           /* CGCPT = 1 */
    /* CSTOP = 1 */
    /* TCLR  = 1 */

    /* Disable main source clock timer interrupt  */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTINTER        =   0x00000000UL;           /* INTE = 0 */

    /* Clear main source clock timer interrupt flag */
    SYSC0_PROTKEYR        =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTICLR         =   0x00000001UL;           /* INTC = 1 */

    /* Wait while timer setting is applied */
    while (SYSC_MOCTSTR_BUSY) {}
}

uint16_t Sys_Get_ms_Rolling_Counter(void)
{
    return SysRollingCounter2ms;
}
/**************************************************************************//**
  * \brief      Tick timer interrupt service routines
  * \retval     None
******************************************************************************/
static __irq __arm void Sys_Tick_Timer_ISR(void)
{
    uint16_t Counter;
    /*bsp_MotorMove_50us_main();*/
    /*
    #if SYS_EXACT_50us_PERIODIC_ROUTINE != NULL
      (*SYS_EXACT_50us_PERIODIC_ROUTINE)();
    #endif
    */
    SYS_EXACT_50us_PERIODIC_ROUTINE();

    SysTickTimer.MainCnt++;

    if (SysTickTimer.MainCnt >= SysTickTimer.DstVal2ms)
    {
        /*
        #if SYS_EXACT_1ms_PERIODIC_ROUTINE != NULL
          (*SYS_EXACT_1ms_PERIODIC_ROUTINE)();
        #endif
        */
        Counter                   = SysRollingCounter2ms;
        SysRollingCounter2ms      = Counter + 2U;
        SysTickTimer.DstVal2ms    = SysTickTimer.MainCnt + 40U;
    }

    if (SysTickTimer.MainCnt >= SysTickTimer.DstVal100ms)
    {
        /*
        #if SYS_EXACT_100ms_PERIODIC_ROUTINE != NULL
          (*SYS_EXACT_100ms_PERIODIC_ROUTINE)();
        #endif
        */
        SYS_EXACT_100ms_PERIODIC_ROUTINE();
        SysTickTimer.DstVal100ms  = SysTickTimer.MainCnt + 2000U;
    }

    if (SysTickTimer.MainCnt & 0xFFFF0000UL)
    {
        SysTickTimer.MainCnt     &= 0x0000FFFFUL;
        SysTickTimer.DstVal2ms   &= 0x0000FFFFUL;
        SysTickTimer.DstVal100ms &= 0x0000FFFFUL;
    }

    SysRollingCounter50us = (uint16_t)SysTickTimer.MainCnt;

    IRQ_DISABLE_LOCAL()
    SYSC0_PROTKEYR     =   SYS_SYSC_UNLOCK_KEY;    /* unlock SYSC0 */
    SYSC_MOCTICLR_INTC = 1U;
    IRQ_RESTORE()

    IRC0_IRQHC = INTERRUPTS_IRQ_NUMBER_218;
}