/**
  * @brief DeInitializes the USART SmartCard peripheral 
  * @param  hsc: pointer to a SMARTCARD_HandleTypeDef structure that contains
  *                the configuration information for SMARTCARD module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SMARTCARD_DeInit(SMARTCARD_HandleTypeDef *hsc)
{
  /* Check the SMARTCARD handle allocation */
  if(hsc == NULL)
  {
    return HAL_ERROR;
  }

  /* Check the parameters */
  assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));

  hsc->State = HAL_SMARTCARD_STATE_BUSY;

  /* Disable the Peripheral */
  __HAL_SMARTCARD_DISABLE(hsc);

  /* DeInit the low level hardware */
  HAL_SMARTCARD_MspDeInit(hsc);

  hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
  hsc->State = HAL_SMARTCARD_STATE_RESET;

  /* Release Lock */
  __HAL_UNLOCK(hsc);

  return HAL_OK;
}
/**
  * @brief Initializes the SmartCard mode according to the specified
  *         parameters in the SMARTCARD_InitTypeDef and create the associated handle .
  * @param  hsc: pointer to a SMARTCARD_HandleTypeDef structure that contains
  *                the configuration information for SMARTCARD module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SMARTCARD_Init(SMARTCARD_HandleTypeDef *hsc)
{
  /* Check the SMARTCARD handle allocation */
  if(hsc == NULL)
  {
    return HAL_ERROR;
  }

  /* Check the parameters */
  assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));
  assert_param(IS_SMARTCARD_NACK_STATE(hsc->Init.NACKState));

  if(hsc->gState == HAL_SMARTCARD_STATE_RESET)
  {  
    /* Allocate lock resource and initialize it */
    hsc->Lock = HAL_UNLOCKED;
    /* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */
    HAL_SMARTCARD_MspInit(hsc);
  }
  
  hsc->gState = HAL_SMARTCARD_STATE_BUSY;

  /* Set the Prescaler */
  MODIFY_REG(hsc->Instance->GTPR, USART_GTPR_PSC, hsc->Init.Prescaler);

  /* Set the Guard Time */
  MODIFY_REG(hsc->Instance->GTPR, USART_GTPR_GT, ((hsc->Init.GuardTime)<<8));

  /* Set the Smartcard Communication parameters */
  SMARTCARD_SetConfig(hsc);

  /* In SmartCard mode, the following bits must be kept cleared: 
  - LINEN bit in the USART_CR2 register
  - HDSEL and IREN bits in the USART_CR3 register.*/
  hsc->Instance->CR2 &= ~USART_CR2_LINEN;
  hsc->Instance->CR3 &= ~(USART_CR3_IREN | USART_CR3_HDSEL);

  /* Enable the SMARTCARD Parity Error Interrupt */
  __HAL_SMARTCARD_ENABLE_IT(hsc, SMARTCARD_IT_PE);

  /* Enable the SMARTCARD Framing Error Interrupt */
  __HAL_SMARTCARD_ENABLE_IT(hsc, SMARTCARD_IT_ERR);

  /* Enable the Peripheral */
  __HAL_SMARTCARD_ENABLE(hsc);

  /* Configure the Smartcard NACK state */
  MODIFY_REG(hsc->Instance->CR3, USART_CR3_NACK, hsc->Init.NACKState);

  /* Enable the SC mode by setting the SCEN bit in the CR3 register */
  hsc->Instance->CR3 |= (USART_CR3_SCEN);

  /* Initialize the SMARTCARD state*/
  hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
  hsc->gState= HAL_SMARTCARD_STATE_READY;
  hsc->RxState= HAL_SMARTCARD_STATE_READY;

  return HAL_OK;
}
/**
  * @brief  Configures the SMARTCARD peripheral. 
  * @param  hsc: Pointer to a SMARTCARD_HandleTypeDef structure that contains
  *                the configuration information for the specified SMARTCARD module.
  * @retval None
  */
