pn532: initial implementation

This driver was written using an Adafruit PN532 board:

http://www.adafruit.com/products/364

It is based heavily on their arduino code, with significant
modifications.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
Signed-off-by: Zion Orent <zorent@ics.com>
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
This commit is contained in:
Jon Trulson 2015-06-12 18:10:29 -06:00 committed by Mihai Tudor Panu
parent fc3a884024
commit c586cd5177
13 changed files with 2790 additions and 0 deletions

View File

@ -126,6 +126,8 @@ add_executable (m24lr64e-example m24lr64e.cxx)
add_executable (grovecircularled-example grovecircularled.cxx)
add_executable (rgbringcoder-example rgbringcoder.cxx)
add_executable (hp20x-example hp20x.cxx)
add_executable (pn532-example pn532.cxx)
add_executable (pn532-writeurl-example pn532-writeurl.cxx)
include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l)
include_directories (${PROJECT_SOURCE_DIR}/src/grove)
@ -230,6 +232,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/m24lr64e)
include_directories (${PROJECT_SOURCE_DIR}/src/grovecircularled)
include_directories (${PROJECT_SOURCE_DIR}/src/rgbringcoder)
include_directories (${PROJECT_SOURCE_DIR}/src/hp20x)
include_directories (${PROJECT_SOURCE_DIR}/src/pn532)
target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT})
@ -357,3 +360,5 @@ target_link_libraries (m24lr64e-example m24lr64e ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (grovecircularled-example grovecircularled ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (rgbringcoder-example rgbringcoder ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (hp20x-example hp20x ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (pn532-example pn532 ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (pn532-writeurl-example pn532 ${CMAKE_THREAD_LIBS_INIT})

View File

@ -0,0 +1,115 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <unistd.h>
#include <iostream>
#include "pn532.h"
using namespace std;
// the URL we want to add as an NDEF record
// NOTE: this cannot exceed 34 characters.
static char url[] = "iotdk.intel.com";
int main(int argc, char **argv)
{
//! [Interesting]
// Instantiate an PN532 on I2C bus 0 (default) using gpio 3 for the
// IRQ, and gpio 2 for the reset pin.
upm::PN532 *nfc = new upm::PN532(3, 2);
if (!nfc->init())
cerr << "init() failed" << endl;
uint32_t vers = nfc->getFirmwareVersion();
if (vers)
printf("Got firmware version: 0x%08x\n", vers);
else
{
printf("Could not identify PN532\n");
return 1;
}
// Now scan and identify any cards that come in range (1 for now)
// Retry forever
nfc->setPassiveActivationRetries(0xff);
nfc->SAMConfig();
uint8_t uidSize;
uint8_t uid[7];
bool foundCard = false;
while (!foundCard)
{
memset(uid, 0, 7);
if (nfc->readPassiveTargetID(nfc->BAUD_MIFARE_ISO14443A,
uid, &uidSize, 2000))
{
// found a card
printf("Found a card: UID len %d\n", uidSize);
printf("UID: ");
for (int i = 0; i < uidSize; i++)
printf("%02x ", uid[i]);
printf("\n");
printf("SAK: 0x%02x\n", nfc->getSAK());
printf("ATQA: 0x%04x\n\n", nfc->getATQA());
foundCard = true;
}
else
{
printf("Waiting for a card...\n");
}
}
if (uidSize != 7)
{
printf("This example will only write an NDEF URI to preformatted\n");
printf("Mifare Ultralight or NTAG2XX tags\n");
return 1;
}
// 48 bytes is maximum data area on ultralight cards, so we use that
// as the maximum datasize here. Obviously if you have a bigger
// card, you can write more data.
if (!nfc->ntag2xx_WriteNDEFURI(nfc->NDEF_URIPREFIX_HTTP, url, 48))
{
// failure
printf("Failed to write NDEF record tag.\n");
return 1;
}
printf("Success, URL record written to tag.\n");
//! [Interesting]
delete nfc;
return 0;
}

101
examples/c++/pn532.cxx Normal file
View File

@ -0,0 +1,101 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <unistd.h>
#include <signal.h>
#include <iostream>
#include "pn532.h"
using namespace std;
bool shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
int main(int argc, char **argv)
{
signal(SIGINT, sig_handler);
//! [Interesting]
// Instantiate an PN532 on I2C bus 0 (default) using gpio 3 for the
// IRQ, and gpio 2 for the reset pin.
upm::PN532 *nfc = new upm::PN532(3, 2);
if (!nfc->init())
cerr << "init() failed" << endl;
uint32_t vers = nfc->getFirmwareVersion();
if (vers)
printf("Got firmware version: 0x%08x\n", vers);
else
{
printf("Could not identify PN532\n");
return 1;
}
// Now scan and identify any cards that come in range (1 for now)
// Retry forever
nfc->setPassiveActivationRetries(0xff);
nfc->SAMConfig();
uint8_t uidSize;
uint8_t uid[7];
while (shouldRun)
{
memset(uid, 0, 7);
if (nfc->readPassiveTargetID(nfc->BAUD_MIFARE_ISO14443A,
uid, &uidSize, 2000))
{
// found a card
printf("Found a card: UID len %d\n", uidSize);
printf("UID: ");
for (int i = 0; i < uidSize; i++)
printf("%02x ", uid[i]);
printf("\n");
printf("SAK: 0x%02x\n", nfc->getSAK());
printf("ATQA: 0x%04x\n\n", nfc->getATQA());
sleep(1);
}
else
{
printf("Waiting for a card...\n");
}
}
//! [Interesting]
delete nfc;
return 0;
}

View File

@ -0,0 +1,136 @@
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// Load PN532 module
var pn532 = require('jsupm_pn532');
// Instantiate an PN532 on I2C bus 0 (default) using gpio 3 for the
// IRQ, and gpio 2 for the reset pin.
var myNFCObj = new pn532.PN532(3, 2);
function writeUrl()
{
if (uidSize.getitem(0) != 7)
{
console.log("This example will only write an NDEF URI to preformatted");
console.log("Mifare Ultralight or NTAG2XX tags");
exit();
}
// 48 bytes is maximum data area on ultralight cards, so we use that
// as the maximum datasize here. Obviously if you have a bigger
// card, you can write more data.
if (!myNFCObj.ntag2xx_WriteNDEFURI(pn532.PN532.NDEF_URIPREFIX_HTTP,
url, 48))
{
// failure
console.log("Failed to write NDEF record tag.");
exit(1);
}
console.log("Success, URL record written to tag.");
}
function toHex(d, pad)
{
// pad should be between 1 and 8
return ("00000000"+(Number(d).toString(16))).slice(-pad)
}
function exit()
{
clearInterval(myInterval);
myNFCObj = null;
pn532.cleanUp();
pn532 = null;
console.log("Exiting");
process.exit(0);
}
// When exiting: clear interval, and print message
process.on('SIGINT', function()
{
exit();
});
// "main"
if (!myNFCObj.init())
console.log("init() failed");
var vers = myNFCObj.getFirmwareVersion();
if (vers)
console.log("Got firmware version: " + toHex(vers, 8));
else
{
console.log("Could not identify PN532");
exit();
}
// Now scan and identify any cards that come in range (1 for now)
// Retry forever
myNFCObj.setPassiveActivationRetries(0xff);
myNFCObj.SAMConfig();
var uidSize = new pn532.uint8Array(0);
var uid = new pn532.uint8Array(7);
// the URL we want to add as an NDEF record
// NOTE: this cannot exceed 34 characters.
url = "iotdk.intel.com";
var myInterval = setInterval(function()
{
for (var x = 0; x < 7; x++)
uid.setitem(x, 0);
if (myNFCObj.readPassiveTargetID(pn532.PN532.BAUD_MIFARE_ISO14443A,
uid, uidSize, 2000))
{
// found a card
console.log("Found a card: UID len " + uidSize.getitem(0));
process.stdout.write("UID: ");
for (var i = 0; i < uidSize.getitem(0); i++)
{
var byteVal = uid.getitem(i);
process.stdout.write(toHex(byteVal, 2) + " ");
}
process.stdout.write("\n");
console.log("SAK: " + toHex(myNFCObj.getSAK(), 2));
console.log("ATQA: " + toHex(myNFCObj.getATQA(), 4));
console.log(" ");
// write the URL
writeUrl();
clearInterval(myInterval);
return;
}
else
console.log("Waiting for a card...");
}, 1000);

View File

@ -0,0 +1,102 @@
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
/*
* Author: Zion Orent <zorent@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// Load PN532 module
var pn532 = require('jsupm_pn532');
// Instantiate an PN532 on I2C bus 0 (default) using gpio 3 for the
// IRQ, and gpio 2 for the reset pin.
var myNFCObj = new pn532.PN532(3, 2);
if (!myNFCObj.init())
console.log("init() failed");
var vers = myNFCObj.getFirmwareVersion();
if (vers)
console.log("Got firmware version: " + toHex(vers, 8));
else
{
console.log("Could not identify PN532");
exit();
}
// Now scan and identify any cards that come in range (1 for now)
// Retry forever
myNFCObj.setPassiveActivationRetries(0xff);
myNFCObj.SAMConfig();
var uidSize = new pn532.uint8Array(0);
var uid = new pn532.uint8Array(7);
var myInterval = setInterval(function()
{
for (var x = 0; x < 7; x++)
uid.setitem(x, 0);
if (myNFCObj.readPassiveTargetID(pn532.PN532.BAUD_MIFARE_ISO14443A,
uid, uidSize, 2000))
{
// found a card
console.log("Found a card: UID len " + uidSize.getitem(0));
process.stdout.write("UID: ");
for (var i = 0; i < uidSize.getitem(0); i++)
{
var byteVal = uid.getitem(i);
process.stdout.write(toHex(byteVal, 2) + " ");
}
process.stdout.write("\n");
console.log("SAK: " + toHex(myNFCObj.getSAK(), 2));
console.log("ATQA: " + toHex(myNFCObj.getATQA(), 4));
console.log(" ");
}
else
console.log("Waiting for a card...");
}, 1000);
function toHex(d, pad)
{
// pad should be between 1 and 8
return ("00000000"+(Number(d).toString(16))).slice(-pad)
}
function exit()
{
clearInterval(myInterval);
myNFCObj = null;
pn532.cleanUp();
pn532 = null;
console.log("Exiting");
process.exit(0);
}
// When exiting: clear interval, and print message
process.on('SIGINT', function()
{
exit();
});

View File

@ -0,0 +1,105 @@
#!/usr/bin/python
# Author: Jon Trulson <jtrulson@ics.com>
# Copyright (c) 2015 Intel Corporation.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import time, sys, signal, atexit
import pyupm_pn532 as upmPn532
# Instantiate an PN532 on I2C bus 0 (default) using gpio 3 for the
# IRQ, and gpio 2 for the reset pin.
myNFC = upmPn532.PN532(3, 2)
## Exit handlers ##
# This stops python from printing a stacktrace when you hit control-C
def SIGINTHandler(signum, frame):
raise SystemExit
# This lets you run code on exit
def exitHandler():
print "Exiting"
sys.exit(0)
# Register exit handlers
atexit.register(exitHandler)
signal.signal(signal.SIGINT, SIGINTHandler)
if (not myNFC.init()):
print "init() failed"
sys.exit(0)
vers = myNFC.getFirmwareVersion()
if (vers):
print "Got firmware version: %08x" % vers
else:
print "Could not identify PN532"
sys.exit(0)
# Now scan and identify any cards that come in range (1 for now)
# Retry forever
myNFC.setPassiveActivationRetries(0xff)
myNFC.SAMConfig()
uidSize = upmPn532.uint8Array(0)
uid = upmPn532.uint8Array(7)
# the URL we want to add as an NDEF record
# NOTE: this cannot exceed 34 characters.
url = "iotdk.intel.com"
foundCard = False
while (not foundCard):
for i in range(7):
uid.__setitem__(i, 0)
if (myNFC.readPassiveTargetID(upmPn532.PN532.BAUD_MIFARE_ISO14443A,
uid, uidSize, 2000)):
# found a card
print "Found a card: UID len", uidSize.__getitem__(0)
print "UID: ",
for i in range(uidSize.__getitem__(0)):
print "%02x" % uid.__getitem__(i),
print
print "SAK: %02x" % myNFC.getSAK()
print "ATQA: %04x" % myNFC.getATQA()
print
foundCard = True
else:
print "Waiting for a card...\n"
if (uidSize.__getitem__(0) != 7):
print "This example will only write an NDEF URI to preformatted"
print "Mifare Ultralight or NTAG2XX tags"
sys.exit(1)
# 48 bytes is maximum data area on ultralight cards, so we use that
# as the maximum datasize here. Obviously if you have a bigger
# card, you can write more data.
if (not myNFC.ntag2xx_WriteNDEFURI(upmPn532.PN532.NDEF_URIPREFIX_HTTP, url, 48)):
# failure
print "Failed to write NDEF record tag."
sys.exit(1)
print "Success, URL record written to tag."

85
examples/python/pn532.py Normal file
View File

@ -0,0 +1,85 @@
#!/usr/bin/python
# Author: Zion Orent <zorent@ics.com>
# Copyright (c) 2015 Intel Corporation.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import time, sys, signal, atexit
import pyupm_pn532 as upmPn532
# Instantiate an PN532 on I2C bus 0 (default) using gpio 3 for the
# IRQ, and gpio 2 for the reset pin.
myNFC = upmPn532.PN532(3, 2)
## Exit handlers ##
# This stops python from printing a stacktrace when you hit control-C
def SIGINTHandler(signum, frame):
raise SystemExit
# This lets you run code on exit
def exitHandler():
print "Exiting"
sys.exit(0)
# Register exit handlers
atexit.register(exitHandler)
signal.signal(signal.SIGINT, SIGINTHandler)
if (not myNFC.init()):
print "init() failed"
sys.exit(0)
vers = myNFC.getFirmwareVersion()
if (vers):
print "Got firmware version: %08x" % vers
else:
print "Could not identify PN532"
sys.exit(0)
# Now scan and identify any cards that come in range (1 for now)
# Retry forever
myNFC.setPassiveActivationRetries(0xff)
myNFC.SAMConfig()
uidSize = upmPn532.uint8Array(0)
uid = upmPn532.uint8Array(7)
while (1):
for i in range(7):
uid.__setitem__(i, 0)
if (myNFC.readPassiveTargetID(upmPn532.PN532.BAUD_MIFARE_ISO14443A,
uid, uidSize, 2000)):
# found a card
print "Found a card: UID len", uidSize.__getitem__(0)
print "UID: ",
for i in range(uidSize.__getitem__(0)):
print "%02x" % uid.__getitem__(i),
print
print "SAK: %02x" % myNFC.getSAK()
print "ATQA: %04x" % myNFC.getATQA()
print
time.sleep(1)
else:
print "Waiting for a card...\n"

5
src/pn532/CMakeLists.txt Normal file
View File

@ -0,0 +1,5 @@
set (libname "pn532")
set (libdescription "upm pn532 NFC/RFID reader/writer")
set (module_src ${libname}.cxx)
set (module_h ${libname}.h)
upm_module_init()

17
src/pn532/jsupm_pn532.i Normal file
View File

@ -0,0 +1,17 @@
%module jsupm_pn532
%include "../upm.i"
%include "../carrays_uint8_t.i"
// Adding this typemap because SWIG is converting uint8 into a short by default
// This forces SWIG to convert it correctly
%typemap(in) uint8_t * {
void *argp = 0 ;
int res = SWIG_ConvertPtr($input, &argp, SWIGTYPE_p_uint8Array, 0 | 0 );
$1 = (uint8_t *)(argp);
}
%{
#include "pn532.h"
%}
%include "pn532.h"

26
src/pn532/license.txt Normal file
View File

@ -0,0 +1,26 @@
Software License Agreement (BSD License)
Copyright (c) 2012, Adafruit Industries
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1569
src/pn532/pn532.cxx Normal file

File diff suppressed because it is too large Load Diff

502
src/pn532/pn532.h Normal file
View File

@ -0,0 +1,502 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* This code is heavily based on the Adafruit-PN532 library at
* https://github.com/adafruit/Adafruit-PN532, which is licensed under
* the BSD license. See upm/src/pn532/license.txt
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <string.h>
#include <string>
#include <mraa/i2c.hpp>
#include <mraa/gpio.hpp>
#define PN532_I2C_BUS 0
#define PN532_DEFAULT_I2C_ADDR (0x48 >> 1)
#define PN532_PREAMBLE (0x00)
#define PN532_STARTCODE1 (0x00)
#define PN532_STARTCODE2 (0xFF)
#define PN532_POSTAMBLE (0x00)
#define PN532_HOSTTOPN532 (0xD4)
#define PN532_PN532TOHOST (0xD5)
namespace upm {
/**
* @brief PN532 NFC/RFID reader/writer
* @defgroup pn532 libupm-pn532
* @ingroup adafruit i2c rfid
*/
/**
* @library pn532
* @sensor pn532
* @comname PN532 NFC/RFID reader/writer
* @type rfid
* @man adafruit
* @web http://www.adafruit.com/products/364
* @con i2c
*
* @brief API for the PN532 based NFC/RFID reader/writer
*
* Identify a card and print out basic info
* @snippet pn532.cxx Interesting
* Add a URI to an already NDEF formatted ultralight or NTAG2XX tag
* @snippet pn532-writeurl.cxx Interesting
*/
class PN532 {
public:
/**
* PN532 commands
*/
typedef enum {
CMD_DIAGNOSE = 0x00,
CMD_GETFIRMWAREVERSION = 0x02,
CMD_GETGENERALSTATUS = 0x04,
CMD_READREGISTER = 0x06,
CMD_WRITEREGISTER = 0x08,
CMD_READGPIO = 0x0C,
CMD_WRITEGPIO = 0x0E,
CMD_SETSERIALBAUDRATE = 0x10,
CMD_SETPARAMETERS = 0x12,
CMD_SAMCONFIGURATION = 0x14,
CMD_POWERDOWN = 0x16,
CMD_RFCONFIGURATION = 0x32,
CMD_RFREGULATIONTEST = 0x58,
CMD_INJUMPFORDEP = 0x56,
CMD_INJUMPFORPSL = 0x46,
CMD_INLISTPASSIVETARGET = 0x4A,
CMD_INATR = 0x50,
CMD_INPSL = 0x4E,
CMD_INDATAEXCHANGE = 0x40,
CMD_INCOMMUNICATETHRU = 0x42,
CMD_INDESELECT = 0x44,
CMD_INRELEASE = 0x52,
CMD_INSELECT = 0x54,
CMD_INAUTOPOLL = 0x60,
CMD_TGINITASTARGET = 0x8C,
CMD_TGSETGENERALBYTES = 0x92,
CMD_TGGETDATA = 0x86,
CMD_TGSETDATA = 0x8E,
CMD_TGSETMETADATA = 0x94,
CMD_TGGETINITIATORCOMMAND = 0x88,
CMD_TGRESPONSETOINITIATOR = 0x90,
CMD_TGGETTARGETSTATUS = 0x8A
} PN532_CMD_T;
/**
* Response bytes
*/
typedef enum {
RSP_INDATAEXCHANGE = 0x41,
RSP_INLISTPASSIVETARGET = 0x4B
} PN532_RSP_T;
/**
* MIFARE commands
*/
typedef enum {
MIFARE_CMD_AUTH_A = 0x60,
MIFARE_CMD_AUTH_B = 0x61,
MIFARE_CMD_READ = 0x30,
MIFARE_CMD_WRITE = 0xA0,
MIFARE_CMD_TRANSFER = 0xB0,
MIFARE_CMD_DECREMENT = 0xC0,
MIFARE_CMD_INCREMENT = 0xC1,
MIFARE_CMD_STORE = 0xC2,
MIFARE_ULTRALIGHT_CMD_WRITE = 0xA2
} MIFARE_CMD_T;
/**
* NDEF prefixes
*/
typedef enum {
NDEF_URIPREFIX_NONE = 0x00,
NDEF_URIPREFIX_HTTP_WWWDOT = 0x01,
NDEF_URIPREFIX_HTTPS_WWWDOT = 0x02,
NDEF_URIPREFIX_HTTP = 0x03,
NDEF_URIPREFIX_HTTPS = 0x04,
NDEF_URIPREFIX_TEL = 0x05,
NDEF_URIPREFIX_MAILTO = 0x06,
NDEF_URIPREFIX_FTP_ANONAT = 0x07,
NDEF_URIPREFIX_FTP_FTPDOT = 0x08,
NDEF_URIPREFIX_FTPS = 0x09,
NDEF_URIPREFIX_SFTP = 0x0A,
NDEF_URIPREFIX_SMB = 0x0B,
NDEF_URIPREFIX_NFS = 0x0C,
NDEF_URIPREFIX_FTP = 0x0D,
NDEF_URIPREFIX_DAV = 0x0E,
NDEF_URIPREFIX_NEWS = 0x0F,
NDEF_URIPREFIX_TELNET = 0x10,
NDEF_URIPREFIX_IMAP = 0x11,
NDEF_URIPREFIX_RTSP = 0x12,
NDEF_URIPREFIX_URN = 0x13,
NDEF_URIPREFIX_POP = 0x14,
NDEF_URIPREFIX_SIP = 0x15,
NDEF_URIPREFIX_SIPS = 0x16,
NDEF_URIPREFIX_TFTP = 0x17,
NDEF_URIPREFIX_BTSPP = 0x18,
NDEF_URIPREFIX_BTL2CAP = 0x19,
NDEF_URIPREFIX_BTGOEP = 0x1A,
NDEF_URIPREFIX_TCPOBEX = 0x1B,
NDEF_URIPREFIX_IRDAOBEX = 0x1C,
NDEF_URIPREFIX_FILE = 0x1D,
NDEF_URIPREFIX_URN_EPC_ID = 0x1E,
NDEF_URIPREFIX_URN_EPC_TAG = 0x1F,
NDEF_URIPREFIX_URN_EPC_PAT = 0x20,
NDEF_URIPREFIX_URN_EPC_RAW = 0x21,
NDEF_URIPREFIX_URN_EPC = 0x22,
NDEF_URIPREFIX_URN_NFC = 0x23
} NDEF_URI_T;
/**
* Card baud rates
*/
typedef enum {
BAUD_MIFARE_ISO14443A = 0x00 // 106 Kbit/s
} BAUD_T;
/**
* Tag types
*/
typedef enum {
TAG_TYPE_UNKNOWN = 0,
TAG_TYPE_MIFARE_CLASSIC = 1,
TAG_TYPE_NFC2 = 2 /* ultralight or NTAG2XX */
} TAG_TYPE_T;
/**
* pn532 constructor
*
* @param irq pin to use for IRQ
* @param reset reset pin
* @param bus i2c bus to use
* @param address the address for this device
*/
PN532(int irq, int reset, int bus=PN532_I2C_BUS,
uint8_t address=PN532_DEFAULT_I2C_ADDR);
/**
* PN532 Destructor
*/
~PN532();
/**
* set up initial values and start operation
*
* @return true if successful
*/
bool init();
/**
* Checks the firmware version of the PN5xx chip
*
* @return the chip's firmware version and ID
*/
uint32_t getFirmwareVersion();
/**
* sends a command and waits a specified period for the ACK
*
* @param cmd Pointer to the command buffer
* @param cmdlen the size of the command in bytes
* @param timeout timeout before giving up (in ms)
*
* @return true if everything is OK, false if timeout occured
* before an ACK was recieved
*/
bool sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen,
uint16_t timeout=1000);
/**
* configures the SAM (Secure Access Module)
*
* @return true if successfully configured
*/
bool SAMConfig(void);
/**
* sets the MxRtyPassiveActivation byte of the RFConfiguration
* register. By default the pn532 will retry indefinitely.
*
* @param maxRetries 0xFF to wait forever, 0x00..0xFE to timeout
* after maxRetries. 0x00 means try once, with no retries on failure.
*
* @return true if everything executed properly, false for an error
*/
bool setPassiveActivationRetries(uint8_t maxRetries);
/**
* waits for an ISO14443A target to enter the field
*
* @param cardbaudbate baud rate of the card, one of the BAUD_T values
* @param uid Pointer to the array that will be populated with the
* cards UID, up to 7 bytes
* @param uidLength Pointer to the variable that will hold the
* length of the card's UID.
* @param timeout the number of milliseconds to wait
*
* @return true if everything executed properly, false for an error
*/
bool readPassiveTargetID(BAUD_T cardbaudrate, uint8_t * uid,
uint8_t * uidLength, uint16_t timeout);
/**
* exchanges an APDU (Application Protocol Data Unit) with the
* currently inlisted peer
*
* @param send Pointer to data to send
* @param sendLength Length of the data to send
* @param response Pointer to response data
* @param responseLength Pointer to the response data length
*
* @return true if everything executed properly, false for an error
*/
bool inDataExchange(uint8_t * send, uint8_t sendLength,
uint8_t * response, uint8_t * responseLength);
/**
* 'InLists' a passive target. PN532 acting as reader/initiator,
* peer acting as card/responder.
*
* @return true if everything executed properly, false for an error
*/
bool inListPassiveTarget();
/**
* Indicates whether the specified block number is the first block
* in the sector (block 0 relative to the current sector)
*
* @return true if it's the first block, false otherwise
*/
bool mifareclassic_IsFirstBlock (uint32_t uiBlock);
/**
* indicates whether the specified block number is the sector trailer
*
* @return true if it's the trailer block, false otherwise
*/
bool mifareclassic_IsTrailerBlock (uint32_t uiBlock);
/**
* tries to authenticate a block of memory on a MIFARE card using the
* INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
* for more information on sending MIFARE and other commands.
*
* @param uid Pointer to a byte array containing the card UID
* @param uidLen The length (in bytes) of the card's UID (Should
* be 4 for MIFARE Classic)
* @param blockNumber The block number to authenticate. (0..63 for
* 1KB cards, and 0..255 for 4KB cards).
* @param keyNumber Which key type to use during authentication
* (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
* @param keyData Pointer to a byte array containing the 6 byte
* key value
*
* @return true if everything executed properly, false for an error
*/
bool mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen,
uint32_t blockNumber,
uint8_t keyNumber,
uint8_t * keyData);
/**
* tries to read an entire 16-byte data block at the specified block
* address.
*
* @param blockNumber The block number to read (0..63 for
* 1KB cards, and 0..255 for 4KB cards).
* @param data Pointer to the byte array that will hold the
* retrieved data (if any)
*
* @return true if everything executed properly, false for an error
*/
bool mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data);
/**
* tries to write an entire 16-byte data block at the specified block
* address.
*
* @param blockNumber The block number to write. (0..63 for
* 1KB cards, and 0..255 for 4KB cards).
* @param data The byte array that contains the data to write.
*
* @returns true if everything executed properly, false for an error
*/
bool mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data);
/**
* formats a Mifare Classic card to store NDEF Records
*
* @return true if everything executed properly, false for an error
*/
bool mifareclassic_FormatNDEF (void);
/**
* writes an NDEF URI Record to the specified sector (1..15)
*
* Note that this function assumes that the Mifare Classic card is
* already formatted to work as an "NFC Forum Tag" and uses a MAD1
* file system. You can use the NXP TagWriter app on Android to
* properly format cards for this.
*
* @param sectorNumber The sector that the URI record should be written
* to (can be 1..15 for a 1K card)
* @param uriIdentifier The uri identifier code (one of the NDEF_URI_T
* values
* @param url the uri text to write (max 38 characters).
*
* @return true if everything executed properly, false for an error
*/
bool mifareclassic_WriteNDEFURI (uint8_t sectorNumber,
NDEF_URI_T uriIdentifier,
const char * url);
/**
* read an entire 4-byte page at the specified address
*
* @param page The page number (0..63 in most cases)
* @param buffer Pointer to the byte array that will hold the
* retrieved data (if any)
*
* @return true if everything executed properly, false for an error
*/
bool ntag2xx_ReadPage (uint8_t page, uint8_t * buffer);
/**
* write an entire 4-byte page at the specified block address
*
* @param page The page number to write. (0..63 for most cases)
* @param data The byte array that contains the data to write.
* Should be exactly 4 bytes long.
*
* @return true if everything executed properly, false for an error
*/
bool ntag2xx_WritePage (uint8_t page, uint8_t * data);
/**
* writes an NDEF URI Record starting at the specified page (4..nn)
*
* Note that this function assumes that the NTAG2xx card is
* already formatted to work as an "NFC Forum Tag".
*
* @param uriIdentifier The uri identifier code (one of the NDEF_URI_T
* values
* @param url The uri text to write (null-terminated string).
* @param dataLen The size of the data area for overflow checks.
*
* @return true if everything executed properly, false for an error
*/
bool ntag2xx_WriteNDEFURI (NDEF_URI_T uriIdentifier, char * url,
uint8_t dataLen);
/**
* return the ATQA (Answer to Request Acknowlege) value. This
* value is only valid after a successfull call to
* readPassiveTargetID()
*
* @return ATQA value
*/
uint16_t getATQA() { return m_ATQA; };
/**
* return the SAK (Select Acknowlege) value. This
* value is only valid after a successfull call to
* readPassiveTargetID()
*
* @return SAK value
*/
uint8_t getSAK() { return m_SAK; };
/**
* provide public access to the class's MRAA i2C context for
* direct user access
*
* @return a reference to the class i2c context
*/
mraa::I2c& i2cContext() { return m_i2c; };
/**
* enable or disable debugging output for pn532 related operations
*
* @param enable true to enabloe debug output, false to disable
*/
void pn532Debug(bool enable) { m_pn532Debug = enable; };
/**
* enable or disable debugging output for mifare related operations
*
* @param enable true to enabloe debug output, false to disable
*/
void mifareDebug(bool enable) { m_mifareDebug = enable; };
/**
* try to determine the tag type
*
* @return one of the TAG_TYPE_T values
*/
TAG_TYPE_T tagType();
protected:
mraa::I2c m_i2c;
mraa::Gpio m_gpioIRQ;
mraa::Gpio m_gpioReset;
bool readAck();
bool isReady();
bool waitForReady(uint16_t timeout);
void readData(uint8_t* buff, uint8_t n);
void writeCommand(uint8_t* cmd, uint8_t cmdlen);
private:
static void dataReadyISR(void *ctx);
bool m_isrInstalled;
volatile bool m_irqRcvd;
uint8_t m_addr;
uint8_t m_uid[7]; // ISO14443A uid
uint8_t m_uidLen; // uid len
uint8_t m_key[6]; // Mifare Classic key
uint8_t m_inListedTag; // Tg number of inlisted tag.
uint16_t m_ATQA; // ATQA (Answer to Request Acknowlege - ISO14443)
// for currently inlisted card
uint8_t m_SAK; // SAK (Select Acknowlege)
// for currently inlisted card
// debugables
bool m_pn532Debug;
bool m_mifareDebug;
};
}

22
src/pn532/pyupm_pn532.i Normal file
View File

@ -0,0 +1,22 @@
%module pyupm_pn532
%include "../upm.i"
%include "../carrays_uint8_t.i"
// Adding this typemap because SWIG is converting uint8, uint16, and uint32 into a short by default
// This forces SWIG to convert it correctly
%typemap(in) uint8_t * {
void *argp = 0 ;
int res = SWIG_ConvertPtr($input, &argp, SWIGTYPE_p_uint8Array, 0 | 0 );
$1 = reinterpret_cast< uint8_t * >(argp);
}
%feature("autodoc", "3");
#ifdef DOXYGEN
%include "pn532_doc.i"
#endif
%include "pn532.h"
%{
#include "pn532.h"
%}