/**************************************************************************//**
 * @file     timer_counting_modes_test.c
 * @version  V1.0
 * $Date:    19/10/30 18:00 $
 * @brief    Timer test case 1, test Timer Counting Modes, including One-Shot
 *           Mode, Periodic Mode, Toggle-Output Mode, Continuous-Counting Mode.
 * @note
 * Copyright (C) 2019 Panchip Technology Corp. All rights reserved.
 *
 ******************************************************************************/
#include "pan271x.h"
#include "timer_common.h"

static void TIMER_PrintInfoCase1(void)
{
    SYS_TEST("\n");
    SYS_TEST("+-----------------------------------------------------------------+ \n");
    SYS_TEST("|    Press key to test specific function:                         | \n");
    SYS_TEST("|                                                                 | \n");
    SYS_TEST("|    Input 'A'    Periodic Mode.                                  | \n");
    SYS_TEST("|    Input 'B'    Continuous-Counting Mode.                       | \n");
    SYS_TEST("|    Input 'C'    Capture function.                               | \n");
    SYS_TEST("|    Press ESC key to back to the top level case list.            | \n");
    SYS_TEST("+-----------------------------------------------------------------+ \n");
}

static void TIMER_PeriodicModeTest(void)
{
    uint32_t tmrCmpValue = 0;       //Comparison Value

    // Select Timer clock source
    CLK_SetTmrClkSrc(TGT_TIMER_CLK_APB); //TGT_TIMER_CLK_RCL
	TIMER_SetWorkMode(TGT_TIMER, TIMER_PERIOD_WORK_MODE);
	
    // expect_timeout = tmrCmpValue / tmrExpCntFreq = 16M / 16MHz = 1s
    // real_timeout = tmrCmpValue / tmrRealCntFreq = 16M / tmrRealCntFreq
    tmrCmpValue = 16000000; 
    TIMER_SetCmpValue(TGT_TIMER, tmrCmpValue);

    // Enable interrupt
    TIMER_EnableInt(TGT_TIMER);
    NVIC_EnableIRQ(TGT_TMR_IRQn);

    // Start Timer counting
    SYS_TEST("\nTimer0, Compare Value:%d\n", tmrCmpValue);

    SYS_TEST("Start Timer...\n");
    TIMER_Start(TGT_TIMER);

    while(tmr_int_trigger_cnt < 5);
    tmr_int_trigger_cnt = 0;

    // Disable interrupt
    TIMER_DisableInt(TGT_TIMER);
    NVIC_DisableIRQ(TGT_TMR_IRQn);

    TIMER_Stop(TGT_TIMER);
	CLK->IPRST1 |= IPRST1_TMR0RST_Msk;
	CLK->IPRST1 &= ~IPRST1_TMR0RST_Msk;
}


static void TIMER_ContiniousCountingModeTest(void)
{
    uint32_t tmrCmpValue = 0, tmrCntValue;       //Comparison Value

    // Select Timer clock source
    CLK_SetTmrClkSrc(TGT_TIMER_CLK_APB); //TGT_TIMER_CLK_RCL
	TIMER_SetWorkMode(TGT_TIMER, TIMER_CONTINUOUS_WORK_MODE);
	
    // Enable interrupt
    TIMER_EnableInt(TGT_TIMER);
    NVIC_EnableIRQ(TGT_TMR_IRQn);

    // First set compare value to 300K
    tmrCmpValue = 300000;
    TIMER_SetCmpValue(TGT_TIMER, tmrCmpValue);

    // Start Timer counting
    SYS_TEST("Start Timer...\n");
    TIMER_Start(TGT_TIMER);

    // Wait for the first INT
    while(tmr_int_trigger_cnt < 1);
    tmrCntValue = TIMER_GetCounter(TGT_TIMER);
    SYS_TEST("\nTimer0, Compare Value:%d\n", tmrCmpValue);

    // Change compare value to 600K
    tmrCmpValue = 600000;
    TIMER_SetCmpValue(TGT_TIMER, tmrCmpValue);

    // Wait for the second INT
    while(tmr_int_trigger_cnt < 2);
    tmrCntValue = TIMER_GetCounter(TGT_TIMER);
    SYS_TEST("\nTimer0, Compare Value:%d\n", tmrCmpValue);

    // Change compare value to 1200K
    tmrCmpValue = 1200000;
    TIMER_SetCmpValue(TGT_TIMER, tmrCmpValue);

    // Wait for the second INT
    while(tmr_int_trigger_cnt < 3);
    tmrCntValue = TIMER_GetCounter(TGT_TIMER);
    SYS_TEST("\nTimer0, Compare Value:%d\n", tmrCmpValue);

    tmr_int_trigger_cnt = 0;

    // Disable interrupt
    TIMER_DisableInt(TGT_TIMER);
    NVIC_DisableIRQ(TGT_TMR_IRQn);

    TIMER_Stop(TGT_TIMER);
	CLK->IPRST1 |= IPRST1_TMR0RST_Msk;
	CLK->IPRST1 &= ~IPRST1_TMR0RST_Msk;
}

