From a2c939a3b020a7c8c1383cd623bfea57b6aa14f7 Mon Sep 17 00:00:00 2001 From: Sucareto <28331534+Sucareto@users.noreply.github.com> Date: Sat, 4 Feb 2023 21:32:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=86=85=E5=AE=B9=EF=BC=9A?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=20SpiceTools=20=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=EF=BC=9B=20=E6=94=B9=E4=B8=BA=E4=BD=BF=E7=94=A8=E5=B7=B2?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=9A=84=20PN532=20=E5=92=8C=20SpiceAPI=20?= =?UTF-8?q?=E5=BA=93=EF=BC=9B=20=E7=A7=BB=E9=99=A4=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=B8=8D=E6=AD=A3=E7=A1=AE=E7=9A=84=20USB=20=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=98=BE=E7=A4=BA=EF=BC=9B=20=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E6=8E=92=E5=B8=83=20OLED=20=E7=9A=84=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E6=96=87=E5=AD=97=E5=92=8C=E5=9B=BE=E6=A0=87=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE=EF=BC=9B=20=E4=BF=AE=E6=94=B9=20SW=20=E5=BC=80?= =?UTF-8?q?=E5=85=B3=E5=AE=9A=E4=B9=89=EF=BC=8C=E7=A7=BB=E9=99=A4=E6=B2=A1?= =?UTF-8?q?=E8=83=BD=E5=AE=9E=E7=8E=B0=E7=9A=84=20BLE=20=E5=88=B7=E5=8D=A1?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9B=20=E5=88=A0=E9=99=A4=E5=86=97?= =?UTF-8?q?=E4=BD=99=E4=BB=A3=E7=A0=81=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ESP32-CardReader.ino | 167 ++++---- README.md | 49 ++- Aime-Reader.h => ReaderCmd.h | 805 ++++++++++++++++++----------------- 3 files changed, 539 insertions(+), 482 deletions(-) rename Aime-Reader.h => ReaderCmd.h (54%) diff --git a/ESP32-CardReader.ino b/ESP32-CardReader.ino index 00848e0..036d4ea 100644 --- a/ESP32-CardReader.ino +++ b/ESP32-CardReader.ino @@ -1,55 +1,54 @@ -#if defined(ARDUINO_NodeMCU_32S) +#ifdef ARDUINO_NodeMCU_32S #pragma message "当前的开发板是 NodeMCU_32S" #define SerialDevice Serial #define LED_PIN 13 #define PN532_SPI_SS 5 +// #define OTA_Enable #define SW1 33 #define SW2 25 #define SW3 26 #define SW4 27 +bool ReaderMode, FWSW; +#ifdef OTA_Enable #pragma message "已启用OTA更新" - #define STASSID "ALL.Net Wi-Fi" #define STAPASS "SEGASEGASEGA" #define OTA_URL "http://esp-update.local/Sucareto/ESP32-Reader:2333/" #include #include +#endif #else #error "开发板选错了!!!" #endif -#include "Aime-Reader.h" +#include "ReaderCmd.h" +void (*ReaderMain)(); void setup() { - pinMode(SW1, INPUT_PULLUP); - pinMode(SW2, INPUT_PULLUP); - pinMode(SW3, INPUT_PULLUP); - pinMode(SW4, INPUT_PULLUP); + pinMode(SW1, INPUT_PULLUP); // Switch to Spice mode + pinMode(SW2, INPUT_PULLUP); // Enable OTA + pinMode(SW3, INPUT_PULLUP); // LED brightness + pinMode(SW4, INPUT_PULLUP); // (Aime) Baudrate & fw/hw | (Spice) 1P 2P - bool high_baudrate = !digitalRead(SW1); - FWSW = !digitalRead(SW2); u8g2.begin(); u8g2.setFont(u8g2_font_6x12_mf); - u8g2.drawXBM(0, 0, 16, 16, usb_disconnect); - u8g2.drawStr(48, 10, high_baudrate ? "HIGH" : "LOW"); - u8g2.sendBuffer(); - - SerialDevice.begin(high_baudrate ? 115200 : 38400); - FastLED.addLeds(leds, 8); - if (!digitalRead(SW3)) { + if (digitalRead(SW3)) { FastLED.setBrightness(20); } FastLED.showColor(0); - if (!digitalRead(SW4)) { +#ifdef OTA_Enable + if (!digitalRead(SW1)) { // OTA check WiFi.begin(STASSID, STAPASS); u8g2.drawStr(0, 28, "WiFi Connecting..."); u8g2.sendBuffer(); - while (WiFi.status() != WL_CONNECTED); + while (WiFi.status() != WL_CONNECTED) { + delay(100); + }; u8g2.drawStr(0, 28, "WiFi connected. "); u8g2.drawStr(0, 41, "Check update... "); u8g2.sendBuffer(); @@ -65,105 +64,92 @@ void setup() { u8g2.drawStr(0, 41, "Already up to date. "); break; } - u8g2.sendBuffer(); } +#endif nfc.begin(); while (!nfc.getFirmwareVersion()) { - u8g2.drawXBM(20, 0, 16, 16, rf_off); + u8g2.drawXBM(95, 0, 16, 16, rf_off); u8g2.sendBuffer(); FastLED.showColor(0xFF0000); delay(500); FastLED.showColor(0); delay(500); } - nfc.setPassiveActivationRetries(0x10);//设定等待次数 + nfc.setPassiveActivationRetries(0x10); nfc.SAMConfig(); + u8g2.clearBuffer(); + ReaderMode = !digitalRead(SW1); + FWSW = digitalRead(SW4); + if (ReaderMode) { // BEMANI mode + SerialDevice.begin(115200); + u8g2.drawStr(0, 14, "SpiceTools"); + u8g2.drawStr(117, 64, FWSW ? "1P" : "2P"); + FastLED.showColor(CRGB::Yellow); + ReaderMain = SpiceToolsReader; + } else { // Aime mode + SerialDevice.begin(FWSW ? 38400 : 115200); + u8g2.drawStr(0, 16, "Aime Reader"); + u8g2.drawStr(105, 64, FWSW ? "LOW" : "HIGH"); + u8g2.drawStr(0, 64, FWSW ? "TN32MSEC003S" : "837-15396"); + FastLED.showColor(FWSW ? CRGB::Green : CRGB::Blue); + ReaderMain = AimeCardReader; + } memset(&req, 0, sizeof(req.bytes)); memset(&res, 0, sizeof(res.bytes)); - - u8g2.drawXBM(20, 0, 16, 16, blank); - u8g2.drawStr(0, 64, FWSW ? "TN32MSEC003S" : "837-15396"); u8g2.sendBuffer(); - FastLED.showColor(high_baudrate ? 0x0000FF : 0x00FF00); - } -unsigned long ConnectTime = 0; -bool ConnectStatus = false; void loop() { - SerialCheck(); - packet_write(); - if (ConnectStatus & millis() - ConnectTime > 5000) { - u8g2.drawXBM(0, 0, 16, 16, usb_disconnect); - u8g2.sendBuffer(); - ConnectStatus = false; - } + ReaderMain(); } -static uint8_t len, r, checksum; -static bool escape = false; -static uint8_t packet_read() { - while (SerialDevice.available()) { - r = SerialDevice.read(); - if (r == 0xE0) { - req.frame_len = 0xFF; - continue; - } - if (req.frame_len == 0xFF) { - req.frame_len = r; - len = 0; - checksum = r; - continue; - } - if (r == 0xD0) { - escape = true; - continue; - } - if (escape) { - r++; - escape = false; - } - req.bytes[++len] = r; - if (len == req.frame_len && checksum == r) { - ConnectStatus = true; - ConnectTime = millis(); - return req.cmd; - } - checksum += r; - } - return 0; -} +void SpiceToolsReader() { // Spice mode + uint16_t SystemCode; + char card_id[17]; + if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, res.mifare_uid, &res.id_len) + && nfc.mifareclassic_AuthenticateBlock(res.mifare_uid, res.id_len, 1, 0, MifareKey) + && nfc.mifareclassic_ReadDataBlock(1, res.block)) { + sprintf(card_id, "%02X%02X%02X%02X%02X%02X%02X%02X", + res.block[0], res.block[1], res.block[2], res.block[3], + res.block[4], res.block[5], res.block[6], res.block[7]); -static void packet_write() { - uint8_t checksum = 0, len = 0; - if (res.cmd == 0) { + } else if (nfc.felica_Polling(0xFFFF, 0x00, res.IDm, res.PMm, &SystemCode, 200) == 1) { + sprintf(card_id, "%02X%02X%02X%02X%02X%02X%02X%02X", + res.IDm[0], res.IDm[1], res.IDm[2], res.IDm[3], + res.IDm[4], res.IDm[5], res.IDm[6], res.IDm[7]); + } else { return; } - SerialDevice.write(0xE0); - while (len <= res.frame_len) { - uint8_t w; - if (len == res.frame_len) { - w = checksum; - } else { - w = res.bytes[len]; - checksum += w; + u8g2.drawXBM(113, 0, 16, 16, card); + u8g2.sendBuffer(); + spiceapi::InfoAvs avs_info{}; + if (spiceapi::info_avs(CON, avs_info)) { + FWSW = digitalRead(SW4); + spiceapi::card_insert(CON, !FWSW, card_id); + u8g2.drawStr(0, 30, card_id); + u8g2.drawStr(0, 64, (avs_info.model + ":" + avs_info.dest + avs_info.spec + avs_info.rev + ":" + avs_info.ext).c_str()); + u8g2.drawStr(117, 64, FWSW ? "1P" : "2P"); + u8g2.sendBuffer(); + for (int i = 0; i < 8; i++) { + leds[i] = CRGB::Red; + leds[7 - i] = CRGB::Blue; + FastLED.delay(50); + leds[i] = CRGB::Black; + leds[7 - i] = CRGB::Black; } - if (w == 0xE0 || w == 0xD0) { - SerialDevice.write(0xD0); - SerialDevice.write(--w); - } else { - SerialDevice.write(w); - } - len++; + FastLED.show(); } - res.cmd = 0; + u8g2.drawXBM(113, 0, 16, 16, blank); + u8g2.drawStr(0, 30, " "); + u8g2.sendBuffer(); } -void SerialCheck() { + +void AimeCardReader() { // Aime mode switch (packet_read()) { case SG_NFC_CMD_RESET: sg_nfc_cmd_reset(); @@ -190,7 +176,7 @@ void SerialCheck() { sg_nfc_cmd_bana_authenticate(); break; case SG_NFC_CMD_MIFARE_SELECT_TAG: - sg_nfc_cmd_mifare_select_tag(); + sg_res_init(); break; case SG_NFC_CMD_MIFARE_SET_KEY_AIME: sg_nfc_cmd_mifare_set_key_aime(); @@ -214,8 +200,9 @@ void SerialCheck() { sg_led_cmd_set_color(); break; case 0: - break; + return; default: sg_res_init(); } + packet_write(); } diff --git a/README.md b/README.md index b8b1d36..ce536f3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,16 @@ # ESP32-CardReader -- 此项目为 [Arduino-Aime-Reader](https://github.com/Sucareto/Arduino-Aime-Reader) 的使用示例。 -- 主控模块是 NodeMCU-32S,添加了 SSD1306 模块显示信息。 -- 可以使用拨码开关切换连接波特率和修改其他设置,也可以切换为 HSU 直通模式。 -- 直通模式可以给 Android 和 PC 连接作为 USB PN532 读卡器使用,例如使用 [MIFARE Classic Tool (MCT)](https://github.com/ikarus23/MifareClassicTool) 或 [MifareOneTool](https://github.com/xcicode/MifareOneTool) 之类的软件。 +- 此项目为 [Arduino-Aime-Reader](https://github.com/Sucareto/Arduino-Aime-Reader) 的使用示例,使用的主控模块是 NodeMCU-32S +- 添加了 SSD1306 模块展示状态 +- 添加了拨码开关用于切换读卡器模式和波特率,也可以切换为 HSU 直通模式 + - 直通模式可以给 Android 或 PC 连接作为 USB PN532 读卡器使用,例如使用 [MIFARE Classic Tool (MCT)](https://github.com/ikarus23/MifareClassicTool) 或 [MifareOneTool](https://github.com/xcicode/MifareOneTool) 等读卡软件 +- 在原版 Aime 读卡器的基础上添加了 SpiceTools 模式,可以读取自定义的 MIFARE 卡和 FeliCa 卡 + - MIFARE 读取 sector 0 block 1 的前半部分作为卡号发送(可以通过代码定义) + - FeliCa 读取 idm 作为卡号发送 + - **仅用于分辨卡片和账号,读卡逻辑和卡号计算未正确实现** + +**本项目仅用于展示原项目 [Arduino-Aime-Reader](https://github.com/Sucareto/Arduino-Aime-Reader) 的使用示例,未曾开展或参与成品售卖,也不会向商业化制作提供任何支持。** + ## 实物图:
点击展开 @@ -18,18 +25,32 @@ https://user-images.githubusercontent.com/28331534/170975661-137f3474-f61a-4a4d- ## 使用说明: ### PCB 设计: -因为不舍得花时间去画 PCB,所以 ESP32 和 PN532 就使用了模块直插的方式,或许以后有机会的话... +- 该 PCB 方案仅用于我自己快速测试,并非最佳实现方案 +- 如果需要使用此 PCB 方案,请务必把 logo 删掉,然后根据需求认真审查 PCB 设计并作出修改后再进行制作 + ### 拨码开关: -在 PCB 放置了两个 4P 拨码开关。 +在 PCB 放置了两个 4P 拨码开关: -#### SW 1-4:(可修改代码自定义) -- SW1:切换波特率,对应`high_baudrate` -- SW2:切换固件显示版本,`TN32MSEC003S` 或 `837-15396` -- SW3:切换 BLE 连接(未实现) -- SW4:启用 OTA 更新 +#### SW 1-4:(用于更改读卡器功能,切换后需要重启) +- SW1:切换读卡器模式 + - ON:SpiceTools 模式,需要在 SpiceTools 添加启动参数 `-apiserial COM1 -apiserialbaud 115200`,"COM1" 改为实际的端口号 + - OFF:Aime 模式,和 [Arduino-Aime-Reader](https://github.com/Sucareto/Arduino-Aime-Reader) 使用方法一致 +- SW2:切换启动时的 OTA 开关 + - ON:连接 WiFi 获取更新,如未能连接到 WiFi 则会持续到连接成功后才能启动 + - OFF:跳过检查更新,直接启动 +- SW3:切换 LED 亮度 + - ON:全亮度 + - OFF:亮度降低到指定值 +- SW4:不同模式的功能切换 + - Spice 模式(可在运行中切换) + - ON:卡号发送到 2P 槽位(需要游戏支持) + - OFF:卡号发送到 1P 槽位 + - Aime 模式 + - ON:使用 38400 波特率初始化,固件版本是 TN32MSEC003S + - OFF:使用 115200 波特率初始化,固件版本是 837-15396 -#### TTL:(用于切换至 “USB PN532 读卡器”模式) +#### TTL:(用于切换至 “USB PN532 读卡器”模式,需要在断电情况下切换) - SW1:连接到 ESP32 的 `EN` 引脚,调为 `ON` 后会停用 ESP32,只使用 CH340 串口通信芯片 - SW2:在目前版本(v2)为空置 - SW3 & SW4:连接 CH340 和 PN532 的 `RX TX`引脚 @@ -48,8 +69,12 @@ https://user-images.githubusercontent.com/28331534/170975661-137f3474-f61a-4a4d- ## 感谢: - 原项目:[Arduino-Aime-Reader](https://github.com/Sucareto/Arduino-Aime-Reader) +- 驱动 WS2812B:[FastLED](https://github.com/FastLED/FastLED) - 操作 SSD1306:[u8g2](https://github.com/olikraus/u8g2) +- Spice 通信(已复制到本仓库并根据需要修改了部分代码):[SpiceAPI](https://github.com/spicetools/spicetools/tree/master/api/resources/arduino) +- 驱动 PN532(已复制到本仓库并根据需要修改了部分代码):[PN532](https://github.com/elechouse/PN532) - OLED 显示图案设计:PCtoLCD2002 - AimePad 盖板设计:[CoolBreezeArcanine](https://github.com/CoolBreezeArcanine) - PCB 图案:[妖夢 - ぷりん](https://www.pixiv.net/artworks/87578487) - OTA 代码参考:[OTA Updates](https://arduino-esp8266.readthedocs.io/en/latest/ota_updates/readme.html#http-server) +- Spice 通信参考:[PN5180-cardio SpiceAPI branch](https://github.com/CrazyRedMachine/PN5180-cardio/tree/SpiceAPI) diff --git a/Aime-Reader.h b/ReaderCmd.h similarity index 54% rename from Aime-Reader.h rename to ReaderCmd.h index 4327405..078cf76 100644 --- a/Aime-Reader.h +++ b/ReaderCmd.h @@ -1,380 +1,425 @@ -#include -#include -PN532_SPI pn532(SPI, PN532_SPI_SS); - -#include "PN532.h" -PN532 nfc(pn532); - -#include "FastLED.h" -CRGB leds[8]; - -#include -U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); - -static unsigned char usb_disconnect[] = { - 0x00, 0x40, 0x00, 0xAE, 0x00, 0x51, 0x80, 0x20, 0x00, 0x41, 0x80, 0x42, 0x40, 0x44, 0x08, 0x28, - 0x14, 0x14, 0x22, 0x02, 0x42, 0x00, 0x82, 0x00, 0x04, 0x01, 0x8A, 0x00, 0x75, 0x00, 0x02, 0x00 -}; - -static unsigned char usb_connect[] = { - 0x00, 0x40, 0x00, 0xA0, 0x00, 0x51, 0x80, 0x2A, 0x60, 0x14, 0x50, 0x08, 0xB0, 0x10, 0x48, 0x21, - 0x84, 0x12, 0x08, 0x0D, 0x10, 0x0A, 0x28, 0x06, 0x54, 0x01, 0x8A, 0x00, 0x05, 0x00, 0x02, 0x00 -}; -static unsigned char rf_open[] = { - 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x02, 0x40, 0x02, 0x40, 0x11, 0x88, 0x91, 0x89, 0x49, 0x92, - 0x49, 0x92, 0x91, 0x89, 0x11, 0x88, 0x02, 0x40, 0x02, 0x40, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char rf_off[] = { - 0x01, 0x00, 0x02, 0x00, 0x04, 0x20, 0x0A, 0x40, 0x12, 0x40, 0x21, 0x88, 0x51, 0x89, 0x89, 0x92, - 0x49, 0x93, 0x91, 0x8A, 0x11, 0x8C, 0x02, 0x48, 0x02, 0x50, 0x04, 0x20, 0x00, 0x40, 0x00, 0x80 -}; -static unsigned char card [] = { - 0x00, 0x00, 0xFC, 0x3F, 0x02, 0x40, 0x32, 0x48, 0x52, 0x48, 0x92, 0x48, 0x12, 0x49, 0x12, 0x4A, - 0x52, 0x48, 0x92, 0x48, 0x12, 0x49, 0x12, 0x4A, 0x12, 0x4C, 0x02, 0x40, 0xFC, 0x3F, 0x00, 0x00 -}; - -static unsigned char blank [] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -uint8_t AimeKey[6], BanaKey[6]; - -//TN32MSEC003S -char FW_TN32[] = {'T', 'N', '3', '2', 'M', 'S', 'E', 'C', '0', '0', '3', 'S', ' ', 'F', '/', 'W', ' ', 'V', 'e', 'r', '1', '.', '2'}; -char HW_TN32[] = {'T', 'N', '3', '2', 'M', 'S', 'E', 'C', '0', '0', '3', 'S', ' ', 'H', '/', 'W', ' ', 'V', 'e', 'r', '3', '.', '0'}; -char BOARD_TN32[] = {'1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12}; - -//837-15396 -char FW_837[] = {0x94}; -char HW_837[] = {'8', '3', '7', '-', '1', '5', '3', '9', '6'}; -char BOARD_837[] = {'0', '0', '0', '-', '0', '0', '0', '0', '0', 0xFF, 0x11, 0x40}; - -bool FWSW; -enum { - SG_NFC_CMD_GET_FW_VERSION = 0x30, - SG_NFC_CMD_GET_HW_VERSION = 0x32, - 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, - SG_NFC_CMD_BANA_AUTHENTICATE = 0x51, - SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, - SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, - SG_NFC_CMD_AIME_AUTHENTICATE = 0x55, - SG_NFC_CMD_TO_UPDATER_MODE = 0x60, - SG_NFC_CMD_SEND_HEX_DATA = 0x61, - SG_NFC_CMD_RESET = 0x62, - SG_NFC_CMD_FELICA_ENCAP = 0x71, - SG_RGB_CMD_SET_COLOR = 0x81, - SG_RGB_CMD_GET_INFO = 0xF0, - SG_RGB_CMD_RESET = 0xF5, - - //FELICA_ENCAP - FELICA_CMD_POLL = 0x00, - FELICA_CMD_NDA_06 = 0x06, - FELICA_CMD_NDA_08 = 0x08, - FELICA_CMD_GET_SYSTEM_CODE = 0x0C, - FELICA_CMD_NDA_A4 = 0xA4, -}; - -typedef union packet_req { - uint8_t bytes[128]; - struct { - uint8_t frame_len; - uint8_t addr; - uint8_t seq_no; - uint8_t cmd; - uint8_t payload_len; - union { - 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_select_tag,sg_nfc_cmd_mifare_authenticate,sg_nfc_cmd_mifare_read_block - uint8_t uid[4]; - uint8_t block_no; - }; - struct { //sg_nfc_req_felica_encap - uint8_t encap_IDm[8]; - uint8_t encap_len; - uint8_t encap_code; - union { - struct { - uint8_t poll_systemCode[2]; - uint8_t poll_requestCode; - uint8_t poll_timeout; - }; - struct { //NDA_06,NDA_08,NDA_A4 - uint8_t RW_IDm[8]; - uint8_t numService;//and NDA_A4 unknown byte - uint8_t serviceCodeList[2]; - uint8_t numBlock; - uint8_t blockList[1][2]; - uint8_t blockData[16];//WriteWithoutEncryption,ignore - }; - uint8_t felica_payload[1]; - }; - }; - }; - }; -} packet_req_t; - -typedef union packet_res { - uint8_t bytes[128]; - struct { - uint8_t frame_len; - uint8_t addr; - uint8_t seq_no; - uint8_t cmd; - uint8_t status; - uint8_t payload_len; - union { - char version[1]; //sg_nfc_res_get_fw_version,sg_nfc_res_get_hw_version,sg_led_res_get_info - uint8_t block[16]; //sg_nfc_res_mifare_read_block - struct { //sg_nfc_res_poll - uint8_t count; - uint8_t type; - uint8_t id_len; - union { - uint8_t mifare_uid[4]; - struct { - uint8_t IDm[8]; - uint8_t PMm[8]; - }; - }; - }; - struct { //sg_nfc_res_felica_encap - uint8_t encap_len; - uint8_t encap_code; - uint8_t encap_IDm[8]; - union { - struct {//FELICA_CMD_POLL - uint8_t poll_PMm[8]; - uint8_t poll_systemCode[2]; - }; - struct { - uint8_t RW_status[2];//猜测,NDA_06,NDA_08 - uint8_t numBlock;//NDA_06 - uint8_t blockData[1][1][16];//NDA_06 - }; - uint8_t felica_payload[1]; - }; - }; - }; - }; -} packet_res_t; - -static packet_req_t req; -static packet_res_t res; - -static void sg_res_init(uint8_t payload_len = 0) { //初始化模板 - res.frame_len = 6 + payload_len; - res.addr = req.addr; - res.seq_no = req.seq_no; - res.cmd = req.cmd; - res.status = 0; - res.payload_len = payload_len; -} - -static void sg_nfc_cmd_reset() { //重置读卡器 - FWSW = !digitalRead(SW2); - nfc.begin(); - nfc.setPassiveActivationRetries(0x10); //设定等待次数,0xFF永远等待 - nfc.SAMConfig(); - if (nfc.getFirmwareVersion()) { - nfc.SAMConfig(); - sg_res_init(); - res.status = 3; - u8g2.drawXBM(0, 0, 16, 16, usb_connect); - u8g2.drawXBM(20, 0, 16, 16, blank); - u8g2.drawXBM(111, 0, 16, 16, blank); - u8g2.sendBuffer(); - return; - } - u8g2.drawXBM(20, 0, 16, 16, rf_off); - u8g2.sendBuffer(); - FastLED.showColor(0xFF0000); -} - -static void sg_nfc_cmd_get_fw_version() { - if (FWSW) { - sg_res_init(sizeof(FW_TN32)); - memcpy(res.version, FW_TN32, res.payload_len); - } else { - sg_res_init(sizeof(FW_837)); - memcpy(res.version, FW_837, res.payload_len); - } -} - -static void sg_nfc_cmd_get_hw_version() { - if (FWSW) { - sg_res_init(sizeof(HW_TN32)); - memcpy(res.version, HW_TN32, res.payload_len); - } else { - sg_res_init(sizeof(HW_837)); - memcpy(res.version, HW_837, res.payload_len); - } -} - -static void sg_led_cmd_get_info() { - if (FWSW) { - sg_res_init(sizeof(BOARD_TN32)); - memcpy(res.version, BOARD_TN32, res.payload_len); - } else { - sg_res_init(sizeof(BOARD_837)); - memcpy(res.version, BOARD_837, res.payload_len); - } -} - -static void sg_nfc_cmd_mifare_set_key_aime() { - sg_res_init(); - memcpy(AimeKey, req.key, 6); -} - -static void sg_nfc_cmd_mifare_set_key_bana() { - sg_res_init(); - memcpy(BanaKey, req.key, 6); -} - -static void sg_led_cmd_reset() { - sg_res_init(); -} - -static void sg_led_cmd_set_color() { - FastLED.showColor(CRGB(req.color_payload[0], req.color_payload[1], req.color_payload[2])); -} - -static void sg_nfc_cmd_radio_on() { - sg_res_init(); - nfc.setRFField(0x00, 0x01); - u8g2.drawXBM(20, 0, 16, 16, rf_open); - u8g2.sendBuffer(); -} - -static void sg_nfc_cmd_radio_off() { - sg_res_init(); - nfc.setRFField(0x00, 0x00); - u8g2.drawXBM(20, 0, 16, 16, blank); - u8g2.sendBuffer(); -} - -static void sg_nfc_cmd_poll() { //卡号发送 - uint16_t SystemCode; - if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, res.mifare_uid, &res.id_len)) { - sg_res_init(0x07); - res.count = 1; - res.type = 0x10; - u8g2.drawXBM(111, 0, 16, 16, card); - u8g2.sendBuffer(); - return; - } - else if (nfc.felica_Polling(0xFFFF, 0x00, res.IDm, res.PMm, &SystemCode, 200) == 1) {//< 0: error - sg_res_init(0x13); - res.count = 1; - res.type = 0x20; - res.id_len = 0x10; - u8g2.drawXBM(111, 0, 16, 16, card); - u8g2.sendBuffer(); - return; - } else { - sg_res_init(1); - res.count = 0; - u8g2.drawXBM(111, 0, 16, 16, blank); - u8g2.sendBuffer(); - } -} - -static void sg_nfc_cmd_mifare_select_tag() { - sg_res_init(); -} - -static void sg_nfc_cmd_aime_authenticate() { - sg_res_init(); - if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 1, AimeKey)) { - return; - } else { - res.status = 1; - } -} - -static void sg_nfc_cmd_bana_authenticate() { - sg_res_init(); - if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 0, BanaKey)) { - return; - } else { - res.status = 1; - } -} - -static void sg_nfc_cmd_mifare_read_block() {//读取卡扇区数据 - if (nfc.mifareclassic_ReadDataBlock(req.block_no, res.block)) { - sg_res_init(0x10); - return; - } - sg_res_init(); - res.status = 1; -} - -static void sg_nfc_cmd_felica_encap() { - uint16_t SystemCode; - if (nfc.felica_Polling(0xFFFF, 0x01, res.encap_IDm, res.poll_PMm, &SystemCode, 200) == 1) { - SystemCode = SystemCode >> 8 | SystemCode << 8;//SystemCode,大小端反转注意 - } - else { - sg_res_init(); - res.status = 1; - return; - } - uint8_t code = req.encap_code; - res.encap_code = code + 1; - switch (code) { - case FELICA_CMD_POLL: - { - sg_res_init(0x14); - res.poll_systemCode[0] = SystemCode; - res.poll_systemCode[1] = SystemCode >> 8; - } - break; - case FELICA_CMD_GET_SYSTEM_CODE: - { - sg_res_init(0x0D); - res.felica_payload[0] = 0x01;//未知 - res.felica_payload[1] = SystemCode;//SystemCode - res.felica_payload[2] = SystemCode >> 8; - } - break; - case FELICA_CMD_NDA_A4: - { - sg_res_init(0x0B); - res.felica_payload[0] = 0x00; - } - break; - case FELICA_CMD_NDA_06: - { - uint16_t serviceCodeList[1] = {(uint16_t)(req.serviceCodeList[1] << 8 | req.serviceCodeList[0])};//大小端反转注意 - for (uint8_t i = 0; i < req.numBlock; i++) { - uint16_t blockList[1] = {(uint16_t)(req.blockList[i][0] << 8 | req.blockList[i][1])}; - if (nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 1, blockList, res.blockData[i]) != 1) { - memset(res.blockData[i], 0, 16);//dummy data - } - } - res.RW_status[0] = 0; - res.RW_status[1] = 0; - res.numBlock = req.numBlock; - sg_res_init(0x0D + req.numBlock * 16); - } - break; - case FELICA_CMD_NDA_08: - { - sg_res_init(0x0C);//此处应有写入卡,但是不打算实现 - res.RW_status[0] = 0; - res.RW_status[1] = 0; - } - break; - default: - sg_res_init(); - res.status = 1; - } - res.encap_len = res.payload_len; -} +#include "src/PN532_SPI.h" +PN532_SPI pn532(SPI, PN532_SPI_SS); + +#include "src/PN532.h" +PN532 nfc(pn532); + +#include "FastLED.h" +CRGB leds[8]; + +#include +U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); + +#define SPICEAPI_INTERFACE Serial +#include "src/wrappers.h" +spiceapi::Connection CON(512); + + +// static unsigned char usb_disconnect[] = { +// 0x00, 0x40, 0x00, 0xAE, 0x00, 0x51, 0x80, 0x20, 0x00, 0x41, 0x80, 0x42, 0x40, 0x44, 0x08, 0x28, +// 0x14, 0x14, 0x22, 0x02, 0x42, 0x00, 0x82, 0x00, 0x04, 0x01, 0x8A, 0x00, 0x75, 0x00, 0x02, 0x00 +// }; +// static unsigned char usb_connect[] = { +// 0x00, 0x40, 0x00, 0xA0, 0x00, 0x51, 0x80, 0x2A, 0x60, 0x14, 0x50, 0x08, 0xB0, 0x10, 0x48, 0x21, +// 0x84, 0x12, 0x08, 0x0D, 0x10, 0x0A, 0x28, 0x06, 0x54, 0x01, 0x8A, 0x00, 0x05, 0x00, 0x02, 0x00 +// }; +static unsigned char rf_open[] = { + 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x02, 0x40, 0x02, 0x40, 0x11, 0x88, 0x91, 0x89, 0x49, 0x92, + 0x49, 0x92, 0x91, 0x89, 0x11, 0x88, 0x02, 0x40, 0x02, 0x40, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char rf_off[] = { + 0x01, 0x00, 0x02, 0x00, 0x04, 0x20, 0x0A, 0x40, 0x12, 0x40, 0x21, 0x88, 0x51, 0x89, 0x89, 0x92, + 0x49, 0x93, 0x91, 0x8A, 0x11, 0x8C, 0x02, 0x48, 0x02, 0x50, 0x04, 0x20, 0x00, 0x40, 0x00, 0x80 +}; +static unsigned char card[] = { + 0x00, 0x00, 0xFC, 0x3F, 0x02, 0x40, 0x32, 0x48, 0x52, 0x48, 0x92, 0x48, 0x12, 0x49, 0x12, 0x4A, + 0x52, 0x48, 0x92, 0x48, 0x12, 0x49, 0x12, 0x4A, 0x12, 0x4C, 0x02, 0x40, 0xFC, 0x3F, 0x00, 0x00 +}; + +static unsigned char blank[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +uint8_t AimeKey[6], BanaKey[6], MifareKey[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +//TN32MSEC003S +char FW_TN32[] = { 'T', 'N', '3', '2', 'M', 'S', 'E', 'C', '0', '0', '3', 'S', ' ', 'F', '/', 'W', ' ', 'V', 'e', 'r', '1', '.', '2' }; +char HW_TN32[] = { 'T', 'N', '3', '2', 'M', 'S', 'E', 'C', '0', '0', '3', 'S', ' ', 'H', '/', 'W', ' ', 'V', 'e', 'r', '3', '.', '0' }; +char BOARD_TN32[] = { '1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12 }; + +//837-15396 +char FW_837[] = { 0x94 }; +char HW_837[] = { '8', '3', '7', '-', '1', '5', '3', '9', '6' }; +char BOARD_837[] = { '0', '0', '0', '-', '0', '0', '0', '0', '0', 0xFF, 0x11, 0x40 }; + +enum { + SG_NFC_CMD_GET_FW_VERSION = 0x30, + SG_NFC_CMD_GET_HW_VERSION = 0x32, + 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, + SG_NFC_CMD_BANA_AUTHENTICATE = 0x51, + SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, + SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, + SG_NFC_CMD_AIME_AUTHENTICATE = 0x55, + SG_NFC_CMD_TO_UPDATER_MODE = 0x60, + SG_NFC_CMD_SEND_HEX_DATA = 0x61, + SG_NFC_CMD_RESET = 0x62, + SG_NFC_CMD_FELICA_ENCAP = 0x71, + SG_RGB_CMD_SET_COLOR = 0x81, + SG_RGB_CMD_GET_INFO = 0xF0, + SG_RGB_CMD_RESET = 0xF5, + + //FELICA_ENCAP + FELICA_CMD_POLL = 0x00, + FELICA_CMD_NDA_06 = 0x06, + FELICA_CMD_NDA_08 = 0x08, + FELICA_CMD_GET_SYSTEM_CODE = 0x0C, + FELICA_CMD_NDA_A4 = 0xA4, +}; + +typedef union packet_req { + uint8_t bytes[128]; + struct { + uint8_t frame_len; + uint8_t addr; + uint8_t seq_no; + uint8_t cmd; + uint8_t payload_len; + union { + 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_select_tag,sg_nfc_cmd_mifare_authenticate,sg_nfc_cmd_mifare_read_block + uint8_t uid[4]; + uint8_t block_no; + }; + struct { //sg_nfc_req_felica_encap + uint8_t encap_IDm[8]; + uint8_t encap_len; + uint8_t encap_code; + union { + struct { + uint8_t poll_systemCode[2]; + uint8_t poll_requestCode; + uint8_t poll_timeout; + }; + struct { //NDA_06,NDA_08,NDA_A4 + uint8_t RW_IDm[8]; + uint8_t numService; //and NDA_A4 unknown byte + uint8_t serviceCodeList[2]; + uint8_t numBlock; + uint8_t blockList[1][2]; + uint8_t blockData[16]; //WriteWithoutEncryption,ignore + }; + uint8_t felica_payload[1]; + }; + }; + }; + }; +} packet_req_t; + +typedef union packet_res { + uint8_t bytes[128]; + struct { + uint8_t frame_len; + uint8_t addr; + uint8_t seq_no; + uint8_t cmd; + uint8_t status; + uint8_t payload_len; + union { + char version[1]; //sg_nfc_res_get_fw_version,sg_nfc_res_get_hw_version,sg_led_res_get_info + uint8_t block[16]; //sg_nfc_res_mifare_read_block + struct { //sg_nfc_res_poll + uint8_t count; + uint8_t type; + uint8_t id_len; + union { + uint8_t mifare_uid[4]; + struct { + uint8_t IDm[8]; + uint8_t PMm[8]; + }; + }; + }; + struct { //sg_nfc_res_felica_encap + uint8_t encap_len; + uint8_t encap_code; + uint8_t encap_IDm[8]; + union { + struct { //FELICA_CMD_POLL + uint8_t poll_PMm[8]; + uint8_t poll_systemCode[2]; + }; + struct { + uint8_t RW_status[2]; //猜测,NDA_06,NDA_08 + uint8_t numBlock; //NDA_06 + uint8_t blockData[1][1][16]; //NDA_06 + }; + uint8_t felica_payload[1]; + }; + }; + }; + }; +} packet_res_t; + +static packet_req_t req; +static packet_res_t res; +static uint8_t len, r, checksum; +static bool escape = false; + +static uint8_t packet_read() { + while (SerialDevice.available()) { + r = SerialDevice.read(); + if (r == 0xE0) { + req.frame_len = 0xFF; + continue; + } + if (req.frame_len == 0xFF) { + req.frame_len = r; + len = 0; + checksum = r; + continue; + } + if (r == 0xD0) { + escape = true; + continue; + } + if (escape) { + r++; + escape = false; + } + req.bytes[++len] = r; + if (len == req.frame_len && checksum == r) { + return req.cmd; + } + checksum += r; + } + return 0; +} + +static void packet_write() { + uint8_t checksum = 0, len = 0; + if (res.cmd == 0) { + return; + } + SerialDevice.write(0xE0); + while (len <= res.frame_len) { + uint8_t w; + if (len == res.frame_len) { + w = checksum; + } else { + w = res.bytes[len]; + checksum += w; + } + if (w == 0xE0 || w == 0xD0) { + SerialDevice.write(0xD0); + SerialDevice.write(--w); + } else { + SerialDevice.write(w); + } + len++; + } + res.cmd = 0; +} + +static void sg_res_init(uint8_t payload_len = 0) { //初始化模板 + res.frame_len = 6 + payload_len; + res.addr = req.addr; + res.seq_no = req.seq_no; + res.cmd = req.cmd; + res.status = 0; + res.payload_len = payload_len; +} + +static void sg_nfc_cmd_reset() { + if (nfc.getFirmwareVersion()) { + sg_res_init(); + res.status = 3; + u8g2.drawXBM(95, 0, 16, 16, blank); + u8g2.drawXBM(113, 0, 16, 16, blank); + u8g2.sendBuffer(); + return; + } + u8g2.drawXBM(95, 0, 16, 16, rf_off); + u8g2.sendBuffer(); + FastLED.showColor(CRGB::Red); + while (true) {}; +} + +static void sg_nfc_cmd_get_fw_version() { + if (FWSW) { + sg_res_init(sizeof(FW_TN32)); + memcpy(res.version, FW_TN32, res.payload_len); + } else { + sg_res_init(sizeof(FW_837)); + memcpy(res.version, FW_837, res.payload_len); + } +} + +static void sg_nfc_cmd_get_hw_version() { + if (FWSW) { + sg_res_init(sizeof(HW_TN32)); + memcpy(res.version, HW_TN32, res.payload_len); + } else { + sg_res_init(sizeof(HW_837)); + memcpy(res.version, HW_837, res.payload_len); + } +} + +static void sg_led_cmd_get_info() { + if (FWSW) { + sg_res_init(sizeof(BOARD_TN32)); + memcpy(res.version, BOARD_TN32, res.payload_len); + } else { + sg_res_init(sizeof(BOARD_837)); + memcpy(res.version, BOARD_837, res.payload_len); + } +} + +static void sg_nfc_cmd_mifare_set_key_aime() { + sg_res_init(); + memcpy(AimeKey, req.key, 6); +} + +static void sg_nfc_cmd_mifare_set_key_bana() { + sg_res_init(); + memcpy(BanaKey, req.key, 6); +} + +static void sg_led_cmd_reset() { + sg_res_init(); +} + +static void sg_led_cmd_set_color() { + FastLED.showColor(CRGB(req.color_payload[0], req.color_payload[1], req.color_payload[2])); +} + +static void sg_nfc_cmd_radio_on() { + sg_res_init(); + nfc.setRFField(0x00, 0x01); + u8g2.drawXBM(95, 0, 16, 16, rf_open); + u8g2.sendBuffer(); +} + +static void sg_nfc_cmd_radio_off() { + sg_res_init(); + nfc.setRFField(0x00, 0x00); + u8g2.drawXBM(95, 0, 16, 16, blank); + u8g2.sendBuffer(); +} + +static void sg_nfc_cmd_poll() { //卡号发送 + uint16_t SystemCode; + if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, res.mifare_uid, &res.id_len)) { + sg_res_init(0x07); + res.count = 1; + res.type = 0x10; + } else if (nfc.felica_Polling(0xFFFF, 0x00, res.IDm, res.PMm, &SystemCode, 200) == 1) { //< 0: error + sg_res_init(0x13); + res.count = 1; + res.type = 0x20; + res.id_len = 0x10; + } else { + sg_res_init(1); + res.count = 0; + u8g2.drawXBM(113, 0, 16, 16, blank); + u8g2.sendBuffer(); + return; + } + u8g2.drawXBM(113, 0, 16, 16, card); + u8g2.sendBuffer(); +} + +static void sg_nfc_cmd_aime_authenticate() { + sg_res_init(); + if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 1, AimeKey)) { + return; + } else { + res.status = 1; + } +} + +static void sg_nfc_cmd_bana_authenticate() { + sg_res_init(); + if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 0, BanaKey)) { + return; + } else { + res.status = 1; + } +} + +static void sg_nfc_cmd_mifare_read_block() { //读取卡扇区数据 + if (nfc.mifareclassic_ReadDataBlock(req.block_no, res.block)) { + sg_res_init(0x10); + return; + } + sg_res_init(); + res.status = 1; +} + +static void sg_nfc_cmd_felica_encap() { + uint16_t SystemCode; + if (nfc.felica_Polling(0xFFFF, 0x01, res.encap_IDm, res.poll_PMm, &SystemCode, 200) == 1) { + SystemCode = SystemCode >> 8 | SystemCode << 8; //SystemCode,大小端反转注意 + } else { + sg_res_init(); + res.status = 1; + return; + } + uint8_t code = req.encap_code; + res.encap_code = code + 1; + switch (code) { + case FELICA_CMD_POLL: + { + sg_res_init(0x14); + res.poll_systemCode[0] = SystemCode; + res.poll_systemCode[1] = SystemCode >> 8; + } + break; + case FELICA_CMD_GET_SYSTEM_CODE: + { + sg_res_init(0x0D); + res.felica_payload[0] = 0x01; //未知 + res.felica_payload[1] = SystemCode; //SystemCode + res.felica_payload[2] = SystemCode >> 8; + } + break; + case FELICA_CMD_NDA_A4: + { + sg_res_init(0x0B); + res.felica_payload[0] = 0x00; + } + break; + case FELICA_CMD_NDA_06: + { + uint16_t serviceCodeList[1] = { (uint16_t)(req.serviceCodeList[1] << 8 | req.serviceCodeList[0]) }; //大小端反转注意 + for (uint8_t i = 0; i < req.numBlock; i++) { + uint16_t blockList[1] = { (uint16_t)(req.blockList[i][0] << 8 | req.blockList[i][1]) }; + if (nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 1, blockList, res.blockData[i]) != 1) { + memset(res.blockData[i], 0, 16); //dummy data + } + } + res.RW_status[0] = 0; + res.RW_status[1] = 0; + res.numBlock = req.numBlock; + sg_res_init(0x0D + req.numBlock * 16); + } + break; + case FELICA_CMD_NDA_08: + { + sg_res_init(0x0C); //此处应有写入卡,但是不打算实现 + res.RW_status[0] = 0; + res.RW_status[1] = 0; + } + break; + default: + sg_res_init(); + res.status = 1; + } + res.encap_len = res.payload_len; +}