/** 
 *******************************************************************************
 * @file    main.c
 * @brief   the application functions of TMRB_PPG demo for the TOSHIBA
 *          'TMPM311' Device Series 
 * @version V0.100
 * @date    2014/10/24
 * 
 * DO NOT USE THIS SOFTWARE WITHOUT THE SOFTWARE LICENSE AGREEMENT.
 * 
 * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2017 All rights reserved
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* declaration ---------------------------------------------------------------*/
void delay(uint32_t DelayTime);
void leadingtiming_display(void);
uint16_t Tmrb_Calculator(uint16_t Tmrb_Require_us, uint32_t ClkDiv);
uint8_t Rate = 0U;

/**
  * @brief  delay some time
  * @param  delay time
  * @retval None.
  */
void delay(uint32_t DelayTime)
{
    uint32_t time = 0U;
    for (time = 0U; time < DelayTime; time++) {
        /* Do nothing */
    }
}

/**
  * @brief  The main function of TMRB_PPG demo
  * @param  None
  * @retval None
  */
int main(void)
{
    TMRB_InitTypeDef m_tmrb;
    TMRB_FFOutputTypeDef PPGFFInital;
    uint8_t keyvalue;
    uint32_t i = 0U;
    uint32_t tgtLeadingTiming[5U] = { 10U, 25U, 50U, 75U, 90U }; /* leadingtiming: 10%, 25%, 50%, 75%, 90% */ 
    uint32_t LeadingTimingus[5U] = {0U};
    uint32_t LeadingTiming[5U] = {0U};

    SCB->VTOR = (unsigned int)0x10000000;

    /* LeadingTimingus: 50, 125, 250, 375, 450 */
    for (i=0U;i<=4U;i++) {
        LeadingTimingus[i] = tgtLeadingTiming[i] * 5U;
    }

    /* UART & switch initialization */
    hardware_init(UART_RETARGET);
    SW_Init();

    /* Set PB1 as TB0OUT for PPG output */
    GPIO_SetOutput(GPIO_PB, GPIO_BIT_1);
    GPIO_EnableFuncReg(GPIO_PB, GPIO_FUNC_REG_1, GPIO_BIT_1);

    m_tmrb.Mode = TMRB_INTERVAL_TIMER;     /* internal timer */
    m_tmrb.ClkDiv = TMRB_CLK_DIV_8;        /* 1/8PhiT0 */
    m_tmrb.UpCntCtrl = TMRB_AUTO_CLEAR;    /* up-counter auto clear */
    for(i=0U;i<=4U;i++) { 
        LeadingTiming[i] = Tmrb_Calculator(LeadingTimingus[i], m_tmrb.ClkDiv);
    } 
    m_tmrb.TrailingTiming = Tmrb_Calculator(500U, m_tmrb.ClkDiv);  /* T = 500us */ 
    m_tmrb.LeadingTiming = LeadingTiming[Rate];   /* leadingtiming, initial value 10% */
    PPGFFInital.FlipflopCtrl = TMRB_FLIPFLOP_SET;
    PPGFFInital.FlipflopReverseTrg = TMRB_FLIPFLOP_MATCH_TRAILING | TMRB_FLIPFLOP_MATCH_LEADING;

    TMRB_Enable(TSB_TB0);
    TMRB_Init(TSB_TB0, &m_tmrb);
    TMRB_SetFlipFlop(TSB_TB0, &PPGFFInital);
    TMRB_SetDoubleBuf(TSB_TB0, ENABLE);        /* enable double buffer */
    TMRB_SetRunState(TSB_TB0, TMRB_RUN);

    do {                        /* Handle the condition that start with the SW0 is high */
        keyvalue = GPIO_ReadDataBit(KEYPORT, GPIO_BIT_4);
        leadingtiming_display();
    } while (GPIO_BIT_VALUE_1 == keyvalue);

    delay(0xFFFFU);             /* noise cancel */

    while (1U) {
        do {
            keyvalue = GPIO_ReadDataBit(KEYPORT, GPIO_BIT_4);   /* display when switch is low */
            leadingtiming_display();
        } while (GPIO_BIT_VALUE_0 == keyvalue);
        delay(0xFFFFU);         /* noise cancel */
        Rate++;
        if (Rate >= LEADINGMAX) {  /* change leadingtiming rate */
            Rate = LEADINGINIT;
        } else {
            /* Do nothing */
        }
        TMRB_ChangeLeadingTiming(TSB_TB0, LeadingTiming[Rate]);
        do {
            keyvalue = GPIO_ReadDataBit(KEYPORT, GPIO_BIT_4);   /* display when switch is high */
            leadingtiming_display();
        } while (GPIO_BIT_VALUE_1 == keyvalue);
        delay(0xFFFFU);         /* noise cancel */
    }
}

/**
  * @brief  Display the string of TMRB_PPG demo
  * @param  None
  * @retval None
  */
void leadingtiming_display()
{
    common_uart_disp("PPG Output");
    common_uart_disp(LeadingTimingRateToString(Rate));
}

/** 
  * @brief  Calculate timer value to set timer register. 
  * @param  Tmrb_Require_us: The require period which the uint is us. 
            ClkDiv: Select the division for TMRB source clock 
  * @retval the value set to Tmrb timer register. 
  */ 
uint16_t Tmrb_Calculator(uint16_t Tmrb_Require_us, uint32_t ClkDiv) 
{      
    uint32_t T0 = 0U; 
    const uint16_t Div[8U] = {1U, 2U, 8U, 32U, 64U, 128U, 256U, 512U}; 
    
    SystemCoreClockUpdate(); 

    T0 = SystemCoreClock / (1U << ((TSB_CG0->CLKCR >> 3U) & 7U));   
    T0 = T0/((Div[ClkDiv])*1000000U); 
         
    return(Tmrb_Require_us * T0); 
} 

/**
  * @brief  Deal with the error parameter
  * @param  file: Pointer to the file where the error parameter locates
  * @param  line: Number of the line in which the error parameter locates
  * @retval None
  */
#ifdef DEBUG
void assert_failed(char *file, int32_t line)
{
    while (1) {
        __NOP();
    }
}
#endif
