v2.1
This commit is contained in:
@@ -0,0 +1,404 @@
|
||||
/********************************** (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) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user