RC663 基于NXP NFC reader 读取 FM1216

前言

最近由于项目需要使用 RC663 读取 FM1216 的 卡片,最初的项目是基于 S70(mifare) 来开发的,而且仅仅是对卡号进行了读取,并未对卡片的内容进行读写操作.而且加之使用的NFC Reader 库是比较老的版本,所以我就下载了新版本,开始了整(踩)合(坑)之路.

1.NXP NFC reader library 的集成

我使用的NFCLib 的版本为: NxpNfcRdLib_RC663_LPC1769_v05.21.00_Full

首先是导入源文件 , 导入头文件 , 这部分就跳过了,因为都是重复操作,没有什么需要注意的,缺什么文件就导入什么文件.

然后,因为我使用的是RC663 ,所以定义 宏 NXPBUILD__PHHAL_HW_RC663 .
而且,我 定义了PHDRIVER_PIRC663_BOARD 用于 控制NSS 脚的拉高拉低.
其次,我没有使用FreeRTOS .所以声明了 PH_OSAL_NULLOS

在这些都弄好后, 就到了驱动层了, 我现在用的是SPI, 所以将 SPI 初始化以及读写部分的函数实现替换为自己的函数.
并且将控制 POWER-DOWN 及 NSS 两个GPIO的 实现替换为自己的实现.

中断部分目前我没有弄.

2. NFC Reader library 的初始化

1. 首先初始化NfcLib

phStatus_t wStatus ;
phNfcLib_Status_t     dwStatus;

phNfcLib_AppContext_t AppContext;
phbalReg_Type_t sBalParams;

wStatus = phbalReg_Init(&sBalParams, sizeof(phbalReg_Type_t));

AppContext.pBalDataparams = &sBalParams ;

dwStatus = phNfcLib_SetContext(&AppContext);

dwStatus = phNfcLib_Init();

2. 初始化 14443 协议层

phhalHw_Rc663_DataParams_t    * pHal;
void *pspalI14443p3a;
void *pspalI14443p3b;
void *pspalI14443p4a;
void *pspalI14443p4;

pHal = phNfcLib_GetDataParams(PH_COMP_HAL);
pspalI14443p3a = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P3A);
pspalI14443p3b = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P3B);
pspalI14443p4a = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4A);
pspalI14443p4 = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4);

/* Configure HAL to ISO mode */
wStatus = phhalHw_SetConfig(
              pHal,
              PHHAL_HW_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);

/* Configure I14443-A PAL to ISO mode */
wStatus = phpalI14443p3a_SetConfig(
              pspalI14443p3a,
              PHPAL_I14443P3A_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);

/* Configure I14443-B PAL to ISO mode */
wStatus = phpalI14443p3b_SetConfig(
              pspalI14443p3b,
              PHPAL_I14443P3B_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);

/* Configure I14443-4A PAL to ISO mode */
wStatus = phpalI14443p4a_SetConfig(
              pspalI14443p4a,
              PHPAL_I14443P4A_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);

/* Configure I14443-4 PAL to ISO mode */
wStatus = phpalI14443p4_SetConfig(
              pspalI14443p4,
              PHPAL_I14443P4_CONFIG_OPE_MODE,
              RD_LIB_MODE_ISO);


到这里 NfcLib 以及14443 的协议层就已经初始化完成了. 接下来就是使用了.

这里唯一需要注意的就是 phbalReg_Init 中的实现了,这部分的实现是根据自身所使用的接口来选择的,我用的是SPI,所以这里就是初始化SPI

3. NFC Reader library 的使用

1. 引用 14443 协议

wStatus = phhalHw_ApplyProtocolSettings(pHal, PHHAL_HW_CARDTYPE_ISO14443A);

这里因为我需要读取的是FM1216 的卡片,所以就 应用的是 14443A Type-A

2. 打开 Field

wStatus = phhalHw_FieldOn(pHal);

3. 做一个简单的延时 , 可以确保Field 打开

