860 lines
20 KiB
C
860 lines
20 KiB
C
#include <string.h>
|
||
#include "atr_decoder.h"
|
||
#include "debug.h"
|
||
#include "queue.h"
|
||
#include "sc_reader.h"
|
||
#include "tpdu.h"
|
||
#include "gpio.h"
|
||
#include <math.h>
|
||
#include "lib.h"
|
||
|
||
static SC_READER_CTRL_TYPE * SC_CTRL = ((SC_READER_CTRL_TYPE *)SC_7816_CTRL_BASE);
|
||
|
||
// bit mask for deferred task
|
||
enum SC_DEFERRED_TASK_MASK {
|
||
CARD_DET_TASK = U32BIT(0), //card insert or remove
|
||
ATR_DONE_TASK = U32BIT(1),
|
||
ATR_FAIL_TASK = U32BIT(2),
|
||
DEACTIVATION_TASK = U32BIT(3),
|
||
};
|
||
|
||
// TPDU status
|
||
typedef enum {
|
||
NOT_READY,
|
||
PPS_REQUESTED,
|
||
ACTIVATED,
|
||
} TASK_STATE;
|
||
|
||
// Module interrupt mask
|
||
enum SC_INT_MASK {
|
||
TX_DONE = U32BIT(0),
|
||
TX_FIFO_EMPTY = U32BIT(1),
|
||
TX_FIFO_THRESHOLD = U32BIT(2),
|
||
TX_PARITY_ERROR = U32BIT(3),
|
||
TX_RETRY = U32BIT(4),
|
||
TX_RETRY_OVER_LIMIT = U32BIT(5),
|
||
RX_FIFO_NOT_EMPTY = U32BIT(6),
|
||
RX_FIFO_THRESHOLD = U32BIT(7),
|
||
RX_TIMEOUT = U32BIT(8), //rx fifo empty timeout
|
||
RX_PARITY_ERROR = U32BIT(9),
|
||
RX_RETRY = U32BIT(10),
|
||
RX_RETRY_OVER_LIMIT = U32BIT(11),
|
||
C2C_WAITING_TIMEOUT = U32BIT(12), //character to character overtime interupt
|
||
ATR_DONE = U32BIT(13),
|
||
ATR_FAIL = U32BIT(14),
|
||
CARD_DETECT = U32BIT(15),
|
||
CARD_REMOVE = U32BIT(16),
|
||
DEACTIVATE_DONE = U32BIT(17),
|
||
SC_INT_ALL = 0x3FFFF,
|
||
};
|
||
|
||
/* Critical section for SC */
|
||
#define SC_CS_IN() \
|
||
do{ \
|
||
NVIC_DisableIRQ(ISO7816_IRQn); \
|
||
} while(false)
|
||
#define SC_CS_OUT() \
|
||
do{ \
|
||
NVIC_EnableIRQ(ISO7816_IRQn); \
|
||
} while(false)
|
||
|
||
/* Define which interrupts are used for TX/RX */
|
||
//#define RX_FIFO_INT (RX_FIFO_THRESHOLD | RX_TIMEOUT)
|
||
#define RX_FIFO_INT (RX_FIFO_THRESHOLD | C2C_WAITING_TIMEOUT | RX_TIMEOUT)
|
||
#define TX_FIFO_INT (TX_FIFO_EMPTY)
|
||
|
||
//±í¸ñÀ´×Ô7816-3ÐÒéTable 8ºÍTable 9
|
||
static const uint32_t F_Table[16] = {372, 372, 558, 744, 1116, 1488, 1860, 0, 0, 512, 768, 1024, 1536, 2048};
|
||
static const uint32_t D_Table[16] = {0, 1, 2, 4, 8, 16, 32, 64, 12, 20};
|
||
|
||
static volatile uint32_t task_flag;
|
||
static volatile bool tx_finished;
|
||
static bool card_in = false;
|
||
static SC_ATR ATR;
|
||
static SC_PPS PPS;
|
||
static bool card_activated = false;
|
||
static bool card_clock_stoppable = false;
|
||
static CALL_BACK callback[CALL_BACK_NUM];
|
||
static PPS_CALLBACK pps_cb[PPS_CALL_BACK_NUM];
|
||
static uint8_t buffer[264];
|
||
static QUEUE sc_queue = {0, 0, sizeof(buffer), buffer};
|
||
|
||
__STATIC_INLINE bool get_byte(uint8_t *data);
|
||
__STATIC_INLINE void sc_reader_enable_retry(void);
|
||
|
||
/* Configure module auto activation when card being inserted */
|
||
void sc_reader_config_auto(bool en)
|
||
{
|
||
SC_CTRL->AUTO_ACTIVATION_EN = (en != 0);
|
||
}
|
||
|
||
/* Configure vcc output when activated */
|
||
void sc_reader_config_vcc_level(bool en)
|
||
{
|
||
SC_CTRL->ACTIVE_VCC_LEVEL = (en != 0);
|
||
}
|
||
|
||
/* Configure module output clock */
|
||
void sc_reader_config_clock_div(uint16_t div)
|
||
{
|
||
if (div <= 1)
|
||
return;
|
||
/* if div is 3, duty cyle will be 2 : 1, which violates spec */
|
||
if (div == 4)
|
||
div = 5;
|
||
SC_CTRL->SC_CLK_DIV = div - 1;
|
||
}
|
||
|
||
/* FD configuration */
|
||
static void sc_reader_set_FD(uint8_t fd)
|
||
{
|
||
int f = (fd >> 4) & 0x0F;
|
||
int d = fd & 0x0F;
|
||
int fi = (atr_decoder_get_FD() >> 4) & 0x0F;
|
||
uint32_t w;
|
||
|
||
if (F_Table[f] == 0 || D_Table[d] == 0)
|
||
SC_CTRL->BAUD_CLK_DIV = 0x173;
|
||
else
|
||
SC_CTRL->BAUD_CLK_DIV = (F_Table[f] / D_Table[d]) - 1;
|
||
|
||
// 16 etu for RX FIFO timeout
|
||
SC_CTRL->RX_TIMEOUT_DELAY = 16 * (SC_CTRL->BAUD_CLK_DIV + 1);
|
||
|
||
SC_CTRL->GUARD_TIME = (D_Table[d] == 64) ? 16 : 12;
|
||
|
||
w = 960 * atr_decoder_get_waiting_integer() * F_Table[fi];
|
||
// 960 etu based
|
||
w /= ((SC_CTRL->BAUD_CLK_DIV + 1) * 960);
|
||
//SC_CTRL->WAITING_TIME = w;
|
||
SC_CTRL->ATR_WAIT_TIME = w;
|
||
}
|
||
|
||
/* Reset module configuration */
|
||
static void sc_reader_spec_default(void)
|
||
{
|
||
NVIC_DisableIRQ(ISO7816_IRQn);
|
||
atr_reset();
|
||
|
||
//------------------------------------------------
|
||
SC_CTRL->EXTRA_GUARD_TIME = 0;
|
||
sc_reader_enable_retry();
|
||
|
||
SC_CTRL->BAUD_CLK_DIV = 371; //default value,¼Ó1·ÖƵ
|
||
|
||
/* Set clk to <= 5MHz */
|
||
{
|
||
uint8_t clk;
|
||
|
||
// source by PCLK
|
||
GetMCUClock(&clk);
|
||
if(clk == SYSTEM_CLOCK_16M_XOSC) clk = SYSTEM_CLOCK_16M_RCOSC;
|
||
clk = 64/pow(2,clk); //SYS_CLK, uint:MHz
|
||
clk /= 2;
|
||
sc_reader_config_clock_div((uint16_t)clk); //clk=10 ×îÖÕʱÖÓËÙ¶ÈΪ4M
|
||
}
|
||
|
||
SC_CTRL->CLK_STOP_EN = false; //¿¨ÔÚ¼¤»î֮ǰд0´ò¿ªÊ±ÖÓ£¬ÖÐ;ÐèÒªÔÝÍ£½»Ò×µÄʱºòд1À´Í£Ö¹clk
|
||
card_clock_stoppable = false;
|
||
|
||
/* Reset RX queue for ATR*/
|
||
queue_reset(&sc_queue);
|
||
|
||
/* config SC interrupt */
|
||
SC_CTRL->INTS_EN = RX_FIFO_INT |
|
||
ATR_DONE | ATR_FAIL |
|
||
CARD_DETECT | CARD_REMOVE |
|
||
DEACTIVATE_DONE |
|
||
TX_RETRY_OVER_LIMIT | RX_RETRY_OVER_LIMIT;
|
||
|
||
/* Clear Pending Interrupt */
|
||
SC_CTRL->INTS_STATE = SC_INT_ALL;
|
||
NVIC_EnableIRQ(ISO7816_IRQn);
|
||
}
|
||
|
||
void sc_reader_deactivate(void)
|
||
{
|
||
if (card_in == true)
|
||
{
|
||
dbg_printf("deactivate!\r\n");
|
||
SC_CTRL->TRIGGER_DEACTIVATE = true;
|
||
}
|
||
}
|
||
|
||
void sc_reader_disable(void)
|
||
{
|
||
sc_reader_deactivate();
|
||
//SYS_CTRL->CLK_SC_EN = 0;
|
||
}
|
||
|
||
void sc_reader_activate(void)
|
||
{
|
||
if (card_in == true)
|
||
{
|
||
dbg_printf("activate!\r\n");
|
||
GPIO_Pin_Set(BIT3);
|
||
SC_CTRL->TRIGGER_ACTIVATE = true;
|
||
}
|
||
}
|
||
|
||
void sc_reader_warm_reset(void)
|
||
{
|
||
// if (!card_in || !card_activated)
|
||
// return;
|
||
|
||
sc_reader_spec_default();
|
||
card_activated = false;
|
||
SC_CTRL->TRIGGER_WARM_RESET = true;
|
||
dbg_printf("called sc_reader_warm_reset!\r\n");
|
||
}
|
||
|
||
/* PPS helper function */
|
||
static void sc_reader_sendPPS(SC_PPS *pps)
|
||
{
|
||
uint8_t tmp[6];
|
||
int idx = 0, i;
|
||
|
||
tmp[idx++] = pps->PPSS;
|
||
tmp[idx++] = pps->PPS[0];
|
||
pps->PCK = PPS.PPSS ^ PPS.PPS[0];
|
||
for (i = 1; i <= 3 ; i++) //bypb:¸Ä i<3 Ϊ i<=3
|
||
{
|
||
if((pps->PPS[0] >> i) & 0x08)
|
||
{
|
||
tmp[idx++] = pps->PPS[i];
|
||
pps->PCK ^= pps->PPS[i];
|
||
}
|
||
}
|
||
tmp[idx++] = pps->PCK;
|
||
|
||
sc_reader_send(tmp, idx);
|
||
}
|
||
|
||
static bool sc_reader_pps_verification(SC_PPS *pps)
|
||
{
|
||
int i;
|
||
uint8_t mask = 0xFF, fd = DEFAULT_FD;
|
||
bool pass = true;
|
||
|
||
// get PPSS
|
||
if (!get_byte(&pps->R_PPSS))
|
||
goto PPS_VERIFY_FAIL;
|
||
pass &= (pps->R_PPSS == 0xFF);
|
||
|
||
// get PPS0
|
||
if (!get_byte(&pps->R_PPS[0]))
|
||
goto PPS_VERIFY_FAIL;
|
||
|
||
// must be T=0
|
||
pass &= (((pps->R_PPS[0] ^ pps->PPS[0]) & 0x0F) == 0);
|
||
mask ^= pps->R_PPS[0];
|
||
|
||
for (i = 1; i < 3; i++) {
|
||
if (pps->R_PPS[0] & (0x08 << i)) {
|
||
// Get data
|
||
if (!get_byte(&pps->R_PPS[i]))
|
||
goto PPS_VERIFY_FAIL;
|
||
mask ^= pps->R_PPS[i];
|
||
// Must be equal to request
|
||
pass &= (pps->R_PPS[i] == pps->PPS[i]);
|
||
|
||
if (i == 1) { /* PPS1 */
|
||
fd = pps->R_PPS[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
// PCK
|
||
if (!get_byte(&pps->R_PCK))
|
||
goto PPS_VERIFY_FAIL;
|
||
mask ^= pps->R_PCK;
|
||
pass &= (mask == 0);
|
||
|
||
sc_reader_set_FD(fd);
|
||
|
||
return pass;
|
||
PPS_VERIFY_FAIL:
|
||
return false;
|
||
}
|
||
|
||
/* TX helper function */
|
||
void sc_reader_send(uint8_t *buf, int length)
|
||
{
|
||
int i;
|
||
|
||
SC_CS_IN();
|
||
queue_reset(&sc_queue);
|
||
SC_CS_OUT();
|
||
|
||
for (i = 0; i < length; i++)
|
||
{
|
||
enqueue(&sc_queue, buf[i]);
|
||
}
|
||
|
||
tx_finished = false;
|
||
sc_reader_enable_retry();
|
||
SC_CTRL->CLK_STOP_EN = false; //´ò¿ªÊ±ÖÓ
|
||
|
||
//°ëË«¹¤£¬Çл»µ½·¢ËÍ(ÖжÏ)ģʽ
|
||
SC_CTRL->INTS_EN &= ~RX_FIFO_INT;
|
||
SC_CTRL->INTS_EN |= TX_FIFO_INT; //ÕâÀï»á´¥·¢TX_FIFO_EMPTYÖжÏ
|
||
|
||
SC_CTRL->INTS_STATE = C2C_WAITING_TIMEOUT;
|
||
}
|
||
|
||
/* RX helper function */
|
||
bool sc_reader_get(uint8_t *buf, int length)
|
||
{
|
||
int i;
|
||
|
||
if (queue_size(&sc_queue) < length)
|
||
{
|
||
// Timeout and data not enough => deactivate
|
||
if (SC_CTRL->INTS_STATE & C2C_WAITING_TIMEOUT)
|
||
{
|
||
dbg_printf("RX queue size = %d\r\n", queue_size(&sc_queue));
|
||
sc_reader_deactivate();
|
||
}
|
||
return false;
|
||
}
|
||
|
||
SC_CS_IN();
|
||
for (i = 0; i < length; i++, buf++)
|
||
{
|
||
dequeue(&sc_queue, buf);
|
||
}
|
||
SC_CS_OUT();
|
||
|
||
return true;
|
||
}
|
||
|
||
void sc_reader_config_clock_stoppable(bool en)
|
||
{
|
||
card_clock_stoppable = en;
|
||
}
|
||
|
||
/* Debug Information */
|
||
void sc_reader_dump_info(void)
|
||
{
|
||
int i;
|
||
uint8_t *buf;
|
||
|
||
dbg_printf("card : %s\r\n", card_in ? "in" : "out");
|
||
dbg_printf("auto : %d\r\n", SC_CTRL->AUTO_ACTIVATION_EN);
|
||
dbg_printf("vcc : %d\r\n", SC_CTRL->ACTIVE_VCC_LEVEL);
|
||
dbg_printf("activated : %d\r\n", card_activated);
|
||
dbg_printf("stoppable : %d\r\n", card_clock_stoppable);
|
||
|
||
// ATR sequence
|
||
dbg_printf("ATR : ");
|
||
for (i = 0, buf = (uint8_t *)&ATR; i < ATR.TotalLength; i++)
|
||
dbg_printf("%02X ", *buf++);
|
||
dbg_printf("\r\n");
|
||
|
||
// PPS
|
||
dbg_printf("PPS : ");
|
||
for (i = 0, buf = (uint8_t *)&PPS; i < sizeof(PPS); i++)
|
||
dbg_printf("%02X ", *buf++);
|
||
dbg_printf("\r\n");
|
||
}
|
||
|
||
/* Callback registration for ACT/DACT */
|
||
void sc_reader_add_callback(CALL_BACK c, SC_CB type)
|
||
{
|
||
if (type >= CALL_BACK_NUM)
|
||
return;
|
||
callback[type] = c;
|
||
}
|
||
|
||
/* Callback registration for PPS releated events */
|
||
void sc_reader_add_PPS_callback(PPS_CALLBACK c, SC_PPS_CB type)
|
||
{
|
||
if (type >= PPS_CALL_BACK_NUM)
|
||
return;
|
||
pps_cb[type] = c;
|
||
}
|
||
|
||
|
||
/* Consume all data in queue */
|
||
__STATIC_INLINE bool get_byte(uint8_t *data)
|
||
{
|
||
while(true)
|
||
{
|
||
if (!is_queue_empty(&sc_queue))
|
||
{
|
||
SC_CS_IN();
|
||
dequeue(&sc_queue, data);
|
||
SC_CS_OUT();
|
||
return true;
|
||
}
|
||
else if (SC_CTRL->INTS_STATE & C2C_WAITING_TIMEOUT)
|
||
{
|
||
dbg_printf("TIMEOUT\r\n");
|
||
sc_reader_deactivate();
|
||
break;
|
||
}
|
||
else if (!card_in)
|
||
{ // card being removed, no timeout will be detected
|
||
break;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
__STATIC_INLINE void sc_reader_enable_retry(void)
|
||
{
|
||
SC_CTRL->TX_RETRY_ENABLE = true;
|
||
SC_CTRL->RX_RETRY_ENABLE = true;
|
||
}
|
||
|
||
/*
|
||
* Perform deferred tasks
|
||
* Do TPDU request & PPS verification
|
||
*/
|
||
|
||
|
||
//uint8_t Get_Challenge_COM[5] = {0x00, 0x84, 0x00, 0x00,0x04};
|
||
|
||
|
||
void get_challenge_test_handle(TPDU_COMMAND *command)
|
||
{
|
||
|
||
uint8_t i =0;
|
||
uint8_t *buf;
|
||
|
||
dbg_printf("get_challenge_test_handle\r\n");
|
||
|
||
dbg_printf("command->header: ");
|
||
for (i = 0; i < HEADER_SIZE ; i++)
|
||
dbg_printf("%02X ", command->header[i]);
|
||
|
||
dbg_printf("\r\n");
|
||
|
||
|
||
|
||
dbg_printf("command->writeCommand:%x\r\n",command->writeCommand);
|
||
|
||
|
||
dbg_printf("command->sw: ");
|
||
for (i = 0; i < SW_SIZE ; i++)
|
||
dbg_printf("%02X ", command->sw[i]);
|
||
|
||
dbg_printf("\r\n");
|
||
|
||
if((command->sw[0] == 0x90) &&(command->sw[1] == 0x00))
|
||
{
|
||
dbg_printf("command->data: ");
|
||
for (i = 0; i < command->header[4] ; i++)
|
||
dbg_printf("%02X ", command->data[i]);
|
||
|
||
dbg_printf("\r\n");
|
||
}
|
||
else
|
||
{
|
||
dbg_printf("command->sw is error\r\n");
|
||
}
|
||
}
|
||
|
||
|
||
TPDU_COMMAND get_challenge_test = {0};
|
||
|
||
|
||
void test_tpdu(void)
|
||
{
|
||
|
||
get_challenge_test.header[0] = 0x00;
|
||
get_challenge_test.header[1] = 0x84;
|
||
get_challenge_test.header[2] = 0x00;
|
||
get_challenge_test.header[3] = 0x00;
|
||
get_challenge_test.header[4] = 0x04;
|
||
get_challenge_test.writeCommand = 0;
|
||
|
||
tpdu_request(&get_challenge_test,get_challenge_test_handle);
|
||
}
|
||
|
||
/*
|
||
* Perform deferred tasks
|
||
* Do TPDU request & PPS verification
|
||
*/
|
||
void sc_reader_task(void)
|
||
{
|
||
static uint8_t send_test = 0;
|
||
|
||
uint32_t flag;
|
||
static TASK_STATE state;
|
||
|
||
SC_CS_IN();
|
||
flag = task_flag; task_flag = 0;
|
||
SC_CS_OUT();
|
||
|
||
// Handle ISR deferred tasks
|
||
if (flag)
|
||
{
|
||
if (flag & CARD_DET_TASK)
|
||
{
|
||
card_activated = false;
|
||
state = NOT_READY;
|
||
dbg_printf(card_in ? "CARD DETECTED!\r\n" : "CARD REMOVED!\r\n"); //card_inÔÚÖжÏÀïÉèÖÃ
|
||
|
||
if (card_in == true)
|
||
{
|
||
sc_reader_activate();
|
||
}
|
||
}
|
||
|
||
// ATR Received
|
||
if (flag & ATR_DONE_TASK)
|
||
{
|
||
uint8_t *buf = (uint8_t *)&ATR;
|
||
|
||
dbg_printf("ATR DONE!\r\n");
|
||
|
||
state = NOT_READY;
|
||
// Get ATR
|
||
memset(buf, 0, sizeof(ATR));
|
||
while(true)
|
||
{
|
||
if (!dequeue(&sc_queue, buf++))
|
||
break;
|
||
ATR.TotalLength++;
|
||
}
|
||
|
||
if (atr_decode(&ATR)) //check error
|
||
{
|
||
sc_reader_deactivate();
|
||
}
|
||
else
|
||
{
|
||
bool clock_lvl;
|
||
|
||
dbg_printf("ATR decode success!\r\n");
|
||
|
||
// Timing configuration
|
||
SC_CTRL->EXTRA_GUARD_TIME = atr_decoder_get_extra_guard_time();
|
||
|
||
// Clock stop
|
||
card_clock_stoppable = atr_decoder_get_clock_stop(&clock_lvl);
|
||
SC_CTRL->CLK_STOP_VAL = clock_lvl;
|
||
|
||
// Setup PPS
|
||
PPS.PPSS = 0xFF;
|
||
PPS.PPS[0] = 0x10; //PPS[1] exist, T0 transmission protocol
|
||
PPS.PPS[1] = atr_decoder_get_FD();
|
||
|
||
if (!atr_decoder_allow_pps() && (pps_cb[PPS_REQUEST_CB] == NULL || pps_cb[PPS_REQUEST_CB](&PPS)))
|
||
{
|
||
// send pps
|
||
dbg_printf("send PPS\r\n");
|
||
sc_reader_sendPPS(&PPS);
|
||
state = PPS_REQUESTED;
|
||
card_activated = true;
|
||
}
|
||
else if (!atr_decoder_get_protocol()) // T0 and specific mode
|
||
{
|
||
// T0 specific mode
|
||
sc_reader_dump_info();
|
||
|
||
// set fd
|
||
sc_reader_set_FD(DEFAULT_FD); //ÎÞÐèÐÞ¸Ä ±£³ÖĬÈÏ
|
||
tpdu_reset();
|
||
state = ACTIVATED;
|
||
card_activated = true;
|
||
}
|
||
else if (atr_decoder_allow_switch_mode()) // T1 and specific mode but allow to change to negotiable mode
|
||
{
|
||
dbg_printf("atr_decoder_allow_switch_mode!\r\n");
|
||
sc_reader_warm_reset();
|
||
}
|
||
else // Not support
|
||
{
|
||
dbg_printf("atr_decoder_Not_support_switch_mode!\r\n");
|
||
sc_reader_deactivate();
|
||
}
|
||
}
|
||
}
|
||
|
||
if (flag & ATR_FAIL_TASK)
|
||
{
|
||
uint8_t *buf = (uint8_t *)&ATR;
|
||
state = NOT_READY;
|
||
card_activated = false; //bypb add
|
||
// Get ATR
|
||
memset(buf, 0, sizeof(ATR));
|
||
while(true)
|
||
{
|
||
if (!dequeue(&sc_queue, buf++))
|
||
break;
|
||
ATR.TotalLength++;
|
||
}
|
||
}
|
||
|
||
if (flag & DEACTIVATION_TASK)
|
||
{
|
||
card_activated = false;
|
||
SC_CS_IN();
|
||
queue_reset(&sc_queue);
|
||
sc_reader_spec_default();
|
||
SC_CS_OUT();
|
||
state = NOT_READY;
|
||
|
||
sc_reader_dump_info();
|
||
|
||
if (callback[DACT_CB])
|
||
{
|
||
callback[DACT_CB]();
|
||
}
|
||
}
|
||
}
|
||
|
||
/* If not in activation, then no TPDU or PPS will be performed */
|
||
if (!card_in || !card_activated) /*Èôδ²å¿¨»òÕß¿¨Î´¼¤»î*/
|
||
{
|
||
tpdu_reset();
|
||
return;
|
||
}
|
||
|
||
// SC reader state machine
|
||
if (state == ACTIVATED)
|
||
{
|
||
static TPDU_TASK_STATE tpdu_state;
|
||
tpdu_state = tpdu_task(tx_finished);
|
||
if (tpdu_state == TT_IDLE)
|
||
{
|
||
if (card_clock_stoppable)
|
||
{
|
||
SC_CTRL->CLK_STOP_EN = true;
|
||
dbg_printf("stop clk!\r\n");
|
||
}
|
||
|
||
if(send_test == 0) {
|
||
send_test = 1;
|
||
dbg_printf("state == ACTIVATED,test_tpdu()\r\n");
|
||
test_tpdu();
|
||
}
|
||
|
||
if (callback[ACT_CB])
|
||
{
|
||
callback[ACT_CB]();
|
||
}
|
||
}
|
||
else if (tpdu_state == TT_ERROR)
|
||
{
|
||
dbg_printf("TPDU error\r\n");
|
||
sc_reader_deactivate();
|
||
state = NOT_READY;
|
||
}
|
||
}
|
||
else if (state == PPS_REQUESTED)
|
||
{
|
||
while (!tx_finished);
|
||
dbg_printf("PPS responsed!\r\n");
|
||
sc_reader_dump_info();
|
||
|
||
if (sc_reader_pps_verification(&PPS))
|
||
{
|
||
state = ACTIVATED;
|
||
dbg_printf("PPS verification success!\r\n");
|
||
|
||
//sc_reader_dump_info();
|
||
|
||
#if 0
|
||
sc_reader_warm_reset(); //ÑéÖ¤Èȸ´Î»
|
||
#elif 0
|
||
sc_reader_deactivate(); //Ñé֤ȥ¼¤»î
|
||
#elif 0
|
||
SC_CTRL->CLK_STOP_EN = true; //Ñéֹ֤ͣʱÖÓ
|
||
dbg_printf("stop clk!\r\n");
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
if (pps_cb[PPS_FAIL_CB])
|
||
{
|
||
pps_cb[PPS_FAIL_CB](&PPS);
|
||
}
|
||
sc_reader_deactivate();
|
||
state = NOT_READY;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Configure module settings */
|
||
void sc_reader_enable(void)
|
||
{
|
||
PIN_CONFIG->PIN_27_SEL = PIN_SEL_SC_DETECT;
|
||
//PIN_CONFIG->PIN_9_SEL = PIN_SEL_SC_VCC;
|
||
PIN_CONFIG->PIN_17_SEL = PIN_SEL_SC_CLK;
|
||
PIN_CONFIG->PIN_26_SEL = PIN_SEL_SC_IO;
|
||
PIN_CONFIG->PIN_4_SEL = PIN_SEL_SC_RSTN;
|
||
|
||
SC_CTRL->MODE = 0; //7816
|
||
|
||
SC_CTRL->T0T1 = 0; //T0 Protocol - default
|
||
SC_CTRL->DET_LEVEL = 0; //Íⲿ½ÓÉÏÀ£¬Ï½µÑØ´¥·¢
|
||
PIN_CONFIG->PAD_6_INPUT_PULL_UP = 1; //ʹÄÜÄÚ²¿ÉÏÀ
|
||
|
||
sc_reader_config_auto(false);
|
||
|
||
/* Configure RESET & ACTIVATE timeout to maximum */
|
||
SC_CTRL->RST_TIME = 400; //100?
|
||
SC_CTRL->ACT_TIME = 30; //200?
|
||
|
||
/* Configure FIFO threshold, FIFO size is 8, set half to inform*/
|
||
SC_CTRL->RX_FIFO_THRESHOLD = 0x4;
|
||
SC_CTRL->TX_FIFO_THRESHOLD = 0x4;
|
||
|
||
/* Retry configuration */
|
||
SC_CTRL->TX_RETRY_CNT = 3;
|
||
SC_CTRL->RX_RETRY_CNT = 3;
|
||
|
||
/* Enable RX FIFO Timeout */
|
||
SC_CTRL->RX_TIMEOUT_DETECT_EN = true;
|
||
|
||
sc_reader_spec_default();
|
||
|
||
/* Enable TX/RX */
|
||
SC_CTRL->TX_ENABLE = true;
|
||
SC_CTRL->RX_ENABLE = true;
|
||
}
|
||
|
||
/* Interrupt Handler */
|
||
void ISO_7816_IRQHandler(void)
|
||
#if 0
|
||
{
|
||
//uint32_t mask = SC_CTRL->INTS_STATE & SC_CTRL->INTS_EN;
|
||
|
||
uint32_t mask = SC_CTRL->INTS_STATE;
|
||
dbg_printf("0:INTS_STATE = 0x%08x\r\n", mask);
|
||
|
||
//SC_CTRL->INTS_STATE = mask; // Clear interrupt
|
||
SC_CTRL->INTS_STATE = SC_INT_ALL; // Clear interrupt
|
||
mask = SC_CTRL->INTS_STATE;
|
||
dbg_printf("1:INTS_STATE = 0x%08x\r\n", mask);
|
||
}
|
||
#else
|
||
{
|
||
uint32_t mask = SC_CTRL->INTS_STATE & SC_CTRL->INTS_EN;
|
||
|
||
// Optimize empty interrupt might occur when access FIFO
|
||
if (!mask)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (mask & DEACTIVATE_DONE)
|
||
{
|
||
task_flag |= DEACTIVATION_TASK;
|
||
}
|
||
|
||
if (mask & (CARD_DETECT | CARD_REMOVE))
|
||
{
|
||
card_in = (bool)((mask & CARD_DETECT)? 1:0);
|
||
task_flag |= CARD_DET_TASK;
|
||
}
|
||
|
||
// RX fifo data available
|
||
if (mask & RX_FIFO_INT)
|
||
{
|
||
while(SC_CTRL->RXFNE)
|
||
{
|
||
enqueue(&sc_queue, SC_CTRL->DATA);
|
||
}
|
||
}
|
||
|
||
// TX fifo available
|
||
if (mask & TX_FIFO_INT)
|
||
{
|
||
uint8_t data;
|
||
uint8_t i=0;
|
||
|
||
// fill data until full or no data
|
||
while ((i<8) && dequeue(&sc_queue, &data))
|
||
{
|
||
SC_CTRL->DATA = data;
|
||
i++;
|
||
}
|
||
|
||
// TX Done
|
||
if (is_queue_empty(&sc_queue) && SC_CTRL->TXFE)
|
||
{
|
||
// Disable TX FIFO available notification
|
||
SC_CTRL->INTS_EN &= ~TX_FIFO_INT;
|
||
SC_CTRL->INTS_EN |= RX_FIFO_INT;
|
||
//°ëË«¹¤£¬Çл»µ½½ÓÊÕ(ÖжÏ)ģʽ,RX_TIMEOUTÖжÏÒ²ÐèÒª£¬ÒòΪËüÖ¸Ã÷ÁËFIFO¿ÕÇҵȴý³¬Ê±
|
||
|
||
tx_finished = true;
|
||
}
|
||
}
|
||
|
||
// ATR failed
|
||
if (mask & ATR_FAIL)
|
||
{
|
||
// Consumes RX FIFO
|
||
while(SC_CTRL->RXFNE)
|
||
{
|
||
enqueue(&sc_queue, SC_CTRL->DATA);
|
||
}
|
||
task_flag |= ATR_FAIL_TASK;
|
||
//dbg_printf("ATR_FAIL, INT_ST = 0x%X\r\n", SC_CTRL->INTS_STATE);
|
||
}
|
||
|
||
if (mask & ATR_DONE)
|
||
{
|
||
// Consume RX FIFO data
|
||
while(SC_CTRL->RXFNE)
|
||
{
|
||
enqueue(&sc_queue, SC_CTRL->DATA);
|
||
}
|
||
task_flag |= ATR_DONE_TASK;
|
||
}
|
||
|
||
if (mask & TX_RETRY_OVER_LIMIT)
|
||
{
|
||
#if 0
|
||
if (SC_CTRL->TX_FORCE_PARITY_ERROR)
|
||
SC_CTRL->TX_FORCE_PARITY_ERROR = false;
|
||
else
|
||
SC_CTRL->TX_RETRY_ENABLE = false;
|
||
#elif 1
|
||
if (SC_CTRL->TXOVRETYR)
|
||
{
|
||
//¿Ï¶¨ÓÐ
|
||
SC_CTRL->TXOVRETYR = 1; //д1Çå³ý
|
||
}
|
||
else
|
||
{
|
||
//³ö´íÁË
|
||
SC_CTRL->TX_RETRY_ENABLE = false;
|
||
//dbg_printf("TXOVRETYR Err\r\n"); while(1);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
if (mask & RX_RETRY_OVER_LIMIT)
|
||
{
|
||
#if 0
|
||
if (SC_CTRL->RX_FORCE_PARITY_ERROR)
|
||
SC_CTRL->RX_FORCE_PARITY_ERROR = false;
|
||
else
|
||
SC_CTRL->RX_RETRY_ENABLE = false;
|
||
#else
|
||
if (SC_CTRL->RXOVRETRY)
|
||
{
|
||
//¿Ï¶¨ÓÐ
|
||
SC_CTRL->RXOVRETRY = 1; //д1Çå³ý
|
||
}
|
||
else
|
||
{
|
||
//³ö´íÁË
|
||
SC_CTRL->RX_RETRY_ENABLE = false;
|
||
//dbg_printf("RXOVRETRY Err\r\n"); while(1);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// Clear interrupt
|
||
SC_CTRL->INTS_STATE = mask;
|
||
}
|
||
#endif
|
||
|