static void SMARTCARD_SetConfig(SMARTCARD_HandleTypeDef *hsc)
{
  /* Check the parameters */
  assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));
  assert_param(IS_SMARTCARD_POLARITY(hsc->Init.CLKPolarity));
  assert_param(IS_SMARTCARD_PHASE(hsc->Init.CLKPhase));
  assert_param(IS_SMARTCARD_LASTBIT(hsc->Init.CLKLastBit));
  assert_param(IS_SMARTCARD_BAUDRATE(hsc->Init.BaudRate));  
  assert_param(IS_SMARTCARD_WORD_LENGTH(hsc->Init.WordLength));
  assert_param(IS_SMARTCARD_STOPBITS(hsc->Init.StopBits));
  assert_param(IS_SMARTCARD_PARITY(hsc->Init.Parity));
  assert_param(IS_SMARTCARD_MODE(hsc->Init.Mode));
  assert_param(IS_SMARTCARD_NACK_STATE(hsc->Init.NACKState));

  /* The LBCL, CPOL and CPHA bits have to be selected when both the transmitter and the
     receiver are disabled (TE=RE=0) to ensure that the clock pulses function correctly. */
  CLEAR_BIT(hsc->Instance->CR1, (uint32_t)(USART_CR1_TE | USART_CR1_RE));
  
  /*-------------------------- SMARTCARD CR2 Configuration ------------------------*/
  /* Clear CLKEN, CPOL, CPHA and LBCL bits */
  /* Configure the SMARTCARD Clock, CPOL, CPHA and LastBit -----------------------*/
  /* Set CPOL bit according to hsc->Init.CLKPolarity value */
  /* Set CPHA bit according to hsc->Init.CLKPhase value */
  /* Set LBCL bit according to hsc->Init.CLKLastBit value */
  MODIFY_REG(hsc->Instance->CR2, 
             ((uint32_t)(USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | USART_CR2_LBCL)),
             ((uint32_t)(USART_CR2_CLKEN | hsc->Init.CLKPolarity | hsc->Init.CLKPhase| hsc->Init.CLKLastBit)) );
  
  /* Set Stop Bits: Set STOP[13:12] bits according to hsc->Init.StopBits value */
  MODIFY_REG(hsc->Instance->CR2, USART_CR2_STOP,(uint32_t)(hsc->Init.StopBits));

  /*-------------------------- SMARTCARD CR1 Configuration -----------------------*/
  /* Clear M, PCE, PS, TE and RE bits */
  /* Configure the SMARTCARD Word Length, Parity and mode: 
     Set the M bits according to hsc->Init.WordLength value 
     Set PCE and PS bits according to hsc->Init.Parity value
     Set TE and RE bits according to hsc->Init.Mode value */
  MODIFY_REG(hsc->Instance->CR1, 
             ((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | USART_CR1_RE)),
             ((uint32_t)(hsc->Init.WordLength | hsc->Init.Parity | hsc->Init.Mode)) );

  /*-------------------------- USART CR3 Configuration -----------------------*/  
  /* Clear CTSE and RTSE bits */
  CLEAR_BIT(hsc->Instance->CR3, (USART_CR3_RTSE | USART_CR3_CTSE));

  /*-------------------------- USART BRR Configuration -----------------------*/
  if(hsc->Instance == USART1)
  {
    hsc->Instance->BRR = SMARTCARD_BRR(HAL_RCC_GetPCLK2Freq(), hsc->Init.BaudRate);
  }
  else
  {
    hsc->Instance->BRR = SMARTCARD_BRR(HAL_RCC_GetPCLK1Freq(), hsc->Init.BaudRate);
  }
}
/**
  * @brief Initializes the SMARTCARD mode according to the specified
  *         parameters in the SMARTCARD_InitTypeDef and creates the associated handle .
  * @param hsc: SMARTCARD handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SMARTCARD_Init(SMARTCARD_HandleTypeDef *hsc)
{
  /* Check the SMARTCARD handle allocation */
  if(hsc == NULL)
  {
    return HAL_ERROR;
  }
  
  /* Check the USART associated to the SmartCard */
  assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));
  
  if(hsc->State == HAL_SMARTCARD_STATE_RESET)
  {  
    /* Allocate lock resource and initialize it */
    hsc->Lock = HAL_UNLOCKED;

    /* Init the low level hardware : GPIO, CLOCK, CORTEX */
    HAL_SMARTCARD_MspInit(hsc);
  }
  
  hsc->State = HAL_SMARTCARD_STATE_BUSY;
  
  /* Disable the Peripheral */
  __HAL_SMARTCARD_DISABLE(hsc);
  
  /* Set the SMARTCARD Communication parameters */
  SMARTCARD_SetConfig(hsc);
  
  if(hsc->AdvancedInit.AdvFeatureInit != SMARTCARD_ADVFEATURE_NO_INIT)
  {
    SMARTCARD_AdvFeatureConfig(hsc);
  }
  
  /* In SmartCard mode, the following bits must be kept cleared: 
  - LINEN in the USART_CR2 register,
  - HDSEL and IREN  bits in the USART_CR3 register.*/
  hsc->Instance->CR2 &= ~(USART_CR2_LINEN); 
  hsc->Instance->CR3 &= ~(USART_CR3_HDSEL | USART_CR3_IREN); 
  
  /* set the USART in SMARTCARD mode */ 
  hsc->Instance->CR3 |= USART_CR3_SCEN; 
  
  /* Enable the Peripheral */
  __HAL_SMARTCARD_ENABLE(hsc);
  
  /* TEACK and/or REACK to check before moving hsc->State to Ready */
  return (SMARTCARD_CheckIdleState(hsc));
}
/**
  * @brief Configure the SMARTCARD associated USART peripheral 
  * @param hsc: SMARTCARD handle
  * @retval None
  */