wStatus = phhalHw_Wait(pHal,PHHAL_HW_TIME_MILLISECONDS, 6);

4. 激活14443A的卡.

wStatus = phpalI14443p3a_ActivateCard(
              pspalI14443p3a,
              NULL,
              0x00,
              bUid,
              &bLength,
              &bSak,
              &bMoreCardsAvailable);

5. 判断是否 PICC (Proximity Card) 是否符合 ISO/IEC 14443-4

 if ( (0x08 == (bSak & 0x08)) &&  (0x20 == (bSak & 0x20)) )

参考自 <ISO/IEC 14443-3 Part 3: Initialization and anticollision> 6.4.3.4 Coding of SAK(Select acknowledge) . Table 6.8 - Coding of SAK

6. Send RATS

wStatus = phpalI14443p4a_Rats(
              pspalI14443p4a,
              0,
              bCid,
              Ats);

7. 获取 14443-4A 的参数并设置 14443-4 协议参数

/* Get parameters from 4A */
wStatus = phpalI14443p4a_GetProtocolParams(
              pspalI14443p4a,
              &bCidEnabled,
              &bCid,
              &bNadSupported,
              &bFwi,
              &bFsdi,
              &bFsci);

/* Apply parameters to layer 4 */
wStatus = phpalI14443p4_SetProtocol(
              pspalI14443p4,
              bCidEnabled,
              bCid,
              0,
              0,
              bFwi,
              bFsdi,
              bFsci);

8. 交换数据

wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              pTxBuffer,
              wTxLength,
              ppRxBuffer,
              pRxLength);

9. 关闭Field

wStatus = phhalHw_FieldOff(pHal);

关于上述流程,参考自 <ISO/IEC 14443-4 Part 4: Transmission protocol> 5. Protocol activation of PICC Type A . Figure 1 (the activation sequence for a PICC type A in the view of a PCD)
另外每完成一个步骤,应该先检查是否执行成功,如果执行成功,才继续往下走.

4. FMCOS 的使用

参考资料 :

我使用的是FM1216系列CPU 卡 ,而他搭载的COS 正是 FMCOS . 这里我不得不吐槽下,FMCOS 的资料真的是好少...

首先要执行发卡流程.
1. 取随机数

uint8_t CMD[] = {0x00, 0x84, 0x00, 0x00, 0x04};
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              CMD,
              sizeof(CMD),
              ppRxBuffer,
              pRxLength);

2. 当取随机数成功后, 返回状态 为 '90 00' 的时候.对齐进行DES 加密后,进行外部认证

uint8_t ExternalAuthentiateData[13] = {0x00,0x82,0x00,0x00,0x08,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} ;
uint8_t Data[8] ;
uint8_t EncryptData[8] ;
uint8_t i ;

memset(Data,0,sizeof(Data));
memcpy(Data,Challenge,4);

des(Data,ExternalKey,0,EncryptData);

for(i=5; i<13; i++) {
    ExternalAuthentiateData[i] = EncryptData[i-5] ;
}

printBuf("ExternalAuthentiateData:", ExternalAuthentiateData, 13, 32);
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              ExternalAuthentiateData,
              sizeof(ExternalAuthentiateData),
              &pRxData,
              &wRxDataLength);

3. 卡片擦除

uint8_t CMD[] = {0x80,0x0E,0x00,0x00,0x00} ;
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              CMD,
              sizeof(CMD),
              &pRxData,
              &wRxDataLength);

4. 选择MF

uint8_t choose_file [] = {0x00,0xA4,0x00,0x00,0x02,0x3F,0x00};
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              choose_file,
              sizeof(choose_file),
              &pRxData,
              &wRxDataLength);

5. 创建密钥文件

uint8_t CMD [20] = {0x80,0xE0,
                    0x00,0x00,  // 文件标识
                    0x07, // lc
                    0x3F,  // 文件类型
                    0x00,0xB0, // 文件空间
                    0x01,  //读权限
                    0xF0,  //写权限
                    0xFF,
                    0xFF  // 详细见6.13.3
                   };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              CMD,
              sizeof(CMD),
              &pRxData,
              &wRxDataLength);

