diff --git a/Arduino-Aime-Reader.ino b/Arduino-Aime-Reader.ino index c8efc44..b8cce4d 100644 --- a/Arduino-Aime-Reader.ino +++ b/Arduino-Aime-Reader.ino @@ -27,10 +27,10 @@ void SerialCheck() { sg_nfc_cmd_mifare_select_tag(); break; case SG_NFC_CMD_MIFARE_SET_KEY_AIME: - sg_nfc_cmd_mifare_set_key_aime(); + sg_nfc_cmd_mifare_set_key(); break; - case SG_NFC_CMD_MIFARE_SET_KEY_BANA://不处理 - sg_res_init(); + case SG_NFC_CMD_MIFARE_SET_KEY_BANA: + sg_nfc_cmd_mifare_set_key(); break; case SG_NFC_CMD_RADIO_ON: sg_nfc_cmd_radio_on(); @@ -47,10 +47,10 @@ void SerialCheck() { case SG_RGB_CMD_SET_COLOR: sg_led_cmd_set_color(); break; - case 0: - break; - default: - sg_res_init(); + // case 0: + // break; + // default: + // sg_res_init(); } } @@ -69,6 +69,7 @@ void setup() { delay(500); } } + nfc.setPassiveActivationRetries(0x10);//设定等待次数 nfc.SAMConfig(); memset(&req, 0, sizeof(req.bytes)); memset(&res, 0, sizeof(res.bytes)); diff --git a/README.md b/README.md index 55b85da..f8e6e88 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,21 @@ # Arduino-Aime-Reader -使用 Arduino + PN532 + WS2812B 制作的 Aime 读卡器。 +使用 Arduino + PN532 + WS2812B 制作的 Aime 读卡器。支持 Felica 和 Aime(Mifare 卡模拟 Felica 是可选功能)。 通信数据格式可参考 [card.txt](https://github.com/Sucareto/Arduino-Aime-Reader/blob/main/doc/card.txt) 和 [nfc.txt](https://github.com/Sucareto/Arduino-Aime-Reader/blob/main/doc/nfc.txt)。 替换 chunihook.dll 可在控制台输出通信数据,源码在 [sg-cmd.c](https://github.com/Sucareto/Arduino-Chunithm-Reader/blob/main/tools/sg-cmd.c)。 + +#### 使用方法: +按照 [PN532](https://github.com/elechouse/PN532) 的提示安装库; +Arduino 和 PN532 接好 VCC,GND,SDA,SCL; +接上 WS2812B 灯条(可选); +上传程序。 + +打开设备管理器,设置 Arduino 的 COM 号,一些参考如下: +Chunithm:COM12,支持 Felica 和 Aime; +Ongeki:COM1,仅支持 Aime; +MaiMai Finale:COM2,仅支持 Aime; + +某些 Arduino 可能需要在打开主程序前给串口发送 DTR/RTS,需要先打开一次 Arduino 串口监视器再启动主程序。 + #### 引用库: [驱动WS2812B FastLED.h](https://github.com/FastLED/FastLED) -[驱动PN532 Adafruit_PN532.h](https://github.com/adafruit/Adafruit-PN532) +[驱动PN532 PN532.h](https://github.com/elechouse/PN532) diff --git a/cmd.h b/cmd.h index 4abafa9..f01d551 100644 --- a/cmd.h +++ b/cmd.h @@ -4,21 +4,39 @@ #define BRI 50 CRGB leds[NUM_LEDS]; -#include "Adafruit_PN532.h" -#define PN532_IRQ 4 -Adafruit_PN532 nfc(PN532_IRQ, 16); -uint8_t cardtype = 0; -uint8_t uid[4], uL; -#define M2F_B 1 //指定从mifare读取第几block当作felica的IDm和PMm +#include +#include +#include -uint8_t AimeKey[6] = {0x57, 0x43, 0x43, 0x46, 0x76, 0x32}; +PN532_I2C pn532i2c(Wire); +PN532 nfc(pn532i2c); + +uint8_t cardtype, uid[4], uL; +uint16_t systemCode = 0xFFFF; +uint8_t requestCode = 0x01; +uint16_t systemCodeResponse; +typedef union { + uint8_t block[16]; + struct { + uint8_t IDm[8]; + uint8_t PMm[8]; + }; +} Felica; +Felica felica; +uint8_t AimeKey[6], BanaKey[6]; + +#define M2F //取消注释此行,将默认密钥的mifare模拟为felica + +#ifdef M2F +#define M2F_B 1 //指定从mifare读取第几block当作felica的IDm和PMm uint8_t MifareKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +#endif enum { SG_NFC_CMD_GET_FW_VERSION = 0x30,//获取FW版本 SG_NFC_CMD_GET_HW_VERSION = 0x32,//获取HW版本 - SG_NFC_CMD_RADIO_ON = 0x40,//不处理 - SG_NFC_CMD_RADIO_OFF = 0x41,//不处理 + SG_NFC_CMD_RADIO_ON = 0x40, + SG_NFC_CMD_RADIO_OFF = 0x41, SG_NFC_CMD_POLL = 0x42,//发送卡号 SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50, @@ -44,7 +62,7 @@ typedef union packet_req { uint8_t cmd; uint8_t payload_len; union { - uint8_t key[6];// sg_nfc_req_mifare_set_key + uint8_t key[6];// sg_nfc_req_mifare_set_key(bana or aime) uint8_t color_payload[3];//sg_led_req_set_color struct {// sg_nfc_cmd_mifare_read_block uint8_t uid[4]; @@ -79,20 +97,19 @@ typedef union packet_res { uint8_t count; uint8_t type; uint8_t id_len; - uint8_t poll[16];//aime uid or felica IDm+PMm + uint8_t IDm[8];//and Aime uid + uint8_t PMm[8]; }; struct {// sg_nfc_res_felica_encap uint8_t encap_len; uint8_t code; + uint8_t encap_IDm[8]; union { struct { - uint8_t encap_block[16]; + uint8_t encap_PMm[8]; uint8_t system_code[2]; }; - struct { - uint8_t encap_IDm[8]; - uint8_t felica_payload[241]; - }; + uint8_t felica_payload[241]; }; }; }; @@ -113,6 +130,8 @@ static void sg_res_init(uint8_t payload_len = 0) { //初始化模板 static void sg_nfc_cmd_reset() {//重置读卡器 nfc.begin(); + nfc.setPassiveActivationRetries(0x10);//设定等待次数 + nfc.SAMConfig(); if (nfc.getFirmwareVersion()) { nfc.SAMConfig(); sg_res_init(); @@ -125,17 +144,21 @@ static void sg_nfc_cmd_reset() {//重置读卡器 static void sg_nfc_cmd_get_fw_version() { sg_res_init(sizeof(res.version)); - memcpy(res.version, "TN32MSEC003S F/W Ver1.2E", sizeof(res.version)); + memcpy(res.version, "TN32MSEC003S F/W Ver1.2E", 23); } static void sg_nfc_cmd_get_hw_version() { sg_res_init(sizeof(res.version)); - memcpy(res.version, "TN32MSEC003S H/W Ver3.0J", sizeof(res.version)); + memcpy(res.version, "TN32MSEC003S H/W Ver3.0J", 23); } -static void sg_nfc_cmd_mifare_set_key_aime() { //设置aime的读取key +static void sg_nfc_cmd_mifare_set_key() { sg_res_init(); - // memcpy(req.key, AimeKey, sizeof(AimeKey)); + if (req.cmd == SG_NFC_CMD_MIFARE_SET_KEY_BANA) { + memcpy(BanaKey, req.key, 6); + } else if (req.cmd == SG_NFC_CMD_MIFARE_SET_KEY_AIME) { + memcpy(AimeKey, req.key, 6); + } } static void sg_led_cmd_reset() { @@ -160,29 +183,33 @@ static void sg_led_cmd_set_color() { } static void sg_nfc_cmd_radio_on() { + cardtype = 0; + uL = 0; + memset(&uid, 0, 4); + memset(&felica, 0, 16); sg_res_init(); - nfc.startPassiveTargetIDDetection(PN532_MIFARE_ISO14443A); - delay(10); - if (!digitalRead(PN532_IRQ) && nfc.readDetectedPassiveTargetID(uid, &uL)) { - if (nfc.mifareclassic_AuthenticateBlock(uid, uL, 1, MIFARE_CMD_AUTH_B, AimeKey)) { - cardtype = 0x10; - return; - } + //uid,uidLength,block,keyA(0) or keyB(1),Key + if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, 1, 1, AimeKey)) { + cardtype = 0x10; + return; } - nfc.startPassiveTargetIDDetection(PN532_MIFARE_ISO14443A); - delay(10); - if (!digitalRead(PN532_IRQ) && nfc.readDetectedPassiveTargetID(uid, &uL)) { - if (nfc.mifareclassic_AuthenticateBlock(uid, uL, M2F_B, MIFARE_CMD_AUTH_A, MifareKey)) { - cardtype = 0x20; - return; - } + if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, 1, 0, BanaKey)) { + cardtype = 0x10; + return; } + if (nfc.felica_Polling(systemCode, requestCode, felica.IDm, felica.PMm, &systemCodeResponse, 200)) { + cardtype = 0x20; + return; + } +#ifdef M2F + if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, M2F_B, 0, MifareKey)) { + cardtype = 0x30; + return; + } +#endif } static void sg_nfc_cmd_radio_off() { - cardtype = 0; - uint8_t EKey[6] = {0x11, 0x45, 0x14, 0x19, 0x19, 0x81}; - nfc.mifareclassic_AuthenticateBlock(uid, uL, 63, MIFARE_CMD_AUTH_A, EKey);//断开卡片 sg_res_init(); } @@ -191,17 +218,31 @@ static void sg_nfc_cmd_poll() { //卡号发送 res.count = 1; res.type = 0x10; res.id_len = uL; - memcpy(res.poll, uid, uL); + memcpy(res.IDm, uid, uL); sg_res_init(7); return; } - if (cardtype == 0x20 && nfc.mifareclassic_ReadDataBlock(M2F_B, res.poll)) { + if (cardtype == 0x20) { sg_res_init(19);//count,type,id_len,IDm,PMm + memcpy(res.IDm, felica.IDm, 8); + memcpy(res.PMm, felica.PMm, 8); res.count = 1; res.type = 0x20; res.id_len = 0x10; return; } +#ifdef M2F + if (cardtype == 0x30) { + sg_res_init(19);//count,type,id_len,IDm,PMm + nfc.mifareclassic_ReadDataBlock(M2F_B, felica.block); + memcpy(res.IDm, felica.IDm, 8); + memcpy(res.PMm, felica.PMm, 8); + res.count = 1; + res.type = 0x20; + res.id_len = 0x10; + return; + } +#endif sg_res_init(1); res.count = 0; } @@ -210,6 +251,10 @@ static void sg_nfc_cmd_mifare_select_tag() { sg_res_init(); } +static void sg_nfc_cmd_mifare_authenticate() { + sg_res_init(); +} + static void sg_nfc_cmd_mifare_read_block() {//读取卡扇区数据 sg_res_init(); if (req.block_no > 2) { @@ -222,26 +267,24 @@ static void sg_nfc_cmd_mifare_read_block() {//读取卡扇区数据 } static void sg_nfc_cmd_felica_encap() { - if (!nfc.mifareclassic_ReadDataBlock(M2F_B, res.encap_block)) { - sg_res_init(); - res.status = 1; - return; - } uint8_t code = req.code; res.code = code + 1; switch (code) { case FELICA_CMD_POLL: sg_res_init(0x14); + memcpy(res.encap_IDm, felica.IDm, 8); + memcpy(res.encap_PMm, felica.PMm, 8); res.system_code[0] = 0x00; res.system_code[1] = 0x00; break; case FELICA_CMD_GET_SYSTEM_CODE: sg_res_init(0x0D); + memcpy(res.IDm, felica.IDm, 8); res.felica_payload[0] = 0x01; res.felica_payload[1] = 0x00; - res.felica_payload[2] = 0x00; + res.felica_payload[2] = 0x00;//0x03 break; - case FELICA_CMD_NDA_A4: + case FELICA_CMD_NDA_A4://pass // sg_res_init(0x0B); // res.felica_payload[0] = 0x00; sg_res_init();