Merge remote-tracking branch 'card-reader/main'
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
__pycache__/
|
||||||
|
.idea
|
||||||
|
.pio
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "lib/FastLED"]
|
||||||
|
path = lib/FastLED
|
||||||
|
url = https://github.com/FastLED/FastLED
|
||||||
Binary file not shown.
@@ -7,4 +7,4 @@
|
|||||||
## Index / 索引
|
## Index / 索引
|
||||||
|
|
||||||
* [Coyote-Pikachu](./Coyote-Pikachu/) 让某电击小盒子变成一只皮卡丘的外壳 ⚡️
|
* [Coyote-Pikachu](./Coyote-Pikachu/) 让某电击小盒子变成一只皮卡丘的外壳 ⚡️
|
||||||
* [TaikoStick](./TaikoStick/) 一对可以在任何表面上打太鼓达人的鼓槌 🥁
|
* [TaikoStick](./TaikoStick/) 一对可以在任何表面上打太鼓达人的鼓槌 🥁
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef TYPES_H
|
||||||
|
#define TYPES_H
|
||||||
|
|
||||||
|
#define u8 uint8_t
|
||||||
|
#define u16 uint16_t
|
||||||
|
#define u32 uint32_t
|
||||||
|
|
||||||
|
#define s8 int8_t
|
||||||
|
#define s16 int16_t
|
||||||
|
#define s32 int32_t
|
||||||
|
|
||||||
|
#define f32 float
|
||||||
|
#define f64 double
|
||||||
|
|
||||||
|
#endif //TYPES_H
|
||||||
Submodule
+1
Submodule lib/FastLED added at 3a03742a09
+1509
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,212 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@file PN532/PN532/PN532.h
|
||||||
|
@author Adafruit Industries & Seeed Studio
|
||||||
|
@license BSD
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __PN532_H__
|
||||||
|
#define __PN532_H__
|
||||||
|
|
||||||
|
#include <stdint.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)
|
||||||
|
|
||||||
|
// Prefixes for NDEF Records (to identify record type)
|
||||||
|
#define NDEF_URIPREFIX_NONE (0x00)
|
||||||
|
#define NDEF_URIPREFIX_HTTP_WWWDOT (0x01)
|
||||||
|
#define NDEF_URIPREFIX_HTTPS_WWWDOT (0x02)
|
||||||
|
#define NDEF_URIPREFIX_HTTP (0x03)
|
||||||
|
#define NDEF_URIPREFIX_HTTPS (0x04)
|
||||||
|
#define NDEF_URIPREFIX_TEL (0x05)
|
||||||
|
#define NDEF_URIPREFIX_MAILTO (0x06)
|
||||||
|
#define NDEF_URIPREFIX_FTP_ANONAT (0x07)
|
||||||
|
#define NDEF_URIPREFIX_FTP_FTPDOT (0x08)
|
||||||
|
#define NDEF_URIPREFIX_FTPS (0x09)
|
||||||
|
#define NDEF_URIPREFIX_SFTP (0x0A)
|
||||||
|
#define NDEF_URIPREFIX_SMB (0x0B)
|
||||||
|
#define NDEF_URIPREFIX_NFS (0x0C)
|
||||||
|
#define NDEF_URIPREFIX_FTP (0x0D)
|
||||||
|
#define NDEF_URIPREFIX_DAV (0x0E)
|
||||||
|
#define NDEF_URIPREFIX_NEWS (0x0F)
|
||||||
|
#define NDEF_URIPREFIX_TELNET (0x10)
|
||||||
|
#define NDEF_URIPREFIX_IMAP (0x11)
|
||||||
|
#define NDEF_URIPREFIX_RTSP (0x12)
|
||||||
|
#define NDEF_URIPREFIX_URN (0x13)
|
||||||
|
#define NDEF_URIPREFIX_POP (0x14)
|
||||||
|
#define NDEF_URIPREFIX_SIP (0x15)
|
||||||
|
#define NDEF_URIPREFIX_SIPS (0x16)
|
||||||
|
#define NDEF_URIPREFIX_TFTP (0x17)
|
||||||
|
#define NDEF_URIPREFIX_BTSPP (0x18)
|
||||||
|
#define NDEF_URIPREFIX_BTL2CAP (0x19)
|
||||||
|
#define NDEF_URIPREFIX_BTGOEP (0x1A)
|
||||||
|
#define NDEF_URIPREFIX_TCPOBEX (0x1B)
|
||||||
|
#define NDEF_URIPREFIX_IRDAOBEX (0x1C)
|
||||||
|
#define NDEF_URIPREFIX_FILE (0x1D)
|
||||||
|
#define NDEF_URIPREFIX_URN_EPC_ID (0x1E)
|
||||||
|
#define NDEF_URIPREFIX_URN_EPC_TAG (0x1F)
|
||||||
|
#define NDEF_URIPREFIX_URN_EPC_PAT (0x20)
|
||||||
|
#define NDEF_URIPREFIX_URN_EPC_RAW (0x21)
|
||||||
|
#define NDEF_URIPREFIX_URN_EPC (0x22)
|
||||||
|
#define NDEF_URIPREFIX_URN_NFC (0x23)
|
||||||
|
|
||||||
|
#define PN532_GPIO_VALIDATIONBIT (0x80)
|
||||||
|
#define PN532_GPIO_P30 (0)
|
||||||
|
#define PN532_GPIO_P31 (1)
|
||||||
|
#define PN532_GPIO_P32 (2)
|
||||||
|
#define PN532_GPIO_P33 (3)
|
||||||
|
#define PN532_GPIO_P34 (4)
|
||||||
|
#define PN532_GPIO_P35 (5)
|
||||||
|
|
||||||
|
// 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 writeGPIO(uint8_t pinstate);
|
||||||
|
uint8_t readGPIO(void);
|
||||||
|
bool setPassiveActivationRetries(uint8_t maxRetries);
|
||||||
|
bool setRFField(uint8_t autoRFCA, uint8_t rFOnOff);
|
||||||
|
bool powerDownMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 startPassiveTargetIDDetection(uint8_t cardbaudrate);
|
||||||
|
bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 1000, bool inlist = false);
|
||||||
|
bool inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength);
|
||||||
|
bool inCommunicateThru(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);
|
||||||
|
uint8_t mifareclassic_FormatNDEF (void);
|
||||||
|
uint8_t mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char *url);
|
||||||
|
|
||||||
|
// Mifare Ultralight functions
|
||||||
|
uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t *buffer);
|
||||||
|
uint8_t mifareultralight_WritePage (uint8_t page, uint8_t *buffer);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// Help functions to display formatted text
|
||||||
|
static void PrintHex(const uint8_t *data, const uint32_t numBytes);
|
||||||
|
static void PrintHexChar(const uint8_t *pbtData, const uint32_t numBytes);
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#ifndef __PN532_INTERFACE_H__
|
||||||
|
#define __PN532_INTERFACE_H__
|
||||||
|
|
||||||
|
#include <stdint.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
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef __DEBUG_H__
|
||||||
|
#define __DEBUG_H__
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
|
||||||
|
#define SERIAL SerialUSB
|
||||||
|
#else
|
||||||
|
#define SERIAL Serial
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DMSG(args...) SERIAL.print(args)
|
||||||
|
#define DMSG_STR(str) SERIAL.println(str)
|
||||||
|
#define DMSG_HEX(num) SERIAL.print(' '); SERIAL.print((num>>4)&0x0F, HEX); SERIAL.print(num&0x0F, HEX)
|
||||||
|
#define DMSG_INT(num) SERIAL.print(' '); SERIAL.print(num)
|
||||||
|
#else
|
||||||
|
#define DMSG(args...)
|
||||||
|
#define DMSG_STR(str)
|
||||||
|
#define DMSG_HEX(num)
|
||||||
|
#define DMSG_INT(num)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
## NFC library for Arduino
|
||||||
|
|
||||||
|
This is an Arduino library for PN532 to use NFC technology.
|
||||||
|
It works with
|
||||||
|
|
||||||
|
+ [NFC Shield](http://goo.gl/Cac2OH)
|
||||||
|
+ [Xadow NFC](http://goo.gl/qBZMt0)
|
||||||
|
+ [PN532 NFC/RFID controller breakout board](http://goo.gl/tby9Sw)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
+ Support I2C, SPI and HSU of PN532
|
||||||
|
+ Read/write Mifare Classic Card
|
||||||
|
+ Works with [Don's NDEF Library](http://goo.gl/jDjsXl)
|
||||||
|
+ Support Peer to Peer communication(exchange data with android 4.0+)
|
||||||
|
+ Support [mbed platform](http://goo.gl/kGPovZ)
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
1. Download [zip file](http://goo.gl/F6beRM) and
|
||||||
|
extract the 4 folders(PN532, PN532_SPI, PN532_I2C and PN532_HSU) into Arduino's libraries.
|
||||||
|
2. Downlaod [Don's NDEF library](http://goo.gl/ewxeAe) and extract it intro Arduino's libraries.
|
||||||
|
3. Follow the examples of the two libraries.
|
||||||
|
|
||||||
|
### To do
|
||||||
|
+ Card emulation
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
It's based on [Adafruit_NFCShield_I2C](http://goo.gl/pk3FdB).
|
||||||
|
[Seeed Studio](http://goo.gl/zh1iQh) adds SPI interface and peer to peer communication support.
|
||||||
|
@Don writes the [NDEF library](http://goo.gl/jDjsXl) to make it more easy to use.
|
||||||
|
@JiapengLi adds HSU interface.
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@file emulatetag.cpp
|
||||||
|
@author Armin Wieser
|
||||||
|
@license BSD
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "emulatetag.h"
|
||||||
|
#include "PN532_debug.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MAX_TGREAD
|
||||||
|
|
||||||
|
// Command APDU
|
||||||
|
#define C_APDU_CLA 0
|
||||||
|
#define C_APDU_INS 1 // instruction
|
||||||
|
#define C_APDU_P1 2 // parameter 1
|
||||||
|
#define C_APDU_P2 3 // parameter 2
|
||||||
|
#define C_APDU_LC 4 // length command
|
||||||
|
#define C_APDU_DATA 5 // data
|
||||||
|
|
||||||
|
#define C_APDU_P1_SELECT_BY_ID 0x00
|
||||||
|
#define C_APDU_P1_SELECT_BY_NAME 0x04
|
||||||
|
|
||||||
|
// Response APDU
|
||||||
|
#define R_APDU_SW1_COMMAND_COMPLETE 0x90
|
||||||
|
#define R_APDU_SW2_COMMAND_COMPLETE 0x00
|
||||||
|
|
||||||
|
#define R_APDU_SW1_NDEF_TAG_NOT_FOUND 0x6a
|
||||||
|
#define R_APDU_SW2_NDEF_TAG_NOT_FOUND 0x82
|
||||||
|
|
||||||
|
#define R_APDU_SW1_FUNCTION_NOT_SUPPORTED 0x6A
|
||||||
|
#define R_APDU_SW2_FUNCTION_NOT_SUPPORTED 0x81
|
||||||
|
|
||||||
|
#define R_APDU_SW1_MEMORY_FAILURE 0x65
|
||||||
|
#define R_APDU_SW2_MEMORY_FAILURE 0x81
|
||||||
|
|
||||||
|
#define R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x62
|
||||||
|
#define R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x82
|
||||||
|
|
||||||
|
// ISO7816-4 commands
|
||||||
|
#define ISO7816_SELECT_FILE 0xA4
|
||||||
|
#define ISO7816_READ_BINARY 0xB0
|
||||||
|
#define ISO7816_UPDATE_BINARY 0xD6
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
CC,
|
||||||
|
NDEF
|
||||||
|
} tag_file; // CC ... Compatibility Container
|
||||||
|
|
||||||
|
bool EmulateTag::init()
|
||||||
|
{
|
||||||
|
pn532.begin();
|
||||||
|
return pn532.SAMConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulateTag::setNdefFile(const uint8_t *ndef, const int16_t ndefLength)
|
||||||
|
{
|
||||||
|
if (ndefLength > (NDEF_MAX_LENGTH - 2))
|
||||||
|
{
|
||||||
|
DMSG("ndef file too large (> NDEF_MAX_LENGHT -2) - aborting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ndef_file[0] = ndefLength >> 8;
|
||||||
|
ndef_file[1] = ndefLength & 0xFF;
|
||||||
|
memcpy(ndef_file + 2, ndef, ndefLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulateTag::setUid(uint8_t *uid)
|
||||||
|
{
|
||||||
|
uidPtr = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EmulateTag::emulate(const uint16_t tgInitAsTargetTimeout)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t command[] = {
|
||||||
|
PN532_COMMAND_TGINITASTARGET,
|
||||||
|
5, // MODE: PICC only, Passive only
|
||||||
|
|
||||||
|
0x04, 0x00, // SENS_RES
|
||||||
|
0x00, 0x00, 0x00, // NFCID1
|
||||||
|
0x20, // SEL_RES
|
||||||
|
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // FeliCaParams
|
||||||
|
0, 0,
|
||||||
|
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // NFCID3t
|
||||||
|
|
||||||
|
0, // length of general bytes
|
||||||
|
0 // length of historical bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
if (uidPtr != 0)
|
||||||
|
{ // if uid is set copy 3 bytes to nfcid1
|
||||||
|
memcpy(command + 4, uidPtr, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 != pn532.tgInitAsTarget(command, sizeof(command), tgInitAsTargetTimeout))
|
||||||
|
{
|
||||||
|
DMSG("tgInitAsTarget failed or timed out!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t compatibility_container[] = {
|
||||||
|
0, 0x0F,
|
||||||
|
0x20,
|
||||||
|
0, 0x54,
|
||||||
|
0, 0xFF,
|
||||||
|
0x04, // T
|
||||||
|
0x06, // L
|
||||||
|
0xE1, 0x04, // File identifier
|
||||||
|
((NDEF_MAX_LENGTH & 0xFF00) >> 8), (NDEF_MAX_LENGTH & 0xFF), // maximum NDEF file size
|
||||||
|
0x00, // read access 0x0 = granted
|
||||||
|
0x00 // write access 0x0 = granted | 0xFF = deny
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tagWriteable == false)
|
||||||
|
{
|
||||||
|
compatibility_container[14] = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
tagWrittenByInitiator = false;
|
||||||
|
|
||||||
|
uint8_t rwbuf[128];
|
||||||
|
uint8_t sendlen;
|
||||||
|
int16_t status;
|
||||||
|
tag_file currentFile = NONE;
|
||||||
|
uint16_t cc_size = sizeof(compatibility_container);
|
||||||
|
bool runLoop = true;
|
||||||
|
|
||||||
|
while (runLoop)
|
||||||
|
{
|
||||||
|
status = pn532.tgGetData(rwbuf, sizeof(rwbuf));
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
DMSG("tgGetData failed!\n");
|
||||||
|
pn532.inRelease();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t p1 = rwbuf[C_APDU_P1];
|
||||||
|
uint8_t p2 = rwbuf[C_APDU_P2];
|
||||||
|
uint8_t lc = rwbuf[C_APDU_LC];
|
||||||
|
uint16_t p1p2_length = ((int16_t)p1 << 8) + p2;
|
||||||
|
|
||||||
|
switch (rwbuf[C_APDU_INS])
|
||||||
|
{
|
||||||
|
case ISO7816_SELECT_FILE:
|
||||||
|
switch (p1)
|
||||||
|
{
|
||||||
|
case C_APDU_P1_SELECT_BY_ID:
|
||||||
|
if (p2 != 0x0c)
|
||||||
|
{
|
||||||
|
DMSG("C_APDU_P2 != 0x0c\n");
|
||||||
|
setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
else if (lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA + 1] == 0x03 || rwbuf[C_APDU_DATA + 1] == 0x04))
|
||||||
|
{
|
||||||
|
setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
|
||||||
|
if (rwbuf[C_APDU_DATA + 1] == 0x03)
|
||||||
|
{
|
||||||
|
currentFile = CC;
|
||||||
|
}
|
||||||
|
else if (rwbuf[C_APDU_DATA + 1] == 0x04)
|
||||||
|
{
|
||||||
|
currentFile = NDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case C_APDU_P1_SELECT_BY_NAME:
|
||||||
|
const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
|
||||||
|
if (0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2)))
|
||||||
|
{
|
||||||
|
setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DMSG("function not supported\n");
|
||||||
|
setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ISO7816_READ_BINARY:
|
||||||
|
switch (currentFile)
|
||||||
|
{
|
||||||
|
case NONE:
|
||||||
|
setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
|
||||||
|
break;
|
||||||
|
case CC:
|
||||||
|
if (p1p2_length > NDEF_MAX_LENGTH)
|
||||||
|
{
|
||||||
|
setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(rwbuf, compatibility_container + p1p2_length, lc);
|
||||||
|
setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NDEF:
|
||||||
|
if (p1p2_length > NDEF_MAX_LENGTH)
|
||||||
|
{
|
||||||
|
setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(rwbuf, ndef_file + p1p2_length, lc);
|
||||||
|
setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ISO7816_UPDATE_BINARY:
|
||||||
|
if (!tagWriteable)
|
||||||
|
{
|
||||||
|
setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p1p2_length > NDEF_MAX_LENGTH)
|
||||||
|
{
|
||||||
|
setResponse(MEMORY_FAILURE, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(ndef_file + p1p2_length, rwbuf + C_APDU_DATA, lc);
|
||||||
|
setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
|
||||||
|
tagWrittenByInitiator = true;
|
||||||
|
|
||||||
|
uint16_t ndef_length = (ndef_file[0] << 8) + ndef_file[1];
|
||||||
|
if ((ndef_length > 0) && (updateNdefCallback != 0))
|
||||||
|
{
|
||||||
|
updateNdefCallback(ndef_file + 2, ndef_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DMSG("Command not supported!");
|
||||||
|
DMSG_HEX(rwbuf[C_APDU_INS]);
|
||||||
|
DMSG("\n");
|
||||||
|
setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
|
||||||
|
}
|
||||||
|
status = pn532.tgSetData(rwbuf, sendlen);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
DMSG("tgSetData failed\n!");
|
||||||
|
pn532.inRelease();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pn532.inRelease();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmulateTag::setResponse(responseCommand cmd, uint8_t *buf, uint8_t *sendlen, uint8_t sendlenOffset)
|
||||||
|
{
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case COMMAND_COMPLETE:
|
||||||
|
buf[0] = R_APDU_SW1_COMMAND_COMPLETE;
|
||||||
|
buf[1] = R_APDU_SW2_COMMAND_COMPLETE;
|
||||||
|
*sendlen = 2 + sendlenOffset;
|
||||||
|
break;
|
||||||
|
case TAG_NOT_FOUND:
|
||||||
|
buf[0] = R_APDU_SW1_NDEF_TAG_NOT_FOUND;
|
||||||
|
buf[1] = R_APDU_SW2_NDEF_TAG_NOT_FOUND;
|
||||||
|
*sendlen = 2;
|
||||||
|
break;
|
||||||
|
case FUNCTION_NOT_SUPPORTED:
|
||||||
|
buf[0] = R_APDU_SW1_FUNCTION_NOT_SUPPORTED;
|
||||||
|
buf[1] = R_APDU_SW2_FUNCTION_NOT_SUPPORTED;
|
||||||
|
*sendlen = 2;
|
||||||
|
break;
|
||||||
|
case MEMORY_FAILURE:
|
||||||
|
buf[0] = R_APDU_SW1_MEMORY_FAILURE;
|
||||||
|
buf[1] = R_APDU_SW2_MEMORY_FAILURE;
|
||||||
|
*sendlen = 2;
|
||||||
|
break;
|
||||||
|
case END_OF_FILE_BEFORE_REACHED_LE_BYTES:
|
||||||
|
buf[0] = R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
|
||||||
|
buf[1] = R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
|
||||||
|
*sendlen = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@file PN532/PN532/emulatetag.h
|
||||||
|
@author Armin Wieser
|
||||||
|
@license BSD
|
||||||
|
|
||||||
|
Implemented using NFC forum documents & library of libnfc
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __EMULATETAG_H__
|
||||||
|
#define __EMULATETAG_H__
|
||||||
|
|
||||||
|
#include "PN532.h"
|
||||||
|
|
||||||
|
#define NDEF_MAX_LENGTH 128 // altough ndef can handle up to 0xfffe in size, arduino cannot.
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
COMMAND_COMPLETE,
|
||||||
|
TAG_NOT_FOUND,
|
||||||
|
FUNCTION_NOT_SUPPORTED,
|
||||||
|
MEMORY_FAILURE,
|
||||||
|
END_OF_FILE_BEFORE_REACHED_LE_BYTES
|
||||||
|
} responseCommand;
|
||||||
|
|
||||||
|
class EmulateTag
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
EmulateTag(PN532Interface &interface) : pn532(interface), uidPtr(0), tagWrittenByInitiator(false), tagWriteable(true), updateNdefCallback(0) {}
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
bool emulate(const uint16_t tgInitAsTargetTimeout = 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param uid pointer to byte array of length 3 (uid is 4 bytes - first byte is fixed) or zero for uid
|
||||||
|
*/
|
||||||
|
void setUid(uint8_t *uid = 0);
|
||||||
|
|
||||||
|
void setNdefFile(const uint8_t *ndef, const int16_t ndefLength);
|
||||||
|
|
||||||
|
void getContent(uint8_t **buf, uint16_t *length)
|
||||||
|
{
|
||||||
|
*buf = ndef_file + 2; // first 2 bytes = length
|
||||||
|
*length = (ndef_file[0] << 8) + ndef_file[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeOccured()
|
||||||
|
{
|
||||||
|
return tagWrittenByInitiator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTagWriteable(bool setWriteable)
|
||||||
|
{
|
||||||
|
tagWriteable = setWriteable;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *getNdefFilePtr()
|
||||||
|
{
|
||||||
|
return ndef_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getNdefMaxLength()
|
||||||
|
{
|
||||||
|
return NDEF_MAX_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void attach(void (*func)(uint8_t *buf, uint16_t length))
|
||||||
|
{
|
||||||
|
updateNdefCallback = func;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
PN532 pn532;
|
||||||
|
uint8_t ndef_file[NDEF_MAX_LENGTH];
|
||||||
|
uint8_t *uidPtr;
|
||||||
|
bool tagWrittenByInitiator;
|
||||||
|
bool tagWriteable;
|
||||||
|
void (*updateNdefCallback)(uint8_t *ndef, uint16_t length);
|
||||||
|
|
||||||
|
void setResponse(responseCommand cmd, uint8_t *buf, uint8_t *sendlen, uint8_t sendlenOffset = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
This example will attempt to connect to an FeliCa
|
||||||
|
card or tag and retrieve some basic information about it
|
||||||
|
that can be used to determine what type of card it is.
|
||||||
|
|
||||||
|
Note that you need the baud rate to be 115200 because we need to print
|
||||||
|
out the data and read from the card at the same time!
|
||||||
|
|
||||||
|
To enable debug message, define DEBUG in PN532/PN532_debug.h
|
||||||
|
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532_SPI.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
#elif 0
|
||||||
|
#include <PN532_HSU.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_I2C pn532i2c(Wire);
|
||||||
|
PN532 nfc(pn532i2c);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <PN532_debug.h>
|
||||||
|
|
||||||
|
uint8_t _prevIDm[8];
|
||||||
|
unsigned long _prevTime;
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Hello!");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (!versiondata)
|
||||||
|
{
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1) {delay(10);}; // halt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
|
||||||
|
Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// Set the max number of retry attempts to read from a card
|
||||||
|
// This prevents us from waiting forever for a card, which is
|
||||||
|
// the default behaviour of the PN532.
|
||||||
|
nfc.setPassiveActivationRetries(0xFF);
|
||||||
|
nfc.SAMConfig();
|
||||||
|
|
||||||
|
memset(_prevIDm, 0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
uint16_t systemCode = 0xFFFF;
|
||||||
|
uint8_t requestCode = 0x01; // System Code request
|
||||||
|
uint8_t idm[8];
|
||||||
|
uint8_t pmm[8];
|
||||||
|
uint16_t systemCodeResponse;
|
||||||
|
|
||||||
|
// Wait for an FeliCa type cards.
|
||||||
|
// When one is found, some basic information such as IDm, PMm, and System Code are retrieved.
|
||||||
|
Serial.print("Waiting for an FeliCa card... ");
|
||||||
|
ret = nfc.felica_Polling(systemCode, requestCode, idm, pmm, &systemCodeResponse, 5000);
|
||||||
|
|
||||||
|
if (ret != 1)
|
||||||
|
{
|
||||||
|
Serial.println("Could not find a card");
|
||||||
|
delay(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( memcmp(idm, _prevIDm, 8) == 0 ) {
|
||||||
|
if ( (millis() - _prevTime) < 3000 ) {
|
||||||
|
Serial.println("Same card");
|
||||||
|
delay(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Found a card!");
|
||||||
|
Serial.print(" IDm: ");
|
||||||
|
nfc.PrintHex(idm, 8);
|
||||||
|
Serial.print(" PMm: ");
|
||||||
|
nfc.PrintHex(pmm, 8);
|
||||||
|
Serial.print(" System Code: ");
|
||||||
|
Serial.print(systemCodeResponse, HEX);
|
||||||
|
Serial.print("\n");
|
||||||
|
|
||||||
|
memcpy(_prevIDm, idm, 8);
|
||||||
|
_prevTime = millis();
|
||||||
|
|
||||||
|
// Wait 1 second before continuing
|
||||||
|
Serial.println("Card access completed!\n");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
This example will attempt to connect to an FeliCa
|
||||||
|
card or tag and retrieve some basic information about it
|
||||||
|
that can be used to determine what type of card it is.
|
||||||
|
|
||||||
|
Note that you need the baud rate to be 115200 because we need to print
|
||||||
|
out the data and read from the card at the same time!
|
||||||
|
|
||||||
|
To enable debug message, define DEBUG in PN532/PN532_debug.h
|
||||||
|
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532_SPI.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
#elif 0
|
||||||
|
#include <PN532_HSU.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_I2C pn532i2c(Wire);
|
||||||
|
PN532 nfc(pn532i2c);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <PN532_debug.h>
|
||||||
|
|
||||||
|
uint8_t _prevIDm[8];
|
||||||
|
unsigned long _prevTime;
|
||||||
|
|
||||||
|
void PrintHex8(const uint8_t d) {
|
||||||
|
Serial.print(" ");
|
||||||
|
Serial.print( (d >> 4) & 0x0F, HEX);
|
||||||
|
Serial.print( d & 0x0F, HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(void)
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Hello!");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (!versiondata)
|
||||||
|
{
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1) {delay(10);}; // halt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
|
||||||
|
Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// Set the max number of retry attempts to read from a card
|
||||||
|
// This prevents us from waiting forever for a card, which is
|
||||||
|
// the default behaviour of the PN532.
|
||||||
|
nfc.setPassiveActivationRetries(0xFF);
|
||||||
|
nfc.SAMConfig();
|
||||||
|
|
||||||
|
memset(_prevIDm, 0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
uint16_t systemCode = 0xFFFF;
|
||||||
|
uint8_t requestCode = 0x01; // System Code request
|
||||||
|
uint8_t idm[8];
|
||||||
|
uint8_t pmm[8];
|
||||||
|
uint16_t systemCodeResponse;
|
||||||
|
|
||||||
|
// Wait for an FeliCa type cards.
|
||||||
|
// When one is found, some basic information such as IDm, PMm, and System Code are retrieved.
|
||||||
|
Serial.print("Waiting for an FeliCa card... ");
|
||||||
|
ret = nfc.felica_Polling(systemCode, requestCode, idm, pmm, &systemCodeResponse, 5000);
|
||||||
|
|
||||||
|
if (ret != 1)
|
||||||
|
{
|
||||||
|
Serial.println("Could not find a card");
|
||||||
|
delay(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( memcmp(idm, _prevIDm, 8) == 0 ) {
|
||||||
|
if ( (millis() - _prevTime) < 3000 ) {
|
||||||
|
Serial.println("Same card");
|
||||||
|
delay(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Found a card!");
|
||||||
|
Serial.print(" IDm: ");
|
||||||
|
nfc.PrintHex(idm, 8);
|
||||||
|
Serial.print(" PMm: ");
|
||||||
|
nfc.PrintHex(pmm, 8);
|
||||||
|
Serial.print(" System Code: ");
|
||||||
|
Serial.print(systemCodeResponse, HEX);
|
||||||
|
Serial.print("\n");
|
||||||
|
|
||||||
|
memcpy(_prevIDm, idm, 8);
|
||||||
|
_prevTime = millis();
|
||||||
|
|
||||||
|
uint8_t blockData[3][16];
|
||||||
|
uint16_t serviceCodeList[1];
|
||||||
|
uint16_t blockList[3];
|
||||||
|
|
||||||
|
Serial.println("Write Without Encryption command ");
|
||||||
|
serviceCodeList[0] = 0x0009;
|
||||||
|
blockList[0] = 0x8000;
|
||||||
|
unsigned long now = millis();
|
||||||
|
blockData[0][3] = now & 0xFF;
|
||||||
|
blockData[0][2] = (now >>= 8) & 0xFF;
|
||||||
|
blockData[0][1] = (now >>= 8) & 0xFF;
|
||||||
|
blockData[0][0] = (now >>= 8) & 0xFF;
|
||||||
|
Serial.print(" Writing current millis (");
|
||||||
|
PrintHex8(blockData[0][0]);
|
||||||
|
PrintHex8(blockData[0][1]);
|
||||||
|
PrintHex8(blockData[0][2]);
|
||||||
|
PrintHex8(blockData[0][3]);
|
||||||
|
Serial.print(" ) to Block 0 -> ");
|
||||||
|
ret = nfc.felica_WriteWithoutEncryption(1, serviceCodeList, 1, blockList, blockData);
|
||||||
|
if (ret != 1)
|
||||||
|
{
|
||||||
|
Serial.println("error");
|
||||||
|
} else {
|
||||||
|
Serial.println("OK!");
|
||||||
|
}
|
||||||
|
memset(blockData[0], 0, 16);
|
||||||
|
|
||||||
|
Serial.print("Read Without Encryption command -> ");
|
||||||
|
serviceCodeList[0] = 0x000B;
|
||||||
|
blockList[0] = 0x8000;
|
||||||
|
blockList[1] = 0x8001;
|
||||||
|
blockList[2] = 0x8002;
|
||||||
|
ret = nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 3, blockList, blockData);
|
||||||
|
if (ret != 1)
|
||||||
|
{
|
||||||
|
Serial.println("error");
|
||||||
|
} else {
|
||||||
|
Serial.println("OK!");
|
||||||
|
for(int i=0; i<3; i++ ) {
|
||||||
|
Serial.print(" Block no. "); Serial.print(i, DEC); Serial.print(": ");
|
||||||
|
nfc.PrintHex(blockData[i], 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait 1 second before continuing
|
||||||
|
Serial.println("Card access completed!\n");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
#if 0
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532/PN532/PN532_SPI.h>
|
||||||
|
#include "PN532/PN532/PN532.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
#elif 1
|
||||||
|
#include <PN532/PN532/PN532_HSU.h>
|
||||||
|
#include <PN532/PN532/PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("-------Peer to Peer HCE--------");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (!versiondata)
|
||||||
|
{
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1)
|
||||||
|
; // halt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5");
|
||||||
|
Serial.println((versiondata >> 24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. ");
|
||||||
|
Serial.print((versiondata >> 16) & 0xFF, DEC);
|
||||||
|
Serial.print('.');
|
||||||
|
Serial.println((versiondata >> 8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// Set the max number of retry attempts to read from a card
|
||||||
|
// This prevents us from waiting forever for a card, which is
|
||||||
|
// the default behaviour of the PN532.
|
||||||
|
//nfc.setPassiveActivationRetries(0xFF);
|
||||||
|
|
||||||
|
// configure board to read RFID tags
|
||||||
|
nfc.SAMConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
uint8_t responseLength = 32;
|
||||||
|
|
||||||
|
Serial.println("Waiting for an ISO14443A card");
|
||||||
|
|
||||||
|
// set shield to inListPassiveTarget
|
||||||
|
success = nfc.inListPassiveTarget();
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.println("Found something!");
|
||||||
|
|
||||||
|
uint8_t selectApdu[] = {0x00, /* CLA */
|
||||||
|
0xA4, /* INS */
|
||||||
|
0x04, /* P1 */
|
||||||
|
0x00, /* P2 */
|
||||||
|
0x07, /* Length of AID */
|
||||||
|
0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* AID defined on Android App */
|
||||||
|
0x00 /* Le */};
|
||||||
|
|
||||||
|
uint8_t response[32];
|
||||||
|
|
||||||
|
success = nfc.inDataExchange(selectApdu, sizeof(selectApdu), response, &responseLength);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.print("responseLength: ");
|
||||||
|
Serial.println(responseLength);
|
||||||
|
|
||||||
|
nfc.PrintHexChar(response, responseLength);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
uint8_t apdu[] = "Hello from Arduino";
|
||||||
|
uint8_t back[32];
|
||||||
|
uint8_t length = 32;
|
||||||
|
|
||||||
|
success = nfc.inDataExchange(apdu, sizeof(apdu), back, &length);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.print("responseLength: ");
|
||||||
|
Serial.println(length);
|
||||||
|
|
||||||
|
nfc.PrintHexChar(back, length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.println("Broken connection?");
|
||||||
|
}
|
||||||
|
} while (success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.println("Failed sending SELECT AID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.println("Didn't find anything!");
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printResponse(uint8_t *response, uint8_t responseLength)
|
||||||
|
{
|
||||||
|
|
||||||
|
String respBuffer;
|
||||||
|
|
||||||
|
for (int i = 0; i < responseLength; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (response[i] < 0x10)
|
||||||
|
respBuffer = respBuffer + "0"; //Adds leading zeros if hex value is smaller than 0x10
|
||||||
|
|
||||||
|
respBuffer = respBuffer + String(response[i], HEX) + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("response: ");
|
||||||
|
Serial.println(respBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupNFC()
|
||||||
|
{
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (!versiondata)
|
||||||
|
{
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1)
|
||||||
|
; // halt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5");
|
||||||
|
Serial.println((versiondata >> 24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. ");
|
||||||
|
Serial.print((versiondata >> 16) & 0xFF, DEC);
|
||||||
|
Serial.print('.');
|
||||||
|
Serial.println((versiondata >> 8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// configure board to read RFID tags
|
||||||
|
nfc.SAMConfig();
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#include "PN532/PN532/emulatetag.h"
|
||||||
|
#include "NdefMessage.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532/PN532/PN532_SPI.h>
|
||||||
|
#include "PN532/PN532/PN532.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
EmulateTag nfc(pn532spi);
|
||||||
|
#elif 1
|
||||||
|
#include <PN532/PN532/PN532_HSU.h>
|
||||||
|
#include <PN532/PN532/PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
EmulateTag nfc(pn532hsu);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t ndefBuf[120];
|
||||||
|
NdefMessage message;
|
||||||
|
int messageSize;
|
||||||
|
|
||||||
|
uint8_t uid[3] = {0x12, 0x34, 0x56};
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("------- Emulate Tag --------");
|
||||||
|
|
||||||
|
message = NdefMessage();
|
||||||
|
message.addUriRecord("http://www.seeedstudio.com");
|
||||||
|
messageSize = message.getEncodedSize();
|
||||||
|
if (messageSize > sizeof(ndefBuf))
|
||||||
|
{
|
||||||
|
Serial.println("ndefBuf is too small");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("Ndef encoded message size: ");
|
||||||
|
Serial.println(messageSize);
|
||||||
|
|
||||||
|
message.encode(ndefBuf);
|
||||||
|
|
||||||
|
// comment out this command for no ndef message
|
||||||
|
nfc.setNdefFile(ndefBuf, messageSize);
|
||||||
|
|
||||||
|
// uid must be 3 bytes!
|
||||||
|
nfc.setUid(uid);
|
||||||
|
|
||||||
|
nfc.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
// uncomment for overriding ndef in case a write to this tag occured
|
||||||
|
//nfc.setNdefFile(ndefBuf, messageSize);
|
||||||
|
|
||||||
|
// start emulation (blocks)
|
||||||
|
nfc.emulate();
|
||||||
|
|
||||||
|
// or start emulation with timeout
|
||||||
|
/*if(!nfc.emulate(1000)){ // timeout 1 second
|
||||||
|
Serial.println("timed out");
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// deny writing to the tag
|
||||||
|
// nfc.setTagWriteable(false);
|
||||||
|
|
||||||
|
if (nfc.writeOccured())
|
||||||
|
{
|
||||||
|
Serial.println("\nWrite occured !");
|
||||||
|
uint8_t *tag_buf;
|
||||||
|
uint16_t length;
|
||||||
|
|
||||||
|
nfc.getContent(&tag_buf, &length);
|
||||||
|
NdefMessage msg = NdefMessage(tag_buf, length);
|
||||||
|
msg.print();
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
This example will attempt to connect to an ISO14443A
|
||||||
|
card or tag and retrieve some basic information about it
|
||||||
|
that can be used to determine what type of card it is.
|
||||||
|
|
||||||
|
Note that you need the baud rate to be 115200 because we need to print
|
||||||
|
out the data and read from the card at the same time!
|
||||||
|
|
||||||
|
To enable debug message, define DEBUG in PN532/PN532_debug.h
|
||||||
|
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* When the number after #if set as 1, it will be switch to SPI Mode*/
|
||||||
|
#if 0
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532_SPI.h>
|
||||||
|
#include "PN532.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
|
||||||
|
/* When the number after #elif set as 1, it will be switch to HSU Mode*/
|
||||||
|
#elif 0
|
||||||
|
#include <PN532_HSU.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
|
||||||
|
/* When the number after #if & #elif set as 0, it will be switch to I2C Mode*/
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_I2C pn532i2c(Wire);
|
||||||
|
PN532 nfc(pn532i2c);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Hello!");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (! versiondata) {
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1); // halt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||||
|
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// Set the max number of retry attempts to read from a card
|
||||||
|
// This prevents us from waiting forever for a card, which is
|
||||||
|
// the default behaviour of the PN532.
|
||||||
|
nfc.setPassiveActivationRetries(0xFF);
|
||||||
|
|
||||||
|
// configure board to read RFID tags
|
||||||
|
nfc.SAMConfig();
|
||||||
|
|
||||||
|
Serial.println("Waiting for an ISO14443A card");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
boolean success;
|
||||||
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||||
|
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||||
|
|
||||||
|
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||||
|
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||||
|
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||||
|
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
Serial.println("Found a card!");
|
||||||
|
Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||||
|
Serial.print("UID Value: ");
|
||||||
|
for (uint8_t i=0; i < uidLength; i++)
|
||||||
|
{
|
||||||
|
Serial.print(" 0x");Serial.print(uid[i], HEX);
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
// Wait 1 second before continuing
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// PN532 probably timed out waiting for a card
|
||||||
|
Serial.println("Timed out waiting for a card");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
This example attempts to format a clean Mifare Classic 1K card as
|
||||||
|
an NFC Forum tag (to store NDEF messages that can be read by any
|
||||||
|
NFC enabled Android phone, etc.)
|
||||||
|
|
||||||
|
Note that you need the baud rate to be 115200 because we need to print
|
||||||
|
out the data and read from the card at the same time!
|
||||||
|
|
||||||
|
To enable debug message, define DEBUG in PN532/PN532_debug.h
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532_SPI.h>
|
||||||
|
#include "PN532.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
#elif 1
|
||||||
|
#include <PN532_HSU.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
We can encode many different kinds of pointers to the card,
|
||||||
|
from a URL, to an Email address, to a phone number, and many more
|
||||||
|
check the library header .h file to see the large # of supported
|
||||||
|
prefixes!
|
||||||
|
*/
|
||||||
|
// For a http://www. url:
|
||||||
|
const char * url = "elechouse.com";
|
||||||
|
uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT;
|
||||||
|
|
||||||
|
// for an email address
|
||||||
|
//const char * url = "mail@example.com";
|
||||||
|
//uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO;
|
||||||
|
|
||||||
|
// for a phone number
|
||||||
|
//const char * url = "+1 212 555 1212";
|
||||||
|
//uint8_t ndefprefix = NDEF_URIPREFIX_TEL;
|
||||||
|
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Looking for PN532...");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (! versiondata) {
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1); // halt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||||
|
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// configure board to read RFID tags
|
||||||
|
nfc.SAMConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
uint8_t success; // Flag to check if there was an error with the PN532
|
||||||
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||||
|
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||||
|
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||||
|
|
||||||
|
// Use the default key
|
||||||
|
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("PLEASE NOTE: Formatting your card for NDEF records will change the");
|
||||||
|
Serial.println("authentication keys. To reformat your NDEF tag as a clean Mifare");
|
||||||
|
Serial.println("Classic tag, use the mifareclassic_ndeftoclassic example!");
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("Place your Mifare Classic card on the reader to format with NDEF");
|
||||||
|
Serial.println("and press any key to continue ...");
|
||||||
|
// Wait for user input before proceeding
|
||||||
|
while (!Serial.available());
|
||||||
|
// a key was pressed1
|
||||||
|
while (Serial.available()) Serial.read();
|
||||||
|
|
||||||
|
// Wait for an ISO14443A type card (Mifare, etc.). When one is found
|
||||||
|
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||||
|
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||||
|
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// Display some basic information about the card
|
||||||
|
Serial.println("Found an ISO14443A card");
|
||||||
|
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||||
|
Serial.print(" UID Value: ");
|
||||||
|
nfc.PrintHex(uid, uidLength);
|
||||||
|
for (uint8_t i = 0; i < uidLength; i++) {
|
||||||
|
Serial.print(uid[i], HEX);
|
||||||
|
Serial.print(' ');
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
// Make sure this is a Mifare Classic card
|
||||||
|
if (uidLength != 4)
|
||||||
|
{
|
||||||
|
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We probably have a Mifare Classic card ...
|
||||||
|
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||||
|
|
||||||
|
// Try to format the card for NDEF data
|
||||||
|
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 0, 0, keya);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
Serial.println("Unable to authenticate block 0 to enable card formatting!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
success = nfc.mifareclassic_FormatNDEF();
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
Serial.println("Unable to format the card for NDEF");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Card has been formatted for NDEF data using MAD1");
|
||||||
|
|
||||||
|
// Try to authenticate block 4 (first block of sector 1) using our key
|
||||||
|
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keya);
|
||||||
|
|
||||||
|
// Make sure the authentification process didn't fail
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
Serial.println("Authentication failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to write a URL
|
||||||
|
Serial.println("Writing URI to sector 1 as an NDEF Message");
|
||||||
|
|
||||||
|
// Authenticated seems to have worked
|
||||||
|
// Try to write an NDEF record to sector 1
|
||||||
|
// Use 0x01 for the URI Identifier Code to prepend "http://www."
|
||||||
|
// to the url (and save some space). For information on URI ID Codes
|
||||||
|
// see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef
|
||||||
|
if (strlen(url) > 38)
|
||||||
|
{
|
||||||
|
// The length is also checked in the WriteNDEFURI function, but lets
|
||||||
|
// warn users here just in case they change the value and it's bigger
|
||||||
|
// than it should be
|
||||||
|
Serial.println("URI is too long ... must be less than 38 characters long");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// URI is within size limits ... write it to the card and report success/failure
|
||||||
|
success = nfc.mifareclassic_WriteNDEFURI(1, ndefprefix, url);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Serial.println("NDEF URI Record written to sector 1");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("NDEF Record creation failed! :(");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait a bit before trying again
|
||||||
|
Serial.println("\n\nDone!");
|
||||||
|
delay(1000);
|
||||||
|
Serial.flush();
|
||||||
|
while(Serial.available()) Serial.read();
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
This example attempts to dump the contents of a Mifare Classic 1K card
|
||||||
|
|
||||||
|
Note that you need the baud rate to be 115200 because we need to print
|
||||||
|
out the data and read from the card at the same time!
|
||||||
|
|
||||||
|
To enable debug message, define DEBUG in PN532/PN532_debug.h
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532_SPI.h>
|
||||||
|
#include "PN532.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
#elif 1
|
||||||
|
#include <PN532_HSU.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_I2C pn532i2c(Wire);
|
||||||
|
PN532 nfc(pn532i2c);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
// has to be fast to dump the entire memory contents!
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Looking for PN532...");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (! versiondata) {
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1); // halt
|
||||||
|
}
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||||
|
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// configure board to read RFID tags
|
||||||
|
nfc.SAMConfig();
|
||||||
|
|
||||||
|
Serial.println("Waiting for an ISO14443A Card ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
uint8_t success; // Flag to check if there was an error with the PN532
|
||||||
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||||
|
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||||
|
uint8_t currentblock; // Counter to keep track of which block we're on
|
||||||
|
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||||
|
uint8_t data[16]; // Array to store block data during reads
|
||||||
|
|
||||||
|
// Keyb on NDEF and Mifare Classic should be the same
|
||||||
|
uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
|
||||||
|
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||||
|
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||||
|
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||||
|
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// Display some basic information about the card
|
||||||
|
Serial.println("Found an ISO14443A card");
|
||||||
|
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||||
|
Serial.print(" UID Value: ");
|
||||||
|
for (uint8_t i = 0; i < uidLength; i++) {
|
||||||
|
Serial.print(uid[i], HEX);
|
||||||
|
Serial.print(' ');
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
if (uidLength == 4)
|
||||||
|
{
|
||||||
|
// We probably have a Mifare Classic card ...
|
||||||
|
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||||
|
|
||||||
|
// Now we try to go through all 16 sectors (each having 4 blocks)
|
||||||
|
// authenticating each sector, and then dumping the blocks
|
||||||
|
for (currentblock = 0; currentblock < 64; currentblock++)
|
||||||
|
{
|
||||||
|
// Check if this is a new block so that we can reauthenticate
|
||||||
|
if (nfc.mifareclassic_IsFirstBlock(currentblock)) authenticated = false;
|
||||||
|
|
||||||
|
// If the sector hasn't been authenticated, do so first
|
||||||
|
if (!authenticated)
|
||||||
|
{
|
||||||
|
// Starting of a new sector ... try to to authenticate
|
||||||
|
Serial.print("------------------------Sector ");Serial.print(currentblock/4, DEC);Serial.println("-------------------------");
|
||||||
|
if (currentblock == 0)
|
||||||
|
{
|
||||||
|
// This will be 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF for Mifare Classic (non-NDEF!)
|
||||||
|
// or 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 for NDEF formatted cards using key a,
|
||||||
|
// but keyb should be the same for both (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF)
|
||||||
|
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This will be 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF for Mifare Classic (non-NDEF!)
|
||||||
|
// or 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 for NDEF formatted cards using key a,
|
||||||
|
// but keyb should be the same for both (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF)
|
||||||
|
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal);
|
||||||
|
}
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
authenticated = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("Authentication error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we're still not authenticated just skip the block
|
||||||
|
if (!authenticated)
|
||||||
|
{
|
||||||
|
Serial.print("Block ");Serial.print(currentblock, DEC);Serial.println(" unable to authenticate");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Authenticated ... we should be able to read the block now
|
||||||
|
// Dump the data into the 'data' array
|
||||||
|
success = nfc.mifareclassic_ReadDataBlock(currentblock, data);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// Read successful
|
||||||
|
Serial.print("Block ");Serial.print(currentblock, DEC);
|
||||||
|
if (currentblock < 10)
|
||||||
|
{
|
||||||
|
Serial.print(" ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.print(" ");
|
||||||
|
}
|
||||||
|
// Dump the raw data
|
||||||
|
nfc.PrintHexChar(data, 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Oops ... something happened
|
||||||
|
Serial.print("Block ");Serial.print(currentblock, DEC);
|
||||||
|
Serial.println(" unable to read this block");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait a bit before trying again
|
||||||
|
Serial.println("\n\nSend a character to run the mem dumper again!");
|
||||||
|
Serial.flush();
|
||||||
|
while (!Serial.available());
|
||||||
|
while (Serial.available()) {
|
||||||
|
Serial.read();
|
||||||
|
}
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
This examples attempts to take a Mifare Classic 1K card that has been
|
||||||
|
formatted for NDEF messages using mifareclassic_formatndef, and resets
|
||||||
|
the authentication keys back to the Mifare Classic defaults
|
||||||
|
|
||||||
|
To enable debug message, define DEBUG in PN532/PN532_debug.h
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532_SPI.h>
|
||||||
|
#include "PN532.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
#elif 1
|
||||||
|
#include <PN532_HSU.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NR_SHORTSECTOR (32) // Number of short sectors on Mifare 1K/4K
|
||||||
|
#define NR_LONGSECTOR (8) // Number of long sectors on Mifare 4K
|
||||||
|
#define NR_BLOCK_OF_SHORTSECTOR (4) // Number of blocks in a short sector
|
||||||
|
#define NR_BLOCK_OF_LONGSECTOR (16) // Number of blocks in a long sector
|
||||||
|
|
||||||
|
// Determine the sector trailer block based on sector number
|
||||||
|
#define BLOCK_NUMBER_OF_SECTOR_TRAILER(sector) (((sector)<NR_SHORTSECTOR)? \
|
||||||
|
((sector)*NR_BLOCK_OF_SHORTSECTOR + NR_BLOCK_OF_SHORTSECTOR-1):\
|
||||||
|
(NR_SHORTSECTOR*NR_BLOCK_OF_SHORTSECTOR + (sector-NR_SHORTSECTOR)*NR_BLOCK_OF_LONGSECTOR + NR_BLOCK_OF_LONGSECTOR-1))
|
||||||
|
|
||||||
|
// Determine the sector's first block based on the sector number
|
||||||
|
#define BLOCK_NUMBER_OF_SECTOR_1ST_BLOCK(sector) (((sector)<NR_SHORTSECTOR)? \
|
||||||
|
((sector)*NR_BLOCK_OF_SHORTSECTOR):\
|
||||||
|
(NR_SHORTSECTOR*NR_BLOCK_OF_SHORTSECTOR + (sector-NR_SHORTSECTOR)*NR_BLOCK_OF_LONGSECTOR))
|
||||||
|
|
||||||
|
// The default Mifare Classic key
|
||||||
|
static const uint8_t KEY_DEFAULT_KEYAB[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Looking for PN532...");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (! versiondata) {
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1); // halt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||||
|
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// configure board to read RFID tags
|
||||||
|
nfc.SAMConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
uint8_t success; // Flag to check if there was an error with the PN532
|
||||||
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||||
|
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||||
|
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||||
|
uint8_t blockBuffer[16]; // Buffer to store block contents
|
||||||
|
uint8_t blankAccessBits[3] = { 0xff, 0x07, 0x80 };
|
||||||
|
uint8_t idx = 0;
|
||||||
|
uint8_t numOfSector = 16; // Assume Mifare Classic 1K for now (16 4-block sectors)
|
||||||
|
|
||||||
|
Serial.println("Place your NDEF formatted Mifare Classic 1K card on the reader");
|
||||||
|
Serial.println("and press any key to continue ...");
|
||||||
|
|
||||||
|
// Wait for user input before proceeding
|
||||||
|
while (!Serial.available());
|
||||||
|
while (Serial.available()) Serial.read();
|
||||||
|
|
||||||
|
// Wait for an ISO14443A type card (Mifare, etc.). When one is found
|
||||||
|
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||||
|
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||||
|
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// We seem to have a tag ...
|
||||||
|
// Display some basic information about it
|
||||||
|
Serial.println("Found an ISO14443A card/tag");
|
||||||
|
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||||
|
Serial.print(" UID Value: ");
|
||||||
|
nfc.PrintHex(uid, uidLength);
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
// Make sure this is a Mifare Classic card
|
||||||
|
if (uidLength != 4)
|
||||||
|
{
|
||||||
|
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("Reformatting card for Mifare Classic (please don't touch it!) ... ");
|
||||||
|
|
||||||
|
// Now run through the card sector by sector
|
||||||
|
for (idx = 0; idx < numOfSector; idx++)
|
||||||
|
{
|
||||||
|
// Step 1: Authenticate the current sector using key B 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
|
||||||
|
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, BLOCK_NUMBER_OF_SECTOR_TRAILER(idx), 1, (uint8_t *)KEY_DEFAULT_KEYAB);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
Serial.print("Authentication failed for sector "); Serial.println(numOfSector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Write to the other blocks
|
||||||
|
if (idx == 16)
|
||||||
|
{
|
||||||
|
memset(blockBuffer, 0, sizeof(blockBuffer));
|
||||||
|
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 3, blockBuffer)))
|
||||||
|
{
|
||||||
|
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((idx == 0) || (idx == 16))
|
||||||
|
{
|
||||||
|
memset(blockBuffer, 0, sizeof(blockBuffer));
|
||||||
|
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 2, blockBuffer)))
|
||||||
|
{
|
||||||
|
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(blockBuffer, 0, sizeof(blockBuffer));
|
||||||
|
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 3, blockBuffer)))
|
||||||
|
{
|
||||||
|
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 2, blockBuffer)))
|
||||||
|
{
|
||||||
|
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memset(blockBuffer, 0, sizeof(blockBuffer));
|
||||||
|
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 1, blockBuffer)))
|
||||||
|
{
|
||||||
|
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Reset both keys to 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
|
||||||
|
memcpy(blockBuffer, KEY_DEFAULT_KEYAB, sizeof(KEY_DEFAULT_KEYAB));
|
||||||
|
memcpy(blockBuffer + 6, blankAccessBits, sizeof(blankAccessBits));
|
||||||
|
blockBuffer[9] = 0x69;
|
||||||
|
memcpy(blockBuffer + 10, KEY_DEFAULT_KEYAB, sizeof(KEY_DEFAULT_KEYAB));
|
||||||
|
|
||||||
|
// Step 4: Write the trailer block
|
||||||
|
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)), blockBuffer)))
|
||||||
|
{
|
||||||
|
Serial.print("Unable to write trailer block of sector "); Serial.println(numOfSector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait a bit before trying again
|
||||||
|
Serial.println("\n\nDone!");
|
||||||
|
delay(1000);
|
||||||
|
Serial.flush();
|
||||||
|
while(Serial.available()) Serial.read();
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
Updates a sector that is already formatted for NDEF (using
|
||||||
|
mifareclassic_formatndef.pde for example), inserting a new url
|
||||||
|
|
||||||
|
To enable debug message, define DEBUG in PN532/PN532_debug.h
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532_SPI.h>
|
||||||
|
#include "PN532.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
#elif 1
|
||||||
|
#include <PN532_HSU.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
We can encode many different kinds of pointers to the card,
|
||||||
|
from a URL, to an Email address, to a phone number, and many more
|
||||||
|
check the library header .h file to see the large # of supported
|
||||||
|
prefixes!
|
||||||
|
*/
|
||||||
|
// For a http://www. url:
|
||||||
|
const char * url = "elechouse.com";
|
||||||
|
uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT;
|
||||||
|
|
||||||
|
// for an email address
|
||||||
|
//const char * url = "mail@example.com";
|
||||||
|
//uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO;
|
||||||
|
|
||||||
|
// for a phone number
|
||||||
|
//const char * url = "+1 212 555 1212";
|
||||||
|
//uint8_t ndefprefix = NDEF_URIPREFIX_TEL;
|
||||||
|
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Looking for PN532...");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (! versiondata) {
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1); // halt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||||
|
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// configure board to read RFID tags
|
||||||
|
nfc.SAMConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
uint8_t success; // Flag to check if there was an error with the PN532
|
||||||
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||||
|
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||||
|
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||||
|
|
||||||
|
// Use the default NDEF keys (these would have have set by mifareclassic_formatndef.pde!)
|
||||||
|
uint8_t keya[6] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 };
|
||||||
|
uint8_t keyb[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 };
|
||||||
|
|
||||||
|
Serial.println("Place your NDEF formatted Mifare Classic card on the reader to update the");
|
||||||
|
Serial.println("NDEF record and press any key to continue ...");
|
||||||
|
// Wait for user input before proceeding
|
||||||
|
while (!Serial.available());
|
||||||
|
// a key was pressed1
|
||||||
|
while (Serial.available()) Serial.read();
|
||||||
|
|
||||||
|
// Wait for an ISO14443A type card (Mifare, etc.). When one is found
|
||||||
|
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||||
|
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||||
|
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// Display some basic information about the card
|
||||||
|
Serial.println("Found an ISO14443A card");
|
||||||
|
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||||
|
Serial.print(" UID Value: ");
|
||||||
|
nfc.PrintHex(uid, uidLength);
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
// Make sure this is a Mifare Classic card
|
||||||
|
if (uidLength != 4)
|
||||||
|
{
|
||||||
|
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We probably have a Mifare Classic card ...
|
||||||
|
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||||
|
|
||||||
|
// Check if this is an NDEF card (using first block of sector 1 from mifareclassic_formatndef.pde)
|
||||||
|
// Must authenticate on the first key using 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7
|
||||||
|
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keyb);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
Serial.println("Unable to authenticate block 4 ... is this card NDEF formatted?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Authentication succeeded (seems to be an NDEF/NFC Forum tag) ...");
|
||||||
|
|
||||||
|
// Authenticated seems to have worked
|
||||||
|
// Try to write an NDEF record to sector 1
|
||||||
|
// Use 0x01 for the URI Identifier Code to prepend "http://www."
|
||||||
|
// to the url (and save some space). For information on URI ID Codes
|
||||||
|
// see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef
|
||||||
|
if (strlen(url) > 38)
|
||||||
|
{
|
||||||
|
// The length is also checked in the WriteNDEFURI function, but lets
|
||||||
|
// warn users here just in case they change the value and it's bigger
|
||||||
|
// than it should be
|
||||||
|
Serial.println("URI is too long ... must be less than 38 characters!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Updating sector 1 with URI as NDEF Message");
|
||||||
|
|
||||||
|
// URI is within size limits ... write it to the card and report success/failure
|
||||||
|
success = nfc.mifareclassic_WriteNDEFURI(1, ndefprefix, url);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Serial.println("NDEF URI Record written to sector 1");
|
||||||
|
Serial.println("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("NDEF Record creation failed! :(");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait a bit before trying again
|
||||||
|
Serial.println("\n\nDone!");
|
||||||
|
delay(1000);
|
||||||
|
Serial.flush();
|
||||||
|
while(Serial.available()) Serial.read();
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
// NTAG21x supports 4 bytes password to protect pages started from AUTH0
|
||||||
|
// AUTH0 defines the page address from which the password verification is required.
|
||||||
|
// Valid address range for byte AUTH0 is from 00h to FFh.
|
||||||
|
// If AUTH0 is set to a page address which is higher than the last page from the user configuration,
|
||||||
|
// the password protection is effectively disabled
|
||||||
|
#include <PN532/PN532/PN532.h>
|
||||||
|
#include <NfcAdapter.h>
|
||||||
|
#if 0 // Using PN532's SPI (Seeed NFC shield)
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532/PN532_SPI/PN532_SPI.h>
|
||||||
|
|
||||||
|
|
||||||
|
PN532_SPI intf(SPI, 10);
|
||||||
|
PN532 nfc = PN532(intf);
|
||||||
|
#else // Using PN532's I2C
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532/PN532_I2C/PN532_I2C.h>
|
||||||
|
|
||||||
|
PN532_I2C intf(Wire);
|
||||||
|
PN532 nfc = PN532(intf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Using PN532's UART (Grove NFC)
|
||||||
|
|
||||||
|
// #include <PN532/PN532_I2C/PN532_I2C.h>
|
||||||
|
// #include <PN532/PN532/PN532.h>
|
||||||
|
// #include <NfcAdapter.h>
|
||||||
|
// PN532_HSU intf(Serial1);
|
||||||
|
// PN532 nfc = PN532(intf);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t password[4] = {0x12, 0x34, 0x56, 0x78};
|
||||||
|
uint8_t buf[4];
|
||||||
|
uint8_t uid[7];
|
||||||
|
uint8_t uidLength;
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(9600);
|
||||||
|
Serial.println("NTAG21x R/W");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
nfc.SAMConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
Serial.println("wait for a tag");
|
||||||
|
// wait until a tag is present
|
||||||
|
while (!nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// if NTAG21x enables r/w protection, uncomment the following line
|
||||||
|
// nfc.ntag21x_auth(password);
|
||||||
|
|
||||||
|
nfc.mifareultralight_ReadPage(3, buf);
|
||||||
|
int capacity = buf[2] * 8;
|
||||||
|
Serial.print(F("Tag capacity "));
|
||||||
|
Serial.print(capacity);
|
||||||
|
Serial.println(F(" bytes"));
|
||||||
|
|
||||||
|
uint8_t cfg_page_base = 0x29; // NTAG213
|
||||||
|
if (capacity == 0x3E) {
|
||||||
|
cfg_page_base = 0x83; // NTAG215
|
||||||
|
} else if (capacity == 0x6D) {
|
||||||
|
cfg_page_base = 0xE3; // NTAG216
|
||||||
|
}
|
||||||
|
|
||||||
|
// PWD page, set new password
|
||||||
|
nfc.mifareultralight_WritePage(cfg_page_base + 2, password);
|
||||||
|
|
||||||
|
// disable r/w
|
||||||
|
// | PROT | CFG_LCK | RFUI | NFC_CNT_EN | NFC_CNT_PWD_PROT | AUTHLIM (2:0) |
|
||||||
|
buf[0] = (1 << 7) | 0x0;
|
||||||
|
nfc.mifareultralight_WritePage(cfg_page_base + 1, buf);
|
||||||
|
|
||||||
|
// protect pages started from AUTH0
|
||||||
|
uint8_t auth0 = 0x10;
|
||||||
|
buf[0] = 0;
|
||||||
|
buf[1] = 0;
|
||||||
|
buf[2] = 0;
|
||||||
|
buf[3] = auth0;
|
||||||
|
nfc.mifareultralight_WritePage(cfg_page_base, buf);
|
||||||
|
|
||||||
|
|
||||||
|
// wait until the tag is removed
|
||||||
|
while (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
// Clean resets a tag back to factory-like state
|
||||||
|
// For Mifare Classic, tag is zero'd and reformatted as Mifare Classic
|
||||||
|
// For Mifare Ultralight, tags is zero'd and left empty
|
||||||
|
#include <PN532/PN532/PN532.h>
|
||||||
|
#include <NfcAdapter.h>
|
||||||
|
|
||||||
|
#if 0 // Using PN532's SPI (Seeed NFC shield)
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532/PN532_SPI/PN532_SPI.h>
|
||||||
|
|
||||||
|
|
||||||
|
PN532_SPI intf(SPI, 10);
|
||||||
|
PN532 nfc = PN532(intf);
|
||||||
|
#else // Using PN532's I2C
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532/PN532_I2C/PN532_I2C.h>
|
||||||
|
|
||||||
|
|
||||||
|
PN532_I2C intf(Wire);
|
||||||
|
PN532 nfc = PN532(intf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Using PN532's UART (Grove NFC)
|
||||||
|
|
||||||
|
// #include <PN532/PN532_I2C/PN532_I2C.h>
|
||||||
|
// #include <PN532/PN532/PN532.h>
|
||||||
|
// #include <NfcAdapter.h>
|
||||||
|
// PN532_HSU intf(Serial1);
|
||||||
|
// PN532 nfc = PN532(intf);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t password[4] = {0x12, 0x34, 0x56, 0x78};
|
||||||
|
uint8_t buf[4];
|
||||||
|
uint8_t uid[7];
|
||||||
|
uint8_t uidLength;
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(9600);
|
||||||
|
Serial.println("NTAG21x R/W");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
nfc.SAMConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
Serial.println("wait for a tag");
|
||||||
|
// wait until a tag is present
|
||||||
|
while (!nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// if NTAG21x enables r/w protection, uncomment the following line
|
||||||
|
// nfc.ntag21x_auth(password);
|
||||||
|
|
||||||
|
nfc.mifareultralight_ReadPage(3, buf);
|
||||||
|
int capacity = buf[2] * 8;
|
||||||
|
Serial.print(F("Tag capacity "));
|
||||||
|
Serial.print(capacity);
|
||||||
|
Serial.println(F(" bytes"));
|
||||||
|
|
||||||
|
for (int i=4; i<capacity/4; i++) {
|
||||||
|
nfc.mifareultralight_ReadPage(i, buf);
|
||||||
|
nfc.PrintHexChar(buf, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until the tag is removed
|
||||||
|
while (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// snep_test.ino
|
||||||
|
// send a SNEP message to adnroid and get a message from android
|
||||||
|
|
||||||
|
#include "SPI.h"
|
||||||
|
#include "PN532/PN532_SPI/PN532_SPI.h"
|
||||||
|
#include "PN532/PN532/llcp.h"
|
||||||
|
#include "PN532/PN532/snep.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
SNEP nfc(pn532spi);
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("-------Peer to Peer--------");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t message[] = {
|
||||||
|
0xD2, 0xA, 0xB, 0x74,0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C,
|
||||||
|
0x61, 0x69, 0x6E, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77,
|
||||||
|
0x6F, 0x72, 0x6C, 0x64};
|
||||||
|
|
||||||
|
uint8_t buf[128];
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
|
||||||
|
nfc.write(message, sizeof(message));
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
int16_t len = nfc.read(buf, sizeof(buf));
|
||||||
|
if (len > 0) {
|
||||||
|
Serial.println("get a SNEP message:");
|
||||||
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
|
Serial.print(buf[i], HEX);
|
||||||
|
Serial.print(' ');
|
||||||
|
}
|
||||||
|
Serial.print('\n');
|
||||||
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
|
char c = buf[i];
|
||||||
|
if (c <= 0x1f || c > 0x7f) {
|
||||||
|
Serial.print('.');
|
||||||
|
} else {
|
||||||
|
Serial.print(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.print('\n');
|
||||||
|
}
|
||||||
|
delay(3000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// send a NDEF message to adnroid or get a NDEF message
|
||||||
|
//
|
||||||
|
// note: [NDEF library](https://github.com/Don/NDEF) is needed.
|
||||||
|
|
||||||
|
#include "SPI.h"
|
||||||
|
#include "PN532/PN532_SPI/PN532_SPI.h"
|
||||||
|
#include "PN532/PN532/snep.h"
|
||||||
|
#include "NdefMessage.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
SNEP nfc(pn532spi);
|
||||||
|
uint8_t ndefBuf[128];
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("-------Peer to Peer--------");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
Serial.println("Send a message to Android");
|
||||||
|
NdefMessage message = NdefMessage();
|
||||||
|
message.addUriRecord("http://www.seeedstudio.com");
|
||||||
|
int messageSize = message.getEncodedSize();
|
||||||
|
if (messageSize > sizeof(ndefBuf)) {
|
||||||
|
Serial.println("ndefBuf is too small");
|
||||||
|
while (1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
message.encode(ndefBuf);
|
||||||
|
if (0 >= nfc.write(ndefBuf, messageSize)) {
|
||||||
|
Serial.println("Failed");
|
||||||
|
} else {
|
||||||
|
Serial.println("Success");
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(3000);
|
||||||
|
#else
|
||||||
|
Serial.println("Get a message from Android");
|
||||||
|
int msgSize = nfc.read(ndefBuf, sizeof(ndefBuf));
|
||||||
|
if (msgSize > 0) {
|
||||||
|
NdefMessage msg = NdefMessage(ndefBuf, msgSize);
|
||||||
|
msg.print();
|
||||||
|
Serial.println("\nSuccess");
|
||||||
|
} else {
|
||||||
|
Serial.println("failed");
|
||||||
|
}
|
||||||
|
delay(3000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
This example will wait for any ISO14443A card or tag, and
|
||||||
|
depending on the size of the UID will attempt to read from it.
|
||||||
|
|
||||||
|
If the card has a 4-byte UID it is probably a Mifare
|
||||||
|
Classic card, and the following steps are taken:
|
||||||
|
|
||||||
|
- Authenticate block 4 (the first block of Sector 1) using
|
||||||
|
the default KEYA of 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
|
||||||
|
- If authentication succeeds, we can then read any of the
|
||||||
|
4 blocks in that sector (though only block 4 is read here)
|
||||||
|
|
||||||
|
If the card has a 7-byte UID it is probably a Mifare
|
||||||
|
Ultralight card, and the 4 byte pages can be read directly.
|
||||||
|
Page 4 is read by default since this is the first 'general-
|
||||||
|
purpose' page on the tags.
|
||||||
|
|
||||||
|
To enable debug message, define DEBUG in PN532/PN532_debug.h
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <PN532_SPI.h>
|
||||||
|
#include "PN532.h"
|
||||||
|
|
||||||
|
PN532_SPI pn532spi(SPI, 10);
|
||||||
|
PN532 nfc(pn532spi);
|
||||||
|
#elif 1
|
||||||
|
#include <PN532_HSU.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
|
||||||
|
PN532_HSU pn532hsu(Serial1);
|
||||||
|
PN532 nfc(pn532hsu);
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
PN532_I2C pn532i2c(Wire);
|
||||||
|
PN532 nfc(pn532i2c);
|
||||||
|
#endif
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Hello!");
|
||||||
|
|
||||||
|
nfc.begin();
|
||||||
|
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (! versiondata) {
|
||||||
|
Serial.print("Didn't find PN53x board");
|
||||||
|
while (1); // halt
|
||||||
|
}
|
||||||
|
// Got ok data, print it out!
|
||||||
|
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||||
|
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||||
|
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||||
|
|
||||||
|
// configure board to read RFID tags
|
||||||
|
nfc.SAMConfig();
|
||||||
|
|
||||||
|
Serial.println("Waiting for an ISO14443A Card ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop(void) {
|
||||||
|
uint8_t success;
|
||||||
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||||
|
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||||
|
|
||||||
|
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||||
|
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||||
|
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||||
|
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// Display some basic information about the card
|
||||||
|
Serial.println("Found an ISO14443A card");
|
||||||
|
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||||
|
Serial.print(" UID Value: ");
|
||||||
|
nfc.PrintHex(uid, uidLength);
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
if (uidLength == 4)
|
||||||
|
{
|
||||||
|
// We probably have a Mifare Classic card ...
|
||||||
|
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||||
|
|
||||||
|
// Now we need to try to authenticate it for read/write access
|
||||||
|
// Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
|
||||||
|
Serial.println("Trying to authenticate block 4 with default KEYA value");
|
||||||
|
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
|
||||||
|
// Start with block 4 (the first block of sector 1) since sector 0
|
||||||
|
// contains the manufacturer data and it's probably better just
|
||||||
|
// to leave it alone unless you know what you're doing
|
||||||
|
success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Serial.println("Sector 1 (Blocks 4..7) has been authenticated");
|
||||||
|
uint8_t data[16];
|
||||||
|
|
||||||
|
// If you want to write something to block 4 to test with, uncomment
|
||||||
|
// the following line and this text should be read back in a minute
|
||||||
|
// data = { 'a', 'd', 'a', 'f', 'r', 'u', 'i', 't', '.', 'c', 'o', 'm', 0, 0, 0, 0};
|
||||||
|
// success = nfc.mifareclassic_WriteDataBlock (4, data);
|
||||||
|
|
||||||
|
// Try to read the contents of block 4
|
||||||
|
success = nfc.mifareclassic_ReadDataBlock(4, data);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// Data seems to have been read ... spit it out
|
||||||
|
Serial.println("Reading Block 4:");
|
||||||
|
nfc.PrintHexChar(data, 16);
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
// Wait a bit before reading the card again
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("Ooops ... unable to read the requested block. Try another key?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("Ooops ... authentication failed: Try another key?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uidLength == 7)
|
||||||
|
{
|
||||||
|
// We probably have a Mifare Ultralight card ...
|
||||||
|
Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)");
|
||||||
|
|
||||||
|
// Try to read the first general-purpose user page (#4)
|
||||||
|
Serial.println("Reading page 4");
|
||||||
|
uint8_t data[32];
|
||||||
|
success = nfc.mifareultralight_ReadPage (4, data);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// Data seems to have been read ... spit it out
|
||||||
|
nfc.PrintHexChar(data, 4);
|
||||||
|
Serial.println("");
|
||||||
|
|
||||||
|
// Wait a bit before reading the card again
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("Ooops ... unable to read the requested page!?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
Software License Agreement (BSD License)
|
||||||
|
|
||||||
|
Copyright (c) 2012, Adafruit Industries
|
||||||
|
Copyright (c) 2013, Seeed Technology Inc.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. Neither the name of the copyright holders nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
@@ -0,0 +1,373 @@
|
|||||||
|
|
||||||
|
#include "llcp.h"
|
||||||
|
#include "PN532_debug.h"
|
||||||
|
|
||||||
|
// LLCP PDU Type Values
|
||||||
|
#define PDU_SYMM 0x00
|
||||||
|
#define PDU_PAX 0x01
|
||||||
|
#define PDU_CONNECT 0x04
|
||||||
|
#define PDU_DISC 0x05
|
||||||
|
#define PDU_CC 0x06
|
||||||
|
#define PDU_DM 0x07
|
||||||
|
#define PDU_I 0x0c
|
||||||
|
#define PDU_RR 0x0d
|
||||||
|
|
||||||
|
uint8_t LLCP::SYMM_PDU[2] = {0, 0};
|
||||||
|
|
||||||
|
inline uint8_t getPType(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
return ((buf[0] & 0x3) << 2) + (buf[1] >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t getSSAP(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
return buf[1] & 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t getDSAP(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
return buf[0] >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t LLCP::activate(uint16_t timeout)
|
||||||
|
{
|
||||||
|
return link.activateAsTarget(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t LLCP::waitForConnection(uint16_t timeout)
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
mode = 1;
|
||||||
|
ns = 0;
|
||||||
|
nr = 0;
|
||||||
|
|
||||||
|
// Get CONNECT PDU
|
||||||
|
DMSG("wait for a CONNECT PDU\n");
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (2 > link.read(headerBuf, headerBufLen))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = getPType(headerBuf);
|
||||||
|
if (PDU_CONNECT == type)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (PDU_SYMM == type)
|
||||||
|
{
|
||||||
|
if (!link.write(SYMM_PDU, sizeof(SYMM_PDU)))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
// Put CC PDU
|
||||||
|
DMSG("put a CC(Connection Complete) PDU to response the CONNECT PDU\n");
|
||||||
|
ssap = getDSAP(headerBuf);
|
||||||
|
dsap = getSSAP(headerBuf);
|
||||||
|
headerBuf[0] = (dsap << 2) + ((PDU_CC >> 2) & 0x3);
|
||||||
|
headerBuf[1] = ((PDU_CC & 0x3) << 6) + ssap;
|
||||||
|
if (!link.write(headerBuf, 2))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t LLCP::waitForDisconnection(uint16_t timeout)
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
// Get DISC PDU
|
||||||
|
DMSG("wait for a DISC PDU\n");
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (2 > link.read(headerBuf, headerBufLen))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = getPType(headerBuf);
|
||||||
|
if (PDU_DISC == type)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (PDU_SYMM == type)
|
||||||
|
{
|
||||||
|
if (!link.write(SYMM_PDU, sizeof(SYMM_PDU)))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
// Put DM PDU
|
||||||
|
DMSG("put a DM(Disconnect Mode) PDU to response the DISC PDU\n");
|
||||||
|
// ssap = getDSAP(headerBuf);
|
||||||
|
// dsap = getSSAP(headerBuf);
|
||||||
|
headerBuf[0] = (dsap << 2) + (PDU_DM >> 2);
|
||||||
|
headerBuf[1] = ((PDU_DM & 0x3) << 6) + ssap;
|
||||||
|
if (!link.write(headerBuf, 2))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t LLCP::connect(uint16_t timeout)
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
mode = 0;
|
||||||
|
dsap = LLCP_DEFAULT_DSAP;
|
||||||
|
ssap = LLCP_DEFAULT_SSAP;
|
||||||
|
ns = 0;
|
||||||
|
nr = 0;
|
||||||
|
|
||||||
|
// try to get a SYMM PDU
|
||||||
|
if (2 > link.read(headerBuf, headerBufLen))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
type = getPType(headerBuf);
|
||||||
|
if (PDU_SYMM != type)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// put a CONNECT PDU
|
||||||
|
headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_CONNECT >> 2);
|
||||||
|
headerBuf[1] = ((PDU_CONNECT & 0x03) << 6) + LLCP_DEFAULT_SSAP;
|
||||||
|
uint8_t body[] = " urn:nfc:sn:snep";
|
||||||
|
body[0] = 0x06;
|
||||||
|
body[1] = sizeof(body) - 2 - 1;
|
||||||
|
if (!link.write(headerBuf, 2, body, sizeof(body) - 1))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for a CC PDU
|
||||||
|
DMSG("wait for a CC PDU\n");
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (2 > link.read(headerBuf, headerBufLen))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = getPType(headerBuf);
|
||||||
|
if (PDU_CC == type)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (PDU_SYMM == type)
|
||||||
|
{
|
||||||
|
if (!link.write(SYMM_PDU, sizeof(SYMM_PDU)))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t LLCP::disconnect(uint16_t timeout)
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
// try to get a SYMM PDU
|
||||||
|
if (2 > link.read(headerBuf, headerBufLen))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
type = getPType(headerBuf);
|
||||||
|
if (PDU_SYMM != type)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// put a DISC PDU
|
||||||
|
headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_DISC >> 2);
|
||||||
|
headerBuf[1] = ((PDU_DISC & 0x03) << 6) + LLCP_DEFAULT_SSAP;
|
||||||
|
if (!link.write(headerBuf, 2))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for a DM PDU
|
||||||
|
DMSG("wait for a DM PDU\n");
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (2 > link.read(headerBuf, headerBufLen))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = getPType(headerBuf);
|
||||||
|
if (PDU_CC == type)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (PDU_DM == type)
|
||||||
|
{
|
||||||
|
if (!link.write(SYMM_PDU, sizeof(SYMM_PDU)))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLCP::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t buf[3];
|
||||||
|
|
||||||
|
if (mode)
|
||||||
|
{
|
||||||
|
// Get a SYMM PDU
|
||||||
|
if (2 != link.read(buf, sizeof(buf)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerBufLen < (hlen + 3))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int8_t i = hlen - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
headerBuf[i + 3] = header[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
headerBuf[0] = (dsap << 2) + (PDU_I >> 2);
|
||||||
|
headerBuf[1] = ((PDU_I & 0x3) << 6) + ssap;
|
||||||
|
headerBuf[2] = (ns << 4) + nr;
|
||||||
|
if (!link.write(headerBuf, 3 + hlen, body, blen))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ns++;
|
||||||
|
|
||||||
|
// Get a RR PDU
|
||||||
|
int16_t status;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
status = link.read(headerBuf, headerBufLen);
|
||||||
|
if (2 > status)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = getPType(headerBuf);
|
||||||
|
if (PDU_RR == type)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (PDU_SYMM == type)
|
||||||
|
{
|
||||||
|
if (!link.write(SYMM_PDU, sizeof(SYMM_PDU)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
if (!link.write(SYMM_PDU, sizeof(SYMM_PDU)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t LLCP::read(uint8_t *buf, uint8_t length)
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
uint16_t status;
|
||||||
|
|
||||||
|
// Get INFO PDU
|
||||||
|
do
|
||||||
|
{
|
||||||
|
status = link.read(buf, length);
|
||||||
|
if (2 > status)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = getPType(buf);
|
||||||
|
if (PDU_I == type)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (PDU_SYMM == type)
|
||||||
|
{
|
||||||
|
if (!link.write(SYMM_PDU, sizeof(SYMM_PDU)))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
uint8_t len = status - 3;
|
||||||
|
ssap = getDSAP(buf);
|
||||||
|
dsap = getSSAP(buf);
|
||||||
|
|
||||||
|
headerBuf[0] = (dsap << 2) + (PDU_RR >> 2);
|
||||||
|
headerBuf[1] = ((PDU_RR & 0x3) << 6) + ssap;
|
||||||
|
headerBuf[2] = (buf[2] >> 4) + 1;
|
||||||
|
if (!link.write(headerBuf, 3))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
buf[i] = buf[i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
nr++;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
#ifndef __LLCP_H__
|
||||||
|
#define __LLCP_H__
|
||||||
|
|
||||||
|
#include "mac_link.h"
|
||||||
|
|
||||||
|
#define LLCP_DEFAULT_TIMEOUT 20000
|
||||||
|
#define LLCP_DEFAULT_DSAP 0x04
|
||||||
|
#define LLCP_DEFAULT_SSAP 0x20
|
||||||
|
|
||||||
|
class LLCP {
|
||||||
|
public:
|
||||||
|
LLCP(PN532Interface &interface) : link(interface) {
|
||||||
|
headerBuf = link.getHeaderBuffer(&headerBufLen);
|
||||||
|
ns = 0;
|
||||||
|
nr = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Actiave PN532 as a target
|
||||||
|
* @param timeout max time to wait, 0 means no timeout
|
||||||
|
* @return > 0 success
|
||||||
|
* = 0 timeout
|
||||||
|
* < 0 failed
|
||||||
|
*/
|
||||||
|
int8_t activate(uint16_t timeout = 0);
|
||||||
|
|
||||||
|
int8_t waitForConnection(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
int8_t waitForDisconnection(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
int8_t connect(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
int8_t disconnect(uint16_t timeout = LLCP_DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief write a packet, the packet should be less than (255 - 2) bytes
|
||||||
|
* @param header packet header
|
||||||
|
* @param hlen length of header
|
||||||
|
* @param body packet body
|
||||||
|
* @param blen length of body
|
||||||
|
* @return true success
|
||||||
|
* false failed
|
||||||
|
*/
|
||||||
|
bool write(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief read a packet, the packet will be less than (255 - 2) bytes
|
||||||
|
* @param buf the buffer to contain the packet
|
||||||
|
* @param len lenght of the buffer
|
||||||
|
* @return >=0 length of the packet
|
||||||
|
* <0 failed
|
||||||
|
*/
|
||||||
|
int16_t read(uint8_t *buf, uint8_t len);
|
||||||
|
|
||||||
|
uint8_t *getHeaderBuffer(uint8_t *len) {
|
||||||
|
uint8_t *buf = link.getHeaderBuffer(len);
|
||||||
|
len -= 3; // I PDU header has 3 bytes
|
||||||
|
return buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
MACLink link;
|
||||||
|
uint8_t mode;
|
||||||
|
uint8_t ssap;
|
||||||
|
uint8_t dsap;
|
||||||
|
uint8_t *headerBuf;
|
||||||
|
uint8_t headerBufLen;
|
||||||
|
uint8_t ns; // Number of I PDU Sent
|
||||||
|
uint8_t nr; // Number of I PDU Received
|
||||||
|
|
||||||
|
static uint8_t SYMM_PDU[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __LLCP_H__
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
#include "mac_link.h"
|
||||||
|
#include "PN532_debug.h"
|
||||||
|
|
||||||
|
int8_t MACLink::activateAsTarget(uint16_t timeout)
|
||||||
|
{
|
||||||
|
pn532.begin();
|
||||||
|
pn532.SAMConfig();
|
||||||
|
return pn532.tgInitAsTarget(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MACLink::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
|
||||||
|
{
|
||||||
|
return pn532.tgSetData(header, hlen, body, blen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t MACLink::read(uint8_t *buf, uint8_t len)
|
||||||
|
{
|
||||||
|
return pn532.tgGetData(buf, len);
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#ifndef __MAC_LINK_H__
|
||||||
|
#define __MAC_LINK_H__
|
||||||
|
|
||||||
|
#include "PN532.h"
|
||||||
|
|
||||||
|
class MACLink {
|
||||||
|
public:
|
||||||
|
MACLink(PN532Interface &interface) : pn532(interface) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Activate PN532 as a target
|
||||||
|
* @param timeout max time to wait, 0 means no timeout
|
||||||
|
* @return > 0 success
|
||||||
|
* = 0 timeout
|
||||||
|
* < 0 failed
|
||||||
|
*/
|
||||||
|
int8_t activateAsTarget(uint16_t timeout = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief write a PDU packet, the packet should be less than (255 - 2) bytes
|
||||||
|
* @param header packet header
|
||||||
|
* @param hlen length of header
|
||||||
|
* @param body packet body
|
||||||
|
* @param blen length of body
|
||||||
|
* @return true success
|
||||||
|
* false failed
|
||||||
|
*/
|
||||||
|
bool write(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief read a PDU packet, the packet will be less than (255 - 2) bytes
|
||||||
|
* @param buf the buffer to contain the PDU packet
|
||||||
|
* @param len lenght of the buffer
|
||||||
|
* @return >=0 length of the PDU packet
|
||||||
|
* <0 failed
|
||||||
|
*/
|
||||||
|
int16_t read(uint8_t *buf, uint8_t len);
|
||||||
|
|
||||||
|
uint8_t *getHeaderBuffer(uint8_t *len) {
|
||||||
|
return pn532.getBuffer(len);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
PN532 pn532;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __MAC_LINK_H__
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
|
||||||
|
#include "snep.h"
|
||||||
|
#include "PN532_debug.h"
|
||||||
|
|
||||||
|
int8_t SNEP::write(const uint8_t *buf, uint8_t len, uint16_t timeout)
|
||||||
|
{
|
||||||
|
if (0 >= llcp.activate(timeout))
|
||||||
|
{
|
||||||
|
DMSG("failed to activate PN532 as a target\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 >= llcp.connect(timeout))
|
||||||
|
{
|
||||||
|
DMSG("failed to set up a connection\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// response a success SNEP message
|
||||||
|
headerBuf[0] = SNEP_DEFAULT_VERSION;
|
||||||
|
headerBuf[1] = SNEP_REQUEST_PUT;
|
||||||
|
headerBuf[2] = 0;
|
||||||
|
headerBuf[3] = 0;
|
||||||
|
headerBuf[4] = 0;
|
||||||
|
headerBuf[5] = len;
|
||||||
|
if (0 >= llcp.write(headerBuf, 6, buf, len))
|
||||||
|
{
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rbuf[16];
|
||||||
|
if (6 > llcp.read(rbuf, sizeof(rbuf)))
|
||||||
|
{
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check SNEP version
|
||||||
|
if (SNEP_DEFAULT_VERSION != rbuf[0])
|
||||||
|
{
|
||||||
|
DMSG("The received SNEP message's major version is different\n");
|
||||||
|
// To-do: send Unsupported Version response
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect a put request
|
||||||
|
if (SNEP_RESPONSE_SUCCESS != rbuf[1])
|
||||||
|
{
|
||||||
|
DMSG("Expect a success response\n");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
llcp.disconnect(timeout);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t SNEP::read(uint8_t *buf, uint8_t len, uint16_t timeout)
|
||||||
|
{
|
||||||
|
if (0 >= llcp.activate(timeout))
|
||||||
|
{
|
||||||
|
DMSG("failed to activate PN532 as a target\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 >= llcp.waitForConnection(timeout))
|
||||||
|
{
|
||||||
|
DMSG("failed to set up a connection\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t status = llcp.read(buf, len);
|
||||||
|
if (6 > status)
|
||||||
|
{
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check SNEP version
|
||||||
|
|
||||||
|
// in case of platform specific bug, shift SNEP message for 4 bytes.
|
||||||
|
// tested on Nexus 5, Android 5.1
|
||||||
|
if (SNEP_DEFAULT_VERSION != buf[0] && SNEP_DEFAULT_VERSION == buf[4])
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < len - 4; i++)
|
||||||
|
{
|
||||||
|
buf[i] = buf[i + 4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SNEP_DEFAULT_VERSION != buf[0])
|
||||||
|
{
|
||||||
|
DMSG(F("SNEP->read: The received SNEP message's major version is different, me: "));
|
||||||
|
DMSG(SNEP_DEFAULT_VERSION);
|
||||||
|
DMSG(", their: ");
|
||||||
|
DMSG(buf[0]);
|
||||||
|
DMSG("\n");
|
||||||
|
// To-do: send Unsupported Version response
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect a put request
|
||||||
|
if (SNEP_REQUEST_PUT != buf[1])
|
||||||
|
{
|
||||||
|
DMSG("Expect a put request\n");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check message's length
|
||||||
|
uint32_t length = (buf[2] << 24) + (buf[3] << 16) + (buf[4] << 8) + buf[5];
|
||||||
|
// length should not be more than 244 (header + body < 255, header = 6 + 3 + 2)
|
||||||
|
if (length > (status - 6))
|
||||||
|
{
|
||||||
|
DMSG("The SNEP message is too large: ");
|
||||||
|
DMSG_INT(length);
|
||||||
|
DMSG_INT(status - 6);
|
||||||
|
DMSG("\n");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
buf[i] = buf[i + 6];
|
||||||
|
}
|
||||||
|
|
||||||
|
// response a success SNEP message
|
||||||
|
headerBuf[0] = SNEP_DEFAULT_VERSION;
|
||||||
|
headerBuf[1] = SNEP_RESPONSE_SUCCESS;
|
||||||
|
headerBuf[2] = 0;
|
||||||
|
headerBuf[3] = 0;
|
||||||
|
headerBuf[4] = 0;
|
||||||
|
headerBuf[5] = 0;
|
||||||
|
llcp.write(headerBuf, 6);
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#ifndef __SNEP_H__
|
||||||
|
#define __SNEP_H__
|
||||||
|
|
||||||
|
#include "llcp.h"
|
||||||
|
|
||||||
|
#define SNEP_DEFAULT_VERSION 0x10 // Major: 1, Minor: 0
|
||||||
|
|
||||||
|
#define SNEP_REQUEST_PUT 0x02
|
||||||
|
#define SNEP_REQUEST_GET 0x01
|
||||||
|
|
||||||
|
#define SNEP_RESPONSE_SUCCESS 0x81
|
||||||
|
#define SNEP_RESPONSE_REJECT 0xFF
|
||||||
|
|
||||||
|
class SNEP {
|
||||||
|
public:
|
||||||
|
SNEP(PN532Interface &interface) : llcp(interface) {
|
||||||
|
headerBuf = llcp.getHeaderBuffer(&headerBufLen);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief write a SNEP packet, the packet should be less than (255 - 2 - 3) bytes
|
||||||
|
* @param buf the buffer to contain the packet
|
||||||
|
* @param len lenght of the buffer
|
||||||
|
* @param timeout max time to wait, 0 means no timeout
|
||||||
|
* @return >0 success
|
||||||
|
* =0 timeout
|
||||||
|
* <0 failed
|
||||||
|
*/
|
||||||
|
int8_t write(const uint8_t *buf, uint8_t len, uint16_t timeout = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief read a SNEP packet, the packet will be less than (255 - 2 - 3) bytes
|
||||||
|
* @param buf the buffer to contain the packet
|
||||||
|
* @param len lenght of the buffer
|
||||||
|
* @param timeout max time to wait, 0 means no timeout
|
||||||
|
* @return >=0 length of the packet
|
||||||
|
* <0 failed
|
||||||
|
*/
|
||||||
|
int16_t read(uint8_t *buf, uint8_t len, uint16_t timeout = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LLCP llcp;
|
||||||
|
uint8_t *headerBuf;
|
||||||
|
uint8_t headerBufLen;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SNEP_H__
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
/**
|
||||||
|
* @modified picospuch
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PN532_I2C.h"
|
||||||
|
#include "PN532_debug.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
#define PN532_I2C_ADDRESS (0x48 >> 1)
|
||||||
|
|
||||||
|
PN532_I2C::PN532_I2C(TwoWire &wire)
|
||||||
|
{
|
||||||
|
_wire = &wire;
|
||||||
|
command = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PN532_I2C::begin()
|
||||||
|
{
|
||||||
|
_wire->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PN532_I2C::wakeup()
|
||||||
|
{
|
||||||
|
delay(500); // wait for all ready to manipulate pn532
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t PN532_I2C::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
|
||||||
|
{
|
||||||
|
command = header[0];
|
||||||
|
_wire->beginTransmission(PN532_I2C_ADDRESS);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
DMSG("write: ");
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < hlen; i++)
|
||||||
|
{
|
||||||
|
if (write(header[i]))
|
||||||
|
{
|
||||||
|
sum += header[i];
|
||||||
|
|
||||||
|
DMSG_HEX(header[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DMSG("\nToo many data to send, I2C doesn't support such a big packet\n"); // I2C max packet: 32 bytes
|
||||||
|
return PN532_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < blen; i++)
|
||||||
|
{
|
||||||
|
if (write(body[i]))
|
||||||
|
{
|
||||||
|
sum += body[i];
|
||||||
|
|
||||||
|
DMSG_HEX(body[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DMSG("\nToo many data to send, I2C doesn't support such a big packet\n"); // I2C max packet: 32 bytes
|
||||||
|
return PN532_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t checksum = ~sum + 1; // checksum of TFI + DATA
|
||||||
|
write(checksum);
|
||||||
|
write(PN532_POSTAMBLE);
|
||||||
|
|
||||||
|
_wire->endTransmission();
|
||||||
|
|
||||||
|
DMSG('\n');
|
||||||
|
|
||||||
|
return readAckFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t PN532_I2C::getResponseLength(uint8_t buf[], uint8_t len, uint16_t timeout)
|
||||||
|
{
|
||||||
|
const uint8_t PN532_NACK[] = {0, 0, 0xFF, 0xFF, 0, 0};
|
||||||
|
uint16_t time = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (_wire->requestFrom(PN532_I2C_ADDRESS, 6))
|
||||||
|
{
|
||||||
|
if (read() & 1)
|
||||||
|
{ // check first byte --- status
|
||||||
|
break; // PN532 is ready
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1);
|
||||||
|
time++;
|
||||||
|
if ((0 != timeout) && (time > timeout))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
if (0x00 != read() || // PREAMBLE
|
||||||
|
0x00 != read() || // STARTCODE1
|
||||||
|
0xFF != read() // STARTCODE2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
return PN532_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t length = read();
|
||||||
|
|
||||||
|
// request for last respond msg again
|
||||||
|
_wire->beginTransmission(PN532_I2C_ADDRESS);
|
||||||
|
for (uint16_t i = 0; i < sizeof(PN532_NACK); ++i)
|
||||||
|
{
|
||||||
|
write(PN532_NACK[i]);
|
||||||
|
}
|
||||||
|
_wire->endTransmission();
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t PN532_I2C::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout)
|
||||||
|
{
|
||||||
|
uint16_t time = 0;
|
||||||
|
uint8_t length;
|
||||||
|
|
||||||
|
length = getResponseLength(buf, len, timeout);
|
||||||
|
|
||||||
|
// [RDY] 00 00 FF LEN LCS (TFI PD0 ... PDn) DCS 00
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (_wire->requestFrom(PN532_I2C_ADDRESS, 6 + length + 2))
|
||||||
|
{
|
||||||
|
if (read() & 1)
|
||||||
|
{ // check first byte --- status
|
||||||
|
break; // PN532 is ready
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1);
|
||||||
|
time++;
|
||||||
|
if ((0 != timeout) && (time > timeout))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
if (0x00 != read() || // PREAMBLE
|
||||||
|
0x00 != read() || // STARTCODE1
|
||||||
|
0xFF != read() // STARTCODE2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
return PN532_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = read();
|
||||||
|
|
||||||
|
if (0 != (uint8_t)(length + read()))
|
||||||
|
{ // checksum of length
|
||||||
|
return PN532_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t cmd = command + 1; // response command
|
||||||
|
if (PN532_PN532TOHOST != read() || (cmd) != read())
|
||||||
|
{
|
||||||
|
return PN532_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 2;
|
||||||
|
if (length > len)
|
||||||
|
{
|
||||||
|
return PN532_NO_SPACE; // not enough space
|
||||||
|
}
|
||||||
|
|
||||||
|
DMSG("read: ");
|
||||||
|
DMSG_HEX(cmd);
|
||||||
|
|
||||||
|
uint8_t sum = PN532_PN532TOHOST + cmd;
|
||||||
|
for (uint8_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
buf[i] = read();
|
||||||
|
sum += buf[i];
|
||||||
|
|
||||||
|
DMSG_HEX(buf[i]);
|
||||||
|
}
|
||||||
|
DMSG('\n');
|
||||||
|
|
||||||
|
uint8_t checksum = read();
|
||||||
|
if (0 != (uint8_t)(sum + checksum))
|
||||||
|
{
|
||||||
|
DMSG("checksum is not ok\n");
|
||||||
|
return PN532_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
read(); // POSTAMBLE
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t PN532_I2C::readAckFrame()
|
||||||
|
{
|
||||||
|
const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0};
|
||||||
|
uint8_t ackBuf[sizeof(PN532_ACK)];
|
||||||
|
|
||||||
|
DMSG("wait for ack at : ");
|
||||||
|
DMSG(millis());
|
||||||
|
DMSG('\n');
|
||||||
|
|
||||||
|
uint16_t time = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (_wire->requestFrom(PN532_I2C_ADDRESS, sizeof(PN532_ACK) + 1))
|
||||||
|
{
|
||||||
|
if (read() & 1)
|
||||||
|
{ // check first byte --- status
|
||||||
|
break; // PN532 is ready
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1);
|
||||||
|
time++;
|
||||||
|
if (time > PN532_ACK_WAIT_TIME)
|
||||||
|
{
|
||||||
|
DMSG("Time out when waiting for ACK\n");
|
||||||
|
return PN532_TIMEOUT;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
DMSG("ready at : ");
|
||||||
|
DMSG(millis());
|
||||||
|
DMSG('\n');
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < sizeof(PN532_ACK); i++)
|
||||||
|
{
|
||||||
|
ackBuf[i] = read();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK)))
|
||||||
|
{
|
||||||
|
DMSG("Invalid ACK\n");
|
||||||
|
return PN532_INVALID_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* @modified picospuch
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PN532_I2C_H__
|
||||||
|
#define __PN532_I2C_H__
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include "PN532Interface.h"
|
||||||
|
|
||||||
|
class PN532_I2C : public PN532Interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PN532_I2C(TwoWire &wire);
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
void wakeup();
|
||||||
|
virtual 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:
|
||||||
|
TwoWire *_wire;
|
||||||
|
uint8_t command;
|
||||||
|
|
||||||
|
int8_t readAckFrame();
|
||||||
|
int16_t getResponseLength(uint8_t buf[], uint8_t len, uint16_t timeout);
|
||||||
|
|
||||||
|
inline uint8_t write(uint8_t data)
|
||||||
|
{
|
||||||
|
#if ARDUINO >= 100
|
||||||
|
return _wire->write(data);
|
||||||
|
#else
|
||||||
|
return _wire->send(data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t read()
|
||||||
|
{
|
||||||
|
#if ARDUINO >= 100
|
||||||
|
return _wire->read();
|
||||||
|
#else
|
||||||
|
return _wire->receive();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:airm2m_core_esp32c3]
|
||||||
|
platform = espressif32
|
||||||
|
board = airm2m_core_esp32c3
|
||||||
|
framework = arduino
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import time
|
||||||
|
import serial
|
||||||
|
import re
|
||||||
|
from vk import *
|
||||||
|
import winsound
|
||||||
|
|
||||||
|
# Configure your serial port and baud rate
|
||||||
|
SERIAL_PORT = 'COM3' # Replace 'COMx' with your serial port (e.g., 'COM3' on Windows or '/dev/ttyUSB0' on Linux)
|
||||||
|
# SERIAL_PORT = '/dev/ttyACM0'
|
||||||
|
BAUD_RATE = 115200
|
||||||
|
PATH = Path('C:/MUGS/felica.txt')
|
||||||
|
# PATH = Path('/tmp/felica.txt')
|
||||||
|
|
||||||
|
AUDIO_EFFECT = Path(__file__).parent / 'Audio/tofu.wav'
|
||||||
|
|
||||||
|
def parse_uid(data):
|
||||||
|
"""
|
||||||
|
Parse the UID from the serial data.
|
||||||
|
"""
|
||||||
|
uid_value_match = re.search(r'UID Value: ([0-9A-F]+)', data)
|
||||||
|
|
||||||
|
if uid_value_match:
|
||||||
|
uid = uid_value_match.group(1)
|
||||||
|
|
||||||
|
# If UID is not 8 bytes, pad it with zeros
|
||||||
|
if len(uid) < 16:
|
||||||
|
uid = uid.zfill(16)
|
||||||
|
|
||||||
|
# If the UID Doesn't start with 01 2E, set it to 01 2E
|
||||||
|
if uid[:4] != '012E':
|
||||||
|
uid = '012E' + uid[4:]
|
||||||
|
|
||||||
|
# Write the UID to the file
|
||||||
|
print(f"UID: {uid}")
|
||||||
|
PATH.write_text(uid)
|
||||||
|
|
||||||
|
# Play audio effect
|
||||||
|
winsound.PlaySound(str(AUDIO_EFFECT), winsound.SND_FILENAME)
|
||||||
|
|
||||||
|
# Press scan button
|
||||||
|
for i in range(3):
|
||||||
|
press_key()
|
||||||
|
time.sleep(0.1)
|
||||||
|
release_key()
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
return uid
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
|
||||||
|
print(f"Listening on {SERIAL_PORT}...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
if ser.in_waiting > 0:
|
||||||
|
line = ser.readline().decode('utf-8', errors='replace').strip()
|
||||||
|
print(line)
|
||||||
|
parse_uid(line)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("Exiting...")
|
||||||
|
finally:
|
||||||
|
ser.close()
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pyserial
|
||||||
|
pynput
|
||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <PN532_I2C.h>
|
||||||
|
#include <PN532.h>
|
||||||
|
#include <FastLED.h>
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
constexpr u8 NUM_LEDS = 7;
|
||||||
|
constexpr u8 BR_DIM = 8;
|
||||||
|
constexpr u8 BR_BRIGHT = 14;
|
||||||
|
CRGB leds[NUM_LEDS];
|
||||||
|
|
||||||
|
PN532_I2C pn532i2c(Wire);
|
||||||
|
PN532 nfc(pn532i2c);
|
||||||
|
|
||||||
|
constexpr u8 UID_LENGTH = 8;
|
||||||
|
u8 prevIDm[UID_LENGTH];
|
||||||
|
u32 prevTime;
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
// Add initial delay to allow the serial monitor to catch up
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
// Initialize serial port
|
||||||
|
USBSerial.begin(115200);
|
||||||
|
USBSerial.println("Hello!");
|
||||||
|
|
||||||
|
// Initialize I2C communication
|
||||||
|
Wire.setPins(GPIO_NUM_4, GPIO_NUM_5);
|
||||||
|
|
||||||
|
// Initialize the LED
|
||||||
|
CFastLED::addLeds<NEOPIXEL, GPIO_NUM_6>(leds, NUM_LEDS);
|
||||||
|
FastLED.setBrightness(BR_DIM);
|
||||||
|
|
||||||
|
// Find the PN532 NFC module
|
||||||
|
nfc.begin();
|
||||||
|
u32 versiondata;
|
||||||
|
while ((versiondata = nfc.getFirmwareVersion()) == 0)
|
||||||
|
{
|
||||||
|
USBSerial.println("Didn't find PN53x board");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Got ok data, print it out!
|
||||||
|
USBSerial.print("Found chip PN5");
|
||||||
|
USBSerial.println(versiondata >> 24 & 0xFF, HEX);
|
||||||
|
USBSerial.print("Firmware ver. ");
|
||||||
|
USBSerial.print(versiondata >> 16 & 0xFF, DEC);
|
||||||
|
USBSerial.print('.');
|
||||||
|
USBSerial.println(versiondata >> 8 & 0xFF, DEC);
|
||||||
|
|
||||||
|
// Set the max number of retry attempts to read from a card
|
||||||
|
// This prevents us from waiting forever for a card, which is the default behaviour of the PN532.
|
||||||
|
nfc.setPassiveActivationRetries(0xFF);
|
||||||
|
nfc.SAMConfig();
|
||||||
|
|
||||||
|
// Clear the IDm buffer
|
||||||
|
memset(prevIDm, 0, UID_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void led_animation()
|
||||||
|
{
|
||||||
|
FastLED.setBrightness(BR_BRIGHT);
|
||||||
|
CRGB colors[] = {CRGB::LimeGreen, CRGB::Black, CRGB::Gold, CRGB::Black};
|
||||||
|
|
||||||
|
for (const auto color : colors)
|
||||||
|
{
|
||||||
|
for (u8 i = 1; i < NUM_LEDS; i++)
|
||||||
|
{
|
||||||
|
leds[i] = color;
|
||||||
|
FastLED.show();
|
||||||
|
delay(35);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FastLED.setBrightness(BR_DIM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void foundCard(const u8* uid, const u8 len, const char* cardType)
|
||||||
|
{
|
||||||
|
// Check if the same card is present
|
||||||
|
if (memcmp(uid, prevIDm, UID_LENGTH) == 0 && millis() - prevTime < 3000)
|
||||||
|
{
|
||||||
|
delay(5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBSerial.printf("\nFound a %s card!\n", cardType);
|
||||||
|
USBSerial.print("UID Value: ");
|
||||||
|
for (u8 i = 0; i < len; i++)
|
||||||
|
USBSerial.print(uid[i], HEX);
|
||||||
|
USBSerial.println("");
|
||||||
|
|
||||||
|
led_animation();
|
||||||
|
|
||||||
|
memcpy(prevIDm, uid, UID_LENGTH);
|
||||||
|
prevTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
u8 idm[UID_LENGTH] = {0};
|
||||||
|
u8 pmm[8];
|
||||||
|
u16 systemCode;
|
||||||
|
|
||||||
|
// Wait for an FeliCa type cards.
|
||||||
|
// When one is found, some basic information such as IDm, PMm, and System Code are retrieved.
|
||||||
|
leds[0] = CRGB::BlueViolet;
|
||||||
|
FastLED.show();
|
||||||
|
if (nfc.felica_Polling(0xFFFF, 0x00, idm, pmm, &systemCode, 5) == 1)
|
||||||
|
foundCard(idm, UID_LENGTH, "FeliCa");
|
||||||
|
|
||||||
|
// Wait for an ISO14443A type cards (MIFARE, etc.). When one is found
|
||||||
|
u8 uidLength;
|
||||||
|
leds[0] = CRGB::OrangeRed;
|
||||||
|
FastLED.show();
|
||||||
|
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, idm, &uidLength, 5) == 1)
|
||||||
|
foundCard(idm, uidLength, "ISO14443A");
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
%1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0 ::","","runas",1)(window.close)&&exit
|
||||||
|
cd /d "%~dp0"
|
||||||
|
cd Code\CardReader
|
||||||
|
:Start
|
||||||
|
python receiver.py
|
||||||
|
echo Press Ctrl-C if you don't want to restart automatically
|
||||||
|
ping -n 1 localhost
|
||||||
|
|
||||||
|
goto Start
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import ctypes
|
||||||
|
from ctypes import wintypes
|
||||||
|
|
||||||
|
# Virtual-Key codes
|
||||||
|
# RESERVED: 0xEA
|
||||||
|
VK = 0x6B
|
||||||
|
KEYEVENTF_KEYUP = 0x0002
|
||||||
|
|
||||||
|
def press_key(vk_code = VK):
|
||||||
|
scan_code = ctypes.windll.user32.MapVirtualKeyA(vk_code, 0)
|
||||||
|
ctypes.windll.user32.keybd_event(vk_code, scan_code, 0, 0)
|
||||||
|
|
||||||
|
def release_key(vk_code = VK):
|
||||||
|
scan_code = ctypes.windll.user32.MapVirtualKeyA(vk_code, 0)
|
||||||
|
ctypes.windll.user32.keybd_event(vk_code, scan_code, KEYEVENTF_KEYUP, 0)
|
||||||
Reference in New Issue
Block a user