diff --git a/Aime-Reader.h b/Aime-Reader.h new file mode 100644 index 0000000..4327405 --- /dev/null +++ b/Aime-Reader.h @@ -0,0 +1,380 @@ +#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; +} diff --git a/ESP32-CardReader.ino b/ESP32-CardReader.ino new file mode 100644 index 0000000..00848e0 --- /dev/null +++ b/ESP32-CardReader.ino @@ -0,0 +1,221 @@ +#if defined(ARDUINO_NodeMCU_32S) +#pragma message "当前的开发板是 NodeMCU_32S" +#define SerialDevice Serial +#define LED_PIN 13 +#define PN532_SPI_SS 5 + +#define SW1 33 +#define SW2 25 +#define SW3 26 +#define SW4 27 + +#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 + +#else +#error "开发板选错了!!!" +#endif + +#include "Aime-Reader.h" + +void setup() { + pinMode(SW1, INPUT_PULLUP); + pinMode(SW2, INPUT_PULLUP); + pinMode(SW3, INPUT_PULLUP); + pinMode(SW4, INPUT_PULLUP); + + 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)) { + FastLED.setBrightness(20); + } + FastLED.showColor(0); + + if (!digitalRead(SW4)) { + WiFi.begin(STASSID, STAPASS); + u8g2.drawStr(0, 28, "WiFi Connecting..."); + u8g2.sendBuffer(); + while (WiFi.status() != WL_CONNECTED); + u8g2.drawStr(0, 28, "WiFi connected. "); + u8g2.drawStr(0, 41, "Check update... "); + u8g2.sendBuffer(); + WiFiClient client; + httpUpdate.setLedPin(LED_BUILTIN, LOW); + t_httpUpdate_return ret = httpUpdate.update(client, OTA_URL); + switch (ret) { + case HTTP_UPDATE_FAILED: + u8g2.drawStr(0, 41, "Check failed. "); + break; + + case HTTP_UPDATE_NO_UPDATES: + u8g2.drawStr(0, 41, "Already up to date. "); + break; + } + u8g2.sendBuffer(); + } + + nfc.begin(); + while (!nfc.getFirmwareVersion()) { + u8g2.drawXBM(20, 0, 16, 16, rf_off); + u8g2.sendBuffer(); + FastLED.showColor(0xFF0000); + delay(500); + FastLED.showColor(0); + delay(500); + } + nfc.setPassiveActivationRetries(0x10);//设定等待次数 + nfc.SAMConfig(); + + 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; + } +} + +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; +} + +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; +} + +void SerialCheck() { + switch (packet_read()) { + case SG_NFC_CMD_RESET: + sg_nfc_cmd_reset(); + break; + case SG_NFC_CMD_GET_FW_VERSION: + sg_nfc_cmd_get_fw_version(); + break; + case SG_NFC_CMD_GET_HW_VERSION: + sg_nfc_cmd_get_hw_version(); + break; + case SG_NFC_CMD_POLL: + sg_nfc_cmd_poll(); + break; + case SG_NFC_CMD_MIFARE_READ_BLOCK: + sg_nfc_cmd_mifare_read_block(); + break; + case SG_NFC_CMD_FELICA_ENCAP: + sg_nfc_cmd_felica_encap(); + break; + case SG_NFC_CMD_AIME_AUTHENTICATE: + sg_nfc_cmd_aime_authenticate(); + break; + case SG_NFC_CMD_BANA_AUTHENTICATE: + sg_nfc_cmd_bana_authenticate(); + break; + case SG_NFC_CMD_MIFARE_SELECT_TAG: + sg_nfc_cmd_mifare_select_tag(); + break; + case SG_NFC_CMD_MIFARE_SET_KEY_AIME: + sg_nfc_cmd_mifare_set_key_aime(); + break; + case SG_NFC_CMD_MIFARE_SET_KEY_BANA: + sg_nfc_cmd_mifare_set_key_bana(); + break; + case SG_NFC_CMD_RADIO_ON: + sg_nfc_cmd_radio_on(); + break; + case SG_NFC_CMD_RADIO_OFF: + sg_nfc_cmd_radio_off(); + break; + case SG_RGB_CMD_RESET: + sg_led_cmd_reset(); + break; + case SG_RGB_CMD_GET_INFO: + sg_led_cmd_get_info(); + break; + case SG_RGB_CMD_SET_COLOR: + sg_led_cmd_set_color(); + break; + case 0: + break; + default: + sg_res_init(); + } +}