/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2023. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */
/******************************************************************************
 * @version: V1.0.0
 ******************************************************************************/

/*!
 * @file timer_pulse_counter.c
 *
 * @brief timer works on PULSE COUNTER mode
 * ---------------------------
 * CHx    ALTx   GPIOx    FUNx
 * ---------------------------
 * CH0    ALT0    PC6     FUN2
 * CH0    ALT0    PC10    FUN2 [use]
 * CH1    ALT1    PC7     FUN2
 * CH1    ALT1    PA6     FUN2 [use]
 * CH2    ALT2    PA8     FUN3
 * CH2    ALT2    PD6     FUN3
 * CH3    ALT0    PC9     FUN2
 * ---------------------------
 */

/* ===========================================  Includes  =========================================== */
#include <stdint.h>
#include <string.h>

#include "ac7803x_debugout.h"
#include "ac780x_gpio.h"
#include "ac780x_timer.h"
#include "ac780x_timer_reg.h"

#include "timer_pulse_counter.h"

/* ============================================  Define  ============================================ */

/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */
static uint32_t msCnt = 0;
static uint32_t usCnt = 0;

/* ====================================  Functions declaration  ===================================== */

/* ======================================  Functions define  ======================================== */
/*!
 * @brief Timer channel0 timeout callback function.
 *
 * @param device: the Timer channel0.
 * @param wpara: the value of TIMER_SR(Timer interrupt flag register).
 * @param lpara: unused.
 */
static void TIMER_CH0Callback(void* device, uint32_t wpara, uint32_t lpara)
{
    printf("CH0(PC10) capture 2000 rising edges, ms = %d, us = %d\r\n", msCnt, usCnt);
}

/*!
 * @brief Timer channel1 timeout callback function.
 *
 * @param device: the Timer channel1.
 * @param wpara: the value of TIMER_SR(Timer interrupt flag register).
 * @param lpara: unused.
 */
static void TIMER_CH1Callback(void* device, uint32_t wpara, uint32_t lpara)
{
    printf("CH1(PA6) capture 1000 rising edges, ms = %d, us = %d\r\n", msCnt, usCnt);
}

/*!
 * @brief Timer channel2 timeout callback function.
 *
 * @param device: the Timer channel2.
 * @param wpara: the value of TIMER_SR(Timer interrupt flag register).
 * @param lpara: unused.
 */
static void TIMER_CH2Callback(void* device, uint32_t wpara, uint32_t lpara)
{
    usCnt += 10;
    if (0 == (usCnt % 250))  // T = 500us duty = 50%
    {
        if (GPIO_LEVEL_LOW == GPIO_GetPinLevel(GPIOC, GPIO_PIN6))
        {
            GPIO_SetPinLevel(GPIOC, GPIO_PIN6, GPIO_LEVEL_HIGH);
        }
        else
        {
            GPIO_SetPinLevel(GPIOC, GPIO_PIN6, GPIO_LEVEL_LOW);
        }
    }
    if (0 == (usCnt % 500))  // T = 1000us duty = 50%
    {
        if (GPIO_LEVEL_LOW == GPIO_GetPinLevel(GPIOC, GPIO_PIN7))
        {
            GPIO_SetPinLevel(GPIOC, GPIO_PIN7, GPIO_LEVEL_HIGH);
        }
        else
        {
            GPIO_SetPinLevel(GPIOC, GPIO_PIN7, GPIO_LEVEL_LOW);
        }
    }
    if (usCnt == 1000)
    {
        msCnt++;
        usCnt = 0;
    }
}

/*!
 * @brief Initialize timer channel 0, no filter is used, the working mode is set to pulse counter mode, and
 * the rising edge is captured.
 *
 */
static void TIMER_CH0Init(void)
{
    TIMER_ConfigType config;
    memset(&config, 0U, sizeof(config));

    config.timeMode    = TIMER_WORKMODE_PULSECOUNTER;
    config.pinPol      = PULSE_ACTIVE_HIGH; /* rise pulse count */
    config.chainModeEn = DISABLE;

    config.bypEn = ENABLE; /* bypass the filter */

    config.cvalReadSel = TIMER_BCLK_FCLK_4;
    config.periodValue = 2000 - 1; /* 1000 valid pulses trigger an interrupt */

    config.interruptEn = ENABLE;
    config.callback    = TIMER_CH0Callback;

    TIMER_InitChannel(TIMER_CHANNEL0, &config);
}

