675 lines
20 KiB
C
675 lines
20 KiB
C
/**
|
|
******************************************************************************
|
|
* @file SMARTCARD_T0/Src/smartcard.c
|
|
* @author MCD Application Team
|
|
* @brief This file provides all the Smartcard firmware functions.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2016 STMicroelectronics.
|
|
* 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.
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/** @addtogroup STM32F1xx_HAL_Examples
|
|
* @{
|
|
*/
|
|
|
|
/** @addtogroup SMARTCARD_T0
|
|
* @{
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "smartcard.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
/* Private variables ---------------------------------------------------------*/
|
|
/* Global variables definition and initialization ----------------------------*/
|
|
SC_ATR SC_A2R;
|
|
uint8_t SC_ATR_Table[40] = {0};
|
|
static __IO uint8_t SCData = 0;
|
|
static uint32_t F_Table[16] = {372, 372, 558, 744, 1116, 1488, 1860, 0,
|
|
0, 512, 768, 1024, 1536, 2048, 0, 0};
|
|
static uint32_t D_Table[16] = {0, 1, 2, 4, 8, 16, 32, 0, 12, 20, 0, 0, 0, 0, 0, 0};
|
|
SMARTCARD_HandleTypeDef SCHandle;
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* Transport Layer -----------------------------------------------------------*/
|
|
/*--------------APDU-----------*/
|
|
void SC_SendData(SC_ADPU_Commands *SC_ADPU, SC_ADPU_Response *SC_ResponseStatus);
|
|
|
|
/*------------ ATR ------------*/
|
|
static void SC_AnswerReq(SC_State *SCState, uint8_t *card, uint8_t length); /* Ask ATR */
|
|
static uint8_t SC_decode_Answer2reset(uint8_t *card); /* Decode ATR */
|
|
|
|
/* Physical Port Layer -------------------------------------------------------*/
|
|
static void SC_Init(void);
|
|
static void SC_DeInit(void);
|
|
static void SC_VoltageConfig(uint32_t SC_Voltage);
|
|
static uint8_t SC_Detect(void);
|
|
|
|
/* Private functions ---------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Handles all Smartcard states and serves to send and receive all
|
|
* communication data between Smartcard and reader.
|
|
* @param SCState: pointer to an SC_State enumeration that will contain the
|
|
* Smartcard state.
|
|
* @param SC_ADPU: pointer to an SC_ADPU_Commands structure that will be initialized.
|
|
* @param SC_Response: pointer to a SC_ADPU_Response structure which will be initialized.
|
|
* @retval None
|
|
*/
|
|
void SC_Handler(SC_State *SCState, SC_ADPU_Commands *SC_ADPU, SC_ADPU_Response *SC_Response)
|
|
{
|
|
uint32_t i = 0;
|
|
switch(*SCState)
|
|
{
|
|
case SC_POWER_ON:
|
|
if (SC_ADPU->Header.INS == SC_GET_A2R)
|
|
{
|
|
/* Smartcard initialization --------------------------------------------*/
|
|
SC_Init();
|
|
|
|
/* Reset Data from SC buffer -------------------------------------------*/
|
|
for (i = 0; i < 40; i++)
|
|
{
|
|
SC_ATR_Table[i] = 0;
|
|
}
|
|
|
|
/* Reset SC_A2R Structure ----------------------------------------------*/
|
|
SC_A2R.TS = 0;
|
|
SC_A2R.T0 = 0;
|
|
for (i = 0; i < SETUP_LENGTH; i++)
|
|
{
|
|
SC_A2R.T[i] = 0;
|
|
}
|
|
for (i = 0; i < HIST_LENGTH; i++)
|
|
{
|
|
SC_A2R.H[i] = 0;
|
|
}
|
|
SC_A2R.Tlength = 0;
|
|
SC_A2R.Hlength = 0;
|
|
|
|
/* Next State ----------------------------------------------------------*/
|
|
*SCState = SC_RESET_LOW;
|
|
}
|
|
break;
|
|
|
|
case SC_RESET_LOW:
|
|
if(SC_ADPU->Header.INS == SC_GET_A2R)
|
|
{
|
|
/* If card is detected then Power ON, Card Reset and wait for an answer) */
|
|
if (SC_Detect())
|
|
{
|
|
while(((*SCState) != SC_POWER_OFF) && ((*SCState) != SC_ACTIVE))
|
|
{
|
|
SC_AnswerReq(SCState, (uint8_t *)&SC_ATR_Table, 40); /* Check for answer to reset */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*SCState) = SC_POWER_OFF;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SC_ACTIVE:
|
|
if (SC_ADPU->Header.INS == SC_GET_A2R)
|
|
{
|
|
if(SC_decode_Answer2reset(&SC_ATR_Table[0]) == T0_PROTOCOL)
|
|
{
|
|
(*SCState) = SC_ACTIVE_ON_T0;
|
|
}
|
|
else
|
|
{
|
|
(*SCState) = SC_POWER_OFF;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SC_ACTIVE_ON_T0:
|
|
SC_SendData(SC_ADPU, SC_Response);
|
|
break;
|
|
|
|
case SC_POWER_OFF:
|
|
SC_DeInit(); /* Disable Smartcard interface */
|
|
break;
|
|
|
|
default: (*SCState) = SC_POWER_OFF;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Enables or disables the power to the Smartcard.
|
|
* @param NewState: new state of the Smartcard power supply.
|
|
* This parameter can be: ENABLE or DISABLE.
|
|
* @retval None
|
|
*/
|
|
void SC_PowerCmd(FunctionalState NewState)
|
|
{
|
|
if(NewState != DISABLE)
|
|
{
|
|
HAL_GPIO_WritePin(SC_CMDVCC_GPIO_PORT, SC_CMDVCC_PIN, GPIO_PIN_RESET);
|
|
}
|
|
else
|
|
{
|
|
HAL_GPIO_WritePin(SC_CMDVCC_GPIO_PORT, SC_CMDVCC_PIN, GPIO_PIN_SET);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Sets or clears the Smartcard reset pin.
|
|
* @param ResetState: this parameter specifies the state of the Smartcard
|
|
* reset pin. BitVal must be one of the GPIO_PinState enum values:
|
|
* @arg GPIO_PIN_RESET: to clear the port pin.
|
|
* @arg GPIO_PIN_SET: to set the port pin.
|
|
* @retval None
|
|
*/
|
|
void SC_Reset(GPIO_PinState ResetState)
|
|
{
|
|
HAL_GPIO_WritePin(SC_RESET_GPIO_PORT, SC_RESET_PIN, ResetState);
|
|
}
|
|
|
|
/**
|
|
* @brief Resends the byte that failed to be received (by the Smartcard) correctly.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void SC_ParityErrorHandler(void)
|
|
{
|
|
HAL_SMARTCARD_Transmit(&SCHandle, (uint8_t *)&SCData, 1, SC_TRANSMIT_TIMEOUT);
|
|
}
|
|
|
|
/**
|
|
* @brief Configures the IO speed (BaudRate) communication.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void SC_PTSConfig(void)
|
|
{
|
|
uint32_t workingbaudrate = 0, apbclock = 0;
|
|
uint8_t PPSConfirmStatus = 1;
|
|
uint8_t ptscmd[4] = {0x00};
|
|
uint8_t ptsanswer[4] = {0x00};
|
|
|
|
/* Reconfigure the USART Baud Rate -----------------------------------------*/
|
|
apbclock = HAL_RCC_GetPCLK1Freq();
|
|
apbclock /= ((SC_USART->GTPR & (uint16_t)0x00FF) * 2);
|
|
|
|
/* Enable the DMA Receive (Set DMAR bit only) to enable interrupt generation
|
|
in case of a framing error FE */
|
|
__HAL_SMARTCARD_DMA_REQUEST_ENABLE(&SCHandle, SMARTCARD_DMAREQ_RX);
|
|
|
|
if((SC_A2R.T0 & (uint8_t)0x10) == 0x10)
|
|
{
|
|
if(SC_A2R.T[0] != 0x11)
|
|
{
|
|
/* PPSS identifies the PPS request or response and is equal to 0xFF */
|
|
ptscmd[0] = 0xFF;
|
|
|
|
/* PPS0 indicates by the bits b5, b6, b7 equal to 1 the presence of the optional
|
|
bytes PPSI1, PPS2, PPS3 respectively */
|
|
ptscmd[1] = 0x10;
|
|
|
|
/* PPS1 allows the interface device to propose value of F and D to the card */
|
|
ptscmd[2] = SC_A2R.T[0];
|
|
|
|
/* PCK check character */
|
|
ptscmd[3] = (uint8_t)0xFF^(uint8_t)0x10^(uint8_t)SC_A2R.T[0];
|
|
|
|
/* Start the receive IT process: to receive the command answer from the card */
|
|
HAL_SMARTCARD_Receive_IT(&SCHandle, (uint8_t *)ptsanswer, 4);
|
|
|
|
/* Send command */
|
|
HAL_SMARTCARD_Transmit(&SCHandle, (uint8_t *)ptscmd, 4, SC_TRANSMIT_TIMEOUT);
|
|
|
|
/* Disable the DMA Receive Request */
|
|
__HAL_SMARTCARD_DMA_REQUEST_DISABLE(&SCHandle, SMARTCARD_DMAREQ_RX);
|
|
|
|
/* Wait until receiving the answer from the card */
|
|
while(HAL_SMARTCARD_GetState(&SCHandle) != HAL_SMARTCARD_STATE_READY)
|
|
{}
|
|
|
|
/* Check the received command answer */
|
|
if((ptsanswer[0] != 0xFF) || (ptsanswer[1] != 0x10) || (ptsanswer[2] != SC_A2R.T[0]) || (ptsanswer[3] != ((uint8_t)0xFF^(uint8_t)0x10^(uint8_t)SC_A2R.T[0])))
|
|
{
|
|
/* PPSS, PPS0, PPS1 and PCK exchange unsuccessful */
|
|
PPSConfirmStatus = 0x00;
|
|
}
|
|
|
|
/* PPS exchange successful */
|
|
if(PPSConfirmStatus == 0x01)
|
|
{
|
|
workingbaudrate = apbclock * D_Table[(SC_A2R.T[0] & (uint8_t)0x0F)];
|
|
workingbaudrate /= F_Table[((SC_A2R.T[0] >> 4) & (uint8_t)0x0F)];
|
|
|
|
SCHandle.Init.BaudRate = workingbaudrate;
|
|
SCHandle.Init.WordLength = SMARTCARD_WORDLENGTH_9B;
|
|
SCHandle.Init.StopBits = SMARTCARD_STOPBITS_1_5;
|
|
SCHandle.Init.Parity = SMARTCARD_PARITY_EVEN;
|
|
SCHandle.Init.Mode = SMARTCARD_MODE_TX_RX;
|
|
SCHandle.Init.CLKPolarity = SMARTCARD_POLARITY_LOW;
|
|
SCHandle.Init.CLKPhase = SMARTCARD_PHASE_1EDGE;
|
|
SCHandle.Init.CLKLastBit = SMARTCARD_LASTBIT_ENABLE;
|
|
SCHandle.Init.Prescaler = SMARTCARD_PRESCALER_SYSCLK_DIV10;
|
|
SCHandle.Init.GuardTime = 16;
|
|
SCHandle.Init.NACKState = SMARTCARD_NACK_ENABLE;
|
|
SCHandle.Instance = SC_USART;
|
|
|
|
if(HAL_SMARTCARD_Init(&SCHandle) != HAL_OK)
|
|
{
|
|
while (1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Manages the Smartcard transport layer: send APDU commands and receives
|
|
* the APDU response.
|
|
* @param SC_ADPU: pointer to a SC_ADPU_Commands structure which will be initialized.
|
|
* @param SC_ADPU_Response: pointer to a SC_ADPU_Response structure which will be initialized.
|
|
* @retval None
|
|
*/
|
|
void SC_SendData(SC_ADPU_Commands *SC_ADPU, SC_ADPU_Response *SC_ResponseStatus)
|
|
{
|
|
uint32_t i = 0;
|
|
|
|
uint8_t command[5] = {0x00};
|
|
uint8_t answer[40] = {0x00};
|
|
|
|
/* Reset response buffer ---------------------------------------------------*/
|
|
for(i = 0; i < LC_MAX; i++)
|
|
{
|
|
SC_ResponseStatus->Data[i] = 0;
|
|
}
|
|
|
|
SC_ResponseStatus->SW1 = 0;
|
|
SC_ResponseStatus->SW2 = 0;
|
|
|
|
/* Enable the DMA Receive (Set DMAR bit only) to enable interrupt generation
|
|
in case of a framing error FE */
|
|
__HAL_SMARTCARD_DMA_REQUEST_ENABLE(&SCHandle, SMARTCARD_DMAREQ_RX);
|
|
|
|
/* Send header -------------------------------------------------------------*/
|
|
command[0] = SC_ADPU->Header.CLA;
|
|
command[1] = SC_ADPU->Header.INS;
|
|
command[2] = SC_ADPU->Header.P1;
|
|
command[3] = SC_ADPU->Header.P2;
|
|
|
|
/* Send body length to/from SC ---------------------------------------------*/
|
|
if(SC_ADPU->Body.LC)
|
|
{
|
|
command[4] = SC_ADPU->Body.LC;
|
|
HAL_SMARTCARD_Transmit(&SCHandle, (uint8_t *)command, 5, SC_TRANSMIT_TIMEOUT);
|
|
}
|
|
else if(SC_ADPU->Body.LE)
|
|
{
|
|
command[4] = SC_ADPU->Body.LE;
|
|
HAL_SMARTCARD_Transmit(&SCHandle, (uint8_t *)command, 5, SC_TRANSMIT_TIMEOUT);
|
|
}
|
|
|
|
/* Flush the SC_USART DR */
|
|
__HAL_SMARTCARD_FLUSH_DRREGISTER(&SCHandle);
|
|
|
|
/* Start the receive IT process: to receive the command answer from the card */
|
|
HAL_SMARTCARD_Receive_IT(&SCHandle, (uint8_t *)&answer[0], 1);
|
|
|
|
/* Wait until receiving the answer from the card */
|
|
while(HAL_SMARTCARD_GetState(&SCHandle) != HAL_SMARTCARD_STATE_READY)
|
|
{}
|
|
|
|
/* --------------------------------------------------------
|
|
Wait Procedure byte from card:
|
|
1 - ACK
|
|
2 - NULL
|
|
3 - SW1; SW2
|
|
-------------------------------------------------------- */
|
|
if(((answer[0] & (uint8_t)0xF0) == 0x60) || ((answer[0] & (uint8_t)0xF0) == 0x90))
|
|
{
|
|
/* SW1 received */
|
|
SC_ResponseStatus->SW1 = answer[0];
|
|
|
|
if(HAL_SMARTCARD_Receive_IT(&SCHandle, (uint8_t *)&answer[1], 1) == HAL_OK)
|
|
{
|
|
/* SW2 received */
|
|
SC_ResponseStatus->SW2 = answer[1];
|
|
}
|
|
}
|
|
else if(((answer[0] & (uint8_t)0xFE) == (((uint8_t)~(SC_ADPU->Header.INS)) & (uint8_t)0xFE)) || \
|
|
((answer[0] & (uint8_t)0xFE) == (SC_ADPU->Header.INS & (uint8_t)0xFE)))
|
|
{
|
|
SC_ResponseStatus->Data[0] = answer[0];/* ACK received */
|
|
}
|
|
|
|
/* If no status bytes received ---------------------------------------------*/
|
|
if(SC_ResponseStatus->SW1 == 0x00)
|
|
{
|
|
/* Send body data to SC --------------------------------------------------*/
|
|
if(SC_ADPU->Body.LC)
|
|
{
|
|
/* Send body data */
|
|
HAL_SMARTCARD_Transmit(&SCHandle, (uint8_t *)&SC_ADPU->Body.Data[0], SC_ADPU->Body.LC, SC_TRANSMIT_TIMEOUT);
|
|
|
|
/* Flush the SC_USART DR */
|
|
__HAL_SMARTCARD_FLUSH_DRREGISTER(&SCHandle);
|
|
|
|
/* Disable the DMA Receive (Reset DMAR bit only) */
|
|
__HAL_SMARTCARD_DMA_REQUEST_DISABLE(&SCHandle, SMARTCARD_DMAREQ_RX);
|
|
|
|
/* Start the receive IT process: to receive the command answer from the card */
|
|
HAL_SMARTCARD_Receive_IT(&SCHandle, (uint8_t *)&answer[0], 2);
|
|
|
|
/* Wait until receiving the answer from the card */
|
|
while(HAL_SMARTCARD_GetState(&SCHandle) != HAL_SMARTCARD_STATE_READY)
|
|
{}
|
|
|
|
/* Decode the SW1 */
|
|
SC_ResponseStatus->SW1 = answer[0];
|
|
|
|
/* Decode the SW2 */
|
|
SC_ResponseStatus->SW2 = answer[1];
|
|
}
|
|
|
|
/* Or receive body data from SC ------------------------------------------*/
|
|
else if(SC_ADPU->Body.LE)
|
|
{
|
|
/* Start the receive IT process: to receive the command answer from the card */
|
|
HAL_SMARTCARD_Receive_IT(&SCHandle, (uint8_t *)&answer[0], (SC_ADPU->Body.LE +2));
|
|
|
|
/* Wait until receiving the answer from the card */
|
|
while(HAL_SMARTCARD_GetState(&SCHandle) != HAL_SMARTCARD_STATE_READY)
|
|
{}
|
|
|
|
/* Decode the body data */
|
|
for(i = 0; i < SC_ADPU->Body.LE; i++)
|
|
{
|
|
SC_ResponseStatus->Data[i] = answer[i];
|
|
}
|
|
|
|
/* Decode the SW1 */
|
|
SC_ResponseStatus->SW1 = answer[SC_ADPU->Body.LE];
|
|
|
|
/* Decode the SW2 */
|
|
SC_ResponseStatus->SW2 = answer[SC_ADPU->Body.LE +1];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Requests the reset answer from card.
|
|
* @param SCState: pointer to an SC_State enumeration that will contain the Smartcard state.
|
|
* @param card: pointer to a buffer which will contain the card ATR.
|
|
* @param length: maximum ATR length
|
|
* @retval None
|
|
*/
|
|
static void SC_AnswerReq(SC_State *SCState, uint8_t *card, uint8_t length)
|
|
{
|
|
switch(*SCState)
|
|
{
|
|
case SC_RESET_LOW:
|
|
/* Check response with reset low -----------------------------------------*/
|
|
HAL_SMARTCARD_Receive(&SCHandle, card, length, SC_RECEIVE_TIMEOUT);
|
|
|
|
if(card[0] != 0x00)
|
|
{
|
|
(*SCState) = SC_ACTIVE;
|
|
SC_Reset(GPIO_PIN_SET);
|
|
}
|
|
else
|
|
{
|
|
(*SCState) = SC_RESET_HIGH;
|
|
}
|
|
break;
|
|
|
|
case SC_RESET_HIGH:
|
|
/* Check response with reset high ----------------------------------------*/
|
|
SC_Reset(GPIO_PIN_SET); /* Reset High */
|
|
HAL_SMARTCARD_Receive(&SCHandle, card, length, SC_RECEIVE_TIMEOUT);
|
|
|
|
if(card[0])
|
|
{
|
|
(*SCState) = SC_ACTIVE;
|
|
}
|
|
else
|
|
{
|
|
(*SCState) = SC_POWER_OFF;
|
|
}
|
|
break;
|
|
|
|
case SC_ACTIVE:
|
|
break;
|
|
|
|
case SC_POWER_OFF:
|
|
/* Close Connection if no answer received --------------------------------*/
|
|
SC_Reset(GPIO_PIN_SET); /* Reset high - a bit is used as level shifter from 3.3 to 5 V */
|
|
SC_PowerCmd(DISABLE);
|
|
break;
|
|
|
|
default:
|
|
(*SCState) = SC_RESET_LOW;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Decodes the Answer to reset received from card.
|
|
* @param card: pointer to the buffer containing the card ATR.
|
|
* @retval Smartcard communication Protocol
|
|
*/
|
|
static uint8_t SC_decode_Answer2reset(uint8_t *card)
|
|
{
|
|
uint32_t i = 0, flag = 0, buf = 0, protocol = 0;
|
|
|
|
SC_A2R.TS = card[0]; /* Initial character */
|
|
SC_A2R.T0 = card[1]; /* Format character */
|
|
|
|
SC_A2R.Hlength = SC_A2R.T0 & (uint8_t)0x0F;
|
|
|
|
if ((SC_A2R.T0 & (uint8_t)0x80) == 0x80)
|
|
{
|
|
flag = 1;
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
SC_A2R.Tlength = SC_A2R.Tlength + (((SC_A2R.T0 & (uint8_t)0xF0) >> (4 + i)) & (uint8_t)0x1);
|
|
}
|
|
|
|
for (i = 0; i < SC_A2R.Tlength; i++)
|
|
{
|
|
SC_A2R.T[i] = card[i + 2];
|
|
}
|
|
|
|
if ((SC_A2R.T0 & (uint8_t)0x80) == 0x00)
|
|
{
|
|
protocol = 0;
|
|
}
|
|
else
|
|
{
|
|
protocol = SC_A2R.T[SC_A2R.Tlength - 1] & (uint8_t)0x0F;
|
|
}
|
|
|
|
while (flag)
|
|
{
|
|
if ((SC_A2R.T[SC_A2R.Tlength - 1] & (uint8_t)0x80) == 0x80)
|
|
{
|
|
flag = 1;
|
|
}
|
|
else
|
|
{
|
|
flag = 0;
|
|
}
|
|
|
|
buf = SC_A2R.Tlength;
|
|
SC_A2R.Tlength = 0;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
SC_A2R.Tlength = SC_A2R.Tlength + (((SC_A2R.T[buf - 1] & (uint8_t)0xF0) >> (4 + i)) & (uint8_t)0x1);
|
|
}
|
|
|
|
for (i = 0;i < SC_A2R.Tlength; i++)
|
|
{
|
|
SC_A2R.T[buf + i] = card[i + 2 + buf];
|
|
}
|
|
SC_A2R.Tlength += (uint8_t)buf;
|
|
}
|
|
|
|
for (i = 0; i < SC_A2R.Hlength; i++)
|
|
{
|
|
SC_A2R.H[i] = card[i + 2 + SC_A2R.Tlength];
|
|
}
|
|
|
|
return (uint8_t)protocol;
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes all peripheral used for Smartcard interface.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void SC_Init(void)
|
|
{
|
|
/* SC_USART configuration --------------------------------------------------*/
|
|
/* SC_USART configured as follows:
|
|
- Word Length = 9 Bits
|
|
- 1.5 Stop Bit
|
|
- Even parity
|
|
- BaudRate = 8064 baud
|
|
- Hardware flow control disabled (RTS and CTS signals)
|
|
- Tx and Rx enabled
|
|
- USART Clock enabled
|
|
*/
|
|
/* USART Clock set to 3 MHz (PCLK1 (36 MHz) / 12) => prescaler set to 0x06 */
|
|
SCHandle.Instance = SC_USART;
|
|
SCHandle.Init.BaudRate = 9408; /* Starting baudrate = 3MHz / 372etu */
|
|
SCHandle.Init.WordLength = SMARTCARD_WORDLENGTH_9B;
|
|
SCHandle.Init.StopBits = SMARTCARD_STOPBITS_1_5;
|
|
SCHandle.Init.Parity = SMARTCARD_PARITY_EVEN;
|
|
SCHandle.Init.Mode = SMARTCARD_MODE_TX_RX;
|
|
SCHandle.Init.CLKPolarity = SMARTCARD_POLARITY_LOW;
|
|
SCHandle.Init.CLKPhase = SMARTCARD_PHASE_1EDGE;
|
|
SCHandle.Init.CLKLastBit = SMARTCARD_LASTBIT_ENABLE;
|
|
SCHandle.Init.Prescaler = SMARTCARD_PRESCALER_SYSCLK_DIV10;
|
|
SCHandle.Init.GuardTime = 16;
|
|
SCHandle.Init.NACKState = SMARTCARD_NACK_ENABLE;
|
|
HAL_SMARTCARD_Init(&SCHandle);
|
|
|
|
/* Set RSTIN HIGH */
|
|
SC_Reset(GPIO_PIN_SET);
|
|
}
|
|
|
|
/**
|
|
* @brief Deinitializes all resources used by the Smartcard interface.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void SC_DeInit(void)
|
|
{
|
|
/* Disable CMDVCC */
|
|
SC_PowerCmd(DISABLE);
|
|
|
|
/* Deinitializes the SCHandle */
|
|
HAL_SMARTCARD_DeInit(&SCHandle);
|
|
}
|
|
|
|
/**
|
|
* @brief Configures the card power voltage.
|
|
* @param SC_Voltage: specifies the card power voltage.
|
|
* This parameter can be one of the following values:
|
|
* @arg SC_VOLTAGE_5V: 5V cards.
|
|
* @arg SC_VOLTAGE_3V: 3V cards.
|
|
* @retval None
|
|
*/
|
|
static void SC_VoltageConfig(uint32_t SC_Voltage)
|
|
{
|
|
if(SC_Voltage == SC_VOLTAGE_5V)
|
|
{
|
|
/* Select Smartcard 5V */
|
|
HAL_GPIO_WritePin(SC_3_5V_GPIO_PORT, SC_3_5V_PIN, GPIO_PIN_SET);
|
|
}
|
|
else
|
|
{
|
|
/* Select Smartcard 3V */
|
|
HAL_GPIO_WritePin(SC_3_5V_GPIO_PORT, SC_3_5V_PIN, GPIO_PIN_RESET);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Configures GPIO hardware resources used for Samrtcard.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void SC_IOConfig(void)
|
|
{
|
|
GPIO_InitTypeDef GPIO_InitStruct;
|
|
|
|
/* Enable GPIO clocks */
|
|
SC_3_5V_CLK_ENABLE();
|
|
SC_RESET_CLK_ENABLE();
|
|
SC_CMDVCC_CLK_ENABLE();
|
|
SC_OFF_CLK_ENABLE();
|
|
|
|
/* Configure Smartcard CMDVCC pin */
|
|
GPIO_InitStruct.Pin = SC_CMDVCC_PIN;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
|
HAL_GPIO_Init(SC_CMDVCC_GPIO_PORT, &GPIO_InitStruct);
|
|
|
|
/* Configure Smartcard Reset pin */
|
|
GPIO_InitStruct.Pin = SC_RESET_PIN;
|
|
HAL_GPIO_Init(SC_RESET_GPIO_PORT, &GPIO_InitStruct);
|
|
|
|
/* Configure Smartcard 3/5V pin */
|
|
GPIO_InitStruct.Pin = SC_3_5V_PIN;
|
|
HAL_GPIO_Init(SC_3_5V_GPIO_PORT, &GPIO_InitStruct);
|
|
|
|
/* Select 5V */
|
|
SC_VoltageConfig(SC_VOLTAGE_5V);
|
|
|
|
/* Disable CMDVCC */
|
|
SC_PowerCmd(DISABLE);
|
|
|
|
/* Set RSTIN HIGH */
|
|
SC_Reset(GPIO_PIN_SET);
|
|
|
|
/* Configure Smartcard OFF pin */
|
|
GPIO_InitStruct.Pin = SC_OFF_PIN;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
HAL_GPIO_Init(SC_OFF_GPIO_PORT, &GPIO_InitStruct);
|
|
|
|
/* Configure the NVIC for Smartcard OFF pin */
|
|
HAL_NVIC_SetPriority(SC_OFF_EXTI_IRQn, 0, 0);
|
|
HAL_NVIC_EnableIRQ(SC_OFF_EXTI_IRQn);
|
|
}
|
|
|
|
/**
|
|
* @brief Detects whether the Smartcard is present or not.
|
|
* @param None.
|
|
* @retval 0 - Smartcard inserted
|
|
* 1 - Smartcard not inserted
|
|
*/
|
|
static uint8_t SC_Detect(void)
|
|
{
|
|
return HAL_GPIO_ReadPin(SC_OFF_GPIO_PORT, SC_OFF_PIN);
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|