/* 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) 2016. 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.
 */
 
 #include "inputCapture_singleChannel.h"
 #include "ac780x_pwm.h"
 #include "ac780x_pwm_reg.h"
 #include "string.h"
 #include "ac780x_gpio.h"
 

pwm_capture_t g_pwmCapture = {0};

static void PulseWidthProcess(pwm_capture_t *pwmCapture, PWM_Type *PWMx, PWM_ChannelType channel, \
                              GPIO_Type *channelGpio, GPIO_PinType channelPin);

/**
* PWM_GPIOInit
* @param[in] none
*
* @return none
*
* @brief 配置GPIO
*
*/ 
void PWM_GPIOInit(void)
{
    /*config PWM0 pinmux*/
    GPIO_SetFunc(PWM0CH0_GPIO, PWM0CH0_PIN, PWM0CH0_FUN);/*PWM0_CH0 ->PA1*/
    GPIO_SetFunc(PWM0CH1_GPIO, PWM0CH1_PIN, PWM0CH1_FUN);/*PWM0_CH1 ->PA0*/
    
    /*config PWM1 pinmux*/
    GPIO_SetFunc(PWM1CH2_GPIO, PWM1CH2_PIN, PWM1CH2_FUN);/*PWM1_CH2 ->PB8*/
    GPIO_SetFunc(PWM1CH3_GPIO, PWM1CH3_PIN, PWM1CH3_FUN);/*PWM1_CH3 ->PB7*/
    
}

/*!
 * PrintResults
 *
 * @param[in] pwmCapture: Save the captured pulse width information structure
 *
 * @param[in] str: Print usage, indicating which channel is used
 *
 * @return none
 *
 * @brief 打印所计算的数据信息，可自行修改打印数据类型
 *
 */
void PrintResults(pwm_capture_t *pwmCapture, char *str)
{
    pwmCapture->mutex = 1;  /* Mutex lock, prevent the use of variables when the calculation, is interrupted to modify */
    if ((pwmCapture->positivePulseWidth + pwmCapture->negativePulseWidth) != 0)
    {
        /* The frequency and duty cycle results are amplified processed to avoid accuracy loss */
        pwmCapture->freq = g_periphAPBClock * 100UL / (PWM_PRES+1) / (pwmCapture->negativePulseWidth + pwmCapture->positivePulseWidth);
        pwmCapture->dutyCycle = pwmCapture->positivePulseWidth * 10000UL / (pwmCapture->negativePulseWidth + pwmCapture->positivePulseWidth);
    }
    else
    {
        /* No effective pulse width information was captured and the variable was emptied */
        pwmCapture->freq = 0;
        pwmCapture->dutyCycle = 0;
    }
    
    printf("%s:  capture freq value:%.2f Hz, duty cycle value:%.2f%%\r\n", str, (float)pwmCapture->freq / 100.0f, (float)pwmCapture->dutyCycle / 100.0f);
    pwmCapture->positivePulseWidth = 0;
    pwmCapture->negativePulseWidth = 0;
    pwmCapture->mutex = 0;
}

/**
* PWM1_Capture_CallBack
*
* @param[in] none
*
* @return none
*
* @brief PWM1捕获中断，计算频率和占空比
*/
void PWM1_Capture_CallBack(void *device, uint32_t wpara, uint32_t lpara)
{
    if ((g_pwmCapture.mutex != 1) && (lpara & PWM_STR_CH2SF_Msk))  /* Channel 0 matches interrupt determination */
    {
        PulseWidthProcess(&g_pwmCapture, (PWM_Type *)device, PWM_CH_2, PWM1CH2_GPIO, PWM1CH2_PIN);
    }

}

/*!
 * PulseWidthProcess
 *
 * @param[in] pwmCapture: Save the captured pulse width information structure
 *
 * @param[in] PWMx: pwm module
 *
 * @param[in] channel: The channel that generates the interrupt
 *
 * @param[in] channelGpio: GPIO for the channel
 *
 * @param[in] channelPin: The PIN corresponding to the channel
 *
 * @return none
 *
 * @brief 计算正负脉宽，以计算频率所需的的计数值
 * 
 */
static void PulseWidthProcess(pwm_capture_t *pwmCapture, PWM_Type *PWMx, PWM_ChannelType channel, \
                              GPIO_Type *channelGpio, GPIO_PinType channelPin)
{
    pwmCapture->captureValue = PWM_GetChannelCountValue(PWMx, channel);    /* Get the count of the capture */

    /* After the capture interruption, if the external level is low, the captured data is the high level count value.
       If the external level is high, the captured data is a low level count value */
    if (GPIO_GetPinLevel(channelGpio, channelPin) != GPIO_LEVEL_LOW)
    {
        if (pwmCapture->captureValue > pwmCapture->captureValueLast)    /* Overflow determination */
        {
            pwmCapture->negativePulseWidth = pwmCapture->captureValue - pwmCapture->captureValueLast;   /* Negative pulse width count value */
        }
        else
        {
            /* After overflow, the overflow value needs to be added */
            pwmCapture->negativePulseWidth = PWM_MAX_COUNTER_VALUE + pwmCapture->captureValue - pwmCapture->captureValueLast + 1;
        }
    }
    else
    {
        if (pwmCapture->captureValue > pwmCapture->captureValueLast)
        {
            pwmCapture->positivePulseWidth = pwmCapture->captureValue - pwmCapture->captureValueLast;
        }
        else
        {
            pwmCapture->positivePulseWidth = PWM_MAX_COUNTER_VALUE + pwmCapture->captureValue - pwmCapture->captureValueLast + 1;
        }
    }
    pwmCapture->captureValueLast = pwmCapture->captureValue;
}


