更新说明文件,更新引用链接。
This commit is contained in:
parent
7ab9ac6f3c
commit
7622d91901
@ -1,407 +1,407 @@
|
||||
#if defined(__AVR_ATmega32U4__) || defined(ARDUINO_SAMD_ZERO)
|
||||
#pragma message "当前的开发板是 ATmega32U4 或 SAMD_ZERO"
|
||||
#define SerialDevice SerialUSB
|
||||
#define LED_PIN A3
|
||||
#define PN532_SPI_SS 10
|
||||
|
||||
#elif defined(ESP8266)
|
||||
#pragma message "当前的开发板是 ESP8266"
|
||||
#define SerialDevice Serial
|
||||
#define LED_PIN D5
|
||||
|
||||
#elif defined(ESP32)
|
||||
#pragma message "当前的开发板是 ESP32"
|
||||
#define SerialDevice Serial
|
||||
#define LED_PIN 13
|
||||
#define PN532_SPI_SS 5
|
||||
|
||||
#else
|
||||
#error "未经测试的开发板,请检查串口和针脚定义"
|
||||
#endif
|
||||
|
||||
#ifdef high_baudrate
|
||||
#pragma message "high_baudrate 已启用"
|
||||
#define baudrate 115200
|
||||
#define BootColor 0x0000FF
|
||||
#define fw_version "\x94"
|
||||
#define hw_version "837-15396"
|
||||
#define led_info "000-00000\xFF\x11\x40"
|
||||
|
||||
#else
|
||||
#define baudrate 38400
|
||||
#define BootColor 0x00FF00
|
||||
#define fw_version "TN32MSEC003S F/W Ver1.2"
|
||||
#define hw_version "TN32MSEC003S H/W Ver3.0"
|
||||
#define led_info "15084\xFF\x10\x00\x12"
|
||||
#endif
|
||||
|
||||
#include "FastLED.h"
|
||||
#define NUM_LEDS 8
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
#if defined(PN532_SPI_SS)
|
||||
#pragma message "使用 SPI 连接 PN532"
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
PN532_SPI pn532(SPI, PN532_SPI_SS);
|
||||
#else
|
||||
#pragma message "使用 I2C 连接 PN532"
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
PN532_I2C pn532(Wire);
|
||||
#endif
|
||||
|
||||
#include "PN532.h"
|
||||
PN532 nfc(pn532);
|
||||
uint8_t KeyA[6], KeyB[6];
|
||||
|
||||
enum {
|
||||
CMD_GET_FW_VERSION = 0x30,
|
||||
CMD_GET_HW_VERSION = 0x32,
|
||||
|
||||
// Card read
|
||||
CMD_START_POLLING = 0x40,
|
||||
CMD_STOP_POLLING = 0x41,
|
||||
CMD_CARD_DETECT = 0x42,
|
||||
CMD_CARD_SELECT = 0x43,
|
||||
CMD_CARD_HALT = 0x44,
|
||||
|
||||
// MIFARE
|
||||
CMD_MIFARE_KEY_SET_A = 0x50,
|
||||
CMD_MIFARE_AUTHORIZE_A = 0x51,
|
||||
CMD_MIFARE_READ = 0x52,
|
||||
CMD_MIFARE_WRITE = 0x53,
|
||||
CMD_MIFARE_KEY_SET_B = 0x54,
|
||||
CMD_MIFARE_AUTHORIZE_B = 0x55,
|
||||
|
||||
// Boot,update
|
||||
CMD_TO_UPDATER_MODE = 0x60,
|
||||
CMD_SEND_HEX_DATA = 0x61,
|
||||
CMD_TO_NORMAL_MODE = 0x62,
|
||||
CMD_SEND_BINDATA_INIT = 0x63,
|
||||
CMD_SEND_BINDATA_EXEC = 0x64,
|
||||
|
||||
// FeliCa
|
||||
CMD_FELICA_PUSH = 0x70,
|
||||
CMD_FELICA_THROUGH = 0x71,
|
||||
|
||||
CMD_FELICA_THROUGH_POLL = 0x00,
|
||||
CMD_FELICA_THROUGH_READ = 0x06,
|
||||
CMD_FELICA_THROUGH_WRITE = 0x08,
|
||||
CMD_FELICA_THROUGH_GET_SYSTEM_CODE = 0x0C,
|
||||
CMD_FELICA_THROUGH_NDA_A4 = 0xA4,
|
||||
|
||||
// LED board
|
||||
CMD_EXT_BOARD_LED = 0x80,
|
||||
CMD_EXT_BOARD_LED_RGB = 0x81,
|
||||
CMD_EXT_BOARD_LED_RGB_UNKNOWN = 0x82, // 未知
|
||||
CMD_EXT_BOARD_INFO = 0xf0,
|
||||
CMD_EXT_FIRM_SUM = 0xf2,
|
||||
CMD_EXT_SEND_HEX_DATA = 0xf3,
|
||||
CMD_EXT_TO_BOOT_MODE = 0xf4,
|
||||
CMD_EXT_TO_NORMAL_MODE = 0xf5,
|
||||
};
|
||||
|
||||
enum { // 未确认效果
|
||||
ERROR_NONE = 0,
|
||||
ERROR_NFCRW_INIT_ERROR = 1,
|
||||
ERROR_NFCRW_FIRMWARE_UP_TO_DATE = 3,
|
||||
ERROR_NFCRW_ACCESS_ERROR = 4,
|
||||
ERROR_CARD_DETECT_TIMEOUT = 5,
|
||||
ERROR_CARD_DETECT_ERROR = 32,
|
||||
ERROR_FELICA_ERROR = 33,
|
||||
};
|
||||
|
||||
typedef union {
|
||||
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]; // CMD_MIFARE_KEY_SET
|
||||
uint8_t color_payload[3]; // CMD_EXT_BOARD_LED_RGB
|
||||
struct { // CMD_CARD_SELECT,AUTHORIZE,READ
|
||||
uint8_t uid[4];
|
||||
uint8_t block_no;
|
||||
};
|
||||
struct { // CMD_FELICA_THROUGH
|
||||
uint8_t encap_IDm[8];
|
||||
uint8_t encap_len;
|
||||
uint8_t encap_code;
|
||||
union {
|
||||
struct { // CMD_FELICA_THROUGH_POLL
|
||||
uint8_t poll_systemCode[2];
|
||||
uint8_t poll_requestCode;
|
||||
uint8_t poll_timeout;
|
||||
};
|
||||
struct { // CMD_FELICA_THROUGH_READ,WRITE,NDA_A4
|
||||
uint8_t RW_IDm[8];
|
||||
uint8_t numService;
|
||||
uint8_t serviceCodeList[2];
|
||||
uint8_t numBlock;
|
||||
uint8_t blockList[1][2]; // CMD_FELICA_THROUGH_READ
|
||||
uint8_t blockData[16]; // CMD_FELICA_THROUGH_WRITE
|
||||
};
|
||||
uint8_t felica_payload[1];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} packet_request_t;
|
||||
|
||||
typedef union {
|
||||
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 {
|
||||
uint8_t version[1]; // CMD_GET_FW_VERSION,CMD_GET_HW_VERSION,CMD_EXT_BOARD_INFO
|
||||
uint8_t block[16]; // CMD_MIFARE_READ
|
||||
struct { // CMD_CARD_DETECT
|
||||
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 { // CMD_FELICA_THROUGH
|
||||
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];
|
||||
uint8_t numBlock;
|
||||
uint8_t blockData[1][1][16];
|
||||
};
|
||||
uint8_t felica_payload[1];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} packet_response_t;
|
||||
|
||||
packet_request_t req;
|
||||
packet_response_t res;
|
||||
|
||||
uint8_t len, r, checksum;
|
||||
bool escape = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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 = ERROR_NONE;
|
||||
res.payload_len = payload_len;
|
||||
}
|
||||
|
||||
void sys_to_normal_mode() {
|
||||
res_init();
|
||||
if (nfc.getFirmwareVersion()) {
|
||||
res.status = ERROR_NFCRW_FIRMWARE_UP_TO_DATE;
|
||||
} else {
|
||||
res.status = ERROR_NFCRW_INIT_ERROR;
|
||||
FastLED.showColor(0xFF0000);
|
||||
}
|
||||
}
|
||||
|
||||
void sys_get_fw_version() {
|
||||
res_init(sizeof(fw_version) - 1);
|
||||
memcpy(res.version, fw_version, res.payload_len);
|
||||
}
|
||||
|
||||
void sys_get_hw_version() {
|
||||
res_init(sizeof(hw_version) - 1);
|
||||
memcpy(res.version, hw_version, res.payload_len);
|
||||
}
|
||||
|
||||
void sys_get_led_info() {
|
||||
res_init(sizeof(led_info) - 1);
|
||||
memcpy(res.version, led_info, res.payload_len);
|
||||
}
|
||||
|
||||
|
||||
void nfc_start_polling() {
|
||||
res_init();
|
||||
nfc.setRFField(0x00, 0x01);
|
||||
}
|
||||
|
||||
void nfc_stop_polling() {
|
||||
res_init();
|
||||
nfc.setRFField(0x00, 0x00);
|
||||
}
|
||||
|
||||
void nfc_card_detect() {
|
||||
uint16_t SystemCode;
|
||||
uint8_t bufferLength;
|
||||
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, res.mifare_uid, &res.id_len) && nfc.getBuffer(&bufferLength)[4] == 0x08) { // Only read cards with sak=0x08
|
||||
res_init(0x07);
|
||||
res.count = 1;
|
||||
res.type = 0x10;
|
||||
} else if (nfc.felica_Polling(0xFFFF, 0x00, res.IDm, res.PMm, &SystemCode, 200) == 1) {
|
||||
res_init(0x13);
|
||||
res.count = 1;
|
||||
res.type = 0x20;
|
||||
res.id_len = 0x10;
|
||||
} else {
|
||||
res_init(1);
|
||||
res.count = 0;
|
||||
res.status = ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_mifare_authorize_a() {
|
||||
res_init();
|
||||
if (!nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 0, KeyA)) {
|
||||
res.status = ERROR_NFCRW_ACCESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_mifare_authorize_b() {
|
||||
res_init();
|
||||
if (!nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 1, KeyB)) {
|
||||
res.status = ERROR_NFCRW_ACCESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_mifare_read() {
|
||||
res_init(0x10);
|
||||
if (!nfc.mifareclassic_ReadDataBlock(req.block_no, res.block)) {
|
||||
res_init();
|
||||
res.status = ERROR_CARD_DETECT_TIMEOUT; // TODO
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_felica_through() {
|
||||
uint16_t SystemCode;
|
||||
if (nfc.felica_Polling(0xFFFF, 0x01, res.encap_IDm, res.poll_PMm, &SystemCode, 200) == 1) {
|
||||
SystemCode = SystemCode >> 8 | SystemCode << 8;
|
||||
} else {
|
||||
res_init();
|
||||
res.status = ERROR_FELICA_ERROR;
|
||||
return;
|
||||
}
|
||||
uint8_t code = req.encap_code;
|
||||
res.encap_code = code + 1;
|
||||
switch (code) {
|
||||
case CMD_FELICA_THROUGH_POLL:
|
||||
{
|
||||
res_init(0x14);
|
||||
res.poll_systemCode[0] = SystemCode;
|
||||
res.poll_systemCode[1] = SystemCode >> 8;
|
||||
}
|
||||
break;
|
||||
case CMD_FELICA_THROUGH_GET_SYSTEM_CODE:
|
||||
{
|
||||
res_init(0x0D);
|
||||
res.felica_payload[0] = 0x01;
|
||||
res.felica_payload[1] = SystemCode;
|
||||
res.felica_payload[2] = SystemCode >> 8;
|
||||
}
|
||||
break;
|
||||
case CMD_FELICA_THROUGH_NDA_A4:
|
||||
{
|
||||
res_init(0x0B);
|
||||
res.felica_payload[0] = 0x00;
|
||||
}
|
||||
break;
|
||||
case CMD_FELICA_THROUGH_READ:
|
||||
{
|
||||
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;
|
||||
res_init(0x0D + req.numBlock * 16);
|
||||
}
|
||||
break;
|
||||
case CMD_FELICA_THROUGH_WRITE:
|
||||
{
|
||||
res_init(0x0C); // WriteWithoutEncryption,ignore
|
||||
res.RW_status[0] = 0;
|
||||
res.RW_status[1] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res_init();
|
||||
res.status = ERROR_FELICA_ERROR;
|
||||
}
|
||||
res.encap_len = res.payload_len;
|
||||
}
|
||||
#if defined(__AVR_ATmega32U4__) || defined(ARDUINO_SAMD_ZERO)
|
||||
#pragma message "当前的开发板是 ATmega32U4 或 SAMD_ZERO"
|
||||
#define SerialDevice SerialUSB
|
||||
#define LED_PIN A3
|
||||
#define PN532_SPI_SS 10
|
||||
|
||||
#elif defined(ESP8266)
|
||||
#pragma message "当前的开发板是 ESP8266"
|
||||
#define SerialDevice Serial
|
||||
#define LED_PIN D5
|
||||
|
||||
#elif defined(ESP32)
|
||||
#pragma message "当前的开发板是 ESP32"
|
||||
#define SerialDevice Serial
|
||||
#define LED_PIN 13
|
||||
#define PN532_SPI_SS 5
|
||||
|
||||
#else
|
||||
#error "未经测试的开发板,请检查串口和针脚定义"
|
||||
#endif
|
||||
|
||||
#ifdef high_baudrate
|
||||
#pragma message "high_baudrate 已启用"
|
||||
#define baudrate 115200
|
||||
#define BootColor 0x0000FF
|
||||
#define fw_version "\x94"
|
||||
#define hw_version "837-15396"
|
||||
#define led_info "000-00000\xFF\x11\x40"
|
||||
|
||||
#else
|
||||
#define baudrate 38400
|
||||
#define BootColor 0x00FF00
|
||||
#define fw_version "TN32MSEC003S F/W Ver1.2"
|
||||
#define hw_version "TN32MSEC003S H/W Ver3.0"
|
||||
#define led_info "15084\xFF\x10\x00\x12"
|
||||
#endif
|
||||
|
||||
#include "FastLED.h"
|
||||
#define NUM_LEDS 8
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
#if defined(PN532_SPI_SS)
|
||||
#pragma message "使用 SPI 连接 PN532"
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
PN532_SPI pn532(SPI, PN532_SPI_SS);
|
||||
#else
|
||||
#pragma message "使用 I2C 连接 PN532"
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
PN532_I2C pn532(Wire);
|
||||
#endif
|
||||
|
||||
#include "PN532.h"
|
||||
PN532 nfc(pn532);
|
||||
uint8_t KeyA[6], KeyB[6];
|
||||
|
||||
enum {
|
||||
CMD_GET_FW_VERSION = 0x30,
|
||||
CMD_GET_HW_VERSION = 0x32,
|
||||
|
||||
// Card read
|
||||
CMD_START_POLLING = 0x40,
|
||||
CMD_STOP_POLLING = 0x41,
|
||||
CMD_CARD_DETECT = 0x42,
|
||||
CMD_CARD_SELECT = 0x43,
|
||||
CMD_CARD_HALT = 0x44,
|
||||
|
||||
// MIFARE
|
||||
CMD_MIFARE_KEY_SET_A = 0x50,
|
||||
CMD_MIFARE_AUTHORIZE_A = 0x51,
|
||||
CMD_MIFARE_READ = 0x52,
|
||||
CMD_MIFARE_WRITE = 0x53,
|
||||
CMD_MIFARE_KEY_SET_B = 0x54,
|
||||
CMD_MIFARE_AUTHORIZE_B = 0x55,
|
||||
|
||||
// Boot,update
|
||||
CMD_TO_UPDATER_MODE = 0x60,
|
||||
CMD_SEND_HEX_DATA = 0x61,
|
||||
CMD_TO_NORMAL_MODE = 0x62,
|
||||
CMD_SEND_BINDATA_INIT = 0x63,
|
||||
CMD_SEND_BINDATA_EXEC = 0x64,
|
||||
|
||||
// FeliCa
|
||||
CMD_FELICA_PUSH = 0x70,
|
||||
CMD_FELICA_THROUGH = 0x71,
|
||||
|
||||
CMD_FELICA_THROUGH_POLL = 0x00,
|
||||
CMD_FELICA_THROUGH_READ = 0x06,
|
||||
CMD_FELICA_THROUGH_WRITE = 0x08,
|
||||
CMD_FELICA_THROUGH_GET_SYSTEM_CODE = 0x0C,
|
||||
CMD_FELICA_THROUGH_NDA_A4 = 0xA4,
|
||||
|
||||
// LED board
|
||||
CMD_EXT_BOARD_LED = 0x80,
|
||||
CMD_EXT_BOARD_LED_RGB = 0x81,
|
||||
CMD_EXT_BOARD_LED_RGB_UNKNOWN = 0x82, // 未知
|
||||
CMD_EXT_BOARD_INFO = 0xf0,
|
||||
CMD_EXT_FIRM_SUM = 0xf2,
|
||||
CMD_EXT_SEND_HEX_DATA = 0xf3,
|
||||
CMD_EXT_TO_BOOT_MODE = 0xf4,
|
||||
CMD_EXT_TO_NORMAL_MODE = 0xf5,
|
||||
};
|
||||
|
||||
enum { // 未确认效果
|
||||
ERROR_NONE = 0,
|
||||
ERROR_NFCRW_INIT_ERROR = 1,
|
||||
ERROR_NFCRW_FIRMWARE_UP_TO_DATE = 3,
|
||||
ERROR_NFCRW_ACCESS_ERROR = 4,
|
||||
ERROR_CARD_DETECT_TIMEOUT = 5,
|
||||
ERROR_CARD_DETECT_ERROR = 32,
|
||||
ERROR_FELICA_ERROR = 33,
|
||||
};
|
||||
|
||||
typedef union {
|
||||
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]; // CMD_MIFARE_KEY_SET
|
||||
uint8_t color_payload[3]; // CMD_EXT_BOARD_LED_RGB
|
||||
struct { // CMD_CARD_SELECT,AUTHORIZE,READ
|
||||
uint8_t uid[4];
|
||||
uint8_t block_no;
|
||||
};
|
||||
struct { // CMD_FELICA_THROUGH
|
||||
uint8_t encap_IDm[8];
|
||||
uint8_t encap_len;
|
||||
uint8_t encap_code;
|
||||
union {
|
||||
struct { // CMD_FELICA_THROUGH_POLL
|
||||
uint8_t poll_systemCode[2];
|
||||
uint8_t poll_requestCode;
|
||||
uint8_t poll_timeout;
|
||||
};
|
||||
struct { // CMD_FELICA_THROUGH_READ,WRITE,NDA_A4
|
||||
uint8_t RW_IDm[8];
|
||||
uint8_t numService;
|
||||
uint8_t serviceCodeList[2];
|
||||
uint8_t numBlock;
|
||||
uint8_t blockList[1][2]; // CMD_FELICA_THROUGH_READ
|
||||
uint8_t blockData[16]; // CMD_FELICA_THROUGH_WRITE
|
||||
};
|
||||
uint8_t felica_payload[1];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} packet_request_t;
|
||||
|
||||
typedef union {
|
||||
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 {
|
||||
uint8_t version[1]; // CMD_GET_FW_VERSION,CMD_GET_HW_VERSION,CMD_EXT_BOARD_INFO
|
||||
uint8_t block[16]; // CMD_MIFARE_READ
|
||||
struct { // CMD_CARD_DETECT
|
||||
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 { // CMD_FELICA_THROUGH
|
||||
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];
|
||||
uint8_t numBlock;
|
||||
uint8_t blockData[1][1][16];
|
||||
};
|
||||
uint8_t felica_payload[1];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} packet_response_t;
|
||||
|
||||
packet_request_t req;
|
||||
packet_response_t res;
|
||||
|
||||
uint8_t len, r, checksum;
|
||||
bool escape = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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 = ERROR_NONE;
|
||||
res.payload_len = payload_len;
|
||||
}
|
||||
|
||||
void sys_to_normal_mode() {
|
||||
res_init();
|
||||
if (nfc.getFirmwareVersion()) {
|
||||
res.status = ERROR_NFCRW_FIRMWARE_UP_TO_DATE;
|
||||
} else {
|
||||
res.status = ERROR_NFCRW_INIT_ERROR;
|
||||
FastLED.showColor(0xFF0000);
|
||||
}
|
||||
}
|
||||
|
||||
void sys_get_fw_version() {
|
||||
res_init(sizeof(fw_version) - 1);
|
||||
memcpy(res.version, fw_version, res.payload_len);
|
||||
}
|
||||
|
||||
void sys_get_hw_version() {
|
||||
res_init(sizeof(hw_version) - 1);
|
||||
memcpy(res.version, hw_version, res.payload_len);
|
||||
}
|
||||
|
||||
void sys_get_led_info() {
|
||||
res_init(sizeof(led_info) - 1);
|
||||
memcpy(res.version, led_info, res.payload_len);
|
||||
}
|
||||
|
||||
|
||||
void nfc_start_polling() {
|
||||
res_init();
|
||||
nfc.setRFField(0x00, 0x01);
|
||||
}
|
||||
|
||||
void nfc_stop_polling() {
|
||||
res_init();
|
||||
nfc.setRFField(0x00, 0x00);
|
||||
}
|
||||
|
||||
void nfc_card_detect() {
|
||||
uint16_t SystemCode;
|
||||
uint8_t bufferLength;
|
||||
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, res.mifare_uid, &res.id_len) && nfc.getBuffer(&bufferLength)[4] == 0x08) { // Only read cards with sak=0x08
|
||||
res_init(0x07);
|
||||
res.count = 1;
|
||||
res.type = 0x10;
|
||||
} else if (nfc.felica_Polling(0xFFFF, 0x00, res.IDm, res.PMm, &SystemCode, 200) == 1) {
|
||||
res_init(0x13);
|
||||
res.count = 1;
|
||||
res.type = 0x20;
|
||||
res.id_len = 0x10;
|
||||
} else {
|
||||
res_init(1);
|
||||
res.count = 0;
|
||||
res.status = ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_mifare_authorize_a() {
|
||||
res_init();
|
||||
if (!nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 0, KeyA)) {
|
||||
res.status = ERROR_NFCRW_ACCESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_mifare_authorize_b() {
|
||||
res_init();
|
||||
if (!nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 1, KeyB)) {
|
||||
res.status = ERROR_NFCRW_ACCESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_mifare_read() {
|
||||
res_init(0x10);
|
||||
if (!nfc.mifareclassic_ReadDataBlock(req.block_no, res.block)) {
|
||||
res_init();
|
||||
res.status = ERROR_CARD_DETECT_TIMEOUT; // TODO
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_felica_through() {
|
||||
uint16_t SystemCode;
|
||||
if (nfc.felica_Polling(0xFFFF, 0x01, res.encap_IDm, res.poll_PMm, &SystemCode, 200) == 1) {
|
||||
SystemCode = SystemCode >> 8 | SystemCode << 8;
|
||||
} else {
|
||||
res_init();
|
||||
res.status = ERROR_FELICA_ERROR;
|
||||
return;
|
||||
}
|
||||
uint8_t code = req.encap_code;
|
||||
res.encap_code = code + 1;
|
||||
switch (code) {
|
||||
case CMD_FELICA_THROUGH_POLL:
|
||||
{
|
||||
res_init(0x14);
|
||||
res.poll_systemCode[0] = SystemCode;
|
||||
res.poll_systemCode[1] = SystemCode >> 8;
|
||||
}
|
||||
break;
|
||||
case CMD_FELICA_THROUGH_GET_SYSTEM_CODE:
|
||||
{
|
||||
res_init(0x0D);
|
||||
res.felica_payload[0] = 0x01;
|
||||
res.felica_payload[1] = SystemCode;
|
||||
res.felica_payload[2] = SystemCode >> 8;
|
||||
}
|
||||
break;
|
||||
case CMD_FELICA_THROUGH_NDA_A4:
|
||||
{
|
||||
res_init(0x0B);
|
||||
res.felica_payload[0] = 0x00;
|
||||
}
|
||||
break;
|
||||
case CMD_FELICA_THROUGH_READ:
|
||||
{
|
||||
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;
|
||||
res_init(0x0D + req.numBlock * 16);
|
||||
}
|
||||
break;
|
||||
case CMD_FELICA_THROUGH_WRITE:
|
||||
{
|
||||
res_init(0x0C); // WriteWithoutEncryption,ignore
|
||||
res.RW_status[0] = 0;
|
||||
res.RW_status[1] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res_init();
|
||||
res.status = ERROR_FELICA_ERROR;
|
||||
}
|
||||
res.encap_len = res.payload_len;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#include "cmd.h"
|
||||
bool high_baudrate = true;//high_baudrate=true
|
||||
#define high_baudrate
|
||||
|
||||
#include "Aime_Redaer.h"
|
||||
|
||||
void setup() {
|
||||
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
|
||||
@ -12,132 +13,83 @@ void setup() {
|
||||
FastLED.showColor(0);
|
||||
delay(500);
|
||||
}
|
||||
nfc.setPassiveActivationRetries(0x10);//设定等待次数
|
||||
nfc.setPassiveActivationRetries(0x10);
|
||||
nfc.SAMConfig();
|
||||
memset(&req, 0, sizeof(req.bytes));
|
||||
memset(&res, 0, sizeof(res.bytes));
|
||||
memset(req.bytes, 0, sizeof(req.bytes));
|
||||
memset(res.bytes, 0, sizeof(res.bytes));
|
||||
|
||||
SerialDevice.begin(high_baudrate ? 115200 : 38400);
|
||||
FastLED.showColor(high_baudrate ? 0x0000FF : 0x00FF00);
|
||||
SerialDevice.begin(baudrate);
|
||||
FastLED.showColor(BootColor);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
SerialCheck();
|
||||
packet_write();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
case CMD_TO_NORMAL_MODE:
|
||||
sys_to_normal_mode();
|
||||
break;
|
||||
case CMD_GET_FW_VERSION:
|
||||
sys_get_fw_version();
|
||||
break;
|
||||
case CMD_GET_HW_VERSION:
|
||||
sys_get_hw_version();
|
||||
break;
|
||||
|
||||
// Card read
|
||||
case CMD_START_POLLING:
|
||||
nfc_start_polling();
|
||||
break;
|
||||
case CMD_STOP_POLLING:
|
||||
nfc_stop_polling();
|
||||
break;
|
||||
case CMD_CARD_DETECT:
|
||||
nfc_card_detect();
|
||||
break;
|
||||
|
||||
// MIFARE
|
||||
case CMD_MIFARE_KEY_SET_A:
|
||||
memcpy(KeyA, req.key, 6);
|
||||
res_init();
|
||||
break;
|
||||
|
||||
case CMD_MIFARE_KEY_SET_B:
|
||||
res_init();
|
||||
memcpy(KeyB, req.key, 6);
|
||||
break;
|
||||
|
||||
case CMD_MIFARE_AUTHORIZE_A:
|
||||
nfc_mifare_authorize_a();
|
||||
break;
|
||||
|
||||
case CMD_MIFARE_AUTHORIZE_B:
|
||||
nfc_mifare_authorize_b();
|
||||
break;
|
||||
|
||||
case CMD_MIFARE_READ:
|
||||
nfc_mifare_read();
|
||||
break;
|
||||
|
||||
// FeliCa
|
||||
case CMD_FELICA_THROUGH:
|
||||
nfc_felica_through();
|
||||
break;
|
||||
|
||||
// LED
|
||||
case CMD_EXT_BOARD_LED_RGB:
|
||||
FastLED.showColor(CRGB(req.color_payload[0], req.color_payload[1], req.color_payload[2]));
|
||||
break;
|
||||
|
||||
case CMD_EXT_BOARD_INFO:
|
||||
sys_get_led_info();
|
||||
break;
|
||||
|
||||
case CMD_EXT_BOARD_LED_RGB_UNKNOWN:
|
||||
break;
|
||||
|
||||
default:
|
||||
sg_res_init();
|
||||
res_init();
|
||||
}
|
||||
packet_write();
|
||||
}
|
||||
|
48
README.md
48
README.md
@ -1,30 +1,30 @@
|
||||
# Arduino-Aime-Reader
|
||||
使用 Arduino + PN532 + WS2812B 制作的 Aime 兼容读卡器。
|
||||
**目前所有主要功能已经实现,如果没有 bug 应该不会再更新。**
|
||||
使用 Arduino + PN532 制作的 Aime 兼容读卡器。
|
||||
**当前更新内容未经过长时间测试,如果遇到问题可以回滚到[稳定的 v1.0 版本](https://github.com/Sucareto/Arduino-Aime-Reader/tree/v1.0)**
|
||||
English: [lawliuwuu/Arduino-Aime-Reader](https://github.com/lawliuwuu/Arduino-Aime-Reader)
|
||||
|
||||
支持卡片类型: [FeliCa](https://zh.wikipedia.org/wiki/FeliCa)(Amusement IC、Suica、八达通等)和 [MIFARE](https://zh.wikipedia.org/wiki/MIFARE)(Aime,Banapassport)。
|
||||
实现逻辑为官方读卡器串口数据对比 + 脑补,不保证正确实现。
|
||||
通信数据格式参考了 [Segatools]() 和官方读卡器抓包数据,可在 [Example.txt](doc/Example.txt) 和 [nfc.txt](doc/nfc.txt) 查看。
|
||||
一个使用例:[ESP32-CardReader](https://github.com/Sucareto/ESP32-CardReader)
|
||||
- 支持卡片类型: [FeliCa](https://zh.wikipedia.org/wiki/FeliCa)(Amusement IC、Suica、八达通等)和 [MIFARE](https://zh.wikipedia.org/wiki/MIFARE)(Aime,Banapassport)
|
||||
- 逻辑实现是通过对官方读卡器串口数据进行分析猜测出来的,并非逆向,不保证正确实现
|
||||
- 通信数据格式参考了 [Segatools](https://github.com/djhackersdev/segatools) 和官方读卡器抓包数据,可在 [Example.txt](doc/Example.txt) 和 [nfc.txt](https://github.com/djhackersdev/segatools/blob/master/doc/nfc.txt) 查看
|
||||
- 定制使用例(主要的开发测试环境):[ESP32-CardReader](https://github.com/Sucareto/ESP32-CardReader)
|
||||
|
||||
|
||||
### 使用方法:
|
||||
1. 按照 [PN532](https://github.com/elechouse/PN532) 的提示安装库
|
||||
2. 按照使用方式,在 Arduino 和 PN532 接好连接线(I2C或SPI),并调整 PN532 上的拨码开关
|
||||
3. 接上 WS2812B 灯条(可选)
|
||||
2. 按照使用方式,在 Arduino 和 PN532 接好连接线(I2C 或 SPI),并调整 PN532 上的拨码开关
|
||||
3. 接上 WS2812B 灯条(可选,不会影响正常读卡功能)
|
||||
4. 上传 [ReaderTest](tools/ReaderTest/ReaderTest.ino) 测试硬件是否工作正常
|
||||
5. 若读卡正常,可按照支持列表打开设备管理器设置 COM 端口号
|
||||
6. 按照游戏的波特率设置代码的`high_baudrate`选项,`115200`是`true`,`38400`是`false`
|
||||
7. 上传程序打开游戏测试
|
||||
8. 安装 [MifareClassicTool](https://github.com/ikarus23/MifareClassicTool),修改 [Aime 卡示例](doc/aime示例.mct) 后写入空白 MIFARE UID/CUID 卡
|
||||
7. 如果有使用 [Segatools](https://github.com/djhackersdev/segatools),参考 [segatools.ini 设置教程](https://github.com/djhackersdev/segatools/blob/master/doc/config/common.md#enable) 关闭 Aime 模拟读卡器
|
||||
8. 上传程序打开游戏测试
|
||||
|
||||
如果需要自定义 Aime 卡,安装 [MifareClassicTool](https://github.com/ikarus23/MifareClassicTool),修改 [Aime 卡示例](doc/aime示例.mct) 后写入空白 MIFARE UID/CUID 卡,即可刷卡使用。
|
||||
某些 Arduino 可能需要在游戏主程序连接前给串口以正确的波特率发送 DTR/RTS,需要先打开一次 Arduino 串口监视器再启动主程序。
|
||||
如果是 SDBT,可以在启动前运行一次 [DTR-RTS.exe](tools/DTR-RTS.exe) 以向 COM1 和 COM12 发送DTR/RTS。
|
||||
如果需要向其他端口和特定的波特率发送,可以修改 [DTR-RTS.c](tools/DTR-RTS.c) 然后编译。
|
||||
|
||||
|
||||
### 支持列表:
|
||||
| 游戏代号 | COM端口号 | 支持的卡 | 默认波特率 |
|
||||
### 支持游戏列表:
|
||||
| 代号 | 默认 COM 号 | 支持的卡 | 默认波特率 |
|
||||
| - | - | - | - |
|
||||
| SDDT/SDEZ | COM1 | FeliCa,MIFARE | 115200 |
|
||||
| SDEY | COM2 | MIFARE | 38400 |
|
||||
@ -35,23 +35,27 @@ English: [lawliuwuu/Arduino-Aime-Reader](https://github.com/lawliuwuu/Arduino-Ai
|
||||
- 如果读卡器没有正常工作,可以切换波特率试下
|
||||
- 有使用 amdaemon 的,可以参考 config_common.json 内 aime > unit > port 确认端口号
|
||||
- 如果 `"high_baudrate" : true` 则波特率是`115200`,否则就是`38400`
|
||||
- 在 `"high_baudrate" : true` 的情况下,本读卡器程序支持 emoney 功能,端末认证和刷卡支付均正常(需要游戏和服务器支持)
|
||||
|
||||
|
||||
### 已测试开发板:
|
||||
- SparkFun Pro Micro(ATmega32U4),需要发送 DTR/RTS
|
||||
- SparkFun SAMD21 Dev Breakout(ATSAMD21G18)
|
||||
- NodeMCU 1.0(ESP-12E + CP2102 & CH340),SDA=D2,SCL=D1
|
||||
- NodeMCU-32S(ESP32-S + CH340)
|
||||
### 开发板适配情况:
|
||||
| 开发板名 | 主控 | 备注 |
|
||||
| - | - | - |
|
||||
| SparkFun Pro Micro | ATmega32U4 | 需要发送 DTR/RTS,未完全测试 |
|
||||
| SparkFun SAMD21 Dev Breakout | ATSAMD21G18 | 未完全测试 |
|
||||
| NodeMCU 1.0 | ESP-12E + CP2102 & CH340 | SDA=D2,SCL=D1 |
|
||||
| NodeMCU-32S | ESP32-S + CH340 | 主要适配环境 |
|
||||
| Arduino Uno | ATmega328P + CH340 | 未实际测试,据反馈不可用 |
|
||||
|
||||
|
||||
### 已知问题:
|
||||
- 在 NDA_08 命令的写入 Felica 操作没有实现,因为未确认是否会影响卡片后续使用
|
||||
- 未确定`res.status`的意义,因此`res.status = 1;`可能是错误的
|
||||
- 未实现`mifare_select_tag`,未支持多卡选择,只会读到最先识别的卡片
|
||||
- 未确定`res.status`错误码的定义,因此`res.status`的值可能是错误的
|
||||
- 因为 PN532 库不支持同时读取多张卡片,所以未实现`mifare_select_tag`,只会读到最先识别的卡片
|
||||
|
||||
|
||||
### 引用库:
|
||||
- 驱动 WS2812B:[FastLED](https://github.com/FastLED/FastLED)
|
||||
- 驱动 PN532:[PN532](https://github.com/elechouse/PN532)
|
||||
- 驱动 PN532:[PN532](https://github.com/elechouse/PN532) 或 [Aime_Reader_PN532](https://github.com/Sucareto/Aime_Reader_PN532)
|
||||
- 读取 FeliCa 参考:[PN532を使ってArduinoでFeliCa学生証を読む方法](https://qiita.com/gpioblink/items/91597a5275862f7ffb3c)
|
||||
- 读取 FeliCa 数据的程序:[NFC TagInfo](https://play.google.com/store/apps/details?id=at.mroland.android.apps.nfctaginfo),[NFC TagInfo by NXP](https://play.google.com/store/apps/details?id=com.nxp.taginfolite)
|
||||
|
244
doc/nfc.txt
244
doc/nfc.txt
@ -1,244 +0,0 @@
|
||||
N.B. Quoted strings are NOT NUL-terminated unless otherwise noted.
|
||||
Useful reading: https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf
|
||||
|
||||
(AiMe branded cards are Mifare Classic cards. Other technologies exist though)
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
||||
Hardware:
|
||||
Assembly connector:
|
||||
5V Host in
|
||||
Tx;Rx;GND Host RS232 in
|
||||
Tx;Rx;GND Daisy-chain out
|
||||
Main board (probably LED controller):
|
||||
Silk "837-15084"
|
||||
CN1: Host 5V power in, ?V NFC-sub power out
|
||||
CN2: Host RS232 Tx;Rx;GND in, NFC-sub Tx;Rx out
|
||||
CN3: LED-Sub power and data(?) out
|
||||
DIPSW1: Set to hex nibble 8.
|
||||
Contains ADM3222 RS232 transceiver IC
|
||||
Contains ATMega32 MCU
|
||||
NFC subboard:
|
||||
Sticker: Model "TN32MSEC003S"
|
||||
CN1: ?V power and Tx;Rx;GND in, Tx;Rx;GND ass'y CN daisy out.
|
||||
DIPSW1: Set to hex nibble 0.
|
||||
Contains ATmega168 MCU
|
||||
Contains ADM3202A RS232 transceiver IC
|
||||
Contains shielded RF circuit
|
||||
Entire non-ground-plane PCB area is visible through the chassis
|
||||
torx screws lol
|
||||
LED subboard:
|
||||
Silk: "837-15120"
|
||||
CN1: ?V power and Tx;Rx;GND in.
|
||||
Five RGB LEDs and a bunch of resistors
|
||||
No visible logic ICs..?
|
||||
No DIPSW.
|
||||
|
||||
JVS framing:
|
||||
E0 sync
|
||||
D0 escape (+1 to unescape)
|
||||
Checksum is sum of bytes after unescaping
|
||||
|
||||
Frame header:
|
||||
Frame length (including length byte itself)
|
||||
Address
|
||||
Sequence no, hopefully loops before hitting esc byte...
|
||||
Command byte
|
||||
|
||||
Bus addressing:
|
||||
Low nibble set using DIPSWs
|
||||
High nibble ???
|
||||
Daisy chaining mechanism unknown (RS232 wires probably multi-tap)
|
||||
|
||||
Startup
|
||||
-------
|
||||
|
||||
Addr 00 Command 62:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Unknown. Reset?
|
||||
|
||||
Addr 00 Command 30:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
17 Payload length
|
||||
.. "TN32MSEC003S F/W Ver1.2E"
|
||||
Description:
|
||||
Get firmware version
|
||||
|
||||
Addr 00 Command 32:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
17 Payload length
|
||||
.. "TN32MSEC003S H/W Ver3.0J"
|
||||
Description:
|
||||
Get hardware version
|
||||
|
||||
Addr 08 Command f5:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
LED sub-board reset.
|
||||
Won't accept LED commands until you do this.
|
||||
|
||||
Addr 08 Command f0:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
09 Payload length
|
||||
.. "15084" (part nr for LED board)
|
||||
FF ??
|
||||
11 ??
|
||||
00 ??
|
||||
12 ??
|
||||
Description:
|
||||
Get board "info"
|
||||
|
||||
Addr 00 Command 54:
|
||||
Req:
|
||||
06 Payload length
|
||||
57 'W'
|
||||
43 'C'
|
||||
43 'C'
|
||||
46 'F'
|
||||
76 'v'
|
||||
32 '2'
|
||||
Resp:
|
||||
00 Status byte?
|
||||
00 ??
|
||||
Description:
|
||||
Set Mifare KeyA.
|
||||
"WCCF" might refer this this SEGA arcade game:
|
||||
https://en.wikipedia.org/wiki/World_Club_Champion_Football
|
||||
It's quite old and has AiMe readers, maybe where they first appeared?
|
||||
|
||||
Addr 00 Command 50:
|
||||
Req:
|
||||
06 Payload length
|
||||
60 ??
|
||||
90 ??
|
||||
D0 ?? (This is escaped of course)
|
||||
06 ??
|
||||
32 ??
|
||||
F5 ??
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Possibly Mifare KeyB.
|
||||
|
||||
Polling
|
||||
-------
|
||||
|
||||
Addr 00 Command 40:
|
||||
Req:
|
||||
01 Payload length
|
||||
03 ??
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Poll some other NFC technology?
|
||||
|
||||
Addr 00 Command 42:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp if no MiFare card:
|
||||
00 Status byte
|
||||
01 Payload length
|
||||
00 (represents nothing i guess)
|
||||
Resp if MiFare card:
|
||||
00 Status byte?
|
||||
07 Payload length
|
||||
01 Chunk length?
|
||||
10 ?? Block size maybe?
|
||||
04 Chunk length?
|
||||
.. Mifare UID, four bytes.
|
||||
Description:
|
||||
Check for Mifare card presence?
|
||||
|
||||
Addr 00 Command 41:
|
||||
Req:
|
||||
00 Payload length
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Unknown. Poll some other NFC technology?
|
||||
|
||||
Card read
|
||||
---------
|
||||
|
||||
Addr 00 Command 43:
|
||||
Req:
|
||||
04 Payload length
|
||||
.. Mifare UID, four bytes.
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Select MiFare by UID?
|
||||
|
||||
Addr 00 Command 55:
|
||||
Req:
|
||||
05 Payload length
|
||||
.. Mifare UID, four bytes.
|
||||
03 ??
|
||||
Resp:
|
||||
00 Status byte
|
||||
00 Payload length
|
||||
Description:
|
||||
Unknown.
|
||||
Block 3 on a Mifare sector contains keys and an access control list.
|
||||
It is generally not accessed directly (unless being provisioned?)
|
||||
|
||||
Addr 00 Command 52:
|
||||
Req:
|
||||
05 Payload length
|
||||
.. Mifare UID, four bytes.
|
||||
.. Block number, 1 or 2.
|
||||
Resp for Block 1:
|
||||
00 Status byte
|
||||
10 Payload length (1 block)
|
||||
.. "SBSD"
|
||||
00 00 00 00
|
||||
00 00 00 00
|
||||
00 4E C6 22
|
||||
Resp for Block 2:
|
||||
00 Status byte
|
||||
10 Payload length (1 block)
|
||||
.. 00 00 00 00 00 00 xx xx
|
||||
xx xx xx xx xx xx xx xx
|
||||
Description:
|
||||
Probably reads blocks 1 and 2 from Mifare sector 0.
|
||||
Block 0 contains the "vendor information" and UID.
|
||||
Block 1 contents are unknown, probably AiMe DB info.
|
||||
Block 2 last 10 bytes hex are printed on the card ("local unique id").
|
||||
(Block 3 contains encryption keys so is not allowed to be read)
|
||||
|
||||
LED
|
||||
---
|
||||
|
||||
Addr 08 Command 81:
|
||||
Req:
|
||||
03 Payload length
|
||||
ff Red intensity
|
||||
ff Green intensity
|
||||
ff Blue intensity
|
||||
Resp:
|
||||
None! Command is not acknowledged
|
||||
Description:
|
||||
Set LED color
|
Loading…
Reference in New Issue
Block a user