void printCaptureEdge(void)
{
    SYS_TEST("\n");
    SYS_TEST("+---------------------------------------------------------+ \n");
    SYS_TEST("|    Press key to test capture edge:                      | \n");
    SYS_TEST("|                                                         | \n");
    SYS_TEST("|    Input '1'    Rising edge.                            | \n");
    SYS_TEST("|    Input '2'    Falling edge.                           | \n");
    SYS_TEST("|    Input '3'    Both edge.                              | \n");
    SYS_TEST("+--------------------------------------------------- -----+ \n");
}


void USB_IRQHandler(void)
{
	uint8_t     IntrUSB;

	IntrUSB = READ_REG(USB->INT_USB);
	if (IntrUSB & 0x08) 
		cap_buf[tmr_cap_int_cnt++] = TIMER_GetCaptureCount(TGT_TIMER);
}

static void TIMER_CaptureTest(void)
{
	char input;
	uint32_t reg_tmp;
	
    uint32_t tmrCmpValue = 0;
	TIMER_CaptureEdgeDef capEdge;

    // Select Timer clock source
    CLK_SetTmrClkSrc(TGT_TIMER_CLK_APB);
	CLK_SetTmrCaptureSrc(SYS_CTRL_CAP_SRC_SEL_USB_SOF);
	TIMER_SetWorkMode(TGT_TIMER, TIMER_CONTINUOUS_WORK_MODE);

	tmrCmpValue = 32000;
    TIMER_SetCmpValue(TGT_TIMER, tmrCmpValue);
    // Configure Timer capture mode and capture edge
	printCaptureEdge();
	input = getchar();
	switch (input) {
		case '1': capEdge = TIMER_CAPTURE_EDGE_SEL_RISING;break;
		case '2': capEdge = TIMER_CAPTURE_EDGE_SEL_FALLING;break;
		case '3': capEdge = TIMER_CAPTURE_EDGE_SEL_BOTH;break;
		default: capEdge = TIMER_CAPTURE_EDGE_SEL_RISING;break;
	}
	TIMER_SetCaptureEdge(TGT_TIMER, capEdge);
    TIMER_CaptureEnable(TGT_TIMER, ENABLE);
	TIMER_Start(TGT_TIMER);

	SYS->SYS_CTRL |= (SYS_CTRL_USB_PU_Msk | SYS_CTRL_USB_PU2_Msk | SYS_CTRL_USB_EN_Msk);
	/*usb debounce time*/
	SYS->SYS_CTRL = ((SYS->SYS_CTRL & ~SYS_CTRL_VALID_REMOVAL_CYCLES_Msk) | 100);

	reg_tmp = READ_REG(USB->INT_USBE);
	reg_tmp |= 0x08;
	WRITE_REG (USB->INT_USBE,reg_tmp);
	NVIC_EnableIRQ(USB_IRQn);

	// Wait for the first INT
    while(tmr_cap_int_cnt < 10){}
	NVIC_DisableIRQ(USB_IRQn);
    tmr_cap_int_cnt = 0;    //Reset global INT count after use
	for (uint16_t i = 0; i < 9; i++) {
		SYS_TEST("%d ", (cap_buf[i+1]-cap_buf[i]));
	}
	SYS_TEST("\n");

    TIMER_Stop(TGT_TIMER);
	CLK->IPRST1 |= IPRST1_TMR0RST_Msk;
	CLK->IPRST1 &= ~IPRST1_TMR0RST_Msk;
	CLK->IPRST0 |= IPRST0_USBRST_Msk;
	CLK->IPRST0 &= ~IPRST0_USBRST_Msk;
}


T_TIMER_TEST_RESULT TIMER_TimerCountingModesTestCase(void)
{
    char c;

    while(1)
    {
        TIMER_PrintInfoCase1();
		c = getchar();
        switch(c)
        {
        /* A. Periodic Mode */
        case 'A':
        case 'a':
            TIMER_PeriodicModeTest();
            break;
        /* B. Continuous-Counting Mode */
        case 'B':
        case 'b':
            TIMER_ContiniousCountingModeTest();
            break;
        /* C. Capture Internal Src function */
        case 'C':
        case 'c':
            TIMER_CaptureTest();
            break;
        case 0x1B:  // Keyboard code <ESC>
            goto OUT;
        default:
            SYS_WARN("Cannot find subtest case %c!\n", c);
            break;
        }
    }
OUT:
    return TIMER_TST_OK;
}