/**
* PWM1_Capture_SingleChannel
* @param[in] none
*
* @return none
*
* @brief 配置PWM1模块，PWM1_CH2作为输入捕获通道，
*        
*/
void PWM1_Capture_SingleChannel(void)
{
    PWM_inputChConfigType inputChConfig[1];     /*输入通道配置*/
    PWM_inputCaptureConfigType inputCapconfig;  /*输入捕获结构体*/
    PWM_ConfigType config;                      /*PWM模块结构体*/

    /*结构体数据清零*/
    memset(&inputChConfig, 0, sizeof(inputChConfig));
    memset(&inputCapconfig, 0, sizeof(inputCapconfig));
    memset(&config, 0, sizeof(config));

    /*输入通道结构体配置，如果有多个输入通道，更改结构体数组，在后面添加相关配置即可。*/
    /*
    初始化PWM为捕获模式，捕获频率用单通道即可。任意一个通道都可以进行捕获。
    捕获模式可以设为上升沿，下降沿，或上升/下降沿
    */

    inputChConfig[0].channel = PWM_CH_2;                /*信号捕获通道选择, PB7 */
    inputChConfig[0].mode = PWM_INPUTCAP_SINGLE_EDGE;   /*输入捕获模式 PWM_INPUTCAP_SINGLE_EDGE：输入捕获 PWM_INPUTCAP_DUAL_EDGE：双边沿捕获*/
    inputChConfig[0].detectType = PWM_BOTH_EDGE_DETECT; /*检测边沿配置。上升沿和下降沿捕获*/
    inputChConfig[0].onceMode = PWM_INPUTCAP_CONTINUOUS;/*连续捕获*/
    inputChConfig[0].filterEn = DISABLE;                /*输入滤波配置，CH0-CH3才有该功能*/
    inputChConfig[0].filterValue = 0;                   /*filterValue值范围0-31，输入信号将被延迟filterValue*4个总线时钟*/
    inputChConfig[0].eventPsc = PWM_EVENT_PSC_1;        /*输入事件与通道中断的对应关系。PWM_EVENT_PSC_1表示1次输入事件产生一次通道中断，PWM_EVENT_PSC_4表示4次输入事件产生一次通道中断。*/
    inputChConfig[0].interruptEn = ENABLE;              /*输入捕获中断使能*/
    
    /*输入捕获配置*/
    inputCapconfig.channelNum = 1;
    inputCapconfig.channelConfig = inputChConfig;/*输入通道配置变量地址赋值。*/
    
    /*
    PWM模块配置
    设置捕获时钟频率：
    可捕获的最小频率（前提是时钟源为PWM_CLK_SOURCE_APB）：
    min_clk = SYS_CLK/(PWM_PRES+1)/65536 = 24000000/2/65536 = 183HZ
    */
    config.mode = PWM_MODE_INPUT_CAPTURE;    /*PWM模块配置为输入捕获模式*/
    config.initModeStruct = &inputCapconfig; /*输入捕获配置变量赋值*/
    config.clkSource = PWM_CLK_SOURCE_APB;   /*PWM时钟源配置*/
    config.clkPsc = PWM_PRES;                /*PWM时钟源分频*/
    config.initValue = 0;                    /*计数器初始寄存器值*/
    config.maxValue = 65535;                 /*PWM计数器最大值，在捕获模式下，计数器计满16bit数据*/
    config.overflowInterrupEn = ENABLE;      /*计数器溢出中断使能位*/
    config.cntOverflowFreq = 0;              /*CNTOF中断产生的频率与计数器频率的关系(0-127), 0表示每次计数器溢出都产生溢出中断，1表示间隔1次，2表示间隔2次，以此类推。*/
    config.interruptEn = ENABLE;             /*PWM中断使能*/
    config.callBack = PWM1_Capture_CallBack; /*PWM中断回调*/

    PWM_Init(PWM1, &config);                 /*配置初始化生效*/
    NVIC_SetPriority(PWM1_IRQn, 0);          /*设置PWM模块中断的优先级*/
}


