forked from wanrenqi/PASII
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)
|
|||
|
|
|||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>7816-3Э<33><D0AD>Table 8<><38>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,<2C><>1<EFBFBD><31>Ƶ
|
|||
|
|
|||
|
/* 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 <20><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>ٶ<EFBFBD>Ϊ4M
|
|||
|
}
|
|||
|
|
|||
|
SC_CTRL->CLK_STOP_EN = false; //<2F><><EFBFBD>ڼ<EFBFBD><DABC><EFBFBD>֮ǰд0<D0B4><30><EFBFBD><EFBFBD>ʱ<EFBFBD>ӣ<EFBFBD><D3A3><EFBFBD>;<EFBFBD><CDBE>Ҫ<EFBFBD><D2AA>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>д1<D0B4><31>ֹͣ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:<3A><> 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; //<2F><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
|||
|
|
|||
|
//<2F><>˫<EFBFBD><CBAB><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28>ж<EFBFBD>)ģʽ
|
|||
|
SC_CTRL->INTS_EN &= ~RX_FIFO_INT;
|
|||
|
SC_CTRL->INTS_EN |= TX_FIFO_INT; //<2F><><EFBFBD><EFBFBD><EFBFBD>ᴥ<EFBFBD><E1B4A5>TX_FIFO_EMPTY<54>ж<EFBFBD>
|
|||
|
|
|||
|
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<69><6E><EFBFBD>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
|||
|
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); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>Ĭ<EFBFBD><C4AC>
|
|||
|
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) /*<2A><>δ<EFBFBD>忨<EFBFBD><E5BFA8><EFBFBD>߿<EFBFBD>δ<EFBFBD><CEB4><EFBFBD><EFBFBD>*/
|
|||
|
{
|
|||
|
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(); //<2F><>֤<EFBFBD>ȸ<EFBFBD>λ
|
|||
|
#elif 0
|
|||
|
sc_reader_deactivate(); //<2F><>֤ȥ<D6A4><C8A5><EFBFBD><EFBFBD>
|
|||
|
#elif 0
|
|||
|
SC_CTRL->CLK_STOP_EN = true; //<2F><>ֹ֤ͣʱ<D6B9><CAB1>
|
|||
|
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; //<2F>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD>ش<EFBFBD><D8B4><EFBFBD>
|
|||
|
PIN_CONFIG->PAD_6_INPUT_PULL_UP = 1; //ʹ<><CAB9><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
|||
|
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;
|
|||
|
//<2F><>˫<EFBFBD><CBAB><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28>ж<EFBFBD>)ģʽ,RX_TIMEOUT<55>ж<EFBFBD>Ҳ<EFBFBD><D2B2>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD>FIFO<46><4F><EFBFBD>ҵȴ<D2B5><C8B4><EFBFBD>ʱ
|
|||
|
|
|||
|
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)
|
|||
|
{
|
|||
|
//<2F>϶<EFBFBD><CFB6><EFBFBD>
|
|||
|
SC_CTRL->TXOVRETYR = 1; //д1<D0B4><31><EFBFBD><EFBFBD>
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
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)
|
|||
|
{
|
|||
|
//<2F>϶<EFBFBD><CFB6><EFBFBD>
|
|||
|
SC_CTRL->RXOVRETRY = 1; //д1<D0B4><31><EFBFBD><EFBFBD>
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
SC_CTRL->RX_RETRY_ENABLE = false;
|
|||
|
//dbg_printf("RXOVRETRY Err\r\n"); while(1);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
// Clear interrupt
|
|||
|
SC_CTRL->INTS_STATE = mask;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|