--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare.h
+*/
+/**************************************************************************/
+
+#ifndef __PN532_MIFARE_H__
+#define __PN532_MIFARE_H__
+
+#include "projectconfig.h"
+
+// These may need to be enlarged for multi card support
+#define PN532_RESPONSELEN_INLISTPASSIVETARGET (32)
+#define PN532_RESPONSELEN_INDATAEXCHANGE (32)
+
+typedef enum pn532_mifare_cmd_e
+{
+ PN532_MIFARE_CMD_AUTH_A = 0x60,
+ PN532_MIFARE_CMD_AUTH_B = 0x61,
+ PN532_MIFARE_CMD_READ = 0x30,
+ PN532_MIFARE_CMD_WRITE = 0xA0,
+ PN532_MIFARE_CMD_TRANSFER = 0xB0,
+ PN532_MIFARE_CMD_DECREMENT = 0xC0,
+ PN532_MIFARE_CMD_INCREMENT = 0xC1,
+ PN532_MIFARE_CMD_STORE = 0xC2
+}
+pn532_mifare_cmd_t;
+
+#endif
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare_classic.c
+*/
+/**************************************************************************/
+
+/* MIFARE CLASSIC DESCRIPTION
+ ==========================
+
+ MIFARE Classic cards come in 1K and 4K varieties. While several
+ varieties of chips exist, the two main chipsets used are described
+ in the following publicly accessible documents:
+
+ MF1S503x Mifare Classic 1K data sheet:
+ http://www.nxp.com/documents/data_sheet/MF1S503x.pdf
+
+ MF1S70yyX MIFARE Classic 4K data sheet:
+ http://www.nxp.com/documents/data_sheet/MF1S70YYX.pdf
+
+ Mifare Classic cards typically have a a 4-byte NUID, though you may
+ find cards with 7 byte IDs as well
+
+ EEPROM MEMORY
+ =============
+ Mifare Classic cards have either 1K or 4K of EEPROM memory. Each
+ memory block can be configured with different access conditions,
+ with two seperate authentication keys present in each block.
+
+ The two main Mifare Classic card types are organised as follows:
+
+ 1K Cards: 16 sectors of 4 blocks (0..15)
+ 4K Cards: 32 sectors of 4 blocks (0..31) and
+ 8 sectors of 16 blocks (32..39)
+
+ 4 block sectors
+ ===============
+ Sector Block Bytes Description
+ ------ ----- ----- -----------
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+
+ 1 3 [-------KEY A-------] [Access Bits] [-------KEY A-------] Sector Trailer 1
+ 2 [ Data ] Data
+ 1 [ Data ] Data
+ 0 [ Data ] Data
+
+ 0 3 [-------KEY A-------] [Access Bits] [-------KEY A-------] Sector Trailer 1
+ 2 [ Data ] Data
+ 1 [ Data ] Data
+ 0 [ Manufacturer Data ] Manufacturer Block
+
+ Sector Trailer (Block 3)
+ ------------------------
+ The sector trailer block contains the two secret keys (Key A and Key B), as well
+ as the access conditions for the four blocks. It has the following structure:
+
+ Sector Trailer Bytes
+ --------------------------------------------------------------
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ [ Key A ] [Access Bits] [ Key B ]
+
+ For more information in using Keys to access the clock contents, see
+ Accessing Data Blocks further below.
+
+ Data Blocks (Blocks 0..2)
+ -------------------------
+ Data blocks are 16 bytes wide and, depending on the permissions set in the
+ access bits, can be read from and written to. You are free to use the 16 data
+ bytes in any way you wish. You can easily store text input, store four 32-bit
+ integer values, a 16 character uri, etc.
+
+ Data Blocks as "Value Blocks"
+ -----------------------------
+ An alternative to storing random data in the 16 byte-wide blocks is to
+ configure them as "Value Blocks". Value blocks allow performing electronic
+ purse functions (valid commands are: read, write, increment, decrement,
+ restore, transfer).
+
+ Each Value block contains a single signed 32-bit value, and this value is
+ stored 3 times for data integrity and security reasons. It is stored twice
+ non-inverted, and once inverted. The last 4 bytes are used for a 1-byte
+ address, which is stored 4 times (twice non-inverted, and twice inverted).
+
+ Data blocks configured as "Value Blocks" have the following structure:
+
+ Value Block Bytes
+ --------------------------------------------------------------
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ [ Value ] [ ~Value ] [ Value ] [A ~A A ~A]
+
+ Manufacturer Block (Sector 0, Block 0)
+ --------------------------------------
+ Sector 0 is special since it contains the Manufacturer Block. This block
+ contains the manufacturer data, and is read-only. It should be avoided
+ unless you know what you are doing.
+
+ 16 block sectors
+ ================
+ 16 block sectors are identical to 4 block sectors, but with more data blocks. The same
+ structure described in the 4 block sectors above applies.
+
+ Sector Block Bytes Description
+ ------ ----- ----- ----------
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+
+ 32 15 [-------KEY A-------] [Access Bits] [-------KEY B-------] Sector Trailer 32
+ 14 [ Data ] Data
+ 13 [ Data ] Data
+ ...
+ 2 [ Data ] Data
+ 1 [ Data ] Data
+ 0 [ Data ] Data
+
+ ACCESSING DATA BLOCKS
+ =====================
+
+ Before you can access the cards, you must following two steps:
+
+ 1.) You must retrieve the 7 byte UID or the 4-byte NUID of the card.
+ This can be done using pn532_mifareclassic_WaitForPassiveTarget()
+ below, which will return the appropriate ID.
+
+ 2.) You must authenticate the sector you wish to access according to the
+ access rules defined in the Sector Trailer block for that sector.
+ This can be done using pn532_mifareclassic_AuthenticateBlock(),
+ passing in the appropriate key value.
+
+ Most new cards have a default Key A of 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF,
+ but some common values worth trying are:
+
+ 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
+ 0XD3 0XF7 0XD3 0XF7 0XD3 0XF7
+ 0XA0 0XA1 0XA2 0XA3 0XA4 0XA5
+ 0XB0 0XB1 0XB2 0XB3 0XB4 0XB5
+ 0X4D 0X3A 0X99 0XC3 0X51 0XDD
+ 0X1A 0X98 0X2C 0X7E 0X45 0X9A
+ 0XAA 0XBB 0XCC 0XDD 0XEE 0XFF
+ 0X00 0X00 0X00 0X00 0X00 0X00
+ 0XAB 0XCD 0XEF 0X12 0X34 0X56
+
+ 3.) Once authenication has succeeded, and depending on the sector
+ permissions, you can then read/write/increment/decrement the
+ contents of the specific block, using one of the helper functions
+ included in this module.
+
+*/
+
+#include <string.h>
+
+#include "../pn532.h"
+#include "../pn532_bus.h"
+#include "pn532_mifare.h"
+#include "pn532_mifare_classic.h"
+
+#include "core/systick/systick.h"
+
+/**************************************************************************/
+/*!
+ Indicates whether the specified block number is the first block
+ in the sector (block 0 relative to the current sector)
+*/
+/**************************************************************************/
+bool is_first_block (uint32_t uiBlock)
+{
+ // Test if we are in the small or big sectors
+ if (uiBlock < 128)
+ return ((uiBlock) % 4 == 0);
+ else
+ return ((uiBlock) % 16 == 0);
+}
+
+/**************************************************************************/
+/*!
+ Indicates whether the specified block number is the sector trailer
+*/
+/**************************************************************************/
+bool is_trailer_block (uint32_t uiBlock)
+{
+ // Test if we are in the small or big sectors
+ if (uiBlock < 128)
+ return ((uiBlock + 1) % 4 == 0);
+ else
+ return ((uiBlock + 1) % 16 == 0);
+}
+
+/**************************************************************************/
+/*!
+ Tries to detect MIFARE targets in passive mode. This needs to be done
+ before anything useful can be accomplished with a tag since you need
+ the tag's unique UID to communicate with it.
+
+ @param pbtCUID Pointer to the byte array where the card's UID
+ will be stored once a card is detected
+ @param pszUIDLen Pointer to the size of the card UID in bytes
+
+ Response for a valid ISO14443A 106KBPS (Mifare Classic, etc.)
+ should be in the following format. See UM0701-02 section
+ 7.3.5 for more information
+
+ byte Description
+ ------------- ------------------------------------------
+ b0..6 Frame header and preamble
+ b7 Tags Found
+ b8 Tag Number (only one used in this example)
+ b9..10 SENS_RES
+ b11 SEL_RES
+ b12 NFCID Length
+ b13..NFCIDLen NFCID
+
+ SENS_RES SEL_RES Manufacturer/Card Type NFCID Len
+ -------- ------- ----------------------- ---------
+ 00 04 08 NXP Mifare Classic 1K 4 bytes
+ 00 02 18 NXP Mifare Classic 4K 4 bytes
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_WRONGCARDTYPE
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareclassic_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen)
+{
+ byte_t abtResponse[PN532_RESPONSELEN_INLISTPASSIVETARGET];
+ pn532_error_t error;
+ size_t szLen;
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Waiting for an ISO14443A Card%s", CFG_PRINTF_NEWLINE);
+ #endif
+
+ /* Try to initialise a single ISO14443A tag at 106KBPS */
+ /* Note: To wait for a card with a known UID, append the four byte */
+ /* UID to the end of the command. */
+ byte_t abtCommand[] = { PN532_COMMAND_INLISTPASSIVETARGET, 0x01, PN532_MODULATION_ISO14443A_106KBPS};
+ error = pn532Write(abtCommand, sizeof(abtCommand));
+ if (error)
+ return error;
+
+ /* Wait until we get a valid response or a timeout */
+ do
+ {
+ systickDelay(25);
+ error = pn532Read(abtResponse, &szLen);
+ } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ return error;
+
+ /* Check SENSE_RES to make sure this is a Mifare Classic card */
+ /* Classic 1K = 00 04 */
+ /* Classic 4K = 00 02 */
+ /* Classic Emulated = 00 08 */
+ if ((abtResponse[10] == 0x02) ||
+ (abtResponse[10] == 0x04) ||
+ (abtResponse[10] == 0x08))
+ {
+ /* Card appears to be Mifare Classic */
+ *szCUIDLen = abtResponse[12];
+ for (uint8_t i=0; i < *szCUIDLen; i++)
+ {
+ pbtCUID[i] = abtResponse[13+i];
+ }
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Card Found: %s", CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" ATQA: ");
+ pn532PrintHex(abtResponse+9, 2);
+ PN532_DEBUG(" SAK: %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID: ");
+ pn532PrintHex(pbtCUID, *szCUIDLen);
+ #endif
+ }
+ else
+ {
+ /* Card is ISO14443A but doesn't appear to be Mifare Classic */
+ /* Mifare Ultralight = 0x0044 */
+ /* Mifare DESFire = 0x0344 */
+ /* Innovision Jewel = 0x0C00 */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Wrong Card Type (Expected ATQA 00 02, 00 04 or 00 08) %s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" ATQA : ");
+ pn532PrintHex(abtResponse+9, 2);
+ PN532_DEBUG(" SAK : %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID Length : %d%s", abtResponse[12], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID : ");
+ size_t pos;
+ for (pos=0; pos < abtResponse[12]; pos++)
+ {
+ printf("%02x ", abtResponse[13 + pos]);
+ }
+ printf("%s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_WRONGCARDTYPE;
+ }
+
+ return PN532_ERROR_NONE;
+}
+
+
+/**************************************************************************/
+/*!
+ Tries to authenticate a block of memory on a MIFARE card using the
+ INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
+ for more information on sending MIFARE and other commands.
+
+ @param pbtCUID Pointer to a byte array containing the card UID
+ @param szCUIDLen The length (in bytes) of the card's UID (Should
+ be 4 for MIFARE Classic)
+ @param uiBlockNumber The block number to authenticate. (0..63 for
+ 1KB cards, and 0..255 for 4KB cards).
+ @param uiKeyType Which key type to use during authentication
+ (PN532_MIFARE_CMD_AUTH_A or PN532_MIFARE_CMD_AUTH_B)
+ @param pbtKeys Pointer to a byte array containing the 6 byte
+ key value
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareclassic_AuthenticateBlock (byte_t * pbtCUID, size_t szCUIDLen, uint32_t uiBlockNumber, uint8_t uiKeyType, byte_t * pbtKeys)
+{
+ pn532_error_t error;
+ byte_t abtCommand[17];
+ byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
+ size_t szLen;
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Trying to authenticate card ");
+ pn532PrintHex(pbtCUID, szCUIDLen);
+ #endif
+
+ /* Prepare the authentication command */
+ abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
+ abtCommand[1] = 1; /* Max card numbers */
+ abtCommand[2] = (uiKeyType) ? PN532_MIFARE_CMD_AUTH_A : PN532_MIFARE_CMD_AUTH_B;
+ abtCommand[3] = uiBlockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
+ memcpy (abtCommand+4, pbtKeys, 6);
+ uint8_t i;
+ for (i = 0; i < szCUIDLen; i++)
+ {
+ abtCommand[10+i] = pbtCUID[i]; /* 4 byte card ID */
+ }
+
+ /* Send the command */
+ error = pn532Write(abtCommand, 10+szCUIDLen);
+ if (error)
+ {
+ /* Problem with the serial bus, etc. */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Authentification failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Read the authentification response */
+ memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
+ do
+ {
+ systickDelay(25);
+ error = pn532Read(abtResponse, &szLen);
+ }
+ while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Authentification failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ // ToDo: How to check if authentification really worked (bad key, etc.)?
+
+ /* Output the authentification data */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Authenticated block %d %s", uiBlockNumber, CFG_PRINTF_NEWLINE);
+ #endif
+
+ // Return OK signal
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ Tries to read an entire 16-byte data block at the specified block
+ address.
+
+ @param uiBlockNumber The block number to authenticate. (0..63 for
+ 1KB cards, and 0..255 for 4KB cards).
+ @param pbtData Pointer to the byte array that will hold the
+ retrieved data (if any)
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_BLOCKREADFAILED
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareclassic_ReadDataBlock (uint8_t uiBlockNumber, byte_t * pbtData)
+{
+ pn532_error_t error;
+ byte_t abtCommand[4];
+ byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
+ size_t szLen;
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Reading 16 bytes at block %03d%s", uiBlockNumber, CFG_PRINTF_NEWLINE);
+ #endif
+
+ /* Prepare the command */
+ abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE;
+ abtCommand[1] = 1; /* Card number */
+ abtCommand[2] = PN532_MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
+ abtCommand[3] = uiBlockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
+
+ /* Send the commands */
+ error = pn532Write(abtCommand, sizeof(abtCommand));
+ if (error)
+ {
+ /* Bus error, etc. */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Read the response */
+ memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
+ do
+ {
+ systickDelay(50);
+ error = pn532Read(abtResponse, &szLen);
+ }
+ while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Make sure we have a valid response (should be 26 bytes long) */
+ if (szLen == 26)
+ {
+ /* Copy the 16 data bytes to the output buffer */
+ /* Block content starts at byte 8 of a valid response */
+ memcpy (pbtData, abtResponse+7, 16);
+ }
+ else
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Unexpected response reading block %d. Bad key?%s", uiBlockNumber, CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_BLOCKREADFAILED;
+ }
+
+ /* Display data for debug if requested */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Block %03d: ", uiBlockNumber, CFG_PRINTF_NEWLINE);
+ pn532PrintHexVerbose(pbtData, 16);
+ #endif
+
+ // Return OK signal
+ return PN532_ERROR_NONE;
+}
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare_classic.h
+*/
+/**************************************************************************/
+
+#ifndef __PN532_MIFARE_CLASSIC_H__
+#define __PN532_MIFARE_CLASSIC_H__
+
+#include "projectconfig.h"
+#include "pn532_mifare.h"
+
+pn532_error_t pn532_mifareclassic_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen);
+pn532_error_t pn532_mifareclassic_AuthenticateBlock (byte_t * pbtCUID, size_t szCUIDLen, uint32_t uiBlockNumber, uint8_t uiKeyType, byte_t * pbtKeys);
+pn532_error_t pn532_mifareclassic_ReadDataBlock (uint8_t uiBlockNumber, byte_t * pbtData);
+
+#endif
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare_ultralight.c
+*/
+/**************************************************************************/
+
+/* MIFARE ULTRALIGHT DESCRIPTION
+ =============================
+
+ MIFARE Ultralight cards typically contain 512 bits (64 bytes) of
+ memory, including 4 bytes (32-bits) of OTP (One Time Programmable)
+ memory where the individual bits can be written but not erased.
+
+ MF0ICU1 Mifare Ultralight Functional Specification:
+ http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf
+
+
+ Mifare Ultralight cards have a 7-byte UID
+
+ EEPROM MEMORY
+ =============
+ Mifare Ultralight cards have 512 bits (64 bytes) of EEPROM memory,
+ including 4 byte (32 bits) of OTP memory. Unlike Mifare Classic cards,
+ there is no authentication on a per block level, although the blocks
+ can be set to "read-only" mode using Lock Bytes (described below).
+
+ EEPROM memory is organised into 16 pages of four bytes eachs, in
+ the following order
+
+ Page Description
+ ---- ------------
+ 0 Serial Number (4 bytes)
+ 1 Serial Number (4 bytes)
+ 2 Byte 0: Serial Number
+ Byte 1: Internal Memory
+ Byte 2..3: lock bytes
+ 3 One-time programmable memory (4 bytes)
+ 4..15 User memory (4 bytes)
+
+ Lock Bytes (Page 2)
+ -------------------
+ Bytes 2 and 3 of page 2 are referred to as "Lock Bytes". Each
+ page from 0x03 and higher can individually locked by setting the
+ corresponding locking bit to "1" to prevent further write access,
+ effectively making the memory read only.
+
+ For information on the lock byte mechanism, refer to section 8.5.2 of
+ the datasheet (referenced above).
+
+ OTP Bytes (Page 3)
+ ------------------
+ Page 3 is the OTP memory, and by default all bits on this page are
+ set to 0. These bits can be bitwise modified using the Mifare WRITE
+ command, and individual bits can be set to 1, but can not be changed
+ back to 0.
+
+ Data Pages (Pages 4..15)
+ ------------------------
+ Pages 4 to 15 are can be freely read from and written to,
+ provided there is no conflict with the Lock Bytes described above.
+
+ After production, the bytes have the following default values:
+
+ Page Byte Values
+ ---- ----------------------
+ 0 1 2 3
+ 4 0xFF 0xFF 0xFF 0xFF
+ 5..15 0x00 0x00 0x00 0x00
+
+ ACCESSING DATA BLOCKS
+ =====================
+
+ Before you can access the cards, you must following two steps:
+
+ 1.) 'Connect' to a Mifare Ultralight card and retrieve the 7 byte
+ UID of the card.
+
+ 2.) Memory can be read and written directly once a passive mode
+ connection has been made. No authentication is required for
+ Mifare Ultralight cards.
+
+*/
+
+#include <string.h>
+
+#include "../pn532.h"
+#include "../pn532_bus.h"
+#include "pn532_mifare_ultralight.h"
+
+#include "core/systick/systick.h"
+
+/**************************************************************************/
+/*!
+ Tries to detect MIFARE targets in passive mode.
+
+ @param pbtCUID Pointer to the byte array where the card's 7 byte
+ UID will be stored once a card is detected
+ @param pszUIDLen Pointer to the size of the card UID in bytes
+
+ Response for a valid ISO14443A 106KBPS (Mifare Ultralight, etc.)
+ should be in the following format. See UM0701-02 section
+ 7.3.5 for more information
+
+ byte Description
+ ------------- ------------------------------------------
+ b0..6 Frame header and preamble
+ b7 Tags Found
+ b8 Tag Number (only one used in this example)
+ b9..10 SENS_RES
+ b11 SEL_RES
+ b12 NFCID Length
+ b13..NFCIDLen NFCID
+
+ SENS_RES SEL_RES Manufacturer/Card Type NFCID Len
+ -------- ------- ----------------------- ---------
+ 00 44 00 NXP Mifare Ultralight 7 bytes
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_WRONGCARDTYPE
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareultralight_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen)
+{
+ byte_t abtResponse[PN532_RESPONSELEN_INLISTPASSIVETARGET];
+ pn532_error_t error;
+ size_t szLen;
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Waiting for an ISO14443A Card%s", CFG_PRINTF_NEWLINE);
+ #endif
+
+ /* Try to initialise a single ISO14443A tag at 106KBPS */
+ /* Note: To wait for a card with a known UID, append the four byte */
+ /* UID to the end of the command. */
+ byte_t abtCommand[] = { PN532_COMMAND_INLISTPASSIVETARGET, 0x01, PN532_MODULATION_ISO14443A_106KBPS};
+ error = pn532Write(abtCommand, sizeof(abtCommand));
+ if (error)
+ return error;
+
+ /* Wait until we get a valid response or a timeout */
+ do
+ {
+ systickDelay(25);
+ error = pn532Read(abtResponse, &szLen);
+ } while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ return error;
+
+ /* Check SENS_RES to make sure this is a Mifare Ultralight card */
+ /* Mifare Ultralight = 00 44 */
+ if (abtResponse[10] == 0x44)
+ {
+ /* Card appears to be Mifare Ultralight */
+ *szCUIDLen = abtResponse[12];
+ for (uint8_t i=0; i < *szCUIDLen; i++)
+ {
+ pbtCUID[i] = abtResponse[13+i];
+ }
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Card Found: %s", CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" ATQA: ");
+ pn532PrintHex(abtResponse+9, 2);
+ PN532_DEBUG(" SAK: %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID: ");
+ pn532PrintHex(pbtCUID, *szCUIDLen);
+ #endif
+ }
+ else
+ {
+ /* Card is ISO14443A but doesn't appear to be Mifare Ultralight */
+ /* Mifare Classic = 0x0002, 0x0004, 0x0008 */
+ /* Mifare DESFire = 0x0344 */
+ /* Innovision Jewel = 0x0C00 */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Wrong Card Type (Expected ATQA 00 44) %s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" ATQA : ");
+ pn532PrintHex(abtResponse+9, 2);
+ PN532_DEBUG(" SAK : %02x%s", abtResponse[11], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID Length : %d%s", abtResponse[12], CFG_PRINTF_NEWLINE);
+ PN532_DEBUG(" UID : ");
+ size_t pos;
+ for (pos=0; pos < abtResponse[12]; pos++)
+ {
+ printf("%02x ", abtResponse[13 + pos]);
+ }
+ printf("%s%s", CFG_PRINTF_NEWLINE, CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_WRONGCARDTYPE;
+ }
+
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ Tries to read an entire 4-byte page at the specified address.
+
+ @param page The page number (0..63 in most cases)
+ @param pbtBuffer Pointer to the byte array that will hold the
+ retrieved data (if any)
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_ADDRESSOUTOFRANGE
+ - PN532_ERROR_BLOCKREADFAILED
+*/
+/**************************************************************************/
+pn532_error_t pn532_mifareultralight_ReadPage (uint8_t page, byte_t * pbtBuffer)
+{
+ pn532_error_t error;
+ byte_t abtCommand[4];
+ byte_t abtResponse[PN532_RESPONSELEN_INDATAEXCHANGE];
+ size_t szLen;
+
+ if (page >= 64)
+ {
+ return PN532_ERROR_ADDRESSOUTOFRANGE;
+ }
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Reading page %03d%s", page, CFG_PRINTF_NEWLINE);
+ #endif
+
+ /* Prepare the command */
+ abtCommand[0] = PN532_COMMAND_INDATAEXCHANGE;
+ abtCommand[1] = 1; /* Card number */
+ abtCommand[2] = PN532_MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
+ abtCommand[3] = page; /* Page Number (0..63 in most cases) */
+
+ /* Send the commands */
+ error = pn532Write(abtCommand, sizeof(abtCommand));
+ if (error)
+ {
+ /* Bus error, etc. */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Read the response */
+ memset(abtResponse, 0, PN532_RESPONSELEN_INDATAEXCHANGE);
+ do
+ {
+ systickDelay(50);
+ error = pn532Read(abtResponse, &szLen);
+ }
+ while (error == PN532_ERROR_RESPONSEBUFFEREMPTY);
+ if (error)
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Read failed%s", CFG_PRINTF_NEWLINE);
+ #endif
+ return error;
+ }
+
+ /* Make sure we have a valid response (should be 26 bytes long) */
+ if (szLen == 26)
+ {
+ /* Copy the 4 data bytes to the output buffer */
+ /* Block content starts at byte 8 of a valid response */
+ /* Note that the command actually reads 16 byte or 4 */
+ /* pages at a time ... we simply discard the last 12 */
+ /* bytes */
+ memcpy (pbtBuffer, abtResponse+8, 4);
+ }
+ else
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Unexpected response reading block %d. Bad key?%s", page, CFG_PRINTF_NEWLINE);
+ #endif
+ return PN532_ERROR_BLOCKREADFAILED;
+ }
+
+ /* Display data for debug if requested */
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Page %02d: ", page, CFG_PRINTF_NEWLINE);
+ pn532PrintHexVerbose(pbtBuffer, 4);
+ #endif
+
+ // Return OK signal
+ return PN532_ERROR_NONE;
+}
+
+//static bool
+//read_card (void)
+//{
+// uint32_t page;
+// bool bFailure = false;
+// uint32_t uiReadedPages = 0;
+//
+// printf ("Reading %d pages |", uiBlocks + 1);
+//
+// for (page = 0; page <= uiBlocks; page += 4) {
+// // Try to read out the data block
+// if (nfc_initiator_mifare_cmd (pnd, MC_READ, page, &mp)) {
+// memcpy (mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16);
+// } else {
+// bFailure = true;
+// break;
+// }
+//
+// print_success_or_failure (bFailure, &uiReadedPages);
+// print_success_or_failure (bFailure, &uiReadedPages);
+// print_success_or_failure (bFailure, &uiReadedPages);
+// print_success_or_failure (bFailure, &uiReadedPages);
+// }
+// printf ("|\n");
+// printf ("Done, %d of %d pages readed.\n", uiReadedPages, uiBlocks + 1);
+// fflush (stdout);
+//
+// return (!bFailure);
+//}
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_mifare_ultralight.h
+*/
+/**************************************************************************/
+
+#ifndef __PN532_MIFARE_ULTRALIGHT_H__
+#define __PN532_MIFARE_ULTRALIGHT_H__
+
+#include "projectconfig.h"
+#include "pn532_mifare.h"
+
+pn532_error_t pn532_mifareultralight_WaitForPassiveTarget (byte_t * pbtCUID, size_t * szCUIDLen);
+pn532_error_t pn532_mifareultralight_ReadPage (uint8_t page, byte_t * pbtBuffer);
+
+#endif
@param szBytes Data length in bytes
*/
/**************************************************************************/
-void pn532PrintHexVerbose(const byte_t * pbtData, const size_t szBytes)
+void pn532PrintHexChar(const byte_t * pbtData, const size_t szBytes)
{
size_t szPos;
for (szPos=0; szPos < szBytes; szPos++)
printf(" ");
for (szPos=0; szPos < szBytes; szPos++)
{
- printf("%c", pbtData[szPos] == 0 ? '.' : pbtData[szPos]);
+ printf("%c", pbtData[szPos] <= 0x1F ? '.' : pbtData[szPos]);
}
printf(CFG_PRINTF_NEWLINE);
}
#include "projectconfig.h"
// Comment out this line to disable debug output
-#define PN532_DEBUGMODE
+// #define PN532_DEBUGMODE
#define PN532_DEBUG(fmt, args...) printf(fmt, ##args)
/* Error messages generated by the stack */
} pn532_pcb_t;
void pn532PrintHex(const byte_t * pbtData, const size_t szBytes);
-void pn532PrintHexVerbose(const byte_t * pbtData, const size_t szBytes);
+void pn532PrintHexChar(const byte_t * pbtData, const size_t szBytes);
pn532_pcb_t * pn532GetPCB();
void pn532Init();
pn532_error_t pn532Read(byte_t *pbtResponse, size_t * pszLen);
--- /dev/null
+/**************************************************************************/
+/*!
+ @file pn532_bus_uart.c
+*/
+/**************************************************************************/
+#include <string.h>
+
+#include "pn532.h"
+#include "pn532_bus.h"
+
+#ifdef PN532_BUS_UART
+
+#include "core/systick/systick.h"
+#include "core/gpio/gpio.h"
+#include "core/uart/uart.h"
+
+/**************************************************************************/
+/*!
+ @brief Builds a standard PN532 frame using the supplied data
+
+ @param pbtFrame Pointer to the field that will hold the frame data
+ @param pszFrame Pointer to the field that will hold the frame length
+ @param pbtData Pointer to the data to insert in a frame
+ @param swData Length of the data to insert in bytes
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_EXTENDEDFRAME
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_BuildFrame(byte_t * pbtFrame, size_t * pszFrame, const byte_t * pbtData, const size_t szData)
+{
+ if (szData > PN532_NORMAL_FRAME__DATA_MAX_LEN)
+ {
+ // Extended frames currently unsupported
+ return PN532_ERROR_EXTENDEDFRAME;
+ }
+
+ // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
+ pbtFrame[3] = szData + 1;
+ // LCS - Packet length checksum
+ pbtFrame[4] = 256 - (szData + 1);
+ // TFI
+ pbtFrame[5] = 0xD4;
+ // DATA - Copy the PN53X command into the packet buffer
+ memcpy (pbtFrame + 6, pbtData, szData);
+
+ // DCS - Calculate data payload checksum
+ byte_t btDCS = (256 - 0xD4);
+ size_t szPos;
+ for (szPos = 0; szPos < szData; szPos++)
+ {
+ btDCS -= pbtData[szPos];
+ }
+ pbtFrame[6 + szData] = btDCS;
+
+ // 0x00 - End of stream marker
+ pbtFrame[szData + 7] = 0x00;
+
+ (*pszFrame) = szData + PN532_NORMAL_FRAME__OVERHEAD;
+
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Initialises UART and configures the PN532
+*/
+/**************************************************************************/
+void pn532_bus_HWInit(void)
+{
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Initialising UART (%d)%s", PN532_UART_BAUDRATE, CFG_PRINTF_NEWLINE);
+ #endif
+ uartInit(PN532_UART_BAUDRATE);
+
+ // Set reset pin as output and reset device
+ gpioSetDir(PN532_RSTPD_PORT, PN532_RSTPD_PIN, gpioDirection_Output);
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Resetting the PN532...\r\n");
+ #endif
+ gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 0);
+ systickDelay(400);
+ gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 1);
+
+ // Wait for the PN532 to finish booting
+ systickDelay(100);
+}
+
+/**************************************************************************/
+/*!
+ @brief Sends the specified command to the PN532, automatically
+ creating an appropriate frame for it
+
+ @param pdbData Pointer to the byte data to send
+ @param szData Length in bytes of the data to send
+
+ @note Possible error messages are:
+
+ - PN532_ERROR_BUSY
+ - PN532_ERROR_NOACK
+ - PN532_ERROR_INVALIDACK
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_SendCommand(const byte_t * pbtData, const size_t szData)
+{
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ // Check if we're busy
+ if (pn532->state == PN532_STATE_BUSY)
+ {
+ return PN532_ERROR_BUSY;
+ }
+
+ // Flag the stack as busy
+ pn532->state = PN532_STATE_BUSY;
+
+ // Every packet must start with "00 00 ff"
+ byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
+ size_t szFrame = 0;
+
+ // Build the frame
+ pn532_bus_BuildFrame (abtFrame, &szFrame, pbtData, szData);
+
+ // Keep track of the last command that was sent
+ pn532->lastCommand = pbtData[0];
+
+ // Output the frame data for debugging if requested
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Sending (%02d): ", szFrame);
+ pn532PrintHex(abtFrame, szFrame);
+ #endif
+
+ // Send data to the PN532
+ uartSend (abtFrame, szFrame);
+
+ // Wait for ACK
+ byte_t abtRxBuf[6];
+ uart_pcb_t *uart = uartGetPCB();
+ systickDelay(10); // FIXME: How long should we wait for ACK?
+ if (uart->rxfifo.len < 6)
+ {
+ // Unable to read ACK
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG ("Unable to read ACK%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NOACK;
+ }
+
+ // Read ACK ... this will also remove it from the buffer
+ const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
+ abtRxBuf[0] = uartRxBufferRead();
+ abtRxBuf[1] = uartRxBufferRead();
+ abtRxBuf[2] = uartRxBufferRead();
+ abtRxBuf[3] = uartRxBufferRead();
+ abtRxBuf[4] = uartRxBufferRead();
+ abtRxBuf[5] = uartRxBufferRead();
+
+ // Make sure the received ACK matches the prototype
+ if (0 != (memcmp (abtRxBuf, abtAck, 6)))
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG ("Invalid ACK: ");
+ pn532PrintHex(abtRxBuf, 6);
+ PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_INVALIDACK;
+ }
+
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Reads a response from the PN532
+
+ @note Possible error message are:
+
+ - PN532_ERROR_BUSY
+ - PN532_ERROR_RESPONSEBUFFEREMPTY
+ - PN532_ERROR_PREAMBLEMISMATCH
+ - PN532_ERROR_APPLEVELERROR
+ - PN532_ERROR_EXTENDEDFRAME
+ - PN532_ERROR_LENCHECKSUMMISMATCH
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
+{
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ // Check if we're busy
+ if (pn532->state == PN532_STATE_BUSY)
+ {
+ return PN532_ERROR_BUSY;
+ }
+
+ // Flag the stack as busy
+ pn532->state = PN532_STATE_BUSY;
+
+ // Reset the app error flag
+ pn532->appError = PN532_APPERROR_NONE;
+
+ // Read response from uart
+ if (!uartRxBufferReadArray(pbtResponse, pszRxLen))
+ {
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_RESPONSEBUFFEREMPTY;
+ }
+
+ // Display the raw response data for debugging if requested
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Received (%02d): ", *pszRxLen);
+ pn532PrintHex(pbtResponse, *pszRxLen);
+ #endif
+
+ // Check preamble
+ const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
+ if (0 != (memcmp (pbtResponse, pn53x_preamble, 3)))
+ {
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_PREAMBLEMISMATCH;
+ }
+
+ // Check the frame type
+ if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4]))
+ {
+ // Error frame
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Application level error (0x%02x)%s", pbtResponse[5], CFG_PRINTF_NEWLINE);
+ #endif
+ // Set application error message ID
+ pn532->appError = pbtResponse[5];
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_APPLEVELERROR;
+ }
+ else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4]))
+ {
+ // Extended frame
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_EXTENDEDFRAME;
+ }
+ else
+ {
+ // Normal frame
+ if (256 != (pbtResponse[3] + pbtResponse[4]))
+ {
+ // TODO: Retry
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
+ #endif
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_LENCHECKSUMMISMATCH;
+ }
+ // size_t szPayloadLen = abtRx[3] - 2;
+ }
+
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NONE;
+}
+
+/**************************************************************************/
+/*!
+ @brief Sends the wakeup sequence to the PN532.
+*/
+/**************************************************************************/
+pn532_error_t pn532_bus_Wakeup(void)
+{
+ size_t szLen;
+ byte_t abtWakeUp[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };
+
+ pn532_pcb_t *pn532 = pn532GetPCB();
+
+ #ifdef PN532_DEBUGMODE
+ PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
+ #endif
+ uartSend(abtWakeUp,sizeof(abtWakeUp));
+ systickDelay(100);
+
+ byte_t response[32];
+ pn532_bus_ReadResponse(response, &szLen);
+
+ // Todo: Check for error ... currently throws a checksum error
+ // that isn't really an error
+
+ pn532->state = PN532_STATE_READY;
+ return PN532_ERROR_NONE;
+}
+
+#endif // #ifdef PN532_BUS_UART
\ No newline at end of file