/**
* PWM0_Output_CentralAlign
* @param[in] none
*
* @return none
*
* @brief 配置PWM0模块，PWM0CH0(PA1)和PWM0CH1(PA0)独立输出中央对齐的PWM
*
*/
void PWM0_Output_CentralAlign(void)
{
    PWM_IndependentChConfig  independentChConfig[2];/*独立模式相关结构体*/
    PWM_ModulationConfigType pwmConfig;             /*PWM模式相关结构体*/
    PWM_ConfigType           config;                /*PWM模块结构体*/
    /*结构体数据清零*/
    memset(&independentChConfig, 0, sizeof(independentChConfig));
    memset(&pwmConfig, 0, sizeof(pwmConfig));
    memset(&config, 0, sizeof(config));
     
    /*
    边沿对齐PWM模式：
    周期=(MCVR-CNTIN+1)*PWM计数器时钟周期
    占空比=(CHnV-CNTIN+1)*PWM计数器时钟周期
    中心对齐PWM模式：
    周期=2*(MCVR-CNTIN)*PWM计数器时钟周期
    占空比=2*(CH(n)V-CNTIN)*PWM计数器时钟周期
    */
    /*channel 0*/
    independentChConfig[0].channel = PWM_CH_0;                           /*独立输出通道选择CH0, PA1 */
    independentChConfig[0].chValue = MOD_PWM0 >> 1;                      /*通道0 channel值，输出占空比 = chValue / (config.maxValue ) = 50%*/
    independentChConfig[0].levelMode = PWM_HIGH_TRUE;                    /*输出PWM高有效*/
    independentChConfig[0].polarity = PWM_OUTPUT_POLARITY_ACTIVE_HIGH;   /*输出极性高有效，PWM mask后PWM输出低电平*/
    independentChConfig[0].interruptEn = DISABLE;                        /*PWM通道匹配中断使能位*/
    independentChConfig[0].initLevel = PWM_LOW_LEVEL;                    /*PWM初始电平输出为低，该配置受initChOutputEn控制，决定PWM计数器未工作前PWM口的输出电平值。*/
    independentChConfig[0].triggerEn = DISABLE;                          /*通道匹配触发使能位，用于ADC的采样触发*/
    /*channel 1*/
    independentChConfig[1].channel = PWM_CH_1;                           /*独立输出通道选择CH1, PA2 */
    independentChConfig[1].chValue = MOD_PWM0 >> 2;                       /*通道1 channel值，输出占空比 = chValue / (config.maxValue ) = 25%*/
    independentChConfig[1].levelMode = PWM_HIGH_TRUE;                    /*输出PWM高有效*/
    independentChConfig[1].polarity = PWM_OUTPUT_POLARITY_ACTIVE_HIGH;   /*输出极性高有效，PWM mask后PWM输出低电平*/
    independentChConfig[1].interruptEn = DISABLE;                        /*PWM通道匹配中断使能位*/
    independentChConfig[1].initLevel = PWM_LOW_LEVEL;                    /*PWM初始电平输出为低，该配置受initChOutputEn控制，决定PWM计数器未工作前PWM口的输出电平值。*/
    independentChConfig[1].triggerEn = DISABLE;                          /*通道匹配触发使能位，用于ADC的采样触发*/

    /*modulation mode config*/
    pwmConfig.countMode = PWM_UP_DOWN_COUNT;                /*PWM计数器模式，中央对齐模式，需选择 PWM_UP_DOWN_COUNT 方式 */
    pwmConfig.independentChannelNum = 2;                    /*独立通道数*/
    pwmConfig.combineChannelNum = 0;                        /*组合对数*/
    pwmConfig.independentChConfig = independentChConfig;    /*独立通道配置变量地址赋值*/
    pwmConfig.combineChConfig = NULL;                       /*组合通道配置变量地址赋值*/
    pwmConfig.deadtimePsc = PWM_DEADTIME_DIVID_1;           /*死区插入分频值，与deadtime一起决定插入死区的时间 */
    pwmConfig.deadtime = 0;                                 /*死区时间 = (DTPSC * DTVAL)/PWM计数器时钟周期 */
    pwmConfig.initChOutputEn = ENABLE;                      /*使能初始化通道输出，使能后独立PWM模式的initLevel和组合PWM模式的ch1stInitLevel和ch2ndPolarity配置才会生效*/
    pwmConfig.initTriggerEn = DISABLE;                      /*PWM初始触发使能位，用于ADC的采样触发*/
    
    /*pwm config*/
    config.mode = PWM_MODE_MODULATION;              /*PWM模块配置为PWM调制模式*/
    config.initModeStruct = &pwmConfig;             /*PWM配置结构体地址赋值*/
    config.clkSource = PWM_CLK_SOURCE_APB;          /*PWM时钟源配置*/
    config.clkPsc = PWM_PRES;                       /*PWM时钟源分频*/
    config.initValue = 0;                           /*计数器初始寄存器值*/
    config.maxValue = (MOD_PWM0);                   /*PWM计数器最大值，决定输出波形频率*/
    config.overflowInterrupEn = DISABLE;            /*计数器溢出中断使能位*/
    config.cntOverflowFreq = 0;                     /*CNTOF中断产生的频率与计数器频率的关系(0-127), 0表示每次计数器溢出都产生溢出中断，1表示间隔1次，2表示间隔2次，以此类推*/
    config.interruptEn = DISABLE;                   /*PWM中断使能*/
    config.callBack = NULL;                         /*PWM中断回调*/
    PWM_Init(PWM0, &config);                        /*配置初始化生效*/

}

