/************************************************************************************************/
/**
* @file               std_exti.h
* @author             MCU Ecosystem Development Team
* @brief              EXTI STD库驱动头文件。
*                     提供EXTI相关的STD库操作函数声明、数据类型以及常量的定义。                         
*                     
*
**************************************************************************************************
* @attention
* Copyright (c) CEC Huada Electronic Design Co.,Ltd. All rights reserved.
*
**************************************************************************************************
*/

/* 避免头文件重复引用 */
#ifndef STD_EXTI_H
#define STD_EXTI_H

/************************************************************************************************/
/** 
* @addtogroup STD_Driver
* @{
*/

/**
* @defgroup EXTI EXTI
* @brief 扩展中断和事件控制器的STD库驱动
* @{
*/
/************************************************************************************************/



#ifdef __cplusplus
 extern "C" {
#endif

/*------------------------------------------includes--------------------------------------------*/
#include "std_common.h"

/*-----------------------------------------type define------------------------------------------*/
/************************************************************************************************/
/** 
* @defgroup EXTI_Types EXTI Types
* @brief EXTI数据类型定义
* @{
*/
/************************************************************************************************/

/**
* @brief  EXTI参数配置结构体定义
*/
typedef struct
{
    uint32_t line_id;                 /**< EXTI通道ID
                                               @arg EXTI_LINE_GPIO_PIN0 ... */
    uint32_t mode;                    /**< EXTI通道模式
                                               @arg EXTI_MODE_INTERRUPT ... */
    uint32_t trigger;                 /**< EXTI通道触发类型
                                               @arg EXTI_TRIGGER_RISING ... */
    uint32_t gpio_id;                 /**< GPIO端口ID
                                               @arg EXTI_GPIOA ...          */
} std_exti_init_t;


/**
* @}
*/

/*--------------------------------------------define--------------------------------------------*/

/************************************************************************************************/
/**
* @defgroup EXTI_Constants EXTI Constants 
* @brief  EXTI常量定义及宏定义
* @{
*
*/
/************************************************************************************************/

/* EXTI LINE ID定义 */
#define EXTI_LINE_GPIO_PIN0                 (EXTI_GPIO        | 0x00U)                         /**< EXTI_LINE0  */
#define EXTI_LINE_GPIO_PIN1                 (EXTI_GPIO        | 0x01U)                         /**< EXTI_LINE1  */
#define EXTI_LINE_GPIO_PIN2                 (EXTI_GPIO        | 0x02U)                         /**< EXTI_LINE2  */
#define EXTI_LINE_GPIO_PIN3                 (EXTI_GPIO        | 0x03U)                         /**< EXTI_LINE3  */
#define EXTI_LINE_GPIO_PIN4                 (EXTI_GPIO        | 0x04U)                         /**< EXTI_LINE4  */
#define EXTI_LINE_GPIO_PIN5                 (EXTI_GPIO        | 0x05U)                         /**< EXTI_LINE5  */
#define EXTI_LINE_GPIO_PIN6                 (EXTI_GPIO        | 0x06U)                         /**< EXTI_LINE6  */
#define EXTI_LINE_GPIO_PIN7                 (EXTI_GPIO        | 0x07U)                         /**< EXTI_LINE7  */
#define EXTI_LINE_GPIO_PIN8                 (EXTI_GPIO        | 0x08U)                         /**< EXTI_LINE8  */
#define EXTI_LINE_GPIO_PIN9                 (EXTI_GPIO        | 0x09U)                         /**< EXTI_LINE9  */

#define EXTI_LINE_COMP1                     (EXTI_DIRECT      | 0x10U)                         /**< EXTI_LINE16 */
#define EXTI_LINE_COMP2                     (EXTI_DIRECT      | 0x11U)                         /**< EXTI_LINE17 */  
#define EXTI_LINE_PVD                       (EXTI_DIRECT      | 0x18U)                         /**< EXTI_LINE24 */ 
#define EXTI_LINE_RTC                       (EXTI_DIRECT      | 0x19U)                         /**< EXTI_LINE25 */ 
#define EXTI_LINE_LPUART1                   (EXTI_DIRECT      | 0x1DU)                         /**< EXTI_LINE29 */ 
#define EXTI_LINE_LPTIM1                    (EXTI_DIRECT      | 0x1EU)                         /**< EXTI_LINE30 */
#define EXTI_LINE_LXTAL_CSS                 (EXTI_DIRECT      | 0x1FU)                         /**< EXTI_LINE31 */

/* EXTI LINE 分组 */
#define EXTI_DIRECT                         (0x01000000)                                       /**< 直接通道           */   
#define EXTI_GPIO                           (0x06000000)                                       /**< GPIO 可配置通道    */  
#define EXTI_PROPERTY_MASK                  (EXTI_DIRECT      | EXTI_GPIO)                     /**< 通道屏蔽掩码       */  
                                                                                               
/* EXTI LINE屏蔽掩码，用于筛选EXTI LINE ID */                                                   
#define EXTI_LINE_MASK                      (0x0000001FU)                                      /**< EXTI LINE屏蔽掩码  */
                                                                                               
#define EXTI_MODE_NONE                      (0x00000000U)                                      /**< 无中断/事件唤醒    */
#define EXTI_MODE_INTERRUPT                 (0x00000001U)                                      /**< 中断唤醒           */
#define EXTI_MODE_EVENT                     (0x00000002U)                                      /**< 事件唤醒           */
#define EXTI_MODE_INTERRUPT_EVENT           (EXTI_MODE_EVENT  | EXTI_MODE_INTERRUPT)            /**< 中断/事件唤醒     */
                                                                                               
/* EXTI LINE 触发类型定义，用于可配置通道，信号触发类型配置 */                                   
#define EXTI_TRIGGER_NONE                   (0x00000000U)                                      /**< 不触发             */
#define EXTI_TRIGGER_RISING                 (0x00000001U)                                      /**< 上降沿触发         */
#define EXTI_TRIGGER_FALLING                (0x00000002U)                                      /**< 下降沿触发         */
#define EXTI_TRIGGER_RISING_FALLING         (EXTI_TRIGGER_RISING | EXTI_TRIGGER_FALLING)       /**< 上升沿下降沿触发   */
                                                                                               
/* EXTI LINE 触发类型屏蔽掩码，用于筛选EXTI 可配置通道触发类型 */                                
#define EXTI_TRIGGER_MASK                   (EXTI_TRIGGER_RISING | EXTI_TRIGGER_FALLING)        /**< 触发类型屏蔽掩码 */

/* EXTI 滤波时钟源 */
#define EXTI_FLTCLK_HCLK                    EXTI_FILTER_FLTCLK_HCLK                             /**< 滤波时间源 HCLK       */
#define EXTI_FLTCLK_HCLK_DIV2               EXTI_FILTER_FLTCLK_HCLK_DIV2                        /**< 滤波时间源 HCLK_DIV2  */
#define EXTI_FLTCLK_HCLK_DIV4               EXTI_FILTER_FLTCLK_HCLK_DIV4                        /**< 滤波时间源 HCLK_DIV4  */
#define EXTI_FLTCLK_HCLK_DIV8               EXTI_FILTER_FLTCLK_HCLK_DIV8                        /**< 滤波时间源 HCLK_DIV8  */
#define EXTI_FLTCLK_TIM8_OV                 EXTI_FILTER_FLTCLK_TIM8_OV                          /**< 滤波时间源 TIM8_OV    */
#define EXTI_FLTCLK_RCL                     EXTI_FILTER_FLTCLK_RCL                              /**< 滤波时间源 RCL        */
#define EXTI_FLTCLK_LXTAL                   EXTI_FILTER_FLTCLK_LXTAL                            /**< 滤波时间源 LXTAL      */
#define EXTI_FLTCLK_LPTIM1_OV               EXTI_FILTER_FLTCLK_LPTIM1_OV                        /**< 滤波时间源 LPTIM1_OV  */


/* GPIO端口ID定义 
*  GPIOB端口引脚没有PIN9，GPIOF端口引脚没有PIN5-PIN9，缺省的PIN对应的EXTI通道被GPIOA PIN10-PIN15重映射占用
*  当GPIO端口是GPIOA PIN10-PIN13,PIN15时，映射到EXTI LINE5-LINE9; gpio_id选择EXTI_GPIOA_REMAP_GPIOF
*  当GPIO端口是GPIOA PIN14时，映射到EXTI LINE9; gpio_id选择EXTI_GPIOA_REMAP_GPIOB
*/
#define EXTI_GPIOA                          (0x00000000UL)                                      /**< GPIOA ID                */
#define EXTI_GPIOB                          (0x00000001UL)                                      /**< GPIOB ID                */
#define EXTI_GPIOF                          (0x00000002UL)                                      /**< GPIOF ID                */
#define EXTI_GPIOA_REMAP_GPIOB              (0x00000001UL)                                      /**< GPIOA ID重映射到GPIOB   */
#define EXTI_GPIOA_REMAP_GPIOF              (0x00000002UL)                                      /**< GPIOA ID重映射到GPIOF   */
/** 
* @} 
*/

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

/************************************************************************************************/
/**
* @defgroup EXTI_External_Functions EXTI External Functions
* @brief    EXTI对外函数
* @{
*
*/
/************************************************************************************************/
/**
* @brief  读取EXTI通道中断挂起状态
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval bool 上升沿中断挂起状态
*             @arg true  表示已挂起
*             @arg false 表示未挂起
*/
__STATIC_INLINE bool std_exti_get_pending_status(uint32_t exti_line)
{
    return ((EXTI->PIR & (0x01U << (exti_line & EXTI_LINE_MASK))) != 0);
}


/**
* @brief  清除EXTI通道中断挂起状态
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval 无
*/
__STATIC_INLINE void std_exti_clear_pending(uint32_t exti_line)
{
    EXTI->PIR = (0x01U << (exti_line & EXTI_LINE_MASK));
}

/**
* @brief  使能EXTI通道上升沿触发
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval 无
*/
__STATIC_INLINE void std_exti_rising_trigger_enable(uint32_t exti_line)
{
    EXTI->RTSR |= (0x01U << (exti_line & EXTI_LINE_MASK));
}

/**
* @brief  禁止EXTI通道上升沿触发
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval 无
*/
__STATIC_INLINE void std_exti_rising_trigger_disable(uint32_t exti_line)
{
    EXTI->RTSR &= (~(0x01U << (exti_line & EXTI_LINE_MASK)));
}

/**
* @brief  使能EXTI通道下降沿触发
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval 无
*/
__STATIC_INLINE void std_exti_falling_trigger_enable(uint32_t exti_line)
{
    EXTI->FTSR |= (0x01U << (exti_line & EXTI_LINE_MASK));
}

/**
* @brief  禁止EXTI通道下降沿触发
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval 无
*/
__STATIC_INLINE void std_exti_falling_trigger_disable(uint32_t exti_line)
{
    EXTI->FTSR &= (~(0x01U << (exti_line & EXTI_LINE_MASK)));
}

/**
* @brief  读取EXTI通道上升沿触发状态
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1 
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval bool 上升沿触发状态
*             @arg true  表示已使能
*             @arg false 表示已禁止
*/
__STATIC_INLINE bool std_exti_get_rising_trigger_enable(uint32_t exti_line)
{
    return ((EXTI->RTSR & (0x01U << (exti_line & EXTI_LINE_MASK))) != 0);
}

/**
* @brief  读取EXTI通道下降沿触发状态
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval bool 下降沿触发状态
*             @arg true  表示已使能
*             @arg false 表示已禁止
*/
__STATIC_INLINE bool std_exti_get_falling_trigger_enable(uint32_t exti_line)
{
    return ((EXTI->FTSR & (0x01U << (exti_line & EXTI_LINE_MASK))) != 0);
}

/** 
* @brief  设置EXTI滤波时钟源
* @param  clock_source  EXTI滤波时钟
*             @arg EXTI_FLTCLK_HCLK      
*             @arg EXTI_FLTCLK_HCLK_DIV2 
*             @arg EXTI_FLTCLK_HCLK_DIV4 
*             @arg EXTI_FLTCLK_HCLK_DIV8 
*             @arg EXTI_FLTCLK_TIM8_OV   
*             @arg EXTI_FLTCLK_RCL       
*             @arg EXTI_FLTCLK_LXTAL     
*             @arg EXTI_FLTCLK_LPTIM1_OV 
* @retval 无
*/
__STATIC_INLINE void std_exti_set_filter_clock(uint32_t clock_source)
{
    MODIFY_REG(EXTI->FILTER, EXTI_FILTER_FLTCLK, clock_source);
}

/** 
* @brief  获取EXTI滤波时钟源
* @retval uint32_t EXTI滤波时钟
*             @arg EXTI_FLTCLK_HCLK      
*             @arg EXTI_FLTCLK_HCLK_DIV2 
*             @arg EXTI_FLTCLK_HCLK_DIV4 
*             @arg EXTI_FLTCLK_HCLK_DIV8 
*             @arg EXTI_FLTCLK_TIM8_OV   
*             @arg EXTI_FLTCLK_RCL       
*             @arg EXTI_FLTCLK_LXTAL     
*             @arg EXTI_FLTCLK_LPTIM1_OV 
*/
__STATIC_INLINE uint32_t std_exti_get_filter_clock(void)
{
    return (EXTI->FILTER & EXTI_FILTER_FLTCLK);
}

/**
* @brief  使能EXTI滤波通道
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval 无
*/
__STATIC_INLINE void std_exti_filter_enable(uint32_t exti_line)
{
    EXTI->FILTER |= (0x01U << (exti_line & EXTI_LINE_MASK));
}

/**
* @brief  禁止EXTI通道滤波
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @retval 无
*/
__STATIC_INLINE void std_exti_filter_disable(uint32_t exti_line)
{
    EXTI->FILTER &= (~(0x01U << (exti_line & EXTI_LINE_MASK)));
}

/**
* @brief  使能EXTI通道唤醒中断
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_LXTAL_CSS
* @retval 无
*/
__STATIC_INLINE void std_exti_interrupt_enable(uint32_t exti_line)
{
    EXTI->IMR |= (0x01U << (exti_line & EXTI_LINE_MASK));
}

/**
* @brief  禁止EXTI通道唤醒中断
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_LXTAL_CSS
* @retval 无
*/
__STATIC_INLINE void std_exti_interrupt_disable(uint32_t exti_line)
{
    EXTI->IMR &= (~(0x01U << (exti_line & EXTI_LINE_MASK)));
}

/**
* @brief  使能EXTI通道唤醒事件
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_LXTAL_CSS
* @retval 无
*/
__STATIC_INLINE void std_exti_event_enable(uint32_t exti_line)
{
    EXTI->EMR |= (0x01U << (exti_line & EXTI_LINE_MASK));
}

/**
* @brief  禁止EXTI通道唤醒事件
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_LXTAL_CSS
* @retval 无
*/
__STATIC_INLINE void std_exti_event_disable(uint32_t exti_line)
{
    EXTI->EMR &= (~(0x01U << (exti_line & EXTI_LINE_MASK)));
}

/**
* @brief  设置EXTI通道所对应GPIO端口
* @param  gpio_id  GPIO端口ID
*             @arg EXTI_GPIOA
*             @arg EXTI_GPIOB
*             @arg EXTI_GPIOF
*             @arg EXTI_GPIOA_REMAP_GPIOB
*             @arg EXTI_GPIOA_REMAP_GPIOF
* @param  exti_line  EXTI通道ID
*             @arg EXTI_LINE_GPIO_PIN0
*             @arg EXTI_LINE_GPIO_PIN1
*             @arg ...
*             @arg EXTI_LINE_GPIO_PIN9
* @note   GPIOB端口引脚没有PIN9，GPIOF端口引脚没有PIN5-PIN9，缺省的PIN对应的EXTI通道被GPIOA PIN10-PIN15重映射占用
*         当GPIO端口是GPIOA PIN10-PIN13,PIN15时，映射到EXTI LINE5-LINE9; gpio_id选择EXTI_GPIOA_REMAP_GPIOF
*         当GPIO端口是GPIOA PIN14时，映射到EXTI LINE9; gpio_id选择EXTI_GPIOA_REMAP_GPIOB
*         
* @retval 无
*/
__STATIC_INLINE void std_exti_set_gpio(uint32_t gpio_id, uint32_t exti_line)
{
    if ((exti_line & EXTI_GPIO) == EXTI_GPIO)
    {
        exti_line &= EXTI_LINE_MASK;
        MODIFY_REG(EXTI->EXTICR[(exti_line & EXTI_LINE_MASK) >> 3U],
                  (EXTI_EXTICR1_EXTI0_MASK << (EXTI_EXTICR1_EXTI1_POS * (exti_line & 0x07))),
                  (gpio_id << (EXTI_EXTICR1_EXTI1_POS * (exti_line & 0x07))));
    }
}

/* EXTI初始化函数 */
void std_exti_init(std_exti_init_t* exti_init_param);
/* EXTI去初始化函数 */
void std_exti_deinit(void);
/* EXTI结构体初始化函数 */
void std_exti_struct_init(std_exti_init_t* exti_init_struct);

/** 
* @} 
*/


#ifdef __cplusplus
}
#endif

/**
* @} 
*/  

/**
* @}
*/

#endif /* STD_EXTI_H */
