欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

T6S项目IC卡驱动总结

程序员文章站 2023-12-28 22:15:16
...

IC卡消费是支付行业必须要支持的消费手段,实现IC卡的读卡操作流程相对较简单,现在总结一下,方便以后调试。

1. 硬件连接

主控集成了IC卡接口,我们配置使用即可,如下所示。

#define ICC_DEV_NSLOT       0    //IC卡对应的物理端口
#define ICC_DET_PIN         GPIO_PIN_PTA6 
#define ICC_CMD_PIN         GPIO_PIN_PTA7 
#define ICC_CLK_PIN         GPIO_PIN_PTA8 
#define ICC_RSTN_PIN        GPIO_PIN_PTA9 
#define ICC_IO_PIN          GPIO_PIN_PTA10 

2. 初始化设备

drv_icc_init()函数的实现如下所示:

void drv_icc_init(void)
{
    /*SCI0 VCCEN信号有效电平选择*/
    SYSCTRL->PHER_CTRL |= BIT(20);  //高电平有效
    //SYSCTRL->PHER_CTRL &= (~BIT(20));
}

void dev_icc_init(void)
{    
    drv_icc_init();  //硬件相关的初始化

    g_psam_existflg = 0;  
    /*判断有没有PSAM卡*/
    if(g_psam_existflg)
    {
        drv_psam_init();
    }
}

3. 打开设备

drv_icc_open()函数的实现如下所示:

s32 drv_icc_open(void)
{
    s32 i;
    
    /*使能SCI0时钟*/
    SYSCTRL_APBPeriphClockCmd(SYSCTRL_APBPeriph_SCI0, ENABLE);
    SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_SCI0, ENABLE);  

    /*SCI0卡检测信号有效电平选择*/
    SYSCTRL->PHER_CTRL &= ~BIT(16);  //高有效
    /*SCI0 VCCEN信号有效电平选择*/
    SYSCTRL->PHER_CTRL |= BIT(20);  //低有效    

    /*SCI1卡检测信号有效电平选择*/
    SYSCTRL->PHER_CTRL &= ~BIT(17);  //高有效    
    /*SCI1 VCCEN信号有效电平选择*/
    SYSCTRL->PHER_CTRL |= BIT(21);  //低有效
    
    /*SCI2卡检测信号有效电平选择*/
    SYSCTRL->PHER_CTRL &= ~BIT(18);  //高有效
    /*SCI2 VCCEN信号有效电平选择*/
    SYSCTRL->PHER_CTRL |= BIT(22);  //低有效    

    /*配置SCI0管脚*/
    dev_gpio_config_mux(ICC_CLK_PIN, MUX_CONFIG_ALT0);
    dev_gpio_config_mux(ICC_RSTN_PIN, MUX_CONFIG_ALT0);
    dev_gpio_config_mux(ICC_IO_PIN, MUX_CONFIG_ALT0);
    dev_gpio_config_mux(ICC_DET_PIN, MUX_CONFIG_ALT0);    
    
  #if 1
    /*使用外部芯片控制,SCI0_VCCEN*/
    dev_gpio_config_mux(ICC_CMD_PIN, MUX_CONFIG_ALT1);   
    dev_gpio_set_pad(ICC_CMD_PIN, PAD_CTL_PULL_UP);
    dev_gpio_direction_output(ICC_CMD_PIN, 1);
  #else
    dev_gpio_config_mux(ICC_CMD_PIN, MUX_CONFIG_ALT0);
  #endif 
  
    /*库函数初始化*/
    SCI_ConfigEMV(0x01, 3000000);      
    iso7816_device_init();     
    g_icc_active = 0;  //上电成功的标志位

    /*使能SCI0中断*/
    NVIC_ClearPendingIRQ(SCI0_IRQn);
    NVIC_EnableIRQ(SCI0_IRQn);    
    
    i = iso7816_getlibversion();    //读取库的版本信息
    ICC_DEBUG("icc_ver=%08X\r\n", i);    
    
    return 0;     
    
  #if 0    
    //GPIO_PinRemapConfig(GPIOA, GPIO_Pin_4  | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14, GPIO_Remap_0);
    SYSCTRL->SCI_GLF = SYSCTRL->SCI_GLF & ~BIT(29) | BIT(28);  //5V
    //SYSCTRL->SCI_GLF = SYSCTRL->SCI_GLF & ~(0x03 << 28) | (0x02 << 28);   //3V
    //虑毛刺使能
    //SYSCTRL->SCI_GLF |= BIT(31);
    SYSCTRL->SCI_GLF &= ~0xFFFFF;
    SYSCTRL->SCI_GLF |= SYSCTRL->PCLK_1MS_VAL>>2;
    //SYSCTRL->CARD_RSVD &= ~BIT(1);
    //SYSCTRL->CARD_RSVD |= BIT(1); //High TH(400mA protect)
    //PA6-CARD_DECTECT PA8-CLK PA9-RSTN PA10-IO PA14-VCC_EN
    //GPIO_GROUP[0].PUE |= BIT(10) | BIT(9);
    //GPIO_GROUP[0].PUE &= ~BIT(10);
  #endif    
}

