1
0
mirror of https://github.com/Sucareto/ESP32-CardReader.git synced 2024-11-23 23:00:56 +01:00

同步更新,移除不再使用的库文件。

This commit is contained in:
Sucareto 2023-07-02 02:26:05 +08:00
parent 47515a42d6
commit 0c3fbcc07b
6 changed files with 195 additions and 1614 deletions

View File

@ -1,12 +1,55 @@
#include "src/PN532_SPI.h"
PN532_SPI pn532(SPI, PN532_SPI_SS);
#ifdef ESP32
#pragma message "当前的开发板是 ESP32"
#define SerialDevice Serial
#define LED_PIN 13
#define PN532_SPI_SS 5
#include "src/PN532.h"
PN532 nfc(pn532);
#define SW1_MODE 33
#define SW2_OTA 25
#define SW3_CARD 26
#define SW4_FW 27
// #define OTA_Enable
#ifdef OTA_Enable
#pragma message "已开启 OTA 更新功能"
#define STASSID "SSIDNAME"
#define STAPASS "PASSWORD"
#define OTA_URL "http://esp-update.local/Sucareto/ESP32-Reader:2333/"
#include <WiFi.h>
#include <HTTPUpdate.h>
#endif
#else
#error "未适配的开发板!!!"
#endif
#define old_fw_version "TN32MSEC003S F/W Ver1.2"
#define old_hw_version "TN32MSEC003S H/W Ver3.0"
#define old_led_info "15084\xFF\x10\x00\x12"
#define new_fw_version "\x94"
#define new_hw_version "837-15396"
#define new_led_info "000-00000\xFF\x11\x40"
bool ReaderMode, FWSW;
uint8_t len, r, checksum;
bool escape = false;
unsigned long ConnectTime = 0;
bool ConnectStatus = false;
uint16_t SleepDelay = 10000; // ms
#include "FastLED.h"
CRGB leds[8];
#include <SPI.h>
#include <PN532_SPI.h>
PN532_SPI pn532(SPI, PN532_SPI_SS);
#include "PN532.h"
PN532 nfc(pn532);
uint8_t KeyA[6], KeyB[6];
uint8_t DefaultKey[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);
@ -22,14 +65,6 @@ static uint8_t mifare_data[][16] = {
{ 0x57, 0x43, 0x43, 0x46, 0x76, 0x32, 0x08, 0x77, 0x8F, 0x11, 0x57, 0x43, 0x43, 0x46, 0x76, 0x32 },
};
// 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
@ -39,6 +74,7 @@ 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
@ -49,47 +85,58 @@ static unsigned char blank[] = {
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,
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,
};
typedef union packet_req {
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;
@ -98,38 +145,38 @@ typedef union packet_req {
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 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 { //sg_nfc_req_felica_encap
struct { // CMD_FELICA_THROUGH
uint8_t encap_IDm[8];
uint8_t encap_len;
uint8_t encap_code;
union {
struct {
struct { // CMD_FELICA_THROUGH_POLL
uint8_t poll_systemCode[2];
uint8_t poll_requestCode;
uint8_t poll_timeout;
};
struct { //NDA_06,NDA_08,NDA_A4
struct { // CMD_FELICA_THROUGH_READ,WRITE,NDA_A4
uint8_t RW_IDm[8];
uint8_t numService; //and NDA_A4 unknown byte
uint8_t numService;
uint8_t serviceCodeList[2];
uint8_t numBlock;
uint8_t blockList[1][2];
uint8_t blockData[16]; //WriteWithoutEncryption,ignore
uint8_t blockList[1][2]; // CMD_FELICA_THROUGH_READ
uint8_t blockData[16]; // CMD_FELICA_THROUGH_WRITE
};
uint8_t felica_payload[1];
};
};
};
};
} packet_req_t;
} packet_request_t;
typedef union packet_res {
typedef union {
uint8_t bytes[128];
struct {
uint8_t frame_len;
@ -139,9 +186,9 @@ typedef union packet_res {
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 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;
@ -153,33 +200,31 @@ typedef union packet_res {
};
};
};
struct { //sg_nfc_res_felica_encap
struct { // CMD_FELICA_THROUGH
uint8_t encap_len;
uint8_t encap_code;
uint8_t encap_IDm[8];
union {
struct { //FELICA_CMD_POLL
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 RW_status[2];
uint8_t numBlock;
uint8_t blockData[1][1][16];
};
uint8_t felica_payload[1];
};
};
};
};
} packet_res_t;
} packet_response_t;
static packet_req_t req;
static packet_res_t res;
static uint8_t len, r, checksum;
static bool escape = false;
packet_request_t req;
packet_response_t res;
static uint8_t packet_read() {
uint8_t packet_read() {
while (SerialDevice.available()) {
r = SerialDevice.read();
if (r == 0xE0) {
@ -209,7 +254,7 @@ static uint8_t packet_read() {
return 0;
}
static void packet_write() {
void packet_write() {
uint8_t checksum = 0, len = 0;
if (res.cmd == 0) {
return;
@ -234,228 +279,183 @@ static void packet_write() {
res.cmd = 0;
}
static void sg_res_init(uint8_t payload_len = 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 = 0;
res.status = ERROR_NONE;
res.payload_len = payload_len;
}
static void sg_nfc_cmd_reset() {
void sys_to_normal_mode() {
res_init();
if (nfc.getFirmwareVersion()) {
sg_res_init();
res.status = 3;
res.status = ERROR_NFCRW_FIRMWARE_UP_TO_DATE;
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);
res.status = ERROR_NFCRW_INIT_ERROR;
u8g2.drawXBM(95, 0, 16, 16, rf_off);
FastLED.showColor(0xFF0000);
}
}
static void sg_nfc_cmd_get_hw_version() {
void sys_get_fw_version() {
if (FWSW) {
sg_res_init(sizeof(HW_TN32));
memcpy(res.version, HW_TN32, res.payload_len);
res_init(sizeof(old_fw_version) - 1);
memcpy(res.version, old_fw_version, res.payload_len);
} else {
sg_res_init(sizeof(HW_837));
memcpy(res.version, HW_837, res.payload_len);
res_init(sizeof(new_fw_version) - 1);
memcpy(res.version, new_fw_version, res.payload_len);
}
}
static void sg_led_cmd_get_info() {
void sys_get_hw_version() {
if (FWSW) {
sg_res_init(sizeof(BOARD_TN32));
memcpy(res.version, BOARD_TN32, res.payload_len);
res_init(sizeof(old_hw_version) - 1);
memcpy(res.version, old_hw_version, res.payload_len);
} else {
sg_res_init(sizeof(BOARD_837));
memcpy(res.version, BOARD_837, res.payload_len);
res_init(sizeof(new_hw_version));
memcpy(res.version, new_hw_version, res.payload_len);
}
}
static void sg_nfc_cmd_mifare_set_key_aime() {
sg_res_init();
memcpy(AimeKey, req.key, 6);
void sys_get_led_info() {
if (FWSW) {
res_init(sizeof(old_led_info) - 1);
memcpy(res.version, old_led_info, res.payload_len);
} else {
res_init(sizeof(new_led_info) - 1);
memcpy(res.version, new_led_info, res.payload_len);
}
}
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();
void nfc_start_polling() {
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();
void nfc_stop_polling() {
res_init();
nfc.setRFField(0x00, 0x00);
u8g2.drawXBM(95, 0, 16, 16, blank);
u8g2.sendBuffer();
}
static void sg_nfc_cmd_poll() { //卡号发送
void nfc_card_detect() {
uint16_t SystemCode;
uint8_t bufferLength;
if (!digitalRead(SW3_CARD)) {
memcpy(res.mifare_uid, mifare_data[0], 0x04);
res.id_len = 0x04;
sg_res_init(0x07);
res_init(0x07);
res.count = 1;
res.type = 0x10;
u8g2.drawXBM(113, 0, 16, 16, card);
u8g2.sendBuffer();
return;
}
uint16_t SystemCode;
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, res.mifare_uid, &res.id_len)) {
sg_res_init(0x07);
} else 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) { //< 0: error
sg_res_init(0x13);
} 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 {
sg_res_init(1);
res_init(1);
res.count = 0;
res.status = ERROR_NONE;
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 (!digitalRead(SW3_CARD)) {
uint8_t key_block_no = (req.block_no / 4) * 4 + 3;
if (memcmp(AimeKey, mifare_data[key_block_no] + 10, 6)) { // Key B
res.status = 1;
}
return;
}
if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 1, AimeKey)) {
return;
} else {
res.status = 1;
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;
}
}
static void sg_nfc_cmd_bana_authenticate() {
sg_res_init();
if (!digitalRead(SW3_CARD)) {
uint8_t key_block_no = (req.block_no / 4) * 4 + 3;
if (memcmp(BanaKey, mifare_data[key_block_no], 6)) {
res.status = 1;
}
return;
}
if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 0, BanaKey)) {
return;
} else {
res.status = 1;
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;
}
}
static void sg_nfc_cmd_mifare_read_block() { //读取卡扇区数据
void nfc_mifare_read() {
res_init(0x10);
if (!digitalRead(SW3_CARD)) {
memcpy(res.block, mifare_data[req.block_no], 16);
sg_res_init(0x10);
res_init(0x10);
return;
} else if (!nfc.mifareclassic_ReadDataBlock(req.block_no, res.block)) {
res_init();
res.status = ERROR_CARD_DETECT_TIMEOUT; // TODO
}
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() {
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; //SystemCode大小端反转注意
SystemCode = SystemCode >> 8 | SystemCode << 8;
} else {
sg_res_init();
res.status = 1;
res_init();
res.status = ERROR_FELICA_ERROR;
return;
}
uint8_t code = req.encap_code;
res.encap_code = code + 1;
switch (code) {
case FELICA_CMD_POLL:
case CMD_FELICA_THROUGH_POLL:
{
sg_res_init(0x14);
res_init(0x14);
res.poll_systemCode[0] = SystemCode;
res.poll_systemCode[1] = SystemCode >> 8;
}
break;
case FELICA_CMD_GET_SYSTEM_CODE:
case CMD_FELICA_THROUGH_GET_SYSTEM_CODE:
{
sg_res_init(0x0D);
res.felica_payload[0] = 0x01; //未知
res.felica_payload[1] = SystemCode; //SystemCode
res_init(0x0D);
res.felica_payload[0] = 0x01;
res.felica_payload[1] = SystemCode;
res.felica_payload[2] = SystemCode >> 8;
}
break;
case FELICA_CMD_NDA_A4:
case CMD_FELICA_THROUGH_NDA_A4:
{
sg_res_init(0x0B);
res_init(0x0B);
res.felica_payload[0] = 0x00;
}
break;
case FELICA_CMD_NDA_06:
case CMD_FELICA_THROUGH_READ:
{
uint16_t serviceCodeList[1] = { (uint16_t)(req.serviceCodeList[1] << 8 | req.serviceCodeList[0]) }; //大小端反转注意
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
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);
res_init(0x0D + req.numBlock * 16);
}
break;
case FELICA_CMD_NDA_08:
case CMD_FELICA_THROUGH_WRITE:
{
sg_res_init(0x0C); //此处应有写入卡,但是不打算实现
res_init(0x0C); // WriteWithoutEncryption,ignore
res.RW_status[0] = 0;
res.RW_status[1] = 0;
}
break;
default:
sg_res_init();
res.status = 1;
res_init();
res.status = ERROR_FELICA_ERROR;
}
res.encap_len = res.payload_len;
}

View File

@ -1,987 +0,0 @@
/*
https://github.com/elechouse/PN532
使
*/
/**************************************************************************/
/*!
@file PN532.cpp
@author Adafruit Industries & Seeed Studio
@license BSD
*/
/**************************************************************************/
#include "Arduino.h"
#include "PN532.h"
#define HAL(func) (_interface->func)
PN532::PN532(PN532Interface &interface) {
_interface = &interface;
}
/**************************************************************************/
/*!
@brief Setups the HW
*/
/**************************************************************************/
void PN532::begin() {
HAL(begin)
();
HAL(wakeup)
();
}
/**************************************************************************/
/*!
@brief Checks the firmware version of the PN5xx chip
@returns The chip's firmware version and ID
*/
/**************************************************************************/
uint32_t PN532::getFirmwareVersion(void) {
uint32_t response;
pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
if (HAL(writeCommand)(pn532_packetbuffer, 1)) {
return 0;
}
// read data packet
int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
if (0 > status) {
return 0;
}
response = pn532_packetbuffer[0];
response <<= 8;
response |= pn532_packetbuffer[1];
response <<= 8;
response |= pn532_packetbuffer[2];
response <<= 8;
response |= pn532_packetbuffer[3];
return response;
}
/**************************************************************************/
/*!
@brief Read a PN532 register.
@param reg the 16-bit register address.
@returns The register value.
*/
/**************************************************************************/
uint32_t PN532::readRegister(uint16_t reg) {
uint32_t response;
pn532_packetbuffer[0] = PN532_COMMAND_READREGISTER;
pn532_packetbuffer[1] = (reg >> 8) & 0xFF;
pn532_packetbuffer[2] = reg & 0xFF;
if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
return 0;
}
// read data packet
int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
if (0 > status) {
return 0;
}
response = pn532_packetbuffer[0];
return response;
}
/**************************************************************************/
/*!
@brief Write to a PN532 register.
@param reg the 16-bit register address.
@param val the 8-bit value to write.
@returns 0 for failure, 1 for success.
*/
/**************************************************************************/
uint32_t PN532::writeRegister(uint16_t reg, uint8_t val) {
uint32_t response;
pn532_packetbuffer[0] = PN532_COMMAND_WRITEREGISTER;
pn532_packetbuffer[1] = (reg >> 8) & 0xFF;
pn532_packetbuffer[2] = reg & 0xFF;
pn532_packetbuffer[3] = val;
if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
return 0;
}
// read data packet
int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
if (0 > status) {
return 0;
}
return 1;
}
/**************************************************************************/
/*!
@brief Configures the SAM (Secure Access Module)
*/
/**************************************************************************/
bool PN532::SAMConfig(void) {
pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
pn532_packetbuffer[1] = 0x01; // normal mode;
pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
pn532_packetbuffer[3] = 0x01; // use IRQ pin!
if (HAL(writeCommand)(pn532_packetbuffer, 4))
return false;
return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}
/**************************************************************************/
/*!
Sets the MxRtyPassiveActivation uint8_t of the RFConfiguration register
@param maxRetries 0xFF to wait forever, 0x00..0xFE to timeout
after mxRetries
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
bool PN532::setPassiveActivationRetries(uint8_t maxRetries) {
pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries)
pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF)
pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01)
pn532_packetbuffer[4] = maxRetries;
if (HAL(writeCommand)(pn532_packetbuffer, 5))
return 0x0; // no ACK
return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}
/**************************************************************************/
/*!
Sets the RFon/off uint8_t of the RFConfiguration register
@param autoRFCA 0x00 No check of the external field before
activation
0x02 Check the external field before
activation
@param rFOnOff 0x00 Switch the RF field off, 0x01 switch the RF
field on
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
bool PN532::setRFField(uint8_t autoRFCA, uint8_t rFOnOff) {
pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
pn532_packetbuffer[1] = 1;
pn532_packetbuffer[2] = 0x00 | autoRFCA | rFOnOff;
if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
return 0x0; // command failed
}
return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}
/***** ISO14443A Commands ******/
/**************************************************************************/
/*!
Waits for an ISO14443A target to enter the field
@param cardBaudRate Baud rate of the card
@param uid Pointer to the array that will be populated
with the card's UID (up to 7 bytes)
@param uidLength Pointer to the variable that will hold the
length of the card's UID.
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
bool PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout) {
pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
pn532_packetbuffer[2] = cardbaudrate;
if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
return 0x0; // command failed
}
// read data packet
if (HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) {
return 0x0;
}
// check some basic stuff
/* ISO14443A card response should be in the following format:
byte Description
------------- ------------------------------------------
b0 Tags Found
b1 Tag Number (only one used in this example)
b2..3 SENS_RES
b4 SEL_RES
b5 NFCID Length
b6..NFCIDLen NFCID
*/
if (pn532_packetbuffer[0] != 1)
return 0;
if (pn532_packetbuffer[4] != 0x08) // SAK == 0x08
return 0;
uint16_t sens_res = pn532_packetbuffer[2];
sens_res <<= 8;
sens_res |= pn532_packetbuffer[3];
/* Card appears to be Mifare Classic */
*uidLength = pn532_packetbuffer[5];
for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) {
uid[i] = pn532_packetbuffer[6 + i];
}
return 1;
}
/***** Mifare Classic Functions ******/
/**************************************************************************/
/*!
Indicates whether the specified block number is the first block
in the sector (block 0 relative to the current sector)
*/
/**************************************************************************/
bool PN532::mifareclassic_IsFirstBlock(uint32_t uiBlock) {
// Test if we are in the small or big sectors
if (uiBlock < 128)
return ((uiBlock) % 4 == 0);
else
return ((uiBlock) % 16 == 0);
}
/**************************************************************************/
/*!
Indicates whether the specified block number is the sector trailer
*/
/**************************************************************************/
bool PN532::mifareclassic_IsTrailerBlock(uint32_t uiBlock) {
// Test if we are in the small or big sectors
if (uiBlock < 128)
return ((uiBlock + 1) % 4 == 0);
else
return ((uiBlock + 1) % 16 == 0);
}
/**************************************************************************/
/*!
Tries to authenticate a block of memory on a MIFARE card using the
INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
for more information on sending MIFARE and other commands.
@param uid Pointer to a byte array containing the card UID
@param uidLen The length (in bytes) of the card's UID (Should
be 4 for MIFARE Classic)
@param blockNumber The block number to authenticate. (0..63 for
1KB cards, and 0..255 for 4KB cards).
@param keyNumber Which key type to use during authentication
(0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
@param keyData Pointer to a byte array containing the 6 bytes
key value
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareclassic_AuthenticateBlock(uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) {
uint8_t i;
// Hang on to the key and uid data
memcpy(_key, keyData, 6);
memcpy(_uid, uid, uidLen);
_uidLen = uidLen;
// Prepare the authentication command //
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
pn532_packetbuffer[1] = 1; /* Max card numbers */
pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
memcpy(pn532_packetbuffer + 4, _key, 6);
for (i = 0; i < _uidLen; i++) {
pn532_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */
}
if (HAL(writeCommand)(pn532_packetbuffer, 10 + _uidLen))
return 0;
// Read the response packet
HAL(readResponse)
(pn532_packetbuffer, sizeof(pn532_packetbuffer));
// Check if the response is valid and we are authenticated???
// for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
// Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good
if (pn532_packetbuffer[0] != 0x00) {
return 0;
}
return 1;
}
/**************************************************************************/
/*!
Tries to read an entire 16-bytes data block at the specified block
address.
@param blockNumber The block number to authenticate. (0..63 for
1KB cards, and 0..255 for 4KB cards).
@param data Pointer to the byte array that will hold the
retrieved data (if any)
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareclassic_ReadDataBlock(uint8_t blockNumber, uint8_t *data) {
/* Prepare the command */
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
pn532_packetbuffer[1] = 1; /* Card number */
pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
/* Send the command */
if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
return 0;
}
/* Read the response packet */
HAL(readResponse)
(pn532_packetbuffer, sizeof(pn532_packetbuffer));
/* If byte 8 isn't 0x00 we probably have an error */
if (pn532_packetbuffer[0] != 0x00) {
return 0;
}
/* Copy the 16 data bytes to the output buffer */
/* Block content starts at byte 9 of a valid response */
memcpy(data, pn532_packetbuffer + 1, 16);
return 1;
}
/**************************************************************************/
/*!
Tries to write an entire 16-bytes data block at the specified block
address.
@param blockNumber The block number to authenticate. (0..63 for
1KB cards, and 0..255 for 4KB cards).
@param data The byte array that contains the data to write.
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532::mifareclassic_WriteDataBlock(uint8_t blockNumber, uint8_t *data) {
/* Prepare the first command */
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
pn532_packetbuffer[1] = 1; /* Card number */
pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
memcpy(pn532_packetbuffer + 4, data, 16); /* Data Payload */
/* Send the command */
if (HAL(writeCommand)(pn532_packetbuffer, 20)) {
return 0;
}
/* Read the response packet */
return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
}
/**************************************************************************/
/*!
@brief Exchanges an APDU with the currently inlisted peer
@param send Pointer to data to send
@param sendLength Length of the data to send
@param response Pointer to response data
@param responseLength Pointer to the response data length
*/
/**************************************************************************/
bool PN532::inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength) {
uint8_t i;
pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
pn532_packetbuffer[1] = inListedTag;
if (HAL(writeCommand)(pn532_packetbuffer, 2, send, sendLength)) {
return false;
}
int16_t status = HAL(readResponse)(response, *responseLength, 1000);
if (status < 0) {
return false;
}
if ((response[0] & 0x3f) != 0) {
return false;
}
uint8_t length = status;
length -= 1;
if (length > *responseLength) {
length = *responseLength; // silent truncation...
}
for (uint8_t i = 0; i < length; i++) {
response[i] = response[i + 1];
}
*responseLength = length;
return true;
}
/**************************************************************************/
/*!
@brief 'InLists' a passive target. PN532 acting as reader/initiator,
peer acting as card/responder.
*/
/**************************************************************************/
bool PN532::inListPassiveTarget() {
pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
pn532_packetbuffer[1] = 1;
pn532_packetbuffer[2] = 0;
if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
return false;
}
int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 30000);
if (status < 0) {
return false;
}
if (pn532_packetbuffer[0] != 1) {
return false;
}
inListedTag = pn532_packetbuffer[1];
return true;
}
int8_t PN532::tgInitAsTarget(const uint8_t *command, const uint8_t len, const uint16_t timeout) {
int8_t status = HAL(writeCommand)(command, len);
if (status < 0) {
return -1;
}
status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout);
if (status > 0) {
return 1;
} else if (PN532_TIMEOUT == status) {
return 0;
} else {
return -2;
}
}
/**
* Peer to Peer
*/
int8_t PN532::tgInitAsTarget(uint16_t timeout) {
const uint8_t command[] = {
PN532_COMMAND_TGINITASTARGET,
0,
0x00, 0x00, //SENS_RES
0x00, 0x00, 0x00, //NFCID1
0x40, //SEL_RES
0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, // POL_RES
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF,
0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, 0x00, 0x00, //NFCID3t: Change this to desired value
0x06, 0x46, 0x66, 0x6D, 0x01, 0x01, 0x10, 0x00 // LLCP magic number and version parameter
};
return tgInitAsTarget(command, sizeof(command), timeout);
}
int16_t PN532::tgGetData(uint8_t *buf, uint8_t len) {
buf[0] = PN532_COMMAND_TGGETDATA;
if (HAL(writeCommand)(buf, 1)) {
return -1;
}
int16_t status = HAL(readResponse)(buf, len, 3000);
if (0 >= status) {
return status;
}
uint16_t length = status - 1;
if (buf[0] != 0) {
return -5;
}
for (uint8_t i = 0; i < length; i++) {
buf[i] = buf[i + 1];
}
return length;
}
bool PN532::tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) {
if (hlen > (sizeof(pn532_packetbuffer) - 1)) {
if ((body != 0) || (header == pn532_packetbuffer)) {
return false;
}
pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA;
if (HAL(writeCommand)(pn532_packetbuffer, 1, header, hlen)) {
return false;
}
} else {
for (int8_t i = hlen - 1; i >= 0; i--) {
pn532_packetbuffer[i + 1] = header[i];
}
pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA;
if (HAL(writeCommand)(pn532_packetbuffer, hlen + 1, body, blen)) {
return false;
}
}
if (0 > HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 3000)) {
return false;
}
if (0 != pn532_packetbuffer[0]) {
return false;
}
return true;
}
int16_t PN532::inRelease(const uint8_t relevantTarget) {
pn532_packetbuffer[0] = PN532_COMMAND_INRELEASE;
pn532_packetbuffer[1] = relevantTarget;
if (HAL(writeCommand)(pn532_packetbuffer, 2)) {
return 0;
}
// read data packet
return HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
}
/***** FeliCa Functions ******/
/**************************************************************************/
/*!
@brief Poll FeliCa card. PN532 acting as reader/initiator,
peer acting as card/responder.
@param[in] systemCode Designation of System Code. When sending FFFFh as System Code,
all FeliCa cards can return response.
@param[in] requestCode Designation of Request Data as follows:
00h: No Request
01h: System Code request (to acquire System Code of the card)
02h: Communication perfomance request
@param[out] idm IDm of the card (8 bytes)
@param[out] pmm PMm of the card (8 bytes)
@param[out] systemCodeResponse System Code of the card (Optional, 2bytes)
@return = 1: A FeliCa card has detected
= 0: No card has detected
< 0: error
*/
/**************************************************************************/
int8_t PN532::felica_Polling(uint16_t systemCode, uint8_t requestCode, uint8_t *idm, uint8_t *pmm, uint16_t *systemCodeResponse, uint16_t timeout) {
pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
pn532_packetbuffer[1] = 1;
pn532_packetbuffer[2] = 1;
pn532_packetbuffer[3] = FELICA_CMD_POLLING;
pn532_packetbuffer[4] = (systemCode >> 8) & 0xFF;
pn532_packetbuffer[5] = systemCode & 0xFF;
pn532_packetbuffer[6] = requestCode;
pn532_packetbuffer[7] = 0;
if (HAL(writeCommand)(pn532_packetbuffer, 8)) {
return -1;
}
int16_t status = HAL(readResponse)(pn532_packetbuffer, 22, timeout);
if (status < 0) {
return -2;
}
// Check NbTg (pn532_packetbuffer[7])
if (pn532_packetbuffer[0] == 0) {
return 0;
} else if (pn532_packetbuffer[0] != 1) {
return -3;
}
inListedTag = pn532_packetbuffer[1];
// length check
uint8_t responseLength = pn532_packetbuffer[2];
if (responseLength != 18 && responseLength != 20) {
return -4;
}
uint8_t i;
for (i = 0; i < 8; ++i) {
idm[i] = pn532_packetbuffer[4 + i];
_felicaIDm[i] = pn532_packetbuffer[4 + i];
pmm[i] = pn532_packetbuffer[12 + i];
_felicaPMm[i] = pn532_packetbuffer[12 + i];
}
if (responseLength == 20) {
*systemCodeResponse = (uint16_t)((pn532_packetbuffer[20] << 8) + pn532_packetbuffer[21]);
}
return 1;
}
/**************************************************************************/
/*!
@brief Sends FeliCa command to the currently inlisted peer
@param[in] command FeliCa command packet. (e.g. 00 FF FF 00 00 for Polling command)
@param[in] commandlength Length of the FeliCa command packet. (e.g. 0x05 for above Polling command )
@param[out] response FeliCa response packet. (e.g. 01 NFCID2(8 bytes) PAD(8 bytes) for Polling response)
@param[out] responselength Length of the FeliCa response packet. (e.g. 0x11 for above Polling command )
@return = 1: Success
< 0: error
*/
/**************************************************************************/
int8_t PN532::felica_SendCommand(const uint8_t *command, uint8_t commandlength, uint8_t *response, uint8_t *responseLength) {
if (commandlength > 0xFE) {
return -1;
}
pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
pn532_packetbuffer[1] = inListedTag;
pn532_packetbuffer[2] = commandlength + 1;
if (HAL(writeCommand)(pn532_packetbuffer, 3, command, commandlength)) {
return -2;
}
// Wait card response
int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 200);
if (status < 0) {
return -3;
}
// Check status (pn532_packetbuffer[0])
if ((pn532_packetbuffer[0] & 0x3F) != 0) {
return -4;
}
// length check
*responseLength = pn532_packetbuffer[1] - 1;
if ((status - 2) != *responseLength) {
return -5;
}
memcpy(response, &pn532_packetbuffer[2], *responseLength);
return 1;
}
/**************************************************************************/
/*!
@brief Sends FeliCa Request Service command
@param[in] numNode length of the nodeCodeList
@param[in] nodeCodeList Node codes(Big Endian)
@param[out] keyVersions Key Version of each Node (Big Endian)
@return = 1: Success
< 0: error
*/
/**************************************************************************/
int8_t PN532::felica_RequestService(uint8_t numNode, uint16_t *nodeCodeList, uint16_t *keyVersions) {
if (numNode > FELICA_REQ_SERVICE_MAX_NODE_NUM) {
return -1;
}
uint8_t i, j = 0;
uint8_t cmdLen = 1 + 8 + 1 + 2 * numNode;
uint8_t cmd[cmdLen];
cmd[j++] = FELICA_CMD_REQUEST_SERVICE;
for (i = 0; i < 8; ++i) {
cmd[j++] = _felicaIDm[i];
}
cmd[j++] = numNode;
for (i = 0; i < numNode; ++i) {
cmd[j++] = nodeCodeList[i] & 0xFF;
cmd[j++] = (nodeCodeList[i] >> 8) & 0xff;
}
uint8_t response[10 + 2 * numNode];
uint8_t responseLength;
if (felica_SendCommand(cmd, cmdLen, response, &responseLength) != 1) {
return -2;
}
// length check
if (responseLength != 10 + 2 * numNode) {
return -3;
}
for (i = 0; i < numNode; i++) {
keyVersions[i] = (uint16_t)(response[10 + i * 2] + (response[10 + i * 2 + 1] << 8));
}
return 1;
}
/**************************************************************************/
/*!
@brief Sends FeliCa Request Service command
@param[out] mode Current Mode of the card
@return = 1: Success
< 0: error
*/
/**************************************************************************/
int8_t PN532::felica_RequestResponse(uint8_t *mode) {
uint8_t cmd[9];
cmd[0] = FELICA_CMD_REQUEST_RESPONSE;
memcpy(&cmd[1], _felicaIDm, 8);
uint8_t response[10];
uint8_t responseLength;
if (felica_SendCommand(cmd, 9, response, &responseLength) != 1) {
return -1;
}
// length check
if (responseLength != 10) {
return -2;
}
*mode = response[9];
return 1;
}
/**************************************************************************/
/*!
@brief Sends FeliCa Read Without Encryption command
@param[in] numService Length of the serviceCodeList
@param[in] serviceCodeList Service Code List (Big Endian)
@param[in] numBlock Length of the blockList
@param[in] blockList Block List (Big Endian, This API only accepts 2-byte block list element)
@param[out] blockData Block Data
@return = 1: Success
< 0: error
*/
/**************************************************************************/
int8_t PN532::felica_ReadWithoutEncryption(uint8_t numService, const uint16_t *serviceCodeList, uint8_t numBlock, const uint16_t *blockList, uint8_t blockData[][16]) {
if (numService > FELICA_READ_MAX_SERVICE_NUM) {
return -1;
}
if (numBlock > FELICA_READ_MAX_BLOCK_NUM) {
return -2;
}
uint8_t i, j = 0, k;
uint8_t cmdLen = 1 + 8 + 1 + 2 * numService + 1 + 2 * numBlock;
uint8_t cmd[cmdLen];
cmd[j++] = FELICA_CMD_READ_WITHOUT_ENCRYPTION;
for (i = 0; i < 8; ++i) {
cmd[j++] = _felicaIDm[i];
}
cmd[j++] = numService;
for (i = 0; i < numService; ++i) {
cmd[j++] = serviceCodeList[i] & 0xFF;
cmd[j++] = (serviceCodeList[i] >> 8) & 0xff;
}
cmd[j++] = numBlock;
for (i = 0; i < numBlock; ++i) {
cmd[j++] = (blockList[i] >> 8) & 0xFF;
cmd[j++] = blockList[i] & 0xff;
}
uint8_t response[12 + 16 * numBlock];
uint8_t responseLength;
if (felica_SendCommand(cmd, cmdLen, response, &responseLength) != 1) {
return -3;
}
// length check
if (responseLength != 12 + 16 * numBlock) {
return -4;
}
// status flag check
if (response[9] != 0 || response[10] != 0) {
return -5;
}
k = 12;
for (i = 0; i < numBlock; i++) {
for (j = 0; j < 16; j++) {
blockData[i][j] = response[k++];
}
}
return 1;
}
/**************************************************************************/
/*!
@brief Sends FeliCa Write Without Encryption command
@param[in] numService Length of the serviceCodeList
@param[in] serviceCodeList Service Code List (Big Endian)
@param[in] numBlock Length of the blockList
@param[in] blockList Block List (Big Endian, This API only accepts 2-byte block list element)
@param[in] blockData Block Data (each Block has 16 bytes)
@return = 1: Success
< 0: error
*/
/**************************************************************************/
int8_t PN532::felica_WriteWithoutEncryption(uint8_t numService, const uint16_t *serviceCodeList, uint8_t numBlock, const uint16_t *blockList, uint8_t blockData[][16]) {
if (numService > FELICA_WRITE_MAX_SERVICE_NUM) {
return -1;
}
if (numBlock > FELICA_WRITE_MAX_BLOCK_NUM) {
return -2;
}
uint8_t i, j = 0, k;
uint8_t cmdLen = 1 + 8 + 1 + 2 * numService + 1 + 2 * numBlock + 16 * numBlock;
uint8_t cmd[cmdLen];
cmd[j++] = FELICA_CMD_WRITE_WITHOUT_ENCRYPTION;
for (i = 0; i < 8; ++i) {
cmd[j++] = _felicaIDm[i];
}
cmd[j++] = numService;
for (i = 0; i < numService; ++i) {
cmd[j++] = serviceCodeList[i] & 0xFF;
cmd[j++] = (serviceCodeList[i] >> 8) & 0xff;
}
cmd[j++] = numBlock;
for (i = 0; i < numBlock; ++i) {
cmd[j++] = (blockList[i] >> 8) & 0xFF;
cmd[j++] = blockList[i] & 0xff;
}
for (i = 0; i < numBlock; ++i) {
for (k = 0; k < 16; k++) {
cmd[j++] = blockData[i][k];
}
}
uint8_t response[11];
uint8_t responseLength;
if (felica_SendCommand(cmd, cmdLen, response, &responseLength) != 1) {
return -3;
}
// length check
if (responseLength != 11) {
return -4;
}
// status flag check
if (response[9] != 0 || response[10] != 0) {
return -5;
}
return 1;
}
/**************************************************************************/
/*!
@brief Sends FeliCa Request System Code command
@param[out] numSystemCode Length of the systemCodeList
@param[out] systemCodeList System Code list (Array length should longer than 16)
@return = 1: Success
< 0: error
*/
/**************************************************************************/
int8_t PN532::felica_RequestSystemCode(uint8_t *numSystemCode, uint16_t *systemCodeList) {
uint8_t cmd[9];
cmd[0] = FELICA_CMD_REQUEST_SYSTEM_CODE;
memcpy(&cmd[1], _felicaIDm, 8);
uint8_t response[10 + 2 * 16];
uint8_t responseLength;
if (felica_SendCommand(cmd, 9, response, &responseLength) != 1) {
return -1;
}
*numSystemCode = response[9];
// length check
if (responseLength < 10 + 2 * *numSystemCode) {
return -2;
}
uint8_t i;
for (i = 0; i < *numSystemCode; i++) {
systemCodeList[i] = (uint16_t)((response[10 + i * 2] << 8) + response[10 + i * 2 + 1]);
}
return 1;
}
/**************************************************************************/
/*!
@brief Release FeliCa card
@return = 1: Success
< 0: error
*/
/**************************************************************************/
int8_t PN532::felica_Release() {
// InRelease
pn532_packetbuffer[0] = PN532_COMMAND_INRELEASE;
pn532_packetbuffer[1] = 0x00; // All target
if (HAL(writeCommand)(pn532_packetbuffer, 2)) {
return -1; // no ACK
}
// Wait card response
int16_t frameLength = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 1000);
if (frameLength < 0) {
return -2;
}
// Check status (pn532_packetbuffer[0])
if ((pn532_packetbuffer[0] & 0x3F) != 0) {
return -3;
}
return 1;
}

