/**
  ******************************************************************************
  * @file    lcm32f06x_exti.c
  * @author  System R&D Team
  * @version V2.0.2
  * @date    10-April-2025
  * @brief   This file provides all the EXTI firmware functions.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) Hangzhou Lingxin Microelectronics Co.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "lcm32f06x_exti.h"


#define EXTI_LINENONE ((uint32_t)0x00000) /* No interrupt selected */

/**
  * @name   EXTI_DeInit
  * @brief  EN: Deinitializes EXTI peripheral registers to their default reset values.
  *         CN: 将 EXTI 外设寄存器初始化为其默认重置值
  * @param  None
  * @retval None
  */
void EXTI_DeInit(void)
{
  EXTI->IMR = 0x00000000;
  EXTI->EMR = 0x00000000;
  EXTI->RTSR = 0x00000000;
  EXTI->FTSR = 0x00000000;
  EXTI->PR = 0x01FFFFFF;
}


/**
  * @name EXTI_Init
  * @brief  EN: Initializes the EXTI according to the specified
  *             parameters in the EXTI_InitTypeDef.
  *         CN: 根据EXTI_InitTypeDef中指定的参数初始化EXTI。
  * @param  EXTI_InitStruct: 
  *         EN: pointer to a EXTI_InitTypeDef structure that contains the
  *             configuration information for the specified EXTI peripheral.
  *         CN: 指向EXTI_InitTypeDef结构的指针，该结构包含指定EXTI外围设备的配置信息。
  * @retval None
  */
void EXTI_Init(EXTI_InitTypeDef *EXTI_InitStruct)
{
  uint32_t tmp = 0;

  /* Check the parameters */
  assert_param(IS_EXTI_MODE(EXTI_InitStruct->EXTI_Mode));
  assert_param(IS_EXTI_TRIGGER(EXTI_InitStruct->EXTI_Trigger));
  assert_param(IS_EXTI_LINE(EXTI_InitStruct->EXTI_Line));
  assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->EXTI_LineCmd));

  tmp = (uint32_t)EXTI_BASE;

  if (EXTI_InitStruct->EXTI_LineCmd != DISABLE)
  {
    /* Clear EXTI line configuration */
    EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line;
    EXTI->EMR &= ~EXTI_InitStruct->EXTI_Line;

    tmp += EXTI_InitStruct->EXTI_Mode;

    *(__IO uint32_t *)tmp |= EXTI_InitStruct->EXTI_Line;

    /* Clear Rising Falling edge configuration */
    EXTI->RTSR &= ~EXTI_InitStruct->EXTI_Line;
    EXTI->FTSR &= ~EXTI_InitStruct->EXTI_Line;

    /* Select the trigger for the selected external interrupts */
    if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling)
    {
      /* Rising Falling edge */
      EXTI->RTSR |= EXTI_InitStruct->EXTI_Line;
      EXTI->FTSR |= EXTI_InitStruct->EXTI_Line;
    }
    else
    {
      tmp = (uint32_t)EXTI_BASE;
      tmp += EXTI_InitStruct->EXTI_Trigger;

      *(__IO uint32_t *)tmp |= EXTI_InitStruct->EXTI_Line;
    }
  }
  else
  {
    tmp += EXTI_InitStruct->EXTI_Mode;

    /* Disable the selected external lines */
    *(__IO uint32_t *)tmp &= ~EXTI_InitStruct->EXTI_Line;
  }
}

/**
  * @name   EXTI_StructInit
  * @brief  EN: Fills each EXTI_InitStruct member with its default value.
  *         CN: 用默认值填充每个 EXTI_InitStruct 成员。
  * @param  EXTI_InitStruct:
  *         EN: pointer to a EXTI_InitTypeDef structure that contains the 
  *             configuration information for the specified EXTI peripheral.
  *         CN: 指向 EXTI_InitTypeDef 结构的指针，该结构包含指定 EXTI 外设的配置信息。
  * @retval None
  */
void EXTI_StructInit(EXTI_InitTypeDef *EXTI_InitStruct)
{
  EXTI_InitStruct->EXTI_Line = EXTI_LINENONE;
  EXTI_InitStruct->EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStruct->EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStruct->EXTI_LineCmd = DISABLE;
}

/**
  * @name   EXTI_GenerateSWInterrupt
  * @brief  EN: Generates a Software interrupt.
  *         CN: 生成软件中断。
  * @param  EXTI_Line:
  *         EN: specifies the EXTI lines to be enabled or disabled.
  *             This parameter can be any combination of EXTI_Linex where x can be (0..23).
  *         CN: 指定要启用或禁用的EXTI线。
  *             此参数可以是EXTI_Linex的任意组合，其中x可以是（0..23）。
  * @retval None
  */
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line)
{
  /* Check the parameters */
  assert_param(IS_EXTI_LINE(EXTI_Line));

  EXTI->SWIER |= EXTI_Line;
}