6. 添加 PIN 到密钥中

uint8_t AddPin2KEY[18] = { 0x80,0xD4,
                           0x01,0x00, //文件标识
                           0x0D,  // 长度
                           0x39,  // 文件类型. 0x39为 外部认证密钥
                           0xF0,  // 读权限
                           0xF0,  // 写权限
                           0xAA,  // 后续状态
                           0x88,  // 错误计数 ,高字节为最多错误次数,低字节为还可以继续错误次数
                           0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF         //密钥
                         } ;
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              AddPin2KEY,
              sizeof(AddPin2KEY),
              &pRxData,
              &wRxDataLength);

7. 建立目录(DF)

uint8_t CMD[29] = { 0x80, 0xE0, // 创建文件
                    (uint8_t)(FileID >> 8),(uint8_t)FileID,  // 文件标识
                    0x0D, // 文件长度
                    0x38,  // 文件类型
                    0x05, 0x20,  //  文件空间大小
                    0xF0,  // 读权限
                    0xF0,  // 写权限
                    0x95,  // 应用文件ID
                    0xFF, 0xFF,   // reversed
                    // DF 名称 ASCII 码 5- 16 个字节
                  };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              AddPin2KEY,
              sizeof(AddPin2KEY),
              &pRxData,
              &wRxDataLength);

8. 选择DF(其实和选择MF 是一样的命令,只是 文件标识不同

uint8_t choose_file [] = {0x00,0xA4,0x00,0x00,0x02,0x3F,0x01};
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              choose_file,
              sizeof(choose_file),
              &pRxData,
              &wRxDataLength);

9. 创建 DF 内的密钥 文件. 参考 5 创建密钥文件

10. 添加 PIN 到 DF 内的密钥中. 参考 6 添加 PIN 到密钥中

11. 建立二进制文件

uint8_t CreateFile_EF_BIN [] = {0x80,0xE0,
                                0x00,0x03,//File ID
                                0x07, // lc
                                0x28,  //文件类型. 
                                0x00,0x1E, //  文件大小
                                0xF0,  //读权限
                                0xF0,  //写权限
                                0xFF,
                                0x02  // 详细见6.13.3
                               };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              CreateFile_EF_BIN,
              sizeof(CreateFile_EF_BIN),
              &pRxData,
              &wRxDataLength);

12. 选择二进制文件 ,参考 选择MF,只是 文件标识不同

13. 写入数据到二进制文件 , 需要注意的是 数据大小不能超过文件空间的大小;

uint8_t WriteFile_BIN [] = {0x00,0xD6,
                            0x00,0x00,//P1 , P2
                            0x05, // lc
                            0x01,0x02,0x03,0x02,0x01 //  写入的数据
                           };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              WriteFile_BIN,
              sizeof(WriteFile_BIN),
              &pRxData,
              &wRxDataLength);

然后是读卡流程

1. 选择DF ,参考 发卡流程的选择DF

2. 验证口令

uint8_t Verify_Pin [] = {0x00,0x20,
                         0x00,0x01,// 密钥标识
                         0x03, // lc
                         0x12,0x34,0x56// 密码
                        };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              Verify_Pin,
              sizeof(Verify_Pin),
              &pRxData,
              &wRxDataLength);                        

3. 选择二进制文件 参考 发卡流程的选择二进制文件

4. 读取二进制文件

uint8_t ReadFile_BIN [] = {0x00,0xB0,
                           0x00,0x00,//P1 , P2 
                           0x00,0x00
                          };
wStatus = phpalI14443p4_Exchange(
              pspalI14443p4,
              PH_EXCHANGE_DEFAULT,
              ReadFile_BIN,
              sizeof(ReadFile_BIN),
              &pRxData,
              &wRxDataLength);                        

目前还没有弄循环记录文件 ,等弄好了之后再继续更新.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容