/*!
 * @brief Init timer channel2,[pulse counter] mode,use filter, target: 1000 pulse, capture rise edge.
 *
 */
static void TIMER_CH1Init(void)
{
    TIMER_ConfigType config;
    memset(&config, 0U, sizeof(config));

    config.timeMode    = TIMER_WORKMODE_PULSECOUNTER;
    config.pinPol      = PULSE_ACTIVE_HIGH; /* rise pulse count */
    config.chainModeEn = DISABLE;

    config.bypEn     = DISABLE;                                /* bypass disable, use the filter */
    config.prescaler = TIMER_PRESCALE_16384_GLITCHFILTER_8191; /* 8191/32M = 0.000256s, High level duration
                                                                  less than it will be filtered(rise pulse count) */

    config.cvalReadSel = TIMER_BCLK_FCLK_4;  /* must set when work on pulse counter mode */
    config.periodValue = 1000 - 1;           /* 1000 valid pulses trigger an interrupt */

    config.interruptEn = ENABLE;
    config.callback    = TIMER_CH1Callback;

    TIMER_InitChannel(TIMER_CHANNEL1, &config);
}

/*!
 * @brief Initialize the timer channel 2, the frequency divider is not used,
 * the work mode is set to the clock counter mode, and an interrupt is triggered
 * every 10us (the clock source is shared, which is the APB clock).
 *
 */
static void TIMER_CH2Init(void)
{
    TIMER_ConfigType config;
    memset(&config, 0U, sizeof(config));

    config.timeMode = TIMER_WORKMODE_TIMER;

    config.bypEn       = ENABLE;                    /* bypass the prescaler */
    config.chainModeEn = DISABLE;                   /* disable chain mode */

    config.cvalReadSel = TIMER_BCLK_FCLK_1;         /* APBCLK/FUNCTION_CLK == 1 */
    config.periodValue = APB_BUS_FREQ / 100000 - 1; /* 10us */

    config.interruptEn = ENABLE;
    config.callback    = TIMER_CH2Callback;

    TIMER_InitChannel(TIMER_CHANNEL2, &config);
}

/*!
 * @brief Init the GPIO.
 *
 */
inline void GPIO_TimerInit(void)
{
    GPIO_SetFunc(GPIOC, GPIO_PIN10, GPIO_FUN2); /* PC10 set pinmux ALT0 */
    GPIO_SetFunc(GPIOA, GPIO_PIN6, GPIO_FUN2);  /* PA6 set pinmux ALT1 */

    GPIO_SetFunc(GPIOC, GPIO_PIN6, GPIO_FUN0);
    GPIO_SetDir(GPIOC, GPIO_PIN6, GPIO_OUT);
    GPIO_SetPinLevel(GPIOC, GPIO_PIN6, GPIO_LEVEL_LOW); /* PC6 GPIO OUT PWM */

    GPIO_SetFunc(GPIOC, GPIO_PIN7, GPIO_FUN0);
    GPIO_SetDir(GPIOC, GPIO_PIN7, GPIO_OUT);
    GPIO_SetPinLevel(GPIOC, GPIO_PIN7, GPIO_LEVEL_LOW); /* PC7 GPIO OUT PWM */
}

/*!
 * @brief Init the timer.
 *
 */
void Timer_Init(void)
{
    /* Initialization, complete before operating other registers, otherwise a hardfault error occurs */
    TIMER_Init(TIMER_CLKSR_APB); /* timer sel：APB_BUS_FREQ(32M)*/
    TIMER_Enable(DISABLE);

    TIMER_CH0Init();
    TIMER_CH1Init();
    TIMER_CH2Init();

    TIMER_Enable(ENABLE);
}

/* =============================================  EOF  ============================================== */