/**
  * @name   EXTI_GetFlagStatus
  * @brief  EN: Checks whether the specified EXTI line flag is set or not.
  *         CN: 检查是否设置了指定的EXTI线标志。
  * @param  EXTI_Line:
  *         EN: specifies the EXTI lines to be enabled or disabled.
  *             This parameter can be any combination of EXTI_Linex where x can be (0..23).
  *         CN: 指定要启用或禁用的EXTI线。
  *             此参数可以是EXTI_Linex的任意组合，其中x可以是（0..23）。
  * @retval FlagStatus
  */
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line)
{
  FlagStatus bitstatus = RESET;
  /* Check the parameters */
  assert_param(IS_GET_EXTI_LINE(EXTI_Line));

  if ((EXTI->PR & EXTI_Line) != (uint32_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

/**
  * @name   EXTI_ClearFlag
  * @brief  EN: Clears the EXTI's line pending flags.
  *         CN: 清除EXTI 线挂起标志。
  * @param  EXTI_Line:
  *         EN: specifies the EXTI lines to be enabled or disabled.
  *             This parameter can be any combination of EXTI_Linex where x can be (0..23).
  *         CN: 指定要启用或禁用的EXTI线。
  *             此参数可以是EXTI_Linex的任意组合，其中x可以是（0..23）。
  * @retval None
  */
void EXTI_ClearFlag(uint32_t EXTI_Line)
{
  /* Check the parameters */
  assert_param(IS_EXTI_LINE(EXTI_Line));

  EXTI->PR = EXTI_Line;
}

/**
  * @name   EXTI_GetITStatus
  * @brief  EN: Obtain the interrupt status of EXTI lines.
  *         CN: 获取EXTI 线的中断状态。
  * @param  EXTI_Line:
  *         EN: specifies the EXTI lines to be enabled or disabled.
  *             This parameter can be any combination of EXTI_Linex where x can be (0..23).
  *         CN: 指定要启用或禁用的EXTI线。
  *             此参数可以是EXTI_Linex的任意组合，其中x可以是（0..23）。
  * @retval ITStatus
  */
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
{
  ITStatus bitstatus = RESET;
  uint32_t enablestatus = 0;
  /* Check the parameters */
  assert_param(IS_GET_EXTI_LINE(EXTI_Line));

  enablestatus = EXTI->IMR & EXTI_Line;
  if (((EXTI->PR & EXTI_Line) != (uint32_t)RESET) && (enablestatus != (uint32_t)RESET))
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

/**
  * @name   EXTI_ClearITPendingBit
  * @brief  EN: Clears the EXTI's line pending bits.
  *         CN: 清除EXTI的行挂起位。
  * @param  EXTI_Line:
  *         EN: specifies the EXTI lines to be enabled or disabled.
  *             This parameter can be any combination of EXTI_Linex where x can be (0..23).
  *         CN: 指定要启用或禁用的EXTI线。
  *             此参数可以是EXTI_Linex的任意组合，其中x可以是（0..23）。
  * @retval ITStatus
  */
void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
{
  /* Check the parameters */
  assert_param(IS_EXTI_LINE(EXTI_Line));

  EXTI->PR = EXTI_Line;
}

/**
  * @name   EXTI_ConnectTo
  * @brief  EN: GPIO optional interrupt line.
  *         CN: GPIO可选连中断线上。
  * @param  GPIOx:
  *         EN: where x can be A or B to select the GPIO peripheral.
  *         CN: x 可以是 A 或 B 以选择 GPIO 外设
  * @param  EXTI_Line:
  *         EN: specifies the EXTI lines to be enabled or disabled.
  *             This parameter can be any combination of EXTI_Linex where x can be (0..23).
  *         CN: 指定要启用或禁用的EXTI线。
  *             此参数可以是EXTI_Linex的任意组合，其中x可以是（0..23）。
  * @retval ITStatus
  */
void EXTI_ConnectTo(GPIO_TypeDef *GPIOx, uint32_t EXTI_Line)
{
  unsigned int tmpreg = 0, tmpreg1 = 0, tmpFlag;
  unsigned char i, setValue;
  unsigned char tmpLine;
  tmpreg = SYSCTRL->EXTI_CFG0;
  tmpreg1 = SYSCTRL->EXTI_CFG1;
  if (GPIOx == GPIOA)
    setValue = 0;
  if (GPIOx == GPIOB)
    setValue = 1;
  tmpLine = 0;
  for (i = 0; i < 16; i++)
  {
    tmpFlag = EXTI_Line & (1 << i);
    tmpLine++;
    if (tmpFlag)
    {
      if (tmpLine <= 8)
      {
        tmpreg &= ~((7) << (4 * (tmpLine - 1)));
        tmpreg |= setValue << (4 * (tmpLine - 1));
        sysctrl_access();
        SYSCTRL->EXTI_CFG0 |= tmpreg;
        __dekey();
      }
      else
      {
        tmpreg1 &= ~((7) << (4 * (tmpLine - 9)));
        tmpreg1 |= setValue << (4 * (tmpLine - 9));
        sysctrl_access();
        SYSCTRL->EXTI_CFG1 |= tmpreg1;
        __dekey();
      }
    }
  }
}

/**
  * @name   NVIC_Init
  * @brief  EN: Initializes the NVIC peripheral according to the specified parameters in the NVIC_InitStruct.
  *         CN: 根据NVIC_InitStruct中的指定参数初始化NVIC外围设备。
  * @param  NVIC_InitStruct: 
  *         EN: pointer to a NVIC_InitTypeDef structure that contains the configuration information for the specified NVIC peripheral.
  *         CN: 指向NVIC_InitTypeDef结构的指针，该结构包含指定NVIC外围设备的配置信息。
  * @retval None
  */
void NVIC_Init(NVIC_InitTypeDef *NVIC_InitStruct)
{
  uint32_t tmppriority = 0x00;

  /* Check the parameters */
  if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
  {
    /* Compute the Corresponding IRQ Priority --------------------------------*/
    tmppriority = NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel >> 0x02];
    tmppriority &= (uint32_t)(~(((uint32_t)0xFF) << ((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8)));
    tmppriority |= (uint32_t)((((uint32_t)NVIC_InitStruct->NVIC_IRQChannelPriority << 6) & 0xFF) << ((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8));

    NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel >> 0x02] = tmppriority;

    /* Enable the Selected IRQ Channels --------------------------------------*/
    NVIC->ISER[0] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
  }
  else
  {
    /* Disable the Selected IRQ Channels -------------------------------------*/
    NVIC->ICER[0] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
  }
}
