diff --git a/README.TXT b/README.TXT
index 22c3e77..01ce245 100644
--- a/README.TXT
+++ b/README.TXT
@@ -2,145 +2,23 @@
Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+------------------------------------------------------------------------
+Welcome to the developers community of libnfc.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+Since it is hard to keep all information up to date
+we decided to only maintain the online documentation.
+Please visit the official website for more info:
+http://www.libnfc.org
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
+If you have questions, remarks, bug-reports, we encourage you to
+post this in the developers community:
+http://www.libnfc.org/community
------------------------------------------------------------------------
-Welcome to the community of libnfc (website: http://www.libnfc.org).
+Proprietary Notes:
-libnfc version 1.0.0
-
-Index:
-1. Introduction
-2. Hardware
-3. Compilation
-4. Examples
-5. Todo
-6. Contact
-
-------------------------------------------------------------------------
-1. Introduction
-
-Since the RFID market is spoiled by proprietary hard and software
-we want to contribute constructively by distributing a free library
-which can be used in RFID/NFC applications.
-
-------------------------------------------------------------------------
-2. Hardware
-
-To communicate with NFC targets/tags you need a USB device which is
-called a "RFID Reader". The cheapest hardware around that can carries
-a fully NFC complied chip is the ACR122 from the company ACS, Advanced
-Card Systems Limited (website: http://www.acs.com.hk/acr122.php).
-This reader uses the PN532 chipset from NXP Semiconductors. The reader
-costs around the €60 and is available in different webshops all over
-the world. The NFC reader used in the "tikitag" project is exactly the
-same reader as the ACR122 but with a different logo. This reader is
-available for only €35,- (website: http://www.tikitag.com). We would
-recommend to use one of these readers, since we tested both of them.
-
-Other NFC readers, like the SCL3710 from SCM Microsystems (website:
-http://www.scmmicro.com/scl3710/) are not supported yet. They use the
-same chipset, so the instruction set is completely the same. This means
-that with little effort these readers could be added to be part of the
-NFC library. We would be very pleased if someone is willing to add this
-support to libnfc.
-
-------------------------------------------------------------------------
-3. Compilation
-
-If you use linux, please make sure you have libpcsc-lite installed.
-For Ubuntu this means you have to install the following packages:
-$sudo apt-get install pcscd
-$sudo apt-get install libpcsclite-dev
-When these are installed, just run "make" and you are ready to go.
-
-MacOSX users have to edit the "Makefile" file in the main directory.
-Uncomment the following lines:
-#LIB_TYPE=...
-#LIB_FLAGS=...
-#PCSC_HEADERS=...
-#PCSC_LIB=...
-Run "make" and you it should work like a charm.
-
-Windows users can use the binairy files located in the "win32bin"
-directory. Or they can open the VS2005 solution which can be found
-in the "win32" directory. Compilation should work "out of the box".
-
-------------------------------------------------------------------------
-4. Examples
-
-There are 6 example tools coming with this library. They can be used
-as a reference during development of your software. All tools try to
-demonstrate a different feature. Below there is short description of
-the tools and their purpose.
-
-anticol - Anti-collision demonstration tool for ISO14443A tags using
- self constructed REQA/WUPA and SELECT frames.
-
-list - List passive tags tool for ISO14443A tags using the commands
- available in the instruction set of the hardware chip.
-
-simulate - With this example you can turn your reader into a NFC target.
- For testing purposes it simulates a ISO14443A tag with a UID
- that consists of 0xDEADBEAF. The frames are delayed because
- of the USB communication, so not all readers will recognize
- the tag. The "Omnikey 5121" though has no problems with this
- small delay.
-
-relay - This tool allows the user to use 2 readers. One will similate
- a ISO14443A tag, while the 2nd reader will stay a reader.
- The original tag can be placed on the 2nd reader and the
- simulated tag can be placed on top of the original reader.
- All communication is relayed now and showed on the screen.
- NOTE: relaying frames is time-consuming, not all readers
- allow slow responds from the (simulated) tag. Though, one of
- the most used RFID readers, the "Omnikey 5121" has no problem
- and can perfectly be used for demonstrating this features.
-
-mfread - With this tool a complete MIFARE card can be readout and stored
- in a MIFARE dump file (*.mfd).
-
-mfwrite - With this tool a complete MIFARE card can be restored from a
- a MIFARE dump file (*.mfd) back to the tag.
-
-A MIFARE dump file (*.mfd) is a plain 4KB image of a mifare tag. This
-image should contain the data, keys and access bits on their usual position.
-A Dump file is always 4KB, even when a 1KB tag is dumped. From the first
-block, the manufacturer data, can be determined if you are dealing with
-a 1KB or a 4KB tag. This is stored in the ATQA part of block0 (byte 6/7).
-More info can be found in the MIFARE functional specification from NXP.
-(Website: http://www.nxp.com/products/identification/mifare/classic)
-
-------------------------------------------------------------------------
-5. Todo
-
-Support more communication protocols. Sony Felica, ISO14443B and Innovision
-Jewel Topaz tags are supported by the chipset, but they are not used by
-this library. It would be very useful if we could add support for these
-tags in this library.
-
-------------------------------------------------------------------------
-6. Contact
-
-Please visit the website (http://www.libnfc.org) and place your questions
-in the community forum there. We are sure a member of the community will
-help you out.
-
-------------------------------------------------------------------------
-Proprietary notes:
-
-Note: FeliCa is s registered trademark of Sony Corporation. MIFARE is a
+FeliCa is s registered trademark of Sony Corporation. MIFARE is a
trademark of NXP Semiconductors. Jewel Topaz is a trademark of Innovision
Research & Technology. All other trademarks are the property of their
respective owners.
+
diff --git a/anticol.c b/anticol.c
index 876d0a9..e4e4e34 100644
--- a/anticol.c
+++ b/anticol.c
@@ -1,142 +1,150 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
-#include
-#include
-#include
-#include "libnfc.h"
-
-static byte abtRecv[MAX_FRAME_LEN];
-static ui32 uiRecvLen;
-static byte abtUid[10];
-static ui32 uiUidLen = 4;
-static dev_id di;
-
-// ISO14443A Anti-Collision Commands
-byte abtWupa [1] = { 0x52 };
-byte abtSelectAll [2] = { 0x93,0x20 };
-byte abtSelectTag [9] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
-byte abtRats [4] = { 0xe0,0x50,0xbc,0xa5 };
-byte abtHalt [4] = { 0x50,0x00,0x57,0xcd };
-
-bool transmit_7bits(const byte btTx)
-{
- bool bResult;
- printf("R: %02x\n",btTx);
- uiRecvLen = MAX_FRAME_LEN;
- bResult = nfc_reader_transceive_7bits(di,btTx,abtRecv,&uiRecvLen);
- if (bResult)
- {
- printf("T: ");
- print_hex(abtRecv,uiRecvLen);
- }
- return bResult;
-}
-
-bool transmit_bytes(const byte* pbtTx, const ui32 uiTxLen)
-{
- bool bResult;
- printf("R: ");
- print_hex(pbtTx,uiTxLen);
- uiRecvLen = MAX_FRAME_LEN;
- bResult = nfc_reader_transceive_bytes(di,pbtTx,uiTxLen,abtRecv,&uiRecvLen);
- if (bResult)
- {
- printf("T: ");
- print_hex(abtRecv,uiRecvLen);
- }
- return bResult;
-}
-
-int main(int argc, const char* argv[])
-{
- // Try to open the NFC reader
- di = acr122_connect(0);
-
- if (di == INVALID_DEVICE_ID)
- {
- printf("Error connecting NFC reader\n");
- return 1;
- }
- nfc_reader_init(di);
-
- // Let the reader only try once to find a tag
- nfc_configure_list_passive_infinite(di,false);
-
- // Drop the field so the tag will be reset
- nfc_configure_field(di,false);
-
- // Configure the communication channel, we use our own CRC
- nfc_configure_handle_crc(di,false);
- nfc_configure_handle_parity(di,true);
-
- // Enable the field so the more power consuming tags will respond
- nfc_configure_field(di,true);
-
- printf("\nConnected to NFC reader\n\n");
-
- if (!transmit_7bits(*abtWupa))
- {
- printf("Error: No tag available\n");
- return 1;
- }
- // Anti-collision
- transmit_bytes(abtSelectAll,2);
-
- // Save the UID
- memcpy(abtUid,abtRecv,4);
- memcpy(abtSelectTag+2,abtRecv,5);
- append_iso14443a_crc(abtSelectTag,7);
- transmit_bytes(abtSelectTag,9);
-
- if (abtUid[0] == 0x88)
- {
- abtSelectAll[0] = 0x95;
- abtSelectTag[0] = 0x95;
-
- // Anti-collision
- transmit_bytes(abtSelectAll,2);
-
- // Save the UID
- memcpy(abtUid+4,abtRecv,4);
- memcpy(abtSelectTag+2,abtRecv,5);
- append_iso14443a_crc(abtSelectTag,7);
- transmit_bytes(abtSelectTag,9);
- uiUidLen = 7;
- }
-
- // Request ATS, this only applies to tags that support ISO 14443A-4
- if (abtRecv[0] & 0x20)
- {
- transmit_bytes(abtRats,4);
- }
-
- // Done, halt the tag now
- transmit_bytes(abtHalt,4);
-
- printf("\nFound tag with UID: ");
- if (uiUidLen == 4)
- {
- printf("%08x\n",swap_endian32(abtUid));
- } else {
- printf("%014llx\n",swap_endian64(abtUid)&0x00ffffffffffffffull);
- }
- return 0;
-}
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+#include
+#include
+#include
+#include "libnfc.h"
+
+#define SAK_FLAG_ATS_SUPPORTED 0x20
+
+static byte abtRx[MAX_FRAME_LEN];
+static ui32 uiRxBits;
+static ui32 uiRxLen;
+static byte abtUid[10];
+static ui32 uiUidLen = 4;
+static dev_info* pdi;
+
+// ISO14443A Anti-Collision Commands
+byte abtReqa [1] = { 0x26 };
+byte abtSelectAll [2] = { 0x93,0x20 };
+byte abtSelectTag [9] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+byte abtRats [4] = { 0xe0,0x50,0xbc,0xa5 };
+byte abtHalt [4] = { 0x50,0x00,0x57,0xcd };
+
+bool transmit_bits(const byte* pbtTx, const ui32 uiTxBits)
+{
+ // Show transmitted command
+ printf("R: "); print_hex_bits(pbtTx,uiTxBits);
+
+ // Transmit the bit frame command, we don't use the arbitrary parity feature
+ if (!nfc_reader_transceive_bits(pdi,pbtTx,uiTxBits,null,abtRx,&uiRxBits,null)) return false;
+
+ // Show received answer
+ printf("T: "); print_hex_bits(abtRx,uiRxBits);
+
+ // Succesful transfer
+ return true;
+}
+
+
+bool transmit_bytes(const byte* pbtTx, const ui32 uiTxLen)
+{
+ // Show transmitted command
+ printf("R: "); print_hex(pbtTx,uiTxLen);
+
+ // Transmit the command bytes
+ if (!nfc_reader_transceive_bytes(pdi,pbtTx,uiTxLen,abtRx,&uiRxLen)) return false;
+
+ // Show received answer
+ printf("T: "); print_hex(abtRx,uiRxLen);
+
+ // Succesful transfer
+ return true;
+}
+
+int main(int argc, const char* argv[])
+{
+ // Try to open the NFC reader
+ pdi = nfc_connect();
+
+ if (!pdi)
+ {
+ printf("Error connecting NFC reader\n");
+ return 1;
+ }
+ nfc_reader_init(pdi);
+
+ // Drop the field for a while
+ nfc_configure(pdi,DCO_ACTIVATE_FIELD,false);
+
+ // Configure the CRC and Parity settings
+ nfc_configure(pdi,DCO_HANDLE_CRC,false);
+ nfc_configure(pdi,DCO_HANDLE_PARITY,true);
+
+ // Enable field so more power consuming cards can power themselves up
+ nfc_configure(pdi,DCO_ACTIVATE_FIELD,true);
+
+ printf("\nConnected to NFC reader: %s\n\n",pdi->acName);
+
+ // Send the 7 bits request command specified in ISO 14443A (0x26)
+ if (!transmit_bits(abtReqa,7))
+ {
+ printf("Error: No tag available\n");
+ nfc_disconnect(pdi);
+ return 1;
+ }
+
+ // Anti-collision
+ transmit_bytes(abtSelectAll,2);
+
+ // Save the UID
+ memcpy(abtUid,abtRx,4);
+ memcpy(abtSelectTag+2,abtRx,5);
+ append_iso14443a_crc(abtSelectTag,7);
+ transmit_bytes(abtSelectTag,9);
+
+ // Test if we are dealing with a 4 bytes uid
+ if (abtUid[0]!= 0x88)
+ {
+ uiUidLen = 4;
+ } else {
+ // We have to do the anti-collision for cascade level 2
+ abtSelectAll[0] = 0x95;
+ abtSelectTag[0] = 0x95;
+
+ // Anti-collision
+ transmit_bytes(abtSelectAll,2);
+
+ // Save the UID
+ memcpy(abtUid+4,abtRx,4);
+ memcpy(abtSelectTag+2,abtRx,5);
+ append_iso14443a_crc(abtSelectTag,7);
+ transmit_bytes(abtSelectTag,9);
+ uiUidLen = 7;
+ }
+
+ // Request ATS, this only applies to tags that support ISO 14443A-4
+ if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) transmit_bytes(abtRats,4);
+
+ // Done, halt the tag now
+ transmit_bytes(abtHalt,4);
+
+ printf("\nFound tag with UID: ");
+ if (uiUidLen == 4)
+ {
+ printf("%08x\n",swap_endian32(abtUid));
+ } else {
+ printf("%014llx\n",swap_endian64(abtUid)&0x00ffffffffffffffull);
+ }
+
+ nfc_disconnect(pdi);
+ return 0;
+}
diff --git a/bitutils.c b/bitutils.c
index f7f9458..5fda4b1 100644
--- a/bitutils.c
+++ b/bitutils.c
@@ -1,23 +1,23 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
#include
#include "bitutils.h"
@@ -116,7 +116,7 @@ ui32 swap_endian32(const void* pui32)
ui64 swap_endian64(const void* pui64)
{
ui64 ui64N = *((ui64*)pui64);
- return (((ui64N&0xFF)<<56)+((ui64N&0xFF00)<<40)+((ui64N&0xFF0000)<<24)+((ui64N&0xFF000000)<<8)+((ui64N&0xFF00000000)>>8)+((ui64N&0xFF0000000000)>>24)+((ui64N&0xFF000000000000)>>40)+((ui64N&0xFF00000000000000)>>56));
+ return (((ui64N&0xFF)<<56)+((ui64N&0xFF00)<<40)+((ui64N&0xFF0000)<<24)+((ui64N&0xFF000000)<<8)+((ui64N&0xFF00000000ull)>>8)+((ui64N&0xFF0000000000ull)>>24)+((ui64N&0xFF000000000000ull)>>40)+((ui64N&0xFF00000000000000ull)>>56));
}
void append_iso14443a_crc(byte* pbtData, ui32 uiLen)
@@ -135,16 +135,33 @@ void append_iso14443a_crc(byte* pbtData, ui32 uiLen)
*pbtData = (byte) ((wCrc >> 8) & 0xFF);
}
-void print_hex(const byte* pbtData, const ui32 uiLen)
+void print_hex(const byte* pbtData, const ui32 uiBytes)
{
ui32 uiPos;
- for (uiPos=0; uiPos < uiLen; uiPos++)
+
+ for (uiPos=0; uiPos < uiBytes; uiPos++)
{
printf("%02x ",pbtData[uiPos]);
}
printf("\n");
}
+void print_hex_bits(const byte* pbtData, const ui32 uiBits)
+{
+ ui32 uiPos;
+ ui32 uiBytes = uiBits/8;
+
+ for (uiPos=0; uiPos < uiBytes; uiPos++)
+ {
+ printf("%02x ",pbtData[uiPos]);
+ }
+
+ // Print the rest bits, these cannot have no parity bit
+ if (uiBits%8 != 0) printf("%02x",pbtData[uiBytes]);
+
+ printf("\n");
+}
+
void print_hex_par(const byte* pbtData, const ui32 uiBits, const byte* pbtDataPar)
{
ui32 uiPos;
@@ -162,10 +179,7 @@ void print_hex_par(const byte* pbtData, const ui32 uiBits, const byte* pbtDataPa
}
// Print the rest bits, these cannot have no parity bit
- if (uiBits%8 != 0)
- {
- printf("%02x",pbtData[uiBytes]);
- }
+ if (uiBits%8 != 0) printf("%02x",pbtData[uiBytes]);
printf("\n");
}
diff --git a/bitutils.h b/bitutils.h
index e231678..312c968 100644
--- a/bitutils.h
+++ b/bitutils.h
@@ -1,46 +1,28 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
#ifndef _LIBNFC_BITUTILS_H_
#define _LIBNFC_BITUTILS_H_
#include "defines.h"
-#define INNER_XOR8(n) {\
- n ^= (n >> 4); \
- n ^= (n >> 2); \
- n ^= (n >> 1); \
- n &= 0x01; \
-}
-
-#define INNER_XOR32(n) {\
- n ^= (n >> 16); \
- n ^= (n >> 8); \
- INNER_XOR8(n); \
-}
-
-#define INNER_XOR64(n) {\
- n ^= (n >> 32); \
- INNER_XOR32(n); \
-}
-
byte oddparity(const byte bt);
void oddparity_bytes(const byte* pbtData, const ui32 uiLen, byte* pbtPar);
@@ -55,6 +37,7 @@ ui64 swap_endian64(const void* pui64);
void append_iso14443a_crc(byte* pbtData, ui32 uiLen);
void print_hex(const byte* pbtData, const ui32 uiLen);
+void print_hex_bits(const byte* pbtData, const ui32 uiBits);
void print_hex_par(const byte* pbtData, const ui32 uiBits, const byte* pbtDataPar);
#endif // _LIBNFC_BITUTILS_H_
diff --git a/defines.h b/defines.h
index 99edc19..6ec18e2 100644
--- a/defines.h
+++ b/defines.h
@@ -1,26 +1,28 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
#ifndef _LIBNFC_DEFINES_H_
#define _LIBNFC_DEFINES_H_
+// #define _LIBNFC_VERBOSE_
+
typedef unsigned char byte;
typedef unsigned char ui8;
typedef unsigned short ui16;
@@ -33,13 +35,16 @@ typedef int i32;
#define null 0
-typedef void* dev_id; // Device Id
-#define INVALID_DEVICE_ID null
+typedef void* dev_spec; // Device connection specification
+#define INVALID_DEVICE_INFO null
#define MAX_FRAME_LEN 264
+#define DEVICE_NAME_LENGTH 256
-#define min(a,b) (((a) < (b)) ? (a) : (b))
-#define max(a,b) (((a) > (b)) ? (a) : (b))
-
-// #define _LIBNFC_VERBOSE_
+// Useful macros
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define INNER_XOR8(n) {n ^= (n >> 4); n ^= (n >> 2); n ^= (n >> 1); n &= 0x01; }
+#define INNER_XOR32(n) {n ^= (n >> 16); n ^= (n >> 8); INNER_XOR8(n); }
+#define INNER_XOR64(n) {n ^= (n >> 32); INNER_XOR32(n); }
#endif // _LIBNFC_DEFINES_H_
diff --git a/libnfc.c b/libnfc.c
index f832b28..8d87140 100644
--- a/libnfc.c
+++ b/libnfc.c
@@ -1,524 +1,761 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
-#include
-#include
-#include "libnfc.h"
-#include "acr122.h"
-#include "bitutils.h"
-
-#define REG_CIU_TX_MODE 0x6302
-#define REG_CIU_RX_MODE 0x6303
-#define REG_CIU_TX_AUTO 0x6305
-#define REG_CIU_MANUAL_RCV 0x630D
-#define REG_CIU_CONTROL 0x633C
-#define REG_CIU_BIT_FRAMING 0x633D
-
-#define PARAM_NONE 0x00
-#define PARAM_NAD_USED 0x01
-#define PARAM_DID_USED 0x02
-#define PARAM_AUTO_ATR_RES 0x04
-#define PARAM_AUTO_RATS 0x10
-#define PARAM_14443_4_PICC 0x20
-#define PARAM_NO_AMBLE 0x40
-
-// PN532 configuration
-byte pncmd_get_firmware_version [ 2] = { 0xD4,0x02 };
-byte pncmd_get_general_status [ 2] = { 0xD4,0x04 };
-byte pncmd_get_register [ 4] = { 0xD4,0x06 };
-byte pncmd_set_register [ 5] = { 0xD4,0x08 };
-byte pncmd_set_parameters [ 3] = { 0xD4,0x12 };
-
-// RF field configuration
-byte pncmd_rf_configure_field [ 4] = { 0xD4,0x32,0x01 };
-byte pncmd_rf_configure_timing [ 4] = { 0xD4,0x32,0x02 };
-byte pncmd_rf_configure_retry_data [ 4] = { 0xD4,0x32,0x04 };
-byte pncmd_rf_configure_retry_select [ 6] = { 0xD4,0x32,0x05 };
-
-// Reader
-byte pncmd_reader_list_passive [264] = { 0xD4,0x4A };
-byte pncmd_reader_select [ 3] = { 0xD4,0x54 };
-byte pncmd_reader_deselect [ 3] = { 0xD4,0x44 };
-byte pncmd_reader_release [ 3] = { 0xD4,0x52 };
-byte pncmd_reader_set_baud_rate [ 5] = { 0xD4,0x4E };
-byte pncmd_reader_exchange_data [265] = { 0xD4,0x40 };
-byte pncmd_reader_auto_poll [ 5] = { 0xD4,0x60 };
-
-// Target
-byte pncmd_target_get_data [ 2] = { 0xD4,0x86 };
-byte pncmd_target_init [ 39] = { 0xD4,0x8C };
-byte pncmd_target_virtual_card [ 4] = { 0xD4,0x14 };
-byte pncmd_target_receive [ 2] = { 0xD4,0x88 };
-byte pncmd_target_send [264] = { 0xD4,0x90 };
-byte pncmd_target_get_status [ 2] = { 0xD4,0x8A };
-
-// Exchange raw data frames
-byte pncmd_exchange_raw_data [266] = { 0xD4,0x42 };
-
-// Global buffers used for communication with the PN532 chip
-#define MAX_FRAME_LEN 264
-static byte abtRx[MAX_FRAME_LEN];
-static ui32 uiRxLen;
-static ui8 ui8Value;
-static ui32 ui32Len = 1;
-
-bool pn532_transceive(const dev_id di, const byte* pbtTx, const ui32 uiTxLen)
-{
- uiRxLen = MAX_FRAME_LEN;
- return acr122_transceive(di,pbtTx,uiTxLen,abtRx,&uiRxLen);
-}
-
-bool pn532_set_reg(const dev_id di, ui16 ui16Reg, ui8 ui8Value)
-{
- pncmd_set_register[2] = ui16Reg >> 8;
- pncmd_set_register[3] = ui16Reg & 0xff;
- pncmd_set_register[4] = ui8Value;
- return acr122_transceive(di,pncmd_set_register,5,null,null);
-}
-
-byte pn532_get_reg(const dev_id di, ui16 ui16Reg)
-{
- pncmd_get_register[2] = ui16Reg >> 8;
- pncmd_get_register[3] = ui16Reg & 0xff;
- acr122_transceive(di,pncmd_get_register,4,&ui8Value,&ui32Len);
- return ui8Value;
-}
-
-bool pn532_set_parameters(const dev_id di, ui8 ui8Value)
-{
- pncmd_set_parameters[2] = ui8Value;
- return acr122_transceive(di,pncmd_set_parameters,3,null,null);
-}
-
-bool pn532_wrap_frame(const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtFrame, ui32* puiFrameBits)
-{
- byte btFrame;
- byte btData;
- ui32 uiBitPos;
- ui32 uiDataPos = 0;
- ui32 uiBitsLeft = uiTxBits;
-
- // Make sure we should frame at least something
- if (uiBitsLeft == 0) return false;
-
- // Handle a short response (1byte) as a special case
- if (uiBitsLeft < 9)
- {
- *pbtFrame = *pbtTx;
- *puiFrameBits = uiTxBits;
- return true;
- }
-
- // We start by calculating the frame length in bits
- *puiFrameBits = uiTxBits + (uiTxBits/8);
-
- // Parse the data bytes and add the parity bits
- // This is really a sensitive process, mirror the frame bytes and append parity bits
- // buffer = mirror(frame-byte) + parity + mirror(frame-byte) + parity + ...
- // split "buffer" up in segments of 8 bits again and mirror them
- // air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + ..
- while(true)
- {
- // Reset the temporary frame byte;
- btFrame = 0;
-
- for (uiBitPos=0; uiBitPos<8; uiBitPos++)
- {
- // Copy as much data that fits in the frame byte
- btData = mirror(pbtTx[uiDataPos]);
- btFrame |= (btData >> uiBitPos);
- // Save this frame byte
- *pbtFrame = mirror(btFrame);
- // Set the remaining bits of the date in the new frame byte and append the parity bit
- btFrame = (btData << (8-uiBitPos));
- btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7-uiBitPos));
- // Backup the frame bits we have so far
- pbtFrame++;
- *pbtFrame = mirror(btFrame);
- // Increase the data (without parity bit) position
- uiDataPos++;
- // Test if we are done
- if (uiBitsLeft < 9) return true;
- uiBitsLeft -= 8;
- }
- // Every 8 data bytes we lose one frame byte to the parities
- pbtFrame++;
- }
-}
-
-bool pn532_unwrap_frame(const byte* pbtFrame, const ui32 uiFrameBits, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
-{
- byte btFrame;
- byte btData;
- ui8 uiBitPos;
- ui32 uiDataPos = 0;
- byte* pbtFramePos = (byte*) pbtFrame;
- ui32 uiBitsLeft = uiFrameBits;
-
- // Make sure we should frame at least something
- if (uiBitsLeft == 0) return false;
-
- // Handle a short response (1byte) as a special case
- if (uiBitsLeft < 9)
- {
- *pbtRx = *pbtFrame;
- *puiRxBits = uiFrameBits;
- return true;
- }
-
- // Calculate the data length in bits
- *puiRxBits = uiFrameBits - (uiFrameBits/9);
-
- // Parse the frame bytes, remove the parity bits and store them in the parity array
- // This process is the reverse of WrapFrame(), look there for more info
- while(true)
- {
- for (uiBitPos=0; uiBitPos<8; uiBitPos++)
- {
- btFrame = mirror(pbtFramePos[uiDataPos]);
- btData = (btFrame << uiBitPos);
- btFrame = mirror(pbtFramePos[uiDataPos+1]);
- btData |= (btFrame >> (8-uiBitPos));
- pbtRx[uiDataPos] = mirror(btData);
- if(pbtRxPar != null) pbtRxPar[uiDataPos] = ((btFrame >> (7-uiBitPos)) & 0x01);
- // Increase the data (without parity bit) position
- uiDataPos++;
- // Test if we are done
- if (uiBitsLeft < 9) return true;
- uiBitsLeft -= 9;
- }
- // Every 8 data bytes we lose one frame byte to the parities
- pbtFramePos++;
- }
-}
-
-bool nfc_configure_handle_crc(const dev_id di, const bool bEnable)
-{
- if (bEnable)
- {
- // Enable automatic receiving/sending of CRC bytes
- if (!pn532_set_reg(di,REG_CIU_TX_MODE,pn532_get_reg(di,REG_CIU_TX_MODE) | 0x80)) return false;
- if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0x80)) return false;
- } else {
- // Disable automatic receiving/sending of CRC bytes
- if (!pn532_set_reg(di,REG_CIU_TX_MODE,pn532_get_reg(di,REG_CIU_TX_MODE) & 0x7f)) return false;
- if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) & 0x7f)) return false;
- }
- return true;
-}
-
-bool nfc_configure_handle_parity(const dev_id di, const bool bEnable)
-{
- if (bEnable)
- {
- // Handle parity by chip
- if (!pn532_set_reg(di,REG_CIU_MANUAL_RCV,pn532_get_reg(di,REG_CIU_MANUAL_RCV) & 0xef)) return false;
-
- } else {
- // Parse parity as data bit
- if (!pn532_set_reg(di,REG_CIU_MANUAL_RCV,pn532_get_reg(di,REG_CIU_MANUAL_RCV) | 0x10)) return false;
- }
- return true;
-}
-
-bool nfc_configure_field(const dev_id di, const bool bEnable)
-{
- pncmd_rf_configure_field[3] = (bEnable) ? 1 : 0;
- return acr122_transceive(di,pncmd_rf_configure_field,4,null,null);
-}
-
-bool nfc_configure_list_passive_infinite(const dev_id di, const bool bEnable)
-{
- // Retry format: 0x00 means only 1 try, 0xff means infinite
- pncmd_rf_configure_retry_select[3] = (bEnable) ? 0xff : 0x00; // MxRtyATR, default: active = 0xff, passive = 0x02
- pncmd_rf_configure_retry_select[4] = (bEnable) ? 0xff : 0x00; // MxRtyPSL, default: 0x01
- pncmd_rf_configure_retry_select[5] = (bEnable) ? 0xff : 0x00; // MxRtyPassiveActivation, default: 0xff
- return acr122_transceive(di,pncmd_rf_configure_retry_select,6,null,null);
-}
-
-bool nfc_configure_accept_invalid_frames(const dev_id di, const bool bEnable)
-{
- if (bEnable)
- {
- // Handle parity by chip
- if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0x08)) return false;
-
- } else {
- // Parse parity as data bit
- if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0xf7)) return false;
- }
- return true;
-}
-
-bool nfc_configure_accept_multiple_frames(const dev_id di, const bool bEnable)
-{
- if (bEnable)
- {
- // Handle parity by chip
- if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0x04)) return false;
-
- } else {
- // Parse parity as data bit
- if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0xfb)) return false;
- }
- return true;
-}
-
-bool nfc_reader_init(const dev_id di)
-{
- // Try to connect to the NFC reader
- if (di == INVALID_DEVICE_ID) return INVALID_DEVICE_ID;
-
- // Let the PN5XX automatically be activated by the RF level detector
- if (!pn532_set_reg(di,REG_CIU_TX_AUTO,pn532_get_reg(di,REG_CIU_TX_AUTO) | 0x40)) return false;
-
- // Configure the PN532 to be an Initiator or Reader/Writer
- if (!pn532_set_reg(di,REG_CIU_CONTROL,pn532_get_reg(di,REG_CIU_CONTROL) | 0x10)) return false;
-
- return true;
-}
-
-bool nfc_reader_list_passive(const dev_id di, const ModulationType mt, const byte* pbtInitData, const ui32 uiInitDataLen, byte* pbtTag, ui32* puiTagLen)
-{
- pncmd_reader_list_passive[2] = 1; // MaxTg, we only want to select 1 tag at the time
- pncmd_reader_list_passive[3] = mt; // BrTy, the type of modulation used for polling a passive tag
-
- // Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or selecting a specific UID).
- if (pbtInitData) memcpy(pncmd_reader_list_passive+4,pbtInitData,uiInitDataLen);
-
- // Try to find the available tags
- if (!acr122_transceive(di,pncmd_reader_list_passive,4+uiInitDataLen,pbtTag,puiTagLen)) return false;
-
- // Return true only if at least one tag has been found, the PN532 returns 0x00 if none was available
- return (pbtTag[0] != 0x00);
-}
-
-bool nfc_reader_transceive_7bits(const dev_id di, const byte btTx, byte* pbtRx, ui32* puiRxLen)
-{
- // Set transmission bits to 7
- if (!pn532_set_reg(di,REG_CIU_BIT_FRAMING,7)) return false;
-
- pncmd_exchange_raw_data[2] = btTx;
- if (!pn532_transceive(di,pncmd_exchange_raw_data,3)) return false;
-
- if (uiRxLen == 1 || abtRx[0] != 0) return false;
- *puiRxLen = uiRxLen-1;
- memcpy(pbtRx,abtRx+1,*puiRxLen);
-
- // Reset transmission bits count
- if (!pn532_set_reg(di,REG_CIU_BIT_FRAMING,0)) return false;
-
- return true;
-}
-
-bool nfc_reader_transceive_bytes(const dev_id di, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
-{
- memcpy(pncmd_exchange_raw_data+2,pbtTx,uiTxLen);
-
- if (!pn532_transceive(di,pncmd_exchange_raw_data,2+uiTxLen)) return false;
-
- if (uiRxLen == 1 || abtRx[0] != 0) return false;
- *puiRxLen = uiRxLen-1;
- memcpy(pbtRx,abtRx+1,*puiRxLen);
-
- return true;
-}
-
-bool nfc_reader_transceive_bits(const dev_id di, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
-{
- ui32 uiFrameBits = 0;
- ui8 ui8Bits = 0;
-
- // Convert data to a frame
- pn532_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_exchange_raw_data+2,&uiFrameBits);
-
- // Retrieve the resting bits
- ui8Bits = uiFrameBits%8;
-
- // Set the amount of transmission bits in the pn532 chip register
- if (!pn532_set_reg(di,REG_CIU_BIT_FRAMING,ui8Bits)) return false;
-
- // Send the frame to the pn532 chip and get the answer
- // We have to give the amount of bytes + 1 byte if there are leading bits + the two 0xD4,0x42
- if (!pn532_transceive(di,pncmd_exchange_raw_data,(uiFrameBits/8)+((ui8Bits==0)?0:1)+2)) return false;
-
- // Make sure there was no failure reported by the PN532 chip (0 == OK)
- // TODO: is this ACR122 specific?
- if (uiRxLen == 1 || abtRx[0] != 0) return false;
-
- // Get the last bit-count that is stored in the received byte
- ui8Bits = pn532_get_reg(di,REG_CIU_CONTROL) & 0x07;
-
- // Unwrap the response frame
- pn532_unwrap_frame(abtRx+1,((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits,pbtRx,puiRxBits,pbtRxPar);
-
- // Everything went successful
- return true;
-}
-
-bool nfc_reader_mifare_cmd(const dev_id di, const MifareCmd mc, const ui8 ui8Block, MifareParam* pmp)
-{
- ui32 uiParamLen;
- pncmd_reader_exchange_data[2] = 0x01; // Use first target/card
- pncmd_reader_exchange_data[3] = mc; // The MIFARE Classic command
- pncmd_reader_exchange_data[4] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
-
- switch (mc)
- {
- // Read and store command have no parameter
- case MC_READ:
- case MC_STORE:
- uiParamLen = 0;
- break;
-
- // Authenticate command
- case MC_AUTH_A:
- case MC_AUTH_B:
- uiParamLen = sizeof(MifareParamAuth);
- break;
-
- // Data command
- case MC_WRITE:
- uiParamLen = sizeof(MifareParamData);
- break;
-
- // Value command
- case MC_DECREMENT:
- case MC_INCREMENT:
- case MC_TRANSFER:
- uiParamLen = sizeof(MifareParamValue);
- break;
-
- // Please fix your code, you never should reach this statement
- default:
- return false;
- break;
- }
-
- // When available, copy the parameter bytes
- if (uiParamLen) memcpy(pncmd_reader_exchange_data+5,(byte*)pmp,uiParamLen);
-
- // Fire the mifare command
- if (!pn532_transceive(di,pncmd_reader_exchange_data,5+uiParamLen)) return false;
-
- // Make sure there was no failure reported by the PN532 chip (0 == OK)
- // TODO: is this ACR122 specific?
- if (abtRx[0] != 0) return false;
-
- // When we have executed a read command, copy the received bytes into the param
- if (mc == MC_READ) memcpy(pmp->mpd.abtData,abtRx+1,16);
-
- // Command succesfully executed
- return true;
-}
-
-bool nfc_target_init(const dev_id di, byte* pbtRx, ui32* puiRxLen)
-{
- // Clear the target init struct, reset to all zeros
- memset(pncmd_target_init+2,0x00,37);
-
- // Set ATQA (SENS_RES)
- pncmd_target_init[3] = 0x04;
- pncmd_target_init[4] = 0x00;
-
- // Set SAK (SEL_RES)
- pncmd_target_init[8] = 0x20;
-
- // Set UID
- pncmd_target_init[5] = 0x00;
- pncmd_target_init[6] = 0xb0;
- pncmd_target_init[7] = 0x0b;
-
- // Enable CRC & parity, needed for target_init to work properly
- nfc_configure_handle_crc(di,true);
- nfc_configure_handle_parity(di,true);
-
- // Request the initialization as a target
- if (!pn532_transceive(di,pncmd_target_init,39)) return false;
-
- if (uiRxLen == 1 || abtRx[0] != 0) return false;
- *puiRxLen = uiRxLen-1;
- memcpy(pbtRx,abtRx+1,*puiRxLen);
-
- return true;
-}
-
-bool nfc_target_receive_bytes(const dev_id di, byte* pbtRx, ui32* puiRxLen)
-{
- if (!pn532_transceive(di,pncmd_target_receive,2)) return false;
-
- if (uiRxLen == 1 || abtRx[0] != 0) return false;
- *puiRxLen = uiRxLen-1;
- memcpy(pbtRx,abtRx+1,*puiRxLen);
-
- return true;
-}
-
-bool nfc_target_receive_bits(const dev_id di, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
-{
- ui8 ui8Bits;
-
- // Try to gather the received frames from the reader
- if (!pn532_transceive(di,pncmd_target_receive,2)) return false;
-
- // Make sure there was no failure reported by the PN532 chip (0 == OK)
- // TODO: is this ACR122 specific?
- if (uiRxLen == 1 || abtRx[0] != 0) return false;
-
- // Get the last bit-count that is stored in the received byte
- ui8Bits = pn532_get_reg(di,REG_CIU_CONTROL) & 0x07;
-
- // Unwrap the response frame
- pn532_unwrap_frame(abtRx+1,((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits,pbtRx,puiRxBits,pbtRxPar);
-
- return true;
-}
-
-bool nfc_target_send_bytes(const dev_id di, const byte* pbtTx, const ui32 uiTxLen)
-{
- memcpy(pncmd_target_send+2,pbtTx,uiTxLen);
- return acr122_transceive(di,pncmd_target_send,2+uiTxLen,null,null);
-}
-
-bool nfc_target_send_bits(const dev_id di, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar)
-{
- ui32 uiFrameBits = 0;
- ui8 ui8Bits = 0;
-
- // Convert data to a frame
- pn532_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_target_send+2,&uiFrameBits);
-
- // Retrieve the resting bits
- ui8Bits = uiFrameBits%8;
-
- // Set the amount of transmission bits in the pn532 chip register
- if (!pn532_set_reg(di,REG_CIU_BIT_FRAMING,ui8Bits)) return false;
-
- // Try to send the bits to the reader
- if (!pn532_transceive(di,pncmd_target_send,(uiFrameBits/8)+((ui8Bits==0)?0:1)+2)) return false;
-
- // Make sure there was no failure reported by the PN532 chip (0 == OK)
- // TODO: is this ACR122 specific?
- if (uiRxLen == 1 || abtRx[0] != 0) return false;
-
- // Everyting seems ok, return true
- return true;
-}
-
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+#include "libnfc.h"
+#include "bitutils.h"
+#include
+#include
+
+// Registers and symbols masks used to covers parts within a register
+#define REG_CIU_TX_MODE 0x6302
+ #define SYMBOL_TX_CRC_ENABLE 0x80
+#define REG_CIU_RX_MODE 0x6303
+ #define SYMBOL_RX_CRC_ENABLE 0x80
+ #define SYMBOL_RX_NO_ERROR 0x08
+ #define SYMBOL_RX_MULTIPLE 0x04
+#define REG_CIU_TX_AUTO 0x6305
+ #define SYMBOL_FORCE_100_ASK 0x40
+ #define SYMBOL_AUTO_WAKE_UP 0x20
+ #define SYMBOL_INITIAL_RF_ON 0x04
+#define REG_CIU_MANUAL_RCV 0x630D
+ #define SYMBOL_PARITY_DISABLE 0x10
+#define REG_CIU_STATUS2 0x6338
+ #define SYMBOL_MF_CRYPTO1_ON 0x08
+#define REG_CIU_CONTROL 0x633C
+ #define SYMBOL_INITIATOR 0x10
+ #define SYMBOL_RX_LAST_BITS 0x07
+#define REG_CIU_BIT_FRAMING 0x633D
+ #define SYMBOL_TX_LAST_BITS 0x07
+
+#define PARAM_NONE 0x00
+#define PARAM_NAD_USED 0x01
+#define PARAM_DID_USED 0x02
+#define PARAM_AUTO_ATR_RES 0x04
+#define PARAM_AUTO_RATS 0x10
+#define PARAM_14443_4_PICC 0x20
+#define PARAM_NO_AMBLE 0x40
+
+// PN53X configuration
+byte pncmd_get_firmware_version [ 2] = { 0xD4,0x02 };
+byte pncmd_get_general_status [ 2] = { 0xD4,0x04 };
+byte pncmd_get_register [ 4] = { 0xD4,0x06 };
+byte pncmd_set_register [ 5] = { 0xD4,0x08 };
+byte pncmd_set_parameters [ 3] = { 0xD4,0x12 };
+
+// RF field configuration
+byte pncmd_rf_configure_field [ 4] = { 0xD4,0x32,0x01 };
+byte pncmd_rf_configure_timing [ 4] = { 0xD4,0x32,0x02 };
+byte pncmd_rf_configure_retry_data [ 4] = { 0xD4,0x32,0x04 };
+byte pncmd_rf_configure_retry_select [ 6] = { 0xD4,0x32,0x05 };
+
+// Reader
+byte pncmd_reader_list_passive [264] = { 0xD4,0x4A };
+byte pncmd_reader_select [ 3] = { 0xD4,0x54 };
+byte pncmd_reader_deselect [ 3] = { 0xD4,0x44,0x00 };
+byte pncmd_reader_release [ 3] = { 0xD4,0x52,0x00 };
+byte pncmd_reader_set_baud_rate [ 5] = { 0xD4,0x4E };
+byte pncmd_reader_exchange_data [265] = { 0xD4,0x40 };
+byte pncmd_reader_auto_poll [ 5] = { 0xD4,0x60 };
+
+// Target
+byte pncmd_target_get_data [ 2] = { 0xD4,0x86 };
+byte pncmd_target_init [ 39] = { 0xD4,0x8C };
+byte pncmd_target_virtual_card [ 4] = { 0xD4,0x14 };
+byte pncmd_target_receive [ 2] = { 0xD4,0x88 };
+byte pncmd_target_send [264] = { 0xD4,0x90 };
+byte pncmd_target_get_status [ 2] = { 0xD4,0x8A };
+
+// Exchange raw data frames
+byte pncmd_exchange_raw_data [266] = { 0xD4,0x42 };
+
+// Global buffers used for communication with the PN53X chip
+#define MAX_FRAME_LEN 264
+static byte abtRx[MAX_FRAME_LEN];
+static ui32 uiRxLen;
+
+bool pn53x_transceive(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen)
+{
+ // Reset the receiving buffer
+ uiRxLen = MAX_FRAME_LEN;
+
+ // Call the tranceive callback function of the current device
+ if (!pdi->pdc->transceive(pdi->ds,pbtTx,uiTxLen,abtRx,&uiRxLen)) return false;
+
+ // Make sure there was no failure reported by the PN53X chip (0x00 == OK)
+ if (abtRx[0] != 0) return false;
+
+ // Succesful transmission
+ return true;
+}
+
+byte pn53x_get_reg(const dev_info* pdi, ui16 ui16Reg)
+{
+ ui8 ui8Value;
+ ui32 uiValueLen = 1;
+ pncmd_get_register[2] = ui16Reg >> 8;
+ pncmd_get_register[3] = ui16Reg & 0xff;
+ pdi->pdc->transceive(pdi->ds,pncmd_get_register,4,&ui8Value,&uiValueLen);
+ return ui8Value;
+}
+
+bool pn53x_set_reg(const dev_info* pdi, ui16 ui16Reg, ui8 ui8SybmolMask, ui8 ui8Value)
+{
+ pncmd_set_register[2] = ui16Reg >> 8;
+ pncmd_set_register[3] = ui16Reg & 0xff;
+ pncmd_set_register[4] = ui8Value | (pn53x_get_reg(pdi,ui16Reg) & (~ui8SybmolMask));
+ return pdi->pdc->transceive(pdi->ds,pncmd_set_register,5,null,null);
+}
+
+bool pn53x_set_parameters(const dev_info* pdi, ui8 ui8Value)
+{
+ pncmd_set_parameters[2] = ui8Value;
+ return pdi->pdc->transceive(pdi->ds,pncmd_set_parameters,3,null,null);
+}
+
+bool pn53x_set_tx_bits(const dev_info* pdi, ui8 ui8Bits)
+{
+ // Test if we need to update the transmission bits register setting
+ if (pdi->ui8TxBits != ui8Bits)
+ {
+ // Set the amount of transmission bits in the PN53X chip register
+ if (!pn53x_set_reg(pdi,REG_CIU_BIT_FRAMING,SYMBOL_TX_LAST_BITS,ui8Bits)) return false;
+
+ // Store the new setting
+ ((dev_info*)pdi)->ui8TxBits = ui8Bits;
+ }
+ return true;
+}
+
+bool pn53x_wrap_frame(const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtFrame, ui32* puiFrameBits)
+{
+ byte btFrame;
+ byte btData;
+ ui32 uiBitPos;
+ ui32 uiDataPos = 0;
+ ui32 uiBitsLeft = uiTxBits;
+
+ // Make sure we should frame at least something
+ if (uiBitsLeft == 0) return false;
+
+ // Handle a short response (1byte) as a special case
+ if (uiBitsLeft < 9)
+ {
+ *pbtFrame = *pbtTx;
+ *puiFrameBits = uiTxBits;
+ return true;
+ }
+
+ // We start by calculating the frame length in bits
+ *puiFrameBits = uiTxBits + (uiTxBits/8);
+
+ // Parse the data bytes and add the parity bits
+ // This is really a sensitive process, mirror the frame bytes and append parity bits
+ // buffer = mirror(frame-byte) + parity + mirror(frame-byte) + parity + ...
+ // split "buffer" up in segments of 8 bits again and mirror them
+ // air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + ..
+ while(true)
+ {
+ // Reset the temporary frame byte;
+ btFrame = 0;
+
+ for (uiBitPos=0; uiBitPos<8; uiBitPos++)
+ {
+ // Copy as much data that fits in the frame byte
+ btData = mirror(pbtTx[uiDataPos]);
+ btFrame |= (btData >> uiBitPos);
+ // Save this frame byte
+ *pbtFrame = mirror(btFrame);
+ // Set the remaining bits of the date in the new frame byte and append the parity bit
+ btFrame = (btData << (8-uiBitPos));
+ btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7-uiBitPos));
+ // Backup the frame bits we have so far
+ pbtFrame++;
+ *pbtFrame = mirror(btFrame);
+ // Increase the data (without parity bit) position
+ uiDataPos++;
+ // Test if we are done
+ if (uiBitsLeft < 9) return true;
+ uiBitsLeft -= 8;
+ }
+ // Every 8 data bytes we lose one frame byte to the parities
+ pbtFrame++;
+ }
+}
+
+bool pn53x_unwrap_frame(const byte* pbtFrame, const ui32 uiFrameBits, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
+{
+ byte btFrame;
+ byte btData;
+ ui8 uiBitPos;
+ ui32 uiDataPos = 0;
+ byte* pbtFramePos = (byte*) pbtFrame;
+ ui32 uiBitsLeft = uiFrameBits;
+
+ // Make sure we should frame at least something
+ if (uiBitsLeft == 0) return false;
+
+ // Handle a short response (1byte) as a special case
+ if (uiBitsLeft < 9)
+ {
+ *pbtRx = *pbtFrame;
+ *puiRxBits = uiFrameBits;
+ return true;
+ }
+
+ // Calculate the data length in bits
+ *puiRxBits = uiFrameBits - (uiFrameBits/9);
+
+ // Parse the frame bytes, remove the parity bits and store them in the parity array
+ // This process is the reverse of WrapFrame(), look there for more info
+ while(true)
+ {
+ for (uiBitPos=0; uiBitPos<8; uiBitPos++)
+ {
+ btFrame = mirror(pbtFramePos[uiDataPos]);
+ btData = (btFrame << uiBitPos);
+ btFrame = mirror(pbtFramePos[uiDataPos+1]);
+ btData |= (btFrame >> (8-uiBitPos));
+ pbtRx[uiDataPos] = mirror(btData);
+ if(pbtRxPar != null) pbtRxPar[uiDataPos] = ((btFrame >> (7-uiBitPos)) & 0x01);
+ // Increase the data (without parity bit) position
+ uiDataPos++;
+ // Test if we are done
+ if (uiBitsLeft < 9) return true;
+ uiBitsLeft -= 9;
+ }
+ // Every 8 data bytes we lose one frame byte to the parities
+ pbtFramePos++;
+ }
+}
+
+dev_info* nfc_connect()
+{
+ dev_info* pdi;
+ ui32 uiDev;
+ byte abtFw[4];
+ ui32 uiFwLen = sizeof(abtFw);
+
+ // Search through the device list for an available device
+ for (uiDev=0; uiDevpdc = &(dev_callbacks_list[uiDev]);
+ pdi->pdc->transceive(pdi->ds,pncmd_get_register,4,null,null);
+
+ // Try to retrieve PN53x chip revision
+ if (!pdi->pdc->transceive(pdi->ds,pncmd_get_firmware_version,2,abtFw,&uiFwLen))
+ {
+ // Failed to get firmware revision??, whatever...let's disconnect and clean up and return err
+ pdi->pdc->disconnect(pdi);
+ return INVALID_DEVICE_INFO;
+ }
+
+ // Add the firmware revision to the device name, PN531 gives 2 bytes info, but PN532 gives 4
+ switch(pdi->ct)
+ {
+ case CT_PN531: sprintf(pdi->acName,"%s - PN531 v%d.%d",pdi->acName,abtFw[0],abtFw[1]); break;
+ case CT_PN532: sprintf(pdi->acName,"%s - PN532 v%d.%d (0x%02x)",pdi->acName,abtFw[1],abtFw[2],abtFw[3]); break;
+ case CT_PN533: sprintf(pdi->acName,"%s - PN533 v%d.%d (0x%02x)",pdi->acName,abtFw[1],abtFw[2],abtFw[3]); break;
+ }
+
+ // Reset the ending transmission bits register, it is unknown what the last tranmission used there
+ if (!pn53x_set_reg(pdi,REG_CIU_BIT_FRAMING,SYMBOL_TX_LAST_BITS,0x00)) return INVALID_DEVICE_INFO;
+
+ // Make sure we reset the CRC and parity to chip handling.
+ if (!nfc_configure(pdi,DCO_HANDLE_CRC,true)) return INVALID_DEVICE_INFO;
+ if (!nfc_configure(pdi,DCO_HANDLE_PARITY,true)) return INVALID_DEVICE_INFO;
+
+ // Deactivate the CRYPTO1 chiper, it may could cause problems when still active
+ if (!nfc_configure(pdi,DCO_ACTIVATE_CRYPTO1,false)) return INVALID_DEVICE_INFO;
+
+ return pdi;
+ }
+ }
+
+ // To bad, no reader is ready to be claimed
+ return INVALID_DEVICE_INFO;
+}
+
+void nfc_disconnect(dev_info* pdi)
+{
+ // Disconnect, clean up and release the device
+ pdi->pdc->disconnect(pdi);
+}
+
+bool nfc_configure(dev_info* pdi, const dev_config_option dco, const bool bEnable)
+{
+ byte btValue;
+
+ // Make sure we are dealing with a active device
+ if (!pdi->bActive) return false;
+
+ switch(dco)
+ {
+ case DCO_HANDLE_CRC:
+ // Enable or disable automatic receiving/sending of CRC bytes
+ // TX and RX are both represented by the symbol 0x80
+ btValue = (bEnable) ? 0x80 : 0x00;
+ if (!pn53x_set_reg(pdi,REG_CIU_TX_MODE,SYMBOL_TX_CRC_ENABLE,btValue)) return false;
+ if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_CRC_ENABLE,btValue)) return false;
+ pdi->bCrc = bEnable;
+ break;
+
+ case DCO_HANDLE_PARITY:
+ // Handle parity bit by PN53X chip or parse it as data bit
+ btValue = (bEnable) ? 0x00 : SYMBOL_PARITY_DISABLE;
+ if (!pn53x_set_reg(pdi,REG_CIU_MANUAL_RCV,SYMBOL_PARITY_DISABLE,btValue)) return false;
+ pdi->bPar = bEnable;
+ break;
+
+ case DCO_ACTIVATE_FIELD:
+ pncmd_rf_configure_field[3] = (bEnable) ? 1 : 0;
+ if (!pdi->pdc->transceive(pdi->ds,pncmd_rf_configure_field,4,null,null)) return false;
+ break;
+
+ case DCO_ACTIVATE_CRYPTO1:
+ btValue = (bEnable) ? SYMBOL_MF_CRYPTO1_ON : 0x00;
+ if (!pn53x_set_reg(pdi,REG_CIU_STATUS2,SYMBOL_MF_CRYPTO1_ON,btValue)) return false;
+ break;
+
+ case DCO_INFINITE_SELECT:
+ // Retry format: 0x00 means only 1 try, 0xff means infinite
+ pncmd_rf_configure_retry_select[3] = (bEnable) ? 0xff : 0x00; // MxRtyATR, default: active = 0xff, passive = 0x02
+ pncmd_rf_configure_retry_select[4] = (bEnable) ? 0xff : 0x00; // MxRtyPSL, default: 0x01
+ pncmd_rf_configure_retry_select[5] = (bEnable) ? 0xff : 0x00; // MxRtyPassiveActivation, default: 0xff
+ if(!pdi->pdc->transceive(pdi->ds,pncmd_rf_configure_retry_select,6,null,null)) return false;
+ break;
+
+ case DCO_ACCEPT_INVALID_FRAMES:
+ btValue = (bEnable) ? SYMBOL_RX_NO_ERROR : 0x00;
+ if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_NO_ERROR,btValue)) return false;
+ break;
+
+ case DCO_ACCEPT_MULTIPLE_FRAMES:
+ btValue = (bEnable) ? SYMBOL_RX_MULTIPLE : 0x00;
+ if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_MULTIPLE,btValue)) return false;
+ return true;
+
+ break;
+ }
+
+ // When we reach this, the configuration is completed and succesful
+ return true;
+}
+
+bool nfc_reader_init(const dev_info* pdi)
+{
+ // Make sure we are dealing with a active device
+ if (!pdi->bActive) return false;
+
+ // Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards)
+ if (!pn53x_set_reg(pdi,REG_CIU_TX_AUTO,SYMBOL_FORCE_100_ASK,0x40)) return false;
+
+ // Configure the PN53X to be an Initiator or Reader/Writer
+ if (!pn53x_set_reg(pdi,REG_CIU_CONTROL,SYMBOL_INITIATOR,0x10)) return false;
+
+ return true;
+}
+
+bool nfc_reader_select(const dev_info* pdi, const init_modulation im, const byte* pbtInitData, const ui32 uiInitDataLen, tag_info* pti)
+{
+ // Make sure we are dealing with a active device
+ if (!pdi->bActive) return false;
+
+ pncmd_reader_list_passive[2] = 1; // MaxTg, we only want to select 1 tag at the time
+ pncmd_reader_list_passive[3] = im; // BrTy, the type of init modulation used for polling a passive tag
+
+ // Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID).
+ if (pbtInitData) memcpy(pncmd_reader_list_passive+4,pbtInitData,uiInitDataLen);
+
+ // Try to find a tag, call the tranceive callback function of the current device
+ uiRxLen = MAX_FRAME_LEN;
+ if (!pdi->pdc->transceive(pdi->ds,pncmd_reader_list_passive,4+uiInitDataLen,abtRx,&uiRxLen)) return false;
+
+ // Make sure one tag has been found, the PN53X returns 0x00 if none was available
+ if (abtRx[0] != 1) return false;
+
+ // Is a tag info struct available
+ if (pti)
+ {
+ // Fill the tag info struct with the values corresponding to this init modulation
+ switch(im)
+ {
+ case IM_ISO14443A_106:
+ // Somehow they switched the lower and upper ATQA bytes around for the PN531 chipset
+ if (pdi->ct == CT_PN531)
+ {
+ pti->tia.abtAtqa[0] = abtRx[3];
+ pti->tia.abtAtqa[1] = abtRx[2];
+ } else {
+ memcpy(pti->tia.abtAtqa,abtRx+2,2);
+ }
+ pti->tia.btSak = abtRx[4];
+ // Copy the NFCID1
+ pti->tia.uiUidLen = abtRx[5];
+ memcpy(pti->tia.abtUid,abtRx+6,pti->tia.uiUidLen);
+ // Did we received an optional ATS (Smardcard ATR)
+ if (uiRxLen > pti->tia.uiUidLen+6)
+ {
+ pti->tia.uiAtsLen = abtRx[pti->tia.uiUidLen+6];
+ memcpy(pti->tia.abtAts,abtRx+pti->tia.uiUidLen+6,pti->tia.uiAtsLen);
+ } else {
+ pti->tia.uiAtsLen = 0;
+ }
+ break;
+
+ case IM_FELICA_212:
+ case IM_FELICA_424:
+ // Store the mandatory info
+ pti->tif.uiLen = abtRx[2];
+ pti->tif.btResCode = abtRx[3];
+ // Copy the NFCID2t
+ memcpy(pti->tif.abtId,abtRx+4,8);
+ // Copy the felica padding
+ memcpy(pti->tif.abtPad,abtRx+12,8);
+ // Test if the System code (SYST_CODE) is available
+ if (uiRxLen > 20)
+ {
+ memcpy(pti->tif.abtSysCode,abtRx+20,2);
+ }
+ break;
+
+ case IM_ISO14443B_106:
+ // Store the mandatory info
+ memcpy(pti->tib.abtAtqb,abtRx+2,12);
+ // Ignore the 0x1D byte, and just store the 4 byte id
+ memcpy(pti->tib.abtId,abtRx+15,4);
+ pti->tib.btParam1 = abtRx[19];
+ pti->tib.btParam2 = abtRx[20];
+ pti->tib.btParam3 = abtRx[21];
+ pti->tib.btParam4 = abtRx[22];
+ // Test if the Higher layer (INF) is available
+ if (uiRxLen > 22)
+ {
+ pti->tib.uiInfLen = abtRx[23];
+ memcpy(pti->tib.abtInf,abtRx+24,pti->tib.uiInfLen);
+ } else {
+ pti->tib.uiInfLen = 0;
+ }
+ break;
+
+ case IM_JEWEL_106:
+ // Store the mandatory info
+ memcpy(pti->tij.btSensRes,abtRx+2,2);
+ memcpy(pti->tij.btId,abtRx+4,4);
+ break;
+
+ default:
+ // Should not be possible, so whatever...
+ break;
+ }
+ }
+ return true;
+}
+
+bool nfc_reader_deselect(const dev_info* pdi)
+{
+ return (pdi->pdc->transceive(pdi->ds,pncmd_reader_deselect,3,null,null));
+}
+
+bool nfc_reader_transceive_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
+{
+ ui32 uiFrameBits = 0;
+ ui32 uiFrameBytes = 0;
+ ui8 ui8Bits = 0;
+
+ // Check if we should prepare the parity bits ourself
+ if (!pdi->bPar)
+ {
+ // Convert data with parity to a frame
+ pn53x_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_exchange_raw_data+2,&uiFrameBits);
+ } else {
+ uiFrameBits = uiTxBits;
+ }
+
+ // Retrieve the leading bits
+ ui8Bits = uiFrameBits%8;
+
+ // Get the amount of frame bytes + optional (1 byte if there are leading bits)
+ uiFrameBytes = (uiFrameBits/8)+((ui8Bits==0)?0:1);
+
+ // When the parity is handled before us, we just copy the data
+ if (pdi->bPar) memcpy(pncmd_exchange_raw_data+2,pbtTx,uiFrameBytes);
+
+ // Set the amount of transmission bits in the PN53X chip register
+ if (!pn53x_set_tx_bits(pdi,ui8Bits)) return false;
+
+ // Send the frame to the PN53X chip and get the answer
+ // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42)
+ if (!pn53x_transceive(pdi,pncmd_exchange_raw_data,uiFrameBytes+2)) return false;
+
+ // Get the last bit-count that is stored in the received byte
+ ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
+
+ // Recover the real frame length in bits
+ uiFrameBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
+
+ // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive()
+ // Check if we should recover the parity bits ourself
+ if (!pdi->bPar)
+ {
+ // Unwrap the response frame
+ pn53x_unwrap_frame(abtRx+1,uiFrameBits,pbtRx,puiRxBits,pbtRxPar);
+ } else {
+ // Save the received bits
+ *puiRxBits = uiFrameBits;
+ // Copy the received bytes
+ memcpy(pbtRx,abtRx+1,uiRxLen-1);
+ }
+
+ // Everything went successful
+ return true;
+}
+
+bool nfc_reader_transceive_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
+{
+ // We can not just send bytes without parity if while the PN53X expects we handled them
+ if (!pdi->bPar) return false;
+
+ // Copy the data into the command frame
+ memcpy(pncmd_exchange_raw_data+2,pbtTx,uiTxLen);
+
+ // To transfer command frames bytes we can not have any leading bits, reset this to zero
+ if (!pn53x_set_tx_bits(pdi,0)) return false;
+
+ // Send the frame to the PN53X chip and get the answer
+ // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42)
+ if (!pn53x_transceive(pdi,pncmd_exchange_raw_data,uiTxLen+2)) return false;
+
+ // Save the received byte count
+ *puiRxLen = uiRxLen-1;
+
+ // Copy the received bytes
+ memcpy(pbtRx,abtRx+1,*puiRxLen);
+
+ // Everything went successful
+ return true;
+}
+
+bool nfc_reader_mifare_cmd(const dev_info* pdi, const mifare_cmd mc, const ui8 ui8Block, mifare_param* pmp)
+{
+ ui32 uiParamLen;
+
+ // Make sure we are dealing with a active device
+ if (!pdi->bActive) return false;
+
+ pncmd_reader_exchange_data[2] = 0x01; // Use first target/card
+ pncmd_reader_exchange_data[3] = mc; // The MIFARE Classic command
+ pncmd_reader_exchange_data[4] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
+
+ switch (mc)
+ {
+ // Read and store command have no parameter
+ case MC_READ:
+ case MC_STORE:
+ uiParamLen = 0;
+ break;
+
+ // Authenticate command
+ case MC_AUTH_A:
+ case MC_AUTH_B:
+ uiParamLen = sizeof(mifare_param_auth);
+ break;
+
+ // Data command
+ case MC_WRITE:
+ uiParamLen = sizeof(mifare_param_data);
+ break;
+
+ // Value command
+ case MC_DECREMENT:
+ case MC_INCREMENT:
+ case MC_TRANSFER:
+ uiParamLen = sizeof(mifare_param_value);
+ break;
+
+ // Please fix your code, you never should reach this statement
+ default:
+ return false;
+ break;
+ }
+
+ // When available, copy the parameter bytes
+ if (uiParamLen) memcpy(pncmd_reader_exchange_data+5,(byte*)pmp,uiParamLen);
+
+ // Fire the mifare command
+ if (!pn53x_transceive(pdi,pncmd_reader_exchange_data,5+uiParamLen)) return false;
+
+ // When we have executed a read command, copy the received bytes into the param
+ if (mc == MC_READ) memcpy(pmp->mpd.abtData,abtRx+1,16);
+
+ // Command succesfully executed
+ return true;
+}
+
+bool nfc_target_init(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits)
+{
+ ui8 ui8Bits;
+
+ // Save the current configuration settings
+ bool bCrc = pdi->bCrc;
+ bool bPar = pdi->bPar;
+
+ // Clear the target init struct, reset to all zeros
+ memset(pncmd_target_init+2,0x00,37);
+
+ // Set ATQA (SENS_RES)
+ pncmd_target_init[3] = 0x04;
+ pncmd_target_init[4] = 0x00;
+
+ // Set SAK (SEL_RES)
+ pncmd_target_init[8] = 0x20;
+
+ // Set UID
+ pncmd_target_init[5] = 0x00;
+ pncmd_target_init[6] = 0xb0;
+ pncmd_target_init[7] = 0x0b;
+
+ // Make sure the CRC & parity are handled by the device, this is needed for target_init to work properly
+ if (!bCrc) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,true);
+ if (!bPar) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,true);
+
+ // Let the PN53X be activated by the RF level detector from power down mode
+ if (!pn53x_set_reg(pdi,REG_CIU_TX_AUTO, SYMBOL_INITIAL_RF_ON,0x04)) return false;
+
+ // Request the initialization as a target, we can not use pn53x_transceive() because
+ // abtRx[0] contains the emulation mode (baudrate, 14443-4?, DEP and framing type)
+ uiRxLen = MAX_FRAME_LEN;
+ if (!pdi->pdc->transceive(pdi->ds,pncmd_target_init,39,abtRx,&uiRxLen)) return false;
+
+ // Get the last bit-count that is stored in the received byte
+ ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
+
+ // We are sure the parity is handled by the PN53X chip, so we handle it this way
+ *puiRxBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
+ // Copy the received bytes
+ memcpy(pbtRx,abtRx+1,uiRxLen-1);
+
+ // Restore the CRC & parity setting to the original value (if needed)
+ if (!bCrc) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,false);
+ if (!bPar) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,false);
+
+ return true;
+}
+
+bool nfc_target_receive_bits(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
+{
+ ui32 uiFrameBits;
+ ui8 ui8Bits;
+
+ // Try to gather a received frame from the reader
+ if (!pn53x_transceive(pdi,pncmd_target_receive,2)) return false;
+
+ // Get the last bit-count that is stored in the received byte
+ ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
+
+ // Recover the real frame length in bits
+ uiFrameBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
+
+ // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive()
+ // Check if we should recover the parity bits ourself
+ if (!pdi->bPar)
+ {
+ // Unwrap the response frame
+ pn53x_unwrap_frame(abtRx+1,uiFrameBits,pbtRx,puiRxBits,pbtRxPar);
+ } else {
+ // Save the received bits
+ *puiRxBits = uiFrameBits;
+ // Copy the received bytes
+ memcpy(pbtRx,abtRx+1,uiRxLen-1);
+ }
+ // Everyting seems ok, return true
+ return true;
+}
+
+bool nfc_target_receive_bytes(const dev_info* pdi, byte* pbtRx, ui32* puiRxLen)
+{
+ // Try to gather a received frame from the reader
+ if (!pn53x_transceive(pdi,pncmd_target_receive,2)) return false;
+
+ // Save the received byte count
+ *puiRxLen = uiRxLen-1;
+
+ // Copy the received bytes
+ memcpy(pbtRx,abtRx+1,*puiRxLen);
+
+ // Everyting seems ok, return true
+ return true;
+}
+
+bool nfc_target_send_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar)
+{
+ ui32 uiFrameBits = 0;
+ ui32 uiFrameBytes = 0;
+ ui8 ui8Bits = 0;
+
+ // Check if we should prepare the parity bits ourself
+ if (!pdi->bPar)
+ {
+ // Convert data with parity to a frame
+ pn53x_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_target_send+2,&uiFrameBits);
+ } else {
+ uiFrameBits = uiTxBits;
+ }
+
+ // Retrieve the leading bits
+ ui8Bits = uiFrameBits%8;
+
+ // Get the amount of frame bytes + optional (1 byte if there are leading bits)
+ uiFrameBytes = (uiFrameBits/8)+((ui8Bits==0)?0:1);
+
+ // When the parity is handled before us, we just copy the data
+ if (pdi->bPar) memcpy(pncmd_target_send+2,pbtTx,uiFrameBytes);
+
+ // Set the amount of transmission bits in the PN53X chip register
+ if (!pn53x_set_tx_bits(pdi,ui8Bits)) return false;
+
+ // Try to send the bits to the reader
+ if (!pn53x_transceive(pdi,pncmd_target_send,uiFrameBytes+2)) return false;
+
+ // Everyting seems ok, return true
+ return true;
+}
+
+
+bool nfc_target_send_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen)
+{
+ // We can not just send bytes without parity if while the PN53X expects we handled them
+ if (!pdi->bPar) return false;
+
+ // Copy the data into the command frame
+ memcpy(pncmd_target_send+2,pbtTx,uiTxLen);
+
+ // Try to send the bits to the reader
+ if (!pn53x_transceive(pdi,pncmd_target_send,uiTxLen+2)) return false;
+
+ // Everyting seems ok, return true
+ return true;
+}
diff --git a/libnfc.h b/libnfc.h
index ba8802a..f122137 100644
--- a/libnfc.h
+++ b/libnfc.h
@@ -1,50 +1,47 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
#ifndef _LIBNFC_H_
#define _LIBNFC_H_
#include "defines.h"
#include "types.h"
#include "bitutils.h"
-#include "acr122.h"
+#include "devices.h"
-bool nfc_configure_handle_crc(const dev_id di, const bool bEnable);
-bool nfc_configure_handle_parity(const dev_id di, const bool bEnable);
-bool nfc_configure_field(const dev_id di, const bool bEnable);
-bool nfc_configure_list_passive_infinite(const dev_id di, const bool bEnable);
-bool nfc_configure_accept_invalid_frames(const dev_id di, const bool bEnable);
-bool nfc_configure_accept_multiple_frames(const dev_id di, const bool bEnable);
+dev_info* nfc_connect();
+void nfc_disconnect(dev_info* pdi);
+bool nfc_configure(dev_info* pdi, const dev_config_option dco, const bool bEnable);
-bool nfc_reader_init(const dev_id di);
-bool nfc_reader_list_passive(const dev_id di, const ModulationType mt, const byte* pbtInitData, const ui32 uiInitDataLen, byte* pbtTag, ui32* puiTagLen);
-bool nfc_reader_transceive_7bits(const dev_id di, const byte btTx, byte* pbtRx, ui32* puiRxLen);
-bool nfc_reader_transceive_bytes(const dev_id di, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
-bool nfc_reader_transceive_bits(const dev_id di, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar);
-bool nfc_reader_mifare_cmd(const dev_id di, const MifareCmd mc, const ui8 ui8Block, MifareParam* pmp);
+bool nfc_reader_init(const dev_info* pdi);
+bool nfc_reader_select(const dev_info* pdi, const init_modulation im, const byte* pbtInitData, const ui32 uiInitDataLen, tag_info* pti);
+bool nfc_reader_deselect(const dev_info* pdi);
+bool nfc_reader_transceive_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar);
+bool nfc_reader_transceive_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
+bool nfc_reader_mifare_cmd(const dev_info* pdi, const mifare_cmd mc, const ui8 ui8Block, mifare_param* pmp);
-bool nfc_target_init(const dev_id di, byte* pbtRx, ui32* puiRxLen);
-bool nfc_target_receive_bytes(const dev_id di, byte* pbtRx, ui32* puiRxLen);
-bool nfc_target_receive_bits(const dev_id di, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar);
-bool nfc_target_send_bytes(const dev_id di, const byte* pbtTx, const ui32 uiTxLen);
-bool nfc_target_send_bits(const dev_id di, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar);
+bool nfc_target_init(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits);
+bool nfc_target_receive_bits(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar);
+bool nfc_target_receive_bytes(const dev_info* pdi, byte* pbtRx, ui32* puiRxLen);
+bool nfc_target_send_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar);
+bool nfc_target_send_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen);
#endif // _LIBNFC_H_
diff --git a/list.c b/list.c
index 7cb111b..be02e9b 100644
--- a/list.c
+++ b/list.c
@@ -23,61 +23,74 @@ along with this program. If not, see .
#include
#include "libnfc.h"
-static byte abtRecv[MAX_FRAME_LEN];
-static ui32 uiRecvLen;
-static dev_id di;
+static dev_info* pdi;
+static byte abtFelica[5] = { 0x00, 0xff, 0xff, 0x00, 0x00 };
int main(int argc, const char* argv[])
{
+ tag_info ti;
+
// Try to open the NFC reader
- di = acr122_connect(0);
+ pdi = nfc_connect();
- if (di == INVALID_DEVICE_ID)
+ if (pdi == INVALID_DEVICE_INFO)
{
printf("Error connecting NFC reader\n");
return 1;
}
- nfc_reader_init(di);
+ nfc_reader_init(pdi);
+
+ // Drop the field for a while
+ nfc_configure(pdi,DCO_ACTIVATE_FIELD,false);
// Let the reader only try once to find a tag
- nfc_configure_list_passive_infinite(di,false);
+ nfc_configure(pdi,DCO_INFINITE_SELECT,false);
- // Drop the field so the tag will be reset
- nfc_configure_field(di,false);
+ // Configure the CRC and Parity settings
+ nfc_configure(pdi,DCO_HANDLE_CRC,true);
+ nfc_configure(pdi,DCO_HANDLE_PARITY,true);
- // Configure the communication channel
- nfc_configure_handle_crc(di,true);
- nfc_configure_handle_parity(di,true);
+ // Enable field so more power consuming cards can power themselves up
+ nfc_configure(pdi,DCO_ACTIVATE_FIELD,true);
- printf("\nConnected to NFC reader\n\n");
-
- uiRecvLen = MAX_FRAME_LEN;
- if (nfc_reader_list_passive(di,MT_ISO14443A_106,null,null,abtRecv,&uiRecvLen))
+ printf("\nConnected to NFC reader: %s\n\n",pdi->acName);
+
+ // Poll for a ISO14443A (MIFARE) tag
+ if (nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
{
- // ISO14443A tag info = ( tag_count[1], tag_nr[1], ATQA[2], SAK[1], uid_len[1], UID[uid_len], ats_len[1], ATS[ats_len-1] )
- // ATS is optional
printf("The following (NFC) ISO14443A tag was found:\n\n");
- printf("%17s","ATQA (SENS_RES): ");
- print_hex(abtRecv+2,2);
- printf("%17s","UID (NFCID1): ");
- print_hex(abtRecv+6,abtRecv[5]);
- printf("%17s","SAK (SEL_RES): ");
- print_hex(abtRecv+4,1);
- if (uiRecvLen > 6+(ui32)abtRecv[5])
+ printf(" ATQA (SENS_RES): "); print_hex(ti.tia.abtAtqa,2);
+ printf(" UID (NFCID%c): ",(ti.tia.abtUid[0]==0x08?'3':'1')); print_hex(ti.tia.abtUid,ti.tia.uiUidLen);
+ printf(" SAK (SEL_RES): "); print_hex(&ti.tia.btSak,1);
+ if (ti.tia.uiAtsLen)
{
- printf("%17s","ATS (ATR): ");
- print_hex(abtRecv+6+abtRecv[5]+1,abtRecv[6+abtRecv[5]]-1);
+ printf(" ATS (ATR): ");
+ print_hex(ti.tia.abtAts,ti.tia.uiAtsLen);
}
- } else {
- printf("Error: no tag was found\n");
}
- // Todo: listing the folllowing tags types
- //
- // MT_FELICA_212
- // MT_FELICA_424
- // MT_ISO14443B_106
- // MT_TOPAZ_106
+ // Poll for a Felica tag
+ if (nfc_reader_select(pdi,IM_FELICA_212,abtFelica,5,&ti) || nfc_reader_select(pdi,IM_FELICA_424,abtFelica,5,&ti))
+ {
+ printf("The following (NFC) Felica tag was found:\n\n");
+ printf("%18s","ID (NFCID2): "); print_hex(ti.tif.abtId,8);
+ printf("%18s","Parameter (PAD): "); print_hex(ti.tif.abtPad,8);
+ }
- return 0;
+ // Poll for a ISO14443B tag
+ if (nfc_reader_select(pdi,IM_ISO14443B_106,null,null,&ti))
+ {
+ // No test results yet
+ printf("iso14443b\n");
+ }
+
+ // Poll for a Jewel tag
+ if (nfc_reader_select(pdi,IM_JEWEL_106,null,null,&ti))
+ {
+ // No test results yet
+ printf("jewel\n");
+ }
+
+ nfc_disconnect(pdi);
+ return 1;
}
diff --git a/mifaretag.h b/mifaretag.h
index f6bc772..b07e43d 100644
--- a/mifaretag.h
+++ b/mifaretag.h
@@ -1,54 +1,54 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
-#ifndef _MIFARE_TAG_H_
-#define _MIFARE_TAG_H_
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+#ifndef _LIBNFC_MIFARE_TAG_H_
+#define _LIBNFC_MIFARE_TAG_H_
#include "defines.h"
-typedef struct tagBlockManufacturer {
+typedef struct {
byte abtUID[4];
byte btBCC;
byte btUnknown;
byte abtATQA[2];
byte abtUnknown[8];
-} BlockManufacturer;
+} mifare_block_manufacturer;
-typedef struct tagBlockData {
- byte abtContent[16];
-} BlockData;
+typedef struct {
+ byte abtData[16];
+} mifare_block_data;
-typedef struct tagBlockTrailer {
+typedef struct {
byte abtKeyA[6];
byte abtAccessBits[4];
byte abtKeyB[6];
-} BlockTrailer;
+} mifare_block_trailer;
-typedef union tagBlock {
- BlockManufacturer bm;
- BlockData bd;
- BlockTrailer bt;
-} Block;
+typedef union {
+ mifare_block_manufacturer mbm;
+ mifare_block_data mbd;
+ mifare_block_trailer mbt;
+} mifare_block;
-typedef struct tagMifareTag {
- Block blContent[256];
-} MifareTag;
+typedef struct {
+ mifare_block amb[256];
+} mifare_tag;
-#endif // _MIFARE_TAG_H_
+#endif // _LIBNFC_MIFARE_TAG_H_
diff --git a/relay.c b/relay.c
index f6295bd..65c1566 100644
--- a/relay.c
+++ b/relay.c
@@ -1,107 +1,99 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
-#include
-#include
-#include
-#include "libnfc.h"
-
-static byte abtReaderRecv[MAX_FRAME_LEN];
-static byte abtReaderRecvPar[MAX_FRAME_LEN];
-static ui32 uiReaderRecvBits;
-static byte abtTagRecv[MAX_FRAME_LEN];
-static byte abtTagRecvPar[MAX_FRAME_LEN];
-static ui32 uiTagRecvBits;
-static dev_id diReader;
-static dev_id diTag;
-
-int main(int argc, const char* argv[])
-{
- // Try to open the NFC reader
- diReader = acr122_connect(0);
- if (diReader == INVALID_DEVICE_ID)
- {
- printf("Error connecting first NFC reader\n");
- return 1;
- }
-
- diTag = acr122_connect(1);
- if (diTag == INVALID_DEVICE_ID)
- {
- printf("Error connecting second NFC reader\n");
- return 1;
- }
-
- printf("\n");
- printf("[+] Connected to the both NFC readers\n");
- acr122_led_red(diTag,true);
- printf("[+] Identified simulated tag by setting the red light\n");
- printf("[+] Place both readers on top of each other\n");
- printf("[+] Please run 'anticol' tool in a different shell\n");
- nfc_target_init(diTag,abtReaderRecv,&uiReaderRecvBits);
- nfc_configure_handle_crc(diTag,false);
- nfc_configure_handle_parity(diTag,false);
- nfc_configure_accept_invalid_frames(diTag,true);
- printf("[+] Thank you, the simulated tag is initialized\n");
-
- printf("[+] Attaching to first NFC reader \n");
- // Retry until it becomes ready
- while (!nfc_reader_init(diReader))
- {
- acr122_disconnect(diReader);
- printf("error\n");
- diReader = acr122_connect(0);
- }
- nfc_configure_handle_crc(diReader,false);
- nfc_configure_handle_parity(diReader,false);
- nfc_configure_accept_invalid_frames(diReader,true);
- printf("[+] Done, relaying frames now!\n\n");
-
- while(true)
- {
- // Test if we received a frame from the reader
- if (nfc_target_receive_bits(diTag,abtReaderRecv,&uiReaderRecvBits,abtReaderRecvPar))
- {
- // Drop down the field before sending a REQA command and start a new session
- if (uiReaderRecvBits == 7 && abtReaderRecv[0] == 0x26)
- {
- // Drop down field for a very short time (tag will reboot)
- nfc_configure_field(diReader,false);
- printf("\n");
- nfc_configure_field(diReader,true);
- }
-
- // Print the reader frame to the screen
- printf("R: ");
- print_hex_par(abtReaderRecv,uiReaderRecvBits,abtReaderRecvPar);
-
- // Forward the frame to the original tag
- if (nfc_reader_transceive_bits(diReader,abtReaderRecv,uiReaderRecvBits,abtReaderRecvPar,abtTagRecv,&uiTagRecvBits,abtTagRecvPar))
- {
- // Redirect the answer back to the reader
- nfc_target_send_bits(diTag,abtTagRecv,uiTagRecvBits,abtTagRecvPar);
-
- // Print the tag frame to the screen
- printf("T: ");
- print_hex_par(abtTagRecv,uiTagRecvBits,abtTagRecvPar);
- }
- }
- }
-}
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+#include
+#include
+#include
+#include "libnfc.h"
+
+static byte abtReaderRx[MAX_FRAME_LEN];
+static byte abtReaderRxPar[MAX_FRAME_LEN];
+static ui32 uiReaderRxBits;
+static byte abtTagRx[MAX_FRAME_LEN];
+static byte abtTagRxPar[MAX_FRAME_LEN];
+static ui32 uiTagRxBits;
+static dev_info* pdiReader;
+static dev_info* pdiTag;
+
+int main(int argc, const char* argv[])
+{
+ // Try to open the NFC emulator device
+ pdiTag = nfc_connect();
+ if (pdiTag == INVALID_DEVICE_INFO)
+ {
+ printf("Error connecting NFC emulator device\n");
+ return 1;
+ }
+
+ printf("\n");
+ printf("[+] Connected to the NFC emulator device\n");
+ printf("[+] Try to break out the auto-simulation, this requires a second reader!\n");
+ printf("[+] To do this, please send any command after the anti-collision\n");
+ printf("[+] For example, send a RATS command or use the \"anticol\" tool\n");
+ nfc_target_init(pdiTag,abtReaderRx,&uiReaderRxBits);
+ printf("[+] Configuring emulator settings\n");
+ nfc_configure(pdiTag,DCO_HANDLE_CRC,false);
+ nfc_configure(pdiTag,DCO_HANDLE_PARITY,false);
+ nfc_configure(pdiTag,DCO_ACCEPT_INVALID_FRAMES,true);
+ printf("[+] Thank you, the emulated tag is initialized\n");
+
+ // Try to open the NFC reader
+ pdiReader = INVALID_DEVICE_INFO;
+ while (pdiReader == INVALID_DEVICE_INFO) pdiReader = nfc_connect();
+ printf("[+] Configuring NFC reader settings\n");
+ nfc_configure(pdiReader,DCO_HANDLE_CRC,false);
+ nfc_configure(pdiReader,DCO_HANDLE_PARITY,false);
+ nfc_configure(pdiReader,DCO_ACCEPT_INVALID_FRAMES,true);
+ printf("[+] Done, relaying frames now!\n\n");
+
+ while(true)
+ {
+ // Test if we received a frame from the reader
+ if (nfc_target_receive_bits(pdiTag,abtReaderRx,&uiReaderRxBits,abtReaderRxPar))
+ {
+ // Drop down the field before sending a REQA command and start a new session
+ if (uiReaderRxBits == 7 && abtReaderRx[0] == 0x26)
+ {
+ // Drop down field for a very short time (original tag will reboot)
+ nfc_configure(pdiReader,DCO_ACTIVATE_FIELD,false);
+ printf("\n");
+ nfc_configure(pdiReader,DCO_ACTIVATE_FIELD,true);
+ }
+
+ // Print the reader frame to the screen
+ printf("R: ");
+ print_hex_par(abtReaderRx,uiReaderRxBits,abtReaderRxPar);
+
+ // Forward the frame to the original tag
+ if (nfc_reader_transceive_bits(pdiReader,abtReaderRx,uiReaderRxBits,abtReaderRxPar,abtTagRx,&uiTagRxBits,abtTagRxPar))
+ {
+ // Redirect the answer back to the reader
+ nfc_target_send_bits(pdiTag,abtTagRx,uiTagRxBits,abtTagRxPar);
+
+ // Print the tag frame to the screen
+ printf("T: ");
+ print_hex_par(abtTagRx,uiTagRxBits,abtTagRxPar);
+ }
+ }
+ }
+
+ nfc_disconnect(pdiTag);
+ nfc_disconnect(pdiReader);
+}
diff --git a/simulate.c b/simulate.c
index ad522a1..d8cf0eb 100644
--- a/simulate.c
+++ b/simulate.c
@@ -1,108 +1,111 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
-#include
-#include
-#include
-#include "libnfc.h"
-
-static byte abtRecv[MAX_FRAME_LEN];
-static ui32 uiRecvLen;
-static dev_id di;
-
-// ISO14443A Anti-Collision response
-byte abtAtqa [2] = { 0x04,0x00 };
-byte abtUidBcc [5] = { 0xDE,0xAD,0xBE,0xAF,0x62 };
-byte abtSak [9] = { 0x08,0xb6,0xdd };
-
-int main(int argc, const char* argv[])
-{
- byte* pbtTx;
- ui32 uiTxLen;
-
- // Try to open the NFC reader
- di = acr122_connect(0);
-
- if (di == INVALID_DEVICE_ID)
- {
- printf("Error connecting NFC reader\n");
- return 1;
- }
-
- printf("\n");
- printf("[+] Connected to NFC target\n");
- acr122_led_red(di,true);
- printf("[+] Identified simulated tag by setting the red light\n");
- printf("[+] First we have to come out auto-simulation\n");
- printf("[+] To do this, please send any command after the\n");
- printf("[+] anti-collision, for example, the RATS command\n\n");
- nfc_target_init(di,abtRecv,&uiRecvLen);
- printf("[+] Initiator command: ");
- print_hex(abtRecv,uiRecvLen);
- printf("[+] Configuring communication");
- nfc_configure_accept_invalid_frames(di,true);
- nfc_configure_handle_crc(di,false);
- printf("[+] Done, the simulated tag is initialized \n");
-
-
- while(true)
- {
- // Test if we received a frame
- if (nfc_target_receive_bytes(di,abtRecv,&uiRecvLen))
- {
- // Prepare the command to send back for the anti-collision request
- switch(uiRecvLen)
- {
- case 1: // Request or Wakeup
- pbtTx = abtAtqa;
- uiTxLen = 2;
- // New anti-collsion session started
- printf("\n");
- break;
-
- case 2: // Select All
- pbtTx = abtUidBcc;
- uiTxLen = 5;
- break;
-
- case 9: // Select Tag
- pbtTx = abtSak;
- uiTxLen = 3;
- break;
-
- default: // unknown length?
- uiTxLen = 0;
- break;
- }
-
- printf("R: ");
- print_hex(abtRecv,uiRecvLen);
-
- // Test if we know how to respond
- if(uiTxLen)
- {
- // Send and print the command to the screen
- nfc_target_send_bytes(di,pbtTx,uiTxLen);
- printf("T: ");
- print_hex(pbtTx,uiTxLen);
- }
- }
- }
-}
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+#include
+#include
+#include
+#include "libnfc.h"
+
+static byte abtRecv[MAX_FRAME_LEN];
+static ui32 uiRecvBits;
+static dev_info* pdi;
+
+// ISO14443A Anti-Collision response
+byte abtAtqa [2] = { 0x04,0x00 };
+byte abtUidBcc [5] = { 0xDE,0xAD,0xBE,0xAF,0x62 };
+byte abtSak [9] = { 0x08,0xb6,0xdd };
+
+int main(int argc, const char* argv[])
+{
+ byte* pbtTx = null;
+ ui32 uiTxBits;
+
+ // Try to open the NFC reader
+ pdi = nfc_connect();
+
+ if (pdi == INVALID_DEVICE_INFO)
+ {
+ printf("Error connecting NFC second reader\n");
+ return 1;
+ }
+
+ printf("\n");
+ printf("[+] Connected to NFC reader: %s\n",pdi->acName);
+ printf("[+] Try to break out the auto-simulation, this requires a second reader!\n");
+ printf("[+] To do this, please send any command after the anti-collision\n");
+ printf("[+] For example, send a RATS command or use the \"anticol\" tool\n");
+ if (!nfc_target_init(pdi,abtRecv,&uiRecvBits))
+ {
+ printf("Error: Could not come out of auto-simulation, no command was received\n");
+ return 1;
+ }
+ printf("[+] Received initiator command: ");
+ print_hex_bits(abtRecv,uiRecvBits);
+ printf("[+] Configuring communication\n");
+ nfc_configure(pdi,DCO_HANDLE_CRC,false);
+ nfc_configure(pdi,DCO_HANDLE_PARITY,true);
+ printf("[+] Done, the simulated tag is initialized\n\n");
+
+ while(true)
+ {
+ // Test if we received a frame
+ if (nfc_target_receive_bits(pdi,abtRecv,&uiRecvBits,null))
+ {
+ // Prepare the command to send back for the anti-collision request
+ switch(uiRecvBits)
+ {
+ case 7: // Request or Wakeup
+ pbtTx = abtAtqa;
+ uiTxBits = 16;
+ // New anti-collsion session started
+ printf("\n");
+ break;
+
+ case 16: // Select All
+ pbtTx = abtUidBcc;
+ uiTxBits = 40;
+ break;
+
+ case 72: // Select Tag
+ pbtTx = abtSak;
+ uiTxBits = 24;
+ break;
+
+ default: // unknown length?
+ uiTxBits = 0;
+ break;
+ }
+
+ printf("R: ");
+ print_hex_bits(abtRecv,uiRecvBits);
+
+ // Test if we know how to respond
+ if(uiTxBits)
+ {
+ // Send and print the command to the screen
+ nfc_target_send_bits(pdi,pbtTx,uiTxBits,null);
+ printf("T: ");
+ print_hex_bits(pbtTx,uiTxBits);
+ }
+ }
+ }
+
+ nfc_disconnect(pdi);
+}
diff --git a/types.h b/types.h
index cba978e..ab3c02d 100644
--- a/types.h
+++ b/types.h
@@ -1,40 +1,126 @@
-/*
-
-Public platform independent Near Field Communication (NFC) library
-Copyright (C) 2009, Roel Verdult
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
+/*
+
+Public platform independent Near Field Communication (NFC) library
+Copyright (C) 2009, Roel Verdult
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
#ifndef _LIBNFC_TYPES_H_
#define _LIBNFC_TYPES_H_
#include "defines.h"
-typedef enum {
- false = 0x00,
- true = 0x01
-}bool;
+// Compiler directive, set struct alignment to 1 byte for compatibility
+#pragma pack(1)
typedef enum {
- MT_ISO14443A_106 = 0x00,
- MT_FELICA_212 = 0x01,
- MT_FELICA_424 = 0x02,
- MT_ISO14443B_106 = 0x03,
- MT_TOPAZ_106 = 0x04,
-}ModulationType;
+ false = 0x00,
+ true = 0x01
+} bool;
+
+typedef enum {
+ CT_PN531 = 0x10,
+ CT_PN532 = 0x20,
+ CT_PN533 = 0x30,
+} chip_type;
+
+struct dev_callbacks; // Prototype the callback struct
+
+typedef struct {
+ const struct dev_callbacks* pdc; // Callback functions for handling device specific wrapping
+ char acName[DEVICE_NAME_LENGTH]; // Device name string, including device wrapper firmware
+ chip_type ct; // PN53X chip type, this is useful for some "bug" work-arounds
+ dev_spec ds; // Pointer to the device connection specification
+ bool bActive; // This represents if the PN53X device was initialized succesful
+ bool bCrc; // Is the crc automaticly added, checked and removed from the frames
+ bool bPar; // Does the PN53x chip handles parity bits, all parities are handled as data
+ ui8 ui8TxBits; // The last tx bits setting, we need to reset this if it does not apply anymore
+} dev_info;
+
+struct dev_callbacks {
+ const char* acDriver; // Driver description
+ dev_info* (*connect)(const ui32 uiIndex);
+ bool (*transceive)(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
+ void (*disconnect)(dev_info* pdi);
+};
+
+typedef enum {
+ DCO_HANDLE_CRC = 0x00,
+ DCO_HANDLE_PARITY = 0x01,
+ DCO_ACTIVATE_FIELD = 0x10,
+ DCO_ACTIVATE_CRYPTO1 = 0x11,
+ DCO_INFINITE_SELECT = 0x20,
+ DCO_ACCEPT_INVALID_FRAMES = 0x30,
+ DCO_ACCEPT_MULTIPLE_FRAMES = 0x31
+}dev_config_option;
+
+////////////////////////////////////////////////////////////////////
+// nfc_reader_list_passive - using InListPassiveTarget
+
+typedef enum {
+ IM_ISO14443A_106 = 0x00,
+ IM_FELICA_212 = 0x01,
+ IM_FELICA_424 = 0x02,
+ IM_ISO14443B_106 = 0x03,
+ IM_JEWEL_106 = 0x04
+}init_modulation;
+
+typedef struct {
+ byte abtAtqa[2];
+ byte btSak;
+ ui32 uiUidLen;
+ byte abtUid[10];
+ ui32 uiAtsLen;
+ byte abtAts[36];
+}tag_info_iso14443a;
+
+typedef struct {
+ ui32 uiLen;
+ byte btResCode;
+ byte abtId[8];
+ byte abtPad[8];
+ byte abtSysCode[2];
+}tag_info_felica;
+
+typedef struct {
+ byte abtAtqb[12];
+ byte abtId[4];
+ byte btParam1;
+ byte btParam2;
+ byte btParam3;
+ byte btParam4;
+ byte btCid;
+ ui32 uiInfLen;
+ byte abtInf[64];
+}tag_info_iso14443b;
+
+typedef struct {
+ byte btSensRes[2];
+ byte btId[4];
+}tag_info_jewel;
+
+typedef union {
+ tag_info_iso14443a tia;
+ tag_info_felica tif;
+ tag_info_iso14443b tib;
+ tag_info_jewel tij;
+}tag_info;
+
+////////////////////////////////////////////////////////////////////
+// InDataExchange, MIFARE Classic card
typedef enum {
MC_AUTH_A = 0x60,
@@ -45,25 +131,29 @@ typedef enum {
MC_DECREMENT = 0xC0,
MC_INCREMENT = 0xC1,
MC_STORE = 0xC2,
-}MifareCmd;
+}mifare_cmd;
+// MIFARE Classic command params
typedef struct {
byte abtKey[6];
byte abtUid[4];
-}MifareParamAuth;
+}mifare_param_auth;
typedef struct {
byte abtData[16];
-}MifareParamData;
+}mifare_param_data;
typedef struct {
byte abtValue[4];
-}MifareParamValue;
+}mifare_param_value;
typedef union {
- MifareParamAuth mpa;
- MifareParamData mpd;
- MifareParamValue mpv;
-}MifareParam;
+ mifare_param_auth mpa;
+ mifare_param_data mpd;
+ mifare_param_value mpv;
+}mifare_param;
+
+// Reset struct alignment to default
+#pragma pack()
#endif // _LIBNFC_TYPES_H_
diff --git a/win32/anticol.vcproj b/win32/anticol.vcproj
index 3e27c8a..b96d8d3 100644
--- a/win32/anticol.vcproj
+++ b/win32/anticol.vcproj
@@ -1,7 +1,7 @@
-
-
-
-
@@ -195,6 +191,26 @@
RelativePath="..\defines.h"
>
+
+
+
+
+
+
+
+
+
+
diff --git a/win32/list.vcproj b/win32/list.vcproj
index d329b0a..69a3dae 100644
--- a/win32/list.vcproj
+++ b/win32/list.vcproj
@@ -1,7 +1,7 @@