static void SMARTCARD_SetConfig(SMARTCARD_HandleTypeDef *hsc)
{
  uint32_t tmpreg = 0x00000000;
  uint32_t clocksource = 0x00000000;
  
  /* Check the parameters */ 
  assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));
  assert_param(IS_SMARTCARD_BAUDRATE(hsc->Init.BaudRate)); 
  assert_param(IS_SMARTCARD_WORD_LENGTH(hsc->Init.WordLength));  
  assert_param(IS_SMARTCARD_STOPBITS(hsc->Init.StopBits));   
  assert_param(IS_SMARTCARD_PARITY(hsc->Init.Parity));
  assert_param(IS_SMARTCARD_MODE(hsc->Init.Mode));
  assert_param(IS_SMARTCARD_POLARITY(hsc->Init.CLKPolarity));
  assert_param(IS_SMARTCARD_PHASE(hsc->Init.CLKPhase));
  assert_param(IS_SMARTCARD_LASTBIT(hsc->Init.CLKLastBit));    
  assert_param(IS_SMARTCARD_ONE_BIT_SAMPLE(hsc->Init.OneBitSampling));
  assert_param(IS_SMARTCARD_NACK(hsc->Init.NACKState));
  assert_param(IS_SMARTCARD_TIMEOUT(hsc->Init.TimeOutEnable));
  assert_param(IS_SMARTCARD_AUTORETRY_COUNT(hsc->Init.AutoRetryCount)); 

  /*-------------------------- USART CR1 Configuration -----------------------*/
  /* In SmartCard mode, M and PCE are forced to 1 (8 bits + parity).
   * Oversampling is forced to 16 (OVER8 = 0).
   * Configure the Parity and Mode: 
   *  set PS bit according to hsc->Init.Parity value
   *  set TE and RE bits according to hsc->Init.Mode value */
  tmpreg = (uint32_t) hsc->Init.Parity | hsc->Init.Mode;
  /* in case of TX-only mode, if NACK is enabled, the USART must be able to monitor 
     the bidirectional line to detect a NACK signal in case of parity error. 
     Therefore, the receiver block must be enabled as well (RE bit must be set). */
  if((hsc->Init.Mode == SMARTCARD_MODE_TX) && (hsc->Init.NACKState == SMARTCARD_NACK_ENABLE))
  {
    tmpreg |= USART_CR1_RE;   
  }
  tmpreg |= (uint32_t) hsc->Init.WordLength;
  MODIFY_REG(hsc->Instance->CR1, USART_CR1_FIELDS, tmpreg);

  /*-------------------------- USART CR2 Configuration -----------------------*/
  /* Stop bits are forced to 1.5 (STOP = 11) */
  tmpreg = hsc->Init.StopBits;
  /* Synchronous mode is activated by default */
  tmpreg |= (uint32_t) USART_CR2_CLKEN | hsc->Init.CLKPolarity; 
  tmpreg |= (uint32_t) hsc->Init.CLKPhase | hsc->Init.CLKLastBit;
  tmpreg |= (uint32_t) hsc->Init.TimeOutEnable;
  MODIFY_REG(hsc->Instance->CR2, USART_CR2_FIELDS, tmpreg); 
    
  /*-------------------------- USART CR3 Configuration -----------------------*/
  /* Configure 
   * - one-bit sampling method versus three samples' majority rule 
   *   according to hsc->Init.OneBitSampling 
   * - NACK transmission in case of parity error according 
   *   to hsc->Init.NACKEnable   
   * - autoretry counter according to hsc->Init.AutoRetryCount     */
  tmpreg =  (uint32_t) hsc->Init.OneBitSampling | hsc->Init.NACKState;
  tmpreg |= (uint32_t) (hsc->Init.AutoRetryCount << SMARTCARD_CR3_SCARCNT_LSB_POS);
  MODIFY_REG(hsc->Instance-> CR3,USART_CR3_FIELDS, tmpreg);
  
  /*-------------------------- USART GTPR Configuration ----------------------*/
  tmpreg = (uint32_t) (hsc->Init.Prescaler | (hsc->Init.GuardTime << SMARTCARD_GTPR_GT_LSB_POS));
  MODIFY_REG(hsc->Instance->GTPR, (uint32_t)(USART_GTPR_GT|USART_GTPR_PSC), tmpreg); 
  
  /*-------------------------- USART RTOR Configuration ----------------------*/ 
  tmpreg =   (uint32_t) (hsc->Init.BlockLength << SMARTCARD_RTOR_BLEN_LSB_POS);
  if(hsc->Init.TimeOutEnable == SMARTCARD_TIMEOUT_ENABLE)
  {
    assert_param(IS_SMARTCARD_TIMEOUT_VALUE(hsc->Init.TimeOutValue));
    tmpreg |=  (uint32_t) hsc->Init.TimeOutValue;
  }
  MODIFY_REG(hsc->Instance->RTOR, (USART_RTOR_RTO|USART_RTOR_BLEN), tmpreg);
  
  /*-------------------------- USART BRR Configuration -----------------------*/
  SMARTCARD_GETCLOCKSOURCE(hsc, clocksource);
  switch (clocksource)
  {
  case SMARTCARD_CLOCKSOURCE_PCLK1: 
    hsc->Instance->BRR = (uint16_t)(HAL_RCC_GetPCLK1Freq() / hsc->Init.BaudRate);
    break;
  case SMARTCARD_CLOCKSOURCE_PCLK2: 
    hsc->Instance->BRR = (uint16_t)(HAL_RCC_GetPCLK2Freq() / hsc->Init.BaudRate);
    break;
  case SMARTCARD_CLOCKSOURCE_HSI: 
    hsc->Instance->BRR = (uint16_t)(HSI_VALUE / hsc->Init.BaudRate); 
    break; 
  case SMARTCARD_CLOCKSOURCE_SYSCLK:  
    hsc->Instance->BRR = (uint16_t)(HAL_RCC_GetSysClockFreq() / hsc->Init.BaudRate);
    break;  
  case SMARTCARD_CLOCKSOURCE_LSE:                
    hsc->Instance->BRR = (uint16_t)(LSE_VALUE / hsc->Init.BaudRate); 
    break;
  default:
    break;
  } 
}
/**
  * @brief  Initializes the SmartCard mode according to the specified
  *         parameters in the SMARTCARD_HandleTypeDef and create the associated handle.
  * @param  hsc: Pointer to a SMARTCARD_HandleTypeDef structure that contains
  *              the configuration information for the specified SMARTCARD module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SMARTCARD_Init(SMARTCARD_HandleTypeDef *hsc)
{
  /* Check the SMARTCARD handle allocation */
  if(hsc == NULL)
  {
    return HAL_ERROR;
  }

  /* Check Wordlength, Parity and Stop bits parameters */
  if (  (!(IS_SMARTCARD_WORD_LENGTH(hsc->Init.WordLength)))
      ||(!(IS_SMARTCARD_STOPBITS(hsc->Init.StopBits)))
      ||(!(IS_SMARTCARD_PARITY(hsc->Init.Parity)))  )
  {
    return HAL_ERROR;
  }

  /* Check the parameters */
  assert_param(IS_SMARTCARD_INSTANCE(hsc->Instance));
  assert_param(IS_SMARTCARD_NACK_STATE(hsc->Init.NACKState));
  assert_param(IS_SMARTCARD_PRESCALER(hsc->Init.Prescaler));

  if(hsc->State == HAL_SMARTCARD_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hsc->Lock = HAL_UNLOCKED;

    /* Init the low level hardware */
    HAL_SMARTCARD_MspInit(hsc);
  }

  hsc->State = HAL_SMARTCARD_STATE_BUSY;

  /* Disable the Peripheral */
  __HAL_SMARTCARD_DISABLE(hsc);

  /* Set the Prescaler */
  MODIFY_REG(hsc->Instance->GTPR, USART_GTPR_PSC, hsc->Init.Prescaler);

  /* Set the Guard Time */
  MODIFY_REG(hsc->Instance->GTPR, USART_GTPR_GT, ((hsc->Init.GuardTime)<<8));

  /* Set the Smartcard Communication parameters */
  SMARTCARD_SetConfig(hsc);

  /* In SmartCard mode, the following bits must be kept cleared:
  - LINEN bit in the USART_CR2 register
  - HDSEL and IREN bits in the USART_CR3 register.*/
  CLEAR_BIT(hsc->Instance->CR2, USART_CR2_LINEN);
  CLEAR_BIT(hsc->Instance->CR3, (USART_CR3_IREN | USART_CR3_HDSEL));

  /* Enable the Peripharal */
  __HAL_SMARTCARD_ENABLE(hsc);

  /* Configure the Smartcard NACK state */
  MODIFY_REG(hsc->Instance->CR3, USART_CR3_NACK, hsc->Init.NACKState);

  /* Enable the SC mode by setting the SCEN bit in the CR3 register */
  SET_BIT(hsc->Instance->CR3, USART_CR3_SCEN);

  /* Initialize the SMARTCARD state*/
  hsc->ErrorCode = HAL_SMARTCARD_ERROR_NONE;
  hsc->State= HAL_SMARTCARD_STATE_READY;

  return HAL_OK;
}