View File

@ -1,153 +0,0 @@
/*
https://github.com/elechouse/PN532
使
*/
/**************************************************************************/
/*!
@file PN532.h
@author Adafruit Industries & Seeed Studio
@license BSD
*/
/**************************************************************************/
#ifndef __PN532_H__
#define __PN532_H__
#include "PN532Interface.h"
// PN532 Commands
#define PN532_COMMAND_DIAGNOSE (0x00)
#define PN532_COMMAND_GETFIRMWAREVERSION (0x02)
#define PN532_COMMAND_GETGENERALSTATUS (0x04)
#define PN532_COMMAND_READREGISTER (0x06)
#define PN532_COMMAND_WRITEREGISTER (0x08)
#define PN532_COMMAND_READGPIO (0x0C)
#define PN532_COMMAND_WRITEGPIO (0x0E)
#define PN532_COMMAND_SETSERIALBAUDRATE (0x10)
#define PN532_COMMAND_SETPARAMETERS (0x12)
#define PN532_COMMAND_SAMCONFIGURATION (0x14)
#define PN532_COMMAND_POWERDOWN (0x16)
#define PN532_COMMAND_RFCONFIGURATION (0x32)
#define PN532_COMMAND_RFREGULATIONTEST (0x58)
#define PN532_COMMAND_INJUMPFORDEP (0x56)
#define PN532_COMMAND_INJUMPFORPSL (0x46)
#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A)
#define PN532_COMMAND_INATR (0x50)
#define PN532_COMMAND_INPSL (0x4E)
#define PN532_COMMAND_INDATAEXCHANGE (0x40)
#define PN532_COMMAND_INCOMMUNICATETHRU (0x42)
#define PN532_COMMAND_INDESELECT (0x44)
#define PN532_COMMAND_INRELEASE (0x52)
#define PN532_COMMAND_INSELECT (0x54)
#define PN532_COMMAND_INAUTOPOLL (0x60)
#define PN532_COMMAND_TGINITASTARGET (0x8C)
#define PN532_COMMAND_TGSETGENERALBYTES (0x92)
#define PN532_COMMAND_TGGETDATA (0x86)
#define PN532_COMMAND_TGSETDATA (0x8E)
#define PN532_COMMAND_TGSETMETADATA (0x94)
#define PN532_COMMAND_TGGETINITIATORCOMMAND (0x88)
#define PN532_COMMAND_TGRESPONSETOINITIATOR (0x90)
#define PN532_COMMAND_TGGETTARGETSTATUS (0x8A)
#define PN532_RESPONSE_INDATAEXCHANGE (0x41)
#define PN532_RESPONSE_INLISTPASSIVETARGET (0x4B)
#define PN532_MIFARE_ISO14443A (0x00)
// Mifare Commands
#define MIFARE_CMD_AUTH_A (0x60)
#define MIFARE_CMD_AUTH_B (0x61)
#define MIFARE_CMD_READ (0x30)
#define MIFARE_CMD_WRITE (0xA0)
#define MIFARE_CMD_WRITE_ULTRALIGHT (0xA2)
#define MIFARE_CMD_TRANSFER (0xB0)
#define MIFARE_CMD_DECREMENT (0xC0)
#define MIFARE_CMD_INCREMENT (0xC1)
#define MIFARE_CMD_STORE (0xC2)
// FeliCa Commands
#define FELICA_CMD_POLLING (0x00)
#define FELICA_CMD_REQUEST_SERVICE (0x02)
#define FELICA_CMD_REQUEST_RESPONSE (0x04)
#define FELICA_CMD_READ_WITHOUT_ENCRYPTION (0x06)
#define FELICA_CMD_WRITE_WITHOUT_ENCRYPTION (0x08)
#define FELICA_CMD_REQUEST_SYSTEM_CODE (0x0C)
// FeliCa consts
#define FELICA_READ_MAX_SERVICE_NUM 16
#define FELICA_READ_MAX_BLOCK_NUM 12 // for typical FeliCa card
#define FELICA_WRITE_MAX_SERVICE_NUM 16
#define FELICA_WRITE_MAX_BLOCK_NUM 10 // for typical FeliCa card
#define FELICA_REQ_SERVICE_MAX_NODE_NUM 32
class PN532 {
public:
PN532(PN532Interface &interface);
void begin(void);
// Generic PN532 functions
bool SAMConfig(void);
uint32_t getFirmwareVersion(void);
uint32_t readRegister(uint16_t reg);
uint32_t writeRegister(uint16_t reg, uint8_t val);
bool setPassiveActivationRetries(uint8_t maxRetries);
bool setRFField(uint8_t autoRFCA, uint8_t rFOnOff);
/**
* @brief Init PN532 as a target
* @param timeout max time to wait, 0 means no timeout
* @return > 0 success
* = 0 timeout
* < 0 failed
*/
int8_t tgInitAsTarget(uint16_t timeout = 0);
int8_t tgInitAsTarget(const uint8_t *command, const uint8_t len, const uint16_t timeout = 0);
int16_t tgGetData(uint8_t *buf, uint8_t len);
bool tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
int16_t inRelease(const uint8_t relevantTarget = 0);
// ISO14443A functions
bool inListPassiveTarget();
bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 1000);
bool inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength);
// Mifare Classic functions
bool mifareclassic_IsFirstBlock(uint32_t uiBlock);
bool mifareclassic_IsTrailerBlock(uint32_t uiBlock);
uint8_t mifareclassic_AuthenticateBlock(uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData);
uint8_t mifareclassic_ReadDataBlock(uint8_t blockNumber, uint8_t *data);
uint8_t mifareclassic_WriteDataBlock(uint8_t blockNumber, uint8_t *data);
// FeliCa Functions
int8_t felica_Polling(uint16_t systemCode, uint8_t requestCode, uint8_t *idm, uint8_t *pmm, uint16_t *systemCodeResponse, uint16_t timeout = 1000);
int8_t felica_SendCommand(const uint8_t *command, uint8_t commandlength, uint8_t *response, uint8_t *responseLength);
int8_t felica_RequestService(uint8_t numNode, uint16_t *nodeCodeList, uint16_t *keyVersions);
int8_t felica_RequestResponse(uint8_t *mode);
int8_t felica_ReadWithoutEncryption(uint8_t numService, const uint16_t *serviceCodeList, uint8_t numBlock, const uint16_t *blockList, uint8_t blockData[][16]);
int8_t felica_WriteWithoutEncryption(uint8_t numService, const uint16_t *serviceCodeList, uint8_t numBlock, const uint16_t *blockList, uint8_t blockData[][16]);
int8_t felica_RequestSystemCode(uint8_t *numSystemCode, uint16_t *systemCodeList);
int8_t felica_Release();
uint8_t *getBuffer(uint8_t *len) {
*len = sizeof(pn532_packetbuffer) - 4;
return pn532_packetbuffer;
};
private:
uint8_t _uid[7]; // ISO14443A uid
uint8_t _uidLen; // uid len
uint8_t _key[6]; // Mifare Classic key
uint8_t inListedTag; // Tg number of inlisted tag.
uint8_t _felicaIDm[8]; // FeliCa IDm (NFCID2)
uint8_t _felicaPMm[8]; // FeliCa PMm (PAD)
uint8_t pn532_packetbuffer[64];
PN532Interface *_interface;
};
#endif