s32 dev_icc_open(s32 nslot)
{
    s32 ret = DEVSTATUS_ERR_PARAM_ERR;
    
    if(nslot >= ICC_SLOT_MAX)  //3
    {
        return DEVSTATUS_ERR_PARAM_ERR;
    }
    
    if(g_icc_fd[nslot]<0)
    {
        switch(nslot)
        {
            case ICC_SLOT_ICCARD:  //0  
                ret = drv_icc_open();
                break;
            case ICC_SLOT_PSAM1:
            case ICC_SLOT_PSAM2:
                if(g_psam_existflg)
                {
                    ret = drv_psam_open(nslot-1);
                }
                break;
        }
        
        if(ret==0)
        {
            g_icc_fd[nslot] = 0;
        }
    }
    else
    {
        return 0;
    }
    
    return ret;
}

typedef enum _ICC_SLOT
{
    ICC_SLOT_ICCARD = 0,
    ICC_SLOT_PSAM1 = 1,
    ICC_SLOT_PSAM2 = 2,
    ICC_SLOT_MAX   = 3,
}icc_slot_t;

4. 关闭设备

drv_icc_close()函数的实现如下所示:

s32 drv_icc_close(void)
{
    iso7816_close(ICC_DEV_NSLOT);  //库函数关闭,0     
    dev_gpio_direction_output(ICC_CMD_PIN, 0);  //SCI0_VCCEN拉低
    /*SCI0 VCCEN信号有效电平选择*/
    SYSCTRL->PHER_CTRL |= (BIT(20));  //低有效,待验证能不能删除掉
    g_icc_active = 0;  //上电成功的标志位
    return 0;
}

s32 dev_icc_close(s32 nslot)
{
    s32 ret = DEVSTATUS_ERR_PARAM_ERR;
    
    if(nslot >= ICC_SLOT_MAX)  //3
    {
        return DEVSTATUS_ERR_PARAM_ERR;
    }
    
    if(g_icc_fd[nslot]==0)
    {
        switch(nslot)
        {
        case ICC_SLOT_ICCARD:  
            ret = drv_icc_close();
            break;
        case ICC_SLOT_PSAM1:
        case ICC_SLOT_PSAM2:
            if(g_psam_existflg)
            {
                ret = drv_psam_close(nslot-1);
            }
            break;
        }

        g_icc_fd[nslot] = -1;
    }
    
    return ret;
}

5. 检测有没有IC卡插入

drv_icc_getstatus()函数的实现如下所示:

s32 drv_icc_getstatus(void)
{
    /*检测有没有IC卡插入*/
    if(0 != iso7816_detect(ICC_DEV_NSLOT))  //没有卡插入,0
    {
        if(g_icc_active==1)
        {
            g_icc_active = 0;
            drv_icc_poweroff();
        } 
        return 0;  
    }
    else  //有卡插入
    {        
        return 1;       
    }
}

s32 dev_icc_getstatus(s32 nslot)
{    
    if(ICC_SLOT_ICCARD == nslot)  //0
    {
        return drv_icc_getstatus();
    }
    else
    {
        return 1;
    }
}

6. IC卡复位

drv_icc_reset()函数的实现如下所示:

s32 drv_icc_reset(u8 *lpAtr)
{
    s32 ret;
    u8 atr[65]; 
    
     /*检测有没有IC卡插入*/
    if(0 == drv_icc_getstatus())  //没有卡插入
    {
        ICC_DEBUG("NO CARD!\r\n");      
        return DEVSTATUS_ERR_FAIL;
    } 
    
    /*对IC卡复位*/
    ret = iso7816_init(ICC_DEV_NSLOT, VCC_3000mV | SPD_1X, atr);  //VCC_5000mV
    if(ret == 0)  //复位成功
    {
        g_icc_active = 1;  //上电成功标志位
        memcpy(lpAtr, &atr[1], atr[0]);  //拷贝IC卡复位的数据 
        
        return atr[0];
    }
    else  //复位失败
    {        
        ICC_DEBUG("reset fail!\r\n");
        return DEVSTATUS_ERR_FAIL;
    }
}

s32 dev_icc_reset(s32 nslot, u8 *lpAtr)
{
    s32 ret = DEVSTATUS_ERR_PARAM_ERR;
    
    if(nslot >= ICC_SLOT_MAX)  //3
    {
        ICC_DEBUG("PARAM Err!(nslot=%d)\r\n", nslot);
        return DEVSTATUS_ERR_PARAM_ERR;
    }
    
    if(g_icc_fd[nslot]<0)
    {
        ICC_DEBUG("DEVICE_NOTOPEN!\r\n");
        return DEVSTATUS_ERR_DEVICE_NOTOPEN;
    }
    
    switch(nslot)
    {
    case ICC_SLOT_ICCARD: 
        ret = drv_icc_reset(lpAtr);
        break;
    case ICC_SLOT_PSAM1:
    case ICC_SLOT_PSAM2:
        if(g_psam_existflg)
        {
            ret = drv_psam_reset(nslot-1, lpAtr);
        }
        break;
    }
    
    return ret;
}

7. APDU交互

drv_icc_exchange_apdu()函数实现如下所示:

s32 drv_icc_exchange_apdu(u8 *wbuf, u32 wlen, u8 *rbuf, u32 *rlen, u32 rxmax)
{
    ST_APDU_RSP rsp;
    ST_APDU_REQ apdu_req;
    s32 ret;

    *rlen = 0;
    
    /*检测有没有IC卡插入*/
    if(0 == drv_icc_getstatus())  //没有卡插入
    {
        ICC_DEBUG("NO CARD!\r\n");   
        return DEVSTATUS_ERR_FAIL;
    }

    /*判断IC卡是否复位*/
    if(g_icc_active == 0)  //没有复位
    {
        ICC_DEBUG("NOT RESET!\r\n");        
        return DEVSTATUS_ERR_FAIL;
    }    

    /*判断数据长度*/
    if((wlen > (255+6)) || (wlen < 4))  //卡片没有复位
    {
        ICC_DEBUG("wlen=%d\r\n", wlen);        
        return DEVSTATUS_ERR_PARAM_ERR;
    }
    
    if(rxmax < 2)  //期望的长度错
    {        
        ICC_DEBUG("rxmax=%d\r\n", rxmax);
        return DEVSTATUS_ERR_PARAM_ERR; 
    } 
    
    memcpy(apdu_req.cmd, wbuf, 4);
    if(4 == wlen)  //case 1
    {        
        apdu_req.lc = 0;
        apdu_req.le = 0;
    }
    else if(5 == wlen)  //case 2
    {        
        apdu_req.lc = 0;
        apdu_req.le = wbuf[4];
        if(apdu_req.le == 0)
        {
            apdu_req.le = 256;
        }
    }
    else if(wlen > 5)
    {
        apdu_req.lc = wbuf[4];
        memcpy(apdu_req.data_in, &wbuf[5], apdu_req.lc);
        if(wlen == (apdu_req.lc+5))  //case3
        {            
            apdu_req.le = 0;
        }
        else  //case4
        {            
            apdu_req.le = wbuf[apdu_req.lc+5];
            if(apdu_req.le == 0)
            {
                apdu_req.le = 256;
            }
        }        
    }

    /*使用库函数接口执行APDU交互*/
    ret = iso7816_exchange(ICC_DEV_NSLOT, AUTO_GET_RSP, &apdu_req, &rsp);
    if(ret != 0)  //出错
    {        
        ICC_DEBUG("exchange err!(%d)\r\n", ret);
        ret = DEVSTATUS_ERR_PARAM_ERR;
    }
    else
    {
        ret = DEVSTATUS_SUCCESS;
        
        if((rsp.len_out+2) > rxmax)  //出错
        {            
            ICC_DEBUG("len_out over!(len_out=%d, rxmax=%d)\r\n", rsp.len_out, rxmax);
            ret = DEVSTATUS_ERR_PARAM_ERR;
        }
        else
        {
            memcpy(rbuf, rsp.data_out, rsp.len_out);
            rbuf[rsp.len_out++] = rsp.swa;
            rbuf[rsp.len_out++] = rsp.swb;
            *rlen = rsp.len_out;
            ret = DEVSTATUS_SUCCESS;
        }
    }
    
    return ret;
}

s32 dev_icc_exchange_apdu(s32 nslot, const u8* lpCApdu, u32 nCApduLen, u8*lpRApdu, u32* lpRApduLen, u32 nRApduSize)
{
    s32 ret = DEVSTATUS_ERR_PARAM_ERR;
    
    if(nslot >= ICC_SLOT_MAX)  //3
    {
        ICC_DEBUG("PARAM Err!(nslot=%d)\r\n", nslot);
        return DEVSTATUS_ERR_PARAM_ERR;
    }
    
    if(g_icc_fd[nslot] < 0)
    {
        ICC_DEBUG("DEVICE_NOTOPEN!\r\n");
        return DEVSTATUS_ERR_DEVICE_NOTOPEN;
    }
    
    switch(nslot)
    {
    case ICC_SLOT_ICCARD:  //0  
        ret = drv_icc_exchange_apdu((u8*)lpCApdu, nCApduLen, lpRApdu, lpRApduLen, nRApduSize);
        break;
    case ICC_SLOT_PSAM1:
    case ICC_SLOT_PSAM2:
        if(g_psam_existflg)
        {
            ret = drv_psam_exchange_apdu(nslot-1, (u8*)lpCApdu, nCApduLen, lpRApdu, lpRApduLen, nRApduSize);
        }
        break;
    }
    
    return ret;
}

 

相关标签: T6S项目

上一篇:

下一篇: