405 lines
12 KiB
C
405 lines
12 KiB
C
/********************************** (C) COPYRIGHT *******************************
|
|
* File Name : main.c
|
|
* Author : WCH
|
|
* Version : V1.0.0
|
|
* Date : 2024/02/20
|
|
* Description : Main program body.
|
|
*********************************************************************************
|
|
* Copyright (c) 2024 Nanjing Qinheng Microelectronics Co., Ltd.
|
|
* Attention: This software (modified or not) and binary are used for
|
|
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
|
*******************************************************************************/
|
|
|
|
/*
|
|
*@Note
|
|
This example shows that the USART peripheral is configured in smart card mode
|
|
and reads ATR data, and then attempts to read the data in T=0 mode.
|
|
pins:
|
|
SMARTCARD_CK -- PA4
|
|
SMARTCARD_IO -- PA2
|
|
SMARTCARD_RST -- PA5
|
|
SMARTCARD_VCC -- 3.3V
|
|
*
|
|
*/
|
|
|
|
#include "debug.h"
|
|
#include "string.h"
|
|
|
|
/* Paramenters */
|
|
#define ATR_MAX_SIZE ((uint8_t)33) /* Maximum size of ATR byte array */
|
|
#define ATR_MAX_HISTORICAL ((uint8_t)15) /* Maximum number of historical bytes */
|
|
#define ATR_MAX_PROTOCOLS ((uint8_t)7) /* Maximun number of protocols */
|
|
#define ATR_MAX_IB ((uint8_t)4) /* Maximum number of interface bytes per protocol */
|
|
#define ATR_INTERFACE_BYTE_TA ((uint8_t)0) /* Interface byte TAi */
|
|
#define ATR_INTERFACE_BYTE_TB ((uint8_t)1) /* Interface byte TBi */
|
|
#define ATR_INTERFACE_BYTE_TC ((uint8_t)2) /* Interface byte TCi */
|
|
#define ATR_INTERFACE_BYTE_TD ((uint8_t)3) /* Interface byte TDi */
|
|
|
|
#define STATE_PARSE_TS 1
|
|
#define STATE_PARSE_T0 2
|
|
#define STATE_PARSE_TA 3
|
|
#define STATE_PARSE_TB 4
|
|
#define STATE_PARSE_TC 5
|
|
#define STATE_PARSE_TD 6
|
|
#define STATE_PARSE_HIST_BYTES 7
|
|
#define STATE_PARSE_TCK 8
|
|
#define STATE_PARSE_END 255
|
|
|
|
#define LC_MAX (20)
|
|
#define RST_PIN GPIO_Pin_5
|
|
|
|
typedef struct {
|
|
uint32_t length;
|
|
uint8_t TS; /* Initial character */
|
|
uint8_t T0; /* Format character */
|
|
|
|
struct {
|
|
uint8_t value; /* The value of the Interface byte */
|
|
uint8_t present; /* The presence of the Interface byte */
|
|
} ib[ATR_MAX_PROTOCOLS][ATR_MAX_IB], TCK; /* Interface bytes, TCK */
|
|
|
|
uint8_t pn; /* Protocol number: the value of i of the Interface bytes */
|
|
uint8_t Ti[ATR_MAX_HISTORICAL]; /* Historical bytes table */
|
|
uint8_t Tin; /* Historical bytes number */
|
|
int8_t protocol;
|
|
} ATR_TypeDef;
|
|
|
|
int ATR_Parse(ATR_TypeDef *atr, uint8_t *atr_buf, int32_t len) {
|
|
uint8_t data;
|
|
uint8_t TCK = 0;
|
|
uint8_t K = 0;
|
|
uint8_t Yi = 0;
|
|
int32_t k, state, index, length, protocol;
|
|
uint8_t *ptr;
|
|
|
|
length = len;
|
|
ptr = atr_buf;
|
|
state = STATE_PARSE_TS;
|
|
index = 0;
|
|
k = 0;
|
|
protocol = 0;
|
|
|
|
while (ptr < (atr_buf + length)) {
|
|
data = *ptr++;
|
|
if (state != STATE_PARSE_TS) {
|
|
TCK ^= data;
|
|
}
|
|
|
|
switch (state) {
|
|
case STATE_PARSE_TS:
|
|
atr->TS = data;
|
|
printf("Ts=%x \n", data);
|
|
if (data == 0x3b) {
|
|
state = STATE_PARSE_T0;
|
|
} else if (data == 0x03) {
|
|
printf("not support\n");
|
|
return 1;
|
|
} else {
|
|
printf("error Ts\n");
|
|
return 1;
|
|
}
|
|
break;
|
|
case STATE_PARSE_T0:
|
|
atr->T0 = data;
|
|
atr->Tin = data & 0x0f;
|
|
printf("T0=%x\n", data);
|
|
printf("Historical bytes number=%d\n", data & 0x0f);
|
|
K = data & 0x0F;
|
|
Yi = data;
|
|
if (data & 0x10) {
|
|
state = STATE_PARSE_TA;
|
|
} else if (data & 0x20) {
|
|
state = STATE_PARSE_TB;
|
|
} else {
|
|
if (data & 0x40) {
|
|
state = STATE_PARSE_TC;
|
|
} else if (data & 0x80) {
|
|
state = STATE_PARSE_TD;
|
|
} else {
|
|
state = STATE_PARSE_HIST_BYTES;
|
|
}
|
|
}
|
|
break;
|
|
case STATE_PARSE_TA:
|
|
printf("TA%d=%x \n", index, data);
|
|
atr->ib[index][ATR_INTERFACE_BYTE_TA].present = 1;
|
|
atr->ib[index][ATR_INTERFACE_BYTE_TA].value = data;
|
|
if (Yi & 0x20) {
|
|
state = STATE_PARSE_TB;
|
|
} else if (Yi & 0x40) {
|
|
state = STATE_PARSE_TC;
|
|
} else if (Yi & 0x80) {
|
|
state = STATE_PARSE_TD;
|
|
} else {
|
|
state = STATE_PARSE_HIST_BYTES;
|
|
}
|
|
break;
|
|
case STATE_PARSE_TB:
|
|
printf("TB%d=%x \n", index, data);
|
|
atr->ib[index][ATR_INTERFACE_BYTE_TB].present = 1;
|
|
atr->ib[index][ATR_INTERFACE_BYTE_TB].value = data;
|
|
if (Yi & 0x40) {
|
|
state = STATE_PARSE_TC;
|
|
} else if (Yi & 0x80) {
|
|
state = STATE_PARSE_TD;
|
|
} else {
|
|
state = STATE_PARSE_HIST_BYTES;
|
|
}
|
|
break;
|
|
case STATE_PARSE_TC:
|
|
printf("TC%d=%x \n", index, data);
|
|
atr->ib[index][ATR_INTERFACE_BYTE_TC].present = 1;
|
|
atr->ib[index][ATR_INTERFACE_BYTE_TC].value = data;
|
|
if (Yi & 0x80) {
|
|
state = STATE_PARSE_TD;
|
|
} else {
|
|
state = STATE_PARSE_HIST_BYTES;
|
|
}
|
|
break;
|
|
case STATE_PARSE_TD:
|
|
|
|
Yi = data;
|
|
printf("TD%d=%x \n", index, data);
|
|
atr->ib[index][ATR_INTERFACE_BYTE_TD].present = 1;
|
|
atr->ib[index][ATR_INTERFACE_BYTE_TD].value = data;
|
|
if (index == 0) {
|
|
protocol = Yi & 0x0F;
|
|
}
|
|
index++;
|
|
atr->pn = index;
|
|
|
|
if (Yi & 0xF0) {
|
|
if (Yi & 0x10) {
|
|
/* TAx character present */
|
|
state = STATE_PARSE_TA;
|
|
} else if (Yi & 0x20) {
|
|
/* TBx character present */
|
|
state = STATE_PARSE_TB;
|
|
} else if (Yi & 0x40) {
|
|
/* TCx character present */
|
|
state = STATE_PARSE_TC;
|
|
} else if (Yi & 0x80) {
|
|
/* TDx character present */
|
|
state = STATE_PARSE_TD;
|
|
} else {
|
|
state = STATE_PARSE_HIST_BYTES;
|
|
}
|
|
} else {
|
|
state = STATE_PARSE_HIST_BYTES;
|
|
}
|
|
break;
|
|
case STATE_PARSE_HIST_BYTES:
|
|
if (K) {
|
|
|
|
if (k < K) {
|
|
atr->Ti[k] = data;
|
|
printf("T[%d]=%x\n", k, data);
|
|
k++;
|
|
if (k == K) {
|
|
if (protocol > 0) {
|
|
state = STATE_PARSE_TCK;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case STATE_PARSE_TCK:
|
|
atr->TCK.present = 1;
|
|
atr->TCK.value = data;
|
|
printf("get TCK %x\n", data);
|
|
if (TCK) {
|
|
// TCK != 0
|
|
printf("TCK error\n");
|
|
return 1;
|
|
}
|
|
// printf("cal TCK result %x\n", TCK);
|
|
break;
|
|
}
|
|
if (state == STATE_PARSE_HIST_BYTES && K == 0 && protocol == 0)
|
|
break;
|
|
}
|
|
|
|
atr->protocol = protocol;
|
|
return 0;
|
|
}
|
|
|
|
void USART2_ReCFG(void) {
|
|
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
|
USART_InitTypeDef USART_InitStructure = {0};
|
|
USART_ClockInitTypeDef USART_ClockInitStructure = {0};
|
|
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
|
|
|
|
/* USART2 Ck-->A.4 TX-->A.2 */
|
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
|
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
|
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
|
|
USART_ClockInitStructure.USART_Clock = USART_Clock_Enable;
|
|
USART_ClockInit(USART2, &USART_ClockInitStructure);
|
|
|
|
USART_InitStructure.USART_BaudRate = 9600;
|
|
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
|
|
USART_InitStructure.USART_StopBits = USART_StopBits_1_5;
|
|
USART_InitStructure.USART_Parity = USART_Parity_Even;
|
|
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
|
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
|
|
USART_Init(USART2, &USART_InitStructure);
|
|
|
|
USART_Cmd(USART2, ENABLE);
|
|
|
|
/// Enable NACK transmission
|
|
USART_SmartCardNACKCmd(USART2, ENABLE);
|
|
|
|
/// Enable Smartcard mode
|
|
USART_SmartCardCmd(USART2, ENABLE);
|
|
|
|
USART_SetPrescaler(USART2, 5);
|
|
USART_SetGuardTime(USART2, 15);
|
|
}
|
|
|
|
void RST_Init() {
|
|
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
|
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
|
|
|
GPIO_InitStructure.GPIO_Pin = RST_PIN;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
|
|
GPIO_ResetBits(GPIOA, RST_PIN);
|
|
}
|
|
|
|
void SC_ClearUart() {
|
|
int32_t i = 0;
|
|
while (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET) {
|
|
i++;
|
|
if (i > 1) {
|
|
break;
|
|
}
|
|
USART_ReceiveData(USART2);
|
|
}
|
|
}
|
|
|
|
void SC_TransmitData(uint8_t *data, uint16_t size) {
|
|
uint8_t dat = 0;
|
|
for (uint8_t index = 0; index < size; index++) {
|
|
dat = data[index];
|
|
USART_SendData(USART2, dat);
|
|
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) {
|
|
}
|
|
}
|
|
while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET) {
|
|
}
|
|
}
|
|
|
|
void SC_ReceiveData(uint8_t *data, uint16_t *size) {
|
|
uint32_t i = 0, t = 0;
|
|
SC_ClearUart();
|
|
while (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET) {
|
|
t++;
|
|
Delay_Ms(1);
|
|
if (t > 10) {
|
|
break;
|
|
}
|
|
}
|
|
t = 0;
|
|
while (1) {
|
|
if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET) {
|
|
data[i] = USART_ReceiveData(USART2);
|
|
i++;
|
|
t = 0;
|
|
} else if (t < 10) {
|
|
Delay_Ms(1);
|
|
t++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
*size = i;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn main
|
|
*
|
|
* @brief Main program.
|
|
*
|
|
* @return none
|
|
*/
|
|
int main(void) {
|
|
ATR_TypeDef atr = {0}; /* Answer To Reset structure */
|
|
|
|
uint8_t pps[] = {0xff, 0x00, 0xff};
|
|
uint8_t testcmd[] = {0x00, 0x84, 0x00, 0x00, 0x08};
|
|
uint8_t recvbuf[ATR_MAX_SIZE] = {0};
|
|
uint16_t recvpos = 0;
|
|
|
|
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
|
|
SystemCoreClockUpdate();
|
|
Delay_Init();
|
|
USART_Printf_Init(115200);
|
|
printf("SystemClk:%d\r\n", SystemCoreClock);
|
|
printf("ChipID:%08x\r\n", DBGMCU_GetCHIPID());
|
|
printf("USART SmartCard TEST\r\n");
|
|
RST_Init();
|
|
USART2_ReCFG(); /* USART2 INIT */
|
|
|
|
GPIO_ResetBits(GPIOA, RST_PIN);
|
|
Delay_Ms(1);
|
|
GPIO_SetBits(GPIOA, RST_PIN);
|
|
|
|
// try to get ATR
|
|
SC_ReceiveData(recvbuf, &(recvpos));
|
|
|
|
if (recvpos == 0) {
|
|
printf("cannot get atr\n");
|
|
printf("end\n");
|
|
while (1) {
|
|
}
|
|
}
|
|
|
|
if (ATR_Parse(&atr, recvbuf, recvpos) != 0) {
|
|
printf("end\n");
|
|
while (1) {
|
|
}
|
|
}
|
|
|
|
printf("mode T=%d \n", atr.protocol);
|
|
if (atr.protocol != 0) {
|
|
recvpos = 0;
|
|
// send pps
|
|
SC_TransmitData(pps, 3);
|
|
SC_ReceiveData(recvbuf, &(recvpos));
|
|
if (memcmp(pps, recvbuf, recvpos) != 0) {
|
|
printf("cannot switch to T=0 mode\n");
|
|
printf("end\n");
|
|
while (1) {
|
|
}
|
|
} else {
|
|
printf("switch to T=0 mode\n");
|
|
}
|
|
}
|
|
|
|
SC_TransmitData(testcmd, 5);
|
|
SC_ReceiveData(recvbuf, &(recvpos));
|
|
|
|
for (int i = 0; i < recvpos; i++) {
|
|
printf("[%d]=%x \n", i, recvbuf[i]);
|
|
}
|
|
printf("SW1 = %x \n", recvbuf[recvpos - 2]);
|
|
printf("SW2 = %x \n", recvbuf[recvpos - 1]);
|
|
if (recvbuf[recvpos - 2] == 0x90 && recvbuf[recvpos - 1] == 0x00 && recvpos == 11) {
|
|
printf("success\n");
|
|
}
|
|
printf("end\n");
|
|
while (1) {
|
|
}
|
|
}
|