View File

@ -1,55 +0,0 @@
/*
https://github.com/elechouse/PN532
使
*/
#ifndef __PN532_INTERFACE_H__
#define __PN532_INTERFACE_H__
#define PN532_PREAMBLE (0x00)
#define PN532_STARTCODE1 (0x00)
#define PN532_STARTCODE2 (0xFF)
#define PN532_POSTAMBLE (0x00)
#define PN532_HOSTTOPN532 (0xD4)
#define PN532_PN532TOHOST (0xD5)
#define PN532_ACK_WAIT_TIME (10) // ms, timeout of waiting for ACK
#define PN532_INVALID_ACK (-1)
#define PN532_TIMEOUT (-2)
#define PN532_INVALID_FRAME (-3)
#define PN532_NO_SPACE (-4)
#define REVERSE_BITS_ORDER(b) \
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; \
b = (b & 0xCC) >> 2 | (b & 0x33) << 2; \
b = (b & 0xAA) >> 1 | (b & 0x55) << 1
class PN532Interface {
public:
virtual void begin() = 0;
virtual void wakeup() = 0;
/**
* @brief write a command and check ack
* @param header packet header
* @param hlen length of header
* @param body packet body
* @param blen length of body
* @return 0 success
* not 0 failed
*/
virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) = 0;
/**
* @brief read the response of a command, strip prefix and suffix
* @param buf to contain the response data
* @param len lenght to read
* @param timeout max time to wait, 0 means no timeout
* @return >=0 length of response without prefix and suffix
* <0 failed to read response
*/
virtual int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 1000) = 0;
};
#endif

View File

@ -1,186 +0,0 @@
/*
https://github.com/elechouse/PN532
使
*/
#include "PN532_SPI.h"
#include "Arduino.h"
#define STATUS_READ 2
#define DATA_WRITE 1
#define DATA_READ 3
PN532_SPI::PN532_SPI(SPIClass &spi, uint8_t ss) {
command = 0;
_spi = &spi;
_ss = ss;
}
void PN532_SPI::begin() {
pinMode(_ss, OUTPUT);
_spi->begin();
_spi->setDataMode(SPI_MODE0); // PN532 only supports mode0
_spi->setBitOrder(LSBFIRST);
#ifndef __SAM3X8E__
_spi->setClockDivider(SPI_CLOCK_DIV8); // set clock 2MHz(max: 5MHz)
#else
/** DUE spi library does not support SPI_CLOCK_DIV8 macro */
_spi->setClockDivider(42); // set clock 2MHz(max: 5MHz)
#endif
}
void PN532_SPI::wakeup() {
digitalWrite(_ss, LOW);
delay(2);
digitalWrite(_ss, HIGH);
}
int8_t PN532_SPI::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) {
command = header[0];
writeFrame(header, hlen, body, blen);
uint8_t timeout = PN532_ACK_WAIT_TIME;
while (!isReady()) {
delay(1);
timeout--;
if (0 == timeout) {
return -2;
}
}
if (readAckFrame()) {
return PN532_INVALID_ACK;
}
return 0;
}
int16_t PN532_SPI::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) {
uint16_t time = 0;
while (!isReady()) {
delay(1);
time++;
if (timeout > 0 && time > timeout) {
return PN532_TIMEOUT;
}
}
digitalWrite(_ss, LOW);
delay(1);
int16_t result;
do {
write(DATA_READ);
if (0x00 != read() || // PREAMBLE
0x00 != read() || // STARTCODE1
0xFF != read() // STARTCODE2
) {
result = PN532_INVALID_FRAME;
break;
}
uint8_t length = read();
if (0 != (uint8_t)(length + read())) { // checksum of length
result = PN532_INVALID_FRAME;
break;
}
uint8_t cmd = command + 1; // response command
if (PN532_PN532TOHOST != read() || (cmd) != read()) {
result = PN532_INVALID_FRAME;
break;
}
length -= 2;
if (length > len) {
for (uint8_t i = 0; i < length; i++) {
}
read();
read();
result = PN532_NO_SPACE; // not enough space
break;
}
uint8_t sum = PN532_PN532TOHOST + cmd;
for (uint8_t i = 0; i < length; i++) {
buf[i] = read();
sum += buf[i];
}
uint8_t checksum = read();
if (0 != (uint8_t)(sum + checksum)) {
result = PN532_INVALID_FRAME;
break;
}
read(); // POSTAMBLE
result = length;
} while (0);
digitalWrite(_ss, HIGH);
return result;
}
bool PN532_SPI::isReady() {
digitalWrite(_ss, LOW);
write(STATUS_READ);
uint8_t status = read() & 1;
digitalWrite(_ss, HIGH);
return status;
}
void PN532_SPI::writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) {
digitalWrite(_ss, LOW);
delay(2); // wake up PN532
write(DATA_WRITE);
write(PN532_PREAMBLE);
write(PN532_STARTCODE1);
write(PN532_STARTCODE2);
uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA
write(length);
write(~length + 1); // checksum of length
write(PN532_HOSTTOPN532);
uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA
for (uint8_t i = 0; i < hlen; i++) {
write(header[i]);
sum += header[i];
}
for (uint8_t i = 0; i < blen; i++) {
write(body[i]);
sum += body[i];
}
uint8_t checksum = ~sum + 1; // checksum of TFI + DATA
write(checksum);
write(PN532_POSTAMBLE);
digitalWrite(_ss, HIGH);
}
int8_t PN532_SPI::readAckFrame() {
const uint8_t PN532_ACK[] = { 0, 0, 0xFF, 0, 0xFF, 0 };
uint8_t ackBuf[sizeof(PN532_ACK)];
digitalWrite(_ss, LOW);
delay(1);
write(DATA_READ);
for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) {
ackBuf[i] = read();
}
digitalWrite(_ss, HIGH);
return memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK));
}

View File

@ -1,38 +0,0 @@
/*
https://github.com/elechouse/PN532
使
*/
#ifndef __PN532_SPI_H__
#define __PN532_SPI_H__
#include <SPI.h>
#include "PN532Interface.h"
class PN532_SPI : public PN532Interface {
public:
PN532_SPI(SPIClass &spi, uint8_t ss);
void begin();
void wakeup();
int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout);
private:
SPIClass *_spi;
uint8_t _ss;
uint8_t command;
bool isReady();
void writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
int8_t readAckFrame();
inline void write(uint8_t data) {
_spi->transfer(data);
};
inline uint8_t read() {
return _spi->transfer(0);
